Skip to content

Commit dfac628

Browse files
Codegen const panic messages as function calls
This skips emitting extra arguments at every callsite (of which there can be many).
1 parent a0c20d5 commit dfac628

File tree

6 files changed

+148
-36
lines changed

6 files changed

+148
-36
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -651,10 +651,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
651651
(LangItem::PanicMisalignedPointerDereference, vec![required, found, location])
652652
}
653653
_ => {
654-
let msg = bx.const_str(msg.description());
655-
// It's `pub fn panic(expr: &str)`, with the wide reference being passed
656-
// as two arguments, and `#[track_caller]` adds an implicit third argument.
657-
(LangItem::Panic, vec![msg.0, msg.1, location])
654+
// It's `pub fn panic_...()` and `#[track_caller]` adds an implicit argument.
655+
(msg.description(), vec![location])
658656
}
659657
};
660658

compiler/rustc_hir/src/lang_items.rs

+19
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,25 @@ language_item_table! {
246246
PanicImpl, sym::panic_impl, panic_impl, Target::Fn, GenericRequirement::None;
247247
PanicCannotUnwind, sym::panic_cannot_unwind, panic_cannot_unwind, Target::Fn, GenericRequirement::Exact(0);
248248
PanicInCleanup, sym::panic_in_cleanup, panic_in_cleanup, Target::Fn, GenericRequirement::Exact(0);
249+
/// Constant panic messages, used for codegen of MIR asserts.
250+
PanicAddOverflow, sym::panic_const_add_overflow, panic_const_add_overflow, Target::Fn, GenericRequirement::None;
251+
PanicSubOverflow, sym::panic_const_sub_overflow, panic_const_sub_overflow, Target::Fn, GenericRequirement::None;
252+
PanicMulOverflow, sym::panic_const_mul_overflow, panic_const_mul_overflow, Target::Fn, GenericRequirement::None;
253+
PanicDivOverflow, sym::panic_const_div_overflow, panic_const_div_overflow, Target::Fn, GenericRequirement::None;
254+
PanicRemOverflow, sym::panic_const_rem_overflow, panic_const_rem_overflow, Target::Fn, GenericRequirement::None;
255+
PanicNegOverflow, sym::panic_const_neg_overflow, panic_const_neg_overflow, Target::Fn, GenericRequirement::None;
256+
PanicShrOverflow, sym::panic_const_shr_overflow, panic_const_shr_overflow, Target::Fn, GenericRequirement::None;
257+
PanicShlOverflow, sym::panic_const_shl_overflow, panic_const_shl_overflow, Target::Fn, GenericRequirement::None;
258+
PanicDivZero, sym::panic_const_div_by_zero, panic_const_div_by_zero, Target::Fn, GenericRequirement::None;
259+
PanicRemZero, sym::panic_const_rem_by_zero, panic_const_rem_by_zero, Target::Fn, GenericRequirement::None;
260+
PanicCoroutineResumed, sym::panic_const_coroutine_resumed, panic_const_coroutine_resumed, Target::Fn, GenericRequirement::None;
261+
PanicAsyncFnResumed, sym::panic_const_async_fn_resumed, panic_const_async_fn_resumed, Target::Fn, GenericRequirement::None;
262+
PanicAsyncGenFnResumed, sym::panic_const_async_gen_fn_resumed, panic_const_async_gen_fn_resumed, Target::Fn, GenericRequirement::None;
263+
PanicGenFnNone, sym::panic_const_gen_fn_none, panic_const_gen_fn_none, Target::Fn, GenericRequirement::None;
264+
PanicCoroutineResumedPanic, sym::panic_const_coroutine_resumed_panic, panic_const_coroutine_resumed_panic, Target::Fn, GenericRequirement::None;
265+
PanicAsyncFnResumedPanic, sym::panic_const_async_fn_resumed_panic, panic_const_async_fn_resumed_panic, Target::Fn, GenericRequirement::None;
266+
PanicAsyncGenFnResumedPanic, sym::panic_const_async_gen_fn_resumed_panic, panic_const_async_gen_fn_resumed_panic, Target::Fn, GenericRequirement::None;
267+
PanicGenFnNonePanic, sym::panic_const_gen_fn_none_panic, panic_const_gen_fn_none_panic, Target::Fn, GenericRequirement::None;
249268
/// libstd panic entry point. Necessary for const eval to be able to catch it
250269
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn, GenericRequirement::None;
251270

compiler/rustc_middle/src/mir/terminator.rs

+47-22
Original file line numberDiff line numberDiff line change
@@ -149,44 +149,45 @@ impl<O> AssertKind<O> {
149149
matches!(self, OverflowNeg(..) | Overflow(Add | Sub | Mul | Shl | Shr, ..))
150150
}
151151

152-
/// Get the message that is printed at runtime when this assertion fails.
152+
/// Get the lang item that is invoked to print a static message when this assert fires.
153153
///
154154
/// The caller is expected to handle `BoundsCheck` and `MisalignedPointerDereference` by
155155
/// invoking the appropriate lang item (panic_bounds_check/panic_misaligned_pointer_dereference)
156-
/// instead of printing a static message.
157-
pub fn description(&self) -> &'static str {
156+
/// instead of printing a static message. Those have dynamic arguments that aren't present for
157+
/// the rest of the messages here.
158+
pub fn description(&self) -> LangItem {
158159
use AssertKind::*;
159160
match self {
160-
Overflow(BinOp::Add, _, _) => "attempt to add with overflow",
161-
Overflow(BinOp::Sub, _, _) => "attempt to subtract with overflow",
162-
Overflow(BinOp::Mul, _, _) => "attempt to multiply with overflow",
163-
Overflow(BinOp::Div, _, _) => "attempt to divide with overflow",
164-
Overflow(BinOp::Rem, _, _) => "attempt to calculate the remainder with overflow",
165-
OverflowNeg(_) => "attempt to negate with overflow",
166-
Overflow(BinOp::Shr, _, _) => "attempt to shift right with overflow",
167-
Overflow(BinOp::Shl, _, _) => "attempt to shift left with overflow",
161+
Overflow(BinOp::Add, _, _) => LangItem::PanicAddOverflow,
162+
Overflow(BinOp::Sub, _, _) => LangItem::PanicSubOverflow,
163+
Overflow(BinOp::Mul, _, _) => LangItem::PanicMulOverflow,
164+
Overflow(BinOp::Div, _, _) => LangItem::PanicDivOverflow,
165+
Overflow(BinOp::Rem, _, _) => LangItem::PanicRemOverflow,
166+
OverflowNeg(_) => LangItem::PanicNegOverflow,
167+
Overflow(BinOp::Shr, _, _) => LangItem::PanicShrOverflow,
168+
Overflow(BinOp::Shl, _, _) => LangItem::PanicShlOverflow,
168169
Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
169-
DivisionByZero(_) => "attempt to divide by zero",
170-
RemainderByZero(_) => "attempt to calculate the remainder with a divisor of zero",
171-
ResumedAfterReturn(CoroutineKind::Coroutine(_)) => "coroutine resumed after completion",
170+
DivisionByZero(_) => LangItem::PanicDivZero,
171+
RemainderByZero(_) => LangItem::PanicRemZero,
172+
ResumedAfterReturn(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumed,
172173
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
173-
"`async fn` resumed after completion"
174+
LangItem::PanicAsyncFnResumed
174175
}
175176
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
176-
"`async gen fn` resumed after completion"
177+
LangItem::PanicAsyncGenFnResumed
177178
}
178179
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
179-
"`gen fn` should just keep returning `None` after completion"
180+
LangItem::PanicGenFnNone
180181
}
181-
ResumedAfterPanic(CoroutineKind::Coroutine(_)) => "coroutine resumed after panicking",
182+
ResumedAfterPanic(CoroutineKind::Coroutine(_)) => LangItem::PanicCoroutineResumedPanic,
182183
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
183-
"`async fn` resumed after panicking"
184+
LangItem::PanicAsyncFnResumedPanic
184185
}
185186
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
186-
"`async gen fn` resumed after panicking"
187+
LangItem::PanicAsyncGenFnResumedPanic
187188
}
188189
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
189-
"`gen fn` should just keep returning `None` after panicking"
190+
LangItem::PanicGenFnNonePanic
190191
}
191192

