]> git.lizzy.rs Git - rust.git/blob - src/libcore/panic.rs
Rollup merge of #54746 - llogiq:simplify-unused-lints, r=michaelwoerister
[rust.git] / src / libcore / panic.rs
1 // Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Panic support in the standard library.
12
13 #![unstable(feature = "core_panic_info",
14             reason = "newly available in libcore",
15             issue = "44489")]
16
17 use any::Any;
18 use fmt;
19
20 /// A struct providing information about a panic.
21 ///
22 /// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
23 /// function.
24 ///
25 /// [`set_hook`]: ../../std/panic/fn.set_hook.html
26 ///
27 /// # Examples
28 ///
29 /// ```should_panic
30 /// use std::panic;
31 ///
32 /// panic::set_hook(Box::new(|panic_info| {
33 ///     if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
34 ///         println!("panic occurred: {:?}", s);
35 ///     } else {
36 ///         println!("panic occurred");
37 ///     }
38 /// }));
39 ///
40 /// panic!("Normal panic");
41 /// ```
42 #[lang = "panic_info"]
43 #[stable(feature = "panic_hooks", since = "1.10.0")]
44 #[derive(Debug)]
45 pub struct PanicInfo<'a> {
46     payload: &'a (dyn Any + Send),
47     message: Option<&'a fmt::Arguments<'a>>,
48     location: Location<'a>,
49 }
50
51 impl<'a> PanicInfo<'a> {
52     #![unstable(feature = "panic_internals",
53                 reason = "internal details of the implementation of the `panic!` \
54                           and related macros",
55                 issue = "0")]
56     #[doc(hidden)]
57     #[inline]
58     pub fn internal_constructor(message: Option<&'a fmt::Arguments<'a>>,
59                                 location: Location<'a>)
60                                 -> Self {
61         struct NoPayload;
62         PanicInfo { payload: &NoPayload, location, message }
63     }
64
65     #[doc(hidden)]
66     #[inline]
67     pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
68         self.payload = info;
69     }
70
71     /// Returns the payload associated with the panic.
72     ///
73     /// This will commonly, but not always, be a `&'static str` or [`String`].
74     ///
75     /// [`String`]: ../../std/string/struct.String.html
76     ///
77     /// # Examples
78     ///
79     /// ```should_panic
80     /// use std::panic;
81     ///
82     /// panic::set_hook(Box::new(|panic_info| {
83     ///     println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap());
84     /// }));
85     ///
86     /// panic!("Normal panic");
87     /// ```
88     #[stable(feature = "panic_hooks", since = "1.10.0")]
89     pub fn payload(&self) -> &(dyn Any + Send) {
90         self.payload
91     }
92
93     /// If the `panic!` macro from the `core` crate (not from `std`)
94     /// was used with a formatting string and some additional arguments,
95     /// returns that message ready to be used for example with [`fmt::write`]
96     ///
97     /// [`fmt::write`]: ../fmt/fn.write.html
98     #[unstable(feature = "panic_info_message", issue = "44489")]
99     pub fn message(&self) -> Option<&fmt::Arguments> {
100         self.message
101     }
102
103     /// Returns information about the location from which the panic originated,
104     /// if available.
105     ///
106     /// This method will currently always return [`Some`], but this may change
107     /// in future versions.
108     ///
109     /// [`Some`]: ../../std/option/enum.Option.html#variant.Some
110     ///
111     /// # Examples
112     ///
113     /// ```should_panic
114     /// use std::panic;
115     ///
116     /// panic::set_hook(Box::new(|panic_info| {
117     ///     if let Some(location) = panic_info.location() {
118     ///         println!("panic occurred in file '{}' at line {}", location.file(),
119     ///             location.line());
120     ///     } else {
121     ///         println!("panic occurred but can't get location information...");
122     ///     }
123     /// }));
124     ///
125     /// panic!("Normal panic");
126     /// ```
127     #[stable(feature = "panic_hooks", since = "1.10.0")]
128     pub fn location(&self) -> Option<&Location> {
129         // NOTE: If this is changed to sometimes return None,
130         // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt.
131         Some(&self.location)
132     }
133 }
134
135 #[stable(feature = "panic_hook_display", since = "1.26.0")]
136 impl fmt::Display for PanicInfo<'_> {
137     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
138         formatter.write_str("panicked at ")?;
139         if let Some(message) = self.message {
140             write!(formatter, "'{}', ", message)?
141         } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
142             write!(formatter, "'{}', ", payload)?
143         }
144         // NOTE: we cannot use downcast_ref::<String>() here
145         // since String is not available in libcore!
146         // The payload is a String when `std::panic!` is called with multiple arguments,
147         // but in that case the message is also available.
148
149         self.location.fmt(formatter)
150     }
151 }
152
153 /// A struct containing information about the location of a panic.
154 ///
155 /// This structure is created by the [`location`] method of [`PanicInfo`].
156 ///
157 /// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location
158 /// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html
159 ///
160 /// # Examples
161 ///
162 /// ```should_panic
163 /// use std::panic;
164 ///
165 /// panic::set_hook(Box::new(|panic_info| {
166 ///     if let Some(location) = panic_info.location() {
167 ///         println!("panic occurred in file '{}' at line {}", location.file(), location.line());
168 ///     } else {
169 ///         println!("panic occurred but can't get location information...");
170 ///     }
171 /// }));
172 ///
173 /// panic!("Normal panic");
174 /// ```
175 #[derive(Debug)]
176 #[stable(feature = "panic_hooks", since = "1.10.0")]
177 pub struct Location<'a> {
178     file: &'a str,
179     line: u32,
180     col: u32,
181 }
182
183 impl<'a> Location<'a> {
184     #![unstable(feature = "panic_internals",
185                 reason = "internal details of the implementation of the `panic!` \
186                           and related macros",
187                 issue = "0")]
188     #[doc(hidden)]
189     pub fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
190         Location { file, line, col }
191     }
192
193     /// Returns the name of the source file from which the panic originated.
194     ///
195     /// # Examples
196     ///
197     /// ```should_panic
198     /// use std::panic;
199     ///
200     /// panic::set_hook(Box::new(|panic_info| {
201     ///     if let Some(location) = panic_info.location() {
202     ///         println!("panic occurred in file '{}'", location.file());
203     ///     } else {
204     ///         println!("panic occurred but can't get location information...");
205     ///     }
206     /// }));
207     ///
208     /// panic!("Normal panic");
209     /// ```
210     #[stable(feature = "panic_hooks", since = "1.10.0")]
211     pub fn file(&self) -> &str {
212         self.file
213     }
214
215     /// Returns the line number from which the panic originated.
216     ///
217     /// # Examples
218     ///
219     /// ```should_panic
220     /// use std::panic;
221     ///
222     /// panic::set_hook(Box::new(|panic_info| {
223     ///     if let Some(location) = panic_info.location() {
224     ///         println!("panic occurred at line {}", location.line());
225     ///     } else {
226     ///         println!("panic occurred but can't get location information...");
227     ///     }
228     /// }));
229     ///
230     /// panic!("Normal panic");
231     /// ```
232     #[stable(feature = "panic_hooks", since = "1.10.0")]
233     pub fn line(&self) -> u32 {
234         self.line
235     }
236
237     /// Returns the column from which the panic originated.
238     ///
239     /// # Examples
240     ///
241     /// ```should_panic
242     /// use std::panic;
243     ///
244     /// panic::set_hook(Box::new(|panic_info| {
245     ///     if let Some(location) = panic_info.location() {
246     ///         println!("panic occurred at column {}", location.column());
247     ///     } else {
248     ///         println!("panic occurred but can't get location information...");
249     ///     }
250     /// }));
251     ///
252     /// panic!("Normal panic");
253     /// ```
254     #[stable(feature = "panic_col", since = "1.25.0")]
255     pub fn column(&self) -> u32 {
256         self.col
257     }
258 }
259
260 #[stable(feature = "panic_hook_display", since = "1.26.0")]
261 impl fmt::Display for Location<'_> {
262     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
263         write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
264     }
265 }
266
267 /// An internal trait used by libstd to pass data from libstd to `panic_unwind`
268 /// and other panic runtimes. Not intended to be stabilized any time soon, do
269 /// not use.
270 #[unstable(feature = "std_internals", issue = "0")]
271 #[doc(hidden)]
272 pub unsafe trait BoxMeUp {
273     fn box_me_up(&mut self) -> *mut (dyn Any + Send);
274     fn get(&mut self) -> &(dyn Any + Send);
275 }