Skip to content

Commit f1695e5

Browse files
committed
Auto merge of rust-lang#122671 - Mark-Simulacrum:const-panic-msg, r=Nilstrieb
Codegen const panic messages as function calls This skips emitting extra arguments at every callsite (of which there can be many). For a librustc_driver build with overflow checks enabled, this cuts 0.7MB from the resulting shared library (see [perf]). A sample improvement from nightly: ``` leaq str.0(%rip), %rdi leaq .Lalloc_d6aeb8e2aa19de39a7f0e861c998af13(%rip), %rdx movl $25, %esi callq *_ZN4core9panicking5panic17h17cabb89c5bcc999E@GOTPCREL(%rip) ``` to this PR: ``` leaq .Lalloc_d6aeb8e2aa19de39a7f0e861c998af13(%rip), %rdi callq *_RNvNtNtCsduqIKoij8JB_4core9panicking11panic_const23panic_const_div_by_zero@GOTPCREL(%rip) ``` [perf]: https://perf.rust-lang.org/compare.html?start=a7e4de13c1785819f4d61da41f6704ed69d5f203&end=64fbb4f0b2d621ff46d559d1e9f5ad89a8d7789b&stat=instructions:u
2 parents 8145779 + 280bc7d commit f1695e5

File tree

1 file changed

+64
-1
lines changed

1 file changed

+64
-1
lines changed

core/src/panicking.rs

+64-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo
130130
#[cfg_attr(feature = "panic_immediate_abort", inline)]
131131
#[track_caller]
132132
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
133-
#[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
133+
#[lang = "panic"] // used by lints and miri for panics
134134
pub const fn panic(expr: &'static str) -> ! {
135135
// Use Arguments::new_const instead of format_args!("{expr}") to potentially
136136
// reduce size overhead. The format_args! macro uses str's Display trait to
@@ -141,6 +141,69 @@ pub const fn panic(expr: &'static str) -> ! {
141141
panic_fmt(fmt::Arguments::new_const(&[expr]));
142142
}
143143

144+
// We generate functions for usage by compiler-generated assertions.
145+
//
146+
// Placing these functions in libcore means that all Rust programs can generate a jump into this
147+
// code rather than expanding to panic("...") above, which adds extra bloat to call sites (for the
148+
// constant string argument's pointer and length).
149+
//
150+
// This is especially important when this code is called often (e.g., with -Coverflow-checks) for
151+
// reducing binary size impact.
152+
macro_rules! panic_const {
153+
($($lang:ident = $message:expr,)+) => {
154+
#[cfg(not(bootstrap))]
155+
pub mod panic_const {
156+
use super::*;
157+
158+
$(
159+
/// This is a panic called with a message that's a result of a MIR-produced Assert.
160+
//
161+
// never inline unless panic_immediate_abort to avoid code
162+
// bloat at the call sites as much as possible
163+
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
164+
#[cfg_attr(feature = "panic_immediate_abort", inline)]
165+
#[track_caller]
166+
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
167+
#[lang = stringify!($lang)]
168+
pub const fn $lang() -> ! {
169+
// Use Arguments::new_const instead of format_args!("{expr}") to potentially
170+
// reduce size overhead. The format_args! macro uses str's Display trait to
171+
// write expr, which calls Formatter::pad, which must accommodate string
172+
// truncation and padding (even though none is used here). Using
173+
// Arguments::new_const may allow the compiler to omit Formatter::pad from the
174+
// output binary, saving up to a few kilobytes.
175+
panic_fmt(fmt::Arguments::new_const(&[$message]));
176+
}
177+
)+
178+
}
179+
}
180+
}
181+
182+
// Unfortunately this set of strings is replicated here and in a few places in the compiler in
183+
// slightly different forms. It's not clear if there's a good way to deduplicate without adding
184+
// special cases to the compiler (e.g., a const generic function wouldn't have a single definition
185+
// shared across crates, which is exactly what we want here).
186+
panic_const! {
187+
panic_const_add_overflow = "attempt to add with overflow",
188+
panic_const_sub_overflow = "attempt to subtract with overflow",
189+
panic_const_mul_overflow = "attempt to multiply with overflow",
190+
panic_const_div_overflow = "attempt to divide with overflow",
191+
panic_const_rem_overflow = "attempt to calculate the remainder with overflow",
192+
panic_const_neg_overflow = "attempt to negate with overflow",
193+
panic_const_shr_overflow = "attempt to shift right with overflow",
194+
panic_const_shl_overflow = "attempt to shift left with overflow",
195+
panic_const_div_by_zero = "attempt to divide by zero",
196+
panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero",
197+
panic_const_coroutine_resumed = "coroutine resumed after completion",
198+
panic_const_async_fn_resumed = "`async fn` resumed after completion",
199+
panic_const_async_gen_fn_resumed = "`async gen fn` resumed after completion",
200+
panic_const_gen_fn_none = "`gen fn` should just keep returning `None` after completion",
201+
panic_const_coroutine_resumed_panic = "coroutine resumed after panicking",
202+
panic_const_async_fn_resumed_panic = "`async fn` resumed after panicking",
203+
panic_const_async_gen_fn_resumed_panic = "`async gen fn` resumed after panicking",
204+
panic_const_gen_fn_none_panic = "`gen fn` should just keep returning `None` after panicking",
205+
}
206+
144207
/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize on the caller.
145208
/// If you want `#[track_caller]` for nicer errors, call `panic_nounwind_fmt` directly.
146209
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]

0 commit comments

Comments
 (0)