192193
BoundsCheck { .. } | MisalignedPointerDereference { .. } => {
@@ -246,13 +247,37 @@ impl<O> AssertKind<O> {
246247
Overflow(BinOp::Shl, _, r) => {
247248
write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {r:?}")
248249
}
250+
Overflow(op, _, _) => bug!("{:?} cannot overflow", op),
249251
MisalignedPointerDereference { required, found } => {
250252
write!(
251253
f,
252254
"\"misaligned pointer dereference: address must be a multiple of {{}} but is {{}}\", {required:?}, {found:?}"
253255
)
254256
}
255-
_ => write!(f, "\"{}\"", self.description()),
257+
ResumedAfterReturn(CoroutineKind::Coroutine(_)) => {
258+
write!(f, "\"coroutine resumed after completion\"")
259+
}
260+
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
261+
write!(f, "\"`async fn` resumed after completion\"")
262+
}
263+
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
264+
write!(f, "\"`async gen fn` resumed after completion\"")
265+
}
266+
ResumedAfterReturn(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
267+
write!(f, "\"`gen fn` should just keep returning `None` after completion\"")
268+
}
269+
ResumedAfterPanic(CoroutineKind::Coroutine(_)) => {
270+
write!(f, "\"coroutine resumed after panicking\"")
271+
}
272+
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)) => {
273+
write!(f, "\"`async fn` resumed after panicking\"")
274+
}
275+
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::AsyncGen, _)) => {
276+
write!(f, "\"`async gen fn` resumed after panicking\"")
277+
}
278+
ResumedAfterPanic(CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) => {
279+
write!(f, "\"`gen fn` should just keep returning `None` after panicking\"")
280+
}
256281
}
257282
}
258283

