about summary refs log tree commit diff
diff options
context:
space:
mode:
authordianne <diannes.gm@gmail.com>2025-08-24 22:48:00 -0700
committerdianne <diannes.gm@gmail.com>2025-09-04 10:14:25 -0700
commit0976d6ccac3d71befb58ceefd3109864f0eb210d (patch)
tree06b3ba5b75734c0f6d1206d89817157f3b12dfd2
parent9fd57df6397b0e2b0cd4db32884ed5e5443c7906 (diff)
downloadrust-0976d6ccac3d71befb58ceefd3109864f0eb210d.tar.gz
rust-0976d6ccac3d71befb58ceefd3109864f0eb210d.zip
don't extend non-extended `super let` initializers' block tail temps
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs24
-rw-r--r--tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr14
-rw-r--r--tests/ui/borrowck/format-args-temporary-scopes.rs1
-rw-r--r--tests/ui/drop/super-let-tail-expr-drop-order.rs14
4 files changed, 40 insertions, 13 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index f5770b7312d..58521697b38 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -467,8 +467,12 @@ fn resolve_local<'tcx>(
     // A, but the inner rvalues `a()` and `b()` have an extended lifetime
     // due to rule C.
 
-    if let_kind == LetKind::Super {
-        if let Some(scope) = visitor.extended_super_lets.remove(&pat.unwrap().hir_id.local_id) {
+    let extend_initializer = match let_kind {
+        LetKind::Regular => true,
+        LetKind::Super
+            if let Some(scope) =
+                visitor.extended_super_lets.remove(&pat.unwrap().hir_id.local_id) =>
+        {
             // This expression was lifetime-extended by a parent let binding. E.g.
             //
             //     let a = {
@@ -481,7 +485,10 @@ fn resolve_local<'tcx>(
             // Processing of `let a` will have already decided to extend the lifetime of this
             // `super let` to its own var_scope. We use that scope.
             visitor.cx.var_parent = scope;
-        } else {
+            // Extend temporaries to live in the same scope as the parent `let`'s bindings.
+            true
+        }
+        LetKind::Super => {
             // This `super let` is not subject to lifetime extension from a parent let binding. E.g.
             //
             //     identity({ super let x = temp(); &x }).method();
@@ -497,10 +504,17 @@ fn resolve_local<'tcx>(
                 }
                 visitor.cx.var_parent = parent;
             }
+            // Don't lifetime-extend child `super let`s or block tail expressions' temporaries in
+            // the initializer when this `super let` is not itself extended by a parent `let`
+            // (#145784). Block tail expressions are temporary drop scopes in Editions 2024 and
+            // later, their temps shouldn't outlive the block in e.g. `f(pin!({ &temp() }))`.
+            false
         }
-    }
+    };
 
-    if let Some(expr) = init {
+    if let Some(expr) = init
+        && extend_initializer
+    {
         record_rvalue_scope_if_borrow_expr(visitor, expr, visitor.cx.var_parent);
 
         if let Some(pat) = pat {
diff --git a/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr b/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr
index 923c929a68d..506fc6e0965 100644
--- a/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr
+++ b/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr
@@ -10,6 +10,18 @@ LL |     println!("{:?}", { &temp() });
    |
    = note: consider using a `let` binding to create a longer lived value
 
-error: aborting due to 1 previous error
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/format-args-temporary-scopes.rs:19:29
+   |
+LL |     println!("{:?}{:?}", { &temp() }, ());
+   |                          ---^^^^^---
+   |                          |  |    |
+   |                          |  |    temporary value is freed at the end of this statement
+   |                          |  creates a temporary value which is freed while still in use
+   |                          borrow later used here
+   |
+   = note: consider using a `let` binding to create a longer lived value
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/borrowck/format-args-temporary-scopes.rs b/tests/ui/borrowck/format-args-temporary-scopes.rs
index e6223d7c551..2641058accb 100644
--- a/tests/ui/borrowck/format-args-temporary-scopes.rs
+++ b/tests/ui/borrowck/format-args-temporary-scopes.rs
@@ -17,4 +17,5 @@ fn main() {
     // arguments when provided with two or more arguments. This caused the result of `temp()` to
     // outlive the result of the block, making this compile.
     println!("{:?}{:?}", { &temp() }, ());
+    //[e2024]~^ ERROR: temporary value dropped while borrowed [E0716]
 }
diff --git a/tests/ui/drop/super-let-tail-expr-drop-order.rs b/tests/ui/drop/super-let-tail-expr-drop-order.rs
index 5aa17bba21f..8ec9296ed4f 100644
--- a/tests/ui/drop/super-let-tail-expr-drop-order.rs
+++ b/tests/ui/drop/super-let-tail-expr-drop-order.rs
@@ -45,10 +45,10 @@ fn main() {
         #[cfg(e2024)]
         (
             pin!((
-                pin!({ &o.log(3) as *const LogDrop<'_> }),
-                drop(o.log(1)),
+                pin!({ &o.log(1) as *const LogDrop<'_> }),
+                drop(o.log(2)),
             )),
-            drop(o.log(2)),
+            drop(o.log(3)),
         );
     });
 
@@ -69,12 +69,12 @@ fn main() {
         (
             {
                 super let _ = {
-                    super let _ = { &o.log(4) as *const LogDrop<'_> };
-                    drop(o.log(1))
+                    super let _ = { &o.log(1) as *const LogDrop<'_> };
+                    drop(o.log(2))
                 };
-                drop(o.log(2))
+                drop(o.log(3))
             },
-            drop(o.log(3)),
+            drop(o.log(4)),
         );
     });