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;
34use crate::panic::{Location, PanicInfo};
35
36#[cfg(not(feature = "ferrocene_certified"))]
38pub(crate) type PanicFmt<'a> = fmt::Arguments<'a>;
39#[cfg(feature = "ferrocene_certified")]
40pub(crate) type PanicFmt<'a> = &'a &'static str;
41
42#[cfg(feature = "panic_immediate_abort")]
43compile_error!(
44 "panic_immediate_abort is now a real panic strategy! \
45 Enable it with `panic = \"immediate-abort\"` in Cargo.toml, \
46 or with the compiler flags `-Zunstable-options -Cpanic=immediate-abort`. \
47 In both cases, you still need to build core, e.g. with `-Zbuild-std`"
48);
49
50#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
62#[cfg_attr(panic = "immediate-abort", inline)]
63#[track_caller]
64#[lang = "panic_fmt"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] pub const fn panic_fmt(fmt: PanicFmt<'_>) -> ! {
69 #[ferrocene::annotation(
70 "The `immediate-abort` behavior is not certified, we only support `abort`."
71 )]
72 if cfg!(panic = "immediate-abort") {
73 super::intrinsics::abort()
74 };
75
76 unsafe extern "Rust" {
79 #[lang = "panic_impl"]
80 fn panic_impl(pi: &PanicInfo<'_>) -> !;
81 }
82
83 #[cfg(not(feature = "ferrocene_certified"))]
84 let pi = PanicInfo::new(
85 &fmt,
86 Location::caller(),
87 true,
88 false,
89 );
90 #[cfg(feature = "ferrocene_certified")]
91 let pi = PanicInfo::new(&fmt, Location::caller());
92 unsafe { panic_impl(&pi) }
94}
95
96#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
100#[cfg_attr(panic = "immediate-abort", inline)]
101#[track_caller]
102#[rustc_nounwind]
106#[rustc_const_stable_indirect] #[rustc_allow_const_fn_unstable(const_eval_select)]
108#[ferrocene::annotation("Cannot be covered as it causes an unwinding panic")]
109pub const fn panic_nounwind_fmt(fmt: PanicFmt<'_>, _force_no_backtrace: bool) -> ! {
110 const_eval_select!(
111 @capture { fmt: PanicFmt<'_>, _force_no_backtrace: bool } -> !:
112 if const #[track_caller] {
113 panic_fmt(fmt)
115 } else #[track_caller] {
116 if cfg!(panic = "immediate-abort") {
117 super::intrinsics::abort()
118 }
119
120 unsafe extern "Rust" {
123 #[lang = "panic_impl"]
124 fn panic_impl(pi: &PanicInfo<'_>) -> !;
125 }
126
127 #[cfg(not(feature = "ferrocene_certified"))]
129 let pi = PanicInfo::new(
130 &fmt,
131 Location::caller(),
132 false,
133 _force_no_backtrace,
134 );
135 #[cfg(feature = "ferrocene_certified")]
136 let pi = PanicInfo::new(&fmt, Location::caller());
137
138 unsafe { panic_impl(&pi) }
140 }
141 )
142}
143
144#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
151#[cfg_attr(panic = "immediate-abort", inline)]
152#[track_caller]
153#[rustc_const_stable_indirect] #[lang = "panic"] pub const fn panic(expr: &'static str) -> ! {
156 #[cfg(not(feature = "ferrocene_certified"))]
168 panic_fmt(fmt::Arguments::from_str(expr));
169 #[cfg(feature = "ferrocene_certified")]
170 panic_fmt(&expr)
171}
172
173macro_rules! panic_const {
182 ($($lang:ident = $message:expr,)+) => {
183 $(
184 #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
189 #[cfg_attr(panic = "immediate-abort", inline)]
190 #[track_caller]
191 #[rustc_const_stable_indirect] #[lang = stringify!($lang)]
193 #[ferrocene::annotation("Cannot be covered as this code cannot be reached during runtime.")]
194 pub const fn $lang() -> ! {
195 #[cfg(not(feature = "ferrocene_certified"))]
197 panic_fmt(fmt::Arguments::from_str($message));
198 #[cfg(feature = "ferrocene_certified")]
199 panic_fmt(&$message);
200 }
201 )+
202 }
203}
204
205pub mod panic_const {
210 use super::*;
211 panic_const! {
212 panic_const_add_overflow = "attempt to add with overflow",
213 panic_const_sub_overflow = "attempt to subtract with overflow",
214 panic_const_mul_overflow = "attempt to multiply with overflow",
215 panic_const_div_overflow = "attempt to divide with overflow",
216 panic_const_rem_overflow = "attempt to calculate the remainder with overflow",
217 panic_const_neg_overflow = "attempt to negate with overflow",
218 panic_const_shr_overflow = "attempt to shift right with overflow",
219 panic_const_shl_overflow = "attempt to shift left with overflow",
220 panic_const_div_by_zero = "attempt to divide by zero",
221 panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero",
222 panic_const_coroutine_resumed = "coroutine resumed after completion",
223 panic_const_async_fn_resumed = "`async fn` resumed after completion",
224 panic_const_async_gen_fn_resumed = "`async gen fn` resumed after completion",
225 panic_const_gen_fn_none = "`gen fn` should just keep returning `None` after completion",
226 panic_const_coroutine_resumed_panic = "coroutine resumed after panicking",
227 panic_const_async_fn_resumed_panic = "`async fn` resumed after panicking",
228 panic_const_async_gen_fn_resumed_panic = "`async gen fn` resumed after panicking",
229 panic_const_gen_fn_none_panic = "`gen fn` should just keep returning `None` after panicking",
230 }
231 panic_const! {
234 panic_const_coroutine_resumed_drop = "coroutine resumed after async drop",
235 panic_const_async_fn_resumed_drop = "`async fn` resumed after async drop",
236 panic_const_async_gen_fn_resumed_drop = "`async gen fn` resumed after async drop",
237 panic_const_gen_fn_none_drop = "`gen fn` resumed after async drop",
238 }
239}
240
241#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
244#[cfg_attr(panic = "immediate-abort", inline)]
245#[lang = "panic_nounwind"] #[rustc_nounwind]
247#[rustc_const_stable_indirect] #[ferrocene::annotation("Cannot be covered as it causes an unwinding panic")]
249pub const fn panic_nounwind(expr: &'static str) -> ! {
250 #[cfg(not(feature = "ferrocene_certified"))]
251 panic_nounwind_fmt(fmt::Arguments::from_str(expr), false);
252 #[cfg(feature = "ferrocene_certified")]
253 panic_nounwind_fmt(&expr, false);
254}
255
256#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
258#[cfg_attr(panic = "immediate-abort", inline)]
259#[rustc_nounwind]
260#[cfg(not(feature = "ferrocene_certified"))]
261pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! {
262 panic_nounwind_fmt(fmt::Arguments::from_str(expr), true);
263}
264
265#[inline]
266#[track_caller]
267#[rustc_diagnostic_item = "unreachable_display"] #[cfg(not(feature = "ferrocene_certified"))]
269pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
270 panic_fmt(format_args!("internal error: entered unreachable code: {}", *x));
271}
272
273#[inline]
276#[track_caller]
277#[rustc_diagnostic_item = "panic_str_2015"]
278#[rustc_const_stable_indirect] #[cfg(not(feature = "ferrocene_certified"))]
280pub const fn panic_str_2015(expr: &str) -> ! {
281 panic_display(&expr);
282}
283
284#[inline]
285#[track_caller]
286#[lang = "panic_display"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] #[cfg(not(feature = "ferrocene_certified"))]
290pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
291 panic_fmt(format_args!("{}", *x));
292}
293
294#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
295#[cfg_attr(panic = "immediate-abort", inline)]
296#[track_caller]
297#[lang = "panic_bounds_check"] #[cfg_attr(feature = "ferrocene_certified", expect(unused_variables))]
299fn panic_bounds_check(index: usize, len: usize) -> ! {
300 if cfg!(panic = "immediate-abort") {
301 super::intrinsics::abort()
302 }
303 panic!("index out of bounds: the len is {len} but the index is {index}")
304}
305
306#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
307#[cfg_attr(panic = "immediate-abort", inline)]
308#[track_caller]
309#[lang = "panic_misaligned_pointer_dereference"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_certified"))]
312fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
313 if cfg!(panic = "immediate-abort") {
314 super::intrinsics::abort()
315 }
316
317 panic_nounwind_fmt(
318 format_args!(
319 "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
320 ),
321 false,
322 )
323}
324
325#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
326#[cfg_attr(panic = "immediate-abort", inline)]
327#[track_caller]
328#[lang = "panic_null_pointer_dereference"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_certified"))]
331fn panic_null_pointer_dereference() -> ! {
332 if cfg!(panic = "immediate-abort") {
333 super::intrinsics::abort()
334 }
335
336 panic_nounwind_fmt(
337 format_args!("null pointer dereference occurred"),
338 false,
339 )
340}
341
342#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
343#[cfg_attr(panic = "immediate-abort", inline)]
344#[track_caller]
345#[lang = "panic_invalid_enum_construction"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_certified"))]
348fn panic_invalid_enum_construction(source: u128) -> ! {
349 if cfg!(panic = "immediate-abort") {
350 super::intrinsics::abort()
351 }
352
353 panic_nounwind_fmt(
354 format_args!("trying to construct an enum from an invalid value {source:#x}"),
355 false,
356 )
357}
358
359#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
367#[cfg_attr(panic = "immediate-abort", inline)]
368#[lang = "panic_cannot_unwind"] #[rustc_nounwind]
370#[ferrocene::annotation("Cannot be covered as it causes an unwinding panic")]
371fn panic_cannot_unwind() -> ! {
372 panic_nounwind("panic in a function that cannot unwind")
374}
375
376#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
384#[cfg_attr(panic = "immediate-abort", inline)]
385#[lang = "panic_in_cleanup"] #[rustc_nounwind]
387#[cfg(not(feature = "ferrocene_certified"))]
388fn panic_in_cleanup() -> ! {
389 panic_nounwind_nobacktrace("panic in a destructor during cleanup")
391}
392
393#[lang = "const_panic_fmt"] #[rustc_const_stable_indirect] #[cfg(not(feature = "ferrocene_certified"))]
397pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
398 if let Some(msg) = fmt.as_str() {
399 panic_display(&msg);
401 } else {
402 unsafe { crate::hint::unreachable_unchecked() };
406 }
407}
408
409#[derive(Debug)]
410#[doc(hidden)]
411#[cfg(not(feature = "ferrocene_certified"))]
412pub enum AssertKind {
413 Eq,
414 Ne,
415 Match,
416}
417
418#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
420#[cfg_attr(panic = "immediate-abort", inline)]
421#[track_caller]
422#[doc(hidden)]
423#[cfg(not(feature = "ferrocene_certified"))]
424pub fn assert_failed<T, U>(
425 kind: AssertKind,
426 left: &T,
427 right: &U,
428 args: Option<fmt::Arguments<'_>>,
429) -> !
430where
431 T: fmt::Debug + ?Sized,
432 U: fmt::Debug + ?Sized,
433{
434 assert_failed_inner(kind, &left, &right, args)
435}
436
437#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
439#[cfg_attr(panic = "immediate-abort", inline)]
440#[track_caller]
441#[doc(hidden)]
442#[cfg(not(feature = "ferrocene_certified"))]
443pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
444 left: &T,
445 right: &str,
446 args: Option<fmt::Arguments<'_>>,
447) -> ! {
448 struct Pattern<'a>(&'a str);
450 impl fmt::Debug for Pattern<'_> {
451 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
452 f.write_str(self.0)
453 }
454 }
455 assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
456}
457
458#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
460#[cfg_attr(panic = "immediate-abort", inline)]
461#[track_caller]
462#[cfg(not(feature = "ferrocene_certified"))]
463fn assert_failed_inner(
464 kind: AssertKind,
465 left: &dyn fmt::Debug,
466 right: &dyn fmt::Debug,
467 args: Option<fmt::Arguments<'_>>,
468) -> ! {
469 let op = match kind {
470 AssertKind::Eq => "==",
471 AssertKind::Ne => "!=",
472 AssertKind::Match => "matches",
473 };
474
475 match args {
476 Some(args) => panic!(
477 r#"assertion `left {op} right` failed: {args}
478 left: {left:?}
479 right: {right:?}"#
480 ),
481 None => panic!(
482 r#"assertion `left {op} right` failed
483 left: {left:?}
484 right: {right:?}"#
485 ),
486 }
487}