Skip to content

Commit 99e34a4

Browse files
authored
Rollup merge of #135976 - WaffleLapkin:tailcall-nodrop, r=oli-obk
Don't drop types with no drop glue when building drops for tailcalls this is required as otherwise drops of `&mut` refs count as a usage of a 'two-phase temporary' causing an ICE. fixes #128097 The underlying issue is that the current code generates drops for `&mut` which are later counted as a second use of a two-phase temporary: `bat t.rs -p` ```rust #![expect(incomplete_features)] #![feature(explicit_tail_calls)] fn f(x: &mut ()) { let _y = String::new(); become f(x); } fn main() {} ``` `rustc t.rs -Zdump_mir=f` ```text error: internal compiler error: compiler/rustc_borrowck/src/borrow_set.rs:298:17: found two uses for 2-phase borrow temporary _4: bb2[1] and bb3[0] --> t.rs:6:5 | 6 | become f(x); | ^^^^^^^^^^^ thread 'rustc' panicked at compiler/rustc_borrowck/src/borrow_set.rs:298:17: Box<dyn Any> stack backtrace: [REDACTED] error: aborting due to 1 previous error ``` `bat ./mir_dump/t.f.-------.renumber.0.mir -p -lrust` ```rust // MIR for `f` 0 renumber fn f(_1: &mut ()) -> () { debug x => _1; let mut _0: (); let mut _2: !; let _3: std::string::String; let mut _4: &mut (); scope 1 { debug _y => _3; } bb0: { StorageLive(_3); _3 = String::new() -> [return: bb1, unwind: bb4]; } bb1: { FakeRead(ForLet(None), _3); StorageLive(_4); _4 = &mut (*_1); drop(_3) -> [return: bb2, unwind: bb3]; } bb2: { StorageDead(_3); tailcall f(Spanned { node: move _4, span: t.rs:6:14: 6:15 (#0) }); } bb3 (cleanup): { drop(_4) -> [return: bb4, unwind terminate(cleanup)]; } bb4 (cleanup): { resume; } } ``` Note how `_4 is moved into the tail call in `bb2` and dropped in `bb3`. This PR adds a check that the locals we drop need dropping. r? `@oli-obk` (feel free to reassign, I'm not sure who would be a good reviewer, but thought you might have an idea) cc `@beepster4096,` since you wrote the original drop implementation.
2 parents 8824ae6 + 9b82f20 commit 99e34a4

13 files changed

+28
-20
lines changed

Diff for: compiler/rustc_mir_build/src/builder/scope.rs

+9
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
785785
let local =
786786
place.as_local().unwrap_or_else(|| bug!("projection in tail call args"));
787787

788+
if !self.local_decls[local].ty.needs_drop(self.tcx, self.typing_env()) {
789+
return None;
790+
}
791+
788792
Some(DropData { source_info, local, kind: DropKind::Value })
789793
}
790794
Operand::Constant(_) => None,
@@ -795,6 +799,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
795799
self.scopes.scopes.iter().rev().nth(1).unwrap().region_scope,
796800
DUMMY_SP,
797801
);
802+
let typing_env = self.typing_env();
798803
let unwind_drops = &mut self.scopes.unwind_drops;
799804

800805
// the innermost scope contains only the destructors for the tail call arguments
@@ -805,6 +810,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
805810
let source_info = drop_data.source_info;
806811
let local = drop_data.local;
807812

