about summary refs log tree commit diff
path: root/src/test/ui
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-07-13 19:32:33 +0530
committerGitHub <noreply@github.com>2022-07-13 19:32:33 +0530
commit0083cd2fd498edb6a4e37bf4c711d11364e0ef20 (patch)
treeae0410e11bd58462d2ad36d710b887bf6dcb6dff /src/test/ui
parentca4e39400ef33198e2715973d1c67a1d3cee15e7 (diff)
parent947cbda5eb557ee3015b2310adfc80a393e42051 (diff)
downloadrust-0083cd2fd498edb6a4e37bf4c711d11364e0ef20.tar.gz
rust-0083cd2fd498edb6a4e37bf4c711d11364e0ef20.zip
Rollup merge of #98574 - dingxiangfei2009:let-else-thir, r=oli-obk
Lower let-else in MIR

This MR will switch to lower let-else statements in MIR building instead.

To lower let-else in MIR, we build a mini-switch two branches. One branch leads to the matching case, and the other leads to the `else` block. This arrangement will allow temporary lifetime analysis running as-is so that the temporaries are properly extended according to the same rule applied to regular `let` statements.

cc https://github.com/rust-lang/rust/issues/87335

Fix #98672
Diffstat (limited to 'src/test/ui')
-rw-r--r--src/test/ui/async-await/async-await-let-else.rs53
-rw-r--r--src/test/ui/async-await/async-await-let-else.stderr94
-rw-r--r--src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr8
-rw-r--r--src/test/ui/let-else/let-else-check.stderr12
-rw-r--r--src/test/ui/let-else/let-else-non-diverging.stderr18
-rw-r--r--src/test/ui/let-else/let-else-ref-bindings.stderr16
-rw-r--r--src/test/ui/let-else/let-else-temporary-lifetime.rs25
7 files changed, 205 insertions, 21 deletions
diff --git a/src/test/ui/async-await/async-await-let-else.rs b/src/test/ui/async-await/async-await-let-else.rs
new file mode 100644
index 00000000000..7ea07ae9add
--- /dev/null
+++ b/src/test/ui/async-await/async-await-let-else.rs
@@ -0,0 +1,53 @@
+// edition:2021
+#![feature(let_else)]
+use std::rc::Rc;
+
+async fn foo(x: Option<bool>) {
+    let Some(_) = x else {
+        let r = Rc::new(());
+        bar().await
+    };
+}
+
+async fn bar() -> ! {
+    panic!()
+}
+
+fn is_send<T: Send>(_: T) {}
+
+async fn foo2(x: Option<bool>) {
+    let Some(_) = x else {
+        bar2(Rc::new(())).await
+    };
+}
+
+async fn bar2<T>(_: T) -> ! {
+    panic!()
+}
+
+async fn foo3(x: Option<bool>) {
+    let Some(_) = x else {
+        (Rc::new(()), bar().await);
+        return;
+    };
+}
+
+async fn foo4(x: Option<bool>) {
+    let Some(_) = x else {
+        let r = Rc::new(());
+        bar().await;
+        println!("{:?}", r);
+        return;
+    };
+}
+
+fn main() {
+    is_send(foo(Some(true)));
+    //~^ ERROR future cannot be sent between threads safely
+    is_send(foo2(Some(true)));
+    //~^ ERROR future cannot be sent between threads safely
+    is_send(foo3(Some(true)));
+    //~^ ERROR future cannot be sent between threads safely
+    is_send(foo4(Some(true)));
+    //~^ ERROR future cannot be sent between threads safely
+}
diff --git a/src/test/ui/async-await/async-await-let-else.stderr b/src/test/ui/async-await/async-await-let-else.stderr
new file mode 100644
index 00000000000..4d23e27c426
--- /dev/null
+++ b/src/test/ui/async-await/async-await-let-else.stderr
@@ -0,0 +1,94 @@
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:45:13
+   |
+LL |     is_send(foo(Some(true)));
+   |             ^^^^^^^^^^^^^^^ future returned by `foo` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:8:14
+   |
+LL |         let r = Rc::new(());
+   |             - has type `Rc<()>` which is not `Send`
+LL |         bar().await
+   |              ^^^^^^ await occurs here, with `r` maybe used later
+LL |     };
+   |     - `r` is later dropped here
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:16:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:47:13
+   |
+LL |     is_send(foo2(Some(true)));
+   |             ^^^^^^^^^^^^^^^^ future returned by `foo2` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:20:26
+   |
+LL |         bar2(Rc::new(())).await
+   |              ----------- ^^^^^^ await occurs here, with `Rc::new(())` maybe used later
+   |              |
+   |              has type `Rc<()>` which is not `Send`
+LL |     };
+   |      - `Rc::new(())` is later dropped here
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:16:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:49:13
+   |
+LL |     is_send(foo3(Some(true)));
+   |             ^^^^^^^^^^^^^^^^ future returned by `foo3` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:30:28
+   |
+LL |         (Rc::new(()), bar().await);
+   |          -----------       ^^^^^^ await occurs here, with `Rc::new(())` maybe used later
+   |          |
+   |          has type `Rc<()>` which is not `Send`
+note: `Rc::new(())` is later dropped here
+  --> $DIR/async-await-let-else.rs:30:35
+   |
+LL |         (Rc::new(()), bar().await);
+   |                                   ^
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:16:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: future cannot be sent between threads safely
+  --> $DIR/async-await-let-else.rs:51:13
+   |
+LL |     is_send(foo4(Some(true)));
+   |             ^^^^^^^^^^^^^^^^ future returned by `foo4` is not `Send`
+   |
+   = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `Rc<()>`
+note: future is not `Send` as this value is used across an await
+  --> $DIR/async-await-let-else.rs:38:14
+   |
+LL |         let r = Rc::new(());
+   |             - has type `Rc<()>` which is not `Send`
+LL |         bar().await;
+   |              ^^^^^^ await occurs here, with `r` maybe used later
+...
+LL |     };
+   |     - `r` is later dropped here
+note: required by a bound in `is_send`
+  --> $DIR/async-await-let-else.rs:16:15
+   |
+LL | fn is_send<T: Send>(_: T) {}
+   |               ^^^^ required by this bound in `is_send`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr
index fdec7e7f6a7..065787cab08 100644
--- a/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr
+++ b/src/test/ui/let-else/let-else-binding-explicit-mut-annotated.stderr
@@ -2,7 +2,9 @@ error[E0308]: mismatched types
   --> $DIR/let-else-binding-explicit-mut-annotated.rs:9:37
    |
 LL |     let Some(n): &mut Option<i32> = &&Some(5i32) else { return };
-   |                                     ^^^^^^^^^^^^ types differ in mutability
+   |                  ----------------   ^^^^^^^^^^^^ types differ in mutability
+   |                  |
+   |                  expected due to this
    |
    = note: expected mutable reference `&mut Option<i32>`
                       found reference `&&Option<i32>`
@@ -11,7 +13,9 @@ error[E0308]: mismatched types
   --> $DIR/let-else-binding-explicit-mut-annotated.rs:13:37
    |
 LL |     let Some(n): &mut Option<i32> = &&mut Some(5i32) else { return };
-   |                                     ^^^^^^^^^^^^^^^^ types differ in mutability
+   |                  ----------------   ^^^^^^^^^^^^^^^^ types differ in mutability
+   |                  |
+   |                  expected due to this
    |
    = note: expected mutable reference `&mut Option<i32>`
                       found reference `&&mut Option<i32>`
diff --git a/src/test/ui/let-else/let-else-check.stderr b/src/test/ui/let-else/let-else-check.stderr
index b3da412ec28..3d647a4c05d 100644
--- a/src/test/ui/let-else/let-else-check.stderr
+++ b/src/test/ui/let-else/let-else-check.stderr
@@ -1,8 +1,8 @@
 error: unused variable: `x`
-  --> $DIR/let-else-check.rs:18:9
+  --> $DIR/let-else-check.rs:14:13
    |
-LL |     let x = 1;
-   |         ^ help: if this is intentional, prefix it with an underscore: `_x`
+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
@@ -11,10 +11,10 @@ LL | #![deny(unused_variables)]
    |         ^^^^^^^^^^^^^^^^
 
 error: unused variable: `x`
-  --> $DIR/let-else-check.rs:14:13
+  --> $DIR/let-else-check.rs:18:9
    |
-LL |         let x = 1;
-   |             ^ help: if this is intentional, prefix it with an underscore: `_x`
+LL |     let x = 1;
+   |         ^ help: if this is intentional, prefix it with an underscore: `_x`
 
 error: aborting due to 2 previous errors
 
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 b961b16b6f6..05e45f68989 100644
--- a/src/test/ui/let-else/let-else-non-diverging.stderr
+++ b/src/test/ui/let-else/let-else-non-diverging.stderr
@@ -1,8 +1,11 @@
 error[E0308]: `else` clause of `let...else` does not diverge
-  --> $DIR/let-else-non-diverging.rs:12:32
+  --> $DIR/let-else-non-diverging.rs:4:32
    |
