1//! Panic support for core
2//!
3//! The core library cannot define panicking, but it does *declare* panicking. This
4//! means that the functions inside of core are allowed to panic, but to be
5//! useful an upstream crate must define panicking for core to use. The current
6//! interface for panicking is:
7//!
8//! ```
9//! fn panic_impl(pi: &core::panic::PanicInfo<'_>) -> !
10//! # { loop {} }
11//! ```
12//!
13//! This definition allows for panicking with any general message, but it does not
14//! allow for failing with a `Box<Any>` value. (`PanicInfo` just contains a `&(dyn Any + Send)`,
15//! for which we fill in a dummy value in `PanicInfo::internal_constructor`.)
16//! The reason for this is that core is not allowed to allocate.
17//!
18//! This module contains a few other panicking functions, but these are just the
19//! necessary lang items for the compiler. All panics are funneled through this
20//! one function. The actual symbol is declared through the `#[panic_handler]` attribute.
21
22#![allow(dead_code, missing_docs)]
23#![unstable(
24 feature = "panic_internals",
25 reason = "internal details of the implementation of the `panic!` and related macros",
26 issue = "none"
27)]
28
29use crate::fmt;
30use crate::panic::{Location, PanicInfo};
31
32#[cfg(feature = "panic_immediate_abort")]
33const _: () = assert!(cfg!(panic = "abort"), "panic_immediate_abort requires -C panic=abort");
34
35// First we define the two main entry points that all panics go through.
36// In the end both are just convenience wrappers around `panic_impl`.
37
38/// The entry point for panicking with a formatted message.
39///
40/// This is designed to reduce the amount of code required at the call
41/// site as much as possible (so that `panic!()` has as low an impact
42/// on (e.g.) the inlining of other functions as possible), by moving
43/// the actual formatting into this shared place.
44// If panic_immediate_abort, inline the abort call,
45// otherwise avoid inlining because of it is cold path.
46#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
47#[cfg_attr(feature = "panic_immediate_abort", inline)]
48#[track_caller]
49#[lang = "panic_fmt"] // needed for const-evaluated panics
50#[rustc_do_not_const_check] // hooked by const-eval
51#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
52pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
53 if cfg!(feature = "panic_immediate_abort") {
54 super::intrinsics::abort()
55 }
56
57 // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
58 // that gets resolved to the `#[panic_handler]` function.
59 extern "Rust" {
60 #[lang = "panic_impl"]
61 fn panic_impl(pi: &PanicInfo<'_>) -> !;
62 }
63
64 let pi: PanicInfo<'_> = PanicInfo::internal_constructor(
65 message:Some(&fmt),
66 Location::caller(),
67 /* can_unwind */ can_unwind:true,
68 /* force_no_backtrace */ force_no_backtrace:false,
69 );
70
71 // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
72 unsafe { panic_impl(&pi) }
73}
74
75/// Like `panic_fmt`, but for non-unwinding panics.
76///
77/// Has to be a separate function so that it can carry the `rustc_nounwind` attribute.
78#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
79#[cfg_attr(feature = "panic_immediate_abort", inline)]
80#[track_caller]
81// This attribute has the key side-effect that if the panic handler ignores `can_unwind`
82// and unwinds anyway, we will hit the "unwinding out of nounwind function" guard,
83// which causes a "panic in a function that cannot unwind".
84#[rustc_nounwind]
85#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
86pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! {
87 #[inline] // this should always be inlined into `panic_nounwind_fmt`
88 #[track_caller]
89 fn runtime(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! {
90 if cfg!(feature = "panic_immediate_abort") {
91 super::intrinsics::abort()
92 }
93
94 // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
95 // that gets resolved to the `#[panic_handler]` function.
96 extern "Rust" {
97 #[lang = "panic_impl"]
98 fn panic_impl(pi: &PanicInfo<'_>) -> !;
99 }
100
101 // PanicInfo with the `can_unwind` flag set to false forces an abort.
102 let pi = PanicInfo::internal_constructor(
103 Some(&fmt),
104 Location::caller(),
105 /* can_unwind */ false,
106 force_no_backtrace,
107 );
108
109 // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
110 unsafe { panic_impl(&pi) }
111 }
112
113 #[inline]
114 #[track_caller]
115 const fn comptime(fmt: fmt::Arguments<'_>, _force_no_backtrace: bool) -> ! {
116 // We don't unwind anyway at compile-time so we can call the regular `panic_fmt`.
117 panic_fmt(fmt);
118 }
119
120 // SAFETY: const panic does not care about unwinding
121 unsafe {
122 super::intrinsics::const_eval_select((fmt, force_no_backtrace), comptime, runtime);
123 }
124}
125
126// Next we define a bunch of higher-level wrappers that all bottom out in the two core functions
127// above.
128
129/// The underlying implementation of core's `panic!` macro when no formatting is used.
130// never inline unless panic_immediate_abort to avoid code
131// bloat at the call sites as much as possible
132#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
133#[cfg_attr(feature = "panic_immediate_abort", inline)]
134#[track_caller]
135#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
136#[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
137pub const fn panic(expr: &'static str) -> ! {
138 // Use Arguments::new_v1 instead of format_args!("{expr}") to potentially
139 // reduce size overhead. The format_args! macro uses str's Display trait to
140 // write expr, which calls Formatter::pad, which must accommodate string
141 // truncation and padding (even though none is used here). Using
142 // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
143 // output binary, saving up to a few kilobytes.
144 panic_fmt(fmt::Arguments::new_const(&[expr]));
145}
146
147/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize on the caller.
148/// If you want `#[track_caller]` for nicer errors, call `panic_nounwind_fmt` directly.
149#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
150#[cfg_attr(feature = "panic_immediate_abort", inline)]
151#[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics
152#[rustc_nounwind]
153#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
154pub const fn panic_nounwind(expr: &'static str) -> ! {
155 panic_nounwind_fmt(fmt:fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ force_no_backtrace:false);
156}
157
158/// Like `panic_nounwind`, but also inhibits showing a backtrace.
159#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
160#[cfg_attr(feature = "panic_immediate_abort", inline)]
161#[rustc_nounwind]
162pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! {
163 panic_nounwind_fmt(fmt:fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ force_no_backtrace:true);
164}
165
166#[inline]
167#[track_caller]
168#[rustc_diagnostic_item = "panic_str"]
169#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
170pub const fn panic_str(expr: &str) -> ! {
171 panic_display(&expr);
172}
173
174#[track_caller]
175#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
176#[cfg_attr(feature = "panic_immediate_abort", inline)]
177#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
178pub const fn panic_explicit() -> ! {
179 panic_display(&"explicit panic");
180}
181
182#[inline]
183#[track_caller]
184#[rustc_diagnostic_item = "unreachable_display"] // needed for `non-fmt-panics` lint
185pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
186 panic_fmt(format_args!("internal error: entered unreachable code: {}", *x));
187}
188
189#[inline]
190#[track_caller]
191#[rustc_do_not_const_check] // hooked by const-eval
192// enforce a &&str argument in const-check and hook this by const-eval
193#[rustc_const_panic_str]
194#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
195pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
196 panic_fmt(format_args!("{}", *x));
197}
198
199#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
200#[cfg_attr(feature = "panic_immediate_abort", inline)]
201#[track_caller]
202#[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access
203fn panic_bounds_check(index: usize, len: usize) -> ! {
204 if cfg!(feature = "panic_immediate_abort") {
205 super::intrinsics::abort()
206 }
207
208 panic!("index out of bounds: the len is {len} but the index is {index}")
209}
210
211#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
212#[cfg_attr(feature = "panic_immediate_abort", inline)]
213#[track_caller]
214#[lang = "panic_misaligned_pointer_dereference"] // needed by codegen for panic on misaligned pointer deref
215#[rustc_nounwind] // `CheckAlignment` MIR pass requires this function to never unwind
216fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
217 if cfg!(feature = "panic_immediate_abort") {
218 super::intrinsics::abort()
219 }
220
221 panic_nounwind_fmt(
222 fmt:format_args!(
223 "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
224 ),
225 /* force_no_backtrace */ force_no_backtrace:false,
226 )
227}
228
229/// Panic because we cannot unwind out of a function.
230///
231/// This is a separate function to avoid the codesize impact of each crate containing the string to
232/// pass to `panic_nounwind`.
233/// This function is called directly by the codegen backend, and must not have
234/// any extra arguments (including those synthesized by track_caller).
235#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
236#[cfg_attr(feature = "panic_immediate_abort", inline)]
237#[lang = "panic_cannot_unwind"] // needed by codegen for panic in nounwind function
238#[rustc_nounwind]
239fn panic_cannot_unwind() -> ! {
240 // Keep the text in sync with `UnwindTerminateReason::as_str` in `rustc_middle`.
241 panic_nounwind(expr:"panic in a function that cannot unwind")
242}
243
244/// Panic because we are unwinding out of a destructor during cleanup.
245///
246/// This is a separate function to avoid the codesize impact of each crate containing the string to
247/// pass to `panic_nounwind`.
248/// This function is called directly by the codegen backend, and must not have
249/// any extra arguments (including those synthesized by track_caller).
250#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
251#[cfg_attr(feature = "panic_immediate_abort", inline)]
252#[lang = "panic_in_cleanup"] // needed by codegen for panic in nounwind function
253#[rustc_nounwind]
254fn panic_in_cleanup() -> ! {
255 // Keep the text in sync with `UnwindTerminateReason::as_str` in `rustc_middle`.
256 panic_nounwind_nobacktrace(expr:"panic in a destructor during cleanup")
257}
258
259/// This function is used instead of panic_fmt in const eval.
260#[lang = "const_panic_fmt"]
261#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
262pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
263 if let Some(msg: &str) = fmt.as_str() {
264 // The panic_display function is hooked by const eval.
265 panic_display(&msg);
266 } else {
267 // SAFETY: This is only evaluated at compile time, which reliably
268 // handles this UB (in case this branch turns out to be reachable
269 // somehow).
270 unsafe { crate::hint::unreachable_unchecked() };
271 }
272}
273
274#[derive(Debug)]
275#[doc(hidden)]
276pub enum AssertKind {
277 Eq,
278 Ne,
279 Match,
280}
281
282/// Internal function for `assert_eq!` and `assert_ne!` macros
283#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
284#[cfg_attr(feature = "panic_immediate_abort", inline)]
285#[track_caller]
286#[doc(hidden)]
287pub fn assert_failed<T, U>(
288 kind: AssertKind,
289 left: &T,
290 right: &U,
291 args: Option<fmt::Arguments<'_>>,
292) -> !
293where
294 T: fmt::Debug + ?Sized,
295 U: fmt::Debug + ?Sized,
296{
297 assert_failed_inner(kind, &left, &right, args)
298}
299
300/// Internal function for `assert_match!`
301#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
302#[cfg_attr(feature = "panic_immediate_abort", inline)]
303#[track_caller]
304#[doc(hidden)]
305pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
306 left: &T,
307 right: &str,
308 args: Option<fmt::Arguments<'_>>,
309) -> ! {
310 // The pattern is a string so it can be displayed directly.
311 struct Pattern<'a>(&'a str);
312 impl fmt::Debug for Pattern<'_> {
313 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
314 f.write_str(self.0)
315 }
316 }
317 assert_failed_inner(kind:AssertKind::Match, &left, &Pattern(right), args);
318}
319
320/// Non-generic version of the above functions, to avoid code bloat.
321#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
322#[cfg_attr(feature = "panic_immediate_abort", inline)]
323#[track_caller]
324fn assert_failed_inner(
325 kind: AssertKind,
326 left: &dyn fmt::Debug,
327 right: &dyn fmt::Debug,
328 args: Option<fmt::Arguments<'_>>,
329) -> ! {
330 let op: &str = match kind {
331 AssertKind::Eq => "==",
332 AssertKind::Ne => "!=",
333 AssertKind::Match => "matches",
334 };
335
336 match args {
337 Some(args: Arguments<'_>) => panic!(
338 r#"assertion `left {op} right` failed: {args}
339 left: {left:?}
340 right: {right:?}"#
341 ),
342 None => panic!(
343 r#"assertion `left {op} right` failed
344 left: {left:?}
345 right: {right:?}"#
346 ),
347 }
348}
349