Skip to main content

core/panic/
panic_info.rs

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