core/panic/panic_info.rs
1#[cfg(not(feature = "ferrocene_subset"))]
2use crate::fmt::{self, Display};
3use crate::panic::Location;
4use crate::panicking::PanicArguments;
5
6/// A struct providing information about a panic.
7///
8/// A `PanicInfo` structure is passed to the panic handler defined by `#[panic_handler]`.
9///
10/// For the type used by the panic hook mechanism in `std`, see [`std::panic::PanicHookInfo`].
11///
12/// [`std::panic::PanicHookInfo`]: ../../std/panic/struct.PanicHookInfo.html
13#[lang = "panic_info"]
14#[stable(feature = "panic_hooks", since = "1.10.0")]
15#[cfg_attr(not(feature = "ferrocene_certified_runtime"), derive(Debug))]
16#[cfg_attr(feature = "ferrocene_certified_runtime", allow(missing_debug_implementations))]
17pub struct PanicInfo<'a> {
18 message: &'a PanicArguments<'a>,
19 location: &'a Location<'a>,
20 #[cfg_attr(feature = "ferrocene_subset", expect(dead_code))]
21 can_unwind: bool,
22 #[cfg_attr(feature = "ferrocene_subset", expect(dead_code))]
23 force_no_backtrace: bool,
24}
25
26/// A message that was given to the `panic!()` macro.
27///
28/// The [`Display`] implementation of this type will format the message with the arguments
29/// that were given to the `panic!()` macro.
30///
31/// See [`PanicInfo::message`].
32#[stable(feature = "panic_info_message", since = "1.81.0")]
33#[cfg_attr(feature = "ferrocene_certified_runtime", allow(missing_debug_implementations))]
34pub struct PanicMessage<'a> {
35 message: &'a PanicArguments<'a>,
36}
37
38impl<'a> PanicInfo<'a> {
39 #[inline]
40 pub(crate) fn new(
41 // Ferrocene annotation: Replace `fmt::Arguments` by the `PanicArguments` alias.
42 message: &'a PanicArguments<'a>,
43 location: &'a Location<'a>,
44 can_unwind: bool,
45 force_no_backtrace: bool,
46 ) -> Self {
47 PanicInfo { location, message, can_unwind, force_no_backtrace }
48 }
49
50 /// The message that was given to the `panic!` macro.
51 ///
52 /// # Example
53 ///
54 /// The type returned by this method implements `Display`, so it can
55 /// be passed directly to [`write!()`] and similar macros.
56 ///
57 /// [`write!()`]: core::write
58 ///
59 /// ```ignore (no_std)
60 /// #[panic_handler]
61 /// fn panic_handler(panic_info: &PanicInfo<'_>) -> ! {
62 /// write!(DEBUG_OUTPUT, "panicked: {}", panic_info.message());
63 /// loop {}
64 /// }
65 /// ```
66 #[must_use]
67 #[stable(feature = "panic_info_message", since = "1.81.0")]
68 pub fn message(&self) -> PanicMessage<'_> {
69 PanicMessage { message: self.message }
70 }
71
72 /// Returns information about the location from which the panic originated,
73 /// if available.
74 ///
75 /// This method will currently always return [`Some`], but this may change
76 /// in future versions.
77 ///
78 /// # Examples
79 ///
80 /// ```should_panic
81 /// use std::panic;
82 ///
83 /// panic::set_hook(Box::new(|panic_info| {
84 /// if let Some(location) = panic_info.location() {
85 /// println!("panic occurred in file '{}' at line {}",
86 /// location.file(),
87 /// location.line(),
88 /// );
89 /// } else {
90 /// println!("panic occurred but can't get location information...");
91 /// }
92 /// }));
93 ///
94 /// panic!("Normal panic");
95 /// ```
96 #[must_use]
97 #[stable(feature = "panic_hooks", since = "1.10.0")]
98 pub fn location(&self) -> Option<&Location<'_>> {
99 // NOTE: If this is changed to sometimes return None,
100 // deal with that case in std::panicking::default_hook and core::panicking::panic_fmt.
101 Some(&self.location)
102 }
103
104 /// Returns the payload associated with the panic.
105 ///
106 /// On this type, `core::panic::PanicInfo`, this method never returns anything useful.
107 /// It only exists because of compatibility with [`std::panic::PanicHookInfo`],
108 /// which used to be the same type.
109 ///
110 /// See [`std::panic::PanicHookInfo::payload`].
111 ///
112 /// [`std::panic::PanicHookInfo`]: ../../std/panic/struct.PanicHookInfo.html
113 /// [`std::panic::PanicHookInfo::payload`]: ../../std/panic/struct.PanicHookInfo.html#method.payload
114 #[deprecated(since = "1.81.0", note = "this never returns anything useful")]
115 #[stable(feature = "panic_hooks", since = "1.10.0")]
116 #[allow(deprecated, deprecated_in_future)]
117 #[cfg(not(feature = "ferrocene_subset"))]
118 pub fn payload(&self) -> &(dyn crate::any::Any + Send) {
119 struct NoPayload;
120 &NoPayload
121 }
122
123 /// Returns whether the panic handler is allowed to unwind the stack from
124 /// the point where the panic occurred.
125 ///
126 /// This is true for most kinds of panics with the exception of panics
127 /// caused by trying to unwind out of a `Drop` implementation or a function
128 /// whose ABI does not support unwinding.
129 ///
130 /// It is safe for a panic handler to unwind even when this function returns
131 /// false, however this will simply cause the panic handler to be called
132 /// again.
133 #[must_use]
134 #[unstable(feature = "panic_can_unwind", issue = "92988")]
135 #[cfg(not(feature = "ferrocene_subset"))]
136 pub fn can_unwind(&self) -> bool {
137 self.can_unwind
138 }
139
140 #[unstable(
141 feature = "panic_internals",
142 reason = "internal details of the implementation of the `panic!` and related macros",
143 issue = "none"
144 )]
145 #[doc(hidden)]
146 #[inline]
147 #[cfg(not(feature = "ferrocene_subset"))]
148 pub fn force_no_backtrace(&self) -> bool {
149 self.force_no_backtrace
150 }
151}
152
153#[stable(feature = "panic_hook_display", since = "1.26.0")]
154#[cfg(not(feature = "ferrocene_certified_runtime"))]
155impl Display for PanicInfo<'_> {
156 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
157 formatter.write_str("panicked at ")?;
158 self.location.fmt(formatter)?;
159 formatter.write_str(":\n")?;
160 formatter.write_fmt(*self.message)?;
161 Ok(())
162 }
163}
164
165impl<'a> PanicMessage<'a> {
166 /// Gets the formatted message, if it has no arguments to be formatted at runtime.
167 ///
168 /// This can be used to avoid allocations in some cases.
169 ///
170 /// # Guarantees
171 ///
172 /// For `panic!("just a literal")`, this function is guaranteed to
173 /// return `Some("just a literal")`.
174 ///
175 /// For most cases with placeholders, this function will return `None`.
176 ///
177 /// See [`fmt::Arguments::as_str`] for details.
178 #[stable(feature = "panic_info_message", since = "1.81.0")]
179 #[rustc_const_stable(feature = "const_arguments_as_str", since = "1.84.0")]
180 #[must_use]
181 #[inline]
182 pub const fn as_str(&self) -> Option<&'static str> {
183 self.message.as_str()
184 }
185}
186
187#[stable(feature = "panic_info_message", since = "1.81.0")]
188#[cfg(not(feature = "ferrocene_certified_runtime"))]
189impl Display for PanicMessage<'_> {
190 #[inline]
191 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
192 formatter.write_fmt(*self.message)
193 }
194}
195
196#[stable(feature = "panic_info_message", since = "1.81.0")]
197#[cfg(all(not(feature = "ferrocene_subset"), feature = "ferrocene_certified_runtime"))]
198impl Display for PanicMessage<'_> {
199 #[inline]
200 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
201 formatter.write_str(self.message.inner)
202 }
203}
204
205#[stable(feature = "panic_info_message", since = "1.81.0")]
206#[cfg(not(feature = "ferrocene_certified_runtime"))]
207impl fmt::Debug for PanicMessage<'_> {
208 #[inline]
209 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
210 formatter.write_fmt(*self.message)
211 }
212}