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 if cfg!(panic = "immediate-abort") {
62 super::intrinsics::abort()
63 }
64
65 unsafe extern "Rust" {
68 #[lang = "panic_impl"]
69 fn panic_impl(pi: &PanicInfo<'_>) -> !;
70 }
71
72 let pi = PanicInfo::new(
73 &fmt,
74 Location::caller(),
75 true,
76 false,
77 );
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)]
95pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! {
96 const_eval_select!(
97 @capture { fmt: fmt::Arguments<'_>, force_no_backtrace: bool } -> !:
98 if const #[track_caller] {
99 panic_fmt(fmt)
101 } else #[track_caller] {
102 if cfg!(panic = "immediate-abort") {
103 super::intrinsics::abort()
104 }
105
106 unsafe extern "Rust" {
109 #[lang = "panic_impl"]
110 fn panic_impl(pi: &PanicInfo<'_>) -> !;
111 }
112
113 let pi = PanicInfo::new(
115 &fmt,
116 Location::caller(),
117 false,
118 force_no_backtrace,
119 );
120
121 unsafe { panic_impl(&pi) }
123 }
124 )
125}
126
127#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
134#[cfg_attr(panic = "immediate-abort", inline)]
135#[track_caller]
136#[rustc_const_stable_indirect] #[lang = "panic"] pub const fn panic(expr: &'static str) -> ! {
139 panic_fmt(fmt::Arguments::new_const(&[expr]));
151}
152
153macro_rules! panic_const {
162 ($($lang:ident = $message:expr,)+) => {
163 $(
164 #[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
169 #[cfg_attr(panic = "immediate-abort", inline)]
170 #[track_caller]
171 #[rustc_const_stable_indirect] #[lang = stringify!($lang)]
173 pub const fn $lang() -> ! {
174 panic_fmt(fmt::Arguments::new_const(&[$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] pub const fn panic_nounwind(expr: &'static str) -> ! {
230 panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), false);
231}
232
233#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold)]
235#[cfg_attr(panic = "immediate-abort", inline)]
236#[rustc_nounwind]
237pub fn panic_nounwind_nobacktrace(expr: &'static str) -> ! {
238 panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), true);
239}
240
241#[inline]
242#[track_caller]
243#[rustc_diagnostic_item = "unreachable_display"] pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
245 panic_fmt(format_args!("internal error: entered unreachable code: {}", *x));
246}
247
248#[inline]
251#[track_caller]
252#[rustc_diagnostic_item = "panic_str_2015"]
253#[rustc_const_stable_indirect] pub const fn panic_str_2015(expr: &str) -> ! {
255 panic_display(&expr);
256}
257
258#[inline]
259#[track_caller]
260#[lang = "panic_display"] #[rustc_do_not_const_check] #[rustc_const_stable_indirect] pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
264 panic_fmt(format_args!("{}", *x));
265}
266
267#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
268#[cfg_attr(panic = "immediate-abort", inline)]
269#[track_caller]
270#[lang = "panic_bounds_check"] fn panic_bounds_check(index: usize, len: usize) -> ! {
272 if cfg!(panic = "immediate-abort") {
273 super::intrinsics::abort()
274 }
275
276 panic!("index out of bounds: the len is {len} but the index is {index}")
277}
278
279#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
280#[cfg_attr(panic = "immediate-abort", inline)]
281#[track_caller]
282#[lang = "panic_misaligned_pointer_dereference"] #[rustc_nounwind] fn panic_misaligned_pointer_dereference(required: usize, found: usize) -> ! {
285 if cfg!(panic = "immediate-abort") {
286 super::intrinsics::abort()
287 }
288
289 panic_nounwind_fmt(
290 format_args!(
291 "misaligned pointer dereference: address must be a multiple of {required:#x} but is {found:#x}"
292 ),
293 false,
294 )
295}
296
297#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
298#[cfg_attr(panic = "immediate-abort", inline)]
299#[track_caller]
300#[lang = "panic_null_pointer_dereference"] #[rustc_nounwind] fn panic_null_pointer_dereference() -> ! {
303 if cfg!(panic = "immediate-abort") {
304 super::intrinsics::abort()
305 }
306
307 panic_nounwind_fmt(
308 format_args!("null pointer dereference occurred"),
309 false,
310 )
311}
312
313#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
314#[cfg_attr(panic = "immediate-abort", inline)]
315#[track_caller]
316#[lang = "panic_invalid_enum_construction"] #[rustc_nounwind] fn panic_invalid_enum_construction(source: u128) -> ! {
319 if cfg!(panic = "immediate-abort") {
320 super::intrinsics::abort()
321 }
322
323 panic_nounwind_fmt(
324 format_args!("trying to construct an enum from an invalid value {source:#x}"),
325 false,
326 )
327}
328
329#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
337#[cfg_attr(panic = "immediate-abort", inline)]
338#[lang = "panic_cannot_unwind"] #[rustc_nounwind]
340fn panic_cannot_unwind() -> ! {
341 panic_nounwind("panic in a function that cannot unwind")
343}
344
345#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
353#[cfg_attr(panic = "immediate-abort", inline)]
354#[lang = "panic_in_cleanup"] #[rustc_nounwind]
356fn panic_in_cleanup() -> ! {
357 panic_nounwind_nobacktrace("panic in a destructor during cleanup")
359}
360
361#[lang = "const_panic_fmt"] #[rustc_const_stable_indirect] pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
365 if let Some(msg) = fmt.as_str() {
366 panic_display(&msg);
368 } else {
369 unsafe { crate::hint::unreachable_unchecked() };
373 }
374}
375
376#[derive(Debug)]
377#[doc(hidden)]
378pub enum AssertKind {
379 Eq,
380 Ne,
381 Match,
382}
383
384#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
386#[cfg_attr(panic = "immediate-abort", inline)]
387#[track_caller]
388#[doc(hidden)]
389pub fn assert_failed<T, U>(
390 kind: AssertKind,
391 left: &T,
392 right: &U,
393 args: Option<fmt::Arguments<'_>>,
394) -> !
395where
396 T: fmt::Debug + ?Sized,
397 U: fmt::Debug + ?Sized,
398{
399 assert_failed_inner(kind, &left, &right, args)
400}
401
402#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
404#[cfg_attr(panic = "immediate-abort", inline)]
405#[track_caller]
406#[doc(hidden)]
407pub fn assert_matches_failed<T: fmt::Debug + ?Sized>(
408 left: &T,
409 right: &str,
410 args: Option<fmt::Arguments<'_>>,
411) -> ! {
412 struct Pattern<'a>(&'a str);
414 impl fmt::Debug for Pattern<'_> {
415 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
416 f.write_str(self.0)
417 }
418 }
419 assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args);
420}
421
422#[cfg_attr(not(panic = "immediate-abort"), inline(never), cold, optimize(size))]
424#[cfg_attr(panic = "immediate-abort", inline)]
425#[track_caller]
426fn assert_failed_inner(
427 kind: AssertKind,
428 left: &dyn fmt::Debug,
429 right: &dyn fmt::Debug,
430 args: Option<fmt::Arguments<'_>>,
431) -> ! {
432 let op = match kind {
433 AssertKind::Eq => "==",
434 AssertKind::Ne => "!=",
435 AssertKind::Match => "matches",
436 };
437
438 match args {
439 Some(args) => panic!(
440 r#"assertion `left {op} right` failed: {args}
441 left: {left:?}
442 right: {right:?}"#
443 ),
444 None => panic!(
445 r#"assertion `left {op} right` failed
446 left: {left:?}
447 right: {right:?}"#
448 ),
449 }
450}