813+
if !self.local_decls[local].ty.needs_drop(self.tcx, typing_env) {
814+
continue;
815+
}
816+
808817
match drop_data.kind {
809818
DropKind::Value => {
810819
// `unwind_to` should drop the value that we're about to

Diff for: src/tools/miri/tests/fail/tail_calls/dangling-local-var.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ LL | let local = 0;
1414
help: ALLOC was deallocated here:
1515
--> tests/fail/tail_calls/dangling-local-var.rs:LL:CC
1616
|
17-
LL | }
18-
| ^
17+
LL | become g(ptr)
18+
| ^^^^^^^^^^^^^
1919
= note: BACKTRACE (of the first span):
2020
= note: inside `g` at tests/fail/tail_calls/dangling-local-var.rs:LL:CC
2121
note: inside `main`

Diff for: tests/crashes/128097.rs

-6
This file was deleted.

Diff for: tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-abort.diff

-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@
6666
bb6: {
6767
+ _8 = const false;
6868
StorageDead(_4);
69-
StorageDead(_3);
7069
drop(_2) -> [return: bb7, unwind: bb12];
7170
}
7271

Diff for: tests/mir-opt/tail_call_drops.f.ElaborateDrops.panic-unwind.diff

-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@
6666
bb6: {
6767
+ _8 = const false;
6868
StorageDead(_4);
69-
StorageDead(_3);
7069
- drop(_2) -> [return: bb7, unwind continue];
7170
+ drop(_2) -> [return: bb7, unwind: bb12];
7271
}

Diff for: tests/mir-opt/tail_call_drops.f.built.after.panic-abort.mir

-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ fn f() -> () {
6363

6464
bb6: {
6565
StorageDead(_4);
66-
StorageDead(_3);
6766
drop(_2) -> [return: bb7, unwind: bb17];
6867
}
6968

Diff for: tests/mir-opt/tail_call_drops.f.built.after.panic-unwind.mir

-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ fn f() -> () {
6363

6464
bb6: {
6565
StorageDead(_4);
66-
StorageDead(_3);
6766
drop(_2) -> [return: bb7, unwind: bb17];
6867
}
6968

Diff for: tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-abort.diff

-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@
8080
bb8: {
8181
+ _12 = const false;
8282
StorageDead(_6);
83-
StorageDead(_5);
8483
drop(_4) -> [return: bb9, unwind: bb16];
8584
}
8685

Diff for: tests/mir-opt/tail_call_drops.f_with_arg.ElaborateDrops.panic-unwind.diff

-1
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,6 @@
8080
bb8: {
8181
+ _12 = const false;
8282
StorageDead(_6);
83-
StorageDead(_5);
8483
drop(_4) -> [return: bb9, unwind: bb16];
8584
}
8685

Diff for: tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-abort.mir

-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ fn f_with_arg(_1: String, _2: String) -> () {
7777

7878
bb8: {
7979
StorageDead(_6);
80-
StorageDead(_5);
8180
drop(_4) -> [return: bb9, unwind: bb23];
8281
}
8382

Diff for: tests/mir-opt/tail_call_drops.f_with_arg.built.after.panic-unwind.mir

-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ fn f_with_arg(_1: String, _2: String) -> () {
7777

7878
bb8: {
7979
StorageDead(_6);
80-
StorageDead(_5);
8180
drop(_4) -> [return: bb9, unwind: bb23];
8281
}
8382

Diff for: tests/ui/explicit-tail-calls/ctfe-arg-bad-borrow.stderr

+3-4
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@ error[E0597]: `local` does not live long enough
44
LL | let local = Type;
55
| ----- binding `local` declared here
66
LL | become takes_borrow(&local);
7-
| ^^^^^^ borrowed value does not live long enough
8-
LL |
9-
LL | }
10-
| - `local` dropped here while still borrowed
7+
| ^^^^^^- `local` dropped here while still borrowed
8+
| |
9+
| borrowed value does not live long enough
1110

1211
error: aborting due to 1 previous error
1312

Diff for: tests/ui/explicit-tail-calls/two-phase.rs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// regression test for <https://github.com/rust-lang/rust/issues/112788>.
2+
// this test used to ICE because we tried to run drop glue of `x`
3+
// if dropping `_y` (happening at the `become` site) panicked and caused an unwind.
4+
//
5+
//@ check-pass
6+
#![expect(incomplete_features)]
7+
#![feature(explicit_tail_calls)]
8+
9+
fn f(x: &mut ()) {
10+
let _y = String::new();
11+
become f(x);
12+
}
13+
14+
fn main() {}

0 commit comments

Comments
 (0)