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 #[ferrocene::annotation(
63 "The `immediate-abort` behavior is not certified, we only support `abort`."
64 )]
65 if cfg!(panic = "immediate-abort") {
66 super::intrinsics::abort()
67 };
68
69 unsafe extern "Rust" {
72 #[lang = "panic_impl"]
73 fn panic_impl(pi: &PanicInfo<'_>) -> !;
74 }
75
76 let pi = PanicInfo::new(
77 &fmt,
78 Location::caller(),
79 true,
80 false,
81 );
82 unsafe { panic_impl(&pi) }
84}
85
86#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
90#[cfg_attr(panic = "immediate-abort", inline)]
91#[track_caller]
92#[rustc_nounwind]
96#[rustc_const_stable_indirect] #[rustc_allow_const_fn_unstable(const_eval_select)]
98#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
99#[ferrocene::prevalidated]
100pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, _force_no_backtrace: bool) -> ! {
101 const_eval_select!(
102 @capture { fmt: fmt::Arguments<'_>, _force_no_backtrace: bool } -> !:
103 if const #[track_caller] {
104 panic_fmt(fmt)
106 } else #[track_caller] {
107 if cfg!(panic = "immediate-abort") {
108 super::intrinsics::abort()
109 }
110
111 unsafe extern "Rust" {
114 #[lang = "panic_impl"]
115 fn panic_impl(pi: &PanicInfo<'_>) -> !;
116 }
117
118 let pi = PanicInfo::new(
120 &fmt,
121 Location::caller(),
122 false,
123 _force_no_backtrace,
124 );
125
126 unsafe { panic_impl(&pi) }
128 }
129 )
130}
131
132#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
139#[cfg_attr(panic = "immediate-abort", inline)]
140#[track_caller]
141#[rustc_const_stable_indirect] #[lang = "panic"] #[ferrocene::prevalidated]
144pub const fn panic(expr: &'static str) -> ! {
145 panic_fmt(fmt::Arguments::from_str(expr));
157}
158
159macro_rules! panic_const {
168 ($($lang:ident = $message:expr,)+) => {
169 $(
170 #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
175 #[cfg_attr(panic = "immediate-abort", inline)]
176 #[track_caller]
177 #[rustc_const_stable_indirect] #[lang = stringify!($lang)]
179 #[ferrocene::annotation("Cannot be covered as this code cannot be reached during runtime.")]
180 #[ferrocene::prevalidated]
181 pub const fn $lang() -> ! {
182 panic_fmt(fmt::Arguments::from_str($message));
184 }
185 )+
186 }
187}
188
189pub mod panic_const {
194 use super::*;
195 panic_const! {
196 panic_const_add_overflow = "attempt to add with overflow",
197 panic_const_sub_overflow = "attempt to subtract with overflow",
198 panic_const_mul_overflow = "attempt to multiply with overflow",
199 panic_const_div_overflow = "attempt to divide with overflow",
200 panic_const_rem_overflow = "attempt to calculate the remainder with overflow",
201 panic_const_neg_overflow = "attempt to negate with overflow",
202 panic_const_shr_overflow = "attempt to shift right with overflow",
203 panic_const_shl_overflow = "attempt to shift left with overflow",
204 panic_const_div_by_zero = "attempt to divide by zero",
205 panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero",
206 panic_const_coroutine_resumed = "coroutine resumed after completion",
207 panic_const_async_fn_resumed = "`async fn` resumed after completion",
208 panic_const_async_gen_fn_resumed = "`async gen fn` resumed after completion",
209 panic_const_gen_fn_none = "`gen fn` should just keep returning `None` after completion",
210 panic_const_coroutine_resumed_panic = "coroutine resumed after panicking",
211 panic_const_async_fn_resumed_panic = "`async fn` resumed after panicking",
212 panic_const_async_gen_fn_resumed_panic = "`async gen fn` resumed after panicking",
213 panic_const_gen_fn_none_panic = "`gen fn` should just keep returning `None` after panicking",
214 }
215 panic_const! {
218 panic_const_coroutine_resumed_drop = "coroutine resumed after async drop",
219 panic_const_async_fn_resumed_drop = "`async fn` resumed after async drop",
220 panic_const_async_gen_fn_resumed_drop = "`async gen fn` resumed after async drop",
221 panic_const_gen_fn_none_drop = "`gen fn` resumed after async drop",
222 }
223}
224
225#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
228#[cfg_attr(panic = "immediate-abort", inline)]
229#[lang = "panic_nounwind"] #[rustc_nounwind]
231#[rustc_const_stable_indirect] #[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
233#[ferrocene::prevalidated]
234pub const fn panic_nounwind(expr: &'static str) -> ! {
235 panic_nounwind_fmt(fmt::Arguments::from_str(expr), false);
236}
237
238#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
240#[cfg_attr(panic = "immediate-abort", inline)]
241#[rustc_nounwind]
242#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
243#[ferrocene::prevalidated]
244pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! {
245 panic_nounwind_fmt(fmt::Arguments::from_str(expr), true);
246}
247
248#[inline]
249#[track_caller]
250#[rustc_diagnostic_item = "unreachable_display"] pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
252 panic_fmt(format_args!("internal error: entered unreachable code: {}", *x));
253}
254
255#[inline]
258#[track_caller]
259#[rustc_diagnostic_item = "panic_str_2015"]
260#[rustc_const_stable_indirect] pub const fn panic_str_2015(expr: &str) -> ! {
262 panic_display(&expr);
263}
264
265#[inline]
266#[track_caller]
267#[lang = "panic_display"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] #[ferrocene::prevalidated]
271pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
272 panic_fmt(format_args!("{}", *x));
273}
274
275#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
276#[cfg_attr(panic = "immediate-abort", inline)]
277#[track_caller]
278#[lang = "panic_bounds_check"] #[ferrocene::prevalidated]
280fn panic_bounds_check(index: usize, len: usize) -> ! {
281 #[ferrocene::annotation(
282 "The `immediate-abort` behavior is not certified, we only support `abort`."
283 )]
284 if cfg!(panic = "immediate-abort") {
285 super::intrinsics::abort()
286 }
287 panic!("index out of bounds: the len is {len} but the index is {index}")
288}
289
290#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
291#[cfg_attr(panic = "immediate-abort", inline)]
292#[track_caller]
293#[lang = "panic_misaligned_pointer_dereference"] #[rustc_nounwind] #[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
296#[ferrocene::prevalidated]
297fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
298 if cfg!(panic = "immediate-abort") {
299 super::intrinsics::abort()
300 }
301
302 panic_nounwind_fmt(
303 format_args!(
304 "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
305 ),
306 false,
307 );
308}
309
310#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
311#[cfg_attr(panic = "immediate-abort", inline)]
312#[track_caller]
313#[lang = "panic_null_pointer_dereference"] #[rustc_nounwind] #[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
316#[ferrocene::prevalidated]
317fn panic_null_pointer_dereference() -> ! {
318 if cfg!(panic = "immediate-abort") {
319 super::intrinsics::abort()
320 }
321
322 panic_nounwind_fmt(
323 fmt::Arguments::from_str("null pointer dereference occurred"),
324 false,
325 )
326}
327
328#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
329#[cfg_attr(panic = "immediate-abort", inline)]
330#[track_caller]
331#[lang = "panic_null_reference_constructed"] #[rustc_nounwind] fn panic_null_reference_constructed() -> ! {
334 if cfg!(panic = "immediate-abort") {
335 super::intrinsics::abort()
336 }
337
338 panic_nounwind_fmt(format_args!("null reference produced"), false)
339}
340
341#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
342#[cfg_attr(panic = "immediate-abort", inline)]
343#[track_caller]
344#[lang = "panic_invalid_enum_construction"] #[rustc_nounwind] fn panic_invalid_enum_construction(source: u128) -> ! {
347 if cfg!(panic = "immediate-abort") {
348 super::intrinsics::abort()
349 }
350
351 panic_nounwind_fmt(
352 format_args!("trying to construct an enum from an invalid value {source:#x}"),
353 false,
354 );
355}
356
357#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
365#[cfg_attr(panic = "immediate-abort", inline)]
366#[lang = "panic_cannot_unwind"] #[rustc_nounwind]
368#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
369#[ferrocene::prevalidated]
370fn panic_cannot_unwind() -> ! {
371 panic_nounwind("panic in a function that cannot unwind")
373}
374
375#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
383#[cfg_attr(panic = "immediate-abort", inline)]
384#[lang = "panic_in_cleanup"] #[rustc_nounwind]
386#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
387#[ferrocene::prevalidated]
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] pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
397 if let Some(msg) = fmt.as_str() {
398 panic_display(&msg);
400 } else {
401 unsafe { crate::hint::unreachable_unchecked() };
405 }
406}
407
408#[derive(Debug)]
409#[doc(hidden)]
410#[ferrocene::prevalidated]
411pub enum AssertKind {
412 Eq,
413 Ne,
414 Match,
415}
416
417#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
419#[cfg_attr(panic = "immediate-abort", inline)]
420#[track_caller]
421#[doc(hidden)]
422#[ferrocene::prevalidated]
423pub fn assert_failed<T, U>(
424 kind: AssertKind,
425 left: &T,
426 right: &U,
427 args: Option<fmt::Arguments<'_>>,
428) -> !
429where
430 T: fmt::Debug + ?Sized,
431 U: fmt::Debug + ?Sized,
432{
433 assert_failed_inner(kind, &left, &right, args)
434}
435
436#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
438#[cfg_attr(panic = "immediate-abort", inline)]
439#[track_caller]
440#[doc(hidden)]
441#[ferrocene::prevalidated]
442pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
443 left: &T,
444 right: &str,
445 args: Option<fmt::Arguments<'_>>,
446) -> ! {
447 #[ferrocene::prevalidated]
449 struct Pattern<'a>(&'a str);
450 impl fmt::Debug for Pattern<'_> {
451 #[ferrocene::prevalidated]
452 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
453 f.write_str(self.0)
454 }
455 }
456 assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
457}
458
459#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
461#[cfg_attr(panic = "immediate-abort", inline)]
462#[track_caller]
463#[ferrocene::prevalidated]
464fn assert_failed_inner(
465 kind: AssertKind,
466 left: &dyn fmt::Debug,
467 right: &dyn fmt::Debug,
468 args: Option<fmt::Arguments<'_>>,
469) -> ! {
470 let op = match kind {
471 AssertKind::Eq => "==",
472 AssertKind::Ne => "!=",
473 AssertKind::Match => "matches",
474 };
475
476 match args {
477 Some(args) => panic!(
478 r#"assertion `left {op} right` failed: {args}
479 left: {left:?}
480 right: {right:?}"#
481 ),
482 None => panic!(
483 r#"assertion `left {op} right` failed
484 left: {left:?}
485 right: {right:?}"#
486 ),
487 }
488}