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_runtime"))]
32use crate::fmt;
33use crate::intrinsics::const_eval_select;
34#[cfg(feature = "ferrocene_certified_runtime")]
35use crate::marker::PhantomData;
36use crate::panic::{Location, PanicInfo};
37
38#[cfg(not(feature = "ferrocene_certified_runtime"))]
40pub(crate) type PanicArguments<'a> = fmt::Arguments<'a>;
41#[cfg(feature = "ferrocene_certified_runtime")]
42#[allow(missing_debug_implementations)]
43pub struct PanicArguments<'a> {
44 pub(crate) inner: &'static str,
45 _marker: PhantomData<&'a ()>,
46}
47
48#[cfg(feature = "ferrocene_certified_runtime")]
49impl<'a> PanicArguments<'a> {
50 pub const fn from_str(inner: &'static str) -> Self {
51 Self { inner, _marker: PhantomData }
52 }
53
54 pub(crate) const fn as_str(&self) -> Option<&'static str> {
55 Some(self.inner)
56 }
57}
58
59#[cfg(feature = "panic_immediate_abort")]
60compile_error!(
61 "panic_immediate_abort is now a real panic strategy! \
62 Enable it with `panic = \"immediate-abort\"` in Cargo.toml, \
63 or with the compiler flags `-Zunstable-options -Cpanic=immediate-abort`. \
64 In both cases, you still need to build core, e.g. with `-Zbuild-std`"
65);
66
67#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
79#[cfg_attr(panic = "immediate-abort", inline)]
80#[track_caller]
81#[lang = "panic_fmt"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] pub const fn panic_fmt(fmt: PanicArguments<'_>) -> ! {
86 #[ferrocene::annotation(
87 "The `immediate-abort` behavior is not certified, we only support `abort`."
88 )]
89 if cfg!(panic = "immediate-abort") {
90 super::intrinsics::abort()
91 };
92
93 unsafe extern "Rust" {
96 #[lang = "panic_impl"]
97 fn panic_impl(pi: &PanicInfo<'_>) -> !;
98 }
99
100 let pi = PanicInfo::new(
101 &fmt,
102 Location::caller(),
103 true,
104 false,
105 );
106 unsafe { panic_impl(&pi) }
108}
109
110#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
114#[cfg_attr(panic = "immediate-abort", inline)]
115#[track_caller]
116#[rustc_nounwind]
120#[rustc_const_stable_indirect] #[rustc_allow_const_fn_unstable(const_eval_select)]
122#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
123pub const fn panic_nounwind_fmt(fmt: PanicArguments<'_>, _force_no_backtrace: bool) -> ! {
124 const_eval_select!(
125 @capture { fmt: PanicArguments<'_>, _force_no_backtrace: bool } -> !:
126 if const #[track_caller] {
127 panic_fmt(fmt)
129 } else #[track_caller] {
130 if cfg!(panic = "immediate-abort") {
131 super::intrinsics::abort()
132 }
133
134 unsafe extern "Rust" {
137 #[lang = "panic_impl"]
138 fn panic_impl(pi: &PanicInfo<'_>) -> !;
139 }
140
141 let pi = PanicInfo::new(
143 &fmt,
144 Location::caller(),
145 false,
146 _force_no_backtrace,
147 );
148
149 unsafe { panic_impl(&pi) }
151 }
152 )
153}
154
155#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
162#[cfg_attr(panic = "immediate-abort", inline)]
163#[track_caller]
164#[rustc_const_stable_indirect] #[lang = "panic"] pub const fn panic(expr: &'static str) -> ! {
167 panic_fmt(PanicArguments::from_str(expr));
179}
180
181macro_rules! panic_const {
190 ($($lang:ident = $message:expr,)+) => {
191 $(
192 #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
197 #[cfg_attr(panic = "immediate-abort", inline)]
198 #[track_caller]
199 #[rustc_const_stable_indirect] #[lang = stringify!($lang)]
201 #[ferrocene::annotation("Cannot be covered as this code cannot be reached during runtime.")]
202 pub const fn $lang() -> ! {
203 panic_fmt(PanicArguments::from_str($message));
205 }
206 )+
207 }
208}
209
210pub mod panic_const {
215 use super::*;
216 panic_const! {
217 panic_const_add_overflow = "attempt to add with overflow",
218 panic_const_sub_overflow = "attempt to subtract with overflow",
219 panic_const_mul_overflow = "attempt to multiply with overflow",
220 panic_const_div_overflow = "attempt to divide with overflow",
221 panic_const_rem_overflow = "attempt to calculate the remainder with overflow",
222 panic_const_neg_overflow = "attempt to negate with overflow",
223 panic_const_shr_overflow = "attempt to shift right with overflow",
224 panic_const_shl_overflow = "attempt to shift left with overflow",
225 panic_const_div_by_zero = "attempt to divide by zero",
226 panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero",
227 panic_const_coroutine_resumed = "coroutine resumed after completion",
228 panic_const_async_fn_resumed = "`async fn` resumed after completion",
229 panic_const_async_gen_fn_resumed = "`async gen fn` resumed after completion",
230 panic_const_gen_fn_none = "`gen fn` should just keep returning `None` after completion",
231 panic_const_coroutine_resumed_panic = "coroutine resumed after panicking",
232 panic_const_async_fn_resumed_panic = "`async fn` resumed after panicking",
233 panic_const_async_gen_fn_resumed_panic = "`async gen fn` resumed after panicking",
234 panic_const_gen_fn_none_panic = "`gen fn` should just keep returning `None` after panicking",
235 }
236 panic_const! {
239 panic_const_coroutine_resumed_drop = "coroutine resumed after async drop",
240 panic_const_async_fn_resumed_drop = "`async fn` resumed after async drop",
241 panic_const_async_gen_fn_resumed_drop = "`async gen fn` resumed after async drop",
242 panic_const_gen_fn_none_drop = "`gen fn` resumed after async drop",
243 }
244}
245
246#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
249#[cfg_attr(panic = "immediate-abort", inline)]
250#[lang = "panic_nounwind"] #[rustc_nounwind]
252#[rustc_const_stable_indirect] #[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
254pub const fn panic_nounwind(expr: &'static str) -> ! {
255 panic_nounwind_fmt(PanicArguments::from_str(expr), false);
256}
257
258#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
260#[cfg_attr(panic = "immediate-abort", inline)]
261#[rustc_nounwind]
262#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
263pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! {
264 panic_nounwind_fmt(PanicArguments::from_str(expr), true);
265}
266
267#[inline]
268#[track_caller]
269#[rustc_diagnostic_item = "unreachable_display"] #[cfg(not(feature = "ferrocene_certified_runtime"))]
271pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
272 panic_fmt(format_args!("internal error: entered unreachable code: {}", *x));
273}
274
275#[inline]
278#[track_caller]
279#[rustc_diagnostic_item = "panic_str_2015"]
280#[rustc_const_stable_indirect] #[cfg(not(feature = "ferrocene_certified_runtime"))]
282pub const fn panic_str_2015(expr: &str) -> ! {
283 panic_display(&expr);
284}
285
286#[cfg(feature = "ferrocene_certified_runtime")]
287#[inline]
288#[track_caller]
289#[lang = "panic_display"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] pub const fn panic_display(msg: &&'static str) -> ! {
293 panic_fmt(PanicArguments::from_str(*msg));
294}
295
296#[cfg(not(feature = "ferrocene_certified_runtime"))]
297#[inline]
298#[track_caller]
299#[lang = "panic_display"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
303 panic_fmt(format_args!("{}", *x));
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_bounds_check"] fn panic_bounds_check(index: usize, len: usize) -> ! {
311 #[ferrocene::annotation(
312 "The `immediate-abort` behavior is not certified, we only support `abort`."
313 )]
314 if cfg!(panic = "immediate-abort") {
315 super::intrinsics::abort()
316 }
317 panic!("index out of bounds: the len is {len} but the index is {index}")
318}
319
320#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
321#[cfg_attr(panic = "immediate-abort", inline)]
322#[track_caller]
323#[lang = "panic_misaligned_pointer_dereference"] #[rustc_nounwind] #[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
326fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
327 if cfg!(panic = "immediate-abort") {
328 super::intrinsics::abort()
329 }
330
331 #[cfg(not(feature = "ferrocene_certified_runtime"))]
332 panic_nounwind_fmt(
333 format_args!(
334 "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
335 ),
336 false,
337 );
338 #[cfg(feature = "ferrocene_certified_runtime")]
339 panic_nounwind_fmt(
340 PanicArguments::from_str("misaligned pointer dereference"),
341 false,
342 );
343}
344
345#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
346#[cfg_attr(panic = "immediate-abort", inline)]
347#[track_caller]
348#[lang = "panic_null_pointer_dereference"] #[rustc_nounwind] #[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
351fn panic_null_pointer_dereference() -> ! {
352 if cfg!(panic = "immediate-abort") {
353 super::intrinsics::abort()
354 }
355
356 panic_nounwind_fmt(
357 PanicArguments::from_str("null pointer dereference occurred"),
358 false,
359 )
360}
361
362#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
363#[cfg_attr(panic = "immediate-abort", inline)]
364#[track_caller]
365#[lang = "panic_invalid_enum_construction"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_subset"))]
368fn panic_invalid_enum_construction(source: u128) -> ! {
369 #[ferrocene::annotation(
370 "The `immediate-abort` behavior is not certified, we only support `abort`."
371 )]
372 if cfg!(panic = "immediate-abort") {
373 super::intrinsics::abort()
374 }
375
376 #[cfg(not(feature = "ferrocene_certified_runtime"))]
377 panic_nounwind_fmt(
378 format_args!("trying to construct an enum from an invalid value {source:#x}"),
379 false,
380 );
381 #[cfg(feature = "ferrocene_certified_runtime")]
382 panic_nounwind_fmt(
383 PanicArguments::from_str("trying to construct an enum from an invalid value"),
384 false,
385 );
386}
387
388#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
396#[cfg_attr(panic = "immediate-abort", inline)]
397#[lang = "panic_cannot_unwind"] #[rustc_nounwind]
399#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
400fn panic_cannot_unwind() -> ! {
401 panic_nounwind("panic in a function that cannot unwind")
403}
404
405#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
413#[cfg_attr(panic = "immediate-abort", inline)]
414#[lang = "panic_in_cleanup"] #[rustc_nounwind]
416#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
417fn panic_in_cleanup() -> ! {
418 panic_nounwind_nobacktrace("panic in a destructor during cleanup")
420}
421
422#[lang = "const_panic_fmt"] #[rustc_const_stable_indirect] #[cfg(not(feature = "ferrocene_subset"))]
426pub const fn const_panic_fmt(fmt: PanicArguments<'_>) -> ! {
427 if let Some(msg) = fmt.as_str() {
428 panic_display(&msg);
430 } else {
431 unsafe { crate::hint::unreachable_unchecked() };
435 }
436}
437
438#[derive(Debug)]
439#[doc(hidden)]
440#[cfg(not(feature = "ferrocene_certified_runtime"))]
441pub enum AssertKind {
442 Eq,
443 Ne,
444 Match,
445}
446
447#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
449#[cfg_attr(panic = "immediate-abort", inline)]
450#[track_caller]
451#[doc(hidden)]
452#[cfg(not(feature = "ferrocene_certified_runtime"))]
453pub fn assert_failed<T, U>(
454 kind: AssertKind,
455 left: &T,
456 right: &U,
457 args: Option<fmt::Arguments<'_>>,
458) -> !
459where
460 T: fmt::Debug + ?Sized,
461 U: fmt::Debug + ?Sized,
462{
463 assert_failed_inner(kind, &left, &right, args)
464}
465
466#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
468#[cfg_attr(panic = "immediate-abort", inline)]
469#[track_caller]
470#[doc(hidden)]
471#[cfg(not(feature = "ferrocene_certified_runtime"))]
472pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
473 left: &T,
474 right: &str,
475 args: Option<fmt::Arguments<'_>>,
476) -> ! {
477 struct Pattern<'a>(&'a str);
479 impl fmt::Debug for Pattern<'_> {
480 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481 f.write_str(self.0)
482 }
483 }
484 assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
485}
486
487#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
489#[cfg_attr(panic = "immediate-abort", inline)]
490#[track_caller]
491#[cfg(not(feature = "ferrocene_certified_runtime"))]
492fn assert_failed_inner(
493 kind: AssertKind,
494 left: &dyn fmt::Debug,
495 right: &dyn fmt::Debug,
496 args: Option<fmt::Arguments<'_>>,
497) -> ! {
498 let op = match kind {
499 AssertKind::Eq => "==",
500 AssertKind::Ne => "!=",
501 AssertKind::Match => "matches",
502 };
503
504 match args {
505 Some(args) => panic!(
506 r#"assertion `left {op} right` failed: {args}
507 left: {left:?}
508 right: {right:?}"#
509 ),
510 None => panic!(
511 r#"assertion `left {op} right` failed
512 left: {left:?}
513 right: {right:?}"#
514 ),
515 }
516}