1
Fork 0

move required_consts check to general post-mono-check function

This commit is contained in:
Ralf Jung 2023-09-11 09:52:45 +02:00
parent ccf817b9bb
commit 89ac57db4d
40 changed files with 319 additions and 257 deletions

View file

@ -2,6 +2,7 @@
use rustc_ast::InlineAsmOptions; use rustc_ast::InlineAsmOptions;
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::adjustment::PointerCoercion;
use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::print::with_no_trimmed_paths;
@ -250,12 +251,21 @@ pub(crate) fn verify_func(
} }
fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
if !crate::constant::check_constants(fx) { match fx.mir.post_mono_checks(fx.tcx, ty::ParamEnv::reveal_all(), |c| Ok(fx.monomorphize(c))) {
fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]); Ok(()) => {}
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]); Err(ErrorHandled::TooGeneric(span)) => {
// compilation should have been aborted span_bug!(span, "codegen encountered polymorphic constant");
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); }
return; Err(ErrorHandled::Reported(info, span)) => {
if !info.is_tainted_by_errors() {
fx.tcx.sess.span_err(span, "erroneous constant encountered");
}
fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
fx.bcx.switch_to_block(fx.block_map[START_BLOCK]);
// compilation should have been aborted
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
return;
}
} }
let arg_uninhabited = fx let arg_uninhabited = fx

View file

@ -2,9 +2,7 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::interpret::{ use rustc_middle::mir::interpret::{read_target_uint, AllocId, ConstValue, GlobalAlloc, Scalar};
read_target_uint, AllocId, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
};
use cranelift_module::*; use cranelift_module::*;
@ -33,16 +31,6 @@ impl ConstantCx {
} }
} }
pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
let mut all_constants_ok = true;
for constant in &fx.mir.required_consts {
if eval_mir_constant(fx, constant).is_none() {
all_constants_ok = false;
}
}
all_constants_ok
}
pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) { pub(crate) fn codegen_static(tcx: TyCtxt<'_>, module: &mut dyn Module, def_id: DefId) {
let mut constants_cx = ConstantCx::new(); let mut constants_cx = ConstantCx::new();
constants_cx.todo.push(TodoItem::Static(def_id)); constants_cx.todo.push(TodoItem::Static(def_id));
@ -76,30 +64,20 @@ pub(crate) fn codegen_tls_ref<'tcx>(
pub(crate) fn eval_mir_constant<'tcx>( pub(crate) fn eval_mir_constant<'tcx>(
fx: &FunctionCx<'_, '_, 'tcx>, fx: &FunctionCx<'_, '_, 'tcx>,
constant: &Constant<'tcx>, constant: &Constant<'tcx>,
) -> Option<(ConstValue<'tcx>, Ty<'tcx>)> { ) -> (ConstValue<'tcx>, Ty<'tcx>) {
let cv = fx.monomorphize(constant.literal); let cv = fx.monomorphize(constant.literal);
// This cannot fail because we checked all required_consts in advance.
let val = cv let val = cv
.eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span)) .eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
.map_err(|err| match err { .expect("erroneous constant not captured by required_consts");
ErrorHandled::Reported(_) => { (val, cv.ty())
fx.tcx.sess.span_err(constant.span, "erroneous constant encountered");
}
ErrorHandled::TooGeneric => {
span_bug!(constant.span, "codegen encountered polymorphic constant: {:?}", err);
}
})
.ok();
val.map(|val| (val, cv.ty()))
} }
pub(crate) fn codegen_constant_operand<'tcx>( pub(crate) fn codegen_constant_operand<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>, fx: &mut FunctionCx<'_, '_, 'tcx>,
constant: &Constant<'tcx>, constant: &Constant<'tcx>,
) -> CValue<'tcx> { ) -> CValue<'tcx> {
let (const_val, ty) = eval_mir_constant(fx, constant).unwrap_or_else(|| { let (const_val, ty) = eval_mir_constant(fx, constant);
span_bug!(constant.span, "erroneous constant not captured by required_consts")
});
codegen_const_value(fx, const_val, ty) codegen_const_value(fx, const_val, ty)
} }
@ -459,7 +437,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
operand: &Operand<'tcx>, operand: &Operand<'tcx>,
) -> Option<ConstValue<'tcx>> { ) -> Option<ConstValue<'tcx>> {
match operand { match operand {
Operand::Constant(const_) => Some(eval_mir_constant(fx, const_).unwrap().0), Operand::Constant(const_) => Some(eval_mir_constant(fx, const_).0),
// FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored
// inside a temporary before being passed to the intrinsic requiring the const argument. // inside a temporary before being passed to the intrinsic requiring the const argument.
// This code tries to find a single constant defining definition of the referenced local. // This code tries to find a single constant defining definition of the referenced local.

View file

@ -242,8 +242,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
} }
} }
InlineAsmOperand::Const { ref value } => { InlineAsmOperand::Const { ref value } => {
let (const_value, ty) = crate::constant::eval_mir_constant(fx, value) let (const_value, ty) = crate::constant::eval_mir_constant(fx, value);
.unwrap_or_else(|| span_bug!(span, "asm const cannot be resolved"));
let value = rustc_codegen_ssa::common::asm_const_to_str( let value = rustc_codegen_ssa::common::asm_const_to_str(
fx.tcx, fx.tcx,
span, span,

View file

@ -1088,9 +1088,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
InlineAsmOperandRef::InOut { reg, late, in_value, out_place } InlineAsmOperandRef::InOut { reg, late, in_value, out_place }
} }
mir::InlineAsmOperand::Const { ref value } => { mir::InlineAsmOperand::Const { ref value } => {
let const_value = self let const_value = self.eval_mir_constant(value);
.eval_mir_constant(value)
.unwrap_or_else(|_| span_bug!(span, "asm const cannot be resolved"));
let string = common::asm_const_to_str( let string = common::asm_const_to_str(
bx.tcx(), bx.tcx(),
span, span,

View file

@ -14,34 +14,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
&self, &self,
bx: &mut Bx, bx: &mut Bx,
constant: &mir::Constant<'tcx>, constant: &mir::Constant<'tcx>,
) -> Result<OperandRef<'tcx, Bx::Value>, ErrorHandled> { ) -> OperandRef<'tcx, Bx::Value> {
let val = self.eval_mir_constant(constant)?; let val = self.eval_mir_constant(constant);
let ty = self.monomorphize(constant.ty()); let ty = self.monomorphize(constant.ty());
Ok(OperandRef::from_const(bx, val, ty)) OperandRef::from_const(bx, val, ty)
} }
pub fn eval_mir_constant( pub fn eval_mir_constant(&self, constant: &mir::Constant<'tcx>) -> ConstValue<'tcx> {
&self,
constant: &mir::Constant<'tcx>,
) -> Result<ConstValue<'tcx>, ErrorHandled> {
self.monomorphize(constant.literal) self.monomorphize(constant.literal)
.eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span)) .eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
.map_err(|err| { .expect("erroneous constant not captured by required_consts")
match err {
ErrorHandled::Reported(_) => {
self.cx
.tcx()
.sess
.emit_err(errors::ErroneousConstant { span: constant.span });
}
ErrorHandled::TooGeneric => {
self.cx.tcx().sess.diagnostic().emit_bug(
errors::PolymorphicConstantTooGeneric { span: constant.span },
);
}
}
err
})
} }
/// This is a convenience helper for `simd_shuffle_indices`. It has the precondition /// This is a convenience helper for `simd_shuffle_indices`. It has the precondition

View file

@ -579,23 +579,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if let Some(dbg_var) = dbg_var { if let Some(dbg_var) = dbg_var {
let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue }; let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) { let operand = self.eval_mir_constant_to_operand(bx, &c);
self.set_debug_loc(bx, var.source_info); self.set_debug_loc(bx, var.source_info);
let base = Self::spill_operand_to_stack( let base =
operand, Self::spill_operand_to_stack(operand, Some(var.name.to_string()), bx);
Some(var.name.to_string()),
bx,
);
bx.dbg_var_addr( bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, Size::ZERO, &[], fragment);
dbg_var,
dbg_loc,
base.llval,
Size::ZERO,
&[],
fragment,
);
}
} }
} }
} }

