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