Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 216574a

Browse files
committed
Auto merge of rust-lang#128068 - goldsteinn:goldsteinn/panic-func-wrappers, r=<try>
panic: Use local functions in `panic!` whenever possible This is basically extending the idea implemented in `panic_2021!`. By creating a cold/noinline function that wraps the setup for the call to the internal panic function moves more of the code-size cost of `panic!` to the cold path. For example: https://godbolt.org/z/T1ndrcq4d
2 parents 004e155 + b8d3c62 commit 216574a

26 files changed

+218
-111
lines changed

library/core/src/panic.rs

Lines changed: 87 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,50 @@ pub use self::unwind_safe::{AssertUnwindSafe, RefUnwindSafe, UnwindSafe};
1919

2020
#[doc(hidden)]
2121
#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
22-
#[allow_internal_unstable(panic_internals, const_format_args)]
22+
#[allow_internal_unstable(
23+
panic_internals,
24+
core_intrinsics,
25+
const_dispatch,
26+
const_eval_select,
27+
const_format_args,
28+
rustc_attrs
29+
)]
2330
#[rustc_diagnostic_item = "core_panic_2015_macro"]
2431
#[rustc_macro_transparency = "semitransparent"]
2532
pub macro panic_2015 {
26-
() => (
27-
$crate::panicking::panic("explicit panic")
28-
),
29-
($msg:literal $(,)?) => (
30-
$crate::panicking::panic($msg)
31-
),
33+
// For all cases where it is possible, wrap the actual call to the
34+
// internal panic implementation function with a local no-inline
35+
// cold function. This moves the codegen for setting up the
36+
// arguments to the panic implementation function to the
37+
// presumably cold panic path.
38+
() => ({
39+
$crate::panicking::panic_cold_explicit();
40+
}),
41+
// Special-case for string literal.
42+
($msg:literal $(,)?) => ({
43+
#[cold]
44+
#[track_caller]
45+
#[inline(never)]
46+
const fn panic_cold_literal() -> ! {
47+
$crate::panicking::panic($msg);
48+
}
49+
panic_cold_literal();
50+
}),
3251
// Use `panic_str_2015` instead of `panic_display::<&str>` for non_fmt_panic lint.
3352
($msg:expr $(,)?) => ({
3453
$crate::panicking::panic_str_2015($msg);
3554
}),
3655
// Special-case the single-argument case for const_panic.
3756
("{}", $arg:expr $(,)?) => ({
38-
$crate::panicking::panic_display(&$arg);
57+
#[cold]
58+
#[track_caller]
59+
#[inline(never)]
60+
#[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval
61+
#[rustc_do_not_const_check] // hooked by const-eval
62+
const fn panic_cold_display<T: $crate::fmt::Display>(arg: &T) -> ! {
63+
$crate::panicking::panic_display(arg)
64+
}
65+
panic_cold_display(&$arg);
3966
}),
4067
($fmt:expr, $($arg:tt)+) => ({
4168
// Semicolon to prevent temporaries inside the formatting machinery from
@@ -44,27 +71,6 @@ pub macro panic_2015 {
4471
}),
4572
}
4673

47-
#[doc(hidden)]
48-
#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
49-
#[allow_internal_unstable(panic_internals, const_format_args)]
50-
#[rustc_diagnostic_item = "core_panic_2021_macro"]
51-
#[rustc_macro_transparency = "semitransparent"]
52-
#[cfg(feature = "panic_immediate_abort")]
53-
pub macro panic_2021 {
54-
() => (
55-
$crate::panicking::panic("explicit panic")
56-
),
57-
// Special-case the single-argument case for const_panic.
58-
("{}", $arg:expr $(,)?) => ({
59-
$crate::panicking::panic_display(&$arg);
60-
}),
61-
($($t:tt)+) => ({
62-
// Semicolon to prevent temporaries inside the formatting machinery from
63-
// being considered alive in the caller after the panic_fmt call.
64-
$crate::panicking::panic_fmt($crate::const_format_args!($($t)+));
65-
}),
66-
}
67-
6874
#[doc(hidden)]
6975
#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
7076
#[allow_internal_unstable(
@@ -77,18 +83,16 @@ pub macro panic_2021 {
7783
)]
7884
#[rustc_diagnostic_item = "core_panic_2021_macro"]
7985
#[rustc_macro_transparency = "semitransparent"]
80-
#[cfg(not(feature = "panic_immediate_abort"))]
8186
pub macro panic_2021 {
87+
// For all cases where it is possible, wrap the actual call to the
88+
// internal panic implementation function with a local no-inline
89+
// cold function. This moves the codegen for setting up the
90+
// arguments to the panic implementation function to the
91+
// presumably cold panic path.
92+
// It would be nice to handle literals here, but there are
93+
// some issues handling embedded format arguments.
8294
() => ({
83-
// Create a function so that the argument for `track_caller`
84-
// can be moved inside if possible.
85-
#[cold]
86-
#[track_caller]
87-
#[inline(never)]
88-
const fn panic_cold_explicit() -> ! {
89-
$crate::panicking::panic_explicit()
90-
}
91-
panic_cold_explicit();
95+
$crate::panicking::panic_cold_explicit();
9296
}),
9397
// Special-case the single-argument case for const_panic.
9498
("{}", $arg:expr $(,)?) => ({
@@ -111,13 +115,34 @@ pub macro panic_2021 {
111115

112116
#[doc(hidden)]
113117
#[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")]
114-
#[allow_internal_unstable(panic_internals)]
118+
#[allow_internal_unstable(
119+
panic_internals,
120+
core_intrinsics,
121+
const_dispatch,
122+
const_eval_select,
123+
const_format_args,
124+
rustc_attrs
125+
)]
115126
#[rustc_diagnostic_item = "unreachable_2015_macro"]
116127
#[rustc_macro_transparency = "semitransparent"]
117128
pub macro unreachable_2015 {
129+
// For all cases where it is possible, wrap the actual call to the
130+
// internal panic implementation function with a local no-inline
131+
// cold function. This moves the codegen for setting up the
132+
// arguments to the panic implementation function to the
133+
// presumably cold panic path.
118134
() => (
119-
$crate::panicking::panic("internal error: entered unreachable code")
135+
$crate::panicking::unreachable_cold_explicit()
120136
),
137+
($msg:literal $(,)?) => ({
138+
#[cold]
139+
#[track_caller]
140+
#[inline(never)]
141+
const fn unreachable_cold_literal() -> ! {
142+
$crate::panicking::unreachable_display(&$msg);
143+
}
144+
unreachable_cold_literal();
145+
}),
121146
// Use of `unreachable_display` for non_fmt_panic lint.
122147
// NOTE: the message ("internal error ...") is embedded directly in unreachable_display
123148
($msg:expr $(,)?) => ({
@@ -130,12 +155,31 @@ pub macro unreachable_2015 {
130155

131156
#[doc(hidden)]
132157
#[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")]
133-
#[allow_internal_unstable(panic_internals)]
158+
#[allow_internal_unstable(
159+
panic_internals,
160+
core_intrinsics,
161+
const_dispatch,
162+
const_eval_select,
163+
const_format_args,
164+
rustc_attrs
165+
)]
134166
#[rustc_macro_transparency = "semitransparent"]
135167
pub macro unreachable_2021 {
136168
() => (
137-
$crate::panicking::panic("internal error: entered unreachable code")
169+
$crate::panicking::unreachable_cold_explicit()
138170
),
171+
// Special-case the single-argument case for const_panic.
172+
("{}", $arg:expr $(,)?) => ({
173+
#[cold]
174+
#[track_caller]
175+
#[inline(never)]
176+
#[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval
177+
#[rustc_do_not_const_check] // hooked by const-eval
178+
const fn unreachable_cold_display<T: $crate::fmt::Display>(arg: &T) -> ! {
179+
$crate::panicking::unreachable_display(arg)
180+
}
181+
unreachable_cold_display(&$arg);
182+
}),
139183
($($t:tt)+) => (
140184
$crate::panic!("internal error: entered unreachable code: {}", $crate::format_args!($($t)+))
141185
),

library/core/src/panicking.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,12 @@ pub const fn panic_explicit() -> ! {
239239

240240
#[inline]
241241
#[track_caller]
242+
#[rustc_do_not_const_check] // hooked by const-eval
243+
// enforce a &&str argument in const-check and hook this by const-eval
244+
#[rustc_const_panic_str]
245+
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
242246
#[rustc_diagnostic_item = "unreachable_display"] // needed for `non-fmt-panics` lint
243-
pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
247+
pub const fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
244248
panic_fmt(format_args!("internal error: entered unreachable code: {}", *x));
245249
}
246250

@@ -254,6 +258,22 @@ pub const fn panic_str_2015(expr: &str) -> ! {
254258
panic_display(&expr);
255259
}
256260

261+
#[cold]
262+
#[track_caller]
263+
#[inline(never)]
264+
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
265+
pub const fn panic_cold_explicit() -> ! {
266+
panic("explicit panic");
267+
}
268+
269+
#[cold]
270+
#[track_caller]
271+
#[inline(never)]
272+
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
273+
pub const fn unreachable_cold_explicit() -> ! {
274+
panic("internal error: entered unreachable code");
275+
}
276+
257277
#[inline]
258278
#[track_caller]
259279
#[rustc_do_not_const_check] // hooked by const-eval

library/std/src/panic.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,19 +212,49 @@ impl fmt::Display for PanicHookInfo<'_> {
212212

213213
#[doc(hidden)]
214214
#[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")]
215-
#[allow_internal_unstable(libstd_sys_internals, const_format_args, panic_internals, rt)]
215+
#[allow_internal_unstable(
216+
libstd_sys_internals,
217+
const_format_args,
218+
panic_internals,
219+
rt,
220+
const_dispatch,
221+
const_eval_select,
222+
rustc_attrs
223+
)]
216224
#[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")]
217225
#[rustc_macro_transparency = "semitransparent"]
218226
pub macro panic_2015 {
227+
// For all cases where it is possible, wrap the actual call to the
228+
// internal panic implementation function with a local no-inline
229+
// cold function. This moves the codegen for setting up the
230+
// arguments to the panic implementation function to the
231+
// presumably cold panic path.
232+
// It would be nice to handle literals here specially with a
233+
// wrapper function, but unfortunately it results in unclear error
234+
// messages when using panic(<non-str>).
219235
() => ({
220-
$crate::rt::begin_panic("explicit panic")
236+
#[cold]
237+
#[track_caller]
238+
#[inline(never)]
239+
const fn panic_cold_explicit() -> ! {
240+
$crate::rt::begin_panic("explicit panic");
241+
}
242+
panic_cold_explicit();
221243
}),
222244
($msg:expr $(,)?) => ({
223245
$crate::rt::begin_panic($msg);
224246
}),
225247
// Special-case the single-argument case for const_panic.
226248
("{}", $arg:expr $(,)?) => ({
227-
$crate::rt::panic_display(&$arg);
249+
#[cold]
250+
#[track_caller]
251+
#[inline(never)]
252+
#[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval
253+
#[rustc_do_not_const_check] // hooked by const-eval
254+
const fn panic_cold_display<T: $crate::fmt::Display>(arg: &T) -> ! {
255+
$crate::rt::panic_display(arg)
256+
}
257+
panic_cold_display(&$arg);
228258
}),
229259
($fmt:expr, $($arg:tt)+) => ({
230260
// Semicolon to prevent temporaries inside the formatting machinery from

tests/mir-opt/building/issue_101867.main.built.after.mir

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ fn main() -> () {
88
let mut _0: ();
99
let _1: std::option::Option<u8> as UserTypeProjection { base: UserType(0), projs: [] };
1010
let mut _2: !;
11-
let _3: ();
12-
let mut _4: !;
11+
let _3: !;
12+
let _4: !;
1313
let mut _6: isize;
1414
scope 1 {
1515
debug x => _1;
@@ -31,14 +31,12 @@ fn main() -> () {
3131
}
3232

3333
bb1: {
34-
StorageLive(_3);
3534
StorageLive(_4);
36-
_4 = begin_panic::<&str>(const "explicit panic") -> bb8;
35+
_4 = panic_cold_explicit() -> bb8;
3736
}
3837

3938
bb2: {
4039
StorageDead(_4);
41-
StorageDead(_3);
4240
unreachable;
4341
}
4442

tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
fn hello() -> () {
55
let mut _0: ();
66
let mut _1: bool;
7-
let mut _2: !;
7+
let _2: !;
88

99
bb0: {
1010
StorageLive(_1);
@@ -14,7 +14,7 @@
1414
}
1515

1616
bb1: {
17-
_2 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable;
17+
_2 = panic_cold_explicit() -> unwind unreachable;
1818
}
1919

2020
bb2: {

tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
fn hello() -> () {
55
let mut _0: ();
66
let mut _1: bool;
7-
let mut _2: !;
7+
let _2: !;
88

99
bb0: {
1010
StorageLive(_1);
@@ -14,7 +14,7 @@
1414
}
1515

1616
bb1: {
17-
_2 = begin_panic::<&str>(const "explicit panic") -> unwind continue;
17+
_2 = panic_cold_explicit() -> unwind continue;
1818
}
1919

2020
bb2: {

tests/mir-opt/gvn.wrap_unwrap.GVN.panic-abort.diff

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
let mut _4: isize;
1010
let _5: T;
1111
let mut _6: !;
12+
let _7: !;
1213
scope 1 {
1314
debug y => _5;
1415
}
@@ -31,8 +32,8 @@
3132
}
3233

3334
bb2: {
34-
StorageLive(_6);
35-
_6 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable;
35+
StorageLive(_7);
36+
_7 = wrap_unwrap::panic_cold_explicit() -> unwind unreachable;
3637
}
3738

3839
bb3: {

tests/mir-opt/gvn.wrap_unwrap.GVN.panic-unwind.diff

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
let mut _4: isize;
1010
let _5: T;
1111
let mut _6: !;
12+
let _7: !;
1213
scope 1 {
1314
debug y => _5;
1415
}
@@ -31,8 +32,8 @@
3132
}
3233

3334
bb2: {
34-
StorageLive(_6);
35-
_6 = begin_panic::<&str>(const "explicit panic") -> unwind continue;
35+
StorageLive(_7);
36+
_7 = wrap_unwrap::panic_cold_explicit() -> unwind continue;
3637
}
3738

3839
bb3: {

tests/mir-opt/inline/inline_diverging.g.Inline.panic-abort.diff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
let mut _5: !;
1111
let _6: !;
1212
+ scope 1 (inlined panic) {
13-
+ let mut _7: !;
13+
+ let _7: !;
1414
+ }
1515

1616
bb0: {
@@ -36,7 +36,7 @@
3636
StorageLive(_6);
3737
- _6 = panic() -> unwind unreachable;
3838
+ StorageLive(_7);
39-
+ _7 = begin_panic::<&str>(const "explicit panic") -> unwind unreachable;
39+
+ _7 = panic_cold_explicit() -> unwind unreachable;
4040
}
4141
}
4242

0 commit comments

Comments
 (0)