Skip to content

Commit 12078d5

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 12078d5

File tree

5 files changed

+61
-13
lines changed

5 files changed

+61
-13
lines changed

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 20 additions & 4 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 17 additions & 9 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 22 additions & 0 deletions
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)