Skip to content

Commit 702405e

Browse files
committed
Split core's PanicInfo and std's PanicInfo.
1 parent c8170e6 commit 702405e

File tree

4 files changed

+177
-97
lines changed

4 files changed

+177
-97
lines changed

core/src/panic/panic_info.rs

+7-73
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,14 @@
1-
use crate::any::Any;
21
use crate::fmt;
32
use crate::panic::Location;
43

54
/// A struct providing information about a panic.
65
///
7-
/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
8-
/// function.
9-
///
10-
/// [`set_hook`]: ../../std/panic/fn.set_hook.html
11-
///
12-
/// # Examples
13-
///
14-
/// ```should_panic
15-
/// use std::panic;
16-
///
17-
/// panic::set_hook(Box::new(|panic_info| {
18-
/// println!("panic occurred: {panic_info}");
19-
/// }));
20-
///
21-
/// panic!("critical system failure");
22-
/// ```
6+
/// A `PanicInfo` structure is passed to the panic handler defined by `#[panic_handler]`.
237
#[lang = "panic_info"]
248
#[stable(feature = "panic_hooks", since = "1.10.0")]
259
#[derive(Debug)]
2610
pub struct PanicInfo<'a> {
27-
payload: &'a (dyn Any + Send),
28-
message: Option<&'a fmt::Arguments<'a>>,
11+
message: fmt::Arguments<'a>,
2912
location: &'a Location<'a>,
3013
can_unwind: bool,
3114
force_no_backtrace: bool,
@@ -40,59 +23,20 @@ impl<'a> PanicInfo<'a> {
4023
#[doc(hidden)]
4124
#[inline]
4225
pub fn internal_constructor(
43-
message: Option<&'a fmt::Arguments<'a>>,
26+
message: fmt::Arguments<'a>,
4427
location: &'a Location<'a>,
4528
can_unwind: bool,
4629
force_no_backtrace: bool,
4730
) -> Self {
48-
struct NoPayload;
49-
PanicInfo { location, message, payload: &NoPayload, can_unwind, force_no_backtrace }
50-
}
51-
52-
#[unstable(
53-
feature = "panic_internals",
54-
reason = "internal details of the implementation of the `panic!` and related macros",
55-
issue = "none"
56-
)]
57-
#[doc(hidden)]
58-
#[inline]
59-
pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
60-
self.payload = info;
61-
}
62-
63-
/// Returns the payload associated with the panic.
64-
///
65-
/// This will commonly, but not always, be a `&'static str` or [`String`].
66-
///
67-
/// [`String`]: ../../std/string/struct.String.html
68-
///
69-
/// # Examples
70-
///
71-
/// ```should_panic
72-
/// use std::panic;
73-
///
74-
/// panic::set_hook(Box::new(|panic_info| {
75-
/// if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
76-
/// println!("panic occurred: {s:?}");
77-
/// } else {
78-
/// println!("panic occurred");
79-
/// }
80-
/// }));
81-
///
82-
/// panic!("Normal panic");
83-
/// ```
84-
#[must_use]
85-
#[stable(feature = "panic_hooks", since = "1.10.0")]
86-
pub fn payload(&self) -> &(dyn Any + Send) {
87-
self.payload
31+
PanicInfo { location, message, can_unwind, force_no_backtrace }
8832
}
8933

9034
/// If the `panic!` macro from the `core` crate (not from `std`)
9135
/// was used with a formatting string and some additional arguments,
9236
/// returns that message ready to be used for example with [`fmt::write`]
9337
#[must_use]
9438
#[unstable(feature = "panic_info_message", issue = "66745")]
95-
pub fn message(&self) -> Option<&fmt::Arguments<'_>> {
39+
pub fn message(&self) -> fmt::Arguments<'_> {
9640
self.message
9741
}
9842

@@ -161,18 +105,8 @@ impl fmt::Display for PanicInfo<'_> {
161105
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
162106
formatter.write_str("panicked at ")?;
163107
self.location.fmt(formatter)?;
164-
formatter.write_str(":")?;
165-
if let Some(message) = self.message {
166-
formatter.write_str("\n")?;
167-
formatter.write_fmt(*message)?;
168-
} else if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
169-
formatter.write_str("\n")?;
170-
formatter.write_str(payload)?;
171-
}
172-
// NOTE: we cannot use downcast_ref::<String>() here
173-
// since String is not available in core!
174-
// The payload is a String when `std::panic!` is called with multiple arguments,
175-
// but in that case the message is also available.
108+
formatter.write_str(":\n")?;
109+
formatter.write_fmt(self.message)?;
176110
Ok(())
177111
}
178112
}

core/src/panicking.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
6262
}
6363

