about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-04-10 18:52:51 +0000
committerbors <bors@rust-lang.org>2024-04-10 18:52:51 +0000
commitb3bd7058c139e71bae0862ef8f8ac936208873e9 (patch)
treeb74588beab0654ccb6c6c343427929f434bf681f
parentc2239bca5b89a8d3573cc0fc0f2fa65c50edb79c (diff)
parentf4caa832dad4482ec1fa85bdbc3156c83cc948de (diff)
downloadrust-b3bd7058c139e71bae0862ef8f8ac936208873e9.tar.gz
rust-b3bd7058c139e71bae0862ef8f8ac936208873e9.zip
Auto merge of #121346 - m-ou-se:temp-lifetime-if-else-match, r=compiler-errors
Propagate temporary lifetime extension into if and match.

This PR makes this work:

```rust
let a = if true {
    ..;
    &temp() // used to error, but now gets lifetime extended
} else {
    ..;
    &temp() // used to error, but now gets lifetime extended
};
```

and

```rust
let a = match () {
    _ => {
        ..;
        &temp() // used to error, but now gets lifetime extended
    }
};
```

to make it consistent with:

```rust
let a = {
    ..;
    &temp() // lifetime is extended
};
```

This is one small part of [the temporary lifetimes work](https://github.com/rust-lang/lang-team/issues/253).

This part is backwards compatible (so doesn't need be edition-gated), because all code affected by this change previously resulted in a hard error.
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs13
-rw-r--r--tests/ui/borrowck/let_underscore_temporary.rs30
-rw-r--r--tests/ui/borrowck/let_underscore_temporary.stderr158
-rw-r--r--tests/ui/lifetimes/temporary-lifetime-extension.rs33
4 files changed, 119 insertions, 115 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 3bdb9a214ec..397893491a3 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -689,6 +689,8 @@ fn resolve_local<'tcx>(
     ///        | [ ..., E&, ... ]
     ///        | ( ..., E&, ... )
     ///        | {...; E&}
+    ///        | if _ { ...; E& } else { ...; E& }
+    ///        | match _ { ..., _ => E&, ... }
     ///        | box E&
     ///        | E& as ...
     ///        | ( E& )
@@ -727,6 +729,17 @@ fn resolve_local<'tcx>(
                     record_rvalue_scope_if_borrow_expr(visitor, subexpr, blk_id);
                 }
             }
+            hir::ExprKind::If(_, then_block, else_block) => {
+                record_rvalue_scope_if_borrow_expr(visitor, then_block, blk_id);
+                if let Some(else_block) = else_block {
+                    record_rvalue_scope_if_borrow_expr(visitor, else_block, blk_id);
+                }
+            }
+            hir::ExprKind::Match(_, arms, _) => {
+                for arm in arms {
+                    record_rvalue_scope_if_borrow_expr(visitor, arm.body, blk_id);
+                }
+            }
             hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) => {
                 // FIXME(@dingxiangfei2009): choose call arguments here
                 // for candidacy for extended parameter rule application
diff --git a/tests/ui/borrowck/let_underscore_temporary.rs b/tests/ui/borrowck/let_underscore_temporary.rs
index 0a24df08925..d1bdabd4eca 100644
--- a/tests/ui/borrowck/let_underscore_temporary.rs
+++ b/tests/ui/borrowck/let_underscore_temporary.rs
@@ -7,8 +7,9 @@ fn let_underscore(string: &Option<&str>, mut num: Option<i32>) {
         *s += 1;
         s
     } else {
-        &mut 0
-        //~^ ERROR temporary value dropped while borrowed
+        let a = 0;
+        &a
+        //~^ ERROR does not live long enough
     };
     let _ = if let Some(ref s) = num { s } else { &0 };
     let _ = if let Some(mut s) = num {
@@ -21,8 +22,9 @@ fn let_underscore(string: &Option<&str>, mut num: Option<i32>) {
         *s += 1;
         s
     } else {
-        &mut 0
-        //~^ ERROR temporary value dropped while borrowed
+        let a = 0;
+        &a
+        //~^ ERROR does not live long enough
     };
 }
 
@@ -33,8 +35,9 @@ fn let_ascribe(string: &Option<&str>, mut num: Option<i32>) {
         *s += 1;
         s
     } else {
-        &mut 0
-        //~^ ERROR temporary value dropped while borrowed
+        let a = 0;
+        &a
+        //~^ ERROR does not live long enough
     };
     let _: _ = if let Some(ref s) = num { s } else { &0 };
     let _: _ = if let Some(mut s) = num {
@@ -47,8 +50,9 @@ fn let_ascribe(string: &Option<&str>, mut num: Option<i32>) {
         *s += 1;
         s
     } else {
-        &mut 0
-        //~^ ERROR temporary value dropped while borrowed
+        let a = 0;
+        &a
+        //~^ ERROR does not live long enough
     };
 }
 
@@ -63,8 +67,9 @@ fn matched(string: &Option<&str>, mut num: Option<i32>) {
         *s += 1;
         s
     } else {
-        &mut 0
-        //~^ ERROR temporary value dropped while borrowed
+        let a = 0;
+        &a
+        //~^ ERROR does not live long enough
     } {
         _ => {}
     };
@@ -83,8 +88,9 @@ fn matched(string: &Option<&str>, mut num: Option<i32>) {
         *s += 1;
         s
     } else {
-        &mut 0
-        //~^ ERROR temporary value dropped while borrowed
+        let a = 0;
+        &a
+        //~^ ERROR does not live long enough
     } {
         _ => {}
     };
diff --git a/tests/ui/borrowck/let_underscore_temporary.stderr b/tests/ui/borrowck/let_underscore_temporary.stderr
index 6bccf329181..90b3462ebf8 100644
--- a/tests/ui/borrowck/let_underscore_temporary.stderr
+++ b/tests/ui/borrowck/let_underscore_temporary.stderr
@@ -1,117 +1,69 @@
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/let_underscore_temporary.rs:10:14
+error[E0597]: `a` does not live long enough
+  --> $DIR/let_underscore_temporary.rs:11:9
    |
-LL |       let _ = if let Some(s) = &mut num {
-   |  _____________-
-LL | |         *s += 1;
-LL | |         s
-LL | |     } else {
-LL | |         &mut 0
-   | |              ^ creates a temporary value which is freed while still in use
-LL | |
-LL | |     };
-   | |     -
-   | |     |
-   | |_____temporary value is freed at the end of this statement
-   |       borrow later used here
-   |
-   = note: consider using a `let` binding to create a longer lived value
+LL |         let a = 0;
+   |             - binding `a` declared here
+LL |         &a
+   |         ^^ borrowed value does not live long enough
+LL |
+LL |     };
+   |     - `a` dropped here while still borrowed
 
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/let_underscore_temporary.rs:24:14
-   |
-LL |       let _ = if let Some(ref mut s) = num {
-   |  _____________-
-LL | |         *s += 1;
-LL | |         s
-LL | |     } else {
-LL | |         &mut 0
-   | |              ^ creates a temporary value which is freed while still in use
-LL | |
-LL | |     };
-   | |     -
-   | |     |
-   | |_____temporary value is freed at the end of this statement
-   |       borrow later used here
+error[E0597]: `a` does not live long enough
+  --> $DIR/let_underscore_temporary.rs:26:9
    |
-   = note: consider using a `let` binding to create a longer lived value
+LL |         let a = 0;
+   |             - binding `a` declared here
+LL |         &a
+   |         ^^ borrowed value does not live long enough
+LL |
+LL |     };
+   |     - `a` dropped here while still borrowed
 
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/let_underscore_temporary.rs:36:14
-   |
-LL |       let _: _ = if let Some(s) = &mut num {
-   |  ________________-
-LL | |         *s += 1;
-LL | |         s
-LL | |     } else {
-LL | |         &mut 0
-   | |              ^ creates a temporary value which is freed while still in use
-LL | |
-LL | |     };
-   | |     -
-   | |     |
-   | |_____temporary value is freed at the end of this statement
-   |       borrow later used here
+error[E0597]: `a` does not live long enough
+  --> $DIR/let_underscore_temporary.rs:39:9
    |
