Skip to content

Commit 06d261d

Browse files
committed
Auto merge of #129582 - nbdd0121:unwind, r=nnethercote
Make destructors on `extern "C"` frames to be executed This would make the example in #123231 print "Noisy Drop". I didn't mark this as fixing the issue because the behaviour is yet to be spec'ed. Tracking: - #74990
2 parents dd51276 + bb53108 commit 06d261d

8 files changed

+99
-17
lines changed

Diff for: compiler/rustc_mir_transform/src/abort_unwinding_calls.rs

+19-6
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,20 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
5151
// This will filter to functions with `extern "C-unwind"` ABIs, for
5252
// example.
5353
for block in body.basic_blocks.as_mut() {
54+
let Some(terminator) = &mut block.terminator else { continue };
55+
let span = terminator.source_info.span;
56+
57+
// If we see an `UnwindResume` terminator inside a function that cannot unwind, we need
58+
// to replace it with `UnwindTerminate`.
59+
if let TerminatorKind::UnwindResume = &terminator.kind
60+
&& !body_can_unwind
61+
{
62+
terminator.kind = TerminatorKind::UnwindTerminate(UnwindTerminateReason::Abi);
63+
}
64+
5465
if block.is_cleanup {
5566
continue;
5667
}
57-
let Some(terminator) = &block.terminator else { continue };
58-
let span = terminator.source_info.span;
5968

6069
let call_can_unwind = match &terminator.kind {
6170
TerminatorKind::Call { func, .. } => {
@@ -87,14 +96,18 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
8796
if !call_can_unwind {
8897
// If this function call can't unwind, then there's no need for it
8998
// to have a landing pad. This means that we can remove any cleanup
90-
// registered for it.
99+
// registered for it (and turn it into `UnwindAction::Unreachable`).
91100
let cleanup = block.terminator_mut().unwind_mut().unwrap();
92101
*cleanup = UnwindAction::Unreachable;
93-
} else if !body_can_unwind {
102+
} else if !body_can_unwind
103+
&& matches!(terminator.unwind(), Some(UnwindAction::Continue))
104+
{
94105
// Otherwise if this function can unwind, then if the outer function
95106
// can also unwind there's nothing to do. If the outer function
96-
// can't unwind, however, we need to change the landing pad for this
97-
// function call to one that aborts.
107+
// can't unwind, however, we need to ensure that any `UnwindAction::Continue`
108+
// is replaced with terminate. For those with `UnwindAction::Cleanup`,
109+
// cleanup will still happen, and terminate will happen afterwards handled by
110+
// the `UnwindResume` -> `UnwindTerminate` terminator replacement.
98111
let cleanup = block.terminator_mut().unwind_mut().unwrap();
99112
*cleanup = UnwindAction::Terminate(UnwindTerminateReason::Abi);
100113
}

Diff for: tests/mir-opt/asm_unwind_panic_abort.main.AbortUnwindingCalls.after.mir

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@ fn main() -> () {
77
bb0: {
88
StorageLive(_1);
99
_1 = const ();
10-
asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind terminate(abi)];
10+
asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind: bb2];
1111
}
1212

1313
bb1: {
1414
StorageDead(_1);
1515
_0 = const ();
1616
return;
1717
}
18+
19+
bb2 (cleanup): {
20+
terminate(abi);
21+
}
1822
}

Diff for: tests/mir-opt/asm_unwind_panic_abort.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
fn main() {
1111
// CHECK-LABEL: fn main(
1212
// CHECK: asm!(
13-
// CHECK-SAME: unwind terminate(abi)
13+
// CHECK-SAME: unwind: [[unwind:bb.*]]]
14+
// CHECK: [[unwind]] (cleanup)
15+
// CHECK-NEXT: terminate(abi)
1416
unsafe {
1517
std::arch::asm!("", options(may_unwind));
1618
}

Diff for: tests/mir-opt/c_unwind_terminate.rs

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//@ needs-unwind
2+
3+
struct Noise;
4+
impl Drop for Noise {
5+
fn drop(&mut self) {
6+
eprintln!("Noisy Drop");
7+
}
8+
}
9+
10+
fn panic() {
11+
panic!();
12+
}
13+
14+
// EMIT_MIR c_unwind_terminate.test.AbortUnwindingCalls.after.mir
15+
extern "C" fn test() {
16+
// CHECK-LABEL: fn test(
17+
// CHECK: drop
18+
// CHECK-SAME: unwind: [[unwind:bb.*]]]
19+
// CHECK: [[unwind]] (cleanup)
20+
// CHECK-NEXT: terminate(abi)
21+
let _val = Noise;
22+
panic();
23+
}
24+
25+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// MIR for `test` after AbortUnwindingCalls
2+
3+
fn test() -> () {
4+
let mut _0: ();
5+
let _1: Noise;
6+
let _2: ();
7+
scope 1 {
8+
debug _val => _1;
9+
}
10+
11+
bb0: {
12+
StorageLive(_1);
13+
_1 = Noise;
14+
StorageLive(_2);
15+
_2 = panic() -> [return: bb1, unwind: bb3];
16+
}
17+
18+
bb1: {
19+
StorageDead(_2);
20+
_0 = const ();
21+
drop(_1) -> [return: bb2, unwind: bb4];
22+
}
23+
24+
bb2: {
25+
StorageDead(_1);
26+
return;
27+
}
28+
29+
bb3 (cleanup): {
30+
drop(_1) -> [return: bb4, unwind terminate(cleanup)];
31+
}
32+
33+
bb4 (cleanup): {
34+
terminate(abi);
35+
}
36+
}

Diff for: tests/run-make/longjmp-across-rust/main.rs

-8
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,11 @@ fn main() {
1010
}
1111
}
1212

13-
struct A;
14-
15-
impl Drop for A {
16-
fn drop(&mut self) {}
17-
}
18-
1913
extern "C" fn test_middle() {
20-
let _a = A;
2114
foo();
2215
}
2316

2417
fn foo() {
25-
let _a = A;
2618
unsafe {
2719
test_end();
2820
}

Diff for: tests/ui/panics/panic-in-ffi.rs

+9
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,22 @@
22
//@ exec-env:RUST_BACKTRACE=0
33
//@ check-run-results
44
//@ error-pattern: panic in a function that cannot unwind
5+
//@ error-pattern: Noisy Drop
56
//@ normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
67
//@ normalize-stderr-test: "\n +at [^\n]+" -> ""
78
//@ normalize-stderr-test: "(core/src/panicking\.rs):[0-9]+:[0-9]+" -> "$1:$$LINE:$$COL"
89
//@ needs-unwind
910
//@ ignore-emscripten "RuntimeError" junk in output
1011

12+
struct Noise;
13+
impl Drop for Noise {
14+
fn drop(&mut self) {
15+
eprintln!("Noisy Drop");
16+
}
17+
}
18+
1119
extern "C" fn panic_in_ffi() {
20+
let _val = Noise;
1221
panic!("Test");
1322
}
1423

Diff for: tests/ui/panics/panic-in-ffi.run.stderr

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
thread 'main' panicked at $DIR/panic-in-ffi.rs:12:5:
1+
thread 'main' panicked at $DIR/panic-in-ffi.rs:21:5:
22
Test
33
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
4+
Noisy Drop
45
thread 'main' panicked at core/src/panicking.rs:$LINE:$COL:
56
panic in a function that cannot unwind
67
stack backtrace:

0 commit comments

Comments
 (0)