View file

@ -1,4 +1,5 @@
use crate::base; use crate::base;
use crate::errors;
use crate::traits::*; use crate::traits::*;
use rustc_index::bit_set::BitSet; use rustc_index::bit_set::BitSet;
use rustc_index::IndexVec; use rustc_index::IndexVec;
@ -212,24 +213,21 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx); fx.per_local_var_debug_info = fx.compute_per_local_var_debug_info(&mut start_bx);
// Evaluate all required consts; codegen later assumes that CTFE will never fail. // Rust post-monomorphization checks; we later rely on them.
let mut all_consts_ok = true; match mir.post_mono_checks(cx.tcx(), ty::ParamEnv::reveal_all(), |c| Ok(fx.monomorphize(c))) {
for const_ in &mir.required_consts { Ok(()) => {}
if let Err(err) = fx.eval_mir_constant(const_) { Err(ErrorHandled::TooGeneric(span)) => {
all_consts_ok = false; cx.tcx().sess.diagnostic().emit_bug(errors::PolymorphicConstantTooGeneric { span });
match err { }
// errored or at least linted Err(ErrorHandled::Reported(info, span)) => {
ErrorHandled::Reported(_) => {} if !info.is_tainted_by_errors() {
ErrorHandled::TooGeneric => { cx.tcx().sess.emit_err(errors::ErroneousConstant { span });
span_bug!(const_.span, "codegen encountered polymorphic constant: {:?}", err) }
} // This IR shouldn't ever be emitted, but let's try to guard against any of this code
} // ever running.
start_bx.abort();
return;
} }
}
if !all_consts_ok {
// We leave the IR in some half-built state here, and rely on this code not even being
// submitted to LLVM once an error was raised.
return;
} }
let memory_locals = analyze::non_ssa_locals(&fx); let memory_locals = analyze::non_ssa_locals(&fx);

View file

@ -575,12 +575,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.codegen_consume(bx, place.as_ref()) self.codegen_consume(bx, place.as_ref())
} }
mir::Operand::Constant(ref constant) => { mir::Operand::Constant(ref constant) => self.eval_mir_constant_to_operand(bx, constant),
// This cannot fail because we checked all required_consts in advance.
self.eval_mir_constant_to_operand(bx, constant).unwrap_or_else(|_err| {
span_bug!(constant.span, "erroneous constant not captured by required_consts")
})
}
} }
} }
} }

View file

@ -4,7 +4,7 @@ use rustc_errors::{DiagnosticArgValue, DiagnosticMessage, IntoDiagnostic, IntoDi
use rustc_middle::mir::AssertKind; use rustc_middle::mir::AssertKind;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::{layout::LayoutError, ConstInt}; use rustc_middle::ty::{layout::LayoutError, ConstInt};
use rustc_span::{ErrorGuaranteed, Span, Symbol}; use rustc_span::{ErrorGuaranteed, Span, Symbol, DUMMY_SP};
use super::InterpCx; use super::InterpCx;
use crate::errors::{self, FrameNote, ReportErrorExt}; use crate::errors::{self, FrameNote, ReportErrorExt};
@ -134,11 +134,11 @@ where
// Don't emit a new diagnostic for these errors, they are already reported elsewhere or // Don't emit a new diagnostic for these errors, they are already reported elsewhere or
// should remain silent. // should remain silent.
err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => {
ErrorHandled::TooGeneric ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))
} }
err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar), err_inval!(AlreadyReported(guar)) => ErrorHandled::Reported(guar, span.unwrap_or(DUMMY_SP)),
err_inval!(Layout(LayoutError::ReferencesError(guar))) => { err_inval!(Layout(LayoutError::ReferencesError(guar))) => {
ErrorHandled::Reported(guar.into()) ErrorHandled::Reported(guar.into(), span.unwrap_or(DUMMY_SP))
} }
// Report remaining errors. // Report remaining errors.
_ => { _ => {
@ -152,7 +152,7 @@ where
// Use *our* span to label the interp error // Use *our* span to label the interp error
err.span_label(our_span, msg); err.span_label(our_span, msg);
ErrorHandled::Reported(err.emit().into()) ErrorHandled::Reported(err.emit().into(), span)
} }
} }
} }

View file