-LL |     let Some(x) = Some(1) else { Some(2) };
-   |                                ^^^^^^^^^^^ expected `!`, found enum `Option`
+LL |       let Some(x) = Some(1) else {
+   |  ________________________________^
+LL | |         Some(2)
+LL | |     };
+   | |_____^ expected `!`, found enum `Option`
    |
    = note: expected type `!`
               found enum `Option<{integer}>`
@@ -26,13 +29,10 @@ 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:4:32
+  --> $DIR/let-else-non-diverging.rs:12:32
    |
-LL |       let Some(x) = Some(1) else {
-   |  ________________________________^
-LL | |         Some(2)
-LL | |     };
-   | |_____^ expected `!`, found enum `Option`
+LL |     let Some(x) = Some(1) else { Some(2) };
+   |                                ^^^^^^^^^^^ expected `!`, found enum `Option`
    |
    = note: expected type `!`
               found enum `Option<{integer}>`
diff --git a/src/test/ui/let-else/let-else-ref-bindings.stderr b/src/test/ui/let-else/let-else-ref-bindings.stderr
index 650f4ec5e77..56b9e073330 100644
--- a/src/test/ui/let-else/let-else-ref-bindings.stderr
+++ b/src/test/ui/let-else/let-else-ref-bindings.stderr
@@ -20,7 +20,9 @@ error[E0308]: mismatched types
   --> $DIR/let-else-ref-bindings.rs:24:34
    |
 LL |     let Some(a): Option<&[u8]> = some else { return };
-   |                                  ^^^^ expected `&[u8]`, found struct `Vec`
+   |                  -------------   ^^^^ expected `&[u8]`, found struct `Vec`
+   |                  |
+   |                  expected due to this
    |
    = note: expected enum `Option<&[u8]>`
               found enum `Option<Vec<u8>>`
@@ -29,7 +31,9 @@ error[E0308]: mismatched types
   --> $DIR/let-else-ref-bindings.rs:27:34
    |
 LL |     let Some(a): Option<&[u8]> = &some else { return };
-   |                                  ^^^^^ expected enum `Option`, found `&Option<Vec<u8>>`
+   |                  -------------   ^^^^^ expected enum `Option`, found `&Option<Vec<u8>>`
+   |                  |
+   |                  expected due to this
    |
    = note:   expected enum `Option<&[u8]>`
            found reference `&Option<Vec<u8>>`
@@ -56,7 +60,9 @@ error[E0308]: mismatched types
   --> $DIR/let-else-ref-bindings.rs:52:38
    |
 LL |     let Some(a): Option<&mut [u8]> = some else { return };
-   |                                      ^^^^ expected `&mut [u8]`, found struct `Vec`
+   |                  -----------------   ^^^^ expected `&mut [u8]`, found struct `Vec`
+   |                  |
+   |                  expected due to this
    |
    = note: expected enum `Option<&mut [u8]>`
               found enum `Option<Vec<u8>>`
@@ -65,7 +71,9 @@ error[E0308]: mismatched types
   --> $DIR/let-else-ref-bindings.rs:55:38
    |
 LL |     let Some(a): Option<&mut [u8]> = &mut some else { return };
-   |                                      ^^^^^^^^^ expected enum `Option`, found mutable reference
+   |                  -----------------   ^^^^^^^^^ expected enum `Option`, found mutable reference
+   |                  |
+   |                  expected due to this
    |
    = note:           expected enum `Option<&mut [u8]>`
            found mutable reference `&mut Option<Vec<u8>>`
diff --git a/src/test/ui/let-else/let-else-temporary-lifetime.rs b/src/test/ui/let-else/let-else-temporary-lifetime.rs
new file mode 100644
index 00000000000..624c2ea37a7
--- /dev/null
+++ b/src/test/ui/let-else/let-else-temporary-lifetime.rs
@@ -0,0 +1,25 @@
+// run-pass
+#![feature(let_else)]
+
+use std::sync::atomic::{AtomicU8, Ordering};
+
+static TRACKER: AtomicU8 = AtomicU8::new(0);
+
+#[derive(Default)]
+struct Droppy {
+    inner: u32,
+}
+
+impl Drop for Droppy {
+    fn drop(&mut self) {
+        TRACKER.store(1, Ordering::Release);
+        println!("I've been dropped");
+    }
+}
+
+fn main() {
+    assert_eq!(TRACKER.load(Ordering::Acquire), 0);
+    let 0 = Droppy::default().inner else { return };
+    assert_eq!(TRACKER.load(Ordering::Acquire), 1);
+    println!("Should have dropped 👆");
+}