about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-06-18 07:20:26 +0000
committerbors <bors@rust-lang.org>2024-06-18 07:20:26 +0000
commitf873ae029e3ee2bbb8bc70a7ef3f1a06c22b0eac (patch)
tree5b61c7f6253849192a9e518bccfce08a20c7cd56
parent737e42308c6e957575692965d73b17937f936f28 (diff)
parent6c2507cab5711f94305841b43f6623ad80d7448b (diff)
downloadrust-f873ae029e3ee2bbb8bc70a7ef3f1a06c22b0eac.tar.gz
rust-f873ae029e3ee2bbb8bc70a7ef3f1a06c22b0eac.zip
Auto merge of #126330 - m-ou-se:panic-message-type, r=Amanieu
Return opaque type from PanicInfo::message()

This changes the return type of the (unstable) PanicInfo::message() method to an opaque type (that implements Display). This allows for a bit more flexibility in the future.

See https://github.com/rust-lang/rust/issues/66745
-rw-r--r--library/core/src/panic.rs2
-rw-r--r--library/core/src/panic/panic_info.rs75
-rw-r--r--library/std/src/panicking.rs13
3 files changed, 79 insertions, 11 deletions
diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs
index b5a0932221a..56ede02673c 100644
--- a/library/core/src/panic.rs
+++ b/library/core/src/panic.rs
@@ -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};
 
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index 78cf1d2e98e..91953fd656b 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -1,4 +1,4 @@
-use crate::fmt;
+use crate::fmt::{self, Display};
 use crate::panic::Location;
 
 /// A struct providing information about a panic.
@@ -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(
@@ -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,
@@ -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)?;
@@ -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)
+    }
+}
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 2bb5ea28b18..ebd05415695 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -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
             })
         }
@@ -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)
+            }
         }
     }