-   = note: consider using a `let` binding to create a longer lived value
+LL |         let a = 0;
+   |             - binding `a` declared here
+LL |         &a
+   |         ^^ borrowed value does not live long enough
+LL |
+LL |     };
+   |     - `a` dropped here while still borrowed
 
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/let_underscore_temporary.rs:50:14
+error[E0597]: `a` does not live long enough
+  --> $DIR/let_underscore_temporary.rs:54:9
    |
-LL |       let _: _ = if let Some(ref mut s) = num {
-   |  ________________-
-LL | |         *s += 1;
-LL | |         s
-LL | |     } else {
-LL | |         &mut 0
-   | |              ^ creates a temporary value which is freed while still in use
-LL | |
-LL | |     };
-   | |     -
-   | |     |
-   | |_____temporary value is freed at the end of this statement
-   |       borrow later used here
-   |
-   = note: consider using a `let` binding to create a longer lived value
+LL |         let a = 0;
+   |             - binding `a` declared here
+LL |         &a
+   |         ^^ borrowed value does not live long enough
+LL |
+LL |     };
+   |     - `a` dropped here while still borrowed
 
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/let_underscore_temporary.rs:66:14
-   |
-LL |       match if let Some(s) = &mut num {
-   |  ___________-
-LL | |         *s += 1;
-LL | |         s
-LL | |     } else {
-LL | |         &mut 0
-   | |              ^ creates a temporary value which is freed while still in use
-LL | |
-LL | |     } {
-   | |     -
-   | |     |
-   | |_____temporary value is freed at the end of this statement
-   |       borrow later used here
+error[E0597]: `a` does not live long enough
+  --> $DIR/let_underscore_temporary.rs:71:9
    |
-   = note: consider using a `let` binding to create a longer lived value
+LL |         let a = 0;
+   |             - binding `a` declared here
+LL |         &a
+   |         ^^ borrowed value does not live long enough
+LL |
+LL |     } {
+   |     - `a` dropped here while still borrowed
 
-error[E0716]: temporary value dropped while borrowed
-  --> $DIR/let_underscore_temporary.rs:86:14
-   |
-LL |       match if let Some(ref mut s) = num {
-   |  ___________-
-LL | |         *s += 1;
-LL | |         s
-LL | |     } else {
-LL | |         &mut 0
-   | |              ^ creates a temporary value which is freed while still in use
-LL | |
-LL | |     } {
-   | |     -
-   | |     |
-   | |_____temporary value is freed at the end of this statement
-   |       borrow later used here
+error[E0597]: `a` does not live long enough
+  --> $DIR/let_underscore_temporary.rs:92:9
    |
-   = note: consider using a `let` binding to create a longer lived value
+LL |         let a = 0;
+   |             - binding `a` declared here
+LL |         &a
+   |         ^^ borrowed value does not live long enough
+LL |
+LL |     } {
+   |     - `a` dropped here while still borrowed
 
 error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0716`.
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/lifetimes/temporary-lifetime-extension.rs b/tests/ui/lifetimes/temporary-lifetime-extension.rs
new file mode 100644
index 00000000000..1ecef2f3d04
--- /dev/null
+++ b/tests/ui/lifetimes/temporary-lifetime-extension.rs
@@ -0,0 +1,33 @@
+//@ check-pass
+
+fn temp() -> (String, i32) {
+    (String::from("Hello"), 1)
+}
+
+fn main() {
+    let a = &temp();
+    let b = [(&temp(),)];
+    let c = &temp().0;
+    let d = &temp().0[..];
+    let e = {
+        let _ = 123;
+        &(*temp().0)[..]
+    };
+    let f = if true {
+        &temp()
+    } else {
+        &temp()
+    };
+    let g = match true {
+        true => &temp(),
+        false => {
+            let _ = 123;
+            &temp()
+        }
+    };
+    let h = match temp() {
+        // The {} moves the value, making a new temporary.
+        owned_non_temporary => &{ owned_non_temporary },
+    };
+    println!("{a:?} {b:?} {c:?} {d:?} {e:?} {f:?} {g:?} {h:?}");
+}