about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJonas Schievink <jonasschievink@gmail.com>2020-10-24 22:39:53 +0200
committerGitHub <noreply@github.com>2020-10-24 22:39:53 +0200
commite3808edeeea28c137129c0c5bf70c24562e794f5 (patch)
treec58e4147d059534a0c5151944ff6da1ff3e9b8f6
parente12e97223f9f0bb0f2806334029aec1d9790f074 (diff)
parent9890217c0eedcbe4742e412ea59e851ecd500bf5 (diff)
downloadrust-e3808edeeea28c137129c0c5bf70c24562e794f5.tar.gz
rust-e3808edeeea28c137129c0c5bf70c24562e794f5.zip
Rollup merge of #78119 - fusion-engineering-forks:panic-use-as-str, r=Amanieu
Throw core::panic!("message") as &str instead of String.

This makes `core::panic!("message")` consistent with `std::panic!("message")`, which throws a `&str` and not a `String`.

This also makes any other panics from `core::panicking::panic` result in a `&str` rather than a `String`, which includes compiler-generated panics such as the panics generated for `mem::zeroed()`.

---

Demonstration:

```rust
use std::panic;
use std::any::Any;

fn main() {
    panic::set_hook(Box::new(|panic_info| check(panic_info.payload())));

    check(&*panic::catch_unwind(|| core::panic!("core")).unwrap_err());
    check(&*panic::catch_unwind(|| std::panic!("std")).unwrap_err());
}

fn check(msg: &(dyn Any + Send)) {
    if let Some(s) = msg.downcast_ref::<String>() {
        println!("Got a String: {:?}", s);
    } else if let Some(s) = msg.downcast_ref::<&str>() {
        println!("Got a &str: {:?}", s);
    }
}
```

Before:
```
Got a String: "core"
Got a String: "core"
Got a &str: "std"
Got a &str: "std"
```

After:
```
Got a &str: "core"
Got a &str: "core"
Got a &str: "std"
Got a &str: "std"
```
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/panicking.rs18
-rw-r--r--src/test/ui/intrinsics/panic-uninitialized-zeroed.rs4
3 files changed, 20 insertions, 3 deletions
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 30e7a7f3c3b..3da0ebdd498 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -259,6 +259,7 @@
 #![feature(exhaustive_patterns)]
 #![feature(extend_one)]
 #![feature(external_doc)]
+#![feature(fmt_as_str)]
 #![feature(fn_traits)]
 #![feature(format_args_nl)]
 #![feature(gen_future)]
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 8dceb12de87..221ae809e23 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -478,10 +478,26 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
         }
     }
 
+    struct StrPanicPayload(&'static str);
+
+    unsafe impl BoxMeUp for StrPanicPayload {
+        fn take_box(&mut self) -> *mut (dyn Any + Send) {
+            Box::into_raw(Box::new(self.0))
+        }
+
+        fn get(&mut self) -> &(dyn Any + Send) {
+            &self.0
+        }
+    }
+
     let loc = info.location().unwrap(); // The current implementation always returns Some
     let msg = info.message().unwrap(); // The current implementation always returns Some
     crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
-        rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+        if let Some(msg) = msg.as_str() {
+            rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc);
+        } else {
+            rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+        }
     })
 }
 
diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
index 24474cabf1e..4a91198ab9f 100644
--- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
+++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs
@@ -53,8 +53,8 @@ enum LR_NonZero {
 fn test_panic_msg<T>(op: impl (FnOnce() -> T) + panic::UnwindSafe, msg: &str) {
     let err = panic::catch_unwind(op).err();
     assert_eq!(
-        err.as_ref().and_then(|a| a.downcast_ref::<String>()).map(|s| &**s),
-        Some(msg)
+        err.as_ref().and_then(|a| a.downcast_ref::<&str>()),
+        Some(&msg)
     );
 }