Skip to content

Commit

Permalink
Emit a hard error when a panic occurs during const-eval
Browse files Browse the repository at this point in the history
Previous, a panic during const evaluation would go through the
`const_err` lint. This PR ensures that such a panic always causes
compilation to fail.
  • Loading branch information
Aaron1011 committed May 30, 2021
1 parent 2023cc3 commit 2779fc1
Show file tree
Hide file tree
Showing 15 changed files with 118 additions and 182 deletions.
8 changes: 6 additions & 2 deletions compiler/rustc_middle/src/mir/interpret/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,8 +435,12 @@ impl<T: Any> AsAny for T {
}

/// A trait for machine-specific errors (or other "machine stop" conditions).
pub trait MachineStopType: AsAny + fmt::Display + Send {}
impl MachineStopType for String {}
pub trait MachineStopType: AsAny + fmt::Display + Send {
/// If `true`, emit a hard error instead of going through the `CONST_ERR` lint
fn is_hard_err(&self) -> bool {
false
}
}

impl dyn MachineStopType {
#[inline(always)]
Expand Down
108 changes: 56 additions & 52 deletions compiler/rustc_mir/src/const_eval/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_span::{Span, Symbol};

use super::InterpCx;
use crate::interpret::{
struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine,
struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType,
};

/// The CTFE machine has some custom error kinds.
Expand All @@ -24,12 +24,21 @@ pub enum ConstEvalErrKind {
Abort(String),
}

impl MachineStopType for ConstEvalErrKind {
fn is_hard_err(&self) -> bool {
match self {
Self::Panic { .. } => true,
_ => false,
}
}
}

// The errors become `MachineStop` with plain strings when being raised.
// `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to
// handle these.
impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind {
fn into(self) -> InterpErrorInfo<'tcx> {
err_machine_stop!(self.to_string()).into()
err_machine_stop!(self).into()
}
}

