summaryrefslogtreecommitdiffstats
path: root/src/test/ui/let-else
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/let-else')
-rw-r--r--src/test/ui/let-else/const-fn.rs19
-rw-r--r--src/test/ui/let-else/issue-100103.rs15
-rw-r--r--src/test/ui/let-else/issue-102317.rs20
-rw-r--r--src/test/ui/let-else/issue-94176.rs10
-rw-r--r--src/test/ui/let-else/issue-94176.stderr19
-rw-r--r--src/test/ui/let-else/issue-99975.rs20
-rw-r--r--src/test/ui/let-else/let-else-allow-in-expr.rs2
-rw-r--r--src/test/ui/let-else/let-else-allow-in-expr.stderr6
-rw-r--r--src/test/ui/let-else/let-else-allow-unused.rs2
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-annotated.rs2
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-borrow.rs4
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-pass.rs2
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut.rs2
-rw-r--r--src/test/ui/let-else/let-else-binding-immutable.rs2
-rw-r--r--src/test/ui/let-else/let-else-bindings.rs2
-rw-r--r--src/test/ui/let-else/let-else-bool-binop-init.fixed2
-rw-r--r--src/test/ui/let-else/let-else-bool-binop-init.rs2
-rw-r--r--src/test/ui/let-else/let-else-brace-before-else.fixed2
-rw-r--r--src/test/ui/let-else/let-else-brace-before-else.rs2
-rw-r--r--src/test/ui/let-else/let-else-check.rs2
-rw-r--r--src/test/ui/let-else/let-else-check.stderr6
-rw-r--r--src/test/ui/let-else/let-else-deref-coercion-annotated.rs2
-rw-r--r--src/test/ui/let-else/let-else-deref-coercion.rs2
-rw-r--r--src/test/ui/let-else/let-else-destructuring.rs1
-rw-r--r--src/test/ui/let-else/let-else-destructuring.stderr4
-rw-r--r--src/test/ui/let-else/let-else-drop-order.rs270
-rw-r--r--src/test/ui/let-else/let-else-drop-order.run.stdout51
-rw-r--r--src/test/ui/let-else/let-else-if.rs2
-rw-r--r--src/test/ui/let-else/let-else-if.stderr2
-rw-r--r--src/test/ui/let-else/let-else-irrefutable.rs2
-rw-r--r--src/test/ui/let-else/let-else-missing-semicolon.rs2
-rw-r--r--src/test/ui/let-else/let-else-missing-semicolon.stderr4
-rw-r--r--src/test/ui/let-else/let-else-no-double-error.rs2
-rw-r--r--src/test/ui/let-else/let-else-non-copy.rs2
-rw-r--r--src/test/ui/let-else/let-else-non-diverging.rs2
-rw-r--r--src/test/ui/let-else/let-else-non-diverging.stderr6
-rw-r--r--src/test/ui/let-else/let-else-ref-bindings-pass.rs2
-rw-r--r--src/test/ui/let-else/let-else-ref-bindings.rs2
-rw-r--r--src/test/ui/let-else/let-else-run-pass.rs2
-rw-r--r--src/test/ui/let-else/let-else-scope.rs2
-rw-r--r--src/test/ui/let-else/let-else-scope.stderr2
-rw-r--r--src/test/ui/let-else/let-else-slicing-error.rs2
-rw-r--r--src/test/ui/let-else/let-else-source-expr-nomove-pass.rs2
-rw-r--r--src/test/ui/let-else/let-else-temp-borrowck.rs2
-rw-r--r--src/test/ui/let-else/let-else-temporary-lifetime.rs13
-rw-r--r--src/test/ui/let-else/let-else-then-diverge.rs19
-rw-r--r--src/test/ui/let-else/let-else-then-diverge.stderr14
-rw-r--r--src/test/ui/let-else/let-else.rs8
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);
+}