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] pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
61 #[ferrocene::annotation(
62 "The `immediate-abort` behavior is not certified, we only support `abort`."
63 )]
64 if cfg!(panic = "immediate-abort") {
65 super::intrinsics::abort()
66 };
67
68 unsafe extern "Rust" {
71 #[lang = "panic_impl"]
72 fn panic_impl(pi: &PanicInfo<'_>) -> !;
73 }
74
75 let pi = PanicInfo::new(
76 &fmt,
77 Location::caller(),
78 true,
79 false,
80 );
81 unsafe { panic_impl(&pi) }
83}
84
85#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
89#[cfg_attr(panic = "immediate-abort", inline)]
90#[track_caller]
91#[rustc_nounwind]
95#[rustc_const_stable_indirect] #[rustc_allow_const_fn_unstable(const_eval_select)]
97#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
98pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, _force_no_backtrace: bool) -> ! {
99 const_eval_select!(
100 @capture { fmt: fmt::Arguments<'_>, _force_no_backtrace: bool } -> !:
101 if const #[track_caller] {
102 panic_fmt(fmt)
104 } else #[track_caller] {
105 if cfg!(panic = "immediate-abort") {
106 super::intrinsics::abort()
107 }
108
109 unsafe extern "Rust" {
112 #[lang = "panic_impl"]
113 fn panic_impl(pi: &PanicInfo<'_>) -> !;
114 }
115
116 let pi = PanicInfo::new(
118 &fmt,
119 Location::caller(),
120 false,
121 _force_no_backtrace,
122 );
123
124 unsafe { panic_impl(&pi) }
126 }
127 )
128}
129
130#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
137#[cfg_attr(panic = "immediate-abort", inline)]
138#[track_caller]
139#[rustc_const_stable_indirect] #[lang = "panic"] pub 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 pub const fn $lang() -> ! {
178 panic_fmt(fmt::Arguments::from_str($message));
180 }
181 )+
182 }
183}
184
185pub mod panic_const {
190 use super::*;
191 panic_const! {
192 panic_const_add_overflow = "attempt to add with overflow",
193 panic_const_sub_overflow = "attempt to subtract with overflow",
194 panic_const_mul_overflow = "attempt to multiply with overflow",
195 panic_const_div_overflow = "attempt to divide with overflow",
196 panic_const_rem_overflow = "attempt to calculate the remainder with overflow",
197 panic_const_neg_overflow = "attempt to negate with overflow",
198 panic_const_shr_overflow = "attempt to shift right with overflow",
199 panic_const_shl_overflow = "attempt to shift left with overflow",
200 panic_const_div_by_zero = "attempt to divide by zero",
201 panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero",
202 panic_const_coroutine_resumed = "coroutine resumed after completion",
203 panic_const_async_fn_resumed = "`async fn` resumed after completion",
204 panic_const_async_gen_fn_resumed = "`async gen fn` resumed after completion",
205 panic_const_gen_fn_none = "`gen fn` should just keep returning `None` after completion",
206 panic_const_coroutine_resumed_panic = "coroutine resumed after panicking",
207 panic_const_async_fn_resumed_panic = "`async fn` resumed after panicking",
208 panic_const_async_gen_fn_resumed_panic = "`async gen fn` resumed after panicking",
209 panic_const_gen_fn_none_panic = "`gen fn` should just keep returning `None` after panicking",
210 }
211 panic_const! {
214 panic_const_coroutine_resumed_drop = "coroutine resumed after async drop",
215 panic_const_async_fn_resumed_drop = "`async fn` resumed after async drop",
216 panic_const_async_gen_fn_resumed_drop = "`async gen fn` resumed after async drop",
217 panic_const_gen_fn_none_drop = "`gen fn` resumed after async drop",
218 }
219}
220
221#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
224#[cfg_attr(panic = "immediate-abort", inline)]
225#[lang = "panic_nounwind"] #[rustc_nounwind]
227#[rustc_const_stable_indirect] #[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
229pub const fn panic_nounwind(expr: &'static str) -> ! {
230 panic_nounwind_fmt(fmt::Arguments::from_str(expr), false);
231}
232
233#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
235#[cfg_attr(panic = "immediate-abort", inline)]
236#[rustc_nounwind]
237#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
238pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! {
239 panic_nounwind_fmt(fmt::Arguments::from_str(expr), true);
240}
241
242#[inline]
243#[track_caller]
244#[rustc_diagnostic_item = "unreachable_display"] pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
246 panic_fmt(format_args!("internal error: entered unreachable code: {}", *x));
247}
248
249#[inline]
252#[track_caller]
253#[rustc_diagnostic_item = "panic_str_2015"]
254#[rustc_const_stable_indirect] pub const fn panic_str_2015(expr: &str) -> ! {
256 panic_display(&expr);
257}
258
259#[inline]
260#[track_caller]
261#[lang = "panic_display"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
265 panic_fmt(format_args!("{}", *x));
266}
267
268#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
269#[cfg_attr(panic = "immediate-abort", inline)]
270#[track_caller]
271#[lang = "panic_bounds_check"] fn panic_bounds_check(index: usize, len: usize) -> ! {
273 #[ferrocene::annotation(
274 "The `immediate-abort` behavior is not certified, we only support `abort`."
275 )]
276 if cfg!(panic = "immediate-abort") {
277 super::intrinsics::abort()
278 }
279 panic!("index out of bounds: the len is {len} but the index is {index}")
280}
281
282#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
283#[cfg_attr(panic = "immediate-abort", inline)]
284#[track_caller]
285#[lang = "panic_misaligned_pointer_dereference"] #[rustc_nounwind] #[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
288fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
289 if cfg!(panic = "immediate-abort") {
290 super::intrinsics::abort()
291 }
292
293 panic_nounwind_fmt(
294 format_args!(
295 "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
296 ),
297 false,
298 );
299}
300
301#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
302#[cfg_attr(panic = "immediate-abort", inline)]
303#[track_caller]
304#[lang = "panic_null_pointer_dereference"] #[rustc_nounwind] #[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
307fn panic_null_pointer_dereference() -> ! {
308 if cfg!(panic = "immediate-abort") {
309 super::intrinsics::abort()
310 }
311
312 panic_nounwind_fmt(
313 fmt::Arguments::from_str("null pointer dereference occurred"),
314 false,
315 )
316}
317
318#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
319#[cfg_attr(panic = "immediate-abort", inline)]
320#[track_caller]
321#[lang = "panic_invalid_enum_construction"] #[rustc_nounwind] #[cfg(not(feature = "ferrocene_subset"))]
324fn panic_invalid_enum_construction(source: u128) -> ! {
325 #[ferrocene::annotation(
326 "The `immediate-abort` behavior is not certified, we only support `abort`."
327 )]
328 if cfg!(panic = "immediate-abort") {
329 super::intrinsics::abort()
330 }
331
332 panic_nounwind_fmt(
333 format_args!("trying to construct an enum from an invalid value {source:#x}"),
334 false,
335 );
336}
337
338#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
346#[cfg_attr(panic = "immediate-abort", inline)]
347#[lang = "panic_cannot_unwind"] #[rustc_nounwind]
349#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
350fn panic_cannot_unwind() -> ! {
351 panic_nounwind("panic in a function that cannot unwind")
353}
354
355#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
363#[cfg_attr(panic = "immediate-abort", inline)]
364#[lang = "panic_in_cleanup"] #[rustc_nounwind]
366#[ferrocene::annotation("Cannot be covered as it causes a non-unwinding panic")]
367fn panic_in_cleanup() -> ! {
368 panic_nounwind_nobacktrace("panic in a destructor during cleanup")
370}
371
372#[lang = "const_panic_fmt"] #[rustc_const_stable_indirect] #[cfg(not(feature = "ferrocene_subset"))]
376pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
377 if let Some(msg) = fmt.as_str() {
378 panic_display(&msg);
380 } else {
381 unsafe { crate::hint::unreachable_unchecked() };
385 }
386}
387
388#[derive(Debug)]
389#[doc(hidden)]
390pub enum AssertKind {
391 Eq,
392 Ne,
393 Match,
394}
395
396#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
398#[cfg_attr(panic = "immediate-abort", inline)]
399#[track_caller]
400#[doc(hidden)]
401pub fn assert_failed<T, U>(
402 kind: AssertKind,
403 left: &T,
404 right: &U,
405 args: Option<fmt::Arguments<'_>>,
406) -> !
407where
408 T: fmt::Debug + ?Sized,
409 U: fmt::Debug + ?Sized,
410{
411 assert_failed_inner(kind, &left, &right, args)
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)]
419pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
420 left: &T,
421 right: &str,
422 args: Option<fmt::Arguments<'_>>,
423) -> ! {
424 struct Pattern<'a>(&'a str);
426 impl fmt::Debug for Pattern<'_> {
427 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
428 f.write_str(self.0)
429 }
430 }
431 assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
432}
433
434#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
436#[cfg_attr(panic = "immediate-abort", inline)]
437#[track_caller]
438fn assert_failed_inner(
439 kind: AssertKind,
440 left: &dyn fmt::Debug,
441 right: &dyn fmt::Debug,
442 args: Option<fmt::Arguments<'_>>,
443) -> ! {
444 let op = match kind {
445 AssertKind::Eq => "==",
446 AssertKind::Ne => "!=",
447 AssertKind::Match => "matches",
448 };
449
450 match args {
451 Some(args) => panic!(
452 r#"assertion `left {op} right` failed: {args}
453 left: {left:?}
454 right: {right:?}"#
455 ),
456 None => panic!(
457 r#"assertion `left {op} right` failed
458 left: {left:?}
459 right: {right:?}"#
460 ),
461 }
462}