@ -212,7 +212,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
key.param_env = key.param_env.with_user_facing(); key.param_env = key.param_env.with_user_facing();
match tcx.eval_to_const_value_raw(key) { match tcx.eval_to_const_value_raw(key) {
// try again with reveal all as requested // try again with reveal all as requested
Err(ErrorHandled::TooGeneric) => {} Err(ErrorHandled::TooGeneric(_)) => {}
// deduplicate calls // deduplicate calls
other => return other, other => return other,
} }
@ -259,7 +259,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
key.param_env = key.param_env.with_user_facing(); key.param_env = key.param_env.with_user_facing();
match tcx.eval_to_allocation_raw(key) { match tcx.eval_to_allocation_raw(key) {
// try again with reveal all as requested // try again with reveal all as requested
Err(ErrorHandled::TooGeneric) => {} Err(ErrorHandled::TooGeneric(_)) => {}
// deduplicate calls // deduplicate calls
other => return other, other => return other,
} }

View file

@ -7,7 +7,7 @@ use hir::CRATE_HIR_ID;
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
use rustc_index::IndexVec; use rustc_index::IndexVec;
use rustc_middle::mir; use rustc_middle::mir;
use rustc_middle::mir::interpret::{ErrorHandled, InterpError, InvalidMetaKind, ReportedErrorInfo}; use rustc_middle::mir::interpret::{ErrorHandled, InvalidMetaKind, ReportedErrorInfo};
use rustc_middle::query::TyCtxtAt; use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{ use rustc_middle::ty::layout::{
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
@ -21,7 +21,7 @@ use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayou
use super::{ use super::{
AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, AllocId, GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace,
MemPlaceMeta, Memory, MemoryKind, Operand, Place, PlaceTy, Pointer, PointerArithmetic, MemPlaceMeta, Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic,
Projectable, Provenance, Scalar, StackPopJump, Projectable, Provenance, Scalar, StackPopJump,
}; };
use crate::errors::{self, ErroneousConstUsed}; use crate::errors::{self, ErroneousConstUsed};
@ -556,7 +556,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
>( >(
&self, &self,
value: T, value: T,
) -> Result<T, InterpError<'tcx>> { ) -> Result<T, ErrorHandled> {
self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value) self.subst_from_frame_and_normalize_erasing_regions(self.frame(), value)
} }
@ -566,7 +566,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
&self, &self,
frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>, frame: &Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>,
value: T, value: T,
) -> Result<T, InterpError<'tcx>> { ) -> Result<T, ErrorHandled> {
frame frame
.instance .instance
.try_subst_mir_and_normalize_erasing_regions( .try_subst_mir_and_normalize_erasing_regions(
@ -574,7 +574,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.param_env, self.param_env,
ty::EarlyBinder::bind(value), ty::EarlyBinder::bind(value),
) )
.map_err(|_| err_inval!(TooGeneric)) .map_err(|_| ErrorHandled::TooGeneric(self.cur_span()))
} }
/// The `args` are assumed to already be in our interpreter "universe" (param_env). /// The `args` are assumed to already be in our interpreter "universe" (param_env).
@ -750,11 +750,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Make sure all the constants required by this frame evaluate successfully (post-monomorphization check). // Make sure all the constants required by this frame evaluate successfully (post-monomorphization check).
if M::POST_MONO_CHECKS { if M::POST_MONO_CHECKS {
for ct in &body.required_consts { // `ctfe_query` does some error message decoration that we want to be in effect here.
let span = ct.span; self.ctfe_query(None, |tcx| {
let ct = self.subst_from_current_frame_and_normalize_erasing_regions(ct.literal)?; body.post_mono_checks(*tcx, self.param_env, |c| {
self.eval_mir_constant(&ct, Some(span), None)?; self.subst_from_current_frame_and_normalize_erasing_regions(c)
} })
})?;
} }
// done // done
@ -1059,28 +1060,29 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
&self, &self,
span: Option<Span>, span: Option<Span>,
query: impl FnOnce(TyCtxtAt<'tcx>) -> Result<T, ErrorHandled>, query: impl FnOnce(TyCtxtAt<'tcx>) -> Result<T, ErrorHandled>,
) -> InterpResult<'tcx, T> { ) -> Result<T, ErrorHandled> {
// Use a precise span for better cycle errors. // Use a precise span for better cycle errors.
query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| { query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| {
match err { match err {
ErrorHandled::Reported(err) => { ErrorHandled::Reported(err, reported_span) => {
if !err.is_tainted_by_errors() && let Some(span) = span { // We trust the provided span more than the one that came out of the query.
let span = span.unwrap_or(reported_span);
if !err.is_tainted_by_errors() {
// To make it easier to figure out where this error comes from, also add a note at the current location. // To make it easier to figure out where this error comes from, also add a note at the current location.
self.tcx.sess.emit_note(ErroneousConstUsed { span }); self.tcx.sess.emit_note(ErroneousConstUsed { span });
} }
err_inval!(AlreadyReported(err))
} }
ErrorHandled::TooGeneric => err_inval!(TooGeneric), ErrorHandled::TooGeneric(_) => {}
} }
.into() err
}) })
} }
pub fn eval_global( pub fn eval_global(
&self, &self,
gid: GlobalId<'tcx>, instance: ty::Instance<'tcx>,
span: Option<Span>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> { ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
let gid = GlobalId { instance, promoted: None };
// For statics we pick `ParamEnv::reveal_all`, because statics don't have generics // For statics we pick `ParamEnv::reveal_all`, because statics don't have generics
// and thus don't care about the parameter environment. While we could just use // and thus don't care about the parameter environment. While we could just use
// `self.param_env`, that would mean we invoke the query to evaluate the static // `self.param_env`, that would mean we invoke the query to evaluate the static
@ -1091,10 +1093,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} else { } else {
self.param_env self.param_env
}; };
let val = self.ctfe_query(span, |tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?; let val = self.ctfe_query(None, |tcx| tcx.eval_to_allocation_raw(param_env.and(gid)))?;
self.raw_const_to_mplace(val) self.raw_const_to_mplace(val)
} }
pub fn eval_mir_constant(
&self,
val: &mir::ConstantKind<'tcx>,
span: Option<Span>,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
let const_val = self.ctfe_query(span, |tcx| val.eval(*tcx, self.param_env, span))?;
self.const_val_to_op(const_val, val.ty(), layout)
}
#[must_use] #[must_use]
pub fn dump_place( pub fn dump_place(
&self, &self,

View file

@ -8,15 +8,14 @@ use either::{Either, Left, Right};
use rustc_hir::def::Namespace; use rustc_hir::def::Namespace;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
use rustc_middle::ty::{ConstInt, Ty, ValTree}; use rustc_middle::ty::{ConstInt, Ty};
use rustc_middle::{mir, ty}; use rustc_middle::{mir, ty};
use rustc_span::Span;
use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size}; use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size};
use super::{ use super::{
alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, GlobalId, alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, Frame, InterpCx,
InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, PlaceTy, Pointer, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, PlaceTy, Pointer, Projectable,
Projectable, Provenance, Scalar, Provenance, Scalar,
}; };
/// An `Immediate` represents a single immediate self-contained Rust value. /// An `Immediate` represents a single immediate self-contained Rust value.
@ -693,54 +692,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ok(op) Ok(op)
} }
fn eval_ty_constant(
&self,
val: ty::Const<'tcx>,
span: Option<Span>,
) -> InterpResult<'tcx, ValTree<'tcx>> {
Ok(match val.kind() {
ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => {
throw_inval!(TooGeneric)
}
// FIXME(generic_const_exprs): `ConstKind::Expr` should be able to be evaluated
ty::ConstKind::Expr(_) => throw_inval!(TooGeneric),
ty::ConstKind::Error(reported) => {
throw_inval!(AlreadyReported(reported.into()))
}
ty::ConstKind::Unevaluated(uv) => {
let instance = self.resolve(uv.def, uv.args)?;
let cid = GlobalId { instance, promoted: None };
self.ctfe_query(span, |tcx| tcx.eval_to_valtree(self.param_env.and(cid)))?
.unwrap_or_else(|| bug!("unable to create ValTree for {uv:?}"))
}
ty::ConstKind::Bound(..) | ty::ConstKind::Infer(..) => {
span_bug!(self.cur_span(), "unexpected ConstKind in ctfe: {val:?}")
}
ty::ConstKind::Value(valtree) => valtree,
})
}
pub fn eval_mir_constant(
&self,
val: &mir::ConstantKind<'tcx>,
span: Option<Span>,
layout: Option<TyAndLayout<'tcx>>,
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
match *val {
mir::ConstantKind::Ty(ct) => {
let ty = ct.ty();
let valtree = self.eval_ty_constant(ct, span)?;
let const_val = self.tcx.valtree_to_const_val((ty, valtree));
self.const_val_to_op(const_val, ty, layout)
}
mir::ConstantKind::Val(val, ty) => self.const_val_to_op(val, ty, layout),
mir::ConstantKind::Unevaluated(uv, _) => {
let instance = self.resolve(uv.def, uv.args)?;
Ok(self.eval_global(GlobalId { instance, promoted: uv.promoted }, span)?.into())
}
}
}
pub(crate) fn const_val_to_op( pub(crate) fn const_val_to_op(
&self, &self,
val_val: ConstValue<'tcx>, val_val: ConstValue<'tcx>,

View file

@ -1596,9 +1596,12 @@ impl<'tcx> InferCtxt<'tcx> {
if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? { if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? {
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, args)); let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, args));
if let Err(e) = ct.error_reported() { if let Err(e) = ct.error_reported() {
return Err(ErrorHandled::Reported(e.into())); return Err(ErrorHandled::Reported(
e.into(),
span.unwrap_or(rustc_span::DUMMY_SP),
));
} else if ct.has_non_region_infer() || ct.has_non_region_param() { } else if ct.has_non_region_infer() || ct.has_non_region_param() {
return Err(ErrorHandled::TooGeneric); return Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP)));
} else { } else {
args = replace_param_and_infer_args_with_placeholder(tcx, args); args = replace_param_and_infer_args_with_placeholder(tcx, args);
} }

