From af2ce8b7022c92de0702bea09f2fb50b80343d2d Mon Sep 17 00:00:00 2001
From: Waffle Lapkin <waffle.lapkin@gmail.com>
Date: Fri, 24 Jan 2025 06:11:23 +0100
Subject: [PATCH] don't drop types with no drop glue when tailcalling

this is required as otherwise drops of `&mut` refs count as a usage of a
'two-phase temporary' causing an ICE.
---
 compiler/rustc_mir_build/src/builder/scope.rs            | 9 +++++++++
 .../tail_call_drops.f.ElaborateDrops.panic-abort.diff    | 1 -
 .../tail_call_drops.f.ElaborateDrops.panic-unwind.diff   | 1 -
 .../tail_call_drops.f.built.after.panic-abort.mir        | 1 -
 .../tail_call_drops.f.built.after.panic-unwind.mir       | 1 -
 ...call_drops.f_with_arg.ElaborateDrops.panic-abort.diff | 1 -
 ...all_drops.f_with_arg.ElaborateDrops.panic-unwind.diff | 1 -
 ...ail_call_drops.f_with_arg.built.after.panic-abort.mir | 1 -
 ...il_call_drops.f_with_arg.built.after.panic-unwind.mir | 1 -
 tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.stderr  | 7 +++----
 10 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs
index 20441530a47..945f02821d9 100644
--- a/compiler/rustc_mir_build/src/builder/scope.rs
+++ b/compiler/rustc_mir_build/src/builder/scope.rs
@@ -785,6 +785,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let local =
                         place.as_local().unwrap_or_else(|| bug!("projection in tail call args"));
 
+                    if !self.local_decls[local].ty.needs_drop(self.tcx, self.typing_env()) {
+                        return None;
+                    }
+
                     Some(DropData { source_info, local, kind: DropKind::Value })
                 }
                 Operand::Constant(_) => None,
@@ -795,6 +799,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             self.scopes.scopes.iter().rev().nth(1).unwrap().region_scope,
             DUMMY_SP,
         );
+        let typing_env = self.typing_env();
         let unwind_drops = &mut self.scopes.unwind_drops;
 
         // the innermost scope contains only the destructors for the tail call arguments
@@ -805,6 +810,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 let source_info = drop_data.source_info;
                 let local = drop_data.local;
 
+                if !self.local_decls[local].ty.needs_drop(self.tcx, typing_env) {
+                    continue;
+                }
+
                 match drop_data.kind {
                     DropKind::Value => {
                         // `unwind_to` should drop the value that we're about to
diff --git a/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-abort.diff b/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-abort.diff
index 17c64d4baf0..9a4f27a497d 100644
--- a/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-abort.diff
+++ b/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-abort.diff
@@ -66,7 +66,6 @@
       bb6: {
 +         _8 = const false;
           StorageDead(_4);
-          StorageDead(_3);
           drop(_2) -> [return: bb7, unwind: bb12];
       }
   
diff --git a/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-unwind.diff b/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-unwind.diff
index 58d8a87986d..f13ee78aa36 100644
--- a/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-unwind.diff
+++ b/tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-unwind.diff
@@ -66,7 +66,6 @@
       bb6: {
 +         _8 = const false;
           StorageDead(_4);
-          StorageDead(_3);
 -         drop(_2) -> [return: bb7, unwind continue];
 +         drop(_2) -> [return: bb7, unwind: bb12];
       }
diff --git a/tests/mir-opt/tail_call_drops.f.built.after.panic-abort.mir b/tests/mir-opt/tail_call_drops.f.built.after.panic-abort.mir
index 2c3d62491d7..e017424a4cc 100644
--- a/tests/mir-opt/tail_call_drops.f.built.after.panic-abort.mir
+++ b/tests/mir-opt/tail_call_drops.f.built.after.panic-abort.mir
@@ -63,7 +63,6 @@ fn f() -> () {
 
     bb6: {
         StorageDead(_4);
-        StorageDead(_3);
         drop(_2) -> [return: bb7, unwind: bb17];
     }
 
diff --git a/tests/mir-opt/tail_call_drops.f.built.after.panic-unwind.mir b/tests/mir-opt/tail_call_drops.f.built.after.panic-unwind.mir
index 2c3d62491d7..e017424a4cc 100644
--- a/tests/mir-opt/tail_call_drops.f.built.after.panic-unwind.mir
+++ b/tests/mir-opt/tail_call_drops.f.built.after.panic-unwind.mir
@@ -63,7 +63,6 @@ fn f() -> () {
 
     bb6: {
         StorageDead(_4);
-        StorageDead(_3);
         drop(_2) -> [return: bb7, unwind: bb17];
     }
 
diff --git a/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-abort.diff b/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-abort.diff
index 1a51601bc56..a8c57d2cfe0 100644
--- a/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-abort.diff
+++ b/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-abort.diff
@@ -80,7 +80,6 @@
       bb8: {
 +         _12 = const false;
           StorageDead(_6);
-          StorageDead(_5);
           drop(_4) -> [return: bb9, unwind: bb16];
       }
   
diff --git a/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-unwind.diff b/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-unwind.diff
index 1a51601bc56..a8c57d2cfe0 100644
--- a/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-unwind.diff
+++ b/tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-unwind.diff
@@ -80,7 +80,6 @@
       bb8: {
 +         _12 = const false;
           StorageDead(_6);
-          StorageDead(_5);
           drop(_4) -> [return: bb9, unwind: bb16];
       }
   
diff --git a/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-abort.mir b/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-abort.mir
index 744f1989acc..f89b98a3205 100644
--- a/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-abort.mir
+++ b/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-abort.mir
@@ -77,7 +77,6 @@ fn f_with_arg(_1: String, _2: String) -> () {
 
     bb8: {
         StorageDead(_6);
-        StorageDead(_5);
         drop(_4) -> [return: bb9, unwind: bb23];
     }
 
diff --git a/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-unwind.mir b/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-unwind.mir
index 744f1989acc..f89b98a3205 100644
--- a/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-unwind.mir
+++ b/tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-unwind.mir
@@ -77,7 +77,6 @@ fn f_with_arg(_1: String, _2: String) -> () {
 
     bb8: {
         StorageDead(_6);
-        StorageDead(_5);
         drop(_4) -> [return: bb9, unwind: bb23];
     }
 
diff --git a/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.stderr b/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.stderr
index 75fb13c378c..ece581dc626 100644
--- a/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.stderr
+++ b/tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.stderr
@@ -4,10 +4,9 @@ error[E0597]: `local` does not live long enough
 LL |     let local = Type;
    |         ----- binding `local` declared here
 LL |     become takes_borrow(&local);
-   |                         ^^^^^^ borrowed value does not live long enough
-LL |
-LL | }
-   | - `local` dropped here while still borrowed
+   |                         ^^^^^^- `local` dropped here while still borrowed
+   |                         |
+   |                         borrowed value does not live long enough
 
 error: aborting due to 1 previous error