]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //! Panic support for libcore |
2 | //! | |
3 | //! The core library cannot define panicking, but it does *declare* panicking. This | |
4 | //! means that the functions inside of libcore are allowed to panic, but to be | |
5 | //! useful an upstream crate must define panicking for libcore to use. The current | |
6 | //! interface for panicking is: | |
7 | //! | |
041b39d2 | 8 | //! ``` |
60c5eb7d | 9 | //! fn panic_impl(pi: &core::panic::PanicInfo<'_>) -> ! |
041b39d2 | 10 | //! # { loop {} } |
1a4d82fc JJ |
11 | //! ``` |
12 | //! | |
13 | //! This definition allows for panicking with any general message, but it does not | |
60c5eb7d XL |
14 | //! allow for failing with a `Box<Any>` value. (`PanicInfo` just contains a `&(dyn Any + Send)`, |
15 | //! for which we fill in a dummy value in `PanicInfo::internal_constructor`.) | |
16 | //! The reason for this is that libcore is not allowed to allocate. | |
1a4d82fc JJ |
17 | //! |
18 | //! This module contains a few other panicking functions, but these are just the | |
19 | //! necessary lang items for the compiler. All panics are funneled through this | |
60c5eb7d XL |
20 | //! one function. The actual symbol is declared through the `#[panic_handler]` attribute. |
21 | ||
1a4d82fc | 22 | #![allow(dead_code, missing_docs)] |
60c5eb7d XL |
23 | #![unstable( |
24 | feature = "core_panic", | |
f035d41b | 25 | reason = "internal details of the implementation of the `panic!` and related macros", |
dfeec247 | 26 | issue = "none" |
60c5eb7d | 27 | )] |
1a4d82fc | 28 | |
48663c56 XL |
29 | use crate::fmt; |
30 | use crate::panic::{Location, PanicInfo}; | |
1a4d82fc | 31 | |
ba9703b0 | 32 | /// The underlying implementation of libcore's `panic!` macro when no formatting is used. |
a1dfa0c6 XL |
33 | #[cold] |
34 | // never inline unless panic_immediate_abort to avoid code | |
35 | // bloat at the call sites as much as possible | |
60c5eb7d | 36 | #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] |
3c0e092e | 37 | #[cfg_attr(feature = "panic_immediate_abort", inline)] |
dfeec247 | 38 | #[track_caller] |
3c0e092e | 39 | #[rustc_const_unstable(feature = "core_panic", issue = "none")] |
60c5eb7d | 40 | #[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators |
3c0e092e | 41 | pub const fn panic(expr: &'static str) -> ! { |
5e7ed085 | 42 | // Use Arguments::new_v1 instead of format_args!("{expr}") to potentially |
e74abb32 XL |
43 | // reduce size overhead. The format_args! macro uses str's Display trait to |
44 | // write expr, which calls Formatter::pad, which must accommodate string | |
45 | // truncation and padding (even though none is used here). Using | |
46 | // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the | |
47 | // output binary, saving up to a few kilobytes. | |
c295e0f8 | 48 | panic_fmt(fmt::Arguments::new_v1(&[expr], &[])); |
e74abb32 XL |
49 | } |
50 | ||
29967ef6 XL |
51 | #[inline] |
52 | #[track_caller] | |
a2a8927a XL |
53 | #[rustc_diagnostic_item = "panic_str"] |
54 | #[rustc_const_unstable(feature = "core_panic", issue = "none")] | |
3c0e092e XL |
55 | pub const fn panic_str(expr: &str) -> ! { |
56 | panic_display(&expr); | |
29967ef6 XL |
57 | } |
58 | ||
a2a8927a XL |
59 | #[inline] |
60 | #[track_caller] | |
61 | #[rustc_diagnostic_item = "unreachable_display"] // needed for `non-fmt-panics` lint | |
62 | pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! { | |
63 | panic_fmt(format_args!("internal error: entered unreachable code: {}", *x)); | |
64 | } | |
65 | ||
c295e0f8 XL |
66 | #[inline] |
67 | #[track_caller] | |
3c0e092e XL |
68 | #[lang = "panic_display"] // needed for const-evaluated panics |
69 | #[rustc_do_not_const_check] // hooked by const-eval | |
5099ac24 | 70 | #[rustc_const_unstable(feature = "core_panic", issue = "none")] |
3c0e092e | 71 | pub const fn panic_display<T: fmt::Display>(x: &T) -> ! { |
c295e0f8 XL |
72 | panic_fmt(format_args!("{}", *x)); |
73 | } | |
74 | ||
ba9703b0 XL |
75 | #[cold] |
76 | #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] | |
77 | #[track_caller] | |
78 | #[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access | |
79 | fn panic_bounds_check(index: usize, len: usize) -> ! { | |
80 | if cfg!(feature = "panic_immediate_abort") { | |
f035d41b | 81 | super::intrinsics::abort() |
ba9703b0 XL |
82 | } |
83 | ||
5e7ed085 | 84 | panic!("index out of bounds: the len is {len} but the index is {index}") |
ba9703b0 XL |
85 | } |
86 | ||
5e7ed085 FG |
87 | // This function is called directly by the codegen backend, and must not have |
88 | // any extra arguments (including those synthesized by track_caller). | |
5099ac24 | 89 | #[cold] |
5e7ed085 | 90 | #[inline(never)] |
5099ac24 FG |
91 | #[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function |
92 | fn panic_no_unwind() -> ! { | |
93 | if cfg!(feature = "panic_immediate_abort") { | |
94 | super::intrinsics::abort() | |
95 | } | |
96 | ||
97 | // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call | |
98 | // that gets resolved to the `#[panic_handler]` function. | |
99 | extern "Rust" { | |
100 | #[lang = "panic_impl"] | |
101 | fn panic_impl(pi: &PanicInfo<'_>) -> !; | |
102 | } | |
103 | ||
104 | // PanicInfo with the `can_unwind` flag set to false forces an abort. | |
105 | let fmt = format_args!("panic in a function that cannot unwind"); | |
106 | let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false); | |
107 | ||
108 | // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. | |
109 | unsafe { panic_impl(&pi) } | |
110 | } | |
111 | ||
3c0e092e XL |
112 | /// The entry point for panicking with a formatted message. |
113 | /// | |
114 | /// This is designed to reduce the amount of code required at the call | |
115 | /// site as much as possible (so that `panic!()` has as low an impact | |
116 | /// on (e.g.) the inlining of other functions as possible), by moving | |
117 | /// the actual formatting into this shared place. | |
e74abb32 | 118 | #[cold] |
3c0e092e XL |
119 | // If panic_immediate_abort, inline the abort call, |
120 | // otherwise avoid inlining because of it is cold path. | |
60c5eb7d XL |
121 | #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] |
122 | #[cfg_attr(feature = "panic_immediate_abort", inline)] | |
f9f354fc | 123 | #[track_caller] |
c295e0f8 | 124 | #[lang = "panic_fmt"] // needed for const-evaluated panics |
3c0e092e | 125 | #[rustc_do_not_const_check] // hooked by const-eval |
5099ac24 | 126 | #[rustc_const_unstable(feature = "core_panic", issue = "none")] |
3c0e092e | 127 | pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { |
e74abb32 | 128 | if cfg!(feature = "panic_immediate_abort") { |
f035d41b | 129 | super::intrinsics::abort() |
e74abb32 XL |
130 | } |
131 | ||
132 | // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call | |
60c5eb7d | 133 | // that gets resolved to the `#[panic_handler]` function. |
e74abb32 XL |
134 | extern "Rust" { |
135 | #[lang = "panic_impl"] | |
136 | fn panic_impl(pi: &PanicInfo<'_>) -> !; | |
137 | } | |
138 | ||
5099ac24 | 139 | let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true); |
ba9703b0 | 140 | |
f9f354fc | 141 | // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. |
94b46f34 XL |
142 | unsafe { panic_impl(&pi) } |
143 | } | |
6a06907d | 144 | |
94222f64 | 145 | /// This function is used instead of panic_fmt in const eval. |
94222f64 | 146 | #[lang = "const_panic_fmt"] |
5099ac24 | 147 | #[rustc_const_unstable(feature = "core_panic", issue = "none")] |
94222f64 XL |
148 | pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { |
149 | if let Some(msg) = fmt.as_str() { | |
150 | panic_str(msg); | |
151 | } else { | |
152 | // SAFETY: This is only evaluated at compile time, which reliably | |
153 | // handles this UB (in case this branch turns out to be reachable | |
154 | // somehow). | |
155 | unsafe { crate::hint::unreachable_unchecked() }; | |
156 | } | |
157 | } | |
158 | ||
6a06907d XL |
159 | #[derive(Debug)] |
160 | #[doc(hidden)] | |
161 | pub enum AssertKind { | |
162 | Eq, | |
163 | Ne, | |
17df50a5 | 164 | Match, |
6a06907d XL |
165 | } |
166 | ||
167 | /// Internal function for `assert_eq!` and `assert_ne!` macros | |
168 | #[cold] | |
169 | #[track_caller] | |
170 | #[doc(hidden)] | |
171 | pub fn assert_failed<T, U>( | |
172 | kind: AssertKind, | |
173 | left: &T, | |
174 | right: &U, | |
175 | args: Option<fmt::Arguments<'_>>, | |
176 | ) -> ! | |
177 | where | |
178 | T: fmt::Debug + ?Sized, | |
179 | U: fmt::Debug + ?Sized, | |
180 | { | |
17df50a5 XL |
181 | assert_failed_inner(kind, &left, &right, args) |
182 | } | |
183 | ||
184 | /// Internal function for `assert_match!` | |
185 | #[cold] | |
186 | #[track_caller] | |
187 | #[doc(hidden)] | |
188 | pub fn assert_matches_failed<T: fmt::Debug + ?Sized>( | |
189 | left: &T, | |
190 | right: &str, | |
191 | args: Option<fmt::Arguments<'_>>, | |
192 | ) -> ! { | |
193 | // Use the Display implementation to display the pattern. | |
194 | struct Pattern<'a>(&'a str); | |
195 | impl fmt::Debug for Pattern<'_> { | |
196 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
197 | fmt::Display::fmt(self.0, f) | |
198 | } | |
199 | } | |
200 | assert_failed_inner(AssertKind::Match, &left, &Pattern(right), args); | |
201 | } | |
202 | ||
203 | /// Non-generic version of the above functions, to avoid code bloat. | |
204 | #[track_caller] | |
205 | fn assert_failed_inner( | |
206 | kind: AssertKind, | |
207 | left: &dyn fmt::Debug, | |
208 | right: &dyn fmt::Debug, | |
209 | args: Option<fmt::Arguments<'_>>, | |
210 | ) -> ! { | |
211 | let op = match kind { | |
212 | AssertKind::Eq => "==", | |
213 | AssertKind::Ne => "!=", | |
214 | AssertKind::Match => "matches", | |
215 | }; | |
216 | ||
217 | match args { | |
218 | Some(args) => panic!( | |
219 | r#"assertion failed: `(left {} right)` | |
6a06907d XL |
220 | left: `{:?}`, |
221 | right: `{:?}`: {}"#, | |
17df50a5 XL |
222 | op, left, right, args |
223 | ), | |
224 | None => panic!( | |
225 | r#"assertion failed: `(left {} right)` | |
6a06907d XL |
226 | left: `{:?}`, |
227 | right: `{:?}`"#, | |
17df50a5 XL |
228 | op, left, right, |
229 | ), | |
6a06907d XL |
230 | } |
231 | } |