core/
panic.rs

1//! Panic support in the standard library.
2
3#![stable(feature = "core_panic_info", since = "1.41.0")]
4
5mod location;
6#[cfg(not(feature = "ferrocene_certified"))]
7mod panic_info;
8#[cfg(not(feature = "ferrocene_certified"))]
9mod unwind_safe;
10
11#[stable(feature = "panic_hooks", since = "1.10.0")]
12pub use self::location::Location;
13#[stable(feature = "panic_hooks", since = "1.10.0")]
14#[cfg(not(feature = "ferrocene_certified"))]
15pub use self::panic_info::PanicInfo;
16#[stable(feature = "panic_info_message", since = "1.81.0")]
17#[cfg(not(feature = "ferrocene_certified"))]
18pub use self::panic_info::PanicMessage;
19#[stable(feature = "catch_unwind", since = "1.9.0")]
20#[cfg(not(feature = "ferrocene_certified"))]
21pub use self::unwind_safe::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe};
22#[cfg(not(feature = "ferrocene_certified"))]
23use crate::any::Any;
24
25#[doc(hidden)]
26#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
27#[allow_internal_unstable(panic_internals, const_format_args)]
28#[rustc_diagnostic_item = "core_panic_2015_macro"]
29#[rustc_macro_transparency = "semitransparent"]
30#[cfg(not(feature = "ferrocene_certified"))]
31pub macro panic_2015 {
32    () => (
33        $crate::panicking::panic("explicit panic")
34    ),
35    ($msg:literal $(,)?) => (
36        $crate::panicking::panic($msg)
37    ),
38    // Use `panic_str_2015` instead of `panic_display::<&str>` for non_fmt_panic lint.
39    ($msg:expr $(,)?) => ({
40        $crate::panicking::panic_str_2015($msg);
41    }),
42    // Special-case the single-argument case for const_panic.
43    ("{}", $arg:expr $(,)?) => ({
44        $crate::panicking::panic_display(&$arg);
45    }),
46    ($fmt:expr, $($arg:tt)+) => ({
47        // Semicolon to prevent temporaries inside the formatting machinery from
48        // being considered alive in the caller after the panic_fmt call.
49        $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+));
50    }),
51}
52
53#[doc(hidden)]
54#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
55#[allow_internal_unstable(panic_internals, const_format_args)]
56#[rustc_diagnostic_item = "core_panic_2021_macro"]
57#[rustc_macro_transparency = "semitransparent"]
58#[cfg(all(feature = "ferrocene_certified", feature = "panic_immediate_abort"))]
59pub macro panic_2021($($t:tt)*) {{ $crate::panicking::panic("explicit panic") }}
60
61#[doc(hidden)]
62#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
63#[allow_internal_unstable(panic_internals, const_format_args)]
64#[rustc_diagnostic_item = "core_panic_2021_macro"]
65#[rustc_macro_transparency = "semitransparent"]
66#[cfg(feature = "panic_immediate_abort")]
67#[cfg(not(feature = "ferrocene_certified"))]
68pub macro panic_2021 {
69    () => (
70        $crate::panicking::panic("explicit panic")
71    ),
72    // Special-case the single-argument case for const_panic.
73    ("{}", $arg:expr $(,)?) => ({
74        $crate::panicking::panic_display(&$arg);
75    }),
76    ($($t:tt)+) => ({
77        // Semicolon to prevent temporaries inside the formatting machinery from
78        // being considered alive in the caller after the panic_fmt call.
79        $crate::panicking::panic_fmt($crate::const_format_args!($($t)+));
80    }),
81}
82
83#[doc(hidden)]
84#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
85#[allow_internal_unstable(
86    panic_internals,
87    core_intrinsics,
88    const_dispatch,
89    const_eval_select,
90    const_format_args,
91    rustc_attrs
92)]
93#[rustc_diagnostic_item = "core_panic_2021_macro"]
94#[rustc_macro_transparency = "semitransparent"]
95#[cfg(not(feature = "panic_immediate_abort"))]
96#[cfg(not(feature = "ferrocene_certified"))]
97pub macro panic_2021 {
98    () => ({
99        // Create a function so that the argument for `track_caller`
100        // can be moved inside if possible.
101        #[cold]
102        #[track_caller]
103        #[inline(never)]
104        const fn panic_cold_explicit() -> ! {
105            $crate::panicking::panic_explicit()
106        }
107        panic_cold_explicit();
108    }),
109    // Special-case the single-argument case for const_panic.
110    ("{}", $arg:expr $(,)?) => ({
111        #[cold]
112        #[track_caller]
113        #[inline(never)]
114        #[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval
115        #[rustc_do_not_const_check] // hooked by const-eval
116        const fn panic_cold_display<T: $crate::fmt::Display>(arg: &T) -> ! {
117            $crate::panicking::panic_display(arg)
118        }
119        panic_cold_display(&$arg);
120    }),
121    ($($t:tt)+) => ({
122        // Semicolon to prevent temporaries inside the formatting machinery from
123        // being considered alive in the caller after the panic_fmt call.
124        $crate::panicking::panic_fmt($crate::const_format_args!($($t)+));
125    }),
126}
127
128#[doc(hidden)]
129#[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")]
130#[allow_internal_unstable(panic_internals)]
131#[rustc_diagnostic_item = "unreachable_2015_macro"]
132#[rustc_macro_transparency = "semitransparent"]
133#[cfg(not(feature = "ferrocene_certified"))]
134pub macro unreachable_2015 {
135    () => (
136        $crate::panicking::panic("internal error: entered unreachable code")
137    ),
138    // Use of `unreachable_display` for non_fmt_panic lint.
139    // NOTE: the message ("internal error ...") is embedded directly in unreachable_display
140    ($msg:expr $(,)?) => ({
141        $crate::panicking::unreachable_display(&$msg);
142    }),
143    ($fmt:expr, $($arg:tt)*) => (
144        $crate::panic!($crate::concat!("internal error: entered unreachable code: ", $fmt), $($arg)*)
145    ),
146}
147
148#[doc(hidden)]
149#[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")]
150#[allow_internal_unstable(panic_internals)]
151#[rustc_macro_transparency = "semitransparent"]
152#[cfg(not(feature = "ferrocene_certified"))]
153pub macro unreachable_2021 {
154    () => (
155        $crate::panicking::panic("internal error: entered unreachable code")
156    ),
157    ($($t:tt)+) => (
158        $crate::panic!("internal error: entered unreachable code: {}", $crate::format_args!($($t)+))
159    ),
160}
161
162/// Invokes a closure, aborting if the closure unwinds.
163///
164/// When compiled with aborting panics, this function is effectively a no-op.
165/// With unwinding panics, an unwind results in another call into the panic
166/// hook followed by a process abort.
167///
168/// # Notes
169///
170/// Instead of using this function, code should attempt to support unwinding.
171/// Implementing [`Drop`] allows you to restore invariants uniformly in both
172/// return and unwind paths.
173///
174/// If an unwind can lead to logical issues but not soundness issues, you
175/// should allow the unwind. Opting out of [`UnwindSafe`] indicates to your
176/// consumers that they need to consider correctness in the face of unwinds.
177///
178/// If an unwind would be unsound, then this function should be used in order
179/// to prevent unwinds. However, note that `extern "C" fn` will automatically
180/// convert unwinds to aborts, so using this function isn't necessary for FFI.
181#[unstable(feature = "abort_unwind", issue = "130338")]
182#[rustc_nounwind]
183#[cfg(not(feature = "ferrocene_certified"))]
184pub fn abort_unwind<F: FnOnce() -> R, R>(f: F) -> R {
185    f()
186}
187
188/// An internal trait used by std to pass data from std to `panic_unwind` and
189/// other panic runtimes. Not intended to be stabilized any time soon, do not
190/// use.
191#[unstable(feature = "std_internals", issue = "none")]
192#[doc(hidden)]
193#[cfg(not(feature = "ferrocene_certified"))]
194pub unsafe trait PanicPayload: crate::fmt::Display {
195    /// Take full ownership of the contents.
196    /// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in core.
197    ///
198    /// After this method got called, only some dummy default value is left in `self`.
199    /// Calling this method twice, or calling `get` after calling this method, is an error.
200    ///
201    /// The argument is borrowed because the panic runtime (`__rust_start_panic`) only
202    /// gets a borrowed `dyn PanicPayload`.
203    fn take_box(&mut self) -> *mut (dyn Any + Send);
204
205    /// Just borrow the contents.
206    fn get(&mut self) -> &(dyn Any + Send);
207
208    /// Tries to borrow the contents as `&str`, if possible without doing any allocations.
209    fn as_str(&mut self) -> Option<&str> {
210        None
211    }
212}
213
214/// Helper macro for panicking in a `const fn`.
215/// Invoke as:
216/// ```rust,ignore (just an example)
217/// core::macros::const_panic!("boring message", "flavored message {a} {b:?}", a: u32 = foo.len(), b: Something = bar);
218/// ```
219/// where the first message will be printed in const-eval,
220/// and the second message will be printed at runtime.
221// All uses of this macro are FIXME(const-hack).
222#[unstable(feature = "panic_internals", issue = "none")]
223#[doc(hidden)]
224#[cfg(not(feature = "ferrocene_certified"))]
225pub macro const_panic {
226    ($const_msg:literal, $runtime_msg:literal, $($arg:ident : $ty:ty = $val:expr),* $(,)?) => {{
227        // Wrap call to `const_eval_select` in a function so that we can
228        // add the `rustc_allow_const_fn_unstable`. This is okay to do
229        // because both variants will panic, just with different messages.
230        #[rustc_allow_const_fn_unstable(const_eval_select)]
231        #[inline(always)] // inline the wrapper
232        #[track_caller]
233        const fn do_panic($($arg: $ty),*) -> ! {
234            $crate::intrinsics::const_eval_select!(
235                @capture { $($arg: $ty = $arg),* } -> !:
236                #[noinline]
237                if const #[track_caller] #[inline] { // Inline this, to prevent codegen
238                    $crate::panic!($const_msg)
239                } else #[track_caller] { // Do not inline this, it makes perf worse
240                    $crate::panic!($runtime_msg)
241                }
242            )
243        }
244
245        do_panic($($val),*)
246    }},
247    // We support leaving away the `val` expressions for *all* arguments
248    // (but not for *some* arguments, that's too tricky).
249    ($const_msg:literal, $runtime_msg:literal, $($arg:ident : $ty:ty),* $(,)?) => {
250        $crate::panic::const_panic!(
251            $const_msg,
252            $runtime_msg,
253            $($arg: $ty = $arg),*
254        )
255    },
256}
257
258/// A version of `assert` that prints a non-formatting message in const contexts.
259///
260/// See [`const_panic!`].
261#[unstable(feature = "panic_internals", issue = "none")]
262#[doc(hidden)]
263#[cfg(not(feature = "ferrocene_certified"))]
264pub macro const_assert {
265    ($condition: expr, $const_msg:literal, $runtime_msg:literal, $($arg:tt)*) => {{
266        if !$crate::intrinsics::likely($condition) {
267            $crate::panic::const_panic!($const_msg, $runtime_msg, $($arg)*)
268        }
269    }}
270}