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:
commit
f9c8a67593
|
@ -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>,
|
||||||
|
|
|
@ -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()) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(..)) => {
|
||||||
|
|
|
@ -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)))
|
||||||
|
|
|
@ -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 => {}
|
||||||
|
|
|
@ -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 `{}`",
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue