Skip to content

Commit b60f7b5

Browse files
committed
Auto merge of #115045 - RalfJung:unwind-terminate-reason, r=davidtwco
when terminating during unwinding, show the reason why With this, the output on double-panic becomes something like that: ``` thread 'main' panicked at src/tools/miri/tests/fail/panic/double_panic.rs:15:5: first note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at src/tools/miri/tests/fail/panic/double_panic.rs:10:9: second stack backtrace: 0: 0xbe273a - std::backtrace_rs::backtrace::miri::trace_unsynchronized::<&mut [closure@std::sys_common::backtrace::_print_fmt::{closure#1}]> at /home/r/src/rust/rustc.3/library/std/src/../../backtrace/src/backtrace/miri.rs:99:5 1: 0xbe22e6 - std::backtrace_rs::backtrace::miri::trace::<&mut [closure@std::sys_common::backtrace::_print_fmt::{closure#1}]> at /home/r/src/rust/rustc.3/library/std/src/../../backtrace/src/backtrace/miri.rs:62:14 2: 0xbe1086 - std::backtrace_rs::backtrace::trace_unsynchronized::<[closure@std::sys_common::backtrace::_print_fmt::{closure#1}]> at /home/r/src/rust/rustc.3/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5 3: 0xba3afd - std::sys_common::backtrace::_print_fmt at /home/r/src/rust/rustc.3/library/std/src/sys_common/backtrace.rs:67:5 4: 0xba2471 - <std::sys_common::backtrace::_print::DisplayBacktrace as std::fmt::Display>::fmt at /home/r/src/rust/rustc.3/library/std/src/sys_common/backtrace.rs:44:22 5: 0xbcf754 - core::fmt::rt::Argument::<'_>::fmt at /home/r/src/rust/rustc.3/library/core/src/fmt/rt.rs:138:9 6: 0x9b8f81 - std::fmt::write at /home/r/src/rust/rustc.3/library/core/src/fmt/mod.rs:1094:17 7: 0x21391d - <std::sys::unix::stdio::Stderr as std::io::Write>::write_fmt at /home/r/src/rust/rustc.3/library/std/src/io/mod.rs:1714:15 8: 0xba37b1 - std::sys_common::backtrace::_print at /home/r/src/rust/rustc.3/library/std/src/sys_common/backtrace.rs:47:5 9: 0xba365b - std::sys_common::backtrace::print at /home/r/src/rust/rustc.3/library/std/src/sys_common/backtrace.rs:34:9 10: 0x143c67 - std::panic_hook_with_disk_dump::{closure#1} at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:278:22 11: 0x144187 - std::panic_hook_with_disk_dump at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:312:9 12: 0x143659 - std::panicking::default_hook at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:239:5 13: 0x1482a7 - std::panicking::rust_panic_with_hook at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:729:13 14: 0x1475d5 - std::rt::begin_panic::<&str>::{closure#0} at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:650:9 15: 0xba496a - std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !> at /home/r/src/rust/rustc.3/library/std/src/sys_common/backtrace.rs:170:18 16: 0x147599 - std::rt::begin_panic::<&str> at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:649:12 17: 0x31916 - <Foo as std::ops::Drop>::drop at src/tools/miri/tests/fail/panic/double_panic.rs:10:9 18: 0x1a2b5e - std::ptr::drop_in_place::<Foo> - shim(Some(Foo)) at /home/r/src/rust/rustc.3/library/core/src/ptr/mod.rs:497:1 19: 0x202bf - main at src/tools/miri/tests/fail/panic/double_panic.rs:16:1 20: 0xcc6a8 - <fn() as std::ops::FnOnce<()>>::call_once - shim(fn()) at /home/r/src/rust/rustc.3/library/core/src/ops/function.rs:250:5 21: 0xba47d9 - std::sys_common::backtrace::__rust_begin_short_backtrace::<fn(), ()> at /home/r/src/rust/rustc.3/library/std/src/sys_common/backtrace.rs:154:18 22: 0x141a6a - std::rt::lang_start::<()>::{closure#0} at /home/r/src/rust/rustc.3/library/std/src/rt.rs:166:18 23: 0xcca18 - std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once at /home/r/src/rust/rustc.3/library/core/src/ops/function.rs:284:13 24: 0x146469 - std::panicking::try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32> at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:524:40 25: 0x145e09 - std::panicking::try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe> at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:488:19 26: 0x7b0ac - std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32> at /home/r/src/rust/rustc.3/library/std/src/panic.rs:142:14 27: 0x14189b - std::rt::lang_start_internal::{closure#2} at /home/r/src/rust/rustc.3/library/std/src/rt.rs:148:48 28: 0x146481 - std::panicking::try::do_call::<[closure@std::rt::lang_start_internal::{closure#2}], isize> at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:524:40 29: 0x145e2c - std::panicking::try::<isize, [closure@std::rt::lang_start_internal::{closure#2}]> at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:488:19 30: 0x7b0d5 - std::panic::catch_unwind::<[closure@std::rt::lang_start_internal::{closure#2}], isize> at /home/r/src/rust/rustc.3/library/std/src/panic.rs:142:14 31: 0x1418b0 - std::rt::lang_start_internal at /home/r/src/rust/rustc.3/library/std/src/rt.rs:148:20 32: 0x141a97 - std::rt::lang_start::<()> at /home/r/src/rust/rustc.3/library/std/src/rt.rs:165:17 thread 'main' panicked at /home/r/src/rust/rustc.3/library/core/src/panicking.rs:126:5: panic in a destructor during cleanup stack backtrace: 0: 0xe9f6d7 - std::backtrace_rs::backtrace::miri::trace_unsynchronized::<&mut [closure@std::sys_common::backtrace::_print_fmt::{closure#1}]> at /home/r/src/rust/rustc.3/library/std/src/../../backtrace/src/backtrace/miri.rs:99:5 1: 0xe9f27d - std::backtrace_rs::backtrace::miri::trace::<&mut [closure@std::sys_common::backtrace::_print_fmt::{closure#1}]> at /home/r/src/rust/rustc.3/library/std/src/../../backtrace/src/backtrace/miri.rs:62:14 2: 0xe9e016 - std::backtrace_rs::backtrace::trace_unsynchronized::<[closure@std::sys_common::backtrace::_print_fmt::{closure#1}]> at /home/r/src/rust/rustc.3/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5 3: 0xba3afd - std::sys_common::backtrace::_print_fmt at /home/r/src/rust/rustc.3/library/std/src/sys_common/backtrace.rs:67:5 4: 0xba2471 - <std::sys_common::backtrace::_print::DisplayBacktrace as std::fmt::Display>::fmt at /home/r/src/rust/rustc.3/library/std/src/sys_common/backtrace.rs:44:22 5: 0xbcf754 - core::fmt::rt::Argument::<'_>::fmt at /home/r/src/rust/rustc.3/library/core/src/fmt/rt.rs:138:9 6: 0x9b8f81 - std::fmt::write at /home/r/src/rust/rustc.3/library/core/src/fmt/mod.rs:1094:17 7: 0x4d0895 - <std::sys::unix::stdio::Stderr as std::io::Write>::write_fmt at /home/r/src/rust/rustc.3/library/std/src/io/mod.rs:1714:15 8: 0xba37b1 - std::sys_common::backtrace::_print at /home/r/src/rust/rustc.3/library/std/src/sys_common/backtrace.rs:47:5 9: 0xba365b - std::sys_common::backtrace::print at /home/r/src/rust/rustc.3/library/std/src/sys_common/backtrace.rs:34:9 10: 0x400bd4 - std::panic_hook_with_disk_dump::{closure#1} at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:278:22 11: 0x144187 - std::panic_hook_with_disk_dump at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:312:9 12: 0x143659 - std::panicking::default_hook at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:239:5 13: 0x1482a7 - std::panicking::rust_panic_with_hook at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:729:13 14: 0x40403b - std::panicking::begin_panic_handler::{closure#0} at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:619:13 15: 0xe618b3 - std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !> at /home/r/src/rust/rustc.3/library/std/src/sys_common/backtrace.rs:170:18 16: 0x403fc8 - std::panicking::begin_panic_handler at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:617:5 17: 0xee23e9 - core::panicking::panic_nounwind_fmt at /home/r/src/rust/rustc.3/library/core/src/panicking.rs:96:14 18: 0xee29e6 - core::panicking::panic_nounwind at /home/r/src/rust/rustc.3/library/core/src/panicking.rs:126:5 19: 0xee365e - core::panicking::panic_in_cleanup at /home/r/src/rust/rustc.3/library/core/src/panicking.rs:206:5 20: 0x2028a - main at src/tools/miri/tests/fail/panic/double_panic.rs:13:1 21: 0x3895ee - <fn() as std::ops::FnOnce<()>>::call_once - shim(fn()) at /home/r/src/rust/rustc.3/library/core/src/ops/function.rs:250:5 22: 0xe61725 - std::sys_common::backtrace::__rust_begin_short_backtrace::<fn(), ()> at /home/r/src/rust/rustc.3/library/std/src/sys_common/backtrace.rs:154:18 23: 0x3fe9aa - std::rt::lang_start::<()>::{closure#0} at /home/r/src/rust/rustc.3/library/std/src/rt.rs:166:18 24: 0x389962 - std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once at /home/r/src/rust/rustc.3/library/core/src/ops/function.rs:284:13 25: 0x4033b9 - std::panicking::try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32> at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:524:40 26: 0x402d58 - std::panicking::try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe> at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:488:19 27: 0x337ff7 - std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32> at /home/r/src/rust/rustc.3/library/std/src/panic.rs:142:14 28: 0x3fe7e7 - std::rt::lang_start_internal::{closure#2} at /home/r/src/rust/rustc.3/library/std/src/rt.rs:148:48 29: 0x4033d6 - std::panicking::try::do_call::<[closure@std::rt::lang_start_internal::{closure#2}], isize> at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:524:40 30: 0x402d7f - std::panicking::try::<isize, [closure@std::rt::lang_start_internal::{closure#2}]> at /home/r/src/rust/rustc.3/library/std/src/panicking.rs:488:19 31: 0x338028 - std::panic::catch_unwind::<[closure@std::rt::lang_start_internal::{closure#2}], isize> at /home/r/src/rust/rustc.3/library/std/src/panic.rs:142:14 32: 0x1418b0 - std::rt::lang_start_internal at /home/r/src/rust/rustc.3/library/std/src/rt.rs:148:20 33: 0x3fe9dc - std::rt::lang_start::<()> at /home/r/src/rust/rustc.3/library/std/src/rt.rs:165:17 thread caused non-unwinding panic. aborting. ``` If we also land #115020, the 2nd backtrace disappears, hopefully making the "panic in a destructor during cleanup" easier to see. Fixes #114954.
2 parents 4535d33 + df5a248 commit b60f7b5

