Skip to content

Commit 02fafb5

Browse files
committed
Auto merge of #122671 - Mark-Simulacrum:const-panic-msg, r=<try>
Codegen const panic messages as function calls This skips emitting extra arguments at every callsite (of which there can be many). We could handwrite these functions if the approach here proves fairly expensive at compile-time. r? `@Mark-Simulacrum` (for perf, for now)
2 parents 62f98b4 + 12078d5 commit 02fafb5

File tree

5 files changed

+61
-13
lines changed

5 files changed

+61
-13
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -651,10 +651,26 @@ 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<const M: &str>()` and `#[track_caller]` adds an implicit argument.
655+
//
656+
// Effects add an implicit `const host: bool` so we add that in as well, matching
657+
// behavior from `ty::Instance::mono`.
658+
659+
let tcx = bx.tcx();
660+
let def_id = tcx.require_lang_item(LangItem::PanicConst, Some(span));
661+
662+
let val_tree = ty::ValTree::from_raw_bytes(tcx, msg.description().as_bytes());
663+
let desc = ty::Const::new_value(tcx, val_tree, Ty::new_static_str(tcx));
664+
let args = tcx.mk_args(&[ty::GenericArg::from(desc), tcx.consts.true_.into()]);
665+
let instance = ty::Instance::new(def_id, args);
666+
let (fn_abi, llfn) =
667+
(bx.fn_abi_of_instance(instance, ty::List::empty()), bx.get_fn_addr(instance));
668+
669+
// Codegen the actual panic invoke/call.
670+
let merging_succ =
671+
helper.do_call(self, bx, fn_abi, llfn, &[location], None, unwind, &[], false);
672+
assert_eq!(merging_succ, MergingSucc::False);
673+
return MergingSucc::False;
658674
}
659675
};
660676

compiler/rustc_hir/src/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ language_item_table! {
236236
// is required to define it somewhere. Additionally, there are restrictions on crates that use
237237
// a weak lang item, but do not have it defined.
238238
Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::Exact(0);
239+
PanicConst, sym::panic_const, panic_const_fn, Target::Fn, GenericRequirement::Exact(1);
239240
PanicNounwind, sym::panic_nounwind, panic_nounwind, Target::Fn, GenericRequirement::Exact(0);
240241
PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None;
241242
ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None;

compiler/rustc_monomorphize/src/collector.rs

+17-9
Original file line numberDiff line numberDiff line change
@@ -886,16 +886,24 @@ 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
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+
let def_id = tcx.require_lang_item(LangItem::PanicConst, Some(source));
898+
let val_tree = ty::ValTree::from_raw_bytes(tcx, msg.description().as_bytes());
899+
let desc = ty::Const::new_value(tcx, val_tree, Ty::new_static_str(tcx));
900+
let args = tcx.mk_args(&[ty::GenericArg::from(desc), tcx.consts.true_.into()]);
901+
let instance = ty::Instance::new(def_id, args);
902+
if should_codegen_locally(tcx, &instance) {
903+
self.output.push(create_fn_mono_item(tcx, instance, source));
894904
}
895-
_ => LangItem::Panic,
896-
};
897-
push_mono_lang_item(self, lang_item);
898-
}
905+
}
906+
},
899907
mir::TerminatorKind::UnwindTerminate(reason) => {
900908
push_mono_lang_item(self, reason.lang_item());
901909
}

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,7 @@ symbols! {
12971297
panic_abort,
12981298
panic_bounds_check,
12991299
panic_cannot_unwind,
1300+
panic_const,
13001301
panic_fmt,
13011302
panic_handler,
13021303
panic_impl,

library/core/src/panicking.rs

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

148+
/// This is the panic called with compile-time messages. This eliminates everything except
149+
/// the track-caller argument at call sites, while not requiring writing a bunch of code inside MIR
150+
/// etc. for generating stub functions.
151+
//
152+
// never inline unless panic_immediate_abort to avoid code
153+
// bloat at the call sites as much as possible
154+
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]
155+
#[cfg_attr(feature = "panic_immediate_abort", inline)]
156+
#[track_caller]
157+
#[rustc_const_unstable(feature = "panic_internals", issue = "none")]
158+
#[lang = "panic_const"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
159+
#[cfg(not(bootstrap))]
160+
pub const fn panic_const<const MESSAGE: &'static str>() -> ! {
161+
// Use Arguments::new_v1 instead of format_args!("{expr}") to potentially
162+
// reduce size overhead. The format_args! macro uses str's Display trait to
163+
// write expr, which calls Formatter::pad, which must accommodate string
164+
// truncation and padding (even though none is used here). Using
165+
// Arguments::new_v1 may allow the compiler to omit Formatter::pad from the
166+
// output binary, saving up to a few kilobytes.
167+
panic_fmt(fmt::Arguments::new_const(&[MESSAGE]));
168+
}
169+
148170
/// Like `panic`, but without unwinding and track_caller to reduce the impact on codesize on the caller.
149171
/// If you want `#[track_caller]` for nicer errors, call `panic_nounwind_fmt` directly.
150172
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never), cold)]

0 commit comments

Comments
 (0)