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}