View file

@ -11,7 +11,7 @@ use rustc_errors::{
}; };
use rustc_macros::HashStable; use rustc_macros::HashStable;
use rustc_session::CtfeBacktrace; use rustc_session::CtfeBacktrace;
use rustc_span::def_id::DefId; use rustc_span::{def_id::DefId, Span, DUMMY_SP};
use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange}; use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange};
use std::borrow::Cow; use std::borrow::Cow;
@ -21,16 +21,25 @@ use std::{any::Any, backtrace::Backtrace, fmt};
pub enum ErrorHandled { pub enum ErrorHandled {
/// Already reported an error for this evaluation, and the compilation is /// Already reported an error for this evaluation, and the compilation is
/// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`. /// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
Reported(ReportedErrorInfo), Reported(ReportedErrorInfo, Span),
/// Don't emit an error, the evaluation failed because the MIR was generic /// Don't emit an error, the evaluation failed because the MIR was generic
/// and the args didn't fully monomorphize it. /// and the args didn't fully monomorphize it.
TooGeneric, TooGeneric(Span),
} }
impl From<ErrorGuaranteed> for ErrorHandled { impl From<ErrorGuaranteed> for ErrorHandled {
#[inline] #[inline]
fn from(error: ErrorGuaranteed) -> ErrorHandled { fn from(error: ErrorGuaranteed) -> ErrorHandled {
ErrorHandled::Reported(error.into()) ErrorHandled::Reported(error.into(), DUMMY_SP)
}
}
impl ErrorHandled {
pub fn with_span(self, span: Span) -> Self {
match self {
ErrorHandled::Reported(err, _span) => ErrorHandled::Reported(err, span),
ErrorHandled::TooGeneric(_span) => ErrorHandled::TooGeneric(span),
}
} }
} }
@ -162,6 +171,16 @@ impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
} }
} }
impl From<ErrorHandled> for InterpErrorInfo<'_> {
fn from(err: ErrorHandled) -> Self {
InterpError::InvalidProgram(match err {
ErrorHandled::Reported(r, _span) => InvalidProgramInfo::AlreadyReported(r),
ErrorHandled::TooGeneric(_span) => InvalidProgramInfo::TooGeneric,
})
.into()
}
}
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> { impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
fn from(kind: InterpError<'tcx>) -> Self { fn from(kind: InterpError<'tcx>) -> Self {
InterpErrorInfo(Box::new(InterpErrorInfoInner { InterpErrorInfo(Box::new(InterpErrorInfoInner {

View file

@ -61,8 +61,8 @@ impl<'tcx> TyCtxt<'tcx> {
let cid = GlobalId { instance, promoted: ct.promoted }; let cid = GlobalId { instance, promoted: ct.promoted };
self.const_eval_global_id(param_env, cid, span) self.const_eval_global_id(param_env, cid, span)
} }
Ok(None) => Err(ErrorHandled::TooGeneric), Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))),
Err(err) => Err(ErrorHandled::Reported(err.into())), Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(DUMMY_SP))),
} }
} }
@ -117,8 +117,8 @@ impl<'tcx> TyCtxt<'tcx> {
} }
}) })
} }
Ok(None) => Err(ErrorHandled::TooGeneric), Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))),
Err(err) => Err(ErrorHandled::Reported(err.into())), Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(DUMMY_SP))),
} }
} }

