about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAmanieu d'Antras <amanieu@gmail.com>2022-01-12 20:45:31 +0000
committerAmanieu d'Antras <amanieu@gmail.com>2022-01-17 00:39:34 +0000
commitfe9dc6e62a312bc2fe01bb5ea65ea5d027ce878d (patch)
tree945ace8c55bb41eb8ab713d06f0174b36d39d316
parent528c4f9158ead3df8cecb51663db50e711fec377 (diff)
downloadrust-fe9dc6e62a312bc2fe01bb5ea65ea5d027ce878d.tar.gz
rust-fe9dc6e62a312bc2fe01bb5ea65ea5d027ce878d.zip
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.
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs27
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs10
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--library/core/src/panicking.rs25
-rw-r--r--src/test/codegen/unwind-and-panic-abort.rs2
6 files changed, 60 insertions, 6 deletions
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 5ce4e606fd2..b1a76b80002 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -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);
     }
 
+    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.
     fn codegen_panic_intrinsic(
         &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::Abort => {
-                bx.abort();
-                // `abort` does not terminate the block, so we still need to generate
-                // an `unreachable` terminator after it.
-                bx.unreachable();
+                self.codegen_abort_terminator(helper, bx, terminator);
             }
 
             mir::TerminatorKind::Goto { target } => {
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index def0c1d0687..be4849d0b84 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -283,6 +283,7 @@ language_item_table! {
     PanicInfo,               sym::panic_info,          panic_info,                 Target::Struct,         GenericRequirement::None;
     PanicLocation,           sym::panic_location,      panic_location,             Target::Struct,         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
     BeginPanic,              sym::begin_panic,         begin_panic_fn,             Target::Fn,             GenericRequirement::None;
 
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 7e7f6938706..7f13da5d38f 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -807,10 +807,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                     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::SwitchInt { .. }
             | mir::TerminatorKind::Resume
-            | mir::TerminatorKind::Abort
             | mir::TerminatorKind::Return
             | mir::TerminatorKind::Unreachable => {}
             mir::TerminatorKind::GeneratorDrop
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 14ac286476c..1e9c8eab2a9 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -983,6 +983,7 @@ symbols! {
         panic_implementation,
         panic_info,
         panic_location,
+        panic_no_unwind,
         panic_runtime,
         panic_str,
         panic_unwind,
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index f260f19127b..5078eea07a1 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -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)
 }
 
+#[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.
 ///
 /// This is designed to reduce the amount of code required at the call
diff --git a/src/test/codegen/unwind-and-panic-abort.rs b/src/test/codegen/unwind-and-panic-abort.rs
index 05d97f3256a..f238741e599 100644
--- a/src/test/codegen/unwind-and-panic-abort.rs
+++ b/src/test/codegen/unwind-and-panic-abort.rs
@@ -9,7 +9,7 @@ extern "C-unwind" {
 
 // CHECK: Function Attrs:{{.*}}nounwind
 // CHECK-NEXT: define{{.*}}void @foo
-// CHECK: call void @llvm.trap()
+// CHECK: call void @_ZN4core9panicking15panic_no_unwind
 #[no_mangle]
 pub unsafe extern "C" fn foo() {
     bar();