1use crate::any::Any;
2use crate::fmt;
3use 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)]
26pub 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
34impl<'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")]
160impl 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 if let Some(message: &Arguments<'_>) = self.message {
165 formatter.write_str(data:":\n")?;
166 formatter.write_fmt(*message)?;
167 } else if let Some(payload: &&str) = self.payload.downcast_ref::<&'static str>() {
168 formatter.write_str(data:":\n")?;
169 formatter.write_str(data:payload)?;
170 }
171 // NOTE: we cannot use downcast_ref::<String>() here
172 // since String is not available in core!
173 // The payload is a String when `std::panic!` is called with multiple arguments,
174 // but in that case the message is also available.
175 Ok(())
176 }
177}
178