]> git.lizzy.rs Git - rust.git/blob - library/core/src/panic.rs
Rollup merge of #82372 - RalfJung:unsafe-cell, r=KodrAus
[rust.git] / library / core / src / 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 #[doc(hidden)]
9 #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
10 #[allow_internal_unstable(core_panic)]
11 #[rustc_diagnostic_item = "core_panic_2015_macro"]
12 #[rustc_macro_transparency = "semitransparent"]
13 pub macro panic_2015 {
14     () => (
15         $crate::panicking::panic("explicit panic")
16     ),
17     ($msg:literal $(,)?) => (
18         $crate::panicking::panic($msg)
19     ),
20     ($msg:expr $(,)?) => (
21         $crate::panicking::panic_str($msg)
22     ),
23     ($fmt:expr, $($arg:tt)+) => (
24         $crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+))
25     ),
26 }
27
28 #[doc(hidden)]
29 #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
30 #[allow_internal_unstable(core_panic)]
31 #[rustc_diagnostic_item = "core_panic_2021_macro"]
32 #[rustc_macro_transparency = "semitransparent"]
33 pub macro panic_2021 {
34     () => (
35         $crate::panicking::panic("explicit panic")
36     ),
37     ($($t:tt)+) => (
38         $crate::panicking::panic_fmt($crate::format_args!($($t)+))
39     ),
40 }
41
42 /// A struct providing information about a panic.
43 ///
44 /// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
45 /// function.
46 ///
47 /// [`set_hook`]: ../../std/panic/fn.set_hook.html
48 ///
49 /// # Examples
50 ///
51 /// ```should_panic
52 /// use std::panic;
53 ///
54 /// panic::set_hook(Box::new(|panic_info| {
55 ///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
56 ///         println!("panic occurred: {:?}", s);
57 ///     } else {
58 ///         println!("panic occurred");
59 ///     }
60 /// }));
61 ///
62 /// panic!("Normal panic");
63 /// ```
64 #[lang = "panic_info"]
65 #[stable(feature = "panic_hooks", since = "1.10.0")]
66 #[derive(Debug)]
67 pub struct PanicInfo<'a> {
68     payload: &'a (dyn Any + Send),
69     message: Option<&'a fmt::Arguments<'a>>,
70     location: &'a Location<'a>,
71 }
72
73 impl<'a> PanicInfo<'a> {
74     #[unstable(
75         feature = "panic_internals",
76         reason = "internal details of the implementation of the `panic!` and related macros",
77         issue = "none"
78     )]
79     #[doc(hidden)]
80     #[inline]
81     pub fn internal_constructor(
82         message: Option<&'a fmt::Arguments<'a>>,
83         location: &'a Location<'a>,
84     ) -> Self {
85         struct NoPayload;
86         PanicInfo { location, message, payload: &NoPayload }
87     }
88
89     #[unstable(
90         feature = "panic_internals",
91         reason = "internal details of the implementation of the `panic!` and related macros",
92         issue = "none"
93     )]
94     #[doc(hidden)]
95     #[inline]
96     pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
97         self.payload = info;
98     }
99
100     /// Returns the payload associated with the panic.
101     ///
102     /// This will commonly, but not always, be a `&'static str` or [`String`].
103     ///
104     /// [`String`]: ../../std/string/struct.String.html
105     ///
106     /// # Examples
107     ///
108     /// ```should_panic
109     /// use std::panic;
110     ///
111     /// panic::set_hook(Box::new(|panic_info| {
112     ///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
113     ///         println!("panic occurred: {:?}", s);
114     ///     } else {
115     ///         println!("panic occurred");
116     ///     }
117     /// }));
118     ///
119     /// panic!("Normal panic");
120     /// ```
121     #[stable(feature = "panic_hooks", since = "1.10.0")]
122     pub fn payload(&self) -> &(dyn Any + Send) {
123         self.payload
124     }
125
126     /// If the `panic!` macro from the `core` crate (not from `std`)
127     /// was used with a formatting string and some additional arguments,
128     /// returns that message ready to be used for example with [`fmt::write`]
129     #[unstable(feature = "panic_info_message", issue = "66745")]
130     pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
131         self.message
132     }
133
134     /// Returns information about the location from which the panic originated,
135     /// if available.
136     ///
137     /// This method will currently always return [`Some`], but this may change
138     /// in future versions.
139     ///
140     /// # Examples
141     ///
142     /// ```should_panic
143     /// use std::panic;
144     ///
145     /// panic::set_hook(Box::new(|panic_info| {
146     ///     if let Some(location) = panic_info.location() {
147     ///         println!("panic occurred in file '{}' at line {}",
148     ///             location.file(),
149     ///             location.line(),
150     ///         );
151     ///     } else {
152     ///         println!("panic occurred but can't get location information...");
153     ///     }
154     /// }));
155     ///
156     /// panic!("Normal panic");
157     /// ```
158     #[stable(feature = "panic_hooks", since = "1.10.0")]
159     pub fn location(&self) -> Option<&Location<'_>> {
160         // NOTE: If this is changed to sometimes return None,
161         // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
162         Some(&self.location)
163     }
164 }
165
166 #[stable(feature = "panic_hook_display", since = "1.26.0")]
167 impl fmt::Display for PanicInfo<'_> {
168     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
169         formatter.write_str("panicked at ")?;
170         if let Some(message) = self.message {
171             write!(formatter, "'{}', ", message)?
172         } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
173             write!(formatter, "'{}', ", payload)?
174         }
175         // NOTE: we cannot use downcast_ref::<String>() here
176         // since String is not available in libcore!
177         // The payload is a String when `std::panic!` is called with multiple arguments,
178         // but in that case the message is also available.
179
180         self.location.fmt(formatter)
181     }
182 }
183
184 /// A struct containing information about the location of a panic.
185 ///
186 /// This structure is created by [`PanicInfo::location()`].
187 ///
188 /// # Examples
189 ///
190 /// ```should_panic
191 /// use std::panic;
192 ///
193 /// panic::set_hook(Box::new(|panic_info| {
194 ///     if let Some(location) = panic_info.location() {
195 ///         println!("panic occurred in file '{}' at line {}", location.file(), location.line());
196 ///     } else {
197 ///         println!("panic occurred but can't get location information...");
198 ///     }
199 /// }));
200 ///
201 /// panic!("Normal panic");
202 /// ```
203 ///
204 /// # Comparisons
205 ///
206 /// Comparisons for equality and ordering are made in file, line, then column priority.
207 /// Files are compared as strings, not `Path`, which could be unexpected.
208 /// See [`Location::file`]'s documentation for more discussion.
209 #[lang = "panic_location"]
210 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
211 #[stable(feature = "panic_hooks", since = "1.10.0")]
212 pub struct Location<'a> {
213     file: &'a str,
214     line: u32,
215     col: u32,
216 }
217
218 impl<'a> Location<'a> {
219     /// Returns the source location of the caller of this function. If that function's caller is
220     /// annotated then its call location will be returned, and so on up the stack to the first call
221     /// within a non-tracked function body.
222     ///
223     /// # Examples
224     ///
225     /// ```
226     /// use std::panic::Location;
227     ///
228     /// /// Returns the [`Location`] at which it is called.
229     /// #[track_caller]
230     /// fn get_caller_location() -> &'static Location<'static> {
231     ///     Location::caller()
232     /// }
233     ///
234     /// /// Returns a [`Location`] from within this function's definition.
235     /// fn get_just_one_location() -> &'static Location<'static> {
236     ///     get_caller_location()
237     /// }
238     ///
239     /// let fixed_location = get_just_one_location();
240     /// assert_eq!(fixed_location.file(), file!());
241     /// assert_eq!(fixed_location.line(), 14);
242     /// assert_eq!(fixed_location.column(), 5);
243     ///
244     /// // running the same untracked function in a different location gives us the same result
245     /// let second_fixed_location = get_just_one_location();
246     /// assert_eq!(fixed_location.file(), second_fixed_location.file());
247     /// assert_eq!(fixed_location.line(), second_fixed_location.line());
248     /// assert_eq!(fixed_location.column(), second_fixed_location.column());
249     ///
250     /// let this_location = get_caller_location();
251     /// assert_eq!(this_location.file(), file!());
252     /// assert_eq!(this_location.line(), 28);
253     /// assert_eq!(this_location.column(), 21);
254     ///
255     /// // running the tracked function in a different location produces a different value
256     /// let another_location = get_caller_location();
257     /// assert_eq!(this_location.file(), another_location.file());
258     /// assert_ne!(this_location.line(), another_location.line());
259     /// assert_ne!(this_location.column(), another_location.column());
260     /// ```
261     #[stable(feature = "track_caller", since = "1.46.0")]
262     #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")]
263     #[track_caller]
264     pub const fn caller() -> &'static Location<'static> {
265         crate::intrinsics::caller_location()
266     }
267 }
268
269 impl<'a> Location<'a> {
270     #![unstable(
271         feature = "panic_internals",
272         reason = "internal details of the implementation of the `panic!` and related macros",
273         issue = "none"
274     )]
275     #[doc(hidden)]
276     pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
277         Location { file, line, col }
278     }
279
280     /// Returns the name of the source file from which the panic originated.
281     ///
282     /// # `&str`, not `&Path`
283     ///
284     /// The returned name refers to a source path on the compiling system, but it isn't valid to
285     /// represent this directly as a `&Path`. The compiled code may run on a different system with
286     /// a different `Path` implementation than the system providing the contents and this library
287     /// does not currently have a different "host path" type.
288     ///
289     /// The most surprising behavior occurs when "the same" file is reachable via multiple paths in
290     /// the module system (usually using the `#[path = "..."]` attribute or similar), which can
291     /// cause what appears to be identical code to return differing values from this function.
292     ///
293     /// # Cross-compilation
294     ///
295     /// This value is not suitable for passing to `Path::new` or similar constructors when the host
296     /// platform and target platform differ.
297     ///
298     /// # Examples
299     ///
300     /// ```should_panic
301     /// use std::panic;
302     ///
303     /// panic::set_hook(Box::new(|panic_info| {
304     ///     if let Some(location) = panic_info.location() {
305     ///         println!("panic occurred in file '{}'", location.file());
306     ///     } else {
307     ///         println!("panic occurred but can't get location information...");
308     ///     }
309     /// }));
310     ///
311     /// panic!("Normal panic");
312     /// ```
313     #[stable(feature = "panic_hooks", since = "1.10.0")]
314     pub fn file(&self) -> &str {
315         self.file
316     }
317
318     /// Returns the line number from which the panic originated.
319     ///
320     /// # Examples
321     ///
322     /// ```should_panic
323     /// use std::panic;
324     ///
325     /// panic::set_hook(Box::new(|panic_info| {
326     ///     if let Some(location) = panic_info.location() {
327     ///         println!("panic occurred at line {}", location.line());
328     ///     } else {
329     ///         println!("panic occurred but can't get location information...");
330     ///     }
331     /// }));
332     ///
333     /// panic!("Normal panic");
334     /// ```
335     #[stable(feature = "panic_hooks", since = "1.10.0")]
336     pub fn line(&self) -> u32 {
337         self.line
338     }
339
340     /// Returns the column from which the panic originated.
341     ///
342     /// # Examples
343     ///
344     /// ```should_panic
345     /// use std::panic;
346     ///
347     /// panic::set_hook(Box::new(|panic_info| {
348     ///     if let Some(location) = panic_info.location() {
349     ///         println!("panic occurred at column {}", location.column());
350     ///     } else {
351     ///         println!("panic occurred but can't get location information...");
352     ///     }
353     /// }));
354     ///
355     /// panic!("Normal panic");
356     /// ```
357     #[stable(feature = "panic_col", since = "1.25.0")]
358     pub fn column(&self) -> u32 {
359         self.col
360     }
361 }
362
363 #[stable(feature = "panic_hook_display", since = "1.26.0")]
364 impl fmt::Display for Location<'_> {
365     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
366         write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
367     }
368 }
369
370 /// An internal trait used by libstd to pass data from libstd to `panic_unwind`
371 /// and other panic runtimes. Not intended to be stabilized any time soon, do
372 /// not use.
373 #[unstable(feature = "std_internals", issue = "none")]
374 #[doc(hidden)]
375 pub unsafe trait BoxMeUp {
376     /// Take full ownership of the contents.
377     /// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in libcore.
378     ///
379     /// After this method got called, only some dummy default value is left in `self`.
380     /// Calling this method twice, or calling `get` after calling this method, is an error.
381     ///
382     /// The argument is borrowed because the panic runtime (`__rust_start_panic`) only
383     /// gets a borrowed `dyn BoxMeUp`.
384     fn take_box(&mut self) -> *mut (dyn Any + Send);
385
386     /// Just borrow the contents.
387     fn get(&mut self) -> &(dyn Any + Send);
388 }