Skip to content
6 changes: 6 additions & 0 deletions compiler/rustc_codegen_cranelift/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
err
);
}
ErrorHandled::Silent(_) => {
span_bug!(
constant.span,
"codegen encountered silent error",
);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: &Alloca
cx.const_struct(&llvals, true)
}

pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, &'tcx Allocation), ErrorHandled> {
pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, &'tcx Allocation), ErrorHandled<'tcx>> {
let alloc = cx.tcx.eval_static_initializer(def_id)?;
Ok((const_alloc_to_gcc(cx, alloc), alloc))
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) ->
pub fn codegen_static_initializer<'ll, 'tcx>(
cx: &CodegenCx<'ll, 'tcx>,
def_id: DefId,
) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> {
) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled<'tcx>> {
let alloc = cx.tcx.eval_static_initializer(def_id)?;
Ok((const_alloc_to_llvm(cx, alloc), alloc))
}
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_ssa/src/mir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
&self,
bx: &mut Bx,
constant: &mir::Constant<'tcx>,
) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> {
) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled<'tcx>> {
let val = self.eval_mir_constant(constant)?;
let ty = self.monomorphize(constant.ty());
Ok(OperandRef::from_const(bx, val, ty))
Expand All @@ -23,7 +23,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
pub fn eval_mir_constant(
&self,
constant: &mir::Constant<'tcx>,
) -> Result<ConstValue<'tcx>, ErrorHandled> {
) -> Result<ConstValue<'tcx>, ErrorHandled<'tcx>> {
let ct = self.monomorphize(constant.literal);
let ct = match ct {
mir::ConstantKind::Ty(ct) => ct,
Expand Down Expand Up @@ -53,7 +53,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx: &Bx,
span: Span,
ty: Ty<'tcx>,
constant: Result<ConstValue<'tcx>, ErrorHandled>,
constant: Result<ConstValue<'tcx>, ErrorHandled<'tcx>>,
) -> (Bx::Value, Ty<'tcx>) {
constant
.map(|val| {
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,10 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
// errored or at least linted
ErrorHandled::Reported(ErrorReported) | ErrorHandled::Linted => {}
ErrorHandled::TooGeneric => {
span_bug!(const_.span, "codgen encountered polymorphic constant: {:?}", err)
span_bug!(const_.span, "codegen encountered polymorphic constant: {:?}", err)
}
ErrorHandled::Silent(_) => {
span_bug!(const_.span, "silent error during codegen")
}
}
}
Expand Down
138 changes: 12 additions & 126 deletions compiler/rustc_const_eval/src/const_eval/error.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
use std::error::Error;
use std::fmt;

use rustc_errors::{DiagnosticBuilder, ErrorReported};
use rustc_hir as hir;
use rustc_middle::mir::interpret::ConstEvalErr;
use rustc_middle::mir::AssertKind;
use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt};
use rustc_middle::ty::ConstInt;
use rustc_span::{Span, Symbol};

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

/// The CTFE machine has some custom error kinds.
#[derive(Clone, Debug)]
Expand Down Expand Up @@ -63,145 +60,34 @@ impl Error for ConstEvalErrKind {}
/// When const-evaluation errors, this type is constructed with the resulting information,
/// and then used to emit the error as a lint or hard error.
#[derive(Debug)]
pub struct ConstEvalErr<'tcx> {
pub span: Span,
pub error: InterpError<'tcx>,
pub stacktrace: Vec<FrameInfo<'tcx>>,
pub struct ConstEvalError<'tcx> {
inner: ConstEvalErr<'tcx>,
}

impl<'tcx> ConstEvalErr<'tcx> {
impl<'tcx> ConstEvalError<'tcx> {
/// Turn an interpreter error into something to report to the user.
/// As a side-effect, if RUSTC_CTFE_BACKTRACE is set, this prints the backtrace.
/// Should be called only if the error is actually going to to be reported!
pub fn new<'mir, M: Machine<'mir, 'tcx>>(
ecx: &InterpCx<'mir, 'tcx, M>,
error: InterpErrorInfo<'tcx>,
span: Option<Span>,
) -> ConstEvalErr<'tcx>
) -> ConstEvalError<'tcx>
where
'tcx: 'mir,
{
error.print_backtrace();
let stacktrace = ecx.generate_stacktrace();
ConstEvalErr {
let inner = ConstEvalErr {
error: error.into_kind(),
stacktrace,
span: span.unwrap_or_else(|| ecx.cur_span()),
}
}

pub fn struct_error(
&self,
tcx: TyCtxtAt<'tcx>,
message: &str,
emit: impl FnOnce(DiagnosticBuilder<'_>),
) -> ErrorHandled {
self.struct_generic(tcx, message, emit, None)
}

pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
self.struct_error(tcx, message, |mut e| e.emit())
}

pub fn report_as_lint(
&self,
tcx: TyCtxtAt<'tcx>,
message: &str,
lint_root: hir::HirId,
span: Option<Span>,
) -> ErrorHandled {
self.struct_generic(
tcx,
message,
|mut lint: DiagnosticBuilder<'_>| {
// 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, "");
}
}
}
lint.emit();
},
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
/// information before handing control back to `emit` to do any final processing.
/// It's the caller's responsibility to call emit(), stash(), etc. within the `emit`
/// function to dispose of the diagnostic properly.
///
/// 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.)
fn struct_generic(
&self,
tcx: TyCtxtAt<'tcx>,
message: &str,
emit: impl FnOnce(DiagnosticBuilder<'_>),
lint_root: Option<hir::HirId>,
) -> ErrorHandled {
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);
}
// Add spans for the stacktrace. Don't print a single-line backtrace though.
if self.stacktrace.len() > 1 {
for frame_info in &self.stacktrace {
err.span_label(frame_info.span, frame_info.to_string());
}
}
// Let the caller finish the job.
emit(err)
};

// 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);
}
_ => {}
};

let err_msg = self.error.to_string();
ConstEvalError { inner }
}

// 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)
}
pub fn into_inner(self) -> ConstEvalErr<'tcx> {
self.inner
}
}
Loading