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(feature = "ferrocene_certified")]
35use crate::panic::PanicInfo;
36#[cfg(not(feature = "ferrocene_certified"))]
37use crate::panic::{Location, PanicInfo};
38
39#[cfg(not(feature = "ferrocene_certified"))]
41pub(crate) type PanicFmt<'a> = fmt::Arguments<'a>;
42#[cfg(feature = "ferrocene_certified")]
43pub(crate) type PanicFmt<'a> = &'a &'static str;
44
45#[cfg(feature = "panic_immediate_abort")]
46compile_error!(
47 "panic_immediate_abort is now a real panic strategy! \
48 Enable it with `panic = \"immediate-abort\"` in Cargo.toml, \
49 or with the compiler flags `-Zunstable-options -Cpanic=immediate-abort`. \
50 In both cases, you still need to build core, e.g. with `-Zbuild-std`"
51);
52
53#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
65#[cfg_attr(panic = "immediate-abort", inline)]
66#[track_caller]
67#[lang = "panic_fmt"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] pub const fn panic_fmt(fmt: PanicFmt<'_>) -> ! {
72 if cfg!(panic = "immediate-abort") {
75 super::intrinsics::abort()
76 }
77
78 unsafe extern "Rust" {
81 #[lang = "panic_impl"]
82 fn panic_impl(pi: &PanicInfo<'_>) -> !;
83 }
84
85 #[cfg(not(feature = "ferrocene_certified"))]
86 let pi = PanicInfo::new(
87 &fmt,
88 Location::caller(),
89 true,
90 false,
91 );
92 #[cfg(feature = "ferrocene_certified")]
93 let pi = PanicInfo::new(&fmt);
94 unsafe { panic_impl(&pi) }
96}
97
98#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
102#[cfg_attr(panic = "immediate-abort", inline)]
103#[track_caller]
104#[rustc_nounwind]
108#[rustc_const_stable_indirect] #[rustc_allow_const_fn_unstable(const_eval_select)]
110pub const fn panic_nounwind_fmt(fmt: PanicFmt<'_>, _force_no_backtrace: bool) -> ! {
111 const_eval_select!(
114 @capture { fmt: PanicFmt<'_>, _force_no_backtrace: bool } -> !:
115 if const #[track_caller] {
116 panic_fmt(fmt)
118 } else #[track_caller] {
119 if cfg!(panic = "immediate-abort") {
120 super::intrinsics::abort()
121 }
122
123 unsafe extern "Rust" {
126 #[lang = "panic_impl"]
127 fn panic_impl(pi: &PanicInfo<'_>) -> !;
128 }
129
130 #[cfg(not(feature = "ferrocene_certified"))]
132 let pi = PanicInfo::new(
133 &fmt,
134 Location::caller(),
135 false,
136 _force_no_backtrace,
137 );
138 #[cfg(feature = "ferrocene_certified")]
139 let pi = PanicInfo::new(&fmt);
140
141 unsafe { panic_impl(&pi) }
143 }
144 )
145}
146
147#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
154#[cfg_attr(panic = "immediate-abort", inline)]
155#[track_caller]
156#[rustc_const_stable_indirect] #[lang = "panic"] pub const fn panic(expr: &'static str) -> ! {
159 #[cfg(not(feature = "ferrocene_certified"))]
171 panic_fmt(fmt::Arguments::new_const(&[expr]));
172 #[cfg(feature = "ferrocene_certified")]
173 panic_fmt(&expr)
174}
175
176#[cfg(not(feature = "ferrocene_certified"))]
185macro_rules! panic_const {
186 ($($lang:ident = $message:expr,)+) => {
187 $(
188 #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
193 #[cfg_attr(panic = "immediate-abort", inline)]
194 #[track_caller]
195 #[rustc_const_stable_indirect] #[lang = stringify!($lang)]
197 pub const fn $lang() -> ! {
198 panic_fmt(fmt::Arguments::new_const(&[$message]));
205 }
206 )+
207 }
208}
209
210#[cfg(not(feature = "ferrocene_certified"))]
215pub 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] pub const fn panic_nounwind(expr: &'static str) -> ! {
255 #[cfg(not(feature = "ferrocene_certified"))]
257 panic_nounwind_fmt(fmt::Arguments::new_const(&[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::new_const(&[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(not(feature = "ferrocene_certified"))]
305fn panic_bounds_check(index: usize, len: usize) -> ! {
306 if cfg!(panic = "immediate-abort") {
307 super::intrinsics::abort()
308 }
309
310 panic!("index out of bounds: the len is {len} but the index is {index}")
311}
312
313#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
314#[cfg_attr(panic = "immediate-abort", inline)]
315#[track_caller]
316#[lang = "panic_misaligned_pointer_dereference"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_certified"))]
319fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
320 if cfg!(panic = "immediate-abort") {
321 super::intrinsics::abort()
322 }
323
324 panic_nounwind_fmt(
325 format_args!(
326 "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
327 ),
328 false,
329 )
330}
331
332#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
333#[cfg_attr(panic = "immediate-abort", inline)]
334#[track_caller]
335#[lang = "panic_null_pointer_dereference"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_certified"))]
338fn panic_null_pointer_dereference() -> ! {
339 if cfg!(panic = "immediate-abort") {
340 super::intrinsics::abort()
341 }
342
343 panic_nounwind_fmt(
344 format_args!("null pointer dereference occurred"),
345 false,
346 )
347}
348
349#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
350#[cfg_attr(panic = "immediate-abort", inline)]
351#[track_caller]
352#[lang = "panic_invalid_enum_construction"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_certified"))]
355fn panic_invalid_enum_construction(source: u128) -> ! {
356 if cfg!(panic = "immediate-abort") {
357 super::intrinsics::abort()
358 }
359
360 panic_nounwind_fmt(
361 format_args!("trying to construct an enum from an invalid value {source:#x}"),
362 false,
363 )
364}
365
366#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
374#[cfg_attr(panic = "immediate-abort", inline)]
375#[lang = "panic_cannot_unwind"] #[rustc_nounwind]
377fn panic_cannot_unwind() -> ! {
378 panic_nounwind("panic in a function that cannot unwind")
383}
384
385#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
393#[cfg_attr(panic = "immediate-abort", inline)]
394#[lang = "panic_in_cleanup"] #[rustc_nounwind]
396#[cfg(not(feature = "ferrocene_certified"))]
397fn panic_in_cleanup() -> ! {
398 panic_nounwind_nobacktrace("panic in a destructor during cleanup")
400}
401
402#[lang = "const_panic_fmt"] #[rustc_const_stable_indirect] #[cfg(not(feature = "ferrocene_certified"))]
406pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
407 if let Some(msg) = fmt.as_str() {
408 panic_display(&msg);
410 } else {
411 unsafe { crate::hint::unreachable_unchecked() };
415 }
416}
417
418#[derive(Debug)]
419#[doc(hidden)]
420#[cfg(not(feature = "ferrocene_certified"))]
421pub enum AssertKind {
422 Eq,
423 Ne,
424 Match,
425}
426
427#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
429#[cfg_attr(panic = "immediate-abort", inline)]
430#[track_caller]
431#[doc(hidden)]
432#[cfg(not(feature = "ferrocene_certified"))]
433pub fn assert_failed<T, U>(
434 kind: AssertKind,
435 left: &T,
436 right: &U,
437 args: Option<fmt::Arguments<'_>>,
438) -> !
439where
440 T: fmt::Debug + ?Sized,
441 U: fmt::Debug + ?Sized,
442{
443 assert_failed_inner(kind, &left, &right, args)
444}
445
446#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
448#[cfg_attr(panic = "immediate-abort", inline)]
449#[track_caller]
450#[doc(hidden)]
451#[cfg(not(feature = "ferrocene_certified"))]
452pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
453 left: &T,
454 right: &str,
455 args: Option<fmt::Arguments<'_>>,
456) -> ! {
457 struct Pattern<'a>(&'a str);
459 impl fmt::Debug for Pattern<'_> {
460 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
461 f.write_str(self.0)
462 }
463 }
464 assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
465}
466
467#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
469#[cfg_attr(panic = "immediate-abort", inline)]
470#[track_caller]
471#[cfg(not(feature = "ferrocene_certified"))]
472fn assert_failed_inner(
473 kind: AssertKind,
474 left: &dyn fmt::Debug,
475 right: &dyn fmt::Debug,
476 args: Option<fmt::Arguments<'_>>,
477) -> ! {
478 let op = match kind {
479 AssertKind::Eq => "==",
480 AssertKind::Ne => "!=",
481 AssertKind::Match => "matches",
482 };
483
484 match args {
485 Some(args) => panic!(
486 r#"assertion `left {op} right` failed: {args}
487 left: {left:?}
488 right: {right:?}"#
489 ),
490 None => panic!(
491 r#"assertion `left {op} right` failed
492 left: {left:?}
493 right: {right:?}"#
494 ),
495 }
496}