diff options
| author | Mara Bos <m-ou.se@m-ou.se> | 2021-07-06 12:38:26 +0000 |
|---|---|---|
| committer | Mara Bos <m-ou.se@m-ou.se> | 2021-07-28 16:10:41 +0200 |
| commit | f827d3e2851c97598b9d5c2648dc494ac00ca02f (patch) | |
| tree | b8e143ec231b79838d0e157fb342b26823f9b9c4 | |
| parent | eba3228b2a9875d268ff3990903d04e19f6cdb0c (diff) | |
| download | rust-f827d3e2851c97598b9d5c2648dc494ac00ca02f.tar.gz rust-f827d3e2851c97598b9d5c2648dc494ac00ca02f.zip | |
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.
| -rw-r--r-- | compiler/rustc_hir/src/lang_items.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/const_eval/machine.rs | 37 | ||||
| -rw-r--r-- | compiler/rustc_mir/src/transform/check_consts/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_span/src/symbol.rs | 4 | ||||
| -rw-r--r-- | library/core/src/fmt/mod.rs | 4 | ||||
| -rw-r--r-- | library/core/src/lib.rs | 1 | ||||
| -rw-r--r-- | library/core/src/panicking.rs | 12 | ||||
| -rw-r--r-- | library/std/src/panicking.rs | 1 |
8 files changed, 53 insertions, 11 deletions
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 28ae08030e6..55000ae7e59 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -276,13 +276,16 @@ language_item_table! { // is required to define it somewhere. Additionally, there are restrictions on crates that use // a weak lang item, but do not have it defined. Panic, sym::panic, panic_fn, Target::Fn; + PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn; PanicStr, sym::panic_str, panic_str, Target::Fn; + ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn; PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn; PanicInfo, sym::panic_info, panic_info, Target::Struct; PanicLocation, sym::panic_location, panic_location, Target::Struct; PanicImpl, sym::panic_impl, panic_impl, Target::Fn; /// libstd panic entry point. Necessary for const eval to be able to catch it BeginPanic, sym::begin_panic, begin_panic_fn, Target::Fn; + BeginPanicFmt, sym::begin_panic_fmt, begin_panic_fmt, Target::Fn; ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn; BoxFree, sym::box_free, box_free_fn, Target::Fn; diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index daaf68c1d2b..40621f6d4be 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -30,7 +30,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> { let def_id = instance.def_id(); if Some(def_id) == self.tcx.lang_items().panic_fn() || Some(def_id) == self.tcx.lang_items().panic_str() @@ -43,10 +43,25 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { let msg = Symbol::intern(self.read_str(&msg_place)?); let span = self.find_closest_untracked_caller_location(); let (file, line, col) = self.location_triple_for_span(span); - Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()) - } else { - Ok(()) + return Err(ConstEvalErrKind::Panic { msg, file, line, col }.into()); + } else if Some(def_id) == self.tcx.lang_items().panic_fmt() + || Some(def_id) == self.tcx.lang_items().begin_panic_fmt() + { + // For panic_fmt, call const_panic_fmt instead. + if let Some(const_panic_fmt) = self.tcx.lang_items().const_panic_fmt() { + return Ok(Some( + ty::Instance::resolve( + *self.tcx, + ty::ParamEnv::reveal_all(), + const_panic_fmt, + self.tcx.intern_substs(&[]), + ) + .unwrap() + .unwrap(), + )); + } } + Ok(None) } } @@ -223,7 +238,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, + mut instance: ty::Instance<'tcx>, _abi: Abi, args: &[OpTy<'tcx>], _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>, @@ -241,10 +256,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, if !ecx.tcx.has_attr(def.did, sym::default_method_body_is_const) { // Some functions we support even if they are non-const -- but avoid testing // that for const fn! - ecx.hook_panic_fn(instance, args)?; - // We certainly do *not* want to actually call the fn - // though, so be sure we return here. - throw_unsup_format!("calling non-const function `{}`", instance) + if let Some(new_instance) = ecx.hook_panic_fn(instance, args)? { + // We call another const fn instead. + instance = new_instance; + } else { + // We certainly do *not* want to actually call the fn + // though, so be sure we return here. + throw_unsup_format!("calling non-const function `{}`", instance) + } } } } diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs index 0ca086d74db..ba8189cf9a8 100644 --- a/compiler/rustc_mir/src/transform/check_consts/mod.rs +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -77,6 +77,8 @@ pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().panic_str() || Some(def_id) == tcx.lang_items().begin_panic_fn() + || Some(def_id) == tcx.lang_items().panic_fmt() + || Some(def_id) == tcx.lang_items().begin_panic_fmt() } pub fn rustc_allow_const_fn_unstable( diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5fc773e431c..3b17d4ca3d2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -323,6 +323,7 @@ symbols! { await_macro, bang, begin_panic, + begin_panic_fmt, bench, bin, bind_by_move_pattern_guards, @@ -420,6 +421,7 @@ symbols! { const_loop, const_mut_refs, const_panic, + const_panic_fmt, const_precise_live_drops, const_ptr, const_raw_ptr_deref, @@ -586,6 +588,7 @@ symbols! { fmaf32, fmaf64, fmt, + fmt_as_str, fmt_internals, fmul_fast, fn_align, @@ -881,6 +884,7 @@ symbols! { panic_2021, panic_abort, panic_bounds_check, + panic_fmt, panic_handler, panic_impl, panic_implementation, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 48142f66915..2494d600020 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -337,7 +337,7 @@ impl<'a> Arguments<'a> { #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - pub fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> { + pub const fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> { Arguments { pieces, fmt: None, args } } @@ -350,7 +350,7 @@ impl<'a> Arguments<'a> { #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] - pub fn new_v1_formatted( + pub const fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>], fmt: &'a [rt::v1::Argument], diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 839be5a143f..d3e66a854c9 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -73,6 +73,7 @@ #![feature(cfg_target_has_atomic)] #![feature(const_heap)] #![feature(const_alloc_layout)] +#![feature(const_arguments_as_str)] #![feature(const_assert_type)] #![feature(const_discriminant)] #![feature(const_cell_into_inner)] diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 3e3e96fcd7f..03398869466 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -74,6 +74,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! { #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[cfg_attr(feature = "panic_immediate_abort", inline)] #[track_caller] +#[cfg_attr(not(bootstrap), lang = "panic_fmt")] // needed for const-evaluated panics pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() @@ -92,6 +93,17 @@ pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { unsafe { panic_impl(&pi) } } +/// This function is used instead of panic_fmt in const eval. +#[cfg(not(bootstrap))] +#[lang = "const_panic_fmt"] +pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { + if let Some(msg) = fmt.as_str() { + panic_str(msg); + } else { + panic_str("???"); + } +} + #[derive(Debug)] #[doc(hidden)] pub enum AssertKind { diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 0b9c9fb479f..5f43393e585 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -448,6 +448,7 @@ pub fn panicking() -> bool { #[cfg_attr(not(feature = "panic_immediate_abort"), track_caller)] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[cfg_attr(feature = "panic_immediate_abort", inline)] +#[cfg_attr(all(not(bootstrap), not(test)), lang = "begin_panic_fmt")] pub fn begin_panic_fmt(msg: &fmt::Arguments<'_>) -> ! { if cfg!(feature = "panic_immediate_abort") { intrinsics::abort() |