File tree

105 files changed

+491
-307
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+491
-307
lines changed

compiler/rustc_borrowck/src/invalidation.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
202202
}
203203
}
204204
TerminatorKind::Goto { target: _ }
205-
| TerminatorKind::UnwindTerminate
205+
| TerminatorKind::UnwindTerminate(_)
206206
| TerminatorKind::Unreachable
207207
| TerminatorKind::FalseEdge { real_target: _, imaginary_target: _ }
208208
| TerminatorKind::FalseUnwind { real_target: _, unwind: _ } => {

compiler/rustc_borrowck/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
770770
}
771771

772772
TerminatorKind::Goto { target: _ }
773-
| TerminatorKind::UnwindTerminate
773+
| TerminatorKind::UnwindTerminate(_)
774774
| TerminatorKind::Unreachable
775775
| TerminatorKind::UnwindResume
776776
| TerminatorKind::Return
@@ -817,7 +817,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
817817
}
818818
}
819819

820-
TerminatorKind::UnwindTerminate
820+
TerminatorKind::UnwindTerminate(_)
821821
| TerminatorKind::Assert { .. }
822822
| TerminatorKind::Call { .. }
823823
| TerminatorKind::Drop { .. }

compiler/rustc_borrowck/src/type_check/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1334,7 +1334,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
13341334
match &term.kind {
13351335
TerminatorKind::Goto { .. }
13361336
| TerminatorKind::UnwindResume
1337-
| TerminatorKind::UnwindTerminate
1337+
| TerminatorKind::UnwindTerminate(_)
13381338
| TerminatorKind::Return
13391339
| TerminatorKind::GeneratorDrop
13401340
| TerminatorKind::Unreachable
@@ -1613,7 +1613,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
16131613
span_mirbug!(self, block_data, "resume on non-cleanup block!")
16141614
}
16151615
}
1616-
TerminatorKind::UnwindTerminate => {
1616+
TerminatorKind::UnwindTerminate(_) => {
16171617
if !is_cleanup {
16181618
span_mirbug!(self, block_data, "abort on non-cleanup block!")
16191619
}
@@ -1697,7 +1697,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
16971697
span_mirbug!(self, ctxt, "unwind on cleanup block")
16981698
}
16991699
}
1700-
UnwindAction::Unreachable | UnwindAction::Terminate => (),
1700+
UnwindAction::Unreachable | UnwindAction::Terminate(_) => (),
17011701
}
17021702
}
17031703

compiler/rustc_codegen_cranelift/src/base.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -474,8 +474,8 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
474474
*destination,
475475
);
476476
}
477-
TerminatorKind::UnwindTerminate => {
478-
codegen_panic_cannot_unwind(fx, source_info);
477+
TerminatorKind::UnwindTerminate(reason) => {
478+
codegen_unwind_terminate(fx, source_info, *reason);
479479
}
480480
TerminatorKind::UnwindResume => {
481481
// FIXME implement unwinding
@@ -971,13 +971,14 @@ pub(crate) fn codegen_panic_nounwind<'tcx>(
971971
codegen_panic_inner(fx, rustc_hir::LangItem::PanicNounwind, &args, source_info.span);
972972
}
973973

974-
pub(crate) fn codegen_panic_cannot_unwind<'tcx>(
974+
pub(crate) fn codegen_unwind_terminate<'tcx>(
975975
fx: &mut FunctionCx<'_, '_, 'tcx>,
976976
source_info: mir::SourceInfo,
977+
reason: UnwindTerminateReason,
977978
) {
978979
let args = [];
979980

980-
codegen_panic_inner(fx, rustc_hir::LangItem::PanicCannotUnwind, &args, source_info.span);
981+
codegen_panic_inner(fx, reason.lang_item(), &args, source_info.span);
981982
}
982983

983984
fn codegen_panic_inner<'tcx>(

compiler/rustc_codegen_cranelift/src/constant.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
551551
TerminatorKind::Goto { .. }
552552
| TerminatorKind::SwitchInt { .. }
553553
| TerminatorKind::UnwindResume
554-
| TerminatorKind::UnwindTerminate
554+
| TerminatorKind::UnwindTerminate(_)
555555
| TerminatorKind::Return
556556
| TerminatorKind::Unreachable
557557
| TerminatorKind::Drop { .. }

compiler/rustc_codegen_ssa/src/mir/analyze.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
285285
match data.terminator().kind {
286286
TerminatorKind::Goto { .. }
287287
| TerminatorKind::UnwindResume
288-
| TerminatorKind::UnwindTerminate
288+
| TerminatorKind::UnwindTerminate(_)
289289
| TerminatorKind::Return
290290
| TerminatorKind::GeneratorDrop
291291
| TerminatorKind::Unreachable

compiler/rustc_codegen_ssa/src/mir/block.rs

+76-73
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::MemFlags;
1212
use rustc_ast as ast;
1313
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
1414
use rustc_hir::lang_items::LangItem;
15-
use rustc_middle::mir::{self, AssertKind, SwitchTargets};
15+
use rustc_middle::mir::{self, AssertKind, SwitchTargets, UnwindTerminateReason};
1616
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
1717
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
1818
use rustc_middle::ty::{self, Instance, Ty};
@@ -178,7 +178,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
178178
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
179179
mir::UnwindAction::Continue => None,
180180
mir::UnwindAction::Unreachable => None,
181-
mir::UnwindAction::Terminate => {
181+
mir::UnwindAction::Terminate(reason) => {
182182
if fx.mir[self.bb].is_cleanup && base::wants_new_eh_instructions(fx.cx.tcx().sess) {
183183
// MSVC SEH will abort automatically if an exception tries to
184184
// propagate out from cleanup.
@@ -191,7 +191,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
191191

192192
None
193193
} else {
194-
Some(fx.terminate_block())
194+
Some(fx.terminate_block(reason))
195195
}
196196
}
197197
};
@@ -264,7 +264,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
264264
) -> MergingSucc {
265265
let unwind_target = match unwind {
266266
mir::UnwindAction::Cleanup(cleanup) => Some(self.llbb_with_cleanup(fx, cleanup)),
267-
mir::UnwindAction::Terminate => Some(fx.terminate_block()),
267+
mir::UnwindAction::Terminate(reason) => Some(fx.terminate_block(reason)),
268268
mir::UnwindAction::Continue => None,
269269
mir::UnwindAction::Unreachable => None,
270270
};
@@ -649,12 +649,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
649649
helper: TerminatorCodegenHelper<'tcx>,
650650
bx: &mut Bx,
651651
terminator: &mir::Terminator<'tcx>,
652+
reason: UnwindTerminateReason,
652653
) {
653654
let span = terminator.source_info.span;
654655
self.set_debug_loc(bx, terminator.source_info);
655656

656657
// Obtain the panic entry point.
657-
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), LangItem::PanicCannotUnwind);
658+
let (fn_abi, llfn) = common::build_langcall(bx, Some(span), reason.lang_item());
658659

