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);
51
52#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
64#[cfg_attr(panic = "immediate-abort", inline)]
65#[track_caller]
66#[lang = "panic_fmt"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] pub const fn panic_fmt(fmt: PanicFmt<'_>) -> ! {
71 if cfg!(panic = "immediate-abort") {
74 super::intrinsics::abort()
75 }
76
77 unsafe extern "Rust" {
80 #[lang = "panic_impl"]
81 fn panic_impl(pi: &PanicInfo<'_>) -> !;
82 }
83
84 #[cfg(not(feature = "ferrocene_certified"))]
85 let pi = PanicInfo::new(
86 &fmt,
87 Location::caller(),
88 true,
89 false,
90 );
91 #[cfg(feature = "ferrocene_certified")]
92 let pi = PanicInfo::new(&fmt);
93 unsafe { panic_impl(&pi) }
95}
96
97#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
101#[cfg_attr(panic = "immediate-abort", inline)]
102#[track_caller]
103#[rustc_nounwind]
107#[rustc_const_stable_indirect] #[rustc_allow_const_fn_unstable(const_eval_select)]
109pub const fn panic_nounwind_fmt(fmt: PanicFmt<'_>, _force_no_backtrace: bool) -> ! {
111 const_eval_select!(
112 @capture { fmt: PanicFmt<'_>, _force_no_backtrace: bool } -> !:
113 if const #[track_caller] {
114 panic_fmt(fmt)
116 } else #[track_caller] {
117 if cfg!(panic = "immediate-abort") {
118 super::intrinsics::abort()
119 }
120
121 unsafe extern "Rust" {
124 #[lang = "panic_impl"]
125 fn panic_impl(pi: &PanicInfo<'_>) -> !;
126 }
127
128 #[cfg(not(feature = "ferrocene_certified"))]
130 let pi = PanicInfo::new(
131 &fmt,
132 Location::caller(),
133 false,
134 _force_no_backtrace,
135 );
136 #[cfg(feature = "ferrocene_certified")]
137 let pi = PanicInfo::new(&fmt);
138
139 unsafe { panic_impl(&pi) }
141 }
142 )
143}
144
145#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
152#[cfg_attr(panic = "immediate-abort", inline)]
153#[track_caller]
154#[rustc_const_stable_indirect] #[lang = "panic"] pub const fn panic(expr: &'static str) -> ! {
157 #[cfg(not(feature = "ferrocene_certified"))]
169 panic_fmt(fmt::Arguments::new_const(&[expr]));
170 #[cfg(feature = "ferrocene_certified")]
171 panic_fmt(&expr)
172}
173
174#[cfg(not(feature = "ferrocene_certified"))]
183macro_rules! panic_const {
184 ($($lang:ident = $message:expr,)+) => {
185 $(
186 #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
191 #[cfg_attr(panic = "immediate-abort", inline)]
192 #[track_caller]
193 #[rustc_const_stable_indirect] #[lang = stringify!($lang)]
195 pub const fn $lang() -> ! {
196 panic_fmt(fmt::Arguments::new_const(&[$message]));
203 }
204 )+
205 }
206}
207
208#[cfg(not(feature = "ferrocene_certified"))]
213pub mod panic_const {
214 use super::*;
215 panic_const! {
216 panic_const_add_overflow = "attempt to add with overflow",
217 panic_const_sub_overflow = "attempt to subtract with overflow",
218 panic_const_mul_overflow = "attempt to multiply with overflow",
219 panic_const_div_overflow = "attempt to divide with overflow",
220 panic_const_rem_overflow = "attempt to calculate the remainder with overflow",
221 panic_const_neg_overflow = "attempt to negate with overflow",
222 panic_const_shr_overflow = "attempt to shift right with overflow",
223 panic_const_shl_overflow = "attempt to shift left with overflow",
224 panic_const_div_by_zero = "attempt to divide by zero",
225 panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero",
226 panic_const_coroutine_resumed = "coroutine resumed after completion",
227 panic_const_async_fn_resumed = "`async fn` resumed after completion",
228 panic_const_async_gen_fn_resumed = "`async gen fn` resumed after completion",
229 panic_const_gen_fn_none = "`gen fn` should just keep returning `None` after completion",
230 panic_const_coroutine_resumed_panic = "coroutine resumed after panicking",
231 panic_const_async_fn_resumed_panic = "`async fn` resumed after panicking",
232 panic_const_async_gen_fn_resumed_panic = "`async gen fn` resumed after panicking",
233 panic_const_gen_fn_none_panic = "`gen fn` should just keep returning `None` after panicking",
234 }
235 panic_const! {
238 panic_const_coroutine_resumed_drop = "coroutine resumed after async drop",
239 panic_const_async_fn_resumed_drop = "`async fn` resumed after async drop",
240 panic_const_async_gen_fn_resumed_drop = "`async gen fn` resumed after async drop",
241 panic_const_gen_fn_none_drop = "`gen fn` resumed after async drop",
242 }
243}
244
245#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
248#[cfg_attr(panic = "immediate-abort", inline)]
249#[lang = "panic_nounwind"] #[rustc_nounwind]
251#[rustc_const_stable_indirect] pub const fn panic_nounwind(expr: &'static str) -> ! {
254 #[cfg(not(feature = "ferrocene_certified"))]
255 panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), false);
256 #[cfg(feature = "ferrocene_certified")]
257 panic_nounwind_fmt(&expr, false);
258}
259
260#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
262#[cfg_attr(panic = "immediate-abort", inline)]
263#[rustc_nounwind]
264#[cfg(not(feature = "ferrocene_certified"))]
265pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! {
266 panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), true);
267}
268
269#[inline]
270#[track_caller]
271#[rustc_diagnostic_item = "unreachable_display"] #[cfg(not(feature = "ferrocene_certified"))]
273pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
274 panic_fmt(format_args!("internal error: entered unreachable code: {}", *x));
275}
276
277#[inline]
280#[track_caller]
281#[rustc_diagnostic_item = "panic_str_2015"]
282#[rustc_const_stable_indirect] #[cfg(not(feature = "ferrocene_certified"))]
284pub const fn panic_str_2015(expr: &str) -> ! {
285 panic_display(&expr);
286}
287
288#[inline]
289#[track_caller]
290#[lang = "panic_display"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] #[cfg(not(feature = "ferrocene_certified"))]
294pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
295 panic_fmt(format_args!("{}", *x));
296}
297
298#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
299#[cfg_attr(panic = "immediate-abort", inline)]
300#[track_caller]
301#[lang = "panic_bounds_check"] #[cfg(not(feature = "ferrocene_certified"))]
303fn panic_bounds_check(index: usize, len: usize) -> ! {
304 if cfg!(panic = "immediate-abort") {
305 super::intrinsics::abort()
306 }
307
308 panic!("index out of bounds: the len is {len} but the index is {index}")
309}
310
311#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
312#[cfg_attr(panic = "immediate-abort", inline)]
313#[track_caller]
314#[lang = "panic_misaligned_pointer_dereference"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_certified"))]
317fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
318 if cfg!(panic = "immediate-abort") {
319 super::intrinsics::abort()
320 }
321
322 panic_nounwind_fmt(
323 format_args!(
324 "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
325 ),
326 false,
327 )
328}
329
330#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
331#[cfg_attr(panic = "immediate-abort", inline)]
332#[track_caller]
333#[lang = "panic_null_pointer_dereference"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_certified"))]
336fn panic_null_pointer_dereference() -> ! {
337 if cfg!(panic = "immediate-abort") {
338 super::intrinsics::abort()
339 }
340
341 panic_nounwind_fmt(
342 format_args!("null pointer dereference occurred"),
343 false,
344 )
345}
346
347#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
348#[cfg_attr(panic = "immediate-abort", inline)]
349#[track_caller]
350#[lang = "panic_invalid_enum_construction"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_certified"))]
353fn panic_invalid_enum_construction(source: u128) -> ! {
354 if cfg!(panic = "immediate-abort") {
355 super::intrinsics::abort()
356 }
357
358 panic_nounwind_fmt(
359 format_args!("trying to construct an enum from an invalid value {source:#x}"),
360 false,
361 )
362}
363
364#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
372#[cfg_attr(panic = "immediate-abort", inline)]
373#[lang = "panic_cannot_unwind"] #[rustc_nounwind]
375fn panic_cannot_unwind() -> ! {
377 panic_nounwind("panic in a function that cannot unwind")
379}
380
381#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
389#[cfg_attr(panic = "immediate-abort", inline)]
390#[lang = "panic_in_cleanup"] #[rustc_nounwind]
392#[cfg(not(feature = "ferrocene_certified"))]
393fn panic_in_cleanup() -> ! {
394 panic_nounwind_nobacktrace("panic in a destructor during cleanup")
396}
397
398#[lang = "const_panic_fmt"] #[rustc_const_stable_indirect] #[cfg(not(feature = "ferrocene_certified"))]
402pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
403 if let Some(msg) = fmt.as_str() {
404 panic_display(&msg);
406 } else {
407 unsafe { crate::hint::unreachable_unchecked() };
411 }
412}
413
414#[derive(Debug)]
415#[doc(hidden)]
416#[cfg(not(feature = "ferrocene_certified"))]
417pub enum AssertKind {
418 Eq,
419 Ne,
420 Match,
421}
422
423#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
425#[cfg_attr(panic = "immediate-abort", inline)]
426#[track_caller]
427#[doc(hidden)]
428#[cfg(not(feature = "ferrocene_certified"))]
429pub fn assert_failed<T, U>(
430 kind: AssertKind,
431 left: &T,
432 right: &U,
433 args: Option<fmt::Arguments<'_>>,
434) -> !
435where
436 T: fmt::Debug + ?Sized,
437 U: fmt::Debug + ?Sized,
438{
439 assert_failed_inner(kind, &left, &right, args)
440}
441
442#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
444#[cfg_attr(panic = "immediate-abort", inline)]
445#[track_caller]
446#[doc(hidden)]
447#[cfg(not(feature = "ferrocene_certified"))]
448pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
449 left: &T,
450 right: &str,
451 args: Option<fmt::Arguments<'_>>,
452) -> ! {
453 struct Pattern<'a>(&'a str);
455 impl fmt::Debug for Pattern<'_> {
456 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
457 f.write_str(self.0)
458 }
459 }
460 assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
461}
462
463#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
465#[cfg_attr(panic = "immediate-abort", inline)]
466#[track_caller]
467#[cfg(not(feature = "ferrocene_certified"))]
468fn assert_failed_inner(
469 kind: AssertKind,
470 left: &dyn fmt::Debug,
471 right: &dyn fmt::Debug,
472 args: Option<fmt::Arguments<'_>>,
473) -> ! {
474 let op = match kind {
475 AssertKind::Eq => "==",
476 AssertKind::Ne => "!=",
477 AssertKind::Match => "matches",
478 };
479
480 match args {
481 Some(args) => panic!(
482 r#"assertion `left {op} right` failed: {args}
483 left: {left:?}
484 right: {right:?}"#
485 ),
486 None => panic!(
487 r#"assertion `left {op} right` failed
488 left: {left:?}
489 right: {right:?}"#
490 ),
491 }
492}