diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index b729d5e116d2c..6db1a1c22029e 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -26,6 +26,11 @@ compiler-builtins-no-f16-f128 = ["compiler_builtins/no-f16-f128"] compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"] # Make panics and failed asserts immediately abort without formatting any message panic_immediate_abort = ["core/panic_immediate_abort"] +# Make the optimizer assume panics are unreachable. +panic_unreachable_unchecked = [ + "panic_immediate_abort", + "core/panic_unreachable_unchecked", +] # 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 1e03a191276ca..679f54de987fe 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -400,6 +400,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! { } #[inline] + #[cfg(not(feature = "panic_immediate_abort"))] fn rt_error(layout: Layout) -> ! { unsafe { __rust_alloc_error_handler(layout.size(), layout.align()); diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml index b60826ee4e6c7..ae31a40003ba8 100644 --- a/library/core/Cargo.toml +++ b/library/core/Cargo.toml @@ -18,6 +18,8 @@ bench = false [features] # Make panics and failed asserts immediately abort without formatting any message panic_immediate_abort = [] +# Make the optimizer assume panics are unreachable. +panic_unreachable_unchecked = ["panic_immediate_abort"] # Choose algorithms that are optimized for binary size instead of runtime performance optimize_for_size = [] # Make `RefCell` store additional debugging information, which is printed out when diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 33ad59916e391..e56b03de24edb 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -53,6 +53,10 @@ const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C #[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_unreachable_unchecked") { + // SAFETY: it's not... + unsafe { super::intrinsics::unreachable() } + } if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() } @@ -94,6 +98,10 @@ 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_unreachable_unchecked") { + // SAFETY: it's not... + unsafe { super::intrinsics::unreachable() } + } if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() } @@ -266,6 +274,10 @@ pub const fn panic_display(x: &T) -> ! { #[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_unreachable_unchecked") { + // SAFETY: it's not... + unsafe { super::intrinsics::unreachable() } + } if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() } @@ -279,6 +291,10 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { #[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_unreachable_unchecked") { + // SAFETY: it's not... + unsafe { super::intrinsics::unreachable() } + } if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() } @@ -297,6 +313,10 @@ fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! { #[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_unreachable_unchecked") { + // SAFETY: it's not... + unsafe { super::intrinsics::unreachable() } + } if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 5cc08f8a71afb..6327f6c425e3d 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -78,6 +78,7 @@ const fn slice_error_fail_ct(_: &str, _: usize, _: usize) -> ! { panic!("failed to slice string"); } +#[cfg(not(feature = "panic_immediate_abort"))] #[track_caller] fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! { const MAX_DISPLAY_LENGTH: usize = 256; diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 176da603d58d7..5519149d193e3 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -107,6 +107,12 @@ panic_immediate_abort = [ "core/panic_immediate_abort", "alloc/panic_immediate_abort", ] +# Make the optimizer assume panics are unreachable. +panic_unreachable_unchecked = [ + "panic_immediate_abort", + "core/panic_unreachable_unchecked", + "alloc/panic_unreachable_unchecked", +] # 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 b35549c92ada7..6a4f738ddf750 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -19,13 +19,14 @@ use realstd::io::try_set_output_capture; use crate::any::Any; #[cfg(not(test))] use crate::io::try_set_output_capture; -use crate::mem::{self, ManuallyDrop}; +#[cfg(not(feature = "panic_immediate_abort"))] +use crate::mem::ManuallyDrop; use crate::panic::{BacktraceStyle, PanicHookInfo}; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::{PoisonError, RwLock}; use crate::sys::backtrace; use crate::sys::stdio::panic_output; -use crate::{fmt, intrinsics, process, thread}; +use crate::{fmt, intrinsics, mem, process, thread}; // This forces codegen of the function called by panic!() inside the std crate, rather than in // downstream crates. Primarily this is useful for rustc's codegen tests, which rely on noticing @@ -341,7 +342,7 @@ pub mod panic_count { } #[inline] - pub fn increase(run_panic_hook: bool) -> Option { + pub fn increase(_run_panic_hook: bool) -> Option { None } @@ -726,6 +727,10 @@ pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! { #[track_caller] #[rustc_do_not_const_check] // hooked by const-eval pub const fn begin_panic(msg: M) -> ! { + if cfg!(feature = "panic_unreachable_unchecked") { + // SAFETY: it's not... + unsafe { super::intrinsics::unreachable() } + } if cfg!(feature = "panic_immediate_abort") { intrinsics::abort() } @@ -898,7 +903,5 @@ fn rust_panic(msg: &mut dyn PanicPayload) -> ! { #[cfg_attr(not(test), rustc_std_internal_symbol)] #[cfg(feature = "panic_immediate_abort")] fn rust_panic(_: &mut dyn PanicPayload) -> ! { - unsafe { - crate::intrinsics::abort(); - } + crate::intrinsics::abort(); } diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index ec6ae31507e05..a6f09c1864348 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -28,6 +28,7 @@ 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"] +panic_unreachable_unchecked = ["std/panic_unreachable_unchecked"] profiler = ["dep:profiler_builtins"] std_detect_file_io = ["std/std_detect_file_io"] std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"]