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.
This commit is contained in:
parent
528c4f9158
commit
fe9dc6e62a
6 changed files with 60 additions and 6 deletions
|
@ -477,6 +477,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup);
|
helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn codegen_abort_terminator(
|
||||||
|
&mut self,
|
||||||
|
helper: TerminatorCodegenHelper<'tcx>,
|
||||||
|
mut bx: Bx,
|
||||||
|
terminator: &mir::Terminator<'tcx>,
|
||||||
|
) {
|
||||||
|
let span = terminator.source_info.span;
|
||||||
|
self.set_debug_loc(&mut bx, terminator.source_info);
|
||||||
|
|
||||||
|
// Get the location information.
|
||||||
|
let location = self.get_caller_location(&mut bx, terminator.source_info).immediate();
|
||||||
|
|
||||||
|
// Obtain the panic entry point.
|
||||||
|
let def_id = common::langcall(bx.tcx(), Some(span), "", LangItem::PanicNoUnwind);
|
||||||
|
let instance = ty::Instance::mono(bx.tcx(), def_id);
|
||||||
|
let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
|
||||||
|
let llfn = bx.get_fn_addr(instance);
|
||||||
|
|
||||||
|
// Codegen the actual panic invoke/call.
|
||||||
|
helper.do_call(self, &mut bx, fn_abi, llfn, &[location], None, None);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns `true` if this is indeed a panic intrinsic and codegen is done.
|
/// Returns `true` if this is indeed a panic intrinsic and codegen is done.
|
||||||
fn codegen_panic_intrinsic(
|
fn codegen_panic_intrinsic(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -1014,10 +1036,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
mir::TerminatorKind::Resume => self.codegen_resume_terminator(helper, bx),
|
mir::TerminatorKind::Resume => self.codegen_resume_terminator(helper, bx),
|
||||||
|
|
||||||
mir::TerminatorKind::Abort => {
|
mir::TerminatorKind::Abort => {
|
||||||
bx.abort();
|
self.codegen_abort_terminator(helper, bx, terminator);
|
||||||
// `abort` does not terminate the block, so we still need to generate
|
|
||||||
// an `unreachable` terminator after it.
|
|
||||||
bx.unreachable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mir::TerminatorKind::Goto { target } => {
|
mir::TerminatorKind::Goto { target } => {
|
||||||
|
|
|
@ -283,6 +283,7 @@ language_item_table! {
|
||||||
PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None;
|
PanicInfo, sym::panic_info, panic_info, Target::Struct, GenericRequirement::None;
|
||||||
PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None;
|
PanicLocation, sym::panic_location, panic_location, Target::Struct, GenericRequirement::None;
|
||||||
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
|
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
|
||||||
|
PanicNoUnwind, sym::panic_no_unwind, panic_no_unwind, Target::Fn, GenericRequirement::Exact(0);
|
||||||
/// libstd panic entry point. Necessary for const eval to be able to catch it
|
/// libstd panic entry point. Necessary for const eval to be able to catch it
|
||||||
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
|
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
|
||||||
|
|
||||||
|
|
|
@ -807,10 +807,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
||||||
self.output.push(create_fn_mono_item(tcx, instance, source));
|
self.output.push(create_fn_mono_item(tcx, instance, source));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mir::TerminatorKind::Abort { .. } => {
|
||||||
|
let instance = Instance::mono(
|
||||||
|
tcx,
|
||||||
|
tcx.require_lang_item(LangItem::PanicNoUnwind, Some(source)),
|
||||||
|
);
|
||||||
|
if should_codegen_locally(tcx, &instance) {
|
||||||
|
self.output.push(create_fn_mono_item(tcx, instance, source));
|
||||||
|
}
|
||||||
|
}
|
||||||
mir::TerminatorKind::Goto { .. }
|
mir::TerminatorKind::Goto { .. }
|
||||||
| mir::TerminatorKind::SwitchInt { .. }
|
| mir::TerminatorKind::SwitchInt { .. }
|
||||||
| mir::TerminatorKind::Resume
|
| mir::TerminatorKind::Resume
|
||||||
| mir::TerminatorKind::Abort
|
|
||||||
| mir::TerminatorKind::Return
|
| mir::TerminatorKind::Return
|
||||||
| mir::TerminatorKind::Unreachable => {}
|
| mir::TerminatorKind::Unreachable => {}
|
||||||
mir::TerminatorKind::GeneratorDrop
|
mir::TerminatorKind::GeneratorDrop
|
||||||
|
|
|
@ -983,6 +983,7 @@ symbols! {
|
||||||
panic_implementation,
|
panic_implementation,
|
||||||
panic_info,
|
panic_info,
|
||||||
panic_location,
|
panic_location,
|
||||||
|
panic_no_unwind,
|
||||||
panic_runtime,
|
panic_runtime,
|
||||||
panic_str,
|
panic_str,
|
||||||
panic_unwind,
|
panic_unwind,
|
||||||
|
|
|
@ -77,6 +77,31 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
|
||||||
panic!("index out of bounds: the len is {} but the index is {}", len, index)
|
panic!("index out of bounds: the len is {} but the index is {}", len, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(bootstrap))]
|
||||||
|
#[cold]
|
||||||
|
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
|
||||||
|
#[track_caller]
|
||||||
|
#[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function
|
||||||
|
fn panic_no_unwind() -> ! {
|
||||||
|
if cfg!(feature = "panic_immediate_abort") {
|
||||||
|
super::intrinsics::abort()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
|
||||||
|
// that gets resolved to the `#[panic_handler]` function.
|
||||||
|
extern "Rust" {
|
||||||
|
#[lang = "panic_impl"]
|
||||||
|
fn panic_impl(pi: &PanicInfo<'_>) -> !;
|
||||||
|
}
|
||||||
|
|
||||||
|
// PanicInfo with the `can_unwind` flag set to false forces an abort.
|
||||||
|
let fmt = format_args!("panic in a function that cannot unwind");
|
||||||
|
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
|
||||||
|
|
||||||
|
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
|
||||||
|
unsafe { panic_impl(&pi) }
|
||||||
|
}
|
||||||
|
|
||||||
/// The entry point for panicking with a formatted message.
|
/// The entry point for panicking with a formatted message.
|
||||||
///
|
///
|
||||||
/// This is designed to reduce the amount of code required at the call
|
/// This is designed to reduce the amount of code required at the call
|
||||||
|
|
|
@ -9,7 +9,7 @@ extern "C-unwind" {
|
||||||
|
|
||||||
// CHECK: Function Attrs:{{.*}}nounwind
|
// CHECK: Function Attrs:{{.*}}nounwind
|
||||||
// CHECK-NEXT: define{{.*}}void @foo
|
// CHECK-NEXT: define{{.*}}void @foo
|
||||||
// CHECK: call void @llvm.trap()
|
// CHECK: call void @_ZN4core9panicking15panic_no_unwind
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn foo() {
|
pub unsafe extern "C" fn foo() {
|
||||||
bar();
|
bar();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue