1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
use crate::fmt::{self, Display};
use crate::panic::Location;

/// A struct providing information about a panic.
///
/// A `PanicInfo` structure is passed to the panic handler defined by `#[panic_handler]`.
///
/// For the type used by the panic hook mechanism in `std`, see [`std::panic::PanicHookInfo`].
///
/// [`std::panic::PanicHookInfo`]: ../../std/panic/struct.PanicHookInfo.html
#[lang = "panic_info"]
#[stable(feature = "panic_hooks", since = "1.10.0")]
#[derive(Debug)]
pub struct PanicInfo<'a> {
    message: fmt::Arguments<'a>,
    location: &'a Location<'a>,
    can_unwind: bool,
    force_no_backtrace: bool,
}

/// A message that was given to the `panic!()` macro.
///
/// The [`Display`] implementation of this type will format the message with the arguments
/// that were given to the `panic!()` macro.
///
/// See [`PanicInfo::message`].
#[stable(feature = "panic_info_message", since = "CURRENT_RUSTC_VERSION")]
pub struct PanicMessage<'a> {
    message: fmt::Arguments<'a>,
}

impl<'a> PanicInfo<'a> {
    #[inline]
    pub(crate) fn new(
        message: fmt::Arguments<'a>,
        location: &'a Location<'a>,
        can_unwind: bool,
        force_no_backtrace: bool,
    ) -> Self {
        PanicInfo { location, message, can_unwind, force_no_backtrace }
    }

    /// The message that was given to the `panic!` macro.
    ///
    /// # Example
    ///
    /// The type returned by this method implements `Display`, so it can
    /// be passed directly to [`write!()`] and similar macros.
    ///
    /// [`write!()`]: core::write
    ///
    /// ```ignore (no_std)
    /// #[panic_handler]
    /// fn panic_handler(panic_info: &PanicInfo<'_>) -> ! {
    ///     write!(DEBUG_OUTPUT, "panicked: {}", panic_info.message());
    ///     loop {}
    /// }
    /// ```
    #[must_use]
    #[stable(feature = "panic_info_message", since = "CURRENT_RUSTC_VERSION")]
    pub fn message(&self) -> PanicMessage<'_> {
        PanicMessage { message: self.message }
    }

    /// Returns information about the location from which the panic originated,
    /// if available.
    ///
    /// This method will currently always return [`Some`], but this may change
    /// in future versions.
    ///
    /// # Examples
    ///
    /// ```should_panic
    /// use std::panic;
    ///
    /// panic::set_hook(Box::new(|panic_info| {
    ///     if let Some(location) = panic_info.location() {
    ///         println!("panic occurred in file '{}' at line {}",
    ///             location.file(),
    ///             location.line(),
    ///         );
    ///     } else {
    ///         println!("panic occurred but can't get location information...");
    ///     }
    /// }));
    ///
    /// panic!("Normal panic");
    /// ```
    #[must_use]
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    pub fn location(&self) -> Option<&Location<'_>> {
        // NOTE: If this is changed to sometimes return None,
        // deal with that case in std::panicking::default_hook and core::panicking::panic_fmt.
        Some(&self.location)
    }

    /// Returns the payload associated with the panic.
    ///
    /// On this type, `core::panic::PanicInfo`, this method never returns anything useful.
    /// It only exists because of compatibility with [`std::panic::PanicHookInfo`],
    /// which used to be the same type.
    ///
    /// See [`std::panic::PanicHookInfo::payload`].
    ///
    /// [`std::panic::PanicHookInfo`]: ../../std/panic/struct.PanicHookInfo.html
    /// [`std::panic::PanicHookInfo::payload`]: ../../std/panic/struct.PanicHookInfo.html#method.payload
    #[deprecated(since = "1.81.0", note = "this never returns anything useful")]
    #[stable(feature = "panic_hooks", since = "1.10.0")]
    #[allow(deprecated, deprecated_in_future)]
    pub fn payload(&self) -> &(dyn crate::any::Any + Send) {
        struct NoPayload;
        &NoPayload
    }

    /// Returns whether the panic handler is allowed to unwind the stack from
    /// the point where the panic occurred.
    ///
    /// This is true for most kinds of panics with the exception of panics
    /// caused by trying to unwind out of a `Drop` implementation or a function
    /// whose ABI does not support unwinding.
    ///
    /// It is safe for a panic handler to unwind even when this function returns
    /// false, however this will simply cause the panic handler to be called
    /// again.
    #[must_use]
    #[unstable(feature = "panic_can_unwind", issue = "92988")]
    pub fn can_unwind(&self) -> bool {
        self.can_unwind
    }

    #[unstable(
        feature = "panic_internals",
        reason = "internal details of the implementation of the `panic!` and related macros",
        issue = "none"
    )]
    #[doc(hidden)]
    #[inline]
    pub fn force_no_backtrace(&self) -> bool {
        self.force_no_backtrace
    }
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl Display for PanicInfo<'_> {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str("panicked at ")?;
        self.location.fmt(formatter)?;
        formatter.write_str(":\n")?;
        formatter.write_fmt(self.message)?;
        Ok(())
    }
}

impl<'a> PanicMessage<'a> {
    /// Get the formatted message, if it has no arguments to be formatted at runtime.
    ///
    /// This can be used to avoid allocations in some cases.
    ///
    /// # Guarantees
    ///
    /// For `panic!("just a literal")`, this function is guaranteed to
    /// return `Some("just a literal")`.
    ///
    /// For most cases with placeholders, this function will return `None`.
    ///
    /// See [`fmt::Arguments::as_str`] for details.
    #[stable(feature = "panic_info_message", since = "CURRENT_RUSTC_VERSION")]
    #[rustc_const_unstable(feature = "const_arguments_as_str", issue = "103900")]
    #[must_use]
    #[inline]
    pub const fn as_str(&self) -> Option<&'static str> {
        self.message.as_str()
    }
}

#[stable(feature = "panic_info_message", since = "CURRENT_RUSTC_VERSION")]
impl Display for PanicMessage<'_> {
    #[inline]
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_fmt(self.message)
    }
}

#[stable(feature = "panic_info_message", since = "CURRENT_RUSTC_VERSION")]
impl fmt::Debug for PanicMessage<'_> {
    #[inline]
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_fmt(self.message)
    }
}