Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make const panic!("..") work in Rust 2021. #86998

Merged
merged 9 commits into from
Jul 29, 2021
1 change: 1 addition & 0 deletions compiler/rustc_builtin_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
44 changes: 36 additions & 8 deletions compiler/rustc_mir/src/const_eval/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ 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>>> {
// 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();
m-ou-se marked this conversation as resolved.
Show resolved Hide resolved
if Some(def_id) == self.tcx.lang_items().panic_fn()
|| Some(def_id) == self.tcx.lang_items().panic_str()
Expand All @@ -43,10 +45,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.
m-ou-se marked this conversation as resolved.
Show resolved Hide resolved
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)
}
}

Expand Down Expand Up @@ -241,10 +258,21 @@ 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.
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.
throw_unsup_format!("calling non-const function `{}`", instance)
}
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_mir/src/transform/check_consts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,14 @@ 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()
m-ou-se marked this conversation as resolved.
Show resolved Hide resolved
|| 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(
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ symbols! {
await_macro,
bang,
begin_panic,
begin_panic_fmt,
bench,
bin,
bind_by_move_pattern_guards,
Expand Down Expand Up @@ -409,6 +410,7 @@ symbols! {
const_fn_transmute,
const_fn_union,
const_fn_unsize,
const_format_args,
const_generic_defaults,
const_generics,
const_generics_defaults,
Expand All @@ -420,6 +422,7 @@ symbols! {
const_loop,
const_mut_refs,
const_panic,
const_panic_fmt,
const_precise_live_drops,
const_ptr,
const_raw_ptr_deref,
Expand Down Expand Up @@ -586,6 +589,7 @@ symbols! {
fmaf32,
fmaf64,
fmt,
fmt_as_str,
fmt_internals,
fmul_fast,
fn_align,
Expand Down Expand Up @@ -881,6 +885,7 @@ symbols! {
panic_2021,
panic_abort,
panic_bounds_check,
panic_fmt,
panic_handler,
panic_impl,
panic_implementation,
Expand Down
6 changes: 4 additions & 2 deletions library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,8 @@ 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> {
#[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 }
}

Expand All @@ -350,7 +351,8 @@ impl<'a> Arguments<'a> {
#[doc(hidden)]
#[inline]
#[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
pub fn new_v1_formatted(
#[rustc_const_unstable(feature = "const_fmt_arguments_new", issue = "none")]
pub const fn new_v1_formatted(
pieces: &'a [&'static str],
args: &'a [ArgumentV1<'a>],
fmt: &'a [rt::v1::Argument],
Expand Down
1 change: 1 addition & 0 deletions library/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
25 changes: 25 additions & 0 deletions library/core/src/macros/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,31 @@ pub(crate) mod builtin {
($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
}

/// 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)]
#[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 can be used in some const contexts.
m-ou-se marked this conversation as resolved.
Show resolved Hide resolved
#[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",
Expand Down
8 changes: 4 additions & 4 deletions library/core/src/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -21,21 +21,21 @@ 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 {
() => (
$crate::panicking::panic("explicit panic")
),
($($t:tt)+) => (
$crate::panicking::panic_fmt($crate::format_args!($($t)+))
$crate::panicking::panic_fmt($crate::const_format_args!($($t)+))
),
}

Expand Down
15 changes: 15 additions & 0 deletions library/core/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -92,6 +93,20 @@ 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 {
// 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() };
}
}

#[derive(Debug)]
#[doc(hidden)]
pub enum AssertKind {
Expand Down
7 changes: 4 additions & 3 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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")]
Expand Down
4 changes: 2 additions & 2 deletions library/std/src/panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)+))
}),
}

Expand Down
1 change: 1 addition & 0 deletions library/std/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion src/test/ui/borrowck/issue-64453.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ 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
//~| ERROR is not yet stable as a const

fn from_string(_: String) -> Value {
Value
Expand Down
3 changes: 2 additions & 1 deletion src/test/ui/borrowck/issue-64453.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ error[E0507]: cannot move out of static item `settings_dir`
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
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
Expand Down
27 changes: 27 additions & 0 deletions src/test/ui/consts/const-eval/const_panic_2021.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// edition:2021
#![feature(const_panic)]
#![crate_type = "lib"]

const A: () = std::panic!("blåhaj");
Copy link
Contributor

@oli-obk oli-obk Jul 9, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So... if my understanding is right, std::panic!(SOME_CONST) does not work anymore in 2021, does your change permit panic!("{}", some_str) to work? If so, that should have a test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oof, our test suite is really subpar. We have zero tests for

const FOO: () = {
    let mut x = [4, 2];
    for i in 0..x.len() {
         x[i] = x[i] + b'0';
    }
    let z = unsafe { std::str::from_utf8_unchecked(&x) };
    panic!("{}", z);
};

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So... if my understanding is right, std::panic!(SOME_CONST) does not work anymore in 2021, does your change permit panic!("{}", some_str) to work?

Nope. I want to make a next PR that makes panic!("{}", "literal") work. panic!("{}", some_str_var) will be a step further into the future.

//~^ 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
Loading