1 | use crate::any::Any; |
2 | use crate::fmt; |
3 | use crate::panic::Location; |
4 | |
5 | /// A struct providing information about a panic. |
6 | /// |
7 | /// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`] |
8 | /// function. |
9 | /// |
10 | /// [`set_hook`]: ../../std/panic/fn.set_hook.html |
11 | /// |
12 | /// # Examples |
13 | /// |
14 | /// ```should_panic |
15 | /// use std::panic; |
16 | /// |
17 | /// panic::set_hook(Box::new(|panic_info| { |
18 | /// println!("panic occurred: {panic_info}" ); |
19 | /// })); |
20 | /// |
21 | /// panic!("critical system failure" ); |
22 | /// ``` |
23 | #[lang = "panic_info" ] |
24 | #[stable (feature = "panic_hooks" , since = "1.10.0" )] |
25 | #[derive (Debug)] |
26 | pub struct PanicInfo<'a> { |
27 | payload: &'a (dyn Any + Send), |
28 | message: Option<&'a fmt::Arguments<'a>>, |
29 | location: &'a Location<'a>, |
30 | can_unwind: bool, |
31 | force_no_backtrace: bool, |
32 | } |
33 | |
34 | impl<'a> PanicInfo<'a> { |
35 | #[unstable ( |
36 | feature = "panic_internals" , |
37 | reason = "internal details of the implementation of the `panic!` and related macros" , |
38 | issue = "none" |
39 | )] |
40 | #[doc (hidden)] |
41 | #[inline ] |
42 | pub fn internal_constructor( |
43 | message: Option<&'a fmt::Arguments<'a>>, |
44 | location: &'a Location<'a>, |
45 | can_unwind: bool, |
46 | force_no_backtrace: bool, |
47 | ) -> Self { |
48 | struct NoPayload; |
49 | PanicInfo { location, message, payload: &NoPayload, can_unwind, force_no_backtrace } |
50 | } |
51 | |
52 | #[unstable ( |
53 | feature = "panic_internals" , |
54 | reason = "internal details of the implementation of the `panic!` and related macros" , |
55 | issue = "none" |
56 | )] |
57 | #[doc (hidden)] |
58 | #[inline ] |
59 | pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) { |
60 | self.payload = info; |
61 | } |
62 | |
63 | /// Returns the payload associated with the panic. |
64 | /// |
65 | /// This will commonly, but not always, be a `&'static str` or [`String`]. |
66 | /// |
67 | /// [`String`]: ../../std/string/struct.String.html |
68 | /// |
69 | /// # Examples |
70 | /// |
71 | /// ```should_panic |
72 | /// use std::panic; |
73 | /// |
74 | /// panic::set_hook(Box::new(|panic_info| { |
75 | /// if let Some(s) = panic_info.payload().downcast_ref::<&str>() { |
76 | /// println!("panic occurred: {s:?}" ); |
77 | /// } else { |
78 | /// println!("panic occurred" ); |
79 | /// } |
80 | /// })); |
81 | /// |
82 | /// panic!("Normal panic" ); |
83 | /// ``` |
84 | #[must_use ] |
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 | #[must_use ] |
94 | #[unstable (feature = "panic_info_message" , issue = "66745" )] |
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 | /// # Examples |
106 | /// |
107 | /// ```should_panic |
108 | /// use std::panic; |
109 | /// |
110 | /// panic::set_hook(Box::new(|panic_info| { |
111 | /// if let Some(location) = panic_info.location() { |
112 | /// println!("panic occurred in file '{}' at line {}" , |
113 | /// location.file(), |
114 | /// location.line(), |
115 | /// ); |
116 | /// } else { |
117 | /// println!("panic occurred but can't get location information..." ); |
118 | /// } |
119 | /// })); |
120 | /// |
121 | /// panic!("Normal panic" ); |
122 | /// ``` |
123 | #[must_use ] |
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 core::panicking::panic_fmt. |
128 | Some(&self.location) |
129 | } |
130 | |
131 | /// Returns whether the panic handler is allowed to unwind the stack from |
132 | /// the point where the panic occurred. |
133 | /// |
134 | /// This is true for most kinds of panics with the exception of panics |
135 | /// caused by trying to unwind out of a `Drop` implementation or a function |
136 | /// whose ABI does not support unwinding. |
137 | /// |
138 | /// It is safe for a panic handler to unwind even when this function returns |
139 | /// false, however this will simply cause the panic handler to be called |
140 | /// again. |
141 | #[must_use ] |
142 | #[unstable (feature = "panic_can_unwind" , issue = "92988" )] |
143 | pub fn can_unwind(&self) -> bool { |
144 | self.can_unwind |
145 | } |
146 | |
147 | #[unstable ( |
148 | feature = "panic_internals" , |
149 | reason = "internal details of the implementation of the `panic!` and related macros" , |
150 | issue = "none" |
151 | )] |
152 | #[doc (hidden)] |
153 | #[inline ] |
154 | pub fn force_no_backtrace(&self) -> bool { |
155 | self.force_no_backtrace |
156 | } |
157 | } |
158 | |
159 | #[stable (feature = "panic_hook_display" , since = "1.26.0" )] |
160 | impl fmt::Display for PanicInfo<'_> { |
161 | fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { |
162 | formatter.write_str(data:"panicked at " )?; |
163 | self.location.fmt(formatter)?; |
164 | formatter.write_str(data:":" )?; |
165 | if let Some(message: &Arguments<'_>) = self.message { |
166 | formatter.write_str(data:" \n" )?; |
167 | formatter.write_fmt(*message)?; |
168 | } else if let Some(payload: &&str) = self.payload.downcast_ref::<&'static str>() { |
169 | formatter.write_str(data:" \n" )?; |
170 | formatter.write_str(data:payload)?; |
171 | } |
172 | // NOTE: we cannot use downcast_ref::<String>() here |
173 | // since String is not available in core! |
174 | // The payload is a String when `std::panic!` is called with multiple arguments, |
175 | // but in that case the message is also available. |
176 | Ok(()) |
177 | } |
178 | } |
179 | |