1 //! Panic support in the standard library.
3 #![stable(feature = "core_panic_info", since = "1.41.0")]
8 /// A struct providing information about a panic.
10 /// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
13 /// [`set_hook`]: ../../std/panic/fn.set_hook.html
20 /// panic::set_hook(Box::new(|panic_info| {
21 /// if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
22 /// println!("panic occurred: {:?}", s);
24 /// println!("panic occurred");
28 /// panic!("Normal panic");
30 #[lang = "panic_info"]
31 #[stable(feature = "panic_hooks", since = "1.10.0")]
33 pub struct PanicInfo<'a> {
34 payload: &'a (dyn Any + Send),
35 message: Option<&'a fmt::Arguments<'a>>,
36 location: &'a Location<'a>,
39 impl<'a> PanicInfo<'a> {
41 feature = "panic_internals",
42 reason = "internal details of the implementation of the `panic!` and related macros",
47 pub fn internal_constructor(
48 message: Option<&'a fmt::Arguments<'a>>,
49 location: &'a Location<'a>,
52 PanicInfo { location, message, payload: &NoPayload }
56 feature = "panic_internals",
57 reason = "internal details of the implementation of the `panic!` and related macros",
62 pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
66 /// Returns the payload associated with the panic.
68 /// This will commonly, but not always, be a `&'static str` or [`String`].
70 /// [`String`]: ../../std/string/struct.String.html
77 /// panic::set_hook(Box::new(|panic_info| {
78 /// if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
79 /// println!("panic occurred: {:?}", s);
81 /// println!("panic occurred");
85 /// panic!("Normal panic");
87 #[stable(feature = "panic_hooks", since = "1.10.0")]
88 pub fn payload(&self) -> &(dyn Any + Send) {
92 /// If the `panic!` macro from the `core` crate (not from `std`)
93 /// was used with a formatting string and some additional arguments,
94 /// returns that message ready to be used for example with [`fmt::write`]
95 #[unstable(feature = "panic_info_message", issue = "66745")]
96 pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
100 /// Returns information about the location from which the panic originated,
103 /// This method will currently always return [`Some`], but this may change
104 /// in future versions.
111 /// panic::set_hook(Box::new(|panic_info| {
112 /// if let Some(location) = panic_info.location() {
113 /// println!("panic occurred in file '{}' at line {}",
118 /// println!("panic occurred but can't get location information...");
122 /// panic!("Normal panic");
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 std::panicking::begin_panic_fmt.
132 #[stable(feature = "panic_hook_display", since = "1.26.0")]
133 impl fmt::Display for PanicInfo<'_> {
134 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
135 formatter.write_str("panicked at ")?;
136 if let Some(message) = self.message {
137 write!(formatter, "'{}', ", message)?
138 } else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
139 write!(formatter, "'{}', ", payload)?
141 // NOTE: we cannot use downcast_ref::<String>() here
142 // since String is not available in libcore!
143 // The payload is a String when `std::panic!` is called with multiple arguments,
144 // but in that case the message is also available.
146 self.location.fmt(formatter)
150 /// A struct containing information about the location of a panic.
152 /// This structure is created by [`PanicInfo::location()`].
159 /// panic::set_hook(Box::new(|panic_info| {
160 /// if let Some(location) = panic_info.location() {
161 /// println!("panic occurred in file '{}' at line {}", location.file(), location.line());
163 /// println!("panic occurred but can't get location information...");
167 /// panic!("Normal panic");
172 /// Comparisons for equality and ordering are made in file, line, then column priority.
173 /// Files are compared as strings, not `Path`, which could be unexpected.
174 /// See [`Location::file`]'s documentation for more discussion.
175 #[lang = "panic_location"]
176 #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
177 #[stable(feature = "panic_hooks", since = "1.10.0")]
178 pub struct Location<'a> {
184 impl<'a> Location<'a> {
185 /// Returns the source location of the caller of this function. If that function's caller is
186 /// annotated then its call location will be returned, and so on up the stack to the first call
187 /// within a non-tracked function body.
192 /// use core::panic::Location;
194 /// /// Returns the [`Location`] at which it is called.
196 /// fn get_caller_location() -> &'static Location<'static> {
197 /// Location::caller()
200 /// /// Returns a [`Location`] from within this function's definition.
201 /// fn get_just_one_location() -> &'static Location<'static> {
202 /// get_caller_location()
205 /// let fixed_location = get_just_one_location();
206 /// assert_eq!(fixed_location.file(), file!());
207 /// assert_eq!(fixed_location.line(), 14);
208 /// assert_eq!(fixed_location.column(), 5);
210 /// // running the same untracked function in a different location gives us the same result
211 /// let second_fixed_location = get_just_one_location();
212 /// assert_eq!(fixed_location.file(), second_fixed_location.file());
213 /// assert_eq!(fixed_location.line(), second_fixed_location.line());
214 /// assert_eq!(fixed_location.column(), second_fixed_location.column());
216 /// let this_location = get_caller_location();
217 /// assert_eq!(this_location.file(), file!());
218 /// assert_eq!(this_location.line(), 28);
219 /// assert_eq!(this_location.column(), 21);
221 /// // running the tracked function in a different location produces a different value
222 /// let another_location = get_caller_location();
223 /// assert_eq!(this_location.file(), another_location.file());
224 /// assert_ne!(this_location.line(), another_location.line());
225 /// assert_ne!(this_location.column(), another_location.column());
227 #[stable(feature = "track_caller", since = "1.46.0")]
228 #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")]
230 pub const fn caller() -> &'static Location<'static> {
231 crate::intrinsics::caller_location()
235 impl<'a> Location<'a> {
237 feature = "panic_internals",
238 reason = "internal details of the implementation of the `panic!` and related macros",
242 pub const fn internal_constructor(file: &'a str, line: u32, col: u32) -> Self {
243 Location { file, line, col }
246 /// Returns the name of the source file from which the panic originated.
248 /// # `&str`, not `&Path`
250 /// The returned name refers to a source path on the compiling system, but it isn't valid to
251 /// represent this directly as a `&Path`. The compiled code may run on a different system with
252 /// a different `Path` implementation than the system providing the contents and this library
253 /// does not currently have a different "host path" type.
255 /// The most surprising behavior occurs when "the same" file is reachable via multiple paths in
256 /// the module system (usually using the `#[path = "..."]` attribute or similar), which can
257 /// cause what appears to be identical code to return differing values from this function.
259 /// # Cross-compilation
261 /// This value is not suitable for passing to `Path::new` or similar constructors when the host
262 /// platform and target platform differ.
269 /// panic::set_hook(Box::new(|panic_info| {
270 /// if let Some(location) = panic_info.location() {
271 /// println!("panic occurred in file '{}'", location.file());
273 /// println!("panic occurred but can't get location information...");
277 /// panic!("Normal panic");
279 #[stable(feature = "panic_hooks", since = "1.10.0")]
280 pub fn file(&self) -> &str {
284 /// Returns the line number from which the panic originated.
291 /// panic::set_hook(Box::new(|panic_info| {
292 /// if let Some(location) = panic_info.location() {
293 /// println!("panic occurred at line {}", location.line());
295 /// println!("panic occurred but can't get location information...");
299 /// panic!("Normal panic");
301 #[stable(feature = "panic_hooks", since = "1.10.0")]
302 pub fn line(&self) -> u32 {
306 /// Returns the column from which the panic originated.
313 /// panic::set_hook(Box::new(|panic_info| {
314 /// if let Some(location) = panic_info.location() {
315 /// println!("panic occurred at column {}", location.column());
317 /// println!("panic occurred but can't get location information...");
321 /// panic!("Normal panic");
323 #[stable(feature = "panic_col", since = "1.25.0")]
324 pub fn column(&self) -> u32 {
329 #[stable(feature = "panic_hook_display", since = "1.26.0")]
330 impl fmt::Display for Location<'_> {
331 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
332 write!(formatter, "{}:{}:{}", self.file, self.line, self.col)
336 /// An internal trait used by libstd to pass data from libstd to `panic_unwind`
337 /// and other panic runtimes. Not intended to be stabilized any time soon, do
339 #[unstable(feature = "std_internals", issue = "none")]
341 pub unsafe trait BoxMeUp {
342 /// Take full ownership of the contents.
343 /// The return type is actually `Box<dyn Any + Send>`, but we cannot use `Box` in libcore.
345 /// After this method got called, only some dummy default value is left in `self`.
346 /// Calling this method twice, or calling `get` after calling this method, is an error.
348 /// The argument is borrowed because the panic runtime (`__rust_start_panic`) only
349 /// gets a borrowed `dyn BoxMeUp`.
350 fn take_box(&mut self) -> *mut (dyn Any + Send);
352 /// Just borrow the contents.
353 fn get(&mut self) -> &(dyn Any + Send);