View file

@ -565,6 +565,37 @@ impl<'tcx> Body<'tcx> {
pub fn is_custom_mir(&self) -> bool { pub fn is_custom_mir(&self) -> bool {
self.injection_phase.is_some() self.injection_phase.is_some()
} }
/// *Must* be called once the full substitution for this body is known, to ensure that the body
/// is indeed fit for code generation or consumption more generally.
///
/// Sadly there's no nice way to represent an "arbitrary normalizer", so we take one for
/// constants specifically. (`Option<GenericArgsRef>` could be used for that, but the fact
/// that `Instance::args_for_mir_body` is private and instead instance exposes normalization
/// functions makes it seem like exposing the generic args is not the intended strategy.)
///
/// Also sadly, CTFE doesn't even know whether it runs on MIR that is already polymorphic or still monomorphic,
/// so we cannot just immediately ICE on TooGeneric.
///
/// Returns Ok(()) if everything went fine, and `Err` if a problem occurred and got reported.
pub fn post_mono_checks(
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
normalize_const: impl Fn(ConstantKind<'tcx>) -> Result<ConstantKind<'tcx>, ErrorHandled>,
) -> Result<(), ErrorHandled> {
// For now, the only thing we have to check is is to ensure that all the constants used in
// the body successfully evaluate.
for &const_ in &self.required_consts {
let c = normalize_const(const_.literal)?;
c.eval(tcx, param_env, Some(const_.span)).map_err(|e| {
// The query results don't always have the span we want.
e.with_span(const_.span)
})?;
}
Ok(())
}
} }
#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)] #[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
@ -2397,10 +2428,10 @@ impl<'tcx> ConstantKind<'tcx> {
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self { pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
match self.eval(tcx, param_env, None) { match self.eval(tcx, param_env, None) {
Ok(val) => Self::Val(val, self.ty()), Ok(val) => Self::Val(val, self.ty()),
Err(ErrorHandled::Reported(guar)) => { Err(ErrorHandled::Reported(guar, _span)) => {
Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty())) Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty()))
} }
Err(ErrorHandled::TooGeneric) => self, Err(ErrorHandled::TooGeneric(_span)) => self,
} }
} }

View file

@ -478,8 +478,8 @@ impl<'tcx> AdtDef<'tcx> {
} }
Err(err) => { Err(err) => {
let msg = match err { let msg = match err {
ErrorHandled::Reported(_) => "enum discriminant evaluation failed", ErrorHandled::Reported(..) => "enum discriminant evaluation failed",
ErrorHandled::TooGeneric => "enum discriminant depends on generics", ErrorHandled::TooGeneric(..) => "enum discriminant depends on generics",
}; };
tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg); tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg);
None None

View file

@ -300,7 +300,7 @@ impl<'tcx> Const<'tcx> {
| ConstKind::Infer(_) | ConstKind::Infer(_)
| ConstKind::Bound(_, _) | ConstKind::Bound(_, _)
| ConstKind::Placeholder(_) | ConstKind::Placeholder(_)
| ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric), | ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))),
} }
} }
@ -309,8 +309,8 @@ impl<'tcx> Const<'tcx> {
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self { pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
match self.eval(tcx, param_env, None) { match self.eval(tcx, param_env, None) {
Ok(val) => Self::new_value(tcx, val, self.ty()), Ok(val) => Self::new_value(tcx, val, self.ty()),
Err(ErrorHandled::Reported(r)) => Self::new_error(tcx, r.into(), self.ty()), Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into(), self.ty()),
Err(ErrorHandled::TooGeneric) => self, Err(ErrorHandled::TooGeneric(_span)) => self,
} }
} }

View file

@ -566,7 +566,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
pattern pattern
} }
} }
Err(ErrorHandled::TooGeneric) => { Err(ErrorHandled::TooGeneric(_)) => {
// While `Reported | Linted` cases will have diagnostics emitted already // While `Reported | Linted` cases will have diagnostics emitted already
// it is not true for TooGeneric case, so we need to give user more information. // it is not true for TooGeneric case, so we need to give user more information.
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
@ -640,14 +640,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
.kind .kind
} else { } else {
// If that fails, convert it to an opaque constant pattern. // If that fails, convert it to an opaque constant pattern.
match tcx.const_eval_resolve(self.param_env, uneval, None) { match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
Ok(val) => self.const_to_pat(mir::ConstantKind::Val(val, ty), id, span, None).kind, Ok(val) => self.const_to_pat(mir::ConstantKind::Val(val, ty), id, span, None).kind,
Err(ErrorHandled::TooGeneric) => { Err(ErrorHandled::TooGeneric(_)) => {
// If we land here it means the const can't be evaluated because it's `TooGeneric`. // If we land here it means the const can't be evaluated because it's `TooGeneric`.
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
PatKind::Wild PatKind::Wild
} }
Err(ErrorHandled::Reported(_)) => PatKind::Wild, Err(ErrorHandled::Reported(..)) => PatKind::Wild,
} }
} }
} }

View file

