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
31use crate::fmt;
32use crate::intrinsics::const_eval_select;
33use crate::panic::{Location, PanicInfo};
34
35#[cfg(feature = "panic_immediate_abort")]
36compile_error!(
37 "panic_immediate_abort is now a real panic strategy! \
38 Enable it with `panic = \"immediate-abort\"` in Cargo.toml, \
39 or with the compiler flags `-Zunstable-options -Cpanic=immediate-abort`. \
40 In both cases, you still need to build core, e.g. with `-Zbuild-std`"
41);
42
43#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
55#[cfg_attr(panic = "immediate-abort", inline)]
56#[track_caller]
57#[lang = "panic_fmt"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] #[ferrocene::prevalidated]
61pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
62 if cfg!(panic = "immediate-abort") {
63 super::intrinsics::abort_immediate()
64 }
65
66 unsafe extern "Rust" {
69 #[lang = "panic_impl"]
70 fn panic_impl(pi: &PanicInfo<'_>) -> !;
71 }
72
73 let pi = PanicInfo::new(
74 &fmt,
75 Location::caller(),
76 true,
77 false,
78 );
79 unsafe { panic_impl(&pi) }
81}
82
83#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
87#[cfg_attr(panic = "immediate-abort", inline)]
88#[track_caller]
89#[rustc_nounwind]
93#[rustc_const_stable_indirect] #[rustc_allow_const_fn_unstable(const_eval_select)]
95#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
96#[ferrocene::prevalidated]
97pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, _force_no_backtrace: bool) -> ! {
98 const_eval_select!(
99 @capture { fmt: fmt::Arguments<'_>, _force_no_backtrace: bool } -> !:
100 if const #[track_caller] {
101 panic_fmt(fmt)
103 } else #[track_caller] {
104 if cfg!(panic = "immediate-abort") {
105 super::intrinsics::abort_immediate()
106 }
107
108 unsafe extern "Rust" {
111 #[lang = "panic_impl"]
112 fn panic_impl(pi: &PanicInfo<'_>) -> !;
113 }
114
115 let pi = PanicInfo::new(
117 &fmt,
118 Location::caller(),
119 false,
120 _force_no_backtrace,
121 );
122
123 unsafe { panic_impl(&pi) }
125 }
126 )
127}
128
129#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
136#[cfg_attr(panic = "immediate-abort", inline)]
137#[track_caller]
138#[rustc_const_stable_indirect] #[lang = "panic"] #[ferrocene::prevalidated]
141pub const fn panic(expr: &'static str) -> ! {
142 panic_fmt(fmt::Arguments::from_str(expr));
154}
155
156macro_rules! panic_const {
165 ($($lang:ident = $message:expr,)+) => {
166 $(
167 #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
172 #[cfg_attr(panic = "immediate-abort", inline)]
173 #[track_caller]
174 #[rustc_const_stable_indirect] #[lang = stringify!($lang)]
176 #[ferrocene::annotation("Cannot be covered as this code cannot be reached during runtime.")]
177 #[ferrocene::prevalidated]
178 pub const fn $lang() -> ! {
179 panic_fmt(fmt::Arguments::from_str($message));
181 }
182 )+
183 }
184}
185
186pub mod panic_const {
191 use super::*;
192 panic_const! {
193 panic_const_add_overflow = "attempt to add with overflow",
194 panic_const_sub_overflow = "attempt to subtract with overflow",
195 panic_const_mul_overflow = "attempt to multiply with overflow",
196 panic_const_div_overflow = "attempt to divide with overflow",
197 panic_const_rem_overflow = "attempt to calculate the remainder with overflow",
198 panic_const_neg_overflow = "attempt to negate with overflow",
199 panic_const_shr_overflow = "attempt to shift right with overflow",
200 panic_const_shl_overflow = "attempt to shift left with overflow",
201 panic_const_div_by_zero = "attempt to divide by zero",
202 panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero",
203 panic_const_coroutine_resumed = "coroutine resumed after completion",
204 panic_const_async_fn_resumed = "`async fn` resumed after completion",
205 panic_const_async_gen_fn_resumed = "`async gen fn` resumed after completion",
206 panic_const_gen_fn_none = "`gen fn` should just keep returning `None` after completion",
207 panic_const_coroutine_resumed_panic = "coroutine resumed after panicking",
208 panic_const_async_fn_resumed_panic = "`async fn` resumed after panicking",
209 panic_const_async_gen_fn_resumed_panic = "`async gen fn` resumed after panicking",
210 panic_const_gen_fn_none_panic = "`gen fn` should just keep returning `None` after panicking",
211 }
212 panic_const! {
215 panic_const_coroutine_resumed_drop = "coroutine resumed after async drop",
216 panic_const_async_fn_resumed_drop = "`async fn` resumed after async drop",
217 panic_const_async_gen_fn_resumed_drop = "`async gen fn` resumed after async drop",
218 panic_const_gen_fn_none_drop = "`gen fn` resumed after async drop",
219 }
220}
221
222#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
225#[cfg_attr(panic = "immediate-abort", inline)]
226#[lang = "panic_nounwind"] #[rustc_nounwind]
228#[rustc_const_stable_indirect] #[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
230#[ferrocene::prevalidated]
231pub const fn panic_nounwind(expr: &'static str) -> ! {
232 panic_nounwind_fmt(fmt::Arguments::from_str(expr), false);
233}
234
235#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
237#[cfg_attr(panic = "immediate-abort", inline)]
238#[rustc_nounwind]
239#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
240#[ferrocene::prevalidated]
241pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! {
242 panic_nounwind_fmt(fmt::Arguments::from_str(expr), true);
243}
244
245#[inline]
246#[track_caller]
247#[rustc_diagnostic_item = "unreachable_display"] pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
249 panic_fmt(format_args!("internal error: entered unreachable code: {}", *x));
250}
251
252#[inline]
255#[track_caller]
256#[rustc_diagnostic_item = "panic_str_2015"]
257#[rustc_const_stable_indirect] pub const fn panic_str_2015(expr: &str) -> ! {
259 panic_display(&expr);
260}
261
262#[inline]
263#[track_caller]
264#[lang = "panic_display"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] #[ferrocene::prevalidated]
268pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
269 panic_fmt(format_args!("{}", *x));
270}
271
272#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
273#[cfg_attr(panic = "immediate-abort", inline)]
274#[track_caller]
275#[lang = "panic_bounds_check"] #[ferrocene::prevalidated]
277fn panic_bounds_check(index: usize, len: usize) -> ! {
278 #[ferrocene::annotation(
279 "The `immediate-abort` behavior is not certified, we only support `abort`."
280 )]
281 if cfg!(panic = "immediate-abort") {
282 super::intrinsics::abort_immediate()
283 }
284 panic!("index out of bounds: the len is {len} but the index is {index}")
285}
286
287#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
288#[cfg_attr(panic = "immediate-abort", inline)]
289#[track_caller]
290#[lang = "panic_misaligned_pointer_dereference"] #[rustc_nounwind] #[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
293#[ferrocene::prevalidated]
294fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
295 if cfg!(panic = "immediate-abort") {
296 super::intrinsics::abort_immediate()
297 }
298
299 panic_nounwind_fmt(
300 format_args!(
301 "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
302 ),
303 false,
304 );
305}
306
307#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
308#[cfg_attr(panic = "immediate-abort", inline)]
309#[track_caller]
310#[lang = "panic_null_pointer_dereference"] #[rustc_nounwind] #[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
313#[ferrocene::prevalidated]
314fn panic_null_pointer_dereference() -> ! {
315 if cfg!(panic = "immediate-abort") {
316 super::intrinsics::abort_immediate()
317 }
318
319 panic_nounwind_fmt(
320 fmt::Arguments::from_str("null pointer dereference occurred"),
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_reference_constructed"] #[rustc_nounwind] fn panic_null_reference_constructed() -> ! {
331 if cfg!(panic = "immediate-abort") {
332 super::intrinsics::abort_immediate()
333 }
334
335 panic_nounwind_fmt(format_args!("null reference produced"), false)
336}
337
338#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
339#[cfg_attr(panic = "immediate-abort", inline)]
340#[track_caller]
341#[lang = "panic_invalid_enum_construction"] #[rustc_nounwind] fn panic_invalid_enum_construction(source: u128) -> ! {
344 if cfg!(panic = "immediate-abort") {
345 super::intrinsics::abort_immediate()
346 }
347
348 panic_nounwind_fmt(
349 format_args!("trying to construct an enum from an invalid value {source:#x}"),
350 false,
351 );
352}
353
354#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
362#[cfg_attr(panic = "immediate-abort", inline)]
363#[lang = "panic_cannot_unwind"] #[rustc_nounwind]
365#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
366#[ferrocene::prevalidated]
367fn panic_cannot_unwind() -> ! {
368 panic_nounwind("panic in a function that cannot unwind")
370}
371
372#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
380#[cfg_attr(panic = "immediate-abort", inline)]
381#[lang = "panic_in_cleanup"] #[rustc_nounwind]
383#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
384#[ferrocene::prevalidated]
385fn panic_in_cleanup() -> ! {
386 panic_nounwind_nobacktrace("panic in a destructor during cleanup")
388}
389
390#[lang = "const_panic_fmt"] #[rustc_const_stable_indirect] pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
394 if let Some(msg) = fmt.as_str() {
395 panic_display(&msg);
397 } else {
398 unsafe { crate::hint::unreachable_unchecked() };
402 }
403}
404
405#[derive(Debug)]
406#[doc(hidden)]
407#[ferrocene::prevalidated]
408pub enum AssertKind {
409 Eq,
410 Ne,
411 Match,
412}
413
414#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
416#[cfg_attr(panic = "immediate-abort", inline)]
417#[track_caller]
418#[doc(hidden)]
419#[ferrocene::prevalidated]
420pub fn assert_failed<T, U>(
421 kind: AssertKind,
422 left: &T,
423 right: &U,
424 args: Option<fmt::Arguments<'_>>,
425) -> !
426where
427 T: fmt::Debug + ?Sized,
428 U: fmt::Debug + ?Sized,
429{
430 assert_failed_inner(kind, &left, &right, args)
431}
432
433#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
435#[cfg_attr(panic = "immediate-abort", inline)]
436#[track_caller]
437#[doc(hidden)]
438#[ferrocene::prevalidated]
439pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
440 left: &T,
441 right: &str,
442 args: Option<fmt::Arguments<'_>>,
443) -> ! {
444 #[ferrocene::prevalidated]
446 struct Pattern<'a>(&'a str);
447 impl fmt::Debug for Pattern<'_> {
448 #[ferrocene::prevalidated]
449 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
450 f.write_str(self.0)
451 }
452 }
453 assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
454}
455
456#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
458#[cfg_attr(panic = "immediate-abort", inline)]
459#[track_caller]
460#[ferrocene::prevalidated]
461fn assert_failed_inner(
462 kind: AssertKind,
463 left: &dyn fmt::Debug,
464 right: &dyn fmt::Debug,
465 args: Option<fmt::Arguments<'_>>,
466) -> ! {
467 let op = match kind {
468 AssertKind::Eq => "==",
469 AssertKind::Ne => "!=",
470 AssertKind::Match => "matches",
471 };
472
473 match args {
474 Some(args) => panic!(
475 r"assertion `left {op} right` failed: {args}
476 left: {left:?}
477 right: {right:?}"
478 ),
479 None => panic!(
480 r"assertion `left {op} right` failed
481 left: {left:?}
482 right: {right:?}"
483 ),
484 }
485}