Add panic=immediate-abort

This commit is contained in:
Ben Kimock
2025-09-07 12:31:35 -04:00
parent 6710835ae7
commit 888679013d
74 changed files with 542 additions and 158 deletions

View File

@@ -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(|| {

View File

@@ -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");
}

View File

@@ -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.

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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"
});
}

View File

@@ -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`

View File

@@ -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);
}

View File

@@ -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}`

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -75,6 +75,16 @@ pub struct RequiredPanicStrategy {
pub desired_strategy: PanicStrategy,
}
#[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 {

View File

@@ -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,
}
}

View File

@@ -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(),
}
}

View File

@@ -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;
}

View File

@@ -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() {

View File

@@ -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>) {

View File

@@ -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.

View File

@@ -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)]

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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! {

View File

@@ -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"]

View File

@@ -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)
}

View File

@@ -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");

View File

@@ -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) -> ! {

View File

@@ -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 = []

View File

@@ -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) -> ! {

View File

@@ -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) -> ! {

View File

@@ -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) -> ! {

View File

@@ -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,

View File

@@ -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]

View File

@@ -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 {

View File

@@ -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!(

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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"]

View File

@@ -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();
}

View File

@@ -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)*);
}

View File

@@ -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) -> ! {

View File

@@ -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"]

View File

@@ -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

View File

@@ -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,

View File

@@ -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",

View File

@@ -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
}

View File

@@ -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"]

View File

@@ -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();
}

View File

@@ -0,0 +1,41 @@
#![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();
}

View File

@@ -0,0 +1,4 @@
[package]
name = "hello"
version = "0.1.0"
edition = "2024"

View File

@@ -0,0 +1 @@
fn main() {}

View File

@@ -0,0 +1,28 @@
//@ needs-target-std
#![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();
}

View File

@@ -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`

View File

@@ -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

View File

@@ -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`

View File

@@ -1,5 +1,7 @@
//@ compile-flags:-C panic=abort
//@ no-prefer-dynamic
#![feature(no_core)]
#![crate_type = "rlib"]
#![no_std]
#![no_core]

View File

@@ -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]

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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

View File

@@ -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`

View File

@@ -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>)

View File

@@ -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`

View File

@@ -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

View File

@@ -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`

View File

@@ -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

View File

@@ -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`

View File

@@ -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

View File

@@ -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`

View File

@@ -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

View File

@@ -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`

View File

@@ -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

View File

@@ -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

View File

@@ -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