1#![allow(dead_code, missing_docs)]
25#![unstable(
26 feature = "panic_internals",
27 reason = "internal details of the implementation of the `panic!` and related macros",
28 issue = "none"
29)]
30
31#[cfg(not(feature = "ferrocene_certified"))]
32use crate::fmt;
33use crate::intrinsics::const_eval_select;
34#[cfg(not(feature = "ferrocene_certified"))]
35use crate::panic::{Location, PanicInfo};
36
37#[cfg(feature = "ferrocene_certified")]
39#[rustfmt::skip]
40use crate::panic::PanicInfo;
41
42#[cfg(not(feature = "ferrocene_certified"))]
44pub(crate) type PanicFmt<'a> = fmt::Arguments<'a>;
45#[cfg(feature = "ferrocene_certified")]
46pub(crate) type PanicFmt<'a> = &'a &'static str;
47
48#[cfg(feature = "panic_immediate_abort")]
49compile_error!(
50 "panic_immediate_abort is now a real panic strategy! \
51 Enable it with `panic = \"immediate-abort\"` in Cargo.toml, \
52 or with the compiler flags `-Zunstable-options -Cpanic=immediate-abort`. \
53 In both cases, you still need to build core, e.g. with `-Zbuild-std`"
54);
55
56#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
68#[cfg_attr(panic = "immediate-abort", inline)]
69#[track_caller]
70#[lang = "panic_fmt"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] pub const fn panic_fmt(fmt: PanicFmt<'_>) -> ! {
75 #[ferrocene::annotation(
76 "The `immediate-abort` behavior is not certified, we only support `abort`."
77 )]
78 if cfg!(panic = "immediate-abort") {
79 super::intrinsics::abort()
80 };
81
82 unsafe extern "Rust" {
85 #[lang = "panic_impl"]
86 fn panic_impl(pi: &PanicInfo<'_>) -> !;
87 }
88
89 #[cfg(not(feature = "ferrocene_certified"))]
90 let pi = PanicInfo::new(
91 &fmt,
92 Location::caller(),
93 true,
94 false,
95 );
96 #[cfg(feature = "ferrocene_certified")]
97 let pi = PanicInfo::new(&fmt);
98 unsafe { panic_impl(&pi) }
100}
101
102#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
106#[cfg_attr(panic = "immediate-abort", inline)]
107#[track_caller]
108#[rustc_nounwind]
112#[rustc_const_stable_indirect] #[rustc_allow_const_fn_unstable(const_eval_select)]
114#[ferrocene::annotation("Cannot be covered as it causes an unwinding panic")]
115pub const fn panic_nounwind_fmt(fmt: PanicFmt<'_>, _force_no_backtrace: bool) -> ! {
116 const_eval_select!(
117 @capture { fmt: PanicFmt<'_>, _force_no_backtrace: bool } -> !:
118 if const #[track_caller] {
119 panic_fmt(fmt)
121 } else #[track_caller] {
122 if cfg!(panic = "immediate-abort") {
123 super::intrinsics::abort()
124 }
125
126 unsafe extern "Rust" {
129 #[lang = "panic_impl"]
130 fn panic_impl(pi: &PanicInfo<'_>) -> !;
131 }
132
133 #[cfg(not(feature = "ferrocene_certified"))]
135 let pi = PanicInfo::new(
136 &fmt,
137 Location::caller(),
138 false,
139 _force_no_backtrace,
140 );
141 #[cfg(feature = "ferrocene_certified")]
142 let pi = PanicInfo::new(&fmt);
143
144 unsafe { panic_impl(&pi) }
146 }
147 )
148}
149
150#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
157#[cfg_attr(panic = "immediate-abort", inline)]
158#[track_caller]
159#[rustc_const_stable_indirect] #[lang = "panic"] pub const fn panic(expr: &'static str) -> ! {
162 #[cfg(not(feature = "ferrocene_certified"))]
174 panic_fmt(fmt::Arguments::from_str(expr));
175 #[cfg(feature = "ferrocene_certified")]
176 panic_fmt(&expr)
177}
178
179macro_rules! panic_const {
188 ($($lang:ident = $message:expr,)+) => {
189 $(
190 #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
195 #[cfg_attr(panic = "immediate-abort", inline)]
196 #[track_caller]
197 #[rustc_const_stable_indirect] #[lang = stringify!($lang)]
199 #[ferrocene::annotation("Cannot be covered as this code cannot be reached during runtime.")]
200 pub const fn $lang() -> ! {
201 #[cfg(not(feature = "ferrocene_certified"))]
203 panic_fmt(fmt::Arguments::from_str($message));
204 #[cfg(feature = "ferrocene_certified")]
205 panic_fmt(&$message);
206 }
207 )+
208 }
209}
210
211pub mod panic_const {
216 use super::*;
217 panic_const! {
218 panic_const_add_overflow = "attempt to add with overflow",
219 panic_const_sub_overflow = "attempt to subtract with overflow",
220 panic_const_mul_overflow = "attempt to multiply with overflow",
221 panic_const_div_overflow = "attempt to divide with overflow",
222 panic_const_rem_overflow = "attempt to calculate the remainder with overflow",
223 panic_const_neg_overflow = "attempt to negate with overflow",
224 panic_const_shr_overflow = "attempt to shift right with overflow",
225 panic_const_shl_overflow = "attempt to shift left with overflow",
226 panic_const_div_by_zero = "attempt to divide by zero",
227 panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero",
228 panic_const_coroutine_resumed = "coroutine resumed after completion",
229 panic_const_async_fn_resumed = "`async fn` resumed after completion",
230 panic_const_async_gen_fn_resumed = "`async gen fn` resumed after completion",
231 panic_const_gen_fn_none = "`gen fn` should just keep returning `None` after completion",
232 panic_const_coroutine_resumed_panic = "coroutine resumed after panicking",
233 panic_const_async_fn_resumed_panic = "`async fn` resumed after panicking",
234 panic_const_async_gen_fn_resumed_panic = "`async gen fn` resumed after panicking",
235 panic_const_gen_fn_none_panic = "`gen fn` should just keep returning `None` after panicking",
236 }
237 panic_const! {
240 panic_const_coroutine_resumed_drop = "coroutine resumed after async drop",
241 panic_const_async_fn_resumed_drop = "`async fn` resumed after async drop",
242 panic_const_async_gen_fn_resumed_drop = "`async gen fn` resumed after async drop",
243 panic_const_gen_fn_none_drop = "`gen fn` resumed after async drop",
244 }
245}
246
247#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
250#[cfg_attr(panic = "immediate-abort", inline)]
251#[lang = "panic_nounwind"] #[rustc_nounwind]
253#[rustc_const_stable_indirect] #[ferrocene::annotation("Cannot be covered as it causes an unwinding panic")]
255pub const fn panic_nounwind(expr: &'static str) -> ! {
256 #[cfg(not(feature = "ferrocene_certified"))]
257 panic_nounwind_fmt(fmt::Arguments::from_str(expr), false);
258 #[cfg(feature = "ferrocene_certified")]
259 panic_nounwind_fmt(&expr, false);
260}
261
262#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
264#[cfg_attr(panic = "immediate-abort", inline)]
265#[rustc_nounwind]
266#[cfg(not(feature = "ferrocene_certified"))]
267pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! {
268 panic_nounwind_fmt(fmt::Arguments::from_str(expr), true);
269}
270
271#[inline]
272#[track_caller]
273#[rustc_diagnostic_item = "unreachable_display"] #[cfg(not(feature = "ferrocene_certified"))]
275pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
276 panic_fmt(format_args!("internal error: entered unreachable code: {}", *x));
277}
278
279#[inline]
282#[track_caller]
283#[rustc_diagnostic_item = "panic_str_2015"]
284#[rustc_const_stable_indirect] #[cfg(not(feature = "ferrocene_certified"))]
286pub const fn panic_str_2015(expr: &str) -> ! {
287 panic_display(&expr);
288}
289
290#[inline]
291#[track_caller]
292#[lang = "panic_display"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] #[cfg(not(feature = "ferrocene_certified"))]
296pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
297 panic_fmt(format_args!("{}", *x));
298}
299
300#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
301#[cfg_attr(panic = "immediate-abort", inline)]
302#[track_caller]
303#[lang = "panic_bounds_check"] #[cfg_attr(feature = "ferrocene_certified", expect(unused_variables))]
305fn panic_bounds_check(index: usize, len: usize) -> ! {
306 if cfg!(panic = "immediate-abort") {
307 super::intrinsics::abort()
308 }
309 panic!("index out of bounds: the len is {len} but the index is {index}")
310}
311
312#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
313#[cfg_attr(panic = "immediate-abort", inline)]
314#[track_caller]
315#[lang = "panic_misaligned_pointer_dereference"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_certified"))]
318fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
319 if cfg!(panic = "immediate-abort") {
320 super::intrinsics::abort()
321 }
322
323 panic_nounwind_fmt(
324 format_args!(
325 "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
326 ),
327 false,
328 )
329}
330
331#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
332#[cfg_attr(panic = "immediate-abort", inline)]
333#[track_caller]
334#[lang = "panic_null_pointer_dereference"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_certified"))]
337fn panic_null_pointer_dereference() -> ! {
338 if cfg!(panic = "immediate-abort") {
339 super::intrinsics::abort()
340 }
341
342 panic_nounwind_fmt(
343 format_args!("null pointer dereference occurred"),
344 false,
345 )
346}
347
348#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
349#[cfg_attr(panic = "immediate-abort", inline)]
350#[track_caller]
351#[lang = "panic_invalid_enum_construction"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_certified"))]
354fn panic_invalid_enum_construction(source: u128) -> ! {
355 if cfg!(panic = "immediate-abort") {
356 super::intrinsics::abort()
357 }
358
359 panic_nounwind_fmt(
360 format_args!("trying to construct an enum from an invalid value {source:#x}"),
361 false,
362 )
363}
364
365#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
373#[cfg_attr(panic = "immediate-abort", inline)]
374#[lang = "panic_cannot_unwind"] #[rustc_nounwind]
376#[ferrocene::annotation("Cannot be covered as it causes an unwinding panic")]
377fn panic_cannot_unwind() -> ! {
378 panic_nounwind("panic in a function that cannot unwind")
380}
381
382#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
390#[cfg_attr(panic = "immediate-abort", inline)]
391#[lang = "panic_in_cleanup"] #[rustc_nounwind]
393#[cfg(not(feature = "ferrocene_certified"))]
394fn panic_in_cleanup() -> ! {
395 panic_nounwind_nobacktrace("panic in a destructor during cleanup")
397}
398
399#[lang = "const_panic_fmt"] #[rustc_const_stable_indirect] #[cfg(not(feature = "ferrocene_certified"))]
403pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
404 if let Some(msg) = fmt.as_str() {
405 panic_display(&msg);
407 } else {
408 unsafe { crate::hint::unreachable_unchecked() };
412 }
413}
414
415#[derive(Debug)]
416#[doc(hidden)]
417#[cfg(not(feature = "ferrocene_certified"))]
418pub enum AssertKind {
419 Eq,
420 Ne,
421 Match,
422}
423
424#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
426#[cfg_attr(panic = "immediate-abort", inline)]
427#[track_caller]
428#[doc(hidden)]
429#[cfg(not(feature = "ferrocene_certified"))]
430pub fn assert_failed<T, U>(
431 kind: AssertKind,
432 left: &T,
433 right: &U,
434 args: Option<fmt::Arguments<'_>>,
435) -> !
436where
437 T: fmt::Debug + ?Sized,
438 U: fmt::Debug + ?Sized,
439{
440 assert_failed_inner(kind, &left, &right, args)
441}
442
443#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
445#[cfg_attr(panic = "immediate-abort", inline)]
446#[track_caller]
447#[doc(hidden)]
448#[cfg(not(feature = "ferrocene_certified"))]
449pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
450 left: &T,
451 right: &str,
452 args: Option<fmt::Arguments<'_>>,
453) -> ! {
454 struct Pattern<'a>(&'a str);
456 impl fmt::Debug for Pattern<'_> {
457 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
458 f.write_str(self.0)
459 }
460 }
461 assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
462}
463
464#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
466#[cfg_attr(panic = "immediate-abort", inline)]
467#[track_caller]
468#[cfg(not(feature = "ferrocene_certified"))]
469fn assert_failed_inner(
470 kind: AssertKind,
471 left: &dyn fmt::Debug,
472 right: &dyn fmt::Debug,
473 args: Option<fmt::Arguments<'_>>,
474) -> ! {
475 let op = match kind {
476 AssertKind::Eq => "==",
477 AssertKind::Ne => "!=",
478 AssertKind::Match => "matches",
479 };
480
481 match args {
482 Some(args) => panic!(
483 r#"assertion `left {op} right` failed: {args}
484 left: {left:?}
485 right: {right:?}"#
486 ),
487 None => panic!(
488 r#"assertion `left {op} right` failed
489 left: {left:?}
490 right: {right:?}"#
491 ),
492 }
493}