From f827d3e2851c97598b9d5c2648dc494ac00ca02f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 6 Jul 2021 12:38:26 +0000 Subject: [PATCH 1/9] 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. --- compiler/rustc_hir/src/lang_items.rs | 3 ++ compiler/rustc_mir/src/const_eval/machine.rs | 37 ++++++++++++++----- .../src/transform/check_consts/mod.rs | 2 + compiler/rustc_span/src/symbol.rs | 4 ++ library/core/src/fmt/mod.rs | 4 +- library/core/src/lib.rs | 1 + library/core/src/panicking.rs | 12 ++++++ 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 28ae08030e630..55000ae7e59d4 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 daaf68c1d2bd5..40621f6d4bea6 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>> { 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 0ca086d74db7b..ba8189cf9a8fc 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 5fc773e431c8b..3b17d4ca3d237 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 48142f66915bb..2494d60002089 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 839be5a143f71..d3e66a854c9b5 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 3e3e96fcd7f78..03398869466c9 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 0b9c9fb479f51..5f43393e58583 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() From 91d0823dffc29dc3e7b09791469d0c7b8beb2407 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 9 Jul 2021 14:17:39 +0200 Subject: [PATCH 2/9] Update test output for const fmt::Arguments constructor. --- src/test/ui/borrowck/issue-64453.rs | 1 - src/test/ui/borrowck/issue-64453.stderr | 12 ++---------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/test/ui/borrowck/issue-64453.rs b/src/test/ui/borrowck/issue-64453.rs index 3e803f3b6d8b2..3cfeb86cdc32a 100644 --- a/src/test/ui/borrowck/issue-64453.rs +++ b/src/test/ui/borrowck/issue-64453.rs @@ -3,7 +3,6 @@ struct Value; static settings_dir: String = format!(""); //~^ ERROR calls in statics are limited to constant functions -//~| ERROR calls in statics are limited to constant functions fn from_string(_: String) -> Value { Value diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr index bd8270ef958cb..29b05068ac74d 100644 --- a/src/test/ui/borrowck/issue-64453.stderr +++ b/src/test/ui/borrowck/issue-64453.stderr @@ -1,17 +1,9 @@ error[E0507]: cannot move out of static item `settings_dir` - --> $DIR/issue-64453.rs:14:37 + --> $DIR/issue-64453.rs:13:37 | LL | let settings_data = from_string(settings_dir); | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants - --> $DIR/issue-64453.rs:4:31 - | -LL | static settings_dir: String = format!(""); - | ^^^^^^^^^^^ - | - = note: this error originates in the macro `$crate::__export::format_args` (in Nightly builds, run with -Z macro-backtrace for more info) - error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants --> $DIR/issue-64453.rs:4:31 | @@ -20,7 +12,7 @@ LL | static settings_dir: String = format!(""); | = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0015, E0507. For more information about an error, try `rustc --explain E0015`. From 76cf1b8bd03142eacee3bd31ca4651f0ce0431ca Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 9 Jul 2021 15:33:42 +0200 Subject: [PATCH 3/9] Add test for const panic in Rust 2021. --- .../ui/consts/const-eval/const_panic_2021.rs | 27 ++++++++ .../consts/const-eval/const_panic_2021.stderr | 67 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 src/test/ui/consts/const-eval/const_panic_2021.rs create mode 100644 src/test/ui/consts/const-eval/const_panic_2021.stderr diff --git a/src/test/ui/consts/const-eval/const_panic_2021.rs b/src/test/ui/consts/const-eval/const_panic_2021.rs new file mode 100644 index 0000000000000..daef34cd6a306 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_panic_2021.rs @@ -0,0 +1,27 @@ +// edition:2021 +#![feature(const_panic)] +#![crate_type = "lib"] + +const A: () = std::panic!("blåhaj"); +//~^ ERROR evaluation of constant value failed + +const B: () = std::panic!(); +//~^ ERROR evaluation of constant value failed + +const C: () = std::unreachable!(); +//~^ ERROR evaluation of constant value failed + +const D: () = std::unimplemented!(); +//~^ ERROR evaluation of constant value failed + +const E: () = core::panic!("shark"); +//~^ ERROR evaluation of constant value failed + +const F: () = core::panic!(); +//~^ ERROR evaluation of constant value failed + +const G: () = core::unreachable!(); +//~^ ERROR evaluation of constant value failed + +const H: () = core::unimplemented!(); +//~^ ERROR evaluation of constant value failed diff --git a/src/test/ui/consts/const-eval/const_panic_2021.stderr b/src/test/ui/consts/const-eval/const_panic_2021.stderr new file mode 100644 index 0000000000000..c1bdab3693d11 --- /dev/null +++ b/src/test/ui/consts/const-eval/const_panic_2021.stderr @@ -0,0 +1,67 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:5:15 + | +LL | const A: () = std::panic!("blåhaj"); + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'blåhaj', $DIR/const_panic_2021.rs:5:15 + | + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:8:15 + | +LL | const B: () = std::panic!(); + | ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:8:15 + | + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:11:15 + | +LL | const C: () = std::unreachable!(); + | ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:11:15 + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:14:15 + | +LL | const D: () = std::unimplemented!(); + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:14:15 + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:17:15 + | +LL | const E: () = core::panic!("shark"); + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'shark', $DIR/const_panic_2021.rs:17:15 + | + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:20:15 + | +LL | const F: () = core::panic!(); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:20:15 + | + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:23:15 + | +LL | const G: () = core::unreachable!(); + | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:23:15 + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:26:15 + | +LL | const H: () = core::unimplemented!(); + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:26:15 + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0080`. From b64c4f9560e370eb718dfd266d9251d0394e6857 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 9 Jul 2021 16:45:50 +0200 Subject: [PATCH 4/9] Add new const_format_args!() macro and use it in panics. --- compiler/rustc_builtin_macros/src/lib.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/fmt/mod.rs | 2 ++ library/core/src/macros/mod.rs | 10 ++++++++++ library/core/src/panic.rs | 8 ++++---- library/std/src/lib.rs | 7 ++++--- library/std/src/panic.rs | 4 ++-- src/test/ui/borrowck/issue-64453.rs | 1 + src/test/ui/borrowck/issue-64453.stderr | 13 +++++++++++-- 9 files changed, 36 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index ba27f10330928..b1be50b0bf990 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -72,6 +72,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { file: source_util::expand_file, format_args_nl: format::expand_format_args_nl, format_args: format::expand_format_args, + const_format_args: format::expand_format_args, global_asm: asm::expand_global_asm, include_bytes: source_util::expand_include_bytes, include_str: source_util::expand_include_str, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3b17d4ca3d237..114750d9b7b3a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -410,6 +410,7 @@ symbols! { const_fn_transmute, const_fn_union, const_fn_unsize, + const_format_args, const_generic_defaults, const_generics, const_generics_defaults, diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 2494d60002089..6ad10990840c2 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -337,6 +337,7 @@ impl<'a> Arguments<'a> { #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] pub const fn new_v1(pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>]) -> Arguments<'a> { Arguments { pieces, fmt: None, args } } @@ -350,6 +351,7 @@ impl<'a> Arguments<'a> { #[doc(hidden)] #[inline] #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")] + #[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")] pub const fn new_v1_formatted( pieces: &'a [&'static str], args: &'a [ArgumentV1<'a>], diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 07ee589e29f56..dbaec2a91d20e 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -837,6 +837,16 @@ pub(crate) mod builtin { ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; } + /// Same as `format_args`, but can be used in some const contexts. + #[unstable(feature = "const_format_args", issue = "none")] + #[allow_internal_unstable(fmt_internals, const_fmt_arguments_new)] + #[rustc_builtin_macro] + #[macro_export] + macro_rules! const_format_args { + ($fmt:expr) => {{ /* compiler built-in */ }}; + ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; + } + /// Same as `format_args`, but adds a newline in the end. #[unstable( feature = "format_args_nl", diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index cbb10c324c495..4b72f9ed169ec 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -7,7 +7,7 @@ use crate::fmt; #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(core_panic)] +#[allow_internal_unstable(core_panic, const_format_args)] #[rustc_diagnostic_item = "core_panic_2015_macro"] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2015 { @@ -21,13 +21,13 @@ pub macro panic_2015 { $crate::panicking::panic_str($msg) ), ($fmt:expr, $($arg:tt)+) => ( - $crate::panicking::panic_fmt($crate::format_args!($fmt, $($arg)+)) + $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+)) ), } #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(core_panic)] +#[allow_internal_unstable(core_panic, const_format_args)] #[rustc_diagnostic_item = "core_panic_2021_macro"] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2021 { @@ -35,7 +35,7 @@ pub macro panic_2021 { $crate::panicking::panic("explicit panic") ), ($($t:tt)+) => ( - $crate::panicking::panic_fmt($crate::format_args!($($t)+)) + $crate::panicking::panic_fmt($crate::const_format_args!($($t)+)) ), } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index f0e628c3d8363..808a2202b3e9f 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -247,6 +247,7 @@ #![feature(const_fn_floating_point_arithmetic)] #![feature(const_fn_fn_ptr_basics)] #![cfg_attr(bootstrap, feature(const_fn_transmute))] +#![feature(const_format_args)] #![feature(const_io_structs)] #![feature(const_ip)] #![feature(const_ipv4)] @@ -556,9 +557,9 @@ pub use core::{ #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] #[allow(deprecated)] pub use core::{ - assert, assert_matches, cfg, column, compile_error, concat, concat_idents, env, file, - format_args, format_args_nl, include, include_bytes, include_str, line, llvm_asm, log_syntax, - module_path, option_env, stringify, trace_macros, + assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args, + env, file, format_args, format_args_nl, include, include_bytes, include_str, line, llvm_asm, + log_syntax, module_path, option_env, stringify, trace_macros, }; #[stable(feature = "core_primitive", since = "1.43.0")] diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 7bc987db8814b..3b3996e437c2b 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -20,7 +20,7 @@ use crate::thread::Result; #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(libstd_sys_internals)] +#[allow_internal_unstable(libstd_sys_internals, const_format_args)] #[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2015 { @@ -31,7 +31,7 @@ pub macro panic_2015 { $crate::rt::begin_panic($msg) }), ($fmt:expr, $($arg:tt)+) => ({ - $crate::rt::begin_panic_fmt(&$crate::format_args!($fmt, $($arg)+)) + $crate::rt::begin_panic_fmt(&$crate::const_format_args!($fmt, $($arg)+)) }), } diff --git a/src/test/ui/borrowck/issue-64453.rs b/src/test/ui/borrowck/issue-64453.rs index 3cfeb86cdc32a..9e70a847457c0 100644 --- a/src/test/ui/borrowck/issue-64453.rs +++ b/src/test/ui/borrowck/issue-64453.rs @@ -3,6 +3,7 @@ struct Value; static settings_dir: String = format!(""); //~^ ERROR calls in statics are limited to constant functions +//~| ERROR is not yet stable as a const fn from_string(_: String) -> Value { Value diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr index 29b05068ac74d..5513c3d217e2a 100644 --- a/src/test/ui/borrowck/issue-64453.stderr +++ b/src/test/ui/borrowck/issue-64453.stderr @@ -1,9 +1,18 @@ error[E0507]: cannot move out of static item `settings_dir` - --> $DIR/issue-64453.rs:13:37 + --> $DIR/issue-64453.rs:14:37 | LL | let settings_data = from_string(settings_dir); | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait +error: `Arguments::<'a>::new_v1` is not yet stable as a const fn + --> $DIR/issue-64453.rs:4:31 + | +LL | static settings_dir: String = format!(""); + | ^^^^^^^^^^^ + | + = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable + = note: this error originates in the macro `$crate::__export::format_args` (in Nightly builds, run with -Z macro-backtrace for more info) + error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants --> $DIR/issue-64453.rs:4:31 | @@ -12,7 +21,7 @@ LL | static settings_dir: String = format!(""); | = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0015, E0507. For more information about an error, try `rustc --explain E0015`. From b48274fd98b74c1fb28842d899aa0ee377d9f923 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 9 Jul 2021 17:29:41 +0200 Subject: [PATCH 5/9] Use unreachable_unchecked in const_panic_fmt. --- library/core/src/panicking.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 03398869466c9..65267a417cb4f 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -100,7 +100,10 @@ pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if let Some(msg) = fmt.as_str() { panic_str(msg); } else { - panic_str("???"); + // SAFETY: This is only evaluated at compile time, which handles this + // fine (in case it turns out this branch turns out to be reachable + // somehow). + unsafe { crate::hint::unreachable_unchecked() }; } } From 38bf5b0412fc38313d8db931febb306093c1bcae Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 9 Jul 2021 17:39:37 +0200 Subject: [PATCH 6/9] Make const_fmt_args!() work during bootstrap. --- library/core/src/macros/mod.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index dbaec2a91d20e..7568565cf59d7 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -838,6 +838,7 @@ pub(crate) mod builtin { } /// Same as `format_args`, but can be used in some const contexts. + #[cfg(not(bootstrap))] #[unstable(feature = "const_format_args", issue = "none")] #[allow_internal_unstable(fmt_internals, const_fmt_arguments_new)] #[rustc_builtin_macro] @@ -847,6 +848,16 @@ pub(crate) mod builtin { ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; } + /// Same as `format_args`, but can be used in some const contexts. + #[cfg(bootstrap)] + #[unstable(feature = "const_format_args", issue = "none")] + #[macro_export] + macro_rules! const_format_args { + ($($t:tt)*) => { + $crate::format_args!($($t)*) + } + } + /// Same as `format_args`, but adds a newline in the end. #[unstable( feature = "format_args_nl", From 4e6356188f14b2c05957a4671e7a8e857fa5f429 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 10 Jul 2021 18:32:27 +0200 Subject: [PATCH 7/9] Check that const_panic_fmt is const too. --- compiler/rustc_mir/src/const_eval/machine.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 40621f6d4bea6..dae2fe91294cb 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -238,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>, - mut instance: ty::Instance<'tcx>, + instance: ty::Instance<'tcx>, _abi: Abi, args: &[OpTy<'tcx>], _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>, @@ -258,7 +258,14 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, // that for const fn! if let Some(new_instance) = ecx.hook_panic_fn(instance, args)? { // We call another const fn instead. - instance = new_instance; + return Self::find_mir_or_eval_fn( + ecx, + new_instance, + _abi, + args, + _ret, + _unwind, + ); } else { // We certainly do *not* want to actually call the fn // though, so be sure we return here. From 0b8033ad8d320c05ec24de5b4538099f6c3b2e4d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 10 Jul 2021 18:39:25 +0200 Subject: [PATCH 8/9] Improve comments about const panic handling Co-authored-by: Ralf Jung --- compiler/rustc_mir/src/const_eval/machine.rs | 2 ++ compiler/rustc_mir/src/transform/check_consts/mod.rs | 3 +++ library/core/src/panicking.rs | 4 ++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index dae2fe91294cb..8a90686b9003f 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -31,6 +31,8 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], ) -> InterpResult<'tcx, Option>> { + // The list of functions we handle here must be in sync with + // `is_lang_panic_fn` in `transform/check_consts/mod.rs`. 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() diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs index ba8189cf9a8fc..7e22ed22db4fe 100644 --- a/compiler/rustc_mir/src/transform/check_consts/mod.rs +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -74,6 +74,9 @@ impl ConstCx<'mir, 'tcx> { /// Returns `true` if this `DefId` points to one of the official `panic` lang items. pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + // We can allow calls to these functions because `hook_panic_fn` in + // `const_eval/machine.rs` ensures the calls are handled specially. + // Keep in sync with what that function handles! 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() diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 65267a417cb4f..2ec6b4d15ffd1 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -100,8 +100,8 @@ pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! { if let Some(msg) = fmt.as_str() { panic_str(msg); } else { - // SAFETY: This is only evaluated at compile time, which handles this - // fine (in case it turns out this branch turns out to be reachable + // SAFETY: This is only evaluated at compile time, which reliably + // handles this UB (in case this branch turns out to be reachable // somehow). unsafe { crate::hint::unreachable_unchecked() }; } From 312bf8e0b8122fd681adf28f65e88f8d15f7a34c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 10 Jul 2021 18:45:28 +0200 Subject: [PATCH 9/9] Extend documentation of const_format_args!(). --- library/core/src/macros/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index 7568565cf59d7..50fefb8273199 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -838,6 +838,10 @@ pub(crate) mod builtin { } /// Same as `format_args`, but can be used in some const contexts. + /// + /// This macro is used by the panic macros for the `const_panic` feature. + /// + /// This macro will be removed once `format_args` is allowed in const contexts. #[cfg(not(bootstrap))] #[unstable(feature = "const_format_args", issue = "none")] #[allow_internal_unstable(fmt_internals, const_fmt_arguments_new)]