Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return opaque type from PanicInfo::message() #126330

Merged
merged 1 commit into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions library/core/src/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use crate::any::Any;
pub use self::location::Location;
#[stable(feature = "panic_hooks", since = "1.10.0")]
pub use self::panic_info::PanicInfo;
#[unstable(feature = "panic_info_message", issue = "66745")]
pub use self::panic_info::PanicMessage;
#[stable(feature = "catch_unwind", since = "1.9.0")]
pub use self::unwind_safe::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe};

Expand Down
75 changes: 69 additions & 6 deletions library/core/src/panic/panic_info.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::fmt;
use crate::fmt::{self, Display};
use crate::panic::Location;

/// A struct providing information about a panic.
Expand All @@ -18,6 +18,17 @@ pub struct PanicInfo<'a> {
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`].
#[unstable(feature = "panic_info_message", issue = "66745")]
pub struct PanicMessage<'a> {
message: fmt::Arguments<'a>,
}

impl<'a> PanicInfo<'a> {
#[inline]
pub(crate) fn new(
Expand All @@ -29,12 +40,26 @@ impl<'a> PanicInfo<'a> {
PanicInfo { location, message, can_unwind, force_no_backtrace }
}

/// The message that was given to the `panic!` macro,
/// ready to be formatted with e.g. [`fmt::write`].
/// 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]
#[unstable(feature = "panic_info_message", issue = "66745")]
pub fn message(&self) -> fmt::Arguments<'_> {
self.message
pub fn message(&self) -> PanicMessage<'_> {
PanicMessage { message: self.message }
}

/// Returns information about the location from which the panic originated,
Expand Down Expand Up @@ -116,7 +141,7 @@ impl<'a> PanicInfo<'a> {
}

#[stable(feature = "panic_hook_display", since = "1.26.0")]
impl fmt::Display for PanicInfo<'_> {
impl Display for PanicInfo<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("panicked at ")?;
self.location.fmt(formatter)?;
Expand All @@ -125,3 +150,41 @@ impl fmt::Display for PanicInfo<'_> {
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.
#[unstable(feature = "panic_info_message", issue = "66745")]
#[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()
}
}

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

#[unstable(feature = "panic_info_message", issue = "66745")]
impl fmt::Debug for PanicMessage<'_> {
#[inline]
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_fmt(self.message)
}
}
13 changes: 8 additions & 5 deletions library/std/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,19 +593,18 @@ pub fn panicking() -> bool {
#[panic_handler]
pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! {
struct FormatStringPayload<'a> {
inner: &'a fmt::Arguments<'a>,
inner: &'a core::panic::PanicMessage<'a>,
string: Option<String>,
}

impl FormatStringPayload<'_> {
fn fill(&mut self) -> &mut String {
use crate::fmt::Write;

let inner = self.inner;
// Lazily, the first time this gets called, run the actual string formatting.
self.string.get_or_insert_with(|| {
let mut s = String::new();
let _err = s.write_fmt(*inner);
let mut fmt = fmt::Formatter::new(&mut s);
let _err = fmt::Display::fmt(&inner, &mut fmt);
s
})
}
Expand All @@ -627,7 +626,11 @@ pub fn begin_panic_handler(info: &core::panic::PanicInfo<'_>) -> ! {

impl fmt::Display for FormatStringPayload<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(s) = &self.string { f.write_str(s) } else { f.write_fmt(*self.inner) }
if let Some(s) = &self.string {
f.write_str(s)
} else {
fmt::Display::fmt(&self.inner, f)
}
}
}

Expand Down
Loading