about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorBen Kimock <kimockb@gmail.com>2025-09-07 12:31:35 -0400
committerBen Kimock <kimockb@gmail.com>2025-09-21 13:12:18 -0400
commit888679013d1f424adef06267f3630069b4cabd40 (patch)
treed0dab028dffe29ac7a2591552494daa182ff5090 /compiler
parent6710835ae739ca326441ff6c63d24fb123858300 (diff)
downloadrust-888679013d1f424adef06267f3630069b4cabd40.tar.gz
rust-888679013d1f424adef06267f3630069b4cabd40.zip
Add panic=immediate-abort
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs10
-rw-r--r--compiler/rustc_codegen_gcc/src/base.rs4
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs3
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs10
-rw-r--r--compiler/rustc_interface/messages.ftl2
-rw-r--r--compiler/rustc_interface/src/passes.rs3
-rw-r--r--compiler/rustc_metadata/messages.ftl7
-rw-r--r--compiler/rustc_metadata/src/creader.rs4
-rw-r--r--compiler/rustc_metadata/src/dependency_format.rs47
-rw-r--r--compiler/rustc_metadata/src/errors.rs10
-rw-r--r--compiler/rustc_middle/src/middle/lang_items.rs1
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs8
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs3
-rw-r--r--compiler/rustc_mir_transform/src/ffi_unwind_calls.rs9
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs3
-rw-r--r--compiler/rustc_session/src/config.rs9
-rw-r--r--compiler/rustc_session/src/config/cfg.rs7
-rw-r--r--compiler/rustc_session/src/options.rs4
-rw-r--r--compiler/rustc_session/src/session.rs10
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs6
23 files changed, 116 insertions, 50 deletions
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 51089e5a1d3..82c59d5a3a2 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -63,8 +63,8 @@ pub fn inject(
 
     if sess.is_test_crate() {
         let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) {
-            (PanicStrategy::Abort, true) => PanicStrategy::Abort,
-            (PanicStrategy::Abort, false) => {
+            (PanicStrategy::Abort | PanicStrategy::ImmediateAbort, true) => panic_strategy,
+            (PanicStrategy::Abort | PanicStrategy::ImmediateAbort, false) => {
                 if panic_strategy == platform_panic_strategy {
                     // Silently allow compiling with panic=abort on these platforms,
                     // but with old behavior (abort if a test fails).
@@ -287,10 +287,8 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box<ast::Item> {
     let ecx = &cx.ext_cx;
     let test_ident = Ident::new(sym::test, sp);
 
-    let runner_name = match cx.panic_strategy {
-        PanicStrategy::Unwind => "test_main_static",
-        PanicStrategy::Abort => "test_main_static_abort",
-    };
+    let runner_name =
+        if cx.panic_strategy.unwinds() { "test_main_static" } else { "test_main_static_abort" };
 
     // test::test_main_static(...)
     let mut test_runner = cx.test_runner.clone().unwrap_or_else(|| {
diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs
index e9d72e457a0..e8672f49580 100644
--- a/compiler/rustc_codegen_gcc/src/base.rs
+++ b/compiler/rustc_codegen_gcc/src/base.rs
@@ -15,9 +15,9 @@ use rustc_middle::mir::mono::Visibility;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::DebugInfo;
 use rustc_span::Symbol;
+use rustc_target::spec::RelocModel;
 #[cfg(feature = "master")]
 use rustc_target::spec::SymbolVisibility;
-use rustc_target::spec::{PanicStrategy, RelocModel};
 
 use crate::builder::Builder;
 use crate::context::CodegenCx;
@@ -101,7 +101,7 @@ pub fn compile_codegen_unit(
         // Instantiate monomorphizations without filling out definitions yet...
         let context = new_context(tcx);
 
-        if tcx.sess.panic_strategy() == PanicStrategy::Unwind {
+        if tcx.sess.panic_strategy().unwinds() {
             context.add_command_line_option("-fexceptions");
             context.add_driver_option("-fexceptions");
         }
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 84fa56cf903..a915f5d6418 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -29,7 +29,6 @@ use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, Instance, Ty};
 use rustc_span::{Span, Symbol, sym};
 use rustc_target::callconv::{ArgAbi, PassMode};
-use rustc_target::spec::PanicStrategy;
 
 #[cfg(feature = "master")]
 use crate::abi::FnAbiGccExt;
@@ -1334,7 +1333,7 @@ fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(
     _catch_func: RValue<'gcc>,
     dest: PlaceRef<'tcx, RValue<'gcc>>,
 ) {
-    if bx.sess().panic_strategy() == PanicStrategy::Abort {
+    if !bx.sess().panic_strategy().unwinds() {
         bx.call(bx.type_void(), None, None, try_func, &[data], None, None);
         // Return 0 unconditionally from the intrinsic call;
         // we can never unwind.
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index e7f4a357048..50398a32142 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -18,7 +18,6 @@ use rustc_middle::{bug, span_bug};
 use rustc_span::{Span, Symbol, sym};
 use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate};
 use rustc_target::callconv::PassMode;
-use rustc_target::spec::PanicStrategy;
 use tracing::debug;
 
 use crate::abi::FnAbiLlvmExt;
@@ -674,7 +673,7 @@ fn catch_unwind_intrinsic<'ll, 'tcx>(
     catch_func: &'ll Value,
     dest: PlaceRef<'tcx, &'ll Value>,
 ) {
-    if bx.sess().panic_strategy() == PanicStrategy::Abort {
+    if !bx.sess().panic_strategy().unwinds() {
         let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
         bx.call(try_func_ty, None, None, try_func, &[data], None, None);
         // Return 0 unconditionally from the intrinsic call;
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 45c5c9aa551..3b920168e06 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -106,7 +106,7 @@ unsafe fn configure_llvm(sess: &Session) {
 
         if sess.target.os == "emscripten"
             && !sess.opts.unstable_opts.emscripten_wasm_eh
-            && sess.panic_strategy() == PanicStrategy::Unwind
+            && sess.panic_strategy().unwinds()
         {
             add("-enable-emscripten-cxx-exceptions", false);
         }
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 48b01ea2df1..327f001e1c8 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -47,8 +47,8 @@ use rustc_span::Symbol;
 use rustc_target::spec::crt_objects::CrtObjects;
 use rustc_target::spec::{
     BinaryFormat, Cc, LinkOutputKind, LinkSelfContainedComponents, LinkSelfContainedDefault,
-    LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy, RelocModel, RelroLevel,
-    SanitizerSet, SplitDebuginfo,
+    LinkerFeatures, LinkerFlavor, LinkerFlavorCli, Lld, RelocModel, RelroLevel, SanitizerSet,
+    SplitDebuginfo,
 };
 use tracing::{debug, info, warn};
 
@@ -2512,10 +2512,10 @@ fn add_order_independent_options(
     if sess.target.os == "emscripten" {
         cmd.cc_arg(if sess.opts.unstable_opts.emscripten_wasm_eh {
             "-fwasm-exceptions"
-        } else if sess.panic_strategy() == PanicStrategy::Abort {
-            "-sDISABLE_EXCEPTION_CATCHING=1"
-        } else {
+        } else if sess.panic_strategy().unwinds() {
             "-sDISABLE_EXCEPTION_CATCHING=0"
+        } else {
+            "-sDISABLE_EXCEPTION_CATCHING=1"
         });
     }
 
diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl
index 6f6666f8c76..1f5c5e74d97 100644
--- a/compiler/rustc_interface/messages.ftl
+++ b/compiler/rustc_interface/messages.ftl
@@ -47,7 +47,7 @@ interface_out_dir_error =
     failed to find or create the directory specified by `--out-dir`
 
 interface_proc_macro_crate_panic_abort =
-    building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
+    building proc macro crate with `panic=abort` or `panic=immediate-abort` may crash the compiler should the proc-macro panic
 
 interface_temps_dir_error =
     failed to find or create the directory specified by `--temps-dir`
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 6cefe887530..761a5c80918 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -42,7 +42,6 @@ use rustc_span::{
     DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span,
     Symbol, sym,
 };
-use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::{solve, traits};
 use tracing::{info, instrument};
 
@@ -282,7 +281,7 @@ fn configure_and_expand(
         feature_err(sess, sym::export_stable, DUMMY_SP, "`sdylib` crate type is unstable").emit();
     }
 
-    if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
+    if is_proc_macro_crate && !sess.panic_strategy().unwinds() {
         sess.dcx().emit_warn(errors::ProcMacroCratePanicAbort);
     }
 
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index e104be2c466..e624bfc5b8b 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -98,6 +98,13 @@ metadata_full_metadata_not_found =
 metadata_global_alloc_required =
     no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
 
+metadata_incompatible_with_immediate_abort =
+    the crate `{$crate_name}` was compiled with a panic strategy which is incompatible with `immediate-abort`
+
+metadata_incompatible_with_immediate_abort_core =
+    the crate `core` was compiled with a panic strategy which is incompatible with `immediate-abort`
+    .help = consider building the standard library from source with `cargo build -Zbuild-std`
+
 metadata_incompatible_panic_in_drop_strategy =
     the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 9e23da88f5e..7650acbd292 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -1027,6 +1027,10 @@ impl CStore {
         let name = match desired_strategy {
             PanicStrategy::Unwind => sym::panic_unwind,
             PanicStrategy::Abort => sym::panic_abort,
+            PanicStrategy::ImmediateAbort => {
+                // Immediate-aborting panics don't use a runtime.
+                return;
+            }
         };
         info!("panic runtime not found -- loading {}", name);
 
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index fb9c2e23b71..8054a48d37a 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -61,11 +61,13 @@ use rustc_session::config::CrateType;
 use rustc_session::cstore::CrateDepKind;
 use rustc_session::cstore::LinkagePreference::{self, RequireDynamic, RequireStatic};
 use rustc_span::sym;
+use rustc_target::spec::PanicStrategy;
 use tracing::info;
 
 use crate::creader::CStore;
 use crate::errors::{
-    BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy, LibRequired,
+    BadPanicStrategy, CrateDepMultiple, IncompatiblePanicInDropStrategy,
+    IncompatibleWithImmediateAbort, IncompatibleWithImmediateAbortCore, LibRequired,
     NonStaticCrateDep, RequiredPanicStrategy, RlibRequired, RustcDriverHelp, RustcLibRequired,
     TwoPanicRuntimes,
 };
@@ -402,15 +404,43 @@ fn activate_injected_dep(
 /// there's only going to be one panic runtime in the output.
 fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) {
     let sess = &tcx.sess;
+    let list: Vec<_> = list
+        .iter_enumerated()
+        .filter_map(
+            |(cnum, linkage)| if *linkage == Linkage::NotLinked { None } else { Some(cnum) },
+        )
+        .collect();
     if list.is_empty() {
         return;
     }
-    let mut panic_runtime = None;
-    for (cnum, linkage) in list.iter_enumerated() {
-        if let Linkage::NotLinked = *linkage {
-            continue;
+    let desired_strategy = sess.panic_strategy();
+
+    // If we are panic=immediate-abort, make sure everything in the dependency tree has also been
+    // compiled with immediate-abort.
+    if list
+        .iter()
+        .any(|cnum| tcx.required_panic_strategy(*cnum) == Some(PanicStrategy::ImmediateAbort))
+    {
+        let mut invalid_crates = Vec::new();
+        for cnum in list.iter().copied() {
+            if tcx.required_panic_strategy(cnum) != Some(PanicStrategy::ImmediateAbort) {
+                invalid_crates.push(cnum);
+                // If core is incompatible, it's very likely that we'd emit an error for every
+                // sysroot crate, so instead of doing that emit a single fatal error that suggests
+                // using build-std.
+                if tcx.crate_name(cnum) == sym::core {
+                    sess.dcx().emit_fatal(IncompatibleWithImmediateAbortCore);
+                }
+            }
         }
+        for cnum in invalid_crates {
+            sess.dcx()
+                .emit_err(IncompatibleWithImmediateAbort { crate_name: tcx.crate_name(cnum) });
+        }
+    }
 
+    let mut panic_runtime = None;
+    for cnum in list.iter().copied() {
         if tcx.is_panic_runtime(cnum) {
             if let Some((prev, _)) = panic_runtime {
                 let prev_name = tcx.crate_name(prev);
@@ -430,8 +460,6 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) {
     // only one, but we perform validation here that all the panic strategy
     // compilation modes for the whole DAG are valid.
     if let Some((runtime_cnum, found_strategy)) = panic_runtime {
-        let desired_strategy = sess.panic_strategy();
-
         // First up, validate that our selected panic runtime is indeed exactly
         // our same strategy.
         if found_strategy != desired_strategy {
@@ -445,10 +473,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &DependencyList) {
         // strategy. If the dep isn't linked, we ignore it, and if our strategy
         // is abort then it's compatible with everything. Otherwise all crates'
         // panic strategy must match our own.
-        for (cnum, linkage) in list.iter_enumerated() {
-            if let Linkage::NotLinked = *linkage {
-                continue;
-            }
+        for cnum in list.iter().copied() {
             if cnum == runtime_cnum || tcx.is_compiler_builtins(cnum) {
                 continue;
             }
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index e5a4fd48353..abfd078f746 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -76,6 +76,16 @@ pub struct RequiredPanicStrategy {
 }
 
 #[derive(Diagnostic)]
+#[diag(metadata_incompatible_with_immediate_abort)]
+pub struct IncompatibleWithImmediateAbort {
+    pub crate_name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(metadata_incompatible_with_immediate_abort_core)]
+pub struct IncompatibleWithImmediateAbortCore;
+
+#[derive(Diagnostic)]
 #[diag(metadata_incompatible_panic_in_drop_strategy)]
 pub struct IncompatiblePanicInDropStrategy {
     pub crate_name: Symbol,
diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs
index 93264f02cc2..a0e4c288c4a 100644
--- a/compiler/rustc_middle/src/middle/lang_items.rs
+++ b/compiler/rustc_middle/src/middle/lang_items.rs
@@ -98,5 +98,6 @@ pub fn required(tcx: TyCtxt<'_>, lang_item: LangItem) -> bool {
             lang_item != LangItem::EhPersonality && lang_item != LangItem::EhCatchTypeinfo
         }
         PanicStrategy::Unwind => true,
+        PanicStrategy::ImmediateAbort => false,
     }
 }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index c477e65f5d6..47b45c58b9f 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -16,7 +16,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
 use rustc_session::config::OptLevel;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
 use rustc_target::callconv::FnAbi;
-use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, PanicStrategy, Target, X86Abi};
+use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi};
 use tracing::debug;
 use {rustc_abi as abi, rustc_hir as hir};
 
@@ -1198,7 +1198,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
         //
         // Note that this is true regardless ABI specified on the function -- a `extern "C-unwind"`
         // function defined in Rust is also required to abort.
-        if tcx.sess.panic_strategy() == PanicStrategy::Abort && !tcx.is_foreign_item(did) {
+        if !tcx.sess.panic_strategy().unwinds() && !tcx.is_foreign_item(did) {
             return false;
         }
 
@@ -1206,7 +1206,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
         //
         // This is not part of `codegen_fn_attrs` as it can differ between crates
         // and therefore cannot be computed in core.
-        if tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Abort
+        if !tcx.sess.opts.unstable_opts.panic_in_drop.unwinds()
             && tcx.is_lang_item(did, LangItem::DropInPlace)
         {
             return false;
@@ -1245,7 +1245,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
         | RiscvInterruptS
         | RustInvalid
         | Unadjusted => false,
-        Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
+        Rust | RustCall | RustCold => tcx.sess.panic_strategy().unwinds(),
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index c1cd2788348..c5cd06f170c 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -86,7 +86,6 @@ use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::source_map::dummy_spanned;
 use rustc_span::symbol::sym;
 use rustc_span::{DUMMY_SP, Span};
-use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::TyCtxtInferExt as _;
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
@@ -1149,7 +1148,7 @@ fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, typing_env: ty::Typing
 
 fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
     // Nothing can unwind when landing pads are off.
-    if tcx.sess.panic_strategy() == PanicStrategy::Abort {
+    if !tcx.sess.panic_strategy().unwinds() {
         return false;
     }
 
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index abbff1c48dd..7c66783548e 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -101,12 +101,15 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
 }
 
 fn required_panic_strategy(tcx: TyCtxt<'_>, _: LocalCrate) -> Option<PanicStrategy> {
+    let local_strategy = tcx.sess.panic_strategy();
+
     if tcx.is_panic_runtime(LOCAL_CRATE) {
-        return Some(tcx.sess.panic_strategy());
+        return Some(local_strategy);
     }
 
-    if tcx.sess.panic_strategy() == PanicStrategy::Abort {
-        return Some(PanicStrategy::Abort);
+    match local_strategy {
+        PanicStrategy::Abort | PanicStrategy::ImmediateAbort => return Some(local_strategy),
+        _ => {}
     }
 
     for def_id in tcx.hir_body_owners() {
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 5b6d7ffb511..b53c1f6d202 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -1,7 +1,6 @@
 use rustc_index::bit_set::DenseBitSet;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
-use rustc_target::spec::PanicStrategy;
 use tracing::debug;
 
 use crate::patch::MirPatch;
@@ -13,7 +12,7 @@ pub(super) struct RemoveNoopLandingPads;
 
 impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        sess.panic_strategy() != PanicStrategy::Abort
+        sess.panic_strategy().unwinds()
     }
 
     fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 795cb2b2cfe..81ada79dd43 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -29,7 +29,8 @@ use rustc_span::{
     SourceFileHashAlgorithm, Symbol, sym,
 };
 use rustc_target::spec::{
-    FramePointer, LinkSelfContainedComponents, LinkerFeatures, SplitDebuginfo, Target, TargetTuple,
+    FramePointer, LinkSelfContainedComponents, LinkerFeatures, PanicStrategy, SplitDebuginfo,
+    Target, TargetTuple,
 };
 use tracing::debug;
 
@@ -2799,6 +2800,12 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
         }
     }
 
+    if !unstable_options_enabled && cg.panic == Some(PanicStrategy::ImmediateAbort) {
+        early_dcx.early_fatal(
+            "`-Cpanic=immediate-abort` requires `-Zunstable-options` and a nightly compiler",
+        )
+    }
+
     let crate_name = matches.opt_str("crate-name");
     let unstable_features = UnstableFeatures::from_environment(crate_name.as_deref());
     // Parse any `-l` flags, which link to native libraries.
diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs
index 7e970461ab7..fc36fe9d5d7 100644
--- a/compiler/rustc_session/src/config/cfg.rs
+++ b/compiler/rustc_session/src/config/cfg.rs
@@ -125,7 +125,9 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) {
                 None | Some(_),
             ) => disallow(cfg, "-Z sanitizer=cfi"),
             (sym::proc_macro, None) => disallow(cfg, "--crate-type proc-macro"),
-            (sym::panic, Some(sym::abort | sym::unwind)) => disallow(cfg, "-C panic"),
+            (sym::panic, Some(sym::abort | sym::unwind | sym::immediate_abort)) => {
+                disallow(cfg, "-C panic")
+            }
             (sym::target_feature, Some(_)) => disallow(cfg, "-C target-feature"),
             (sym::unix, None)
             | (sym::windows, None)
@@ -204,6 +206,9 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg {
     }
 
     ins_sym!(sym::panic, sess.panic_strategy().desc_symbol());
+    if sess.panic_strategy() == PanicStrategy::ImmediateAbort {
+        ins_sym!(sym::panic, PanicStrategy::Abort.desc_symbol());
+    }
 
     // JUSTIFICATION: before wrapper fn is available
     #[allow(rustc::bad_opt_access)]
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 69facde6936..3b9d8117786 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -802,7 +802,7 @@ mod desc {
     pub(crate) const parse_threads: &str = parse_number;
     pub(crate) const parse_time_passes_format: &str = "`text` (default) or `json`";
     pub(crate) const parse_passes: &str = "a space-separated list of passes, or `all`";
-    pub(crate) const parse_panic_strategy: &str = "either `unwind` or `abort`";
+    pub(crate) const parse_panic_strategy: &str = "either `unwind`, `abort`, or `immediate-abort`";
     pub(crate) const parse_on_broken_pipe: &str = "either `kill`, `error`, or `inherit`";
     pub(crate) const parse_patchable_function_entry: &str = "either two comma separated integers (total_nops,prefix_nops), with prefix_nops <= total_nops, or one integer (total_nops)";
     pub(crate) const parse_opt_panic_strategy: &str = parse_panic_strategy;
@@ -1165,6 +1165,7 @@ pub mod parse {
         match v {
             Some("unwind") => *slot = Some(PanicStrategy::Unwind),
             Some("abort") => *slot = Some(PanicStrategy::Abort),
+            Some("immediate-abort") => *slot = Some(PanicStrategy::ImmediateAbort),
             _ => return false,
         }
         true
@@ -1174,6 +1175,7 @@ pub mod parse {
         match v {
             Some("unwind") => *slot = PanicStrategy::Unwind,
             Some("abort") => *slot = PanicStrategy::Abort,
+            Some("immediate-abort") => *slot = PanicStrategy::ImmediateAbort,
             _ => return false,
         }
         true
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index d0dd2cdac0c..25b46241c52 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -777,9 +777,11 @@ impl Session {
         // Otherwise, we can defer to the `-C force-unwind-tables=<yes/no>`
         // value, if it is provided, or disable them, if not.
         self.target.requires_uwtable
-            || self.opts.cg.force_unwind_tables.unwrap_or(
-                self.panic_strategy() == PanicStrategy::Unwind || self.target.default_uwtable,
-            )
+            || self
+                .opts
+                .cg
+                .force_unwind_tables
+                .unwrap_or(self.panic_strategy().unwinds() || self.target.default_uwtable)
     }
 
     /// Returns the number of query threads that should be used for this
@@ -1229,7 +1231,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     }
 
     // KCFI requires panic=abort
-    if sess.is_sanitizer_kcfi_enabled() && sess.panic_strategy() != PanicStrategy::Abort {
+    if sess.is_sanitizer_kcfi_enabled() && sess.panic_strategy().unwinds() {
         sess.dcx().emit_err(errors::SanitizerKcfiRequiresPanicAbort);
     }
 
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 4fef65f46b1..efeb4371e4c 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1195,6 +1195,7 @@ symbols! {
         if_let_rescope,
         if_while_or_patterns,
         ignore,
+        immediate_abort,
         impl_header_lifetime_elision,
         impl_lint_pass,
         impl_trait_in_assoc_type,
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index f705af52bd8..2299db94535 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -834,6 +834,7 @@ crate::target_spec_enum! {
     pub enum PanicStrategy {
         Unwind = "unwind",
         Abort = "abort",
+        ImmediateAbort = "immediate-abort",
     }
 
     parse_error_type = "panic strategy";
@@ -852,8 +853,13 @@ impl PanicStrategy {
         match *self {
             PanicStrategy::Unwind => sym::unwind,
             PanicStrategy::Abort => sym::abort,
+            PanicStrategy::ImmediateAbort => sym::immediate_abort,
         }
     }
+
+    pub fn unwinds(self) -> bool {
+        matches!(self, PanicStrategy::Unwind)
+    }
 }
 
 crate::target_spec_enum! {