@ -752,8 +752,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
let param_env = ty::ParamEnv::reveal_all(); let param_env = ty::ParamEnv::reveal_all();
let val = match literal.eval(self.tcx, param_env, None) { let val = match literal.eval(self.tcx, param_env, None) {
Ok(v) => v, Ok(v) => v,
Err(ErrorHandled::Reported(_)) => return, Err(ErrorHandled::Reported(..)) => return,
Err(ErrorHandled::TooGeneric) => span_bug!( Err(ErrorHandled::TooGeneric(..)) => span_bug!(
self.body.source_info(location).span, self.body.source_info(location).span,
"collection encountered polymorphic constant: {:?}", "collection encountered polymorphic constant: {:?}",
literal literal

View file

@ -949,8 +949,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::interpret::ErrorHandled;
match self.infcx.try_const_eval_resolve(param_env, unevaluated, ty, None) { match self.infcx.try_const_eval_resolve(param_env, unevaluated, ty, None) {
Ok(ct) => Some(ct), Ok(ct) => Some(ct),
Err(ErrorHandled::Reported(e)) => Some(ty::Const::new_error(self.tcx(), e.into(), ty)), Err(ErrorHandled::Reported(e, _)) => {
Err(ErrorHandled::TooGeneric) => None, Some(ty::Const::new_error(self.tcx(), e.into(), ty))
}
Err(ErrorHandled::TooGeneric(_)) => None,
} }
} }

View file

@ -793,7 +793,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
span: tcx.def_span(unevaluated.def), span: tcx.def_span(unevaluated.def),
unevaluated: unevaluated, unevaluated: unevaluated,
}); });
Err(ErrorHandled::Reported(reported.into())) Err(ErrorHandled::Reported(reported.into(), tcx.def_span(unevaluated.def)))
} }
Err(err) => Err(err), Err(err) => Err(err),
} }

View file

@ -73,13 +73,13 @@ pub fn is_const_evaluatable<'tcx>(
ty::ConstKind::Unevaluated(uv) => { ty::ConstKind::Unevaluated(uv) => {
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span)); let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
match concrete { match concrete {
Err(ErrorHandled::TooGeneric) => { Err(ErrorHandled::TooGeneric(_)) => {
Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug( Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
span, span,
"Missing value for constant, but no error reported?", "Missing value for constant, but no error reported?",
))) )))
} }
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())), Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())),
Ok(_) => Ok(()), Ok(_) => Ok(()),
} }
} }
@ -132,7 +132,7 @@ pub fn is_const_evaluatable<'tcx>(
.emit() .emit()
} }
Err(ErrorHandled::TooGeneric) => { Err(ErrorHandled::TooGeneric(_)) => {
let err = if uv.has_non_region_infer() { let err = if uv.has_non_region_infer() {
NotConstEvaluatable::MentionsInfer NotConstEvaluatable::MentionsInfer
} else if uv.has_non_region_param() { } else if uv.has_non_region_param() {
@ -147,7 +147,7 @@ pub fn is_const_evaluatable<'tcx>(
Err(err) Err(err)
} }
Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())), Err(ErrorHandled::Reported(e, _)) => Err(NotConstEvaluatable::Error(e.into())),
Ok(_) => Ok(()), Ok(_) => Ok(()),
} }
} }

View file

@ -560,30 +560,31 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
let stalled_on = &mut pending_obligation.stalled_on; let stalled_on = &mut pending_obligation.stalled_on;
let mut evaluate = let mut evaluate = |c: Const<'tcx>| {
|c: Const<'tcx>| { if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() { match self.selcx.infcx.try_const_eval_resolve(
match self.selcx.infcx.try_const_eval_resolve( obligation.param_env,
obligation.param_env, unevaluated,
unevaluated, c.ty(),
c.ty(), Some(obligation.cause.span),
Some(obligation.cause.span), ) {
) { Ok(val) => Ok(val),
Ok(val) => Ok(val), Err(e) => {
Err(e) => match e { match e {
ErrorHandled::TooGeneric => { ErrorHandled::TooGeneric(..) => {
stalled_on.extend(unevaluated.args.iter().filter_map( stalled_on.extend(unevaluated.args.iter().filter_map(
TyOrConstInferVar::maybe_from_generic_arg, TyOrConstInferVar::maybe_from_generic_arg,
)); ));
Err(ErrorHandled::TooGeneric)
} }
_ => Err(e), _ => {}
}, }
Err(e)
} }
} else {
Ok(c)
} }
}; } else {
Ok(c)
}
};
match (evaluate(c1), evaluate(c2)) { match (evaluate(c1), evaluate(c2)) {
(Ok(c1), Ok(c2)) => { (Ok(c1), Ok(c2)) => {
@ -603,13 +604,14 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
), ),
} }
} }
(Err(ErrorHandled::Reported(reported)), _) (Err(ErrorHandled::Reported(reported, _)), _)
| (_, Err(ErrorHandled::Reported(reported))) => ProcessResult::Error( | (_, Err(ErrorHandled::Reported(reported, _))) => ProcessResult::Error(
CodeSelectionError(SelectionError::NotConstEvaluatable( CodeSelectionError(SelectionError::NotConstEvaluatable(
NotConstEvaluatable::Error(reported.into()), NotConstEvaluatable::Error(reported.into()),
)), )),
), ),
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { (Err(ErrorHandled::TooGeneric(_)), _)
| (_, Err(ErrorHandled::TooGeneric(_))) => {
if c1.has_non_region_infer() || c2.has_non_region_infer() { if c1.has_non_region_infer() || c2.has_non_region_infer() {
ProcessResult::Unchanged ProcessResult::Unchanged
} else { } else {

View file

@ -989,9 +989,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Err(_) => Ok(EvaluatedToErr), Err(_) => Ok(EvaluatedToErr),
} }
} }
(Err(ErrorHandled::Reported(_)), _) (Err(ErrorHandled::Reported(..)), _)
| (_, Err(ErrorHandled::Reported(_))) => Ok(EvaluatedToErr), | (_, Err(ErrorHandled::Reported(..))) => Ok(EvaluatedToErr),
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { (Err(ErrorHandled::TooGeneric(..)), _)
| (_, Err(ErrorHandled::TooGeneric(..))) => {
if c1.has_non_region_infer() || c2.has_non_region_infer() { if c1.has_non_region_infer() || c2.has_non_region_infer() {
Ok(EvaluatedToAmbig) Ok(EvaluatedToAmbig)
} else { } else {

View file

@ -204,7 +204,7 @@ fn is_value_unfrozen_raw<'tcx>(
// similar to 2., but with the a frozen variant) (e.g. borrowing // similar to 2., but with the a frozen variant) (e.g. borrowing
// `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`). // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`).
// I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none). // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
err == ErrorHandled::TooGeneric matches!(err, ErrorHandled::TooGeneric(..))
}, },
|val| val.map_or(true, |val| inner(cx, val, ty)), |val| val.map_or(true, |val| inner(cx, val, ty)),
) )
@ -244,8 +244,8 @@ pub fn const_eval_resolve<'tcx>(
}; };
tcx.const_eval_global_id_for_typeck(param_env, cid, span) tcx.const_eval_global_id_for_typeck(param_env, cid, span)
}, },
Ok(None) => Err(ErrorHandled::TooGeneric), Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP))),
Err(err) => Err(ErrorHandled::Reported(err.into())), Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(rustc_span::DUMMY_SP))),
} }
} }

