core/
panic.rs

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