Skip to content

Commit 7410960

Browse files
author
Lukas Markeffsky
committed
format panic message only once
1 parent f12a7fa commit 7410960

File tree

3 files changed

+37
-13
lines changed

3 files changed

+37
-13
lines changed

library/std/src/panicking.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -249,20 +249,20 @@ fn default_hook(info: &PanicInfo<'_>) {
249249
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
250250

251251
let write = |err: &mut dyn crate::io::Write| {
252-
// Use the panic message directly if available, otherwise take it from
253-
// the payload.
254-
if let Some(msg) = info.message() {
255-
let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
252+
// The std panic runtime always sets a `&str` or `String` payload for `panic!` and related
253+
// macros with the formatted message.
254+
// We try using the payload first to avoid formatting the message twice.
255+
let msg: &dyn fmt::Display = if let Some(s) = info.payload().downcast_ref::<&'static str>()
256+
{
257+
s
258+
} else if let Some(s) = info.payload().downcast_ref::<String>() {
259+
s
260+
} else if let Some(msg) = info.message() {
261+
msg
256262
} else {
257-
let msg = if let Some(s) = info.payload().downcast_ref::<&'static str>() {
258-
*s
259-
} else if let Some(s) = info.payload().downcast_ref::<String>() {
260-
&s[..]
261-
} else {
262-
"Box<dyn Any>"
263-
};
264-
let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
265-
}
263+
&"Box<dyn Any>"
264+
};
265+
let _ = writeln!(err, "thread '{name}' panicked at '{msg}', {location}");
266266

267267
static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
268268

tests/ui/panics/fmt-only-once.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// run-fail
2+
// check-run-results
3+
// exec-env:RUST_BACKTRACE=0
4+
5+
// Test that we format the panic message only once.
6+
// Regression test for https://github.com/rust-lang/rust/issues/110717
7+
8+
use std::fmt;
9+
10+
struct PrintOnFmt;
11+
12+
impl fmt::Display for PrintOnFmt {
13+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
14+
eprintln!("fmt");
15+
f.write_str("PrintOnFmt")
16+
}
17+
}
18+
19+
fn main() {
20+
panic!("{}", PrintOnFmt)
21+
}
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fmt
2+
thread 'main' panicked at 'PrintOnFmt', $DIR/fmt-only-once.rs:20:5
3+
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

0 commit comments

Comments
 (0)