compiler/rustc_monomorphize/src/collector.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -886,16 +886,17 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
886886
}
887887
}
888888
}
889-
mir::TerminatorKind::Assert { ref msg, .. } => {
890-
let lang_item = match &**msg {
891-
mir::AssertKind::BoundsCheck { .. } => LangItem::PanicBoundsCheck,
892-
mir::AssertKind::MisalignedPointerDereference { .. } => {
893-
LangItem::PanicMisalignedPointerDereference
894-
}
895-
_ => LangItem::Panic,
896-
};
897-
push_mono_lang_item(self, lang_item);
898-
}
889+
mir::TerminatorKind::Assert { ref msg, .. } => match &**msg {
890+
mir::AssertKind::BoundsCheck { .. } => {
891+
push_mono_lang_item(self, LangItem::PanicBoundsCheck);
892+
}
893+
mir::AssertKind::MisalignedPointerDereference { .. } => {
894+
push_mono_lang_item(self, LangItem::PanicMisalignedPointerDereference);
895+
}
896+
_ => {
897+
push_mono_lang_item(self, msg.description());
898+
}
899+
},
899900
mir::TerminatorKind::UnwindTerminate(reason) => {
900901
push_mono_lang_item(self, reason.lang_item());
901902
}

compiler/rustc_span/src/symbol.rs

