diff options
| author | bors <bors@rust-lang.org> | 2025-09-23 06:37:03 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-09-23 06:37:03 +0000 |
| commit | 40560823602064f4c726aea3e15e104449e1a392 (patch) | |
| tree | e10dc6a958e29b720376c4e5a549a8bd13a81a4a | |
| parent | f6092f224d2b1774b31033f12d0bee626943b02f (diff) | |
| parent | 4c1595a93b349fa755d84f8943860589c27b64f0 (diff) | |
| download | rust-40560823602064f4c726aea3e15e104449e1a392.tar.gz rust-40560823602064f4c726aea3e15e104449e1a392.zip | |
Auto merge of #146317 - saethlin:panic=immediate-abort, r=nnethercote
Add panic=immediate-abort MCP: https://github.com/rust-lang/compiler-team/issues/909 This adds a new panic strategy, `-Cpanic=immediate-abort`. This panic strategy essentially just codifies use of `-Zbuild-std-features=panic_immediate_abort`. This PR is intended to just set up infrastructure, and while it will change how the compiler is invoked for users of the feature, there should be no other impacts. In many parts of the compiler, `PanicStrategy::ImmediateAbort` behaves just like `PanicStrategy::Abort`, because actually most parts of the compiler just mean to ask "can this unwind?" so I've added a helper function so we can say `sess.panic_strategy().unwinds()`. The panic and unwind strategies have some level of compatibility, which mostly means that we can pre-compile the sysroot with unwinding panics then the sysroot can be linked with aborting panics later. The immediate-abort strategy is all-or-nothing, enforced by `compiler/rustc_metadata/src/dependency_format.rs` and this is tested for in `tests/ui/panic-runtime/`. We could _technically_ be more compatible with the other panic strategies, but immediately-aborting panics primarily exist for users who want to eliminate all the code size responsible for the panic runtime. I'm open to other use cases if people want to present them, but not right now. This PR is already large. `-Cpanic=immediate-abort` sets both `cfg(panic = "immediate-abort")` _and_ `cfg(panic = "abort")`. bjorn3 pointed out that people may be checking for the abort cfg to ask if panics will unwind, and also the sysroot feature this is replacing used to require `-Cpanic=abort` so this seems like a good back-compat step. At least for the moment. Unclear if this is a good idea indefinitely. I can imagine this being confusing. The changes to the standard library attributes are purely mechanical. Apart from that, I removed an `unsafe` we haven't needed for a while since the `abort` intrinsic became safe, and I've added a helpful diagnostic for people trying to use the old feature. To test that `-Cpanic=immediate-abort` conflicts with other panic strategies, I've beefed up the core-stubs infrastructure a bit. There is now a separate attribute to set flags on it. I've added a test that this produces the desired codegen, called `tests/run-make-cargo/panic-immediate-abort-codegen/` and also a separate run-make-cargo test that checks that we can build a binary.
74 files changed, 561 insertions, 157 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..f3d91ce4a5d 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) @@ -203,7 +205,14 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg { ins_none!(sym::overflow_checks); } + // We insert a cfg for the name of session's panic strategy. + // Since the ImmediateAbort strategy is new, it also sets cfg(panic="abort"), so that code + // which is trying to detect whether unwinding is enabled by checking for cfg(panic="abort") + // does not need to be updated. 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 a6ae58f87dc..4e48c96afd6 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1196,6 +1196,7 @@ symbols! { if_let_rescope, if_while_or_patterns, ignore, + immediate_abort: "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 c40358af593..4a82a8bd888 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! { diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index 9ba7c5bd28a..fb1f8c86dbf 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -22,8 +22,6 @@ compiler_builtins = { path = "../compiler-builtins/compiler-builtins", features compiler-builtins-mem = ['compiler_builtins/mem'] compiler-builtins-c = ["compiler_builtins/c"] compiler-builtins-no-f16-f128 = ["compiler_builtins/no-f16-f128"] -# Make panics and failed asserts immediately abort without formatting any message -panic_immediate_abort = ["core/panic_immediate_abort"] # Choose algorithms that are optimized for binary size instead of runtime performance optimize_for_size = ["core/optimize_for_size"] diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 76630a746dd..65c8206e9d4 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -408,12 +408,12 @@ pub const fn handle_alloc_error(layout: Layout) -> ! { } } - #[cfg(not(feature = "panic_immediate_abort"))] + #[cfg(not(panic = "immediate-abort"))] { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) } - #[cfg(feature = "panic_immediate_abort")] + #[cfg(panic = "immediate-abort")] ct_error(layout) } diff --git a/library/alloc/src/raw_vec/mod.rs b/library/alloc/src/raw_vec/mod.rs index b0027e964e4..b7c153b825d 100644 --- a/library/alloc/src/raw_vec/mod.rs +++ b/library/alloc/src/raw_vec/mod.rs @@ -23,7 +23,7 @@ mod tests; // ensure that the code generation related to these panics is minimal as there's // only one location which panics rather than a bunch throughout the module. #[cfg(not(no_global_oom_handling))] -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] fn capacity_overflow() -> ! { panic!("capacity overflow"); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 10c7ee4f6c8..ebdb86f98a8 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -2020,7 +2020,7 @@ impl<T, A: Allocator> Vec<T, A> { #[stable(feature = "rust1", since = "1.0.0")] pub fn swap_remove(&mut self, index: usize) -> T { #[cold] - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] + #[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[optimize(size)] fn assert_failed(index: usize, len: usize) -> ! { @@ -2102,7 +2102,7 @@ impl<T, A: Allocator> Vec<T, A> { #[must_use = "if you don't need a reference to the value, use `Vec::insert` instead"] pub fn insert_mut(&mut self, index: usize, element: T) -> &mut T { #[cold] - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] + #[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[optimize(size)] fn assert_failed(index: usize, len: usize) -> ! { @@ -2166,7 +2166,7 @@ impl<T, A: Allocator> Vec<T, A> { #[rustc_confusables("delete", "take")] pub fn remove(&mut self, index: usize) -> T { #[cold] - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] + #[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[optimize(size)] fn assert_failed(index: usize, len: usize) -> ! { @@ -2955,7 +2955,7 @@ impl<T, A: Allocator> Vec<T, A> { A: Clone, { #[cold] - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] + #[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[optimize(size)] fn assert_failed(at: usize, len: usize) -> ! { diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index 3e34e03a61e..d094172b076 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -16,7 +16,7 @@ test = false bench = false [features] -# Make panics and failed asserts immediately abort without formatting any message +# Issue a compile error that says to use -Cpanic=immediate-abort panic_immediate_abort = [] # Choose algorithms that are optimized for binary size instead of runtime performance optimize_for_size = [] diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 9b53b75ebee..7d4a66640b1 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -778,7 +778,7 @@ impl Display for BorrowMutError { } // This ensures the panicking code is outlined from `borrow_mut` for `RefCell`. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[cold] const fn panic_already_borrowed(err: BorrowMutError) -> ! { @@ -790,7 +790,7 @@ const fn panic_already_borrowed(err: BorrowMutError) -> ! { } // This ensures the panicking code is outlined from `borrow` for `RefCell`. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[cold] const fn panic_already_mutably_borrowed(err: BorrowError) -> ! { diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 54d5a63633c..c75ee11d15e 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1387,8 +1387,8 @@ pub const fn can_not_overflow<T>(radix: u32, is_signed_ty: bool, digits: &[u8]) radix <= 16 && digits.len() <= size_of::<T>() * 2 - is_signed_ty as usize } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] +#[cfg_attr(panic = "immediate-abort", inline)] #[cold] #[track_caller] const fn from_ascii_radix_panic(radix: u32) -> ! { diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 886d581b0a6..430ee3470ac 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2161,8 +2161,8 @@ impl<T, E> Option<Result<T, E>> { } } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] +#[cfg_attr(panic = "immediate-abort", inline)] #[cold] #[track_caller] const fn unwrap_failed() -> ! { @@ -2170,8 +2170,8 @@ const fn unwrap_failed() -> ! { } // This is a separate function to reduce the code size of .expect() itself. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] +#[cfg_attr(panic = "immediate-abort", inline)] #[cold] #[track_caller] const fn expect_failed(msg: &str) -> ! { diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 804a12ee477..3f30038dbc0 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -33,7 +33,10 @@ use crate::intrinsics::const_eval_select; use crate::panic::{Location, PanicInfo}; #[cfg(feature = "panic_immediate_abort")] -const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C panic=abort"); +compile_error!( + "panic_immediate_abort is now a real panic strategy! \ + Enable it with the compiler flags `-Zunstable-options -Cpanic=immediate-abort`" +); // First we define the two main entry points that all panics go through. // In the end both are just convenience wrappers around `panic_impl`. @@ -44,16 +47,16 @@ const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C /// site as much as possible (so that `panic!()` has as low an impact /// on (e.g.) the inlining of other functions as possible), by moving /// the actual formatting into this shared place. -// If panic_immediate_abort, inline the abort call, +// If panic=immediate-abort, inline the abort call, // otherwise avoid inlining because of it is cold path. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[lang = "panic_fmt"] // needed for const-evaluated panics #[rustc_do_not_const_check] // hooked by const-eval #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate-abort") { super::intrinsics::abort() } @@ -78,8 +81,8 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { /// Like `panic_fmt`, but for non-unwinding panics. /// /// Has to be a separate function so that it can carry the `rustc_nounwind` attribute. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] // This attribute has the key side-effect that if the panic handler ignores `can_unwind` // and unwinds anyway, we will hit the "unwinding out of nounwind function" guard, @@ -94,7 +97,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo // We don't unwind anyway at compile-time so we can call the regular `panic_fmt`. panic_fmt(fmt) } else #[track_caller] { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate-abort") { super::intrinsics::abort() } @@ -123,10 +126,10 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo // above. /// The underlying implementation of core's `panic!` macro when no formatting is used. -// Never inline unless panic_immediate_abort to avoid code +// Never inline unless panic=immediate-abort to avoid code // bloat at the call sites as much as possible. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable #[lang = "panic"] // used by lints and miri for panics @@ -158,10 +161,10 @@ macro_rules! panic_const { $( /// This is a panic called with a message that's a result of a MIR-produced Assert. // - // never inline unless panic_immediate_abort to avoid code + // never inline unless panic=immediate-abort to avoid code // bloat at the call sites as much as possible - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] - #[cfg_attr(feature = "panic_immediate_abort", inline)] + #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] + #[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable #[lang = stringify!($lang)] @@ -216,8 +219,8 @@ pub mod panic_const { /// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize on the caller. /// If you want `#[track_caller]` for nicer errors, call `panic_nounwind_fmt` directly. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics #[rustc_nounwind] #[rustc_const_stable_indirect] // must follow stable const rules since it is exposed to stable @@ -226,8 +229,8 @@ pub const fn panic_nounwind(expr: &'static str) -> ! { } /// Like `panic_nounwind`, but also inhibits showing a backtrace. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] #[rustc_nounwind] pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! { panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ true); @@ -259,25 +262,25 @@ pub const fn panic_display<T: fmt::Display>(x: &T) -> ! { panic_fmt(format_args!("{}", *x)); } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access fn panic_bounds_check(index: usize, len: usize) -> ! { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate-abort") { super::intrinsics::abort() } panic!("index out of bounds: the len is {len} but the index is {index}") } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[lang = "panic_misaligned_pointer_dereference"] // needed by codegen for panic on misaligned pointer deref #[rustc_nounwind] // `CheckAlignment` MIR pass requires this function to never unwind fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate-abort") { super::intrinsics::abort() } @@ -289,13 +292,13 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { ) } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[lang = "panic_null_pointer_dereference"] // needed by codegen for panic on null pointer deref #[rustc_nounwind] // `CheckNull` MIR pass requires this function to never unwind fn panic_null_pointer_dereference() -> ! { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate-abort") { super::intrinsics::abort() } @@ -305,13 +308,13 @@ fn panic_null_pointer_dereference() -> ! { ) } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[lang = "panic_invalid_enum_construction"] // needed by codegen for panic on invalid enum construction. #[rustc_nounwind] // `CheckEnums` MIR pass requires this function to never unwind fn panic_invalid_enum_construction(source: u128) -> ! { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate-abort") { super::intrinsics::abort() } @@ -328,8 +331,8 @@ fn panic_invalid_enum_construction(source: u128) -> ! { /// /// This function is called directly by the codegen backend, and must not have /// any extra arguments (including those synthesized by track_caller). -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[lang = "panic_cannot_unwind"] // needed by codegen for panic in nounwind function #[rustc_nounwind] fn panic_cannot_unwind() -> ! { @@ -344,8 +347,8 @@ fn panic_cannot_unwind() -> ! { /// /// This function is called directly by the codegen backend, and must not have /// any extra arguments (including those synthesized by track_caller). -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[lang = "panic_in_cleanup"] // needed by codegen for panic in nounwind function #[rustc_nounwind] fn panic_in_cleanup() -> ! { @@ -377,8 +380,8 @@ pub enum AssertKind { } /// Internal function for `assert_eq!` and `assert_ne!` macros -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[doc(hidden)] pub fn assert_failed<T, U>( @@ -395,8 +398,8 @@ where } /// Internal function for `assert_match!` -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[doc(hidden)] pub fn assert_matches_failed<T: fmt::Debug + ?Sized>( @@ -415,8 +418,8 @@ pub fn assert_matches_failed<T: fmt::Debug + ?Sized>( } /// Non-generic version of the above functions, to avoid code bloat. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] fn assert_failed_inner( kind: AssertKind, diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 5c1f64bfe14..c69762a7285 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1847,7 +1847,7 @@ impl<T, E> Result<Result<T, E>, E> { } // This is a separate function to reduce the code size of the methods -#[cfg(not(feature = "panic_immediate_abort"))] +#[cfg(not(panic = "immediate-abort"))] #[inline(never)] #[cold] #[track_caller] @@ -1859,7 +1859,7 @@ fn unwrap_failed(msg: &str, error: &dyn fmt::Debug) -> ! { // that gets immediately thrown away, since vtables don't get cleaned up // by dead code elimination if a trait object is constructed even if it goes // unused -#[cfg(feature = "panic_immediate_abort")] +#[cfg(panic = "immediate-abort")] #[inline] #[cold] #[track_caller] diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index d4c466201ed..de220e7e38a 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -31,8 +31,8 @@ where } } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] const fn slice_index_fail(start: usize, end: usize, len: usize) -> ! { if start > len { diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index dfbb3628350..f7f5ee819b2 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3858,8 +3858,8 @@ impl<T> [T] { { // The panic code path was put into a cold function to not bloat the // call site. - #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] - #[cfg_attr(feature = "panic_immediate_abort", inline)] + #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] + #[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] const fn len_mismatch_fail(dst_len: usize, src_len: usize) -> ! { const_panic!( diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs index 400daba16c1..e555fce4408 100644 --- a/library/core/src/slice/sort/shared/smallsort.rs +++ b/library/core/src/slice/sort/shared/smallsort.rs @@ -840,8 +840,8 @@ unsafe fn bidirectional_merge<T: FreezeMarker, F: FnMut(&T, &T) -> bool>( } } -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)] +#[cfg_attr(panic = "immediate-abort", inline)] fn panic_on_ord_violation() -> ! { // This is indicative of a logic bug in the user-provided comparison function or Ord // implementation. They are expected to implement a total order as explained in the Ord diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 04fdaa8143e..2e473d348b0 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -64,12 +64,12 @@ pub use validations::{next_code_point, utf8_char_width}; #[cold] #[track_caller] #[rustc_allow_const_fn_unstable(const_eval_select)] -#[cfg(not(feature = "panic_immediate_abort"))] +#[cfg(not(panic = "immediate-abort"))] const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { crate::intrinsics::const_eval_select((s, begin, end), slice_error_fail_ct, slice_error_fail_rt) } -#[cfg(feature = "panic_immediate_abort")] +#[cfg(panic = "immediate-abort")] const fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { slice_error_fail_ct(s, begin, end) } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index d28a7f0b460..958cafb8f3d 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -106,11 +106,6 @@ compiler-builtins-no-f16-f128 = ["alloc/compiler-builtins-no-f16-f128"] llvm-libunwind = ["unwind/llvm-libunwind"] system-llvm-libunwind = ["unwind/system-llvm-libunwind"] -# Make panics and failed asserts immediately abort without formatting any message -panic_immediate_abort = [ - "core/panic_immediate_abort", - "alloc/panic_immediate_abort", -] # Choose algorithms that are optimized for binary size instead of runtime performance optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"] diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 8b7282c51d1..b7be869c4eb 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -331,7 +331,7 @@ fn default_hook(info: &PanicHookInfo<'_>) { #[cfg(not(test))] #[doc(hidden)] -#[cfg(feature = "panic_immediate_abort")] +#[cfg(panic = "immediate-abort")] #[unstable(feature = "update_panic_count", issue = "none")] pub mod panic_count { /// A reason for forcing an immediate abort on panic. @@ -371,7 +371,7 @@ pub mod panic_count { #[cfg(not(test))] #[doc(hidden)] -#[cfg(not(feature = "panic_immediate_abort"))] +#[cfg(not(panic = "immediate-abort"))] #[unstable(feature = "update_panic_count", issue = "none")] pub mod panic_count { use crate::cell::Cell; @@ -499,13 +499,13 @@ pub mod panic_count { pub use realstd::rt::panic_count; /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -#[cfg(feature = "panic_immediate_abort")] +#[cfg(panic = "immediate-abort")] pub unsafe fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> { Ok(f()) } /// Invoke a closure, capturing the cause of an unwinding panic if one occurs. -#[cfg(not(feature = "panic_immediate_abort"))] +#[cfg(not(panic = "immediate-abort"))] pub unsafe fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> { union Data<F, R> { f: ManuallyDrop<F>, @@ -720,14 +720,14 @@ pub fn panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { #[unstable(feature = "libstd_sys_internals", reason = "used by the panic! macro", issue = "none")] #[cfg_attr(not(any(test, doctest)), lang = "begin_panic")] // lang item for CTFE panic support -// never inline unless panic_immediate_abort to avoid code +// never inline unless panic=immediate-abort to avoid code // bloat at the call sites as much as possible -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold, optimize(size))] -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))] +#[cfg_attr(panic = "immediate-abort", inline)] #[track_caller] #[rustc_do_not_const_check] // hooked by const-eval pub const fn begin_panic<M: Any + Send>(msg: M) -> ! { - if cfg!(feature = "panic_immediate_abort") { + if cfg!(panic = "immediate-abort") { intrinsics::abort() } @@ -861,7 +861,7 @@ fn panic_with_hook( /// This is the entry point for `resume_unwind`. /// It just forwards the payload to the panic runtime. -#[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(panic = "immediate-abort", inline)] pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! { panic_count::increase(false); @@ -890,16 +890,14 @@ pub fn resume_unwind(payload: Box<dyn Any + Send>) -> ! { /// on which to slap yer breakpoints. #[inline(never)] #[cfg_attr(not(test), rustc_std_internal_symbol)] -#[cfg(not(feature = "panic_immediate_abort"))] +#[cfg(not(panic = "immediate-abort"))] fn rust_panic(msg: &mut dyn PanicPayload) -> ! { let code = unsafe { __rust_start_panic(msg) }; rtabort!("failed to initiate panic, error {code}") } #[cfg_attr(not(test), rustc_std_internal_symbol)] -#[cfg(feature = "panic_immediate_abort")] +#[cfg(panic = "immediate-abort")] fn rust_panic(_: &mut dyn PanicPayload) -> ! { - unsafe { - crate::intrinsics::abort(); - } + crate::intrinsics::abort(); } diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 8d95cc1fb57..2717b7b469c 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -39,11 +39,11 @@ fn __rust_abort() { // - nothing (so this macro is a no-op) macro_rules! rtprintpanic { ($($t:tt)*) => { - #[cfg(not(feature = "panic_immediate_abort"))] + #[cfg(not(panic = "immediate-abort"))] if let Some(mut out) = crate::sys::stdio::panic_output() { let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); } - #[cfg(feature = "panic_immediate_abort")] + #[cfg(panic = "immediate-abort")] { let _ = format_args!($($t)*); } diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 797feeb2bbb..0a6f2e5d508 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -230,7 +230,7 @@ impl fmt::Display for AccessError { impl Error for AccessError {} // This ensures the panicking code is outlined from `with` for `LocalKey`. -#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[cfg_attr(not(panic = "immediate-abort"), inline(never))] #[track_caller] #[cold] fn panic_access_error(err: AccessError) -> ! { diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 7b4aeed94e9..ee4aec61872 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -31,7 +31,6 @@ llvm-libunwind = ["std/llvm-libunwind"] system-llvm-libunwind = ["std/system-llvm-libunwind"] optimize_for_size = ["std/optimize_for_size"] panic-unwind = ["std/panic-unwind"] -panic_immediate_abort = ["std/panic_immediate_abort"] profiler = ["dep:profiler_builtins"] std_detect_file_io = ["std/std_detect_file_io"] std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"] diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 445b10188e3..0e340de4daa 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -471,11 +471,13 @@ If not specified, overflow checks are enabled if This option lets you control what happens when the code panics. * `abort`: terminate the process upon panic +* `immediate-abort`: terminate the process upon panic, and do not call any panic hooks * `unwind`: unwind the stack upon panic If not specified, the default depends on the target. If any crate in the crate graph uses `abort`, the final binary (`bin`, `dylib`, `cdylib`, `staticlib`) must also use `abort`. +If any crate in the crate graph uses `immediate-abort`, every crate in the graph must use `immediate-abort`. If `std` is used as a `dylib` with `unwind`, the final binary must also use `unwind`. ## passes diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index 1277fd225eb..e84a2278766 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -201,6 +201,8 @@ pub struct TestProps { /// Build and use `minicore` as `core` stub for `no_core` tests in cross-compilation scenarios /// that don't otherwise want/need `-Z build-std`. pub add_core_stubs: bool, + /// Add these flags to the build of `minicore`. + pub core_stubs_compile_flags: Vec<String>, /// Whether line annotatins are required for the given error kind. pub dont_require_annotations: HashSet<ErrorKind>, /// Whether pretty printers should be disabled in gdb. @@ -253,6 +255,7 @@ mod directives { pub const FILECHECK_FLAGS: &'static str = "filecheck-flags"; pub const NO_AUTO_CHECK_CFG: &'static str = "no-auto-check-cfg"; pub const ADD_CORE_STUBS: &'static str = "add-core-stubs"; + pub const CORE_STUBS_COMPILE_FLAGS: &'static str = "core-stubs-compile-flags"; // This isn't a real directive, just one that is probably mistyped often pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags"; pub const DISABLE_GDB_PRETTY_PRINTERS: &'static str = "disable-gdb-pretty-printers"; @@ -311,6 +314,7 @@ impl TestProps { no_auto_check_cfg: false, has_enzyme: false, add_core_stubs: false, + core_stubs_compile_flags: vec![], dont_require_annotations: Default::default(), disable_gdb_pretty_printers: false, compare_output_by_lines: false, @@ -653,6 +657,21 @@ impl TestProps { self.update_add_core_stubs(ln, config); + if let Some(flags) = config.parse_name_value_directive( + ln, + directives::CORE_STUBS_COMPILE_FLAGS, + testfile, + line_number, + ) { + let flags = split_flags(&flags); + for flag in &flags { + if flag == "--edition" || flag.starts_with("--edition=") { + panic!("you must use `//@ edition` to configure the edition"); + } + } + self.core_stubs_compile_flags.extend(flags); + } + if let Some(err_kind) = config.parse_name_value_directive( ln, DONT_REQUIRE_ANNOTATIONS, diff --git a/src/tools/compiletest/src/directives/directive_names.rs b/src/tools/compiletest/src/directives/directive_names.rs index 0ef84fb4594..4fef8992567 100644 --- a/src/tools/compiletest/src/directives/directive_names.rs +++ b/src/tools/compiletest/src/directives/directive_names.rs @@ -19,6 +19,7 @@ pub(crate) const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "check-test-line-numbers-match", "compare-output-by-lines", "compile-flags", + "core-stubs-compile-flags", "disable-gdb-pretty-printers", "doc-flags", "dont-check-compiler-stderr", diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 89fb8eb4357..29578acb404 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1322,6 +1322,7 @@ impl<'test> TestCx<'test> { rustc.args(&["--crate-type", "rlib"]); rustc.arg("-Cpanic=abort"); + rustc.args(self.props.core_stubs_compile_flags.clone()); let res = self.compose_and_run(rustc, self.config.compile_lib_path.as_path(), None, None); if !res.status.success() { @@ -1432,6 +1433,12 @@ impl<'test> TestCx<'test> { aux_rustc.arg("-L").arg(&aux_dir); + if aux_props.add_core_stubs { + let minicore_path = self.build_minicore(); + aux_rustc.arg("--extern"); + aux_rustc.arg(&format!("minicore={}", minicore_path)); + } + let auxres = aux_cx.compose_and_run( aux_rustc, aux_cx.config.compile_lib_path.as_path(), @@ -1858,14 +1865,13 @@ impl<'test> TestCx<'test> { } } - rustc.args(&self.props.compile_flags); - // FIXME(jieyouxu): we should report a fatal error or warning if user wrote `-Cpanic=` with - // something that's not `abort` and `-Cforce-unwind-tables` with a value that is not `yes`, - // however, by moving this last we should override previous `-Cpanic`s and - // `-Cforce-unwind-tables`s. Note that checking here is very fragile, because we'd have to - // account for all possible compile flag splittings (they have some... intricacies and are - // not yet normalized). + // something that's not `abort` and `-Cforce-unwind-tables` with a value that is not `yes`. + // + // We could apply these last and override any provided flags. That would ensure that the + // build works, but some tests want to exercise that mixing panic modes in specific ways is + // rejected. So we enable aborting panics and unwind tables before adding flags, just to + // change the default. // // `minicore` requires `#![no_std]` and `#![no_core]`, which means no unwinding panics. if self.props.add_core_stubs { @@ -1873,6 +1879,8 @@ impl<'test> TestCx<'test> { rustc.arg("-Cforce-unwind-tables=yes"); } + rustc.args(&self.props.compile_flags); + rustc } diff --git a/tests/run-make-cargo/panic-immediate-abort-codegen/Cargo.toml b/tests/run-make-cargo/panic-immediate-abort-codegen/Cargo.toml new file mode 100644 index 00000000000..3c61c12a84e --- /dev/null +++ b/tests/run-make-cargo/panic-immediate-abort-codegen/Cargo.toml @@ -0,0 +1,12 @@ +cargo-features = ["profile-rustflags"] + +[package] +name = "panic_scenarios" +version = "0.1.0" +edition = "2024" + +[lib] +path = "lib.rs" + +[profile.release] +rustflags = ["-Zmerge-functions=disabled", "-Zcodegen-source-order", "--emit=llvm-ir"] diff --git a/tests/run-make-cargo/panic-immediate-abort-codegen/lib.rs b/tests/run-make-cargo/panic-immediate-abort-codegen/lib.rs new file mode 100644 index 00000000000..1e20da93ba8 --- /dev/null +++ b/tests/run-make-cargo/panic-immediate-abort-codegen/lib.rs @@ -0,0 +1,65 @@ +#![no_std] + +#[unsafe(no_mangle)] +pub fn panic_noarg() { + // CHECK-LABEL: @panic_noarg( + // CHECK-NEXT: start: + // CHECK-NEXT: tail call void @llvm.trap() + panic!(); +} + +#[unsafe(no_mangle)] +pub fn panic_str() { + // CHECK-LABEL: @panic_str( + // CHECK-NEXT: start: + // CHECK-NEXT: tail call void @llvm.trap() + panic!("ouch"); +} + +#[unsafe(no_mangle)] +pub fn bounds_check(x: &[u8], idx: usize) -> &u8 { + // CHECK-LABEL: @bounds_check( + // CHECK-NEXT: start: + // CHECK-NEXT: icmp ult + // CHECK-NEXT: br i1 + // CHECK: bb1: + // CHECK-NEXT: getelementptr inbounds nuw i8 + // CHECK-NEXT: ret ptr + // CHECK: panic: + // CHECK-NEXT: tail call void @llvm.trap() + &x[idx] +} + +#[unsafe(no_mangle)] +pub fn str_bounds_check(x: &str, idx: usize) -> &str { + // CHECK-LABEL: @str_bounds_check( + // CHECK-NOT: call + // CHECK: tail call void @llvm.trap() + // CHECK-NOT: call + &x[idx..] +} + +#[unsafe(no_mangle)] +pub fn unsigned_integer_div(x: u16, y: u16) -> u16 { + // CHECK-LABEL: @unsigned_integer_div( + // CHECK-NEXT: start: + // CHECK-NEXT: icmp eq i16 + // CHECK-NEXT: br i1 + // CHECK: bb1: + // CHECK-NEXT: udiv i16 + // CHECK-NEXT: ret i16 + // CHECK: panic: + // CHECK-NEXT: tail call void @llvm.trap() + x / y +} + +#[unsafe(no_mangle)] +pub fn refcell_already_borrowed() { + // CHECK-LABEL: @refcell_already_borrowed( + // CHECK-NOT: call + // CHECK: tail call void @llvm.trap() + // CHECK-NOT: call + let r = core::cell::RefCell::new(0u8); + let _guard = r.borrow_mut(); + r.borrow_mut(); +} diff --git a/tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs b/tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs new file mode 100644 index 00000000000..d7a7a8bfd8c --- /dev/null +++ b/tests/run-make-cargo/panic-immediate-abort-codegen/rmake.rs @@ -0,0 +1,46 @@ +// This is a codegen test which checks that when code is compiled with panic=immediate-abort, +// we get a `tail call void @llvm.trap()` in user code instead of a call into the standard +// library's panic formatting code (such as panic_fmt) or one of the numerous panic outlining shims +// (such as slice_index_fail). + +#![deny(warnings)] + +use run_make_support::{cargo, llvm_filecheck, path, rfs, target}; + +fn main() { + let target_dir = path("target"); + + cargo() + .args(&[ + "build", + "--release", + "--lib", + "--manifest-path", + "Cargo.toml", + "-Zbuild-std=core", + "--target", + &target(), + ]) + .env("RUSTFLAGS", "-Zunstable-options -Cpanic=immediate-abort") + .env("CARGO_TARGET_DIR", &target_dir) + .env("RUSTC_BOOTSTRAP", "1") + // Visual Studio 2022 requires that the LIB env var be set so it can + // find the Windows SDK. + .env("LIB", std::env::var("LIB").unwrap_or_default()) + .run(); + + let out_dir = target_dir.join(target()).join("release").join("deps"); + let ir_file = rfs::read_dir(out_dir) + .find_map(|e| { + let path = e.unwrap().path(); + let file_name = path.file_name().unwrap().to_str().unwrap(); + if file_name.starts_with("panic_scenarios") && file_name.ends_with(".ll") { + Some(path) + } else { + None + } + }) + .unwrap(); + + llvm_filecheck().patterns("lib.rs").input_file(ir_file).run(); +} diff --git a/tests/run-make-cargo/panic-immediate-abort-works/hello/Cargo.toml b/tests/run-make-cargo/panic-immediate-abort-works/hello/Cargo.toml new file mode 100644 index 00000000000..1e278d557c0 --- /dev/null +++ b/tests/run-make-cargo/panic-immediate-abort-works/hello/Cargo.toml @@ -0,0 +1,4 @@ +[package] +name = "hello" +version = "0.1.0" +edition = "2024" diff --git a/tests/run-make-cargo/panic-immediate-abort-works/hello/src/main.rs b/tests/run-make-cargo/panic-immediate-abort-works/hello/src/main.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/tests/run-make-cargo/panic-immediate-abort-works/hello/src/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs b/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs new file mode 100644 index 00000000000..3eeef38c962 --- /dev/null +++ b/tests/run-make-cargo/panic-immediate-abort-works/rmake.rs @@ -0,0 +1,39 @@ +// This test ensures we are able to compile and link a simple binary with panic=immediate-abort. +// The test panic-immediate-abort-codegen checks that panic strategy produces the desired codegen, +// but is based on compiling a library crate (which is the norm for codegen tests because it is +// cleaner and more portable). So this test ensures that we didn't mix up a cfg or a compiler +// implementation detail in a way that makes panic=immediate-abort encounter errors at link time. + +// Ideally this test would be run for most targets, but unfortunately: +// This test is currently written using `fn main() {}` which requires std. +// And since the default linker is only a linker for the host, we can't handle cross-compilation. +// Both of these shortcomings could be addressed at the cost of making the test more complicated. +//@ needs-target-std +//@ ignore-cross-compile + +#![deny(warnings)] + +use run_make_support::{cargo, path, target}; + +fn main() { + let target_dir = path("target"); + + cargo() + .current_dir("hello") + .args(&[ + "build", + "--release", + "--manifest-path", + "Cargo.toml", + "-Zbuild-std", + "--target", + &target(), + ]) + .env("RUSTFLAGS", "-Zunstable-options -Cpanic=immediate-abort") + .env("CARGO_TARGET_DIR", &target_dir) + .env("RUSTC_BOOTSTRAP", "1") + // Visual Studio 2022 requires that the LIB env var be set so it can + // find the Windows SDK. + .env("LIB", std::env::var("LIB").unwrap_or_default()) + .run(); +} diff --git a/tests/ui/check-cfg/report-in-external-macros.cargo.stderr b/tests/ui/check-cfg/report-in-external-macros.cargo.stderr index 989a01f2244..4b5fc91c7eb 100644 --- a/tests/ui/check-cfg/report-in-external-macros.cargo.stderr +++ b/tests/ui/check-cfg/report-in-external-macros.cargo.stderr @@ -18,7 +18,7 @@ warning: unexpected `cfg` condition value: `UNEXPECTED_VALUE` LL | cfg_macro::my_lib_macro_value!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `panic` are: `abort` and `unwind` + = note: expected values for `panic` are: `abort`, `immediate-abort`, and `unwind` = note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate = help: try referring to `cfg_macro::my_lib_macro_value` crate for guidance on how handle this unexpected cfg = help: the macro `cfg_macro::my_lib_macro_value` may come from an old version of the `cfg_macro` crate, try updating your dependency with `cargo update -p cfg_macro` diff --git a/tests/ui/check-cfg/report-in-external-macros.rustc.stderr b/tests/ui/check-cfg/report-in-external-macros.rustc.stderr index 95d10e014f3..0d99d061d28 100644 --- a/tests/ui/check-cfg/report-in-external-macros.rustc.stderr +++ b/tests/ui/check-cfg/report-in-external-macros.rustc.stderr @@ -18,7 +18,7 @@ warning: unexpected `cfg` condition value: `UNEXPECTED_VALUE` LL | cfg_macro::my_lib_macro_value!(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `panic` are: `abort` and `unwind` + = note: expected values for `panic` are: `abort`, `immediate-abort`, and `unwind` = note: using a cfg inside a macro will use the cfgs from the destination crate and not the ones from the defining crate = help: try referring to `cfg_macro::my_lib_macro_value` crate for guidance on how handle this unexpected cfg = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index df2357696a3..e62f741b302 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -80,7 +80,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | panic = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `panic` are: `abort` and `unwind` + = note: expected values for `panic` are: `abort`, `immediate-abort`, and `unwind` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/panic-runtime/auxiliary/needs-abort.rs b/tests/ui/panic-runtime/auxiliary/needs-abort.rs index 21f862e4b43..cba4907dbb6 100644 --- a/tests/ui/panic-runtime/auxiliary/needs-abort.rs +++ b/tests/ui/panic-runtime/auxiliary/needs-abort.rs @@ -1,5 +1,7 @@ //@ compile-flags:-C panic=abort //@ no-prefer-dynamic +#![feature(no_core)] #![crate_type = "rlib"] #![no_std] +#![no_core] diff --git a/tests/ui/panic-runtime/auxiliary/needs-immediate-abort.rs b/tests/ui/panic-runtime/auxiliary/needs-immediate-abort.rs new file mode 100644 index 00000000000..4a41d16faa0 --- /dev/null +++ b/tests/ui/panic-runtime/auxiliary/needs-immediate-abort.rs @@ -0,0 +1,7 @@ +//@ compile-flags:-C panic=immediate-abort -Zunstable-options +//@ no-prefer-dynamic + +#![feature(no_core)] +#![crate_type = "rlib"] +#![no_std] +#![no_core] diff --git a/tests/ui/panic-runtime/auxiliary/needs-unwind-immediate-abort.rs b/tests/ui/panic-runtime/auxiliary/needs-unwind-immediate-abort.rs new file mode 100644 index 00000000000..295876fec52 --- /dev/null +++ b/tests/ui/panic-runtime/auxiliary/needs-unwind-immediate-abort.rs @@ -0,0 +1,18 @@ +//@ compile-flags:-C panic=unwind +//@ no-prefer-dynamic +//@ add-core-stubs + +#![crate_type = "rlib"] +#![feature(no_core)] +#![no_std] +#![no_core] + +extern crate minicore; + +extern "C-unwind" fn foo() {} + +#[inline] +fn bar() { + let ptr: extern "C-unwind" fn() = foo; + ptr(); +} diff --git a/tests/ui/panic-runtime/bad-panic-flag1.rs b/tests/ui/panic-runtime/bad-panic-flag1.rs index 117935847cb..575e30f785c 100644 --- a/tests/ui/panic-runtime/bad-panic-flag1.rs +++ b/tests/ui/panic-runtime/bad-panic-flag1.rs @@ -2,4 +2,4 @@ fn main() {} -//~? ERROR incorrect value `foo` for codegen option `panic` - either `unwind` or `abort` was expected +//~? ERROR incorrect value `foo` for codegen option `panic` - either `unwind`, `abort`, or `immediate-abort` was expected diff --git a/tests/ui/panic-runtime/bad-panic-flag1.stderr b/tests/ui/panic-runtime/bad-panic-flag1.stderr index 013373c6f93..c30598bba53 100644 --- a/tests/ui/panic-runtime/bad-panic-flag1.stderr +++ b/tests/ui/panic-runtime/bad-panic-flag1.stderr @@ -1,2 +1,2 @@ -error: incorrect value `foo` for codegen option `panic` - either `unwind` or `abort` was expected +error: incorrect value `foo` for codegen option `panic` - either `unwind`, `abort`, or `immediate-abort` was expected diff --git a/tests/ui/panic-runtime/bad-panic-flag2.rs b/tests/ui/panic-runtime/bad-panic-flag2.rs index b5d0442a033..4e34da217d7 100644 --- a/tests/ui/panic-runtime/bad-panic-flag2.rs +++ b/tests/ui/panic-runtime/bad-panic-flag2.rs @@ -2,4 +2,4 @@ fn main() {} -//~? ERROR codegen option `panic` requires either `unwind` or `abort` +//~? ERROR codegen option `panic` requires either `unwind`, `abort`, or `immediate-abort` diff --git a/tests/ui/panic-runtime/bad-panic-flag2.stderr b/tests/ui/panic-runtime/bad-panic-flag2.stderr index 6ab94ea704d..c8d12749c5d 100644 --- a/tests/ui/panic-runtime/bad-panic-flag2.stderr +++ b/tests/ui/panic-runtime/bad-panic-flag2.stderr @@ -1,2 +1,2 @@ -error: codegen option `panic` requires either `unwind` or `abort` (C panic=<value>) +error: codegen option `panic` requires either `unwind`, `abort`, or `immediate-abort` (C panic=<value>) diff --git a/tests/ui/panic-runtime/immediate-abort-default-sysroot.rs b/tests/ui/panic-runtime/immediate-abort-default-sysroot.rs new file mode 100644 index 00000000000..94dc7c5671e --- /dev/null +++ b/tests/ui/panic-runtime/immediate-abort-default-sysroot.rs @@ -0,0 +1,15 @@ +//@ build-fail +//@ aux-build:needs-unwind.rs +//@ compile-flags:-C panic=immediate-abort -Zunstable-options +//@ no-prefer-dynamic + +extern crate needs_unwind; + +// immediate-abort does not require any panic runtime, so trying to build a binary crate with +// panic=immediate-abort and the precompiled sysroot will fail to link, because no panic runtime +// provides the panic entrypoints used by sysroot crates. +// This test ensures that we get a clean compile error instead of a linker error. + +fn main() {} + +//~? ERROR the crate `core` was compiled with a panic strategy which is incompatible with `immediate-abort` diff --git a/tests/ui/panic-runtime/immediate-abort-default-sysroot.stderr b/tests/ui/panic-runtime/immediate-abort-default-sysroot.stderr new file mode 100644 index 00000000000..bd6bdd8b667 --- /dev/null +++ b/tests/ui/panic-runtime/immediate-abort-default-sysroot.stderr @@ -0,0 +1,4 @@ +error: the crate `core` was compiled with a panic strategy which is incompatible with `immediate-abort` + +error: aborting due to 1 previous error + diff --git a/tests/ui/panic-runtime/need-abort-got-immediate-abort.rs b/tests/ui/panic-runtime/need-abort-got-immediate-abort.rs new file mode 100644 index 00000000000..78977c60be9 --- /dev/null +++ b/tests/ui/panic-runtime/need-abort-got-immediate-abort.rs @@ -0,0 +1,21 @@ +//@ build-fail +//@ aux-build:needs-abort.rs +//@ compile-flags:-Cpanic=immediate-abort -Zunstable-options +//@ no-prefer-dynamic +//@ add-core-stubs +//@ core-stubs-compile-flags: -Cpanic=immediate-abort -Zunstable-options + +#![feature(no_core)] +#![no_std] +#![no_main] +#![no_core] + +extern crate minicore; +extern crate needs_abort; + +#[no_mangle] +extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { + 0 +} + +//~? ERROR the crate `needs_abort` was compiled with a panic strategy which is incompatible with `immediate-abort` diff --git a/tests/ui/panic-runtime/need-abort-got-immediate-abort.stderr b/tests/ui/panic-runtime/need-abort-got-immediate-abort.stderr new file mode 100644 index 00000000000..65a26b676b9 --- /dev/null +++ b/tests/ui/panic-runtime/need-abort-got-immediate-abort.stderr @@ -0,0 +1,4 @@ +error: the crate `needs_abort` was compiled with a panic strategy which is incompatible with `immediate-abort` + +error: aborting due to 1 previous error + diff --git a/tests/ui/panic-runtime/need-immediate-abort-got-abort.rs b/tests/ui/panic-runtime/need-immediate-abort-got-abort.rs new file mode 100644 index 00000000000..1c5f597a3f9 --- /dev/null +++ b/tests/ui/panic-runtime/need-immediate-abort-got-abort.rs @@ -0,0 +1,20 @@ +//@ build-fail +//@ aux-build:needs-immediate-abort.rs +//@ compile-flags:-C panic=abort +//@ no-prefer-dynamic +//@ add-core-stubs +//@ core-stubs-compile-flags: -Zunstable-options -Cpanic=immediate-abort + +#![feature(no_core)] +#![no_std] +#![no_main] +#![no_core] + +extern crate minicore; +extern crate needs_immediate_abort; + +extern "C" fn main(argc: i32, argv: *const *const u8) -> i32 { + 0 +} + +//~? ERROR the crate `need_immediate_abort_got_abort` was compiled with a panic strategy which is incompatible with `immediate-abort` diff --git a/tests/ui/panic-runtime/need-immediate-abort-got-abort.stderr b/tests/ui/panic-runtime/need-immediate-abort-got-abort.stderr new file mode 100644 index 00000000000..8dcf120cb9f --- /dev/null +++ b/tests/ui/panic-runtime/need-immediate-abort-got-abort.stderr @@ -0,0 +1,4 @@ +error: the crate `need_immediate_abort_got_abort` was compiled with a panic strategy which is incompatible with `immediate-abort` + +error: aborting due to 1 previous error + diff --git a/tests/ui/panic-runtime/need-immediate-abort-got-unwind.rs b/tests/ui/panic-runtime/need-immediate-abort-got-unwind.rs new file mode 100644 index 00000000000..24d521230d4 --- /dev/null +++ b/tests/ui/panic-runtime/need-immediate-abort-got-unwind.rs @@ -0,0 +1,20 @@ +//@ build-fail +//@ needs-unwind +//@ aux-build:needs-immediate-abort.rs +//@ no-prefer-dynamic +//@ add-core-stubs +//@ core-stubs-compile-flags: -Zunstable-options -Cpanic=immediate-abort + +#![feature(no_core)] +#![no_std] +#![no_main] +#![no_core] + +extern crate minicore; +extern crate needs_immediate_abort; + +extern "C" fn main(argc: i32, argv: *const *const u8) -> i32 { + 0 +} + +//~? ERROR the crate `need_immediate_abort_got_unwind` was compiled with a panic strategy which is incompatible with `immediate-abort` diff --git a/tests/ui/panic-runtime/need-immediate-abort-got-unwind.stderr b/tests/ui/panic-runtime/need-immediate-abort-got-unwind.stderr new file mode 100644 index 00000000000..740fc80a77d --- /dev/null +++ b/tests/ui/panic-runtime/need-immediate-abort-got-unwind.stderr @@ -0,0 +1,4 @@ +error: the crate `need_immediate_abort_got_unwind` was compiled with a panic strategy which is incompatible with `immediate-abort` + +error: aborting due to 1 previous error + diff --git a/tests/ui/panic-runtime/need-unwind-got-immediate-abort.rs b/tests/ui/panic-runtime/need-unwind-got-immediate-abort.rs new file mode 100644 index 00000000000..5aec028a46c --- /dev/null +++ b/tests/ui/panic-runtime/need-unwind-got-immediate-abort.rs @@ -0,0 +1,21 @@ +//@ build-fail +//@ aux-build:needs-unwind-immediate-abort.rs +//@ compile-flags:-C panic=immediate-abort -Zunstable-options +//@ no-prefer-dynamic +//@ add-core-stubs +//@ core-stubs-compile-flags: -Zunstable-options -Cpanic=immediate-abort + +#![feature(no_core)] +#![no_std] +#![no_main] +#![no_core] + +extern crate minicore; +extern crate needs_unwind_immediate_abort; + +#[no_mangle] +extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { + 0 +} + +//~? ERROR the crate `needs_unwind_immediate_abort` was compiled with a panic strategy which is incompatible with `immediate-abort` diff --git a/tests/ui/panic-runtime/need-unwind-got-immediate-abort.stderr b/tests/ui/panic-runtime/need-unwind-got-immediate-abort.stderr new file mode 100644 index 00000000000..8b3747d644f --- /dev/null +++ b/tests/ui/panic-runtime/need-unwind-got-immediate-abort.stderr @@ -0,0 +1,4 @@ +error: the crate `needs_unwind_immediate_abort` was compiled with a panic strategy which is incompatible with `immediate-abort` + +error: aborting due to 1 previous error + diff --git a/tests/ui/proc-macro/panic-abort.rs b/tests/ui/proc-macro/panic-abort.rs index 58e1d006433..adedba4ebca 100644 --- a/tests/ui/proc-macro/panic-abort.rs +++ b/tests/ui/proc-macro/panic-abort.rs @@ -2,4 +2,4 @@ //@ force-host //@ check-pass -//~? WARN building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic +//~? WARN building proc macro crate with `panic=abort` or `panic=immediate-abort` may crash the compiler should the proc-macro panic diff --git a/tests/ui/proc-macro/panic-abort.stderr b/tests/ui/proc-macro/panic-abort.stderr index a6e18614f8f..3dd75768bc4 100644 --- a/tests/ui/proc-macro/panic-abort.stderr +++ b/tests/ui/proc-macro/panic-abort.stderr @@ -1,4 +1,4 @@ -warning: building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic +warning: building proc macro crate with `panic=abort` or `panic=immediate-abort` may crash the compiler should the proc-macro panic warning: 1 warning emitted |
