Skip to content

Suppress errors in const eval during trait selection #92653

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

Closed
wants to merge 12 commits into from
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