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