Expand Down Expand Up @@ -148,31 +157,10 @@ impl<'tcx> ConstEvalErr<'tcx> {
tcx: TyCtxtAt<'tcx>,
message: &str,
emit: impl FnOnce(DiagnosticBuilder<'_>),
lint_root: Option<hir::HirId>,
mut lint_root: Option<hir::HirId>,
) -> ErrorHandled {
let must_error = match self.error {
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
return ErrorHandled::TooGeneric;
}
err_inval!(AlreadyReported(error_reported)) => {
return ErrorHandled::Reported(error_reported);
}
// We must *always* hard error on these, even if the caller wants just a lint.
err_inval!(Layout(LayoutError::SizeOverflow(_))) => true,
_ => false,
};
trace!("reporting const eval failure at {:?}", self.span);

let err_msg = match &self.error {
InterpError::MachineStop(msg) => {
// A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`).
// Should be turned into a string by now.
msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone()
}
err => err.to_string(),
};

let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| {
trace!("reporting const eval failure at {:?}", self.span);
if let Some(span_msg) = span_msg {
err.span_label(self.span, span_msg);
}
Expand All @@ -186,34 +174,50 @@ impl<'tcx> ConstEvalErr<'tcx> {
emit(err)
};

if must_error {
// The `message` makes little sense here, this is a more serious error than the
// caller thinks anyway.
// See <https://github.com/rust-lang/rust/pull/63152>.
finish(struct_error(tcx, &err_msg), None);
ErrorHandled::Reported(ErrorReported)
} else {
// Regular case.
if let Some(lint_root) = lint_root {
// Report as lint.
let hir_id = self
.stacktrace
.iter()
.rev()
.find_map(|frame| frame.lint_root)
.unwrap_or(lint_root);
tcx.struct_span_lint_hir(
rustc_session::lint::builtin::CONST_ERR,
hir_id,
tcx.span,
|lint| finish(lint.build(message), Some(err_msg)),
);
ErrorHandled::Linted
} else {
// Report as hard error.
finish(struct_error(tcx, message), Some(err_msg));
ErrorHandled::Reported(ErrorReported)
// Special handling for certain errors
match &self.error {
// Don't emit a new diagnostic for these errors
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
return ErrorHandled::TooGeneric;
}
err_inval!(AlreadyReported(error_reported)) => {
return ErrorHandled::Reported(*error_reported);
}
err_inval!(Layout(LayoutError::SizeOverflow(_))) => {
// We must *always* hard error on these, even if the caller wants just a lint.
// The `message` makes little sense here, this is a more serious error than the
// caller thinks anyway.
// See <https://github.com/rust-lang/rust/pull/63152>.
finish(struct_error(tcx, &self.error.to_string()), None);
return ErrorHandled::Reported(ErrorReported);
}
_ => {}
};

// If we have a 'hard error', then set `lint_root` to `None` so that we don't
// emit a lint.
if matches!(&self.error, InterpError::MachineStop(err) if err.is_hard_err()) {
lint_root = None;
}

let err_msg = self.error.to_string();

// Regular case - emit a lint.
if let Some(lint_root) = lint_root {
// Report as lint.
let hir_id =
self.stacktrace.iter().rev().find_map(|frame| frame.lint_root).unwrap_or(lint_root);
tcx.struct_span_lint_hir(
rustc_session::lint::builtin::CONST_ERR,
hir_id,
tcx.span,
|lint| finish(lint.build(message), Some(err_msg)),
);
ErrorHandled::Linted
} else {
// Report as hard error.
finish(struct_error(tcx, message), Some(err_msg));
ErrorHandled::Reported(ErrorReported)
}
}
}
10 changes: 0 additions & 10 deletions src/test/ui/consts/const-eval/const_panic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,30 @@ const MSG: &str = "hello";

const Z: () = std::panic!("cheese");
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out

const Z2: () = std::panic!();
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out

const Y: () = std::unreachable!();
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out

const X: () = std::unimplemented!();
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out
//
const W: () = std::panic!(MSG);
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out

const Z_CORE: () = core::panic!("cheese");
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out

const Z2_CORE: () = core::panic!();
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out

const Y_CORE: () = core::unreachable!();
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out

const X_CORE: () = core::unimplemented!();
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out

const W_CORE: () = core::panic!(MSG);
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out
78 changes: 29 additions & 49 deletions src/test/ui/consts/const-eval/const_panic.stderr
Original file line number Diff line number Diff line change
@@ -1,123 +1,103 @@
error: any use of this value will cause an error
error[E0080]: any use of this value will cause an error
--> $DIR/const_panic.rs:7:15
|
LL | const Z: () = std::panic!("cheese");
| --------------^^^^^^^^^^^^^^^^^^^^^-
| |
| the evaluated program panicked at 'cheese', $DIR/const_panic.rs:7:15
|
= note: `#[deny(const_err)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)

error: any use of this value will cause an error
--> $DIR/const_panic.rs:11:16
error[E0080]: any use of this value will cause an error
--> $DIR/const_panic.rs:10:16
|
LL | const Z2: () = std::panic!();
| ---------------^^^^^^^^^^^^^-
| |
| the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:11:16
| the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:10:16
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)

error: any use of this value will cause an error
--> $DIR/const_panic.rs:15:15
error[E0080]: any use of this value will cause an error
--> $DIR/const_panic.rs:13:15
|
LL | const Y: () = std::unreachable!();
| --------------^^^^^^^^^^^^^^^^^^^-
| |
| the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:15:15
| the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:13:15
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)

error: any use of this value will cause an error
--> $DIR/const_panic.rs:19:15
error[E0080]: any use of this value will cause an error
--> $DIR/const_panic.rs:16:15
|
LL | const X: () = std::unimplemented!();
| --------------^^^^^^^^^^^^^^^^^^^^^-
| |
| the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:19:15
| the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:16:15
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)

error: any use of this value will cause an error
--> $DIR/const_panic.rs:23:15
error[E0080]: any use of this value will cause an error
--> $DIR/const_panic.rs:19:15
|
LL | const W: () = std::panic!(MSG);
| --------------^^^^^^^^^^^^^^^^-
| |
| the evaluated program panicked at 'hello', $DIR/const_panic.rs:23:15
| the evaluated program panicked at 'hello', $DIR/const_panic.rs:19:15
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)

error: any use of this value will cause an error
--> $DIR/const_panic.rs:27:20
error[E0080]: any use of this value will cause an error
--> $DIR/const_panic.rs:22:20
|
LL | const Z_CORE: () = core::panic!("cheese");
| -------------------^^^^^^^^^^^^^^^^^^^^^^-
| |
| the evaluated program panicked at 'cheese', $DIR/const_panic.rs:27:20
| the evaluated program panicked at 'cheese', $DIR/const_panic.rs:22:20
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)

error: any use of this value will cause an error
--> $DIR/const_panic.rs:31:21
error[E0080]: any use of this value will cause an error
--> $DIR/const_panic.rs:25:21
|
LL | const Z2_CORE: () = core::panic!();
| --------------------^^^^^^^^^^^^^^-
| |
| the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:31:21
| the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:25:21
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)

error: any use of this value will cause an error
--> $DIR/const_panic.rs:35:20
error[E0080]: any use of this value will cause an error
--> $DIR/const_panic.rs:28:20
|
LL | const Y_CORE: () = core::unreachable!();
| -------------------^^^^^^^^^^^^^^^^^^^^-
| |
| the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:35:20
| the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:28:20
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)

error: any use of this value will cause an error
--> $DIR/const_panic.rs:39:20
error[E0080]: any use of this value will cause an error
--> $DIR/const_panic.rs:31:20
|
LL | const X_CORE: () = core::unimplemented!();
| -------------------^^^^^^^^^^^^^^^^^^^^^^-
| |
| the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:39:20
| the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:31:20
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)

error: any use of this value will cause an error
--> $DIR/const_panic.rs:43:20
error[E0080]: any use of this value will cause an error
--> $DIR/const_panic.rs:34:20
|
LL | const W_CORE: () = core::panic!(MSG);
| -------------------^^^^^^^^^^^^^^^^^-
| |
| the evaluated program panicked at 'hello', $DIR/const_panic.rs:43:20
| the evaluated program panicked at 'hello', $DIR/const_panic.rs:34:20
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
= 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 10 previous errors

For more information about this error, try `rustc --explain E0080`.
3 changes: 0 additions & 3 deletions src/test/ui/consts/const-eval/const_panic_libcore_bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,12 @@ use core::panic::PanicInfo;

const Z: () = panic!("cheese");
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out

const Y: () = unreachable!();
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out

const X: () = unimplemented!();
//~^ ERROR any use of this value will cause an error
//~| WARN this was previously accepted by the compiler but is being phased out

#[lang = "eh_personality"]
fn eh() {}
Expand Down
Loading

0 comments on commit 2779fc1

Please sign in to comment.