Skip to content

Commit f827d3e

Browse files
committed
Make const panic!("..") work in Rust 2021.
During const eval, this replaces calls to core::panicking::panic_fmt and std::panicking::being_panic_fmt with a call to a new const fn: core::panicking::const_panic_fmt. That function uses fmt::Arguments::as_str() to get the str and calls panic_str with that instead. panic!() invocations with formatting arguments are still not accepted, as the creation of such a fmt::Arguments cannot be done in constant functions right now.
1 parent eba3228 commit f827d3e

File tree

8 files changed

+53
-11
lines changed

8 files changed

+53
-11
lines changed

compiler/rustc_hir/src/lang_items.rs

+3
Original file line numberDiff line numberDiff line change
@@ -276,13 +276,16 @@ language_item_table! {
276276
// is required to define it somewhere. Additionally, there are restrictions on crates that use
277277
// a weak lang item, but do not have it defined.
278278
Panic, sym::panic, panic_fn, Target::Fn;
279+
PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn;
279280
PanicStr, sym::panic_str, panic_str, Target::Fn;
281+
ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn;
280282
PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn;
281283
PanicInfo, sym::panic_info, panic_info, Target::Struct;
282284
PanicLocation, sym::panic_location, panic_location, Target::Struct;
283285
PanicImpl, sym::panic_impl, panic_impl, Target::Fn;
284286
/// libstd panic entry point. Necessary for const eval to be able to catch it
285287
BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn;
288+
BeginPanicFmt, sym::begin_panic_fmt, begin_panic_fmt, Target::Fn;
286289

287290
ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn;
288291
BoxFree, sym::box_free, box_free_fn, Target::Fn;

compiler/rustc_mir/src/const_eval/machine.rs

+28-9
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
3030
&mut self,
3131
instance: ty::Instance<'tcx>,
3232
args: &[OpTy<'tcx>],
33-
) -> InterpResult<'tcx> {
33+
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
3434
let def_id = instance.def_id();
3535
if Some(def_id) == self.tcx.lang_items().panic_fn()
3636
|| Some(def_id) == self.tcx.lang_items().panic_str()
@@ -43,10 +43,25 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> {
4343
let msg = Symbol::intern(self.read_str(&msg_place)?);
4444
let span = self.find_closest_untracked_caller_location();
4545
let (file, line, col) = self.location_triple_for_span(span);
46-
Err(ConstEvalErrKind::Panic { msg, file, line, col }.into())
47-
} else {
48-
Ok(())
46+
return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into());
47+
} else if Some(def_id) == self.tcx.lang_items().panic_fmt()
48+
|| Some(def_id) == self.tcx.lang_items().begin_panic_fmt()
49+
{
50+
// For panic_fmt, call const_panic_fmt instead.
51+
if let Some(const_panic_fmt) = self.tcx.lang_items().const_panic_fmt() {
52+
return Ok(Some(
53+
ty::Instance::resolve(
54+
*self.tcx,
55+
ty::ParamEnv::reveal_all(),
56+
const_panic_fmt,
57+
self.tcx.intern_substs(&[]),
58+
)
59+
.unwrap()
60+
.unwrap(),
61+
));
62+
}
4963
}
64+
Ok(None)
5065
}
5166
}
5267

@@ -223,7 +238,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
223238

224239
fn find_mir_or_eval_fn(
225240
ecx: &mut InterpCx<'mir, 'tcx, Self>,
226-
instance: ty::Instance<'tcx>,
241+
mut instance: ty::Instance<'tcx>,
227242
_abi: Abi,
228243
args: &[OpTy<'tcx>],
229244
_ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>,
@@ -241,10 +256,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
241256
if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) {
242257
// Some functions we support even if they are non-const -- but avoid testing
243258
// that for const fn!
244-
ecx.hook_panic_fn(instance, args)?;
245-
// We certainly do *not* want to actually call the fn
246-
// though, so be sure we return here.
247-
throw_unsup_format!("calling non-const function `{}`", instance)
259+
if let Some(new_instance) = ecx.hook_panic_fn(instance, args)? {
260+
// We call another const fn instead.
261+
instance = new_instance;
262+
} else {
263+
// We certainly do *not* want to actually call the fn
264+
// though, so be sure we return here.
265+
throw_unsup_format!("calling non-const function `{}`", instance)
266+
}
248267
}
249268
}
250269
}

compiler/rustc_mir/src/transform/check_consts/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
7777
Some(def_id) == tcx.lang_items().panic_fn()
7878
|| Some(def_id) == tcx.lang_items().panic_str()
7979
|| Some(def_id) == tcx.lang_items().begin_panic_fn()
80+
|| Some(def_id) == tcx.lang_items().panic_fmt()
81+
|| Some(def_id) == tcx.lang_items().begin_panic_fmt()
8082
}
8183

8284
pub fn rustc_allow_const_fn_unstable(

compiler/rustc_span/src/symbol.rs

+4
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ symbols! {
323323
await_macro,
324324
bang,
325325
begin_panic,
326+
begin_panic_fmt,
326327
bench,
327328
bin,
328329
bind_by_move_pattern_guards,
@@ -420,6 +421,7 @@ symbols! {
420421
const_loop,
421422
const_mut_refs,
422423
const_panic,
424+
const_panic_fmt,
423425
const_precise_live_drops,
424426
const_ptr,
425427
const_raw_ptr_deref,
@@ -586,6 +588,7 @@ symbols! {
586588
fmaf32,
587589
fmaf64,
588590
fmt,
591+
fmt_as_str,
589592
fmt_internals,
590593
fmul_fast,
591594
fn_align,
@@ -881,6 +884,7 @@ symbols! {
881884
panic_2021,
882885
panic_abort,
883886
panic_bounds_check,
887+
panic_fmt,
884888
panic_handler,
885889
panic_impl,
886890
panic_implementation,

library/core/src/fmt/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ impl<'a> Arguments<'a> {
337337
#[doc(hidden)]
338338
#[inline]
339339
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
340-
pub fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
340+
pub const fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> {
341341
Arguments { pieces, fmt: None, args }
342342
}
343343

@@ -350,7 +350,7 @@ impl<'a> Arguments<'a> {
350350
#[doc(hidden)]
351351
#[inline]
352352
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
353-
pub fn new_v1_formatted(
353+
pub const fn new_v1_formatted(
354354
pieces: &'a [&'static str],
355355
args: &'a [ArgumentV1<'a>],
356356
fmt: &'a [rt::v1::Argument],

library/core/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
#![feature(cfg_target_has_atomic)]
7474
#![feature(const_heap)]
7575
#![feature(const_alloc_layout)]
76+
#![feature(const_arguments_as_str)]
7677
#![feature(const_assert_type)]
7778
#![feature(const_discriminant)]
7879
#![feature(const_cell_into_inner)]

library/core/src/panicking.rs

+12
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
7474
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
7575
#[cfg_attr(feature = "panic_immediate_abort", inline)]
7676
#[track_caller]
77+
#[cfg_attr(not(bootstrap), lang = "panic_fmt")] // needed for const-evaluated panics
7778
pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
7879
if cfg!(feature = "panic_immediate_abort") {
7980
super::intrinsics::abort()
@@ -92,6 +93,17 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
9293
unsafe { panic_impl(&pi) }
9394
}
9495

96+
/// This function is used instead of panic_fmt in const eval.
97+
#[cfg(not(bootstrap))]
98+
#[lang = "const_panic_fmt"]
99+
pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
100+
if let Some(msg) = fmt.as_str() {
101+
panic_str(msg);
102+
} else {
103+
panic_str("???");
104+
}
105+
}
106+
95107
#[derive(Debug)]
96108
#[doc(hidden)]
97109
pub enum AssertKind {

library/std/src/panicking.rs

+1
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ pub fn panicking() -> bool {
448448
#[cfg_attr(not(feature = "panic_immediate_abort"), track_caller)]
449449
#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
450450
#[cfg_attr(feature = "panic_immediate_abort", inline)]
451+
#[cfg_attr(all(not(bootstrap), not(test)), lang = "begin_panic_fmt")]
451452
pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! {
452453
if cfg!(feature = "panic_immediate_abort") {
453454
intrinsics::abort()

0 commit comments

Comments
 (0)