make const_err a hard error
This commit is contained in:
parent
5854680388
commit
fd59d44f58
254 changed files with 1460 additions and 5402 deletions
|
@ -2,7 +2,6 @@ use std::error::Error;
|
|||
use std::fmt;
|
||||
|
||||
use rustc_errors::Diagnostic;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::mir::AssertKind;
|
||||
use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt};
|
||||
use rustc_span::{Span, Symbol};
|
||||
|
@ -23,11 +22,7 @@ pub enum ConstEvalErrKind {
|
|||
Abort(String),
|
||||
}
|
||||
|
||||
impl MachineStopType for ConstEvalErrKind {
|
||||
fn is_hard_err(&self) -> bool {
|
||||
matches!(self, Self::Panic { .. })
|
||||
}
|
||||
}
|
||||
impl MachineStopType for ConstEvalErrKind {}
|
||||
|
||||
// The errors become `MachineStop` with plain strings when being raised.
|
||||
// `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to
|
||||
|
@ -87,48 +82,10 @@ impl<'tcx> ConstEvalErr<'tcx> {
|
|||
ConstEvalErr { error: error.into_kind(), stacktrace, span }
|
||||
}
|
||||
|
||||
pub fn struct_error(
|
||||
&self,
|
||||
tcx: TyCtxtAt<'tcx>,
|
||||
message: &str,
|
||||
decorate: impl FnOnce(&mut Diagnostic),
|
||||
) -> ErrorHandled {
|
||||
self.struct_generic(tcx, message, decorate, None)
|
||||
}
|
||||
|
||||
pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
|
||||
self.struct_error(tcx, message, |_| {})
|
||||
}
|
||||
|
||||
pub fn report_as_lint(
|
||||
&self,
|
||||
tcx: TyCtxtAt<'tcx>,
|
||||
message: &str,
|
||||
lint_root: hir::HirId,
|
||||
span: Option<Span>,
|
||||
) -> ErrorHandled {
|
||||
self.struct_generic(
|
||||
tcx,
|
||||
message,
|
||||
|lint: &mut Diagnostic| {
|
||||
// Apply the span.
|
||||
if let Some(span) = span {
|
||||
let primary_spans = lint.span.primary_spans().to_vec();
|
||||
// point at the actual error as the primary span
|
||||
lint.replace_span_with(span);
|
||||
// point to the `const` statement as a secondary span
|
||||
// they don't have any label
|
||||
for sp in primary_spans {
|
||||
if sp != span {
|
||||
lint.span_label(sp, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Some(lint_root),
|
||||
)
|
||||
}
|
||||
|
||||
/// Create a diagnostic for this const eval error.
|
||||
///
|
||||
/// Sets the message passed in via `message` and adds span labels with detailed error
|
||||
|
@ -137,13 +94,12 @@ impl<'tcx> ConstEvalErr<'tcx> {
|
|||
///
|
||||
/// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
|
||||
/// (Except that for some errors, we ignore all that -- see `must_error` below.)
|
||||
#[instrument(skip(self, tcx, decorate, lint_root), level = "debug")]
|
||||
fn struct_generic(
|
||||
#[instrument(skip(self, tcx, decorate), level = "debug")]
|
||||
pub fn struct_error(
|
||||
&self,
|
||||
tcx: TyCtxtAt<'tcx>,
|
||||
message: &str,
|
||||
decorate: impl FnOnce(&mut Diagnostic),
|
||||
lint_root: Option<hir::HirId>,
|
||||
) -> ErrorHandled {
|
||||
let finish = |err: &mut Diagnostic, span_msg: Option<String>| {
|
||||
trace!("reporting const eval failure at {:?}", self.span);
|
||||
|
@ -224,27 +180,9 @@ impl<'tcx> ConstEvalErr<'tcx> {
|
|||
|
||||
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,
|
||||
message,
|
||||
|lint| {
|
||||
finish(lint, Some(err_msg));
|
||||
lint
|
||||
},
|
||||
);
|
||||
ErrorHandled::Linted
|
||||
} else {
|
||||
// Report as hard error.
|
||||
let mut err = struct_error(tcx, message);
|
||||
finish(&mut err, Some(err_msg));
|
||||
ErrorHandled::Reported(err.emit())
|
||||
}
|
||||
// Report as hard error.
|
||||
let mut err = struct_error(tcx, message);
|
||||
finish(&mut err, Some(err_msg));
|
||||
ErrorHandled::Reported(err.emit())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -317,45 +317,23 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
|
|||
match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) {
|
||||
Err(error) => {
|
||||
let err = ConstEvalErr::new(&ecx, error, None);
|
||||
// Some CTFE errors raise just a lint, not a hard error; see
|
||||
// <https://github.com/rust-lang/rust/issues/71800>.
|
||||
let is_hard_err = if let Some(def) = def.as_local() {
|
||||
// (Associated) consts only emit a lint, since they might be unused.
|
||||
!matches!(tcx.def_kind(def.did.to_def_id()), DefKind::Const | DefKind::AssocConst)
|
||||
// check if the inner InterpError is hard
|
||||
|| err.error.is_hard_err()
|
||||
let msg = if is_static {
|
||||
Cow::from("could not evaluate static initializer")
|
||||
} else {
|
||||
// use of broken constant from other crate: always an error
|
||||
true
|
||||
// If the current item has generics, we'd like to enrich the message with the
|
||||
// instance and its substs: to show the actual compile-time values, in addition to
|
||||
// the expression, leading to the const eval error.
|
||||
let instance = &key.value.instance;
|
||||
if !instance.substs.is_empty() {
|
||||
let instance = with_no_trimmed_paths!(instance.to_string());
|
||||
let msg = format!("evaluation of `{}` failed", instance);
|
||||
Cow::from(msg)
|
||||
} else {
|
||||
Cow::from("evaluation of constant value failed")
|
||||
}
|
||||
};
|
||||
|
||||
if is_hard_err {
|
||||
let msg = if is_static {
|
||||
Cow::from("could not evaluate static initializer")
|
||||
} else {
|
||||
// If the current item has generics, we'd like to enrich the message with the
|
||||
// instance and its substs: to show the actual compile-time values, in addition to
|
||||
// the expression, leading to the const eval error.
|
||||
let instance = &key.value.instance;
|
||||
if !instance.substs.is_empty() {
|
||||
let instance = with_no_trimmed_paths!(instance.to_string());
|
||||
let msg = format!("evaluation of `{}` failed", instance);
|
||||
Cow::from(msg)
|
||||
} else {
|
||||
Cow::from("evaluation of constant value failed")
|
||||
}
|
||||
};
|
||||
|
||||
Err(err.report_as_error(ecx.tcx.at(err.span), &msg))
|
||||
} else {
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(def.as_local().unwrap().did);
|
||||
Err(err.report_as_lint(
|
||||
tcx.at(tcx.def_span(def.did)),
|
||||
"any use of this value will cause an error",
|
||||
hir_id,
|
||||
Some(err.span),
|
||||
))
|
||||
}
|
||||
Err(err.report_as_error(ecx.tcx.at(err.span), &msg))
|
||||
}
|
||||
Ok(mplace) => {
|
||||
// Since evaluation had no errors, validate the resulting constant.
|
||||
|
|
|
@ -258,6 +258,9 @@ impl<'tcx> fmt::Display for FrameInfo<'tcx> {
|
|||
{
|
||||
write!(f, "inside closure")?;
|
||||
} else {
|
||||
// Note: this triggers a `good_path_bug` state, which means that if we ever get here
|
||||
// we must emit a diagnostic. We should never display a `FrameInfo` unless we
|
||||
// actually want to emit a warning or error to the user.
|
||||
write!(f, "inside `{}`", self.instance)?;
|
||||
}
|
||||
if !self.span.is_dummy() {
|
||||
|
|
|
@ -332,8 +332,6 @@ pub enum InternKind {
|
|||
///
|
||||
/// This *cannot raise an interpreter error*. Doing so is left to validation, which
|
||||
/// tracks where in the value we are and thus can show much better error messages.
|
||||
/// Any errors here would anyway be turned into `const_err` lints, whereas validation failures
|
||||
/// are hard errors.
|
||||
#[instrument(level = "debug", skip(ecx))]
|
||||
pub fn intern_const_alloc_recursive<
|
||||
'mir,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue