Rollup merge of #72879 - RalfJung:miri-tctx-at, r=oli-obk

Miri: avoid tracking current location three times

Miri tracks the current instruction to execute in the call stack, but it also additionally has two `TyCtxtAt` that carry a `Span` that also tracks the current instruction. That is quite silly, so this PR uses `TyCtxt` instead, and then uses a method for computing the current span when a `TyCtxtAt` is needed. Having less redundant (semi-)global state seems like a good improvement to me. :D

To keep the ConstProp errors the same, I had to add the option to `error_to_const_error` to overwrite the span. Also for some reason this changes cycle errors a bit -- not sure if we are now better or worse as giving those queries the right span. (It is unfortunately quite easy to accidentally use `DUMMY_SP` by calling the query on a `TyCtxt` instead of a `TyCtxtAt`.)

r? @oli-obk @eddyb
This commit is contained in:
Ralf Jung 2020-06-15 12:01:01 +02:00 committed by GitHub
commit f9c8a67593
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 141 additions and 123 deletions

View File

@ -705,6 +705,7 @@ impl<'tcx> ty::TyS<'tcx> {
/// optimization as well as the rules around static values. Note /// optimization as well as the rules around static values. Note
/// that the `Freeze` trait is not exposed to end users and is /// that the `Freeze` trait is not exposed to end users and is
/// effectively an implementation detail. /// effectively an implementation detail.
// FIXME: use `TyCtxtAt` instead of separate `Span`.
pub fn is_freeze( pub fn is_freeze(
&'tcx self, &'tcx self,
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,

View File

@ -2,7 +2,7 @@ use std::error::Error;
use std::fmt; use std::fmt;
use rustc_middle::mir::AssertKind; use rustc_middle::mir::AssertKind;
use rustc_span::Symbol; use rustc_span::{Span, Symbol};
use super::InterpCx; use super::InterpCx;
use crate::interpret::{ConstEvalErr, InterpErrorInfo, Machine}; use crate::interpret::{ConstEvalErr, InterpErrorInfo, Machine};
@ -53,8 +53,9 @@ impl Error for ConstEvalErrKind {}
pub fn error_to_const_error<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>( pub fn error_to_const_error<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>(
ecx: &InterpCx<'mir, 'tcx, M>, ecx: &InterpCx<'mir, 'tcx, M>,
error: InterpErrorInfo<'tcx>, error: InterpErrorInfo<'tcx>,
span: Option<Span>,
) -> ConstEvalErr<'tcx> { ) -> ConstEvalErr<'tcx> {
error.print_backtrace(); error.print_backtrace();
let stacktrace = ecx.generate_stacktrace(); let stacktrace = ecx.generate_stacktrace();
ConstEvalErr { error: error.kind, stacktrace, span: ecx.tcx.span } ConstEvalErr { error: error.kind, stacktrace, span: span.unwrap_or_else(|| ecx.cur_span()) }
} }

View File

@ -27,7 +27,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
body: &'mir mir::Body<'tcx>, body: &'mir mir::Body<'tcx>,
) -> InterpResult<'tcx, MPlaceTy<'tcx>> { ) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env); debug!("eval_body_using_ecx: {:?}, {:?}", cid, ecx.param_env);
let tcx = ecx.tcx.tcx; let tcx = *ecx.tcx;
let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?; let layout = ecx.layout_of(body.return_ty().subst(tcx, cid.instance.substs))?;
assert!(!layout.is_unsized()); assert!(!layout.is_unsized());
let ret = ecx.allocate(layout, MemoryKind::Stack); let ret = ecx.allocate(layout, MemoryKind::Stack);
@ -81,13 +81,14 @@ fn eval_body_using_ecx<'mir, 'tcx>(
/// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument. /// parameter. These bounds are passed to `mk_eval_cx` via the `ParamEnv` argument.
pub(super) fn mk_eval_cx<'mir, 'tcx>( pub(super) fn mk_eval_cx<'mir, 'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
span: Span, root_span: Span,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
can_access_statics: bool, can_access_statics: bool,
) -> CompileTimeEvalContext<'mir, 'tcx> { ) -> CompileTimeEvalContext<'mir, 'tcx> {
debug!("mk_eval_cx: {:?}", param_env); debug!("mk_eval_cx: {:?}", param_env);
InterpCx::new( InterpCx::new(
tcx.at(span), tcx,
root_span,
param_env, param_env,
CompileTimeInterpreter::new(tcx.sess.const_eval_limit()), CompileTimeInterpreter::new(tcx.sess.const_eval_limit()),
MemoryExtra { can_access_statics }, MemoryExtra { can_access_statics },
@ -163,7 +164,7 @@ pub(super) fn op_to_const<'tcx>(
0, 0,
), ),
}; };
let len = b.to_machine_usize(&ecx.tcx.tcx).unwrap(); let len = b.to_machine_usize(ecx).unwrap();
let start = start.try_into().unwrap(); let start = start.try_into().unwrap();
let len: usize = len.try_into().unwrap(); let len: usize = len.try_into().unwrap();
ConstValue::Slice { data, start, end: start + len } ConstValue::Slice { data, start, end: start + len }
@ -212,7 +213,7 @@ fn validate_and_turn_into_const<'tcx>(
})(); })();
val.map_err(|error| { val.map_err(|error| {
let err = error_to_const_error(&ecx, error); let err = error_to_const_error(&ecx, error, None);
err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| { err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| {
diag.note(note_on_undefined_behavior_error()); diag.note(note_on_undefined_behavior_error());
diag.emit(); diag.emit();
@ -299,9 +300,9 @@ pub fn const_eval_raw_provider<'tcx>(
let is_static = tcx.is_static(def_id); let is_static = tcx.is_static(def_id);
let span = tcx.def_span(cid.instance.def_id());
let mut ecx = InterpCx::new( let mut ecx = InterpCx::new(
tcx.at(span), tcx,
tcx.def_span(cid.instance.def_id()),
key.param_env, key.param_env,
CompileTimeInterpreter::new(tcx.sess.const_eval_limit()), CompileTimeInterpreter::new(tcx.sess.const_eval_limit()),
MemoryExtra { can_access_statics: is_static }, MemoryExtra { can_access_statics: is_static },
@ -311,12 +312,15 @@ pub fn const_eval_raw_provider<'tcx>(
res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body))
.map(|place| RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty }) .map(|place| RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty })
.map_err(|error| { .map_err(|error| {
let err = error_to_const_error(&ecx, error); let err = error_to_const_error(&ecx, error, None);
// errors in statics are always emitted as fatal errors // errors in statics are always emitted as fatal errors
if is_static { if is_static {
// Ensure that if the above error was either `TooGeneric` or `Reported` // Ensure that if the above error was either `TooGeneric` or `Reported`
// an error must be reported. // an error must be reported.
let v = err.report_as_error(ecx.tcx, "could not evaluate static initializer"); let v = err.report_as_error(
ecx.tcx.at(ecx.cur_span()),
"could not evaluate static initializer",
);
// If this is `Reveal:All`, then we need to make sure an error is reported but if // If this is `Reveal:All`, then we need to make sure an error is reported but if
// this is `Reveal::UserFacing`, then it's expected that we could get a // this is `Reveal::UserFacing`, then it's expected that we could get a
@ -372,13 +376,16 @@ pub fn const_eval_raw_provider<'tcx>(
// anything else (array lengths, enum initializers, constant patterns) are // anything else (array lengths, enum initializers, constant patterns) are
// reported as hard errors // reported as hard errors
} else { } else {
err.report_as_error(ecx.tcx, "evaluation of constant value failed") err.report_as_error(
ecx.tcx.at(ecx.cur_span()),
"evaluation of constant value failed",
)
} }
} }
} }
} else { } else {
// use of broken constant from other crate // use of broken constant from other crate
err.report_as_error(ecx.tcx, "could not evaluate constant") err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant")
} }
}) })
} }

View File

@ -268,11 +268,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
(&ty::Array(_, length), &ty::Slice(_)) => { (&ty::Array(_, length), &ty::Slice(_)) => {
let ptr = self.read_immediate(src)?.to_scalar()?; let ptr = self.read_immediate(src)?.to_scalar()?;
// u64 cast is from usize to u64, which is always good // u64 cast is from usize to u64, which is always good
let val = Immediate::new_slice( let val =
ptr, Immediate::new_slice(ptr, length.eval_usize(*self.tcx, self.param_env), self);
length.eval_usize(self.tcx.tcx, self.param_env),
self,
);
self.write_immediate(val, dest) self.write_immediate(val, dest)
} }
(&ty::Dynamic(..), &ty::Dynamic(..)) => { (&ty::Dynamic(..), &ty::Dynamic(..)) => {

View File

@ -33,6 +33,8 @@ pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
pub machine: M, pub machine: M,
/// The results of the type checker, from rustc. /// The results of the type checker, from rustc.
/// The span in this is the "root" of the evaluation, i.e., the const
/// we are evaluating (if this is CTFE).
pub tcx: TyCtxtAt<'tcx>, pub tcx: TyCtxtAt<'tcx>,
/// Bounds in scope for polymorphic evaluations. /// Bounds in scope for polymorphic evaluations.
@ -202,7 +204,7 @@ where
} }
} }
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> { impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> LayoutOf for InterpCx<'mir, 'tcx, M> {
type Ty = Ty<'tcx>; type Ty = Ty<'tcx>;
type TyAndLayout = InterpResult<'tcx, TyAndLayout<'tcx>>; type TyAndLayout = InterpResult<'tcx, TyAndLayout<'tcx>>;
@ -285,14 +287,15 @@ pub(super) fn from_known_layout<'tcx>(
impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
pub fn new( pub fn new(
tcx: TyCtxtAt<'tcx>, tcx: TyCtxt<'tcx>,
root_span: Span,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
machine: M, machine: M,
memory_extra: M::MemoryExtra, memory_extra: M::MemoryExtra,
) -> Self { ) -> Self {
InterpCx { InterpCx {
machine, machine,
tcx, tcx: tcx.at(root_span),
param_env, param_env,
memory: Memory::new(tcx, memory_extra), memory: Memory::new(tcx, memory_extra),
vtables: FxHashMap::default(), vtables: FxHashMap::default(),
@ -300,9 +303,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} }
#[inline(always)] #[inline(always)]
pub fn set_span(&mut self, span: Span) { pub fn cur_span(&self) -> Span {
self.tcx.span = span; self.stack()
self.memory.tcx.span = span; .last()
.and_then(|f| f.current_source_info())
.map(|si| si.span)
.unwrap_or(self.tcx.span)
} }
#[inline(always)] #[inline(always)]
@ -385,7 +391,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
#[inline] #[inline]
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
ty.is_freeze(*self.tcx, self.param_env, DUMMY_SP) ty.is_freeze(*self.tcx, self.param_env, self.tcx.span)
} }
pub fn load_mir( pub fn load_mir(
@ -554,7 +560,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let size = size.align_to(align); let size = size.align_to(align);
// Check if this brought us over the size limit. // Check if this brought us over the size limit.
if size.bytes() >= self.tcx.data_layout().obj_size_bound() { if size.bytes() >= self.tcx.data_layout.obj_size_bound() {
throw_ub!(InvalidMeta("total size is bigger than largest supported object")); throw_ub!(InvalidMeta("total size is bigger than largest supported object"));
} }
Ok(Some((size, align))) Ok(Some((size, align)))
@ -570,7 +576,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let elem = layout.field(self, 0)?; let elem = layout.field(self, 0)?;
// Make sure the slice is not too big. // Make sure the slice is not too big.
let size = elem.size.checked_mul(len, &*self.tcx).ok_or_else(|| { let size = elem.size.checked_mul(len, self).ok_or_else(|| {
err_ub!(InvalidMeta("slice is bigger than largest supported object")) err_ub!(InvalidMeta("slice is bigger than largest supported object"))
})?; })?;
Ok(Some((size, elem.align.abi))) Ok(Some((size, elem.align.abi)))

View File

@ -111,7 +111,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx>>(
if let InternMode::Static(mutability) = mode { if let InternMode::Static(mutability) = mode {
// For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume // For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume
// no interior mutability. // no interior mutability.
let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx.tcx, ecx.param_env, ecx.tcx.span)); let frozen = ty.map_or(true, |ty| ty.is_freeze(*ecx.tcx, ecx.param_env, ecx.tcx.span));
// For statics, allocation mutability is the combination of the place mutability and // For statics, allocation mutability is the combination of the place mutability and
// the type mutability. // the type mutability.
// The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere. // The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere.
@ -253,8 +253,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir
// caused (by somehow getting a mutable reference in a `const`). // caused (by somehow getting a mutable reference in a `const`).
if ref_mutability == Mutability::Mut { if ref_mutability == Mutability::Mut {
match referenced_ty.kind { match referenced_ty.kind {
ty::Array(_, n) ty::Array(_, n) if n.eval_usize(*tcx, self.ecx.param_env) == 0 => {}
if n.eval_usize(tcx.tcx, self.ecx.param_env) == 0 => {}
ty::Slice(_) ty::Slice(_)
if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)? if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)?
== 0 => {} == 0 => {}

View File

@ -347,7 +347,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let index = u64::from(self.read_scalar(args[1])?.to_u32()?); let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
let elem = args[2]; let elem = args[2];
let input = args[0]; let input = args[0];
let (len, e_ty) = input.layout.ty.simd_size_and_type(self.tcx.tcx); let (len, e_ty) = input.layout.ty.simd_size_and_type(*self.tcx);
assert!( assert!(
index < len, index < len,
"Index `{}` must be in bounds of vector type `{}`: `[0, {})`", "Index `{}` must be in bounds of vector type `{}`: `[0, {})`",
@ -374,7 +374,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} }
sym::simd_extract => { sym::simd_extract => {
let index = u64::from(self.read_scalar(args[1])?.to_u32()?); let index = u64::from(self.read_scalar(args[1])?.to_u32()?);
let (len, e_ty) = args[0].layout.ty.simd_size_and_type(self.tcx.tcx); let (len, e_ty) = args[0].layout.ty.simd_size_and_type(*self.tcx);
assert!( assert!(
index < len, index < len,
"index `{}` is out-of-bounds of vector type `{}` with length `{}`", "index `{}` is out-of-bounds of vector type `{}` with length `{}`",

View File

@ -14,7 +14,7 @@ use std::ptr;
use rustc_ast::ast::Mutability; use rustc_ast::ast::Mutability;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_middle::ty::{self, query::TyCtxtAt, Instance, ParamEnv}; use rustc_middle::ty::{self, Instance, ParamEnv, TyCtxt};
use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout}; use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout};
use super::{ use super::{
@ -115,7 +115,7 @@ pub struct Memory<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
pub extra: M::MemoryExtra, pub extra: M::MemoryExtra,
/// Lets us implement `HasDataLayout`, which is awfully convenient. /// Lets us implement `HasDataLayout`, which is awfully convenient.
pub tcx: TyCtxtAt<'tcx>, pub tcx: TyCtxt<'tcx>,
} }
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M> { impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M> {
@ -126,7 +126,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M>
} }
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
pub fn new(tcx: TyCtxtAt<'tcx>, extra: M::MemoryExtra) -> Self { pub fn new(tcx: TyCtxt<'tcx>, extra: M::MemoryExtra) -> Self {
Memory { Memory {
alloc_map: M::MemoryMap::default(), alloc_map: M::MemoryMap::default(),
extra_fn_ptr_map: FxHashMap::default(), extra_fn_ptr_map: FxHashMap::default(),
@ -425,7 +425,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
/// `M::tag_allocation`. /// `M::tag_allocation`.
fn get_global_alloc( fn get_global_alloc(
memory_extra: &M::MemoryExtra, memory_extra: &M::MemoryExtra,
tcx: TyCtxtAt<'tcx>, tcx: TyCtxt<'tcx>,
id: AllocId, id: AllocId,
is_write: bool, is_write: bool,
) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::PointerTag, M::AllocExtra>>> { ) -> InterpResult<'tcx, Cow<'tcx, Allocation<M::PointerTag, M::AllocExtra>>> {
@ -455,7 +455,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
throw_unsup!(ReadForeignStatic(def_id)) throw_unsup!(ReadForeignStatic(def_id))
} }
trace!("get_global_alloc: Need to compute {:?}", def_id); trace!("get_global_alloc: Need to compute {:?}", def_id);
let instance = Instance::mono(tcx.tcx, def_id); let instance = Instance::mono(tcx, def_id);
let gid = GlobalId { instance, promoted: None }; let gid = GlobalId { instance, promoted: None };
// Use the raw query here to break validation cycles. Later uses of the static // Use the raw query here to break validation cycles. Later uses of the static
// will call the full query anyway. // will call the full query anyway.
@ -664,14 +664,14 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) { pub fn dump_allocs(&self, mut allocs: Vec<AllocId>) {
// Cannot be a closure because it is generic in `Tag`, `Extra`. // Cannot be a closure because it is generic in `Tag`, `Extra`.
fn write_allocation_track_relocs<'tcx, Tag: Copy + fmt::Debug, Extra>( fn write_allocation_track_relocs<'tcx, Tag: Copy + fmt::Debug, Extra>(
tcx: TyCtxtAt<'tcx>, tcx: TyCtxt<'tcx>,
allocs_to_print: &mut VecDeque<AllocId>, allocs_to_print: &mut VecDeque<AllocId>,
alloc: &Allocation<Tag, Extra>, alloc: &Allocation<Tag, Extra>,
) { ) {
for &(_, target_id) in alloc.relocations().values() { for &(_, target_id) in alloc.relocations().values() {
allocs_to_print.push_back(target_id); allocs_to_print.push_back(target_id);
} }
pretty::write_allocation(tcx.tcx, alloc, &mut std::io::stderr()).unwrap(); pretty::write_allocation(tcx, alloc, &mut std::io::stderr()).unwrap();
} }
allocs.sort(); allocs.sort();
@ -820,7 +820,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
return Ok(()); return Ok(());
} }
}; };
let tcx = self.tcx.tcx; let tcx = self.tcx;
self.get_raw_mut(ptr.alloc_id)?.write_bytes(&tcx, ptr, src) self.get_raw_mut(ptr.alloc_id)?.write_bytes(&tcx, ptr, src)
} }
@ -846,7 +846,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
return Ok(()); return Ok(());
} }
}; };
let tcx = self.tcx.tcx; let tcx = self.tcx;
let allocation = self.get_raw_mut(ptr.alloc_id)?; let allocation = self.get_raw_mut(ptr.alloc_id)?;
for idx in 0..len { for idx in 0..len {
@ -888,7 +888,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
let relocations = let relocations =
self.get_raw(src.alloc_id)?.prepare_relocation_copy(self, src, size, dest, length); self.get_raw(src.alloc_id)?.prepare_relocation_copy(self, src, size, dest, length);
let tcx = self.tcx.tcx; let tcx = self.tcx;
// This checks relocation edges on the src. // This checks relocation edges on the src.
let src_bytes = let src_bytes =

View File

@ -651,12 +651,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Convert discriminant to variant index, and catch invalid discriminants. // Convert discriminant to variant index, and catch invalid discriminants.
let index = match op.layout.ty.kind { let index = match op.layout.ty.kind {
ty::Adt(adt, _) => { ty::Adt(adt, _) => {
adt.discriminants(self.tcx.tcx).find(|(_, var)| var.val == discr_bits) adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits)
} }
ty::Generator(def_id, substs, _) => { ty::Generator(def_id, substs, _) => {
let substs = substs.as_generator(); let substs = substs.as_generator();
substs substs
.discriminants(def_id, self.tcx.tcx) .discriminants(def_id, *self.tcx)
.find(|(_, var)| var.val == discr_bits) .find(|(_, var)| var.val == discr_bits)
} }
_ => bug!("tagged layout for non-adt non-generator"), _ => bug!("tagged layout for non-adt non-generator"),

View File

@ -404,7 +404,10 @@ where
// to get some code to work that probably ought to work. // to get some code to work that probably ought to work.
field_layout.align.abi field_layout.align.abi
} }
None => bug!("Cannot compute offset for extern type field at non-0 offset"), None => span_bug!(
self.cur_span(),
"cannot compute offset for extern type field at non-0 offset"
),
}; };
(base.meta, offset.align_to(align)) (base.meta, offset.align_to(align))
} else { } else {
@ -440,7 +443,11 @@ where
assert!(!field_layout.is_unsized()); assert!(!field_layout.is_unsized());
base.offset(offset, MemPlaceMeta::None, field_layout, self) base.offset(offset, MemPlaceMeta::None, field_layout, self)
} }
_ => bug!("`mplace_index` called on non-array type {:?}", base.layout.ty), _ => span_bug!(
self.cur_span(),
"`mplace_index` called on non-array type {:?}",
base.layout.ty
),
} }
} }
@ -454,7 +461,7 @@ where
let len = base.len(self)?; // also asserts that we have a type where this makes sense let len = base.len(self)?; // also asserts that we have a type where this makes sense
let stride = match base.layout.fields { let stride = match base.layout.fields {
FieldsShape::Array { stride, .. } => stride, FieldsShape::Array { stride, .. } => stride,
_ => bug!("mplace_array_fields: expected an array layout"), _ => span_bug!(self.cur_span(), "mplace_array_fields: expected an array layout"),
}; };
let layout = base.layout.field(self, 0)?; let layout = base.layout.field(self, 0)?;
let dl = &self.tcx.data_layout; let dl = &self.tcx.data_layout;
@ -484,7 +491,9 @@ where
// (that have count 0 in their layout). // (that have count 0 in their layout).
let from_offset = match base.layout.fields { let from_offset = match base.layout.fields {
FieldsShape::Array { stride, .. } => stride * from, // `Size` multiplication is checked FieldsShape::Array { stride, .. } => stride * from, // `Size` multiplication is checked
_ => bug!("Unexpected layout of index access: {:#?}", base.layout), _ => {
span_bug!(self.cur_span(), "unexpected layout of index access: {:#?}", base.layout)
}
}; };
// Compute meta and new layout // Compute meta and new layout
@ -497,7 +506,9 @@ where
let len = Scalar::from_machine_usize(inner_len, self); let len = Scalar::from_machine_usize(inner_len, self);
(MemPlaceMeta::Meta(len), base.layout.ty) (MemPlaceMeta::Meta(len), base.layout.ty)
} }
_ => bug!("cannot subslice non-array type: `{:?}`", base.layout.ty), _ => {
span_bug!(self.cur_span(), "cannot subslice non-array type: `{:?}`", base.layout.ty)
}
}; };
let layout = self.layout_of(ty)?; let layout = self.layout_of(ty)?;
base.offset(from_offset, meta, layout, self) base.offset(from_offset, meta, layout, self)
@ -768,7 +779,7 @@ where
None => return Ok(()), // zero-sized access None => return Ok(()), // zero-sized access
}; };
let tcx = &*self.tcx; let tcx = *self.tcx;
// FIXME: We should check that there are dest.layout.size many bytes available in // FIXME: We should check that there are dest.layout.size many bytes available in
// memory. The code below is not sufficient, with enough padding it might not // memory. The code below is not sufficient, with enough padding it might not
// cover all the bytes! // cover all the bytes!
@ -776,12 +787,14 @@ where
Immediate::Scalar(scalar) => { Immediate::Scalar(scalar) => {
match dest.layout.abi { match dest.layout.abi {
Abi::Scalar(_) => {} // fine Abi::Scalar(_) => {} // fine
_ => { _ => span_bug!(
bug!("write_immediate_to_mplace: invalid Scalar layout: {:#?}", dest.layout) self.cur_span(),
} "write_immediate_to_mplace: invalid Scalar layout: {:#?}",
dest.layout
),
} }
self.memory.get_raw_mut(ptr.alloc_id)?.write_scalar( self.memory.get_raw_mut(ptr.alloc_id)?.write_scalar(
tcx, &tcx,
ptr, ptr,
scalar, scalar,
dest.layout.size, dest.layout.size,
@ -793,7 +806,8 @@ where
// which `ptr.offset(b_offset)` cannot possibly fail to satisfy. // which `ptr.offset(b_offset)` cannot possibly fail to satisfy.
let (a, b) = match dest.layout.abi { let (a, b) = match dest.layout.abi {
Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value), Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
_ => bug!( _ => span_bug!(
self.cur_span(),
"write_immediate_to_mplace: invalid ScalarPair layout: {:#?}", "write_immediate_to_mplace: invalid ScalarPair layout: {:#?}",
dest.layout dest.layout
), ),
@ -806,8 +820,8 @@ where
// but that does not work: We could be a newtype around a pair, then the // but that does not work: We could be a newtype around a pair, then the
// fields do not match the `ScalarPair` components. // fields do not match the `ScalarPair` components.
self.memory.get_raw_mut(ptr.alloc_id)?.write_scalar(tcx, ptr, a_val, a_size)?; self.memory.get_raw_mut(ptr.alloc_id)?.write_scalar(&tcx, ptr, a_val, a_size)?;
self.memory.get_raw_mut(b_ptr.alloc_id)?.write_scalar(tcx, b_ptr, b_val, b_size) self.memory.get_raw_mut(b_ptr.alloc_id)?.write_scalar(&tcx, b_ptr, b_val, b_size)
} }
} }
} }
@ -841,9 +855,9 @@ where
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
// We do NOT compare the types for equality, because well-typed code can // We do NOT compare the types for equality, because well-typed code can
// actually "transmute" `&mut T` to `&T` in an assignment without a cast. // actually "transmute" `&mut T` to `&T` in an assignment without a cast.
if !mir_assign_valid_types(self.tcx.tcx, src.layout, dest.layout) { if !mir_assign_valid_types(*self.tcx, src.layout, dest.layout) {
span_bug!( span_bug!(
self.tcx.span, self.cur_span(),
"type mismatch when copying!\nsrc: {:?},\ndest: {:?}", "type mismatch when copying!\nsrc: {:?},\ndest: {:?}",
src.layout.ty, src.layout.ty,
dest.layout.ty, dest.layout.ty,
@ -898,7 +912,7 @@ where
src: OpTy<'tcx, M::PointerTag>, src: OpTy<'tcx, M::PointerTag>,
dest: PlaceTy<'tcx, M::PointerTag>, dest: PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
if mir_assign_valid_types(self.tcx.tcx, src.layout, dest.layout) { if mir_assign_valid_types(*self.tcx, src.layout, dest.layout) {
// Fast path: Just use normal `copy_op` // Fast path: Just use normal `copy_op`
return self.copy_op(src, dest); return self.copy_op(src, dest);
} }
@ -910,7 +924,7 @@ where
// on `typeck_tables().has_errors` at all const eval entry points. // on `typeck_tables().has_errors` at all const eval entry points.
debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest); debug!("Size mismatch when transmuting!\nsrc: {:#?}\ndest: {:#?}", src, dest);
self.tcx.sess.delay_span_bug( self.tcx.sess.delay_span_bug(
self.tcx.span, self.cur_span(),
"size-changing transmute, should have been caught by transmute checking", "size-changing transmute, should have been caught by transmute checking",
); );
throw_inval!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty)); throw_inval!(TransmuteSizeDiff(src.layout.ty, dest.layout.ty));

View File

@ -76,7 +76,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> { fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
info!("{:?}", stmt); info!("{:?}", stmt);
self.set_span(stmt.source_info.span);
use rustc_middle::mir::StatementKind::*; use rustc_middle::mir::StatementKind::*;
@ -279,7 +278,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> { fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
info!("{:?}", terminator.kind); info!("{:?}", terminator.kind);
self.set_span(terminator.source_info.span);
self.eval_terminator(terminator)?; self.eval_terminator(terminator)?;
if !self.stack().is_empty() { if !self.stack().is_empty() {

View File

@ -2,7 +2,7 @@ use std::convert::TryFrom;
use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic, Scalar}; use rustc_middle::mir::interpret::{InterpResult, Pointer, PointerArithmetic, Scalar};
use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable};
use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size}; use rustc_target::abi::{Align, LayoutOf, Size};
use super::{FnVal, InterpCx, Machine, MemoryKind}; use super::{FnVal, InterpCx, Machine, MemoryKind};
@ -49,8 +49,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let size = layout.size.bytes(); let size = layout.size.bytes();
let align = layout.align.abi.bytes(); let align = layout.align.abi.bytes();
let tcx = *self.tcx;
let ptr_size = self.pointer_size(); let ptr_size = self.pointer_size();
let ptr_align = self.tcx.data_layout.pointer_align.abi; let ptr_align = tcx.data_layout.pointer_align.abi;
// ///////////////////////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////////////////////
// If you touch this code, be sure to also make the corresponding changes to // If you touch this code, be sure to also make the corresponding changes to
// `get_vtable` in `rust_codegen_llvm/meth.rs`. // `get_vtable` in `rust_codegen_llvm/meth.rs`.
@ -60,33 +61,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ptr_align, ptr_align,
MemoryKind::Vtable, MemoryKind::Vtable,
); );
let tcx = &*self.tcx;
let drop = Instance::resolve_drop_in_place(*tcx, ty); let drop = Instance::resolve_drop_in_place(tcx, ty);
let drop = self.memory.create_fn_alloc(FnVal::Instance(drop)); let drop = self.memory.create_fn_alloc(FnVal::Instance(drop));
// No need to do any alignment checks on the memory accesses below, because we know the // No need to do any alignment checks on the memory accesses below, because we know the
// allocation is correctly aligned as we created it above. Also we're only offsetting by // allocation is correctly aligned as we created it above. Also we're only offsetting by
// multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`. // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`.
let vtable_alloc = self.memory.get_raw_mut(vtable.alloc_id)?; let vtable_alloc = self.memory.get_raw_mut(vtable.alloc_id)?;
vtable_alloc.write_ptr_sized(tcx, vtable, drop.into())?; vtable_alloc.write_ptr_sized(&tcx, vtable, drop.into())?;
let size_ptr = vtable.offset(ptr_size, tcx)?; let size_ptr = vtable.offset(ptr_size, &tcx)?;
vtable_alloc.write_ptr_sized(tcx, size_ptr, Scalar::from_uint(size, ptr_size).into())?; vtable_alloc.write_ptr_sized(&tcx, size_ptr, Scalar::from_uint(size, ptr_size).into())?;
let align_ptr = vtable.offset(ptr_size * 2, tcx)?; let align_ptr = vtable.offset(ptr_size * 2, &tcx)?;
vtable_alloc.write_ptr_sized(tcx, align_ptr, Scalar::from_uint(align, ptr_size).into())?; vtable_alloc.write_ptr_sized(&tcx, align_ptr, Scalar::from_uint(align, ptr_size).into())?;
for (i, method) in methods.iter().enumerate() { for (i, method) in methods.iter().enumerate() {
if let Some((def_id, substs)) = *method { if let Some((def_id, substs)) = *method {
// resolve for vtable: insert shims where needed // resolve for vtable: insert shims where needed
let instance = let instance =
ty::Instance::resolve_for_vtable(*tcx, self.param_env, def_id, substs) ty::Instance::resolve_for_vtable(tcx, self.param_env, def_id, substs)
.ok_or_else(|| err_inval!(TooGeneric))?; .ok_or_else(|| err_inval!(TooGeneric))?;
let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
// We cannot use `vtable_allic` as we are creating fn ptrs in this loop. // We cannot use `vtable_allic` as we are creating fn ptrs in this loop.
let method_ptr = vtable.offset(ptr_size * (3 + i as u64), tcx)?; let method_ptr = vtable.offset(ptr_size * (3 + i as u64), &tcx)?;
self.memory.get_raw_mut(vtable.alloc_id)?.write_ptr_sized( self.memory.get_raw_mut(vtable.alloc_id)?.write_ptr_sized(
tcx, &tcx,
method_ptr, method_ptr,
fn_ptr.into(), fn_ptr.into(),
)?; )?;
@ -171,7 +171,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
alloc.read_ptr_sized(self, vtable.offset(pointer_size * 2, self)?)?.not_undef()?; alloc.read_ptr_sized(self, vtable.offset(pointer_size * 2, self)?)?.not_undef()?;
let align = u64::try_from(self.force_bits(align, pointer_size)?).unwrap(); let align = u64::try_from(self.force_bits(align, pointer_size)?).unwrap();
if size >= self.tcx.data_layout().obj_size_bound() { if size >= self.tcx.data_layout.obj_size_bound() {
throw_ub_format!( throw_ub_format!(
"invalid vtable: \ "invalid vtable: \
size is bigger than largest supported object" size is bigger than largest supported object"

View File

@ -313,7 +313,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
let param_env = tcx.param_env(def_id).with_reveal_all(); let param_env = tcx.param_env(def_id).with_reveal_all();
let span = tcx.def_span(def_id); let span = tcx.def_span(def_id);
let mut ecx = InterpCx::new(tcx.at(span), param_env, ConstPropMachine::new(), ()); let mut ecx = InterpCx::new(tcx, span, param_env, ConstPropMachine::new(), ());
let can_const_prop = CanConstProp::check(body); let can_const_prop = CanConstProp::check(body);
let ret = ecx let ret = ecx
@ -404,9 +404,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
match self.ecx.eval_const_to_op(c.literal, None) { match self.ecx.eval_const_to_op(c.literal, None) {
Ok(op) => Some(op), Ok(op) => Some(op),
Err(error) => { Err(error) => {
// Make sure errors point at the constant. let tcx = self.ecx.tcx.at(c.span);
self.ecx.set_span(c.span); let err = error_to_const_error(&self.ecx, error, Some(c.span));
let err = error_to_const_error(&self.ecx, error);
if let Some(lint_root) = self.lint_root(source_info) { if let Some(lint_root) = self.lint_root(source_info) {
let lint_only = match c.literal.val { let lint_only = match c.literal.val {
// Promoteds must lint and not error as the user didn't ask for them // Promoteds must lint and not error as the user didn't ask for them
@ -418,17 +417,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
if lint_only { if lint_only {
// Out of backwards compatibility we cannot report hard errors in unused // Out of backwards compatibility we cannot report hard errors in unused
// generic functions using associated constants of the generic parameters. // generic functions using associated constants of the generic parameters.
err.report_as_lint( err.report_as_lint(tcx, "erroneous constant used", lint_root, Some(c.span));
self.ecx.tcx,
"erroneous constant used",
lint_root,
Some(c.span),
);
} else { } else {
err.report_as_error(self.ecx.tcx, "erroneous constant used"); err.report_as_error(tcx, "erroneous constant used");
} }
} else { } else {
err.report_as_error(self.ecx.tcx, "erroneous constant used"); err.report_as_error(tcx, "erroneous constant used");
} }
None None
} }
@ -851,7 +845,6 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) { fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
trace!("visit_statement: {:?}", statement); trace!("visit_statement: {:?}", statement);
let source_info = statement.source_info; let source_info = statement.source_info;
self.ecx.set_span(source_info.span);
self.source_info = Some(source_info); self.source_info = Some(source_info);
if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind { if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind {
let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty; let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty;
@ -864,7 +857,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
if let Some(value) = self.get_const(place) { if let Some(value) = self.get_const(place) {
if self.should_const_prop(value) { if self.should_const_prop(value) {
trace!("replacing {:?} with {:?}", rval, value); trace!("replacing {:?} with {:?}", rval, value);
self.replace_with_const(rval, value, statement.source_info); self.replace_with_const(rval, value, source_info);
if can_const_prop == ConstPropMode::FullConstProp if can_const_prop == ConstPropMode::FullConstProp
|| can_const_prop == ConstPropMode::OnlyInsideOwnBlock || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
{ {
@ -927,7 +920,6 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) { fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
let source_info = terminator.source_info; let source_info = terminator.source_info;
self.ecx.set_span(source_info.span);
self.source_info = Some(source_info); self.source_info = Some(source_info);
self.super_terminator(terminator, location); self.super_terminator(terminator, location);
match &mut terminator.kind { match &mut terminator.kind {

View File

@ -23,10 +23,10 @@ LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
= help: add `#![feature(const_if_match)]` to the crate attributes to enable = help: add `#![feature(const_if_match)]` to the crate attributes to enable
error[E0080]: evaluation of constant value failed error[E0080]: evaluation of constant value failed
--> $DIR/infinite_loop.rs:8:20 --> $DIR/infinite_loop.rs:8:17
| |
LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 }; LL | n = if n % 2 == 0 { n/2 } else { 3*n + 1 };
| ^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`)
error: aborting due to 3 previous errors error: aborting due to 3 previous errors

View File

@ -17,8 +17,8 @@ LL | bytes: [u8; std::mem::size_of::<Foo>()]
note: ...which requires const-evaluating `std::mem::size_of`... note: ...which requires const-evaluating `std::mem::size_of`...
--> $SRC_DIR/libcore/mem/mod.rs:LL:COL --> $SRC_DIR/libcore/mem/mod.rs:LL:COL
| |
LL | intrinsics::size_of::<T>() LL | pub const fn size_of<T>() -> usize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `std::intrinsics::size_of`... note: ...which requires const-evaluating + checking `std::intrinsics::size_of`...
--> $SRC_DIR/libcore/intrinsics.rs:LL:COL --> $SRC_DIR/libcore/intrinsics.rs:LL:COL
| |

View File

@ -1,15 +1,18 @@
error: any use of this value will cause an error error: any use of this value will cause an error
--> $DIR/const_eval_limit_reached.rs:8:11 --> $DIR/const_eval_limit_reached.rs:8:5
| |
LL | / const X: usize = { LL | / const X: usize = {
LL | | let mut x = 0; LL | | let mut x = 0;
LL | | while x != 1000 { LL | | while x != 1000 {
| | ^^^^^^^^^ exceeded interpreter step limit (see `#[const_eval_limit]`) | |_____^
LL | | LL | ||
... | LL | || x += 1;
LL | | x LL | || }
LL | | }; | ||_____^ exceeded interpreter step limit (see `#[const_eval_limit]`)
| |__- LL | |
LL | | x
LL | | };
| |__-
| |
= note: `#[deny(const_err)]` on by default = note: `#[deny(const_err)]` on by default

View File

@ -1,8 +1,8 @@
error[E0391]: cycle detected when const-evaluating `FOO` error[E0391]: cycle detected when const-evaluating `FOO`
--> $DIR/recursive-zst-static.rs:10:18 --> $DIR/recursive-zst-static.rs:10:1
| |
LL | static FOO: () = FOO; LL | static FOO: () = FOO;
| ^^^ | ^^^^^^^^^^^^^^^^^^^^^
| |
note: ...which requires const-evaluating `FOO`... note: ...which requires const-evaluating `FOO`...
--> $DIR/recursive-zst-static.rs:10:1 --> $DIR/recursive-zst-static.rs:10:1

View File

@ -1,8 +1,8 @@
error[E0391]: cycle detected when const-evaluating `FOO` error[E0391]: cycle detected when const-evaluating `FOO`
--> $DIR/recursive-zst-static.rs:10:18 --> $DIR/recursive-zst-static.rs:10:1
| |
LL | static FOO: () = FOO; LL | static FOO: () = FOO;
| ^^^ | ^^^^^^^^^^^^^^^^^^^^^
| |
note: ...which requires const-evaluating `FOO`... note: ...which requires const-evaluating `FOO`...
--> $DIR/recursive-zst-static.rs:10:1 --> $DIR/recursive-zst-static.rs:10:1

View File

@ -1,11 +1,11 @@
// build-fail // build-fail
pub const unsafe fn fake_type<T>() -> T { pub const unsafe fn fake_type<T>() -> T {
hint_unreachable() hint_unreachable() //~ ERROR evaluation of constant value failed
} }
pub const unsafe fn hint_unreachable() -> ! { pub const unsafe fn hint_unreachable() -> ! {
fake_type() //~ ERROR evaluation of constant value failed fake_type()
} }
trait Const { trait Const {

View File

@ -1,9 +1,10 @@
error[E0080]: evaluation of constant value failed error[E0080]: evaluation of constant value failed
--> $DIR/uninhabited-const-issue-61744.rs:8:5 --> $DIR/uninhabited-const-issue-61744.rs:4:5
| |
LL | hint_unreachable() LL | hint_unreachable()
| ------------------ | ^^^^^^^^^^^^^^^^^^
| | | |
| reached the configured maximum number of stack frames
| inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
| inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
| inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5 | inside `fake_type::<!>` at $DIR/uninhabited-const-issue-61744.rs:4:5
@ -71,9 +72,8 @@ LL | hint_unreachable()
| inside `fake_type::<i32>` at $DIR/uninhabited-const-issue-61744.rs:4:5 | inside `fake_type::<i32>` at $DIR/uninhabited-const-issue-61744.rs:4:5
... ...
LL | fake_type() LL | fake_type()
| ^^^^^^^^^^^ | -----------
| | | |
| reached the configured maximum number of stack frames
| inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5
| inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5 | inside `hint_unreachable` at $DIR/uninhabited-const-issue-61744.rs:8:5

View File

@ -1,14 +1,14 @@
error[E0391]: cycle detected when const-evaluating `a` error[E0391]: cycle detected when const-evaluating `a`
--> $DIR/infinite-recursion-const-fn.rs:3:25 --> $DIR/infinite-recursion-const-fn.rs:3:1
| |
LL | const fn a() -> usize { b() } LL | const fn a() -> usize { b() }
| ^^^ | ^^^^^^^^^^^^^^^^^^^^^
| |
note: ...which requires const-evaluating `b`... note: ...which requires const-evaluating `b`...
--> $DIR/infinite-recursion-const-fn.rs:4:25 --> $DIR/infinite-recursion-const-fn.rs:4:1
| |
LL | const fn b() -> usize { a() } LL | const fn b() -> usize { a() }
| ^^^ | ^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires const-evaluating `a`, completing the cycle = note: ...which again requires const-evaluating `a`, completing the cycle
note: cycle used when const-evaluating `ARR::{{constant}}#0` note: cycle used when const-evaluating `ARR::{{constant}}#0`
--> $DIR/infinite-recursion-const-fn.rs:5:18 --> $DIR/infinite-recursion-const-fn.rs:5:18

View File

@ -1,8 +1,8 @@
error[E0391]: cycle detected when const-evaluating `FOO` error[E0391]: cycle detected when const-evaluating `FOO`
--> $DIR/recursive-static-definition.rs:1:23 --> $DIR/recursive-static-definition.rs:1:1
| |
LL | pub static FOO: u32 = FOO; LL | pub static FOO: u32 = FOO;
| ^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
note: ...which requires const-evaluating `FOO`... note: ...which requires const-evaluating `FOO`...
--> $DIR/recursive-static-definition.rs:1:1 --> $DIR/recursive-static-definition.rs:1:1

View File

@ -5,10 +5,10 @@ LL | pub static mut B: () = unsafe { A = 1; };
| ^^^^^ modifying a static's initial value from another static's initializer | ^^^^^ modifying a static's initial value from another static's initializer
error[E0391]: cycle detected when const-evaluating `C` error[E0391]: cycle detected when const-evaluating `C`
--> $DIR/write-to-static-mut-in-static.rs:5:34 --> $DIR/write-to-static-mut-in-static.rs:5:1
| |
LL | pub static mut C: u32 = unsafe { C = 1; 0 }; LL | pub static mut C: u32 = unsafe { C = 1; 0 };
| ^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
note: ...which requires const-evaluating `C`... note: ...which requires const-evaluating `C`...
--> $DIR/write-to-static-mut-in-static.rs:5:1 --> $DIR/write-to-static-mut-in-static.rs:5:1