Skip to content

Commit fe9dc6e

Browse files
committed
Change TerminatorKind::Abort to call the panic handler instead of
aborting immediately. The panic handler is called with a special flag which forces it to abort after calling the panic hook.
1 parent 528c4f9 commit fe9dc6e

File tree

6 files changed

+60
-6
lines changed

6 files changed

+60
-6
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

+23-4
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
477477
helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup);
478478
}
479479

480+
fn codegen_abort_terminator(
481+
&mut self,
482+
helper: TerminatorCodegenHelper<'tcx>,
483+
mut bx: Bx,
484+
terminator: &mir::Terminator<'tcx>,
485+
) {
486+
let span = terminator.source_info.span;
487+
self.set_debug_loc(&mut bx, terminator.source_info);
488+
489+
// Get the location information.
490+
let location = self.get_caller_location(&mut bx, terminator.source_info).immediate();
491+
492+
// Obtain the panic entry point.
493+
let def_id = common::langcall(bx.tcx(), Some(span), "", LangItem::PanicNoUnwind);
494+
let instance = ty::Instance::mono(bx.tcx(), def_id);
495+
let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
496+
let llfn = bx.get_fn_addr(instance);
497+
498+
// Codegen the actual panic invoke/call.
499+
helper.do_call(self, &mut bx, fn_abi, llfn, &[location], None, None);
500+
}
501+
480502
/// Returns `true` if this is indeed a panic intrinsic and codegen is done.
481503
fn codegen_panic_intrinsic(
482504
&mut self,
@@ -1014,10 +1036,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10141036
mir::TerminatorKind::Resume => self.codegen_resume_terminator(helper, bx),
10151037

10161038
mir::TerminatorKind::Abort => {
1017-
bx.abort();
1018-
// `abort` does not terminate the block, so we still need to generate
1019-
// an `unreachable` terminator after it.
1020-
bx.unreachable();
1039+
self.codegen_abort_terminator(helper, bx, terminator);
10211040
}
10221041

10231042
mir::TerminatorKind::Goto { target } => {

compiler/rustc_hir/src/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ language_item_table! {
283283
PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None;
284284
PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None;
285285
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
286+
PanicNoUnwind, sym::panic_no_unwind, panic_no_unwind, Target::Fn, GenericRequirement::Exact(0);
286287
/// libstd panic entry point. Necessary for const eval to be able to catch it
287288
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
288289

compiler/rustc_monomorphize/src/collector.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -807,10 +807,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
807807
self.output.push(create_fn_mono_item(tcx, instance, source));
808808
}
809809
}
810+
mir::TerminatorKind::Abort { .. } => {
811+
let instance = Instance::mono(
812+
tcx,
813+
tcx.require_lang_item(LangItem::PanicNoUnwind, Some(source)),
814+
);
815+
if should_codegen_locally(tcx, &instance) {
816+
self.output.push(create_fn_mono_item(tcx, instance, source));
817+
}
818+
}
810819
mir::TerminatorKind::Goto { .. }
811820
| mir::TerminatorKind::SwitchInt { .. }
812821
| mir::TerminatorKind::Resume
813-
| mir::TerminatorKind::Abort
814822
| mir::TerminatorKind::Return
815823
| mir::TerminatorKind::Unreachable => {}
816824
mir::TerminatorKind::GeneratorDrop

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,7 @@ symbols! {
983983
panic_implementation,
984984
panic_info,
985985
panic_location,
986+
panic_no_unwind,
986987
panic_runtime,
987988
panic_str,
988989
panic_unwind,

library/core/src/panicking.rs

+25
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,31 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
7777
panic!("index out of bounds: the len is {} but the index is {}", len, index)
7878
}
7979

80+
#[cfg(not(bootstrap))]
81+
#[cold]
82+
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
83+
#[track_caller]
84+
#[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function
85+
fn panic_no_unwind() -> ! {
86+
if cfg!(feature = "panic_immediate_abort") {
87+
super::intrinsics::abort()
88+
}
89+
90+
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
91+
// that gets resolved to the `#[panic_handler]` function.
92+
extern "Rust" {
93+
#[lang = "panic_impl"]
94+
fn panic_impl(pi: &PanicInfo<'_>) -> !;
95+
}
96+
97+
// PanicInfo with the `can_unwind` flag set to false forces an abort.
98+
let fmt = format_args!("panic in a function that cannot unwind");
99+
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
100+
101+
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
102+
unsafe { panic_impl(&pi) }
103+
}
104+
80105
/// The entry point for panicking with a formatted message.
81106
///
82107
/// This is designed to reduce the amount of code required at the call

src/test/codegen/unwind-and-panic-abort.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ extern "C-unwind" {
99

1010
// CHECK: Function Attrs:{{.*}}nounwind
1111
// CHECK-NEXT: define{{.*}}void @foo
12-
// CHECK: call void @llvm.trap()
12+
// CHECK: call void @_ZN4core9panicking15panic_no_unwind
1313
#[no_mangle]
1414
pub unsafe extern "C" fn foo() {
1515
bar();

0 commit comments

Comments
 (0)