659660
// Codegen the actual panic invoke/call.
660661
let merging_succ = helper.do_call(
@@ -1229,8 +1230,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
12291230
MergingSucc::False
12301231
}
12311232

1232-
mir::TerminatorKind::UnwindTerminate => {
1233-
self.codegen_terminate_terminator(helper, bx, terminator);
1233+
mir::TerminatorKind::UnwindTerminate(reason) => {
1234+
self.codegen_terminate_terminator(helper, bx, terminator, reason);
12341235
MergingSucc::False
12351236
}
12361237

@@ -1579,79 +1580,81 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
15791580
})
15801581
}
15811582

1582-
fn terminate_block(&mut self) -> Bx::BasicBlock {
1583-
self.terminate_block.unwrap_or_else(|| {
1584-
let funclet;
1585-
let llbb;
1586-
let mut bx;
1587-
if base::wants_msvc_seh(self.cx.sess()) {
1588-
// This is a basic block that we're aborting the program for,
1589-
// notably in an `extern` function. These basic blocks are inserted
1590-
// so that we assert that `extern` functions do indeed not panic,
1591-
// and if they do we abort the process.
1592-
//
1593-
// On MSVC these are tricky though (where we're doing funclets). If
1594-
// we were to do a cleanuppad (like below) the normal functions like
1595-
// `longjmp` would trigger the abort logic, terminating the
1596-
// program. Instead we insert the equivalent of `catch(...)` for C++
1597-
// which magically doesn't trigger when `longjmp` files over this
1598-
// frame.
1599-
//
1600-
// Lots more discussion can be found on #48251 but this codegen is
1601-
// modeled after clang's for:
1602-
//
1603-
// try {
1604-
// foo();
1605-
// } catch (...) {
1606-
// bar();
1607-
// }
1608-
//
1609-
// which creates an IR snippet like
1610-
//
1611-
// cs_terminate:
1612-
// %cs = catchswitch within none [%cp_terminate] unwind to caller
1613-
// cp_terminate:
1614-
// %cp = catchpad within %cs [null, i32 64, null]
1615-
// ...
1616-
1617-
llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate");
1618-
let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");
1619-
1620-
let mut cs_bx = Bx::build(self.cx, llbb);
1621-
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
1622-
1623-
// The "null" here is actually a RTTI type descriptor for the
1624-
// C++ personality function, but `catch (...)` has no type so
1625-
// it's null. The 64 here is actually a bitfield which
1626-
// represents that this is a catch-all block.
1627-
bx = Bx::build(self.cx, cp_llbb);
1628-
let null =
1629-
bx.const_null(bx.type_ptr_ext(bx.cx().data_layout().instruction_address_space));
1630-
let sixty_four = bx.const_i32(64);
1631-
funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null]));
1632-
} else {
1633-
llbb = Bx::append_block(self.cx, self.llfn, "terminate");
1634-
bx = Bx::build(self.cx, llbb);
1583+
fn terminate_block(&mut self, reason: UnwindTerminateReason) -> Bx::BasicBlock {
1584+
if let Some((cached_bb, cached_reason)) = self.terminate_block && reason == cached_reason {
1585+
return cached_bb;
1586+
}
16351587

1636-
let llpersonality = self.cx.eh_personality();
1637-
bx.filter_landing_pad(llpersonality);
1588+
let funclet;
1589+
let llbb;
1590+
let mut bx;
1591+
if base::wants_msvc_seh(self.cx.sess()) {
1592+
// This is a basic block that we're aborting the program for,
1593+
// notably in an `extern` function. These basic blocks are inserted
1594+
// so that we assert that `extern` functions do indeed not panic,
1595+
// and if they do we abort the process.
1596+
//
1597+
// On MSVC these are tricky though (where we're doing funclets). If
1598+
// we were to do a cleanuppad (like below) the normal functions like
1599+
// `longjmp` would trigger the abort logic, terminating the
1600+
// program. Instead we insert the equivalent of `catch(...)` for C++
1601+
// which magically doesn't trigger when `longjmp` files over this
1602+
// frame.
1603+
//
1604+
// Lots more discussion can be found on #48251 but this codegen is
1605+
// modeled after clang's for:
1606+
//
1607+
// try {
1608+
// foo();
1609+
// } catch (...) {
1610+
// bar();
1611+
// }
1612+
//
1613+
// which creates an IR snippet like
1614+
//
1615+
// cs_terminate:
1616+
// %cs = catchswitch within none [%cp_terminate] unwind to caller
1617+
// cp_terminate:
1618+
// %cp = catchpad within %cs [null, i32 64, null]
1619+
// ...
1620+
1621+
llbb = Bx::append_block(self.cx, self.llfn, "cs_terminate");
1622+
let cp_llbb = Bx::append_block(self.cx, self.llfn, "cp_terminate");
1623+
1624+
let mut cs_bx = Bx::build(self.cx, llbb);
1625+
let cs = cs_bx.catch_switch(None, None, &[cp_llbb]);
1626+
1627+
// The "null" here is actually a RTTI type descriptor for the
1628+
// C++ personality function, but `catch (...)` has no type so
1629+
// it's null. The 64 here is actually a bitfield which
1630+
// represents that this is a catch-all block.
1631+
bx = Bx::build(self.cx, cp_llbb);
1632+
let null =
1633+
bx.const_null(bx.type_ptr_ext(bx.cx().data_layout().instruction_address_space));
1634+
let sixty_four = bx.const_i32(64);
1635+
funclet = Some(bx.catch_pad(cs, &[null, sixty_four, null]));
1636+
} else {
1637+
llbb = Bx::append_block(self.cx, self.llfn, "terminate");
1638+
bx = Bx::build(self.cx, llbb);
16381639

1639-
funclet = None;
1640-
}
1640+
let llpersonality = self.cx.eh_personality();
1641+
bx.filter_landing_pad(llpersonality);
1642+
1643+
funclet = None;
1644+
}
16411645

1642-
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
1646+
self.set_debug_loc(&mut bx, mir::SourceInfo::outermost(self.mir.span));
16431647

1644-
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicCannotUnwind);
1645-
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
1648+
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, reason.lang_item());
1649+
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
16461650