View file

@ -142,9 +142,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn eval_path_scalar(&self, path: &[&str]) -> Scalar<Provenance> { fn eval_path_scalar(&self, path: &[&str]) -> Scalar<Provenance> {
let this = self.eval_context_ref(); let this = self.eval_context_ref();
let instance = this.resolve_path(path, Namespace::ValueNS); let instance = this.resolve_path(path, Namespace::ValueNS);
let cid = GlobalId { instance, promoted: None };
// We don't give a span -- this isn't actually used directly by the program anyway. // We don't give a span -- this isn't actually used directly by the program anyway.
let const_val = this.eval_global(cid, None).unwrap_or_else(|err| { let const_val = this.eval_global(instance).unwrap_or_else(|err| {
panic!("failed to evaluate required Rust item: {path:?}\n{err:?}") panic!("failed to evaluate required Rust item: {path:?}\n{err:?}")
}); });
this.read_scalar(&const_val) this.read_scalar(&const_val)

View file

@ -3,7 +3,7 @@
// Cyclic assoc. const defaults don't error unless *used* // Cyclic assoc. const defaults don't error unless *used*
trait Tr { trait Tr {
const A: u8 = Self::B; const A: u8 = Self::B;
//~^ cycle detected when const-evaluating + checking `Tr::A` //~^ cycle detected
const B: u8 = Self::A; const B: u8 = Self::A;
} }

View file

@ -1,15 +1,25 @@
error[E0391]: cycle detected when const-evaluating + checking `Tr::A` error[E0391]: cycle detected when simplifying constant for the type system `Tr::A`
--> $DIR/defaults-cyclic-fail.rs:5:5
|
LL | const A: u8 = Self::B;
| ^^^^^^^^^^^
|
note: ...which requires const-evaluating + checking `Tr::A`...
--> $DIR/defaults-cyclic-fail.rs:5:19 --> $DIR/defaults-cyclic-fail.rs:5:19
| |
LL | const A: u8 = Self::B; LL | const A: u8 = Self::B;
| ^^^^^^^ | ^^^^^^^
note: ...which requires simplifying constant for the type system `Tr::B`...
--> $DIR/defaults-cyclic-fail.rs:8:5
| |
LL | const B: u8 = Self::A;
| ^^^^^^^^^^^
note: ...which requires const-evaluating + checking `Tr::B`... note: ...which requires const-evaluating + checking `Tr::B`...
--> $DIR/defaults-cyclic-fail.rs:8:19 --> $DIR/defaults-cyclic-fail.rs:8:19
| |
LL | const B: u8 = Self::A; LL | const B: u8 = Self::A;
| ^^^^^^^ | ^^^^^^^
= note: ...which again requires const-evaluating + checking `Tr::A`, completing the cycle = note: ...which again requires simplifying constant for the type system `Tr::A`, completing the cycle
note: cycle used when const-evaluating + checking `main::promoted[1]` note: cycle used when const-evaluating + checking `main::promoted[1]`
--> $DIR/defaults-cyclic-fail.rs:16:16 --> $DIR/defaults-cyclic-fail.rs:16:16
| |

View file

@ -4,7 +4,12 @@ error[E0391]: cycle detected when elaborating drops for `<impl at $DIR/issue-249
LL | const BAR: u32 = IMPL_REF_BAR; LL | const BAR: u32 = IMPL_REF_BAR;
| ^^^^^^^^^^^^ | ^^^^^^^^^^^^
| |
note: ...which requires const-evaluating + checking `IMPL_REF_BAR`... note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
|
LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
| |
LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
@ -14,6 +19,11 @@ note: ...which requires const-evaluating + checking `IMPL_REF_BAR`...
| |
LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
| ^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 11:19>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
|
LL | const BAR: u32 = IMPL_REF_BAR;
| ^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 11:19>::BAR`... note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 11:19>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
| |

View file

@ -4,7 +4,12 @@ error[E0391]: cycle detected when elaborating drops for `FooDefault::BAR`
LL | const BAR: u32 = DEFAULT_REF_BAR; LL | const BAR: u32 = DEFAULT_REF_BAR;
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
| |
note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`... note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1
|
LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1
| |
LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR; LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
@ -14,6 +19,11 @@ note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`...
| |
LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR; LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `FooDefault::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
|
LL | const BAR: u32 = DEFAULT_REF_BAR;
| ^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `FooDefault::BAR`... note: ...which requires const-evaluating + checking `FooDefault::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
| |

View file

@ -4,7 +4,12 @@ error[E0391]: cycle detected when elaborating drops for `<impl at $DIR/issue-249
LL | const BAR: u32 = TRAIT_REF_BAR; LL | const BAR: u32 = TRAIT_REF_BAR;
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
| |
note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`... note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1
|
LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1
| |
LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR; LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
@ -14,6 +19,11 @@ note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`...
| |
LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR; LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 11:28>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5
|
LL | const BAR: u32 = TRAIT_REF_BAR;
| ^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 11:28>::BAR`... note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 11:28>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5
| |

View file

@ -1,3 +1,9 @@
note: erroneous constant used
--> $DIR/issue-98629.rs:13:10
|
LL | [(); <i32 as Trait>::N]:,
| ^^^^^^^^^^^^^^^^^
error[E0046]: not all trait items implemented, missing: `N` error[E0046]: not all trait items implemented, missing: `N`
--> $DIR/issue-98629.rs:8:1 --> $DIR/issue-98629.rs:8:1
| |

View file

@ -1,15 +1,25 @@
error[E0391]: cycle detected when const-evaluating + checking `Foo::B::{constant#0}` error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{constant#0}`
--> $DIR/issue-36163.rs:4:9 --> $DIR/issue-36163.rs:4:9
| |
LL | B = A, LL | B = A,
| ^ | ^
| |
note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`...
--> $DIR/issue-36163.rs:4:9
|
LL | B = A,
| ^
note: ...which requires simplifying constant for the type system `A`...
--> $DIR/issue-36163.rs:1:1
|
LL | const A: isize = Foo::B as isize;
| ^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `A`... note: ...which requires const-evaluating + checking `A`...
--> $DIR/issue-36163.rs:1:18 --> $DIR/issue-36163.rs:1:18
| |
LL | const A: isize = Foo::B as isize; LL | const A: isize = Foo::B as isize;
| ^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^
= note: ...which again requires const-evaluating + checking `Foo::B::{constant#0}`, completing the cycle = note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle
note: cycle used when simplifying constant for the type system `Foo::B::{constant#0}` note: cycle used when simplifying constant for the type system `Foo::B::{constant#0}`
--> $DIR/issue-36163.rs:4:9 --> $DIR/issue-36163.rs:4:9
| |

View file

@ -10,6 +10,12 @@ note: type in trait
LL | const VALUE: usize; LL | const VALUE: usize;
| ^^^^^ | ^^^^^
note: erroneous constant used
--> $DIR/issue-70942-trait-vs-impl-mismatch.rs:13:18
|
LL | let _: [i32; Zero::VALUE] = [];
| ^^^^^^^^^^^
error: aborting due to previous error error: aborting due to previous error
For more information about this error, try `rustc --explain E0326`. For more information about this error, try `rustc --explain E0326`.

View file

@ -1,10 +1,15 @@
error[E0391]: cycle detected when const-evaluating + checking `FOO` error[E0391]: cycle detected when simplifying constant for the type system `FOO`
--> $DIR/issue-17252.rs:1:1
|
LL | const FOO: usize = FOO;
| ^^^^^^^^^^^^^^^^
|
note: ...which requires const-evaluating + checking `FOO`...
--> $DIR/issue-17252.rs:1:20 --> $DIR/issue-17252.rs:1:20
| |
LL | const FOO: usize = FOO; LL | const FOO: usize = FOO;
| ^^^ | ^^^
| = note: ...which again requires simplifying constant for the type system `FOO`, completing the cycle
= note: ...which immediately requires const-evaluating + checking `FOO` again
note: cycle used when const-evaluating + checking `main::{constant#0}` note: cycle used when const-evaluating + checking `main::{constant#0}`
--> $DIR/issue-17252.rs:4:18 --> $DIR/issue-17252.rs:4:18
| |

View file

@ -1,10 +1,15 @@
error[E0391]: cycle detected when const-evaluating + checking `X::A::{constant#0}` error[E0391]: cycle detected when simplifying constant for the type system `X::A::{constant#0}`
--> $DIR/issue-23302-1.rs:4:9 --> $DIR/issue-23302-1.rs:4:9
| |
LL | A = X::A as isize, LL | A = X::A as isize,
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
| |
= note: ...which immediately requires const-evaluating + checking `X::A::{constant#0}` again note: ...which requires const-evaluating + checking `X::A::{constant#0}`...
--> $DIR/issue-23302-1.rs:4:9
|
LL | A = X::A as isize,
| ^^^^^^^^^^^^^
= note: ...which again requires simplifying constant for the type system `X::A::{constant#0}`, completing the cycle
note: cycle used when simplifying constant for the type system `X::A::{constant#0}` note: cycle used when simplifying constant for the type system `X::A::{constant#0}`
--> $DIR/issue-23302-1.rs:4:9 --> $DIR/issue-23302-1.rs:4:9
| |

View file

@ -1,10 +1,15 @@
error[E0391]: cycle detected when const-evaluating + checking `Y::A::{constant#0}` error[E0391]: cycle detected when simplifying constant for the type system `Y::A::{constant#0}`
--> $DIR/issue-23302-2.rs:4:9 --> $DIR/issue-23302-2.rs:4:9
| |
LL | A = Y::B as isize, LL | A = Y::B as isize,
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
| |
= note: ...which immediately requires const-evaluating + checking `Y::A::{constant#0}` again note: ...which requires const-evaluating + checking `Y::A::{constant#0}`...
--> $DIR/issue-23302-2.rs:4:9
|
LL | A = Y::B as isize,
| ^^^^^^^^^^^^^
= note: ...which again requires simplifying constant for the type system `Y::A::{constant#0}`, completing the cycle
note: cycle used when simplifying constant for the type system `Y::A::{constant#0}` note: cycle used when simplifying constant for the type system `Y::A::{constant#0}`
--> $DIR/issue-23302-2.rs:4:9 --> $DIR/issue-23302-2.rs:4:9
| |

View file

@ -1,15 +1,25 @@
error[E0391]: cycle detected when const-evaluating + checking `A` error[E0391]: cycle detected when simplifying constant for the type system `A`
--> $DIR/issue-23302-3.rs:1:1
|
LL | const A: i32 = B;
| ^^^^^^^^^^^^
|
note: ...which requires const-evaluating + checking `A`...
--> $DIR/issue-23302-3.rs:1:16 --> $DIR/issue-23302-3.rs:1:16
| |
LL | const A: i32 = B; LL | const A: i32 = B;
| ^ | ^
note: ...which requires simplifying constant for the type system `B`...
--> $DIR/issue-23302-3.rs:3:1
| |
LL | const B: i32 = A;
| ^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `B`... note: ...which requires const-evaluating + checking `B`...
--> $DIR/issue-23302-3.rs:3:16 --> $DIR/issue-23302-3.rs:3:16
| |
LL | const B: i32 = A; LL | const B: i32 = A;
| ^ | ^
= note: ...which again requires const-evaluating + checking `A`, completing the cycle = note: ...which again requires simplifying constant for the type system `A`, completing the cycle
note: cycle used when simplifying constant for the type system `A` note: cycle used when simplifying constant for the type system `A`
--> $DIR/issue-23302-3.rs:1:1 --> $DIR/issue-23302-3.rs:1:1
| |

View file

@ -13,6 +13,12 @@ LL | type MyA: TraitA;
LL | impl TraitB for B { LL | impl TraitB for B {
| ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation | ^^^^^^^^^^^^^^^^^ missing `MyA` in implementation
note: erroneous constant used
--> $DIR/issue-69602-type-err-during-codegen-ice.rs:12:26
|
LL | const VALUE: usize = Self::MyA::VALUE;
| ^^^^^^^^^^^^^^^^
note: erroneous constant used note: erroneous constant used
--> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17 --> $DIR/issue-69602-type-err-during-codegen-ice.rs:21:17
| |