]> git.proxmox.com Git - rustc.git/blob - src/libcore/panic.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / libcore / panic.rs
1 //! Panic support in the standard library.
2
3 #![stable(feature = "core_panic_info", since = "1.41.0")]
4
5 use crate::any::Any;
6 use crate::fmt;
7
8 /// A struct providing information about a panic.
9 ///
10 /// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
11 /// function.
12 ///
13 /// [`set_hook`]: ../../std/panic/fn.set_hook.html
14 ///
15 /// # Examples
16 ///
17 /// ```should_panic
18 /// use std::panic;
19 ///
20 /// panic::set_hook(Box::new(|panic_info| {
21 /// if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
22 /// println!("panic occurred: {:?}", s);
23 /// } else {
24 /// println!("panic occurred");
25 /// }
26 /// }));
27 ///
28 /// panic!("Normal panic");
29 /// ```
30 #[lang = "panic_info"]
31 #[stable(feature = "panic_hooks", since = "1.10.0")]
32 #[derive(Debug)]
33 pub struct PanicInfo<'a> {
34 payload: &'a (dyn Any + Send),
35 message: Option<&'a fmt::Arguments<'a>>,
36 location: &'a Location<'a>,
37 }
38
39 impl<'a> PanicInfo<'a> {
40 #[unstable(feature = "panic_internals",
41 reason = "internal details of the implementation of the `panic!` \
42 and related macros",
43 issue = "0")]
44 #[doc(hidden)]
45 #[inline]
46 pub fn internal_constructor(
47 message: Option<&'a fmt::Arguments<'a>>,
48 location: &'a Location<'a>,
49 ) -> Self {
50 struct NoPayload;
51 PanicInfo {
52 location,
53 message,
54 payload: &NoPayload,
55 }
56 }
57
58 #[unstable(feature = "panic_internals",
59 reason = "internal details of the implementation of the `panic!` \
60 and related macros",
61 issue = "0")]
62 #[doc(hidden)]
63 #[inline]
64 pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
65 self.payload = info;
66 }
67
68 /// Returns the payload associated with the panic.
69 ///
70 /// This will commonly, but not always, be a `&'static str` or [`String`].
71 ///
72 /// [`String`]: ../../std/string/struct.String.html
73 ///
74 /// # Examples
75 ///
76 /// ```should_panic
77 /// use std::panic;
78 ///
79 /// panic::set_hook(Box::new(|panic_info| {
80 /// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
81 /// }));
82 ///
83 /// panic!("Normal panic");
84 /// ```
85 #[stable(feature = "panic_hooks", since = "1.10.0")]
86 pub fn payload(&self) -> &(dyn Any + Send) {
87 self.payload
88 }
89
90 /// If the `panic!` macro from the `core` crate (not from `std`)
91 /// was used with a formatting string and some additional arguments,
92 /// returns that message ready to be used for example with [`fmt::write`]
93 ///
94 /// [`fmt::write`]: ../fmt/fn.write.html
95 #[unstable(feature = "panic_info_message", issue = "66745")]
96 pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
97 self.message
98 }
99
100 /// Returns information about the location from which the panic originated,
101 /// if available.
102 ///
103 /// This method will currently always return [`Some`], but this may change
104 /// in future versions.
105 ///
106 /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
107 ///
108 /// # Examples
109 ///
110 /// ```should_panic
111 /// use std::panic;
112 ///
113 /// panic::set_hook(Box::new(|panic_info| {
114 /// if let Some(location) = panic_info.location() {
115 /// println!("panic occurred in file '{}' at line {}", location.file(),
116 /// location.line());
117 /// } else {
118 /// println!("panic occurred but can't get location information...");
119 /// }
120 /// }));
121 ///
122 /// panic!("Normal panic");
123 /// ```
124 #[stable(feature = "panic_hooks", since = "1.10.0")]
125 pub fn location(&self) -> Option<&Location<'_>> {
126 // NOTE: If this is changed to sometimes return None,
127 // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
128 Some(&self.location)
129 }
130 }
131
132 #[stable(feature = "panic_hook_display", since = "1.26.0")]
133 impl fmt::Display for PanicInfo<'_> {
134 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
135 formatter.write_str("panicked at ")?;
136 if let Some(message) = self.message {
137 write!(formatter, "'{}', ", message)?
138 } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
139 write!(formatter, "'{}', ", payload)?
140 }
141 // NOTE: we cannot use downcast_ref::<String>() here
142 // since String is not available in libcore!
143 // The payload is a String when `std::panic!` is called with multiple arguments,
144 // but in that case the message is also available.
145
146 self.location.fmt(formatter)
147 }
148 }
149
150 /// A struct containing information about the location of a panic.
151 ///
152 /// This structure is created by the [`location`] method of [`PanicInfo`].
153 ///
154 /// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location
155 /// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html
156 ///
157 /// # Examples
158 ///
159 /// ```should_panic
160 /// use std::panic;
161 ///
162 /// panic::set_hook(Box::new(|panic_info| {
163 /// if let Some(location) = panic_info.location() {
164 /// println!("panic occurred in file '{}' at line {}", location.file(), location.line());
165 /// } else {
166 /// println!("panic occurred but can't get location information...");
167 /// }
168 /// }));
169 ///
170 /// panic!("Normal panic");
171 /// ```
172 #[lang = "panic_location"]
173 #[derive(Debug)]
174 #[stable(feature = "panic_hooks", since = "1.10.0")]
175 pub struct Location<'a> {
176 file: &'a str,
177 line: u32,
178 col: u32,
179 }
180
181 impl<'a> Location<'a> {
182 /// Returns the source location of the caller of this function. If that function's caller is
183 /// annotated then its call location will be returned, and so on up the stack to the first call
184 /// within a non-tracked function body.
185 ///
186 /// # Examples
187 ///
188 /// ```
189 /// #![feature(track_caller)]
190 /// use core::panic::Location;
191 ///
192 /// /// Returns the [`Location`] at which it is called.
193 /// #[track_caller]
194 /// fn get_caller_location() -> &'static Location<'static> {
195 /// Location::caller()
196 /// }
197 ///
198 /// /// Returns a [`Location`] from within this function's definition.
199 /// fn get_just_one_location() -> &'static Location<'static> {
200 /// get_caller_location()
201 /// }
202 ///
203 /// let fixed_location = get_just_one_location();
204 /// assert_eq!(fixed_location.file(), file!());
205 /// assert_eq!(fixed_location.line(), 15);
206 /// assert_eq!(fixed_location.column(), 5);
207 ///
208 /// // running the same untracked function in a different location gives us the same result
209 /// let second_fixed_location = get_just_one_location();
210 /// assert_eq!(fixed_location.file(), second_fixed_location.file());
211 /// assert_eq!(fixed_location.line(), second_fixed_location.line());
212 /// assert_eq!(fixed_location.column(), second_fixed_location.column());
213 ///
214 /// let this_location = get_caller_location();
215 /// assert_eq!(this_location.file(), file!());
216 /// assert_eq!(this_location.line(), 29);
217 /// assert_eq!(this_location.column(), 21);
218 ///
219 /// // running the tracked function in a different location produces a different value
220 /// let another_location = get_caller_location();
221 /// assert_eq!(this_location.file(), another_location.file());
222 /// assert_ne!(this_location.line(), another_location.line());
223 /// assert_ne!(this_location.column(), another_location.column());
224 /// ```
225 #[cfg(not(bootstrap))]
226 #[unstable(feature = "track_caller",
227 reason = "uses #[track_caller] which is not yet stable",
228 issue = "47809")]
229 #[track_caller]
230 pub const fn caller() -> &'static Location<'static> {
231 crate::intrinsics::caller_location()
232 }
233 }
234
235 impl<'a> Location<'a> {
236 #![unstable(feature = "panic_internals",
237 reason = "internal details of the implementation of the `panic!` \
238 and related macros",
239 issue = "0")]
240 #[doc(hidden)]
241 pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
242 Location { file, line, col }
243 }
244
245 /// Returns the name of the source file from which the panic originated.
246 ///
247 /// # Examples
248 ///
249 /// ```should_panic
250 /// use std::panic;
251 ///
252 /// panic::set_hook(Box::new(|panic_info| {
253 /// if let Some(location) = panic_info.location() {
254 /// println!("panic occurred in file '{}'", location.file());
255 /// } else {
256 /// println!("panic occurred but can't get location information...");
257 /// }
258 /// }));
259 ///
260 /// panic!("Normal panic");
261 /// ```
262 #[stable(feature = "panic_hooks", since = "1.10.0")]
263 pub fn file(&self) -> &str {
264 self.file
265 }
266
267 /// Returns the line number from which the panic originated.
268 ///
269 /// # Examples
270 ///
271 /// ```should_panic
272 /// use std::panic;
273 ///
274 /// panic::set_hook(Box::new(|panic_info| {
275 /// if let Some(location) = panic_info.location() {
276 /// println!("panic occurred at line {}", location.line());
277 /// } else {
278 /// println!("panic occurred but can't get location information...");
279 /// }
280 /// }));
281 ///
282 /// panic!("Normal panic");
283 /// ```
284 #[stable(feature = "panic_hooks", since = "1.10.0")]
285 pub fn line(&self) -> u32 {
286 self.line
287 }
288
289 /// Returns the column from which the panic originated.
290 ///
291 /// # Examples
292 ///
293 /// ```should_panic
294 /// use std::panic;
295 ///
296 /// panic::set_hook(Box::new(|panic_info| {
297 /// if let Some(location) = panic_info.location() {
298 /// println!("panic occurred at column {}", location.column());
299 /// } else {
300 /// println!("panic occurred but can't get location information...");
301 /// }
302 /// }));
303 ///
304 /// panic!("Normal panic");
305 /// ```
306 #[stable(feature = "panic_col", since = "1.25.0")]
307 pub fn column(&self) -> u32 {
308 self.col
309 }
310 }
311
312 #[stable(feature = "panic_hook_display", since = "1.26.0")]
313 impl fmt::Display for Location<'_> {
314 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
315 write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
316 }
317 }
318
319 /// An internal trait used by libstd to pass data from libstd to `panic_unwind`
320 /// and other panic runtimes. Not intended to be stabilized any time soon, do
321 /// not use.
322 #[unstable(feature = "std_internals", issue = "0")]
323 #[doc(hidden)]
324 pub unsafe trait BoxMeUp {
325 /// Take full ownership of the contents.
326 /// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in libcore.
327 ///
328 /// After this method got called, only some dummy default value is left in `self`.
329 /// Calling this method twice, or calling `get` after calling this method, is an error.
330 ///
331 /// The argument is borrowed because the panic runtime (`__rust_start_panic`) only
332 /// gets a borrowed `dyn BoxMeUp`.
333 fn take_box(&mut self) -> *mut (dyn Any + Send);
334
335 /// Just borrow the contents.
336 fn get(&mut self) -> &(dyn Any + Send);
337 }