Skip to content

Commit 353b915

Browse files
authored
Rollup merge of #104317 - RalfJung:ctfe-error-reporting, r=oli-obk
cleanup and dedupe CTFE and Miri error reporting It looks like most of the time, this error raised from const_prop_lint is just redundant -- it duplicates the error reported when evaluating the const-eval query. This lets us make `ConstEvalErr` private to the const_eval module which I think is a good step. The Miri change mostly replaces a `match` by `if let`, and dedupes the "this error is impossible in Miri" checks. r? ``@oli-obk`` Fixes #75461
2 parents fbcd751 + 1115ec6 commit 353b915

File tree

105 files changed

+708
-585
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

105 files changed

+708
-585
lines changed

compiler/rustc_codegen_cranelift/src/constant.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
4747
if let Err(err) = fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) {
4848
all_constants_ok = false;
4949
match err {
50-
ErrorHandled::Reported(_) | ErrorHandled::Linted => {
50+
ErrorHandled::Reported(_) => {
5151
fx.tcx.sess.span_err(constant.span, "erroneous constant encountered");
5252
}
5353
ErrorHandled::TooGeneric => {

compiler/rustc_codegen_ssa/src/mir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
189189
all_consts_ok = false;
190190
match err {
191191
// errored or at least linted
192-
ErrorHandled::Reported(_) | ErrorHandled::Linted => {}
192+
ErrorHandled::Reported(_) => {}
193193
ErrorHandled::TooGeneric => {
194194
span_bug!(const_.span, "codegen encountered polymorphic constant: {:?}", err)
195195
}

compiler/rustc_const_eval/src/const_eval/error.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ impl Error for ConstEvalErrKind {}
5555
/// When const-evaluation errors, this type is constructed with the resulting information,
5656
/// and then used to emit the error as a lint or hard error.
5757
#[derive(Debug)]
58-
pub struct ConstEvalErr<'tcx> {
58+
pub(super) struct ConstEvalErr<'tcx> {
5959
pub span: Span,
6060
pub error: InterpError<'tcx>,
6161
pub stacktrace: Vec<FrameInfo<'tcx>>,
@@ -82,8 +82,8 @@ impl<'tcx> ConstEvalErr<'tcx> {
8282
ConstEvalErr { error: error.into_kind(), stacktrace, span }
8383
}
8484

85-
pub fn report_as_error(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
86-
self.struct_error(tcx, message, |_| {})
85+
pub(super) fn report(&self, tcx: TyCtxtAt<'tcx>, message: &str) -> ErrorHandled {
86+
self.report_decorated(tcx, message, |_| {})
8787
}
8888

8989
/// Create a diagnostic for this const eval error.
@@ -95,7 +95,7 @@ impl<'tcx> ConstEvalErr<'tcx> {
9595
/// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
9696
/// (Except that for some errors, we ignore all that -- see `must_error` below.)
9797
#[instrument(skip(self, tcx, decorate), level = "debug")]
98-
pub fn struct_error(
98+
pub(super) fn report_decorated(
9999
&self,
100100
tcx: TyCtxtAt<'tcx>,
101101
message: &str,

compiler/rustc_const_eval/src/const_eval/eval_queries.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
255255
return eval_nullary_intrinsic(tcx, key.param_env, def_id, substs).map_err(|error| {
256256
let span = tcx.def_span(def_id);
257257
let error = ConstEvalErr { error: error.into_kind(), stacktrace: vec![], span };
258-
error.report_as_error(tcx.at(span), "could not evaluate nullary intrinsic")
258+
error.report(tcx.at(span), "could not evaluate nullary intrinsic")
259259
});
260260
}
261261

@@ -333,7 +333,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
333333
}
334334
};
335335

336-
Err(err.report_as_error(ecx.tcx.at(err.span), &msg))
336+
Err(err.report(ecx.tcx.at(err.span), &msg))
337337
}
338338
Ok(mplace) => {
339339
// Since evaluation had no errors, validate the resulting constant.
@@ -358,7 +358,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
358358
if let Err(error) = validation {
359359
// Validation failed, report an error. This is always a hard error.
360360
let err = ConstEvalErr::new(&ecx, error, None);
361-
Err(err.struct_error(
361+
Err(err.report_decorated(
362362
ecx.tcx,
363363
"it is undefined behavior to use this value",
364364
|diag| {

compiler/rustc_const_eval/src/const_eval/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
103103
) -> InterpResult<'tcx, mir::DestructuredConstant<'tcx>> {
104104
trace!("destructure_mir_constant: {:?}", val);
105105
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
106-
let op = ecx.const_to_op(&val, None)?;
106+
let op = ecx.eval_mir_constant(&val, None, None)?;
107107

108108
// We go to `usize` as we cannot allocate anything bigger anyway.
109109
let (field_count, variant, down) = match val.ty().kind() {
@@ -139,7 +139,7 @@ pub(crate) fn deref_mir_constant<'tcx>(
139139
val: mir::ConstantKind<'tcx>,
140140
) -> mir::ConstantKind<'tcx> {
141141
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
142-
let op = ecx.const_to_op(&val, None).unwrap();
142+
let op = ecx.eval_mir_constant(&val, None, None).unwrap();
143143
let mplace = ecx.deref_operand(&op).unwrap();
144144
if let Some(alloc_id) = mplace.ptr.provenance {
145145
assert_eq!(

compiler/rustc_const_eval/src/interpret/eval_context.rs

+27-10
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::mem;
55
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
66
use rustc_index::vec::IndexVec;
77
use rustc_middle::mir;
8-
use rustc_middle::mir::interpret::{InterpError, InvalidProgramInfo};
8+
use rustc_middle::mir::interpret::{ErrorHandled, InterpError, InvalidProgramInfo};
99
use rustc_middle::ty::layout::{
1010
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
1111
TyAndLayout,
@@ -696,12 +696,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
696696
for ct in &body.required_consts {
697697
let span = ct.span;
698698
let ct = self.subst_from_current_frame_and_normalize_erasing_regions(ct.literal)?;
699-
self.const_to_op(&ct, None).map_err(|err| {
700-
// If there was an error, set the span of the current frame to this constant.
701-
// Avoiding doing this when evaluation succeeds.
702-
self.frame_mut().loc = Err(span);
703-
err
704-
})?;
699+
self.eval_mir_constant(&ct, Some(span), None)?;
705700
}
706701

707702
// Most locals are initially dead.
@@ -912,9 +907,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
912907
Ok(())
913908
}
914909

915-
pub fn eval_to_allocation(
910+
/// Call a query that can return `ErrorHandled`. If `span` is `Some`, point to that span when an error occurs.
911+
pub fn ctfe_query<T>(
912+
&self,
913+
span: Option<Span>,
914+
query: impl FnOnce(TyCtxtAt<'tcx>) -> Result<T, ErrorHandled>,
915+
) -> InterpResult<'tcx, T> {
916+
// Use a precise span for better cycle errors.
917+
query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| {
918+
match err {
919+
ErrorHandled::Reported(err) => {
920+
if let Some(span) = span {
921+
// To make it easier to figure out where this error comes from, also add a note at the current location.
922+
self.tcx.sess.span_note_without_error(span, "erroneous constant used");
923+
}
924+
err_inval!(AlreadyReported(err))
925+
}
926+
ErrorHandled::TooGeneric => err_inval!(TooGeneric),
927+
}
928+
.into()
929+
})
930+
}
931+
932+
pub fn eval_global(
916933
&self,
917934
gid: GlobalId<'tcx>,
935+
span: Option<Span>,
918936
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
919937
// For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
920938
// and thus don't care about the parameter environment. While we could just use
@@ -927,8 +945,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
927945
self.param_env
928946
};
929947
let param_env = param_env.with_const();
930-
// Use a precise span for better cycle errors.
931-
let val = self.tcx.at(self.cur_span()).eval_to_allocation_raw(param_env.and(gid))?;
948+
let val = self.ctfe_query(span, |tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?;
932949
self.raw_const_to_mplace(val)
933950
}
934951

compiler/rustc_const_eval/src/interpret/intrinsics.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -177,8 +177,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
177177
sym::type_name => self.tcx.mk_static_str(),
178178
_ => bug!(),
179179
};
180-
let val =
181-
self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?;
180+
let val = self.ctfe_query(None, |tcx| {
181+
tcx.const_eval_global_id(self.param_env, gid, Some(tcx.span))
182+
})?;
182183
let val = self.const_val_to_op(val, ty, Some(dest.layout))?;
183184
self.copy_op(&val, dest, /*allow_transmute*/ false)?;
184185
}

compiler/rustc_const_eval/src/interpret/memory.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -501,8 +501,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
501501
throw_unsup!(ReadExternStatic(def_id));
502502
}
503503

504-
// Use a precise span for better cycle errors.
505-
(self.tcx.at(self.cur_span()).eval_static_initializer(def_id)?, Some(def_id))
504+
// We don't give a span -- statics don't need that, they cannot be generic or associated.
505+
let val = self.ctfe_query(None, |tcx| tcx.eval_static_initializer(def_id))?;
506+
(val, Some(def_id))
506507
}
507508
};
508509
M::before_access_global(*self.tcx, &self.machine, id, alloc, def_id, is_write)?;

compiler/rustc_const_eval/src/interpret/operand.rs

+37-34
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
use rustc_hir::def::Namespace;
55
use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
66
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
7-
use rustc_middle::ty::{ConstInt, Ty};
7+
use rustc_middle::ty::{ConstInt, Ty, ValTree};
88
use rustc_middle::{mir, ty};
9+
use rustc_span::Span;
910
use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size, TagEncoding};
1011
use rustc_target::abi::{VariantIdx, Variants};
1112

@@ -527,14 +528,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
527528
Copy(place) | Move(place) => self.eval_place_to_op(place, layout)?,
528529

529530
Constant(ref constant) => {
530-
let val =
531+
let c =
531532
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?;
532533

533534
// This can still fail:
534535
// * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
535536
// checked yet.
536537
// * During CTFE, since promoteds in `const`/`static` initializer bodies can fail.
537-
self.const_to_op(&val, layout)?
538+
self.eval_mir_constant(&c, Some(constant.span), layout)?
538539
}
539540
};
540541
trace!("{:?}: {:?}", mir_op, *op);
@@ -549,9 +550,35 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
549550
ops.iter().map(|op| self.eval_operand(op, None)).collect()
550551
}
551552

552-
pub fn const_to_op(
553+
fn eval_ty_constant(
554+
&self,
555+
val: ty::Const<'tcx>,
556+
span: Option<Span>,
557+
) -> InterpResult<'tcx, ValTree<'tcx>> {
558+
Ok(match val.kind() {
559+
ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => {
560+
throw_inval!(TooGeneric)
561+
}
562+
ty::ConstKind::Error(reported) => {
563+
throw_inval!(AlreadyReported(reported))
564+
}
565+
ty::ConstKind::Unevaluated(uv) => {
566+
let instance = self.resolve(uv.def, uv.substs)?;
567+
let cid = GlobalId { instance, promoted: None };
568+
self.ctfe_query(span, |tcx| tcx.eval_to_valtree(self.param_env.and(cid)))?
569+
.unwrap_or_else(|| bug!("unable to create ValTree for {uv:?}"))
570+
}
571+
ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => {
572+
span_bug!(self.cur_span(), "unexpected ConstKind in ctfe: {val:?}")
573+
}
574+
ty::ConstKind::Value(valtree) => valtree,
575+
})
576+
}
577+
578+
pub fn eval_mir_constant(
553579
&self,
554580
val: &mir::ConstantKind<'tcx>,
581+
span: Option<Span>,
555582
layout: Option<TyAndLayout<'tcx>>,
556583
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
557584
// FIXME(const_prop): normalization needed b/c const prop lint in
@@ -563,44 +590,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
563590
let val = self.tcx.normalize_erasing_regions(self.param_env, *val);
564591
match val {
565592
mir::ConstantKind::Ty(ct) => {
566-
match ct.kind() {
567-
ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => {
568-
throw_inval!(TooGeneric)
569-
}
570-
ty::ConstKind::Error(reported) => {
571-
throw_inval!(AlreadyReported(reported))
572-
}
573-
ty::ConstKind::Unevaluated(uv) => {
574-
// NOTE: We evaluate to a `ValTree` here as a check to ensure
575-
// we're working with valid constants, even though we never need it.
576-
let instance = self.resolve(uv.def, uv.substs)?;
577-
let cid = GlobalId { instance, promoted: None };
578-
let _valtree = self
579-
.tcx
580-
.eval_to_valtree(self.param_env.and(cid))?
581-
.unwrap_or_else(|| bug!("unable to create ValTree for {uv:?}"));
582-
583-
Ok(self.eval_to_allocation(cid)?.into())
584-
}
585-
ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => {
586-
span_bug!(self.cur_span(), "unexpected ConstKind in ctfe: {ct:?}")
587-
}
588-
ty::ConstKind::Value(valtree) => {
589-
let ty = ct.ty();
590-
let const_val = self.tcx.valtree_to_const_val((ty, valtree));
591-
self.const_val_to_op(const_val, ty, layout)
592-
}
593-
}
593+
let ty = ct.ty();
594+
let valtree = self.eval_ty_constant(ct, span)?;
595+
let const_val = self.tcx.valtree_to_const_val((ty, valtree));
596+
self.const_val_to_op(const_val, ty, layout)
594597
}
595598
mir::ConstantKind::Val(val, ty) => self.const_val_to_op(val, ty, layout),
596599
mir::ConstantKind::Unevaluated(uv, _) => {
597600
let instance = self.resolve(uv.def, uv.substs)?;
598-
Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into())
601+
Ok(self.eval_global(GlobalId { instance, promoted: uv.promoted }, span)?.into())
599602
}
600603
}
601604
}
602605

603-
pub(crate) fn const_val_to_op(
606+
pub(super) fn const_val_to_op(
604607
&self,
605608
val_val: ConstValue<'tcx>,
606609
ty: Ty<'tcx>,

compiler/rustc_middle/src/mir/interpret/error.rs

+4-19
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ pub enum ErrorHandled {
1616
/// Already reported an error for this evaluation, and the compilation is
1717
/// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
1818
Reported(ErrorGuaranteed),
19-
/// Already emitted a lint for this evaluation.
20-
Linted,
2119
/// Don't emit an error, the evaluation failed because the MIR was generic
2220
/// and the substs didn't fully monomorphize it.
2321
TooGeneric,
@@ -89,18 +87,6 @@ fn print_backtrace(backtrace: &Backtrace) {
8987
eprintln!("\n\nAn error occurred in miri:\n{}", backtrace);
9088
}
9189

92-
impl From<ErrorHandled> for InterpErrorInfo<'_> {
93-
fn from(err: ErrorHandled) -> Self {
94-
match err {
95-
ErrorHandled::Reported(ErrorGuaranteed { .. }) | ErrorHandled::Linted => {
96-
err_inval!(ReferencedConstant)
97-
}
98-
ErrorHandled::TooGeneric => err_inval!(TooGeneric),
99-
}
100-
.into()
101-
}
102-
}
103-
10490
impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
10591
fn from(err: ErrorGuaranteed) -> Self {
10692
InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err)).into()
@@ -138,9 +124,6 @@ impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
138124
pub enum InvalidProgramInfo<'tcx> {
139125
/// Resolution can fail if we are in a too generic context.
140126
TooGeneric,
141-
/// Cannot compute this constant because it depends on another one
142-
/// which already produced an error.
143-
ReferencedConstant,
144127
/// Abort in case errors are already reported.
145128
AlreadyReported(ErrorGuaranteed),
146129
/// An error occurred during layout computation.
@@ -158,9 +141,11 @@ impl fmt::Display for InvalidProgramInfo<'_> {
158141
use InvalidProgramInfo::*;
159142
match self {
160143
TooGeneric => write!(f, "encountered overly generic constant"),
161-
ReferencedConstant => write!(f, "referenced constant has errors"),
162144
AlreadyReported(ErrorGuaranteed { .. }) => {
163-
write!(f, "encountered constants with type errors, stopping evaluation")
145+
write!(
146+
f,
147+
"an error has already been reported elsewhere (this sould not usually be printed)"
148+
)
164149
}
165150
Layout(ref err) => write!(f, "{err}"),
166151
FnAbiAdjustForForeignAbi(ref err) => write!(f, "{err}"),

compiler/rustc_middle/src/mir/interpret/queries.rs

+4
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,8 @@ impl<'tcx> TyCtxt<'tcx> {
175175

176176
impl<'tcx> TyCtxtAt<'tcx> {
177177
/// Evaluate a static's initializer, returning the allocation of the initializer's memory.
178+
///
179+
/// The span is entirely ignored here, but still helpful for better query cycle errors.
178180
pub fn eval_static_initializer(
179181
self,
180182
def_id: DefId,
@@ -187,6 +189,8 @@ impl<'tcx> TyCtxtAt<'tcx> {
187189
}
188190

189191
/// Evaluate anything constant-like, returning the allocation of the final memory.
192+
///
193+
/// The span is entirely ignored here, but still helpful for better query cycle errors.
190194
fn eval_to_allocation(
191195
self,
192196
gid: GlobalId<'tcx>,

compiler/rustc_middle/src/mir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2304,7 +2304,7 @@ impl<'tcx> ConstantKind<'tcx> {
23042304
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
23052305
match tcx.const_eval_resolve(param_env, uneval, None) {
23062306
Ok(val) => Self::Val(val, ty),
2307-
Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => self,
2307+
Err(ErrorHandled::TooGeneric) => self,
23082308
Err(ErrorHandled::Reported(guar)) => {
23092309
Self::Ty(tcx.const_error_with_guaranteed(ty, guar))
23102310
}

compiler/rustc_middle/src/ty/adt.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -463,9 +463,7 @@ impl<'tcx> AdtDef<'tcx> {
463463
}
464464
Err(err) => {
465465
let msg = match err {
466-
ErrorHandled::Reported(_) | ErrorHandled::Linted => {
467-
"enum discriminant evaluation failed"
468-
}
466+
ErrorHandled::Reported(_) => "enum discriminant evaluation failed",
469467
ErrorHandled::TooGeneric => "enum discriminant depends on generics",
470468
};
471469
tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg);

0 commit comments

Comments
 (0)