Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions library/alloc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Copy link
Contributor

@MikailBag MikailBag Apr 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose to rename this feature to unsafe_panic_unreachable_unchecked, so that its name includes word unsafe, because this is actually an unsafe API (like #[no_mangle] attribute), and AFAIU all unsafe APIs tend to include unsafe in their usage (as part of their name, as a surrounding unsafe block, etc).

Alternatively, if this PR is a joke, I'd consider crabs_never_panic as an alternative name.

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

Expand Down
1 change: 1 addition & 0 deletions library/alloc/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
2 changes: 2 additions & 0 deletions library/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions library/core/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This safety comment is inadequate, the condition of soundness relies on the programmer asserting panics will never happen, so a more accurate comment is:

Suggested change
// SAFETY: it's not...
// SAFETY: The user of this flag asserts that a panic will never happen in their codebase
if you want to do april fools, go all in :^)

unsafe { super::intrinsics::unreachable() }
}
if cfg!(feature = "panic_immediate_abort") {
super::intrinsics::abort()
}
Expand Down Expand Up @@ -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()
}
Expand Down Expand Up @@ -266,6 +274,10 @@ pub const fn panic_display<T: fmt::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()
}
Expand All @@ -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()
}
Expand All @@ -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()
}
Expand Down
1 change: 1 addition & 0 deletions library/core/src/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions library/std/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand Down
15 changes: 9 additions & 6 deletions library/std/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -341,7 +342,7 @@ pub mod panic_count {
}

#[inline]
pub fn increase(run_panic_hook: bool) -> Option<MustAbort> {
pub fn increase(_run_panic_hook: bool) -> Option<MustAbort> {
None
}

Expand Down Expand Up @@ -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<M: Any + Send>(msg: M) -> ! {
if cfg!(feature = "panic_unreachable_unchecked") {
// SAFETY: it's not...
unsafe { super::intrinsics::unreachable() }
}
if cfg!(feature = "panic_immediate_abort") {
intrinsics::abort()
}
Expand Down Expand Up @@ -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();
}
1 change: 1 addition & 0 deletions library/sysroot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
Loading