+18
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,24 @@ symbols! {
12971297
panic_abort,
12981298
panic_bounds_check,
12991299
panic_cannot_unwind,
1300+
panic_const_add_overflow,
1301+
panic_const_async_fn_resumed,
1302+
panic_const_async_fn_resumed_panic,
1303+
panic_const_async_gen_fn_resumed,
1304+
panic_const_async_gen_fn_resumed_panic,
1305+
panic_const_coroutine_resumed,
1306+
panic_const_coroutine_resumed_panic,
1307+
panic_const_div_by_zero,
1308+
panic_const_div_overflow,
1309+
panic_const_gen_fn_none,
1310+
panic_const_gen_fn_none_panic,
1311+
panic_const_mul_overflow,
1312+
panic_const_neg_overflow,
1313+
panic_const_rem_by_zero,
1314+
panic_const_rem_overflow,
1315+
panic_const_shl_overflow,
1316+
panic_const_shr_overflow,
1317+
panic_const_sub_overflow,
13001318
panic_fmt,
13011319
panic_handler,
13021320
panic_impl,

library/core/src/panicking.rs

+51
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,57 @@ pub const fn panic(expr: &'static str) -> ! {
145145
panic_fmt(fmt::Arguments::new_const(&[expr]));
146146
}
147147

148+
macro_rules! panic_const {
149+
($($lang:ident = $message:expr,)+) => {
150+
#[cfg(not(bootstrap))]
151+
pub mod panic_const {
152+
use super::*;
153+
154+
$(
155+
/// This is a panic called with a message that's a result of a MIR-produced Assert.
156+
//
157+
// never inline unless panic_immediate_abort to avoid code
158+
// bloat at the call sites as much as possible
159+
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
160+
#[cfg_attr(feature = "panic_immediate_abort", inline)]
161+
#[track_caller]
162+
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
163+
#[lang = stringify!($lang)] // needed by codegen for panic on overflow and other `Assert` MIR terminators
164+
pub const fn $lang() -> ! {
165+
// Use Arguments::new_v1 instead of format_args!("{expr}") to potentially
166+
// reduce size overhead. The format_args! macro uses str's Display trait to
167+
// write expr, which calls Formatter::pad, which must accommodate string
168+
// truncation and padding (even though none is used here). Using
169+
// Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
170+
// output binary, saving up to a few kilobytes.
171+
panic_fmt(fmt::Arguments::new_const(&[$message]));
172+
}
173+
)+
174+
}
175+
}
176+
}
177+
178+
panic_const! {
179+
panic_const_add_overflow = "attempt to add with overflow",
180+
panic_const_sub_overflow = "attempt to subtract with overflow",
181+
panic_const_mul_overflow = "attempt to multiply with overflow",
182+
panic_const_div_overflow = "attempt to divide with overflow",
183+
panic_const_rem_overflow = "attempt to calculate the remainder with overflow",
184+
panic_const_neg_overflow = "attempt to negate with overflow",
185+
panic_const_shr_overflow = "attempt to shift right with overflow",
186+
panic_const_shl_overflow = "attempt to shift left with overflow",
187+
panic_const_div_by_zero = "attempt to divide by zero",
188+
panic_const_rem_by_zero = "attempt to calculate the remainder with a divisor of zero",
189+
panic_const_coroutine_resumed = "coroutine resumed after completion",
190+
panic_const_async_fn_resumed = "`async fn` resumed after completion",
191+
panic_const_async_gen_fn_resumed = "`async gen fn` resumed after completion",
192+
panic_const_gen_fn_none = "`gen fn` should just keep returning `None` after completion",
193+
panic_const_coroutine_resumed_panic = "coroutine resumed after panicking",
194+
panic_const_async_fn_resumed_panic = "`async fn` resumed after panicking",
195+
panic_const_async_gen_fn_resumed_panic = "`async gen fn` resumed after panicking",
196+
panic_const_gen_fn_none_panic = "`gen fn` should just keep returning `None` after panicking",
197+
}
198+
148199
/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize on the caller.
149200
/// If you want `#[track_caller]` for nicer errors, call `panic_nounwind_fmt` directly.
150201
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]

0 commit comments

Comments
 (0)