1647-
let llret = bx.call(fn_ty, None, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
1648-
bx.do_not_inline(llret);
1651+
let llret = bx.call(fn_ty, None, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
1652+
bx.do_not_inline(llret);
16491653

1650-
bx.unreachable();
1654+
bx.unreachable();
16511655

1652-
self.terminate_block = Some(llbb);
1653-
llbb
1654-
})
1656+
self.terminate_block = Some((llbb, reason));
1657+
llbb
16551658
}
16561659

16571660
/// Get the backend `BasicBlock` for a MIR `BasicBlock`, either already

compiler/rustc_codegen_ssa/src/mir/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use rustc_index::IndexVec;
55
use rustc_middle::mir;
66
use rustc_middle::mir::interpret::ErrorHandled;
77
use rustc_middle::mir::traversal;
8+
use rustc_middle::mir::UnwindTerminateReason;
89
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, TyAndLayout};
910
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
1011
use rustc_target::abi::call::{FnAbi, PassMode};
@@ -83,8 +84,8 @@ pub struct FunctionCx<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
8384
/// Cached unreachable block
8485
unreachable_block: Option<Bx::BasicBlock>,
8586

86-
/// Cached terminate upon unwinding block
87-
terminate_block: Option<Bx::BasicBlock>,
87+
/// Cached terminate upon unwinding block and its reason
88+
terminate_block: Option<(Bx::BasicBlock, UnwindTerminateReason)>,
8889

8990
/// The location where each MIR arg/var/tmp/ret is stored. This is
9091
/// usually an `PlaceRef` representing an alloca, but not always:
@@ -174,7 +175,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
174175
let mut start_bx = Bx::build(cx, start_llbb);
175176

176177
if mir.basic_blocks.iter().any(|bb| {
177-
bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate))
178+
bb.is_cleanup || matches!(bb.terminator().unwind(), Some(mir::UnwindAction::Terminate(_)))
178179
}) {
179180
start_bx.set_personality_fn(cx.eh_personality());
180181
}

compiler/rustc_const_eval/src/interpret/eval_context.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -756,16 +756,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
756756
///
757757
/// If `target` is `UnwindAction::Unreachable`, that indicates the function does not allow
758758
/// unwinding, and doing so is UB.
759+
#[cold] // usually we have normal returns, not unwinding
759760
pub fn unwind_to_block(&mut self, target: mir::UnwindAction) -> InterpResult<'tcx> {
760761
self.frame_mut().loc = match target {
761762
mir::UnwindAction::Cleanup(block) => Left(mir::Location { block, statement_index: 0 }),
762763
mir::UnwindAction::Continue => Right(self.frame_mut().body.span),
763764
mir::UnwindAction::Unreachable => {
764765
throw_ub_custom!(fluent::const_eval_unreachable_unwind);
765766
}
766-
mir::UnwindAction::Terminate => {
767+
mir::UnwindAction::Terminate(reason) => {
767768
self.frame_mut().loc = Right(self.frame_mut().body.span);
768-
M::unwind_terminate(self)?;
769+
M::unwind_terminate(self, reason)?;
769770
// This might have pushed a new stack frame, or it terminated execution.
770771
// Either way, `loc` will not be updated.
771772
return Ok(());

compiler/rustc_const_eval/src/interpret/machine.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,10 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
222222
fn panic_nounwind(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: &str) -> InterpResult<'tcx>;
223223

224224
/// Called when unwinding reached a state where execution should be terminated.
225-
fn unwind_terminate(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx>;
225+
fn unwind_terminate(
226+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
227+
reason: mir::UnwindTerminateReason,
228+
) -> InterpResult<'tcx>;
226229

227230
/// Called for all binary operations where the LHS has pointer type.
228231
///
@@ -462,6 +465,7 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
462465

463466
/// Called immediately after a stack frame got popped, but before jumping back to the caller.
464467
/// The `locals` have already been destroyed!
468+
#[inline(always)]
465469
fn after_stack_pop(
466470
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
467471
_frame: Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
@@ -501,7 +505,10 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
501505
}
502506

503507
#[inline(always)]
504-
fn unwind_terminate(_ecx: &mut InterpCx<$mir, $tcx, Self>) -> InterpResult<$tcx> {
508+
fn unwind_terminate(
509+
_ecx: &mut InterpCx<$mir, $tcx, Self>,
510+
_reason: mir::UnwindTerminateReason,
511+
) -> InterpResult<$tcx> {
505512
unreachable!("unwinding cannot happen during compile-time evaluation")
506513
}
507514

0 commit comments

Comments
 (0)