6464
let pi = PanicInfo::internal_constructor(
65-
Some(&fmt),
65+
fmt,
6666
Location::caller(),
6767
/* can_unwind */ true,
6868
/* force_no_backtrace */ false,
@@ -100,7 +100,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo
100100

101101
// PanicInfo with the `can_unwind` flag set to false forces an abort.
102102
let pi = PanicInfo::internal_constructor(
103-
Some(&fmt),
103+
&fmt,
104104
Location::caller(),
105105
/* can_unwind */ false,
106106
force_no_backtrace,

std/src/panic.rs

+152-1
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,162 @@
44

55
use crate::any::Any;
66
use crate::collections;
7+
use crate::fmt;
78
use crate::panicking;
89
use crate::sync::atomic::{AtomicU8, Ordering};
910
use crate::sync::{Condvar, Mutex, RwLock};
1011
use crate::thread::Result;
1112

13+
/// A struct providing information about a panic.
14+
///
15+
/// `PanicInfo` structure is passed to a panic hook set by the [`set_hook`]
16+
/// function.
17+
///
18+
/// [`set_hook`]: ../../std/panic/fn.set_hook.html
19+
///
20+
/// # Examples
21+
///
22+
/// ```should_panic
23+
/// use std::panic;
24+
///
25+
/// panic::set_hook(Box::new(|panic_info| {
26+
/// println!("panic occurred: {panic_info}");
27+
/// }));
28+
///
29+
/// panic!("critical system failure");
30+
/// ```
31+
#[stable(feature = "panic_hooks", since = "1.10.0")]
32+
#[derive(Debug)]
33+
pub struct PanicInfo<'a> {
34+
payload: &'a (dyn Any + Send),
35+
location: &'a Location<'a>,
36+
can_unwind: bool,
37+
force_no_backtrace: bool,
38+
}
39+
40+
impl<'a> PanicInfo<'a> {
41+
#[unstable(feature = "panic_internals", issue = "none")]
42+
#[doc(hidden)]
43+
#[inline]
44+
pub fn internal_constructor(
45+
location: &'a Location<'a>,
46+
can_unwind: bool,
47+
force_no_backtrace: bool,
48+
) -> Self {
49+
struct NoPayload;
50+
PanicInfo { payload: &NoPayload, location, can_unwind, force_no_backtrace }
51+
}
52+
53+
#[unstable(feature = "panic_internals", issue = "none")]
54+
#[doc(hidden)]
55+
#[inline]
56+
pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) {
57+
self.payload = info;
58+
}
59+
60+
/// Returns the payload associated with the panic.
61+
///
62+
/// This will commonly, but not always, be a `&'static str` or [`String`].
63+
///
64+
/// [`String`]: ../../std/string/struct.String.html
65+
///
66+
/// # Examples
67+
///
68+
/// ```should_panic
69+
/// use std::panic;
70+
///
71+
/// panic::set_hook(Box::new(|panic_info| {
72+
/// if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
73+
/// println!("panic occurred: {s:?}");
74+
/// } else {
75+
/// println!("panic occurred");
76+
/// }
77+
/// }));
78+
///
79+
/// panic!("Normal panic");
80+
/// ```
81+
#[must_use]
82+
#[stable(feature = "panic_hooks", since = "1.10.0")]
83+
pub fn payload(&self) -> &(dyn Any + Send) {
84+
self.payload
85+
}
86+
87+
/// Returns information about the location from which the panic originated,
88+
/// if available.
89+
///
90+
/// This method will currently always return [`Some`], but this may change
91+
/// in future versions.
92+
///
93+
/// # Examples
94+
///
95+
/// ```should_panic
96+
/// use std::panic;
97+
///
98+
/// panic::set_hook(Box::new(|panic_info| {
99+
/// if let Some(location) = panic_info.location() {
100+
/// println!("panic occurred in file '{}' at line {}",
101+
/// location.file(),
102+
/// location.line(),
103+
/// );
104+
/// } else {
105+
/// println!("panic occurred but can't get location information...");
106+
/// }
107+
/// }));
108+
///
109+
/// panic!("Normal panic");
110+
/// ```
111+
#[must_use]
112+
#[stable(feature = "panic_hooks", since = "1.10.0")]
113+
pub fn location(&self) -> Option<&Location<'_>> {
114+
// NOTE: If this is changed to sometimes return None,
115+
// deal with that case in std::panicking::default_hook and core::panicking::panic_fmt.
116+
Some(&self.location)
117+
}
118+
119+
/// Returns whether the panic handler is allowed to unwind the stack from
120+
/// the point where the panic occurred.
121+
///
122+
/// This is true for most kinds of panics with the exception of panics
123+
/// caused by trying to unwind out of a `Drop` implementation or a function
124+
/// whose ABI does not support unwinding.
125+
///
126+
/// It is safe for a panic handler to unwind even when this function returns
127+
/// false, however this will simply cause the panic handler to be called
128+
/// again.
129+
#[must_use]
130+
#[unstable(feature = "panic_can_unwind", issue = "92988")]
131+
pub fn can_unwind(&self) -> bool {
132+
self.can_unwind
133+
}
134+
135+
#[unstable(
136+
feature = "panic_internals",
137+
reason = "internal details of the implementation of the `panic!` and related macros",
138+
issue = "none"
139+
)]
140+
#[doc(hidden)]
141+
#[inline]
142+
pub fn force_no_backtrace(&self) -> bool {
143+
self.force_no_backtrace
144+
}
145+
}
146+
147+
#[stable(feature = "panic_hook_display", since = "1.26.0")]
148+
impl fmt::Display for PanicInfo<'_> {
149+
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
150+
formatter.write_str("panicked at ")?;
151+
self.location.fmt(formatter)?;
152+
if let Some(payload) = self.payload.downcast_ref::<&'static str>() {
153+
formatter.write_str(":\n")?;
154+
formatter.write_str(payload)?;
155+
} else if let Some(payload) = self.payload.downcast_ref::<String>() {
156+
formatter.write_str(":\n")?;
157+
formatter.write_str(payload)?;
158+
}
159+
Ok(())
160+
}
161+
}
162+
12163
#[doc(hidden)]
13164
#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
14165
#[allow_internal_unstable(libstd_sys_internals, const_format_args, panic_internals, rt)]
@@ -43,7 +194,7 @@ pub use crate::panicking::{set_hook, take_hook};
43194
pub use crate::panicking::update_hook;
44195

45196
#[stable(feature = "panic_hooks", since = "1.10.0")]
46-
pub use core::panic::{Location, PanicInfo};
197+
pub use core::panic::Location;
47198

48199
#[stable(feature = "catch_unwind", since = "1.9.0")]
49200
pub use core::panic::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe};

std/src/panicking.rs

+16-21
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
1010
#![deny(unsafe_op_in_unsafe_fn)]
1111

12-
use crate::panic::BacktraceStyle;
13-
use core::panic::{Location, PanicInfo, PanicPayload};
12+
use crate::panic::{BacktraceStyle, PanicInfo};
13+
use core::panic::{Location, PanicPayload};
1414

1515
use crate::any::Any;
1616
use crate::fmt;
@@ -597,7 +597,7 @@ pub fn panicking() -> bool {
597597
/// Entry point of panics from the core crate (`panic_impl` lang item).
598598
#[cfg(not(any(test, doctest)))]
599599
#[panic_handler]
600-
pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
600+
pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! {
601601
struct FormatStringPayload<'a> {
602602
inner: &'a fmt::Arguments<'a>,
603603
string: Option<String>,
@@ -648,22 +648,20 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
648648
}
649649

650650
let loc = info.location().unwrap(); // The current implementation always returns Some
651-
let msg = info.message().unwrap(); // The current implementation always returns Some
651+
let msg = info.message();
652652
crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
653-
// FIXME: can we just pass `info` along rather than taking it apart here, only to have
654-
// `rust_panic_with_hook` construct a new `PanicInfo`?
655-
if let Some(msg) = msg.as_str() {
653+
if let Some(s) = msg.as_str() {
656654
rust_panic_with_hook(
657-
&mut StaticStrPayload(msg),
658-
info.message(),
655+
&mut StaticStrPayload(s),
656+
Some(msg),
659657
loc,
660658
info.can_unwind(),
661659
info.force_no_backtrace(),
662660
);
663661
} else {
664662
rust_panic_with_hook(
665-
&mut FormatStringPayload::new(msg),
666-
info.message(),
663+
&mut FormatStringPayload::new(&msg),
664+
Some(msg),
667665
loc,
668666
info.can_unwind(),
669667
info.force_no_backtrace(),
@@ -740,7 +738,7 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
740738
/// abort or unwind.
741739
fn rust_panic_with_hook(
742740
payload: &mut dyn PanicPayload,
743-
message: Option<&fmt::Arguments<'_>>,
741+
message: Option<fmt::Arguments<'_>>,
744742
location: &Location<'_>,
745743
can_unwind: bool,
746744
force_no_backtrace: bool,
@@ -767,20 +765,17 @@ fn rust_panic_with_hook(
767765
panic_count::MustAbort::AlwaysAbort => {
768766
// Unfortunately, this does not print a backtrace, because creating
769767
// a `Backtrace` will allocate, which we must avoid here.
770-
let panicinfo = PanicInfo::internal_constructor(
771-
message,
772-
location,
773-
can_unwind,
774-
force_no_backtrace,
775-
);
776-
rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n");
768+
if let Some(message) = message {
769+
rtprintpanic!("aborting due to panic at {location}:\n{message}\n");
770+
} else {
771+
rtprintpanic!("aborting due to panic at {location}\n");
772+
}
777773
}
778774
}
779775
crate::sys::abort_internal();
780776
}
781777

782-
let mut info =
783-
PanicInfo::internal_constructor(message, location, can_unwind, force_no_backtrace);
778+
let mut info = PanicInfo::internal_constructor(location, can_unwind, force_no_backtrace);
784779
let hook = HOOK.read().unwrap_or_else(PoisonError::into_inner);
785780
match *hook {
786781
// Some platforms (like wasm) know that printing to stderr won't ever actually

0 commit comments

Comments
 (0)