about summary refs log tree commit diff
path: root/library/core
diff options
context:
space:
mode:
authorMark Rousskov <mark.simulacrum@gmail.com>2024-03-17 22:26:39 -0400
committerMark Rousskov <mark.simulacrum@gmail.com>2024-03-22 09:55:50 -0400
commit00f4daa27673a07bf9ad20f4707d97bc1079450f (patch)
treeeef31d06035d56a9abaabb0d0cd3b972d84a4b0b /library/core
parent0ad927c0c07b65fc0dae37105e09c877c87c296a (diff)
downloadrust-00f4daa27673a07bf9ad20f4707d97bc1079450f.tar.gz
rust-00f4daa27673a07bf9ad20f4707d97bc1079450f.zip
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 binary.
Diffstat (limited to 'library/core')
-rw-r--r--library/core/src/panicking.rs69
1 files changed, 66 insertions, 3 deletions
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index 9e8dac88816..cbb0a7d61db 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -130,17 +130,80 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[track_caller]
 #[rustc_const_unstable(feature = "panic_internals", issue = "none")]
-#[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
+#[lang = "panic"] // used by lints and miri for panics
 pub const fn panic(expr: &'static str) -> ! {
-    // Use Arguments::new_v1 instead of format_args!("{expr}") to potentially
+    // Use Arguments::new_const instead of format_args!("{expr}") to potentially
     // reduce size overhead. The format_args! macro uses str's Display trait to
     // write expr, which calls Formatter::pad, which must accommodate string
     // truncation and padding (even though none is used here). Using
-    // Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
+    // Arguments::new_const may allow the compiler to omit Formatter::pad from the
     // output binary, saving up to a few kilobytes.
     panic_fmt(fmt::Arguments::new_const(&[expr]));
 }
 
+// We generate functions for usage by compiler-generated assertions.
+//
+// Placing these functions in libcore means that all Rust programs can generate a jump into this
+// code rather than expanding to panic("...") above, which adds extra bloat to call sites (for the
+// constant string argument's pointer and length).
+//
+// This is especially important when this code is called often (e.g., with -Coverflow-checks) for
+// reducing binary size impact.
+macro_rules! panic_const {
+    ($($lang:ident = $message:expr,)+) => {
+        #[cfg(not(bootstrap))]
+        pub mod panic_const {
+            use super::*;
+
+            $(
+                /// This is a panic called with a message that's a result of a MIR-produced Assert.
+                //
+                // never inline unless panic_immediate_abort to avoid code
+                // bloat at the call sites as much as possible
+                #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
+                #[cfg_attr(feature = "panic_immediate_abort", inline)]
+                #[track_caller]
+                #[rustc_const_unstable(feature = "panic_internals", issue = "none")]
+                #[lang = stringify!($lang)]
+                pub const fn $lang() -> ! {
+                    // Use Arguments::new_const instead of format_args!("{expr}") to potentially
+                    // reduce size overhead. The format_args! macro uses str's Display trait to
+                    // write expr, which calls Formatter::pad, which must accommodate string
+                    // truncation and padding (even though none is used here). Using
+                    // Arguments::new_const may allow the compiler to omit Formatter::pad from the
+                    // output binary, saving up to a few kilobytes.
+                    panic_fmt(fmt::Arguments::new_const(&[$message]));
+                }
+            )+
+        }
+    }
+}
+
+// Unfortunately this set of strings is replicated here and in a few places in the compiler in
+// slightly different forms. It's not clear if there's a good way to deduplicate without adding
+// special cases to the compiler (e.g., a const generic function wouldn't have a single definition
+// shared across crates, which is exactly what we want here).
+panic_const! {
+    panic_const_add_overflow = "attempt to add with overflow",
+    panic_const_sub_overflow = "attempt to subtract with overflow",
+    panic_const_mul_overflow = "attempt to multiply with overflow",
+    panic_const_div_overflow = "attempt to divide with overflow",
+    panic_const_rem_overflow = "attempt to calculate the remainder with overflow",
+    panic_const_neg_overflow = "attempt to negate with overflow",
+    panic_const_shr_overflow = "attempt to shift right with overflow",
+    panic_const_shl_overflow = "attempt to shift left with overflow",
+    panic_const_div_by_zero = "attempt to divide by zero",
+    panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero",
+    panic_const_coroutine_resumed = "coroutine resumed after completion",
+    panic_const_async_fn_resumed = "`async fn` resumed after completion",
+    panic_const_async_gen_fn_resumed = "`async gen fn` resumed after completion",
+    panic_const_gen_fn_none = "`gen fn` should just keep returning `None` after completion",
+    panic_const_coroutine_resumed_panic = "coroutine resumed after panicking",
+    panic_const_async_fn_resumed_panic = "`async fn` resumed after panicking",
+    panic_const_async_gen_fn_resumed_panic = "`async gen fn` resumed after panicking",
+    panic_const_gen_fn_none_panic = "`gen fn` should just keep returning `None` after panicking",
+}
+
 /// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize on the caller.
 /// If you want `#[track_caller]` for nicer errors, call `panic_nounwind_fmt` directly.
 #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]