diff options
Diffstat (limited to 'src/test/ui/let-else')
48 files changed, 515 insertions, 52 deletions
diff --git a/src/test/ui/let-else/const-fn.rs b/src/test/ui/let-else/const-fn.rs new file mode 100644 index 000000000..336b0b4b7 --- /dev/null +++ b/src/test/ui/let-else/const-fn.rs @@ -0,0 +1,19 @@ +// run-pass +// issue #101932 + +#![cfg_attr(bootstrap, feature(let_else))] + +const fn foo(a: Option<i32>) -> i32 { + let Some(a) = a else { + return 42 + }; + + a + 1 +} + +fn main() { + const A: i32 = foo(None); + const B: i32 = foo(Some(1)); + + println!("{} {}", A, B); +} diff --git a/src/test/ui/let-else/issue-100103.rs b/src/test/ui/let-else/issue-100103.rs new file mode 100644 index 000000000..f5f9b2f5f --- /dev/null +++ b/src/test/ui/let-else/issue-100103.rs @@ -0,0 +1,15 @@ +// edition:2021 +// check-pass + +#![feature(try_blocks)] + + +fn main() { + let _: Result<i32, i32> = try { + let Some(x) = Some(0) else { + Err(1)? + }; + + x + }; +} diff --git a/src/test/ui/let-else/issue-102317.rs b/src/test/ui/let-else/issue-102317.rs new file mode 100644 index 000000000..7369b4938 --- /dev/null +++ b/src/test/ui/let-else/issue-102317.rs @@ -0,0 +1,20 @@ +// issue #102317 +// build-pass +// compile-flags: --edition 2021 -C opt-level=3 -Zvalidate-mir + +struct SegmentJob; + +impl Drop for SegmentJob { + fn drop(&mut self) {} +} + +pub async fn run() -> Result<(), ()> { + let jobs = Vec::<SegmentJob>::new(); + let Some(_job) = jobs.into_iter().next() else { + return Ok(()) + }; + + Ok(()) +} + +fn main() {} diff --git a/src/test/ui/let-else/issue-94176.rs b/src/test/ui/let-else/issue-94176.rs new file mode 100644 index 000000000..f76dfc15b --- /dev/null +++ b/src/test/ui/let-else/issue-94176.rs @@ -0,0 +1,10 @@ +// Issue #94176: wrong span for the error message of a mismatched type error, +// if the function uses a `let else` construct. + + +pub fn test(a: Option<u32>) -> Option<u32> { //~ ERROR mismatched types + let Some(_) = a else { return None; }; + println!("Foo"); +} + +fn main() {} diff --git a/src/test/ui/let-else/issue-94176.stderr b/src/test/ui/let-else/issue-94176.stderr new file mode 100644 index 000000000..0cb97acee --- /dev/null +++ b/src/test/ui/let-else/issue-94176.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/issue-94176.rs:5:32 + | +LL | pub fn test(a: Option<u32>) -> Option<u32> { + | ---- ^^^^^^^^^^^ expected enum `Option`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | + = note: expected enum `Option<u32>` + found unit type `()` +help: consider returning the local binding `a` + | +LL ~ println!("Foo"); +LL + a + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/let-else/issue-99975.rs b/src/test/ui/let-else/issue-99975.rs new file mode 100644 index 000000000..5b164f347 --- /dev/null +++ b/src/test/ui/let-else/issue-99975.rs @@ -0,0 +1,20 @@ +// run-pass +// compile-flags: -C opt-level=3 -Zvalidate-mir + + + +fn return_result() -> Option<String> { + Some("ok".to_string()) +} + +fn start() -> String { + let Some(content) = return_result() else { + return "none".to_string() + }; + + content +} + +fn main() { + start(); +} diff --git a/src/test/ui/let-else/let-else-allow-in-expr.rs b/src/test/ui/let-else/let-else-allow-in-expr.rs index 39f4c9060..33acb6c6a 100644 --- a/src/test/ui/let-else/let-else-allow-in-expr.rs +++ b/src/test/ui/let-else/let-else-allow-in-expr.rs @@ -1,5 +1,3 @@ -#![feature(let_else)] - #![deny(unused_variables)] fn main() { diff --git a/src/test/ui/let-else/let-else-allow-in-expr.stderr b/src/test/ui/let-else/let-else-allow-in-expr.stderr index e86bcbc85..3b2b9066c 100644 --- a/src/test/ui/let-else/let-else-allow-in-expr.stderr +++ b/src/test/ui/let-else/let-else-allow-in-expr.stderr @@ -1,17 +1,17 @@ error: unused variable: `x` - --> $DIR/let-else-allow-in-expr.rs:7:13 + --> $DIR/let-else-allow-in-expr.rs:5:13 | LL | let x = 1; | ^ help: if this is intentional, prefix it with an underscore: `_x` | note: the lint level is defined here - --> $DIR/let-else-allow-in-expr.rs:3:9 + --> $DIR/let-else-allow-in-expr.rs:1:9 | LL | #![deny(unused_variables)] | ^^^^^^^^^^^^^^^^ error: unused variable: `x` - --> $DIR/let-else-allow-in-expr.rs:29:9 + --> $DIR/let-else-allow-in-expr.rs:27:9 | LL | let x = 1; | ^ help: if this is intentional, prefix it with an underscore: `_x` diff --git a/src/test/ui/let-else/let-else-allow-unused.rs b/src/test/ui/let-else/let-else-allow-unused.rs index 86ebacfa7..bbb1c7bea 100644 --- a/src/test/ui/let-else/let-else-allow-unused.rs +++ b/src/test/ui/let-else/let-else-allow-unused.rs @@ -1,6 +1,6 @@ // issue #89807 -#![feature(let_else)] + #[deny(unused_variables)] diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs index b65fa13c1..955f33ee1 100644 --- a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs +++ b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs @@ -1,6 +1,6 @@ // from rfc2005 test suite -#![feature(let_else)] + // Verify the binding mode shifts - only when no `&` are auto-dereferenced is the // final default binding mode mutable. diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs b/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs index 63b35df76..1524d0102 100644 --- a/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs +++ b/src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs @@ -1,8 +1,8 @@ -#![feature(let_else)] - // Slightly different from explicit-mut-annotated -- this won't show an error until borrowck. // Should it show a type error instead? + + fn main() { let Some(n): &mut Option<i32> = &mut &Some(5i32) else { //~^ ERROR cannot borrow data in a `&` reference as mutable diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs b/src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs index 305be9221..b0a6264a1 100644 --- a/src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs +++ b/src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(let_else)] + fn main() { let Some(n) = &mut &mut Some(5i32) else { return; }; diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut.rs b/src/test/ui/let-else/let-else-binding-explicit-mut.rs index dbe4715b1..a153b3af0 100644 --- a/src/test/ui/let-else/let-else-binding-explicit-mut.rs +++ b/src/test/ui/let-else/let-else-binding-explicit-mut.rs @@ -1,6 +1,6 @@ // from rfc2005 test suite -#![feature(let_else)] + // Verify the binding mode shifts - only when no `&` are auto-dereferenced is the // final default binding mode mutable. diff --git a/src/test/ui/let-else/let-else-binding-immutable.rs b/src/test/ui/let-else/let-else-binding-immutable.rs index 96de0ffe2..ff2d9f240 100644 --- a/src/test/ui/let-else/let-else-binding-immutable.rs +++ b/src/test/ui/let-else/let-else-binding-immutable.rs @@ -1,6 +1,6 @@ // from rfc2005 test suite -#![feature(let_else)] + pub fn main() { let Some(x) = &Some(3) else { diff --git a/src/test/ui/let-else/let-else-bindings.rs b/src/test/ui/let-else/let-else-bindings.rs index d5121e744..7d2cad978 100644 --- a/src/test/ui/let-else/let-else-bindings.rs +++ b/src/test/ui/let-else/let-else-bindings.rs @@ -1,6 +1,6 @@ // run-pass // adapted from src/test/ui/binding/if-let.rs -#![feature(let_else)] + #![allow(dead_code)] fn none() -> bool { diff --git a/src/test/ui/let-else/let-else-bool-binop-init.fixed b/src/test/ui/let-else/let-else-bool-binop-init.fixed index e47f7f23d..20e558ca9 100644 --- a/src/test/ui/let-else/let-else-bool-binop-init.fixed +++ b/src/test/ui/let-else/let-else-bool-binop-init.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![feature(let_else)] + fn main() { let true = (true && false) else { return }; //~ ERROR a `&&` expression cannot be directly assigned in `let...else` diff --git a/src/test/ui/let-else/let-else-bool-binop-init.rs b/src/test/ui/let-else/let-else-bool-binop-init.rs index e443fb0d6..f88179a94 100644 --- a/src/test/ui/let-else/let-else-bool-binop-init.rs +++ b/src/test/ui/let-else/let-else-bool-binop-init.rs @@ -1,6 +1,6 @@ // run-rustfix -#![feature(let_else)] + fn main() { let true = true && false else { return }; //~ ERROR a `&&` expression cannot be directly assigned in `let...else` diff --git a/src/test/ui/let-else/let-else-brace-before-else.fixed b/src/test/ui/let-else/let-else-brace-before-else.fixed index fb4fd7779..a75c770dd 100644 --- a/src/test/ui/let-else/let-else-brace-before-else.fixed +++ b/src/test/ui/let-else/let-else-brace-before-else.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![feature(let_else)] + fn main() { let Some(1) = ({ Some(1) }) else { diff --git a/src/test/ui/let-else/let-else-brace-before-else.rs b/src/test/ui/let-else/let-else-brace-before-else.rs index c4c5a1ca2..5603b946f 100644 --- a/src/test/ui/let-else/let-else-brace-before-else.rs +++ b/src/test/ui/let-else/let-else-brace-before-else.rs @@ -1,6 +1,6 @@ // run-rustfix -#![feature(let_else)] + fn main() { let Some(1) = { Some(1) } else { diff --git a/src/test/ui/let-else/let-else-check.rs b/src/test/ui/let-else/let-else-check.rs index 9e32cbef7..713fd986e 100644 --- a/src/test/ui/let-else/let-else-check.rs +++ b/src/test/ui/let-else/let-else-check.rs @@ -1,5 +1,3 @@ -#![feature(let_else)] - #![deny(unused_variables)] fn main() { diff --git a/src/test/ui/let-else/let-else-check.stderr b/src/test/ui/let-else/let-else-check.stderr index 3d647a4c0..bdecbf708 100644 --- a/src/test/ui/let-else/let-else-check.stderr +++ b/src/test/ui/let-else/let-else-check.stderr @@ -1,17 +1,17 @@ error: unused variable: `x` - --> $DIR/let-else-check.rs:14:13 + --> $DIR/let-else-check.rs:12:13 | LL | let x = 1; | ^ help: if this is intentional, prefix it with an underscore: `_x` | note: the lint level is defined here - --> $DIR/let-else-check.rs:3:9 + --> $DIR/let-else-check.rs:1:9 | LL | #![deny(unused_variables)] | ^^^^^^^^^^^^^^^^ error: unused variable: `x` - --> $DIR/let-else-check.rs:18:9 + --> $DIR/let-else-check.rs:16:9 | LL | let x = 1; | ^ help: if this is intentional, prefix it with an underscore: `_x` diff --git a/src/test/ui/let-else/let-else-deref-coercion-annotated.rs b/src/test/ui/let-else/let-else-deref-coercion-annotated.rs index 65d88a6d8..60fdf825a 100644 --- a/src/test/ui/let-else/let-else-deref-coercion-annotated.rs +++ b/src/test/ui/let-else/let-else-deref-coercion-annotated.rs @@ -6,7 +6,7 @@ // Deref/DerefMut to Bar. You can do this with an irrefutable binding, so it should work with // let-else too. -#![feature(let_else)] + use std::ops::{Deref, DerefMut}; struct Foo(Bar); diff --git a/src/test/ui/let-else/let-else-deref-coercion.rs b/src/test/ui/let-else/let-else-deref-coercion.rs index 87489d84b..052a5a8c7 100644 --- a/src/test/ui/let-else/let-else-deref-coercion.rs +++ b/src/test/ui/let-else/let-else-deref-coercion.rs @@ -3,7 +3,7 @@ // We attempt to `let Bar::Present(_) = foo else { ... }` where foo is meant to Deref/DerefMut to // Bar. This fails, you must add a type annotation like `let _: &mut Bar = _ else { ... }` -#![feature(let_else)] + use std::ops::{Deref, DerefMut}; struct Foo(Bar); diff --git a/src/test/ui/let-else/let-else-destructuring.rs b/src/test/ui/let-else/let-else-destructuring.rs index 9a09c414a..d1f1a69bf 100644 --- a/src/test/ui/let-else/let-else-destructuring.rs +++ b/src/test/ui/let-else/let-else-destructuring.rs @@ -1,4 +1,3 @@ -#![feature(let_else)] #[derive(Debug)] enum Foo { Done, diff --git a/src/test/ui/let-else/let-else-destructuring.stderr b/src/test/ui/let-else/let-else-destructuring.stderr index 95efb7116..7d6cb2386 100644 --- a/src/test/ui/let-else/let-else-destructuring.stderr +++ b/src/test/ui/let-else/let-else-destructuring.stderr @@ -1,11 +1,11 @@ error: <assignment> ... else { ... } is not allowed - --> $DIR/let-else-destructuring.rs:11:9 + --> $DIR/let-else-destructuring.rs:10:9 | LL | &Foo::Nested(Some(value)) = value else { break }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0070]: invalid left-hand side of assignment - --> $DIR/let-else-destructuring.rs:11:35 + --> $DIR/let-else-destructuring.rs:10:35 | LL | &Foo::Nested(Some(value)) = value else { break }; | ------------------------- ^ diff --git a/src/test/ui/let-else/let-else-drop-order.rs b/src/test/ui/let-else/let-else-drop-order.rs new file mode 100644 index 000000000..e91e5de84 --- /dev/null +++ b/src/test/ui/let-else/let-else-drop-order.rs @@ -0,0 +1,270 @@ +// run-pass +// edition:2021 +// check-run-results +// +// Drop order tests for let else +// +// Mostly this ensures two things: +// 1. That let and let else temporary drop order is the same. +// This is a specific design request: https://github.com/rust-lang/rust/pull/93628#issuecomment-1047140316 +// 2. That the else block truly only runs after the +// temporaries have dropped. +// +// We also print some nice tables for an overview by humans. +// Changes in those tables are considered breakages, but the +// important properties 1 and 2 are also enforced by the code. +// This is important as it's easy to update the stdout file +// with a --bless and miss the impact of that change. + + +#![allow(irrefutable_let_patterns)] + +use std::cell::RefCell; +use std::rc::Rc; + +#[derive(Clone)] +struct DropAccountant(Rc<RefCell<Vec<Vec<String>>>>); + +impl DropAccountant { + fn new() -> Self { + Self(Default::default()) + } + fn build_droppy(&self, v: u32) -> Droppy<u32> { + Droppy(self.clone(), v) + } + fn build_droppy_enum_none(&self, _v: u32) -> ((), DroppyEnum<u32>) { + ((), DroppyEnum::None(self.clone())) + } + fn new_list(&self, s: impl ToString) { + self.0.borrow_mut().push(vec![s.to_string()]); + } + fn push(&self, s: impl ToString) { + let s = s.to_string(); + let mut accounts = self.0.borrow_mut(); + accounts.last_mut().unwrap().push(s); + } + fn print_table(&self) { + println!(); + + let accounts = self.0.borrow(); + let before_last = &accounts[accounts.len() - 2]; + let last = &accounts[accounts.len() - 1]; + let before_last = get_comma_list(before_last); + let last = get_comma_list(last); + const LINES: &[&str] = &[ + "vanilla", + "&", + "&mut", + "move", + "fn(this)", + "tuple", + "array", + "ref &", + "ref mut &mut", + ]; + let max_len = LINES.iter().map(|v| v.len()).max().unwrap(); + let max_len_before = before_last.iter().map(|v| v.len()).max().unwrap(); + let max_len_last = last.iter().map(|v| v.len()).max().unwrap(); + + println!( + "| {: <max_len$} | {: <max_len_before$} | {: <max_len_last$} |", + "construct", before_last[0], last[0] + ); + println!("| {:-<max_len$} | {:-<max_len_before$} | {:-<max_len_last$} |", "", "", ""); + + for ((l, l_before), l_last) in + LINES.iter().zip(before_last[1..].iter()).zip(last[1..].iter()) + { + println!( + "| {: <max_len$} | {: <max_len_before$} | {: <max_len_last$} |", + l, l_before, l_last, + ); + } + } + #[track_caller] + fn assert_all_equal_to(&self, st: &str) { + let accounts = self.0.borrow(); + let last = &accounts[accounts.len() - 1]; + let last = get_comma_list(last); + for line in last[1..].iter() { + assert_eq!(line.trim(), st.trim()); + } + } + #[track_caller] + fn assert_equality_last_two_lists(&self) { + let accounts = self.0.borrow(); + let last = &accounts[accounts.len() - 1]; + let before_last = &accounts[accounts.len() - 2]; + for (l, b) in last[1..].iter().zip(before_last[1..].iter()) { + if !(l == b || l == "n/a" || b == "n/a") { + panic!("not equal: '{last:?}' != '{before_last:?}'"); + } + } + } +} + +fn get_comma_list(sl: &[String]) -> Vec<String> { + std::iter::once(sl[0].clone()) + .chain(sl[1..].chunks(2).map(|c| c.join(","))) + .collect::<Vec<String>>() +} + +struct Droppy<T>(DropAccountant, T); + +impl<T> Drop for Droppy<T> { + fn drop(&mut self) { + self.0.push("drop"); + } +} + +#[allow(dead_code)] +enum DroppyEnum<T> { + Some(DropAccountant, T), + None(DropAccountant), +} + +impl<T> Drop for DroppyEnum<T> { + fn drop(&mut self) { + match self { + DroppyEnum::Some(acc, _inner) => acc, + DroppyEnum::None(acc) => acc, + } + .push("drop"); + } +} + +macro_rules! nestings_with { + ($construct:ident, $binding:pat, $exp:expr) => { + // vanilla: + $construct!($binding, $exp.1); + + // &: + $construct!(&$binding, &$exp.1); + + // &mut: + $construct!(&mut $binding, &mut ($exp.1)); + + { + // move: + let w = $exp; + $construct!( + $binding, + { + let w = w; + w + } + .1 + ); + } + + // fn(this): + $construct!($binding, std::convert::identity($exp).1); + }; +} + +macro_rules! nestings { + ($construct:ident, $binding:pat, $exp:expr) => { + nestings_with!($construct, $binding, $exp); + + // tuple: + $construct!(($binding, 77), ($exp.1, 77)); + + // array: + $construct!([$binding], [$exp.1]); + }; +} + +macro_rules! let_else { + ($acc:expr, $v:expr, $binding:pat, $build:ident) => { + let acc = $acc; + let v = $v; + + macro_rules! let_else_construct { + ($arg:pat, $exp:expr) => { + loop { + let $arg = $exp else { + acc.push("else"); + break; + }; + acc.push("body"); + break; + } + }; + } + nestings!(let_else_construct, $binding, acc.$build(v)); + // ref &: + let_else_construct!($binding, &acc.$build(v).1); + + // ref mut &mut: + let_else_construct!($binding, &mut acc.$build(v).1); + }; +} + +macro_rules! let_ { + ($acc:expr, $binding:tt) => { + let acc = $acc; + + macro_rules! let_construct { + ($arg:pat, $exp:expr) => {{ + let $arg = $exp; + acc.push("body"); + }}; + } + let v = 0; + { + nestings_with!(let_construct, $binding, acc.build_droppy(v)); + } + acc.push("n/a"); + acc.push("n/a"); + acc.push("n/a"); + acc.push("n/a"); + + // ref &: + let_construct!($binding, &acc.build_droppy(v).1); + + // ref mut &mut: + let_construct!($binding, &mut acc.build_droppy(v).1); + }; +} + +fn main() { + let acc = DropAccountant::new(); + + println!(" --- matching cases ---"); + + // Ensure that let and let else have the same behaviour + acc.new_list("let _"); + let_!(&acc, _); + acc.new_list("let else _"); + let_else!(&acc, 0, _, build_droppy); + acc.assert_equality_last_two_lists(); + acc.print_table(); + + // Ensure that let and let else have the same behaviour + acc.new_list("let _v"); + let_!(&acc, _v); + acc.new_list("let else _v"); + let_else!(&acc, 0, _v, build_droppy); + acc.assert_equality_last_two_lists(); + acc.print_table(); + + println!(); + + println!(" --- mismatching cases ---"); + + acc.new_list("let else _ mismatch"); + let_else!(&acc, 1, DroppyEnum::Some(_, _), build_droppy_enum_none); + acc.new_list("let else _v mismatch"); + let_else!(&acc, 1, DroppyEnum::Some(_, _v), build_droppy_enum_none); + acc.print_table(); + // This ensures that we always drop before visiting the else case + acc.assert_all_equal_to("drop,else"); + + acc.new_list("let else 0 mismatch"); + let_else!(&acc, 1, 0, build_droppy); + acc.new_list("let else 0 mismatch"); + let_else!(&acc, 1, 0, build_droppy); + acc.print_table(); + // This ensures that we always drop before visiting the else case + acc.assert_all_equal_to("drop,else"); +} diff --git a/src/test/ui/let-else/let-else-drop-order.run.stdout b/src/test/ui/let-else/let-else-drop-order.run.stdout new file mode 100644 index 000000000..01cf2f73e --- /dev/null +++ b/src/test/ui/let-else/let-else-drop-order.run.stdout @@ -0,0 +1,51 @@ + --- matching cases --- + +| construct | let _ | let else _ | +| ------------ | --------- | ---------- | +| vanilla | drop,body | drop,body | +| & | body,drop | body,drop | +| &mut | body,drop | body,drop | +| move | drop,body | drop,body | +| fn(this) | drop,body | drop,body | +| tuple | n/a,n/a | drop,body | +| array | n/a,n/a | drop,body | +| ref & | body,drop | body,drop | +| ref mut &mut | body,drop | body,drop | + +| construct | let _v | let else _v | +| ------------ | --------- | ----------- | +| vanilla | drop,body | drop,body | +| & | body,drop | body,drop | +| &mut | body,drop | body,drop | +| move | drop,body | drop,body | +| fn(this) | drop,body | drop,body | +| tuple | n/a,n/a | drop,body | +| array | n/a,n/a | drop,body | +| ref & | body,drop | body,drop | +| ref mut &mut | body,drop | body,drop | + + --- mismatching cases --- + +| construct | let else _ mismatch | let else _v mismatch | +| ------------ | ------------------- | -------------------- | +| vanilla | drop,else | drop,else | +| & | drop,else | drop,else | +| &mut | drop,else | drop,else | +| move | drop,else | drop,else | +| fn(this) | drop,else | drop,else | +| tuple | drop,else | drop,else | +| array | drop,else | drop,else | +| ref & | drop,else | drop,else | +| ref mut &mut | drop,else | drop,else | + +| construct | let else 0 mismatch | let else 0 mismatch | +| ------------ | ------------------- | ------------------- | +| vanilla | drop,else | drop,else | +| & | drop,else | drop,else | +| &mut | drop,else | drop,else | +| move | drop,else | drop,else | +| fn(this) | drop,else | drop,else | +| tuple | drop,else | drop,else | +| array | drop,else | drop,else | +| ref & | drop,else | drop,else | +| ref mut &mut | drop,else | drop,else | diff --git a/src/test/ui/let-else/let-else-if.rs b/src/test/ui/let-else/let-else-if.rs index c3a17330d..e8c54ca7a 100644 --- a/src/test/ui/let-else/let-else-if.rs +++ b/src/test/ui/let-else/let-else-if.rs @@ -1,5 +1,3 @@ -#![feature(let_else)] - fn main() { let Some(_) = Some(()) else if true { //~^ ERROR conditional `else if` is not supported for `let...else` diff --git a/src/test/ui/let-else/let-else-if.stderr b/src/test/ui/let-else/let-else-if.stderr index 746738bbd..c63fd61c5 100644 --- a/src/test/ui/let-else/let-else-if.stderr +++ b/src/test/ui/let-else/let-else-if.stderr @@ -1,5 +1,5 @@ error: conditional `else if` is not supported for `let...else` - --> $DIR/let-else-if.rs:4:33 + --> $DIR/let-else-if.rs:2:33 | LL | let Some(_) = Some(()) else if true { | ^^ expected `{` diff --git a/src/test/ui/let-else/let-else-irrefutable.rs b/src/test/ui/let-else/let-else-irrefutable.rs index b1e09a124..1cb68ecb8 100644 --- a/src/test/ui/let-else/let-else-irrefutable.rs +++ b/src/test/ui/let-else/let-else-irrefutable.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(let_else)] + fn main() { let x = 1 else { return }; //~ WARN irrefutable `let...else` pattern diff --git a/src/test/ui/let-else/let-else-missing-semicolon.rs b/src/test/ui/let-else/let-else-missing-semicolon.rs index ed9d79f1e..d87ac90c1 100644 --- a/src/test/ui/let-else/let-else-missing-semicolon.rs +++ b/src/test/ui/let-else/let-else-missing-semicolon.rs @@ -1,5 +1,3 @@ -#![feature(let_else)] - fn main() { let Some(x) = Some(1) else { return; diff --git a/src/test/ui/let-else/let-else-missing-semicolon.stderr b/src/test/ui/let-else/let-else-missing-semicolon.stderr index 1818a0b12..99029ff33 100644 --- a/src/test/ui/let-else/let-else-missing-semicolon.stderr +++ b/src/test/ui/let-else/let-else-missing-semicolon.stderr @@ -1,5 +1,5 @@ error: expected `;`, found keyword `let` - --> $DIR/let-else-missing-semicolon.rs:6:6 + --> $DIR/let-else-missing-semicolon.rs:4:6 | LL | } | ^ help: add `;` here @@ -7,7 +7,7 @@ LL | let _ = ""; | --- unexpected token error: expected `;`, found `}` - --> $DIR/let-else-missing-semicolon.rs:10:6 + --> $DIR/let-else-missing-semicolon.rs:8:6 | LL | } | ^ help: add `;` here diff --git a/src/test/ui/let-else/let-else-no-double-error.rs b/src/test/ui/let-else/let-else-no-double-error.rs index 35dcdd3f6..91fcc5d7e 100644 --- a/src/test/ui/let-else/let-else-no-double-error.rs +++ b/src/test/ui/let-else/let-else-no-double-error.rs @@ -1,6 +1,6 @@ // from rfc2005 test suite -#![feature(let_else)] + // Without caching type lookups in FnCtxt.resolve_ty_and_def_ufcs // the error below would be reported twice (once when checking diff --git a/src/test/ui/let-else/let-else-non-copy.rs b/src/test/ui/let-else/let-else-non-copy.rs index 79ed82dd1..08c07dd1a 100644 --- a/src/test/ui/let-else/let-else-non-copy.rs +++ b/src/test/ui/let-else/let-else-non-copy.rs @@ -10,7 +10,7 @@ // // The move was due to mir::Place being Copy, but mir::VarDebugInfoContents not being Copy. -#![feature(let_else)] + #[derive(Copy, Clone)] struct Copyable; diff --git a/src/test/ui/let-else/let-else-non-diverging.rs b/src/test/ui/let-else/let-else-non-diverging.rs index a1cee335a..b5bd91ceb 100644 --- a/src/test/ui/let-else/let-else-non-diverging.rs +++ b/src/test/ui/let-else/let-else-non-diverging.rs @@ -1,5 +1,3 @@ -#![feature(let_else)] - fn main() { let Some(x) = Some(1) else { //~ ERROR does not diverge Some(2) diff --git a/src/test/ui/let-else/let-else-non-diverging.stderr b/src/test/ui/let-else/let-else-non-diverging.stderr index 05e45f689..c999a5495 100644 --- a/src/test/ui/let-else/let-else-non-diverging.stderr +++ b/src/test/ui/let-else/let-else-non-diverging.stderr @@ -1,5 +1,5 @@ error[E0308]: `else` clause of `let...else` does not diverge - --> $DIR/let-else-non-diverging.rs:4:32 + --> $DIR/let-else-non-diverging.rs:2:32 | LL | let Some(x) = Some(1) else { | ________________________________^ @@ -13,7 +13,7 @@ LL | | }; = help: ...or use `match` instead of `let...else` error[E0308]: `else` clause of `let...else` does not diverge - --> $DIR/let-else-non-diverging.rs:7:32 + --> $DIR/let-else-non-diverging.rs:5:32 | LL | let Some(x) = Some(1) else { | ________________________________^ @@ -29,7 +29,7 @@ LL | | }; = help: ...or use `match` instead of `let...else` error[E0308]: `else` clause of `let...else` does not diverge - --> $DIR/let-else-non-diverging.rs:12:32 + --> $DIR/let-else-non-diverging.rs:10:32 | LL | let Some(x) = Some(1) else { Some(2) }; | ^^^^^^^^^^^ expected `!`, found enum `Option` diff --git a/src/test/ui/let-else/let-else-ref-bindings-pass.rs b/src/test/ui/let-else/let-else-ref-bindings-pass.rs index f4abd6cc2..62fc65731 100644 --- a/src/test/ui/let-else/let-else-ref-bindings-pass.rs +++ b/src/test/ui/let-else/let-else-ref-bindings-pass.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(let_else)] + #![allow(unused_variables)] fn ref_() { diff --git a/src/test/ui/let-else/let-else-ref-bindings.rs b/src/test/ui/let-else/let-else-ref-bindings.rs index a4cd8e8c4..687e235d4 100644 --- a/src/test/ui/let-else/let-else-ref-bindings.rs +++ b/src/test/ui/let-else/let-else-ref-bindings.rs @@ -1,6 +1,6 @@ -#![feature(let_else)] #![allow(unused_variables)] + fn ref_() { let bytes: Vec<u8> = b"Hello"[..].to_vec(); let some = Some(bytes); diff --git a/src/test/ui/let-else/let-else-run-pass.rs b/src/test/ui/let-else/let-else-run-pass.rs index 5d9662323..a0fb6c683 100644 --- a/src/test/ui/let-else/let-else-run-pass.rs +++ b/src/test/ui/let-else/let-else-run-pass.rs @@ -1,6 +1,6 @@ // run-pass -#![feature(let_else)] + fn main() { #[allow(dead_code)] diff --git a/src/test/ui/let-else/let-else-scope.rs b/src/test/ui/let-else/let-else-scope.rs index f17682db4..78a67769e 100644 --- a/src/test/ui/let-else/let-else-scope.rs +++ b/src/test/ui/let-else/let-else-scope.rs @@ -1,5 +1,3 @@ -#![feature(let_else)] - fn main() { let Some(x) = Some(2) else { panic!("{}", x); //~ ERROR cannot find value `x` in this scope diff --git a/src/test/ui/let-else/let-else-scope.stderr b/src/test/ui/let-else/let-else-scope.stderr index 4b3936eac..3b4f09829 100644 --- a/src/test/ui/let-else/let-else-scope.stderr +++ b/src/test/ui/let-else/let-else-scope.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `x` in this scope - --> $DIR/let-else-scope.rs:5:22 + --> $DIR/let-else-scope.rs:3:22 | LL | panic!("{}", x); | ^ not found in this scope diff --git a/src/test/ui/let-else/let-else-slicing-error.rs b/src/test/ui/let-else/let-else-slicing-error.rs index 4022656a8..25770094b 100644 --- a/src/test/ui/let-else/let-else-slicing-error.rs +++ b/src/test/ui/let-else/let-else-slicing-error.rs @@ -1,5 +1,5 @@ // issue #92069 -#![feature(let_else)] + fn main() { let nums = vec![5, 4, 3, 2, 1]; diff --git a/src/test/ui/let-else/let-else-source-expr-nomove-pass.rs b/src/test/ui/let-else/let-else-source-expr-nomove-pass.rs index 2aa17ae8c..ee378abcf 100644 --- a/src/test/ui/let-else/let-else-source-expr-nomove-pass.rs +++ b/src/test/ui/let-else/let-else-source-expr-nomove-pass.rs @@ -1,7 +1,7 @@ // run-pass // issue #89688 -#![feature(let_else)] + fn example_let_else(value: Option<String>) { let Some(inner) = value else { diff --git a/src/test/ui/let-else/let-else-temp-borrowck.rs b/src/test/ui/let-else/let-else-temp-borrowck.rs index 3910d35e7..6b4642d2f 100644 --- a/src/test/ui/let-else/let-else-temp-borrowck.rs +++ b/src/test/ui/let-else/let-else-temp-borrowck.rs @@ -3,7 +3,7 @@ // from issue #93951, where borrowck complained the temporary that `foo(&x)` was stored in was to // be dropped sometime after `x` was. It then suggested adding a semicolon that was already there. -#![feature(let_else)] + use std::fmt::Debug; fn foo<'a>(x: &'a str) -> Result<impl Debug + 'a, ()> { diff --git a/src/test/ui/let-else/let-else-temporary-lifetime.rs b/src/test/ui/let-else/let-else-temporary-lifetime.rs index 9c86901b9..c23eaa997 100644 --- a/src/test/ui/let-else/let-else-temporary-lifetime.rs +++ b/src/test/ui/let-else/let-else-temporary-lifetime.rs @@ -1,5 +1,5 @@ // run-pass -#![feature(let_else)] +// compile-flags: -Zvalidate-mir use std::fmt::Display; use std::rc::Rc; @@ -75,6 +75,17 @@ fn main() { } } { + fn must_pass() { + let rc = Rc::new(()); + let &None = &Some(Rc::clone(&rc)) else { + Rc::try_unwrap(rc).unwrap(); + return; + }; + unreachable!(); + } + must_pass(); + } + { // test let-else drops temps before else block // NOTE: this test has to be the last block in the `main` // body. diff --git a/src/test/ui/let-else/let-else-then-diverge.rs b/src/test/ui/let-else/let-else-then-diverge.rs new file mode 100644 index 000000000..1c8f7d758 --- /dev/null +++ b/src/test/ui/let-else/let-else-then-diverge.rs @@ -0,0 +1,19 @@ +// +// popped up in in #94012, where an alternative desugaring was +// causing unreachable code errors + + +#![deny(unused_variables)] +#![deny(unreachable_code)] + +fn let_else_diverge() -> bool { + let Some(_) = Some("test") else { + let x = 5; //~ ERROR unused variable: `x` + return false; + }; + return true; +} + +fn main() { + let_else_diverge(); +} diff --git a/src/test/ui/let-else/let-else-then-diverge.stderr b/src/test/ui/let-else/let-else-then-diverge.stderr new file mode 100644 index 000000000..ceb61029d --- /dev/null +++ b/src/test/ui/let-else/let-else-then-diverge.stderr @@ -0,0 +1,14 @@ +error: unused variable: `x` + --> $DIR/let-else-then-diverge.rs:11:13 + | +LL | let x = 5; + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | +note: the lint level is defined here + --> $DIR/let-else-then-diverge.rs:6:9 + | +LL | #![deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/let-else/let-else.rs b/src/test/ui/let-else/let-else.rs new file mode 100644 index 000000000..3505533e6 --- /dev/null +++ b/src/test/ui/let-else/let-else.rs @@ -0,0 +1,8 @@ +// run-pass + +fn main() { + let Some(x) = Some(1) else { + return; + }; + assert_eq!(x, 1); +} |