use std::convert::TryFrom;
use std::hash::Hash;
-use rustc::hir;
use rustc::mir;
use rustc::mir::interpret::truncate;
use rustc::ty::{self, Ty};
impl<'a, 'mir, 'tcx, Tag, M> InterpretCx<'a, 'mir, 'tcx, M>
where
// FIXME: Working around https://github.com/rust-lang/rust/issues/54385
- Tag: ::std::fmt::Debug+Default+Copy+Eq+Hash+'static,
+ Tag: ::std::fmt::Debug + Copy + Eq + Hash + 'static,
M: Machine<'a, 'mir, 'tcx, PointerTag=Tag>,
// FIXME: Working around https://github.com/rust-lang/rust/issues/24159
M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
// Take an operand, representing a pointer, and dereference it to a place -- that
// will always be a MemPlace. Lives in `place.rs` because it creates a place.
- // This calls the "deref" machine hook, and counts as a deref as far as
- // Stacked Borrows is concerned.
pub fn deref_operand(
&self,
src: OpTy<'tcx, M::PointerTag>,
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let val = self.read_immediate(src)?;
trace!("deref to {} on {:?}", val.layout.ty, *val);
- let mut place = self.ref_to_mplace(val)?;
- // Pointer tag tracking might want to adjust the tag.
- let mutbl = match val.layout.ty.sty {
- // `builtin_deref` considers boxes immutable, that's useless for our purposes
- ty::Ref(_, _, mutbl) => Some(mutbl),
- ty::Adt(def, _) if def.is_box() => Some(hir::MutMutable),
- ty::RawPtr(_) => None,
- _ => bug!("Unexpected pointer type {}", val.layout.ty),
- };
- place.mplace.ptr = M::tag_dereference(self, place, mutbl)?;
- Ok(place)
+ self.ref_to_mplace(val)
}
- /// Offset a pointer to project to a field. Unlike place_field, this is always
- /// possible without allocating, so it can take &self. Also return the field's layout.
+ /// Offset a pointer to project to a field. Unlike `place_field`, this is always
+ /// possible without allocating, so it can take `&self`. Also return the field's layout.
/// This supports both struct and array fields.
#[inline(always)]
pub fn mplace_field(
/// Evaluate statics and promoteds to an `MPlace`. Used to share some code between
/// `eval_place` and `eval_place_to_op`.
- pub(super) fn eval_place_to_mplace(
+ pub(super) fn eval_static_to_mplace(
&self,
- mir_place: &mir::Place<'tcx>
+ place_static: &mir::Static<'tcx>
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
- use rustc::mir::Place::*;
- use rustc::mir::PlaceBase;
- use rustc::mir::{Static, StaticKind};
- Ok(match *mir_place {
- Base(PlaceBase::Static(box Static { kind: StaticKind::Promoted(promoted), .. })) => {
+ use rustc::mir::StaticKind;
+
+ Ok(match place_static.kind {
+ StaticKind::Promoted(promoted) => {
let instance = self.frame().instance;
self.const_eval_raw(GlobalId {
instance,
})?
}
- Base(PlaceBase::Static(box Static { kind: StaticKind::Static(def_id), ty })) => {
+ StaticKind::Static(def_id) => {
+ let ty = place_static.ty;
assert!(!ty.needs_subst());
let layout = self.layout_of(ty)?;
let instance = ty::Instance::mono(*self.tcx, def_id);
promoted: None
};
// Just create a lazy reference, so we can support recursive statics.
- // tcx takes are of assigning every static one and only one unique AllocId.
+ // tcx takes care of assigning every static one and only one unique AllocId.
// When the data here is ever actually used, memory will notice,
// and it knows how to deal with alloc_id that are present in the
// global table but not in its local memory: It calls back into tcx through
// a query, triggering the CTFE machinery to actually turn this lazy reference
// into a bunch of bytes. IOW, statics are evaluated with CTFE even when
// this InterpretCx uses another Machine (e.g., in miri). This is what we
- // want! This way, computing statics works concistently between codegen
+ // want! This way, computing statics works consistently between codegen
// and miri: They use the same query to eventually obtain a `ty::Const`
// and use that for further computation.
- let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
- MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
+ //
+ // Notice that statics have *two* AllocIds: the lazy one, and the resolved
+ // one. Here we make sure that the interpreted program never sees the
+ // resolved ID. Also see the doc comment of `Memory::get_static_alloc`.
+ let alloc_id = self.tcx.alloc_map.lock().create_static_alloc(cid.instance.def_id());
+ let ptr = self.tag_static_base_pointer(Pointer::from(alloc_id));
+ MPlaceTy::from_aligned_ptr(ptr, layout)
}
-
- _ => bug!("eval_place_to_mplace called on {:?}", mir_place),
})
}
/// place; for reading, a more efficient alternative is `eval_place_for_read`.
pub fn eval_place(
&mut self,
- mir_place: &mir::Place<'tcx>
+ mir_place: &mir::Place<'tcx>,
) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
- use rustc::mir::Place::*;
use rustc::mir::PlaceBase;
- let place = match *mir_place {
- Base(PlaceBase::Local(mir::RETURN_PLACE)) => match self.frame().return_place {
- Some(return_place) =>
- // We use our layout to verify our assumption; caller will validate
- // their layout on return.
- PlaceTy {
- place: *return_place,
- layout: self.layout_of(self.monomorphize(self.frame().mir.return_ty())?)?,
+
+ mir_place.iterate(|place_base, place_projection| {
+ let mut place = match place_base {
+ PlaceBase::Local(mir::RETURN_PLACE) => match self.frame().return_place {
+ Some(return_place) => {
+ // We use our layout to verify our assumption; caller will validate
+ // their layout on return.
+ PlaceTy {
+ place: *return_place,
+ layout: self
+ .layout_of(self.monomorphize(self.frame().mir.return_ty())?)?,
+ }
+ }
+ None => return err!(InvalidNullPointerUsage),
+ },
+ PlaceBase::Local(local) => PlaceTy {
+ // This works even for dead/uninitialized locals; we check further when writing
+ place: Place::Local {
+ frame: self.cur_frame(),
+ local: *local,
},
- None => return err!(InvalidNullPointerUsage),
- },
- Base(PlaceBase::Local(local)) => PlaceTy {
- // This works even for dead/uninitialized locals; we check further when writing
- place: Place::Local {
- frame: self.cur_frame(),
- local,
+ layout: self.layout_of_local(self.frame(), *local, None)?,
},
- layout: self.layout_of_local(self.frame(), local, None)?,
- },
+ PlaceBase::Static(place_static) => self.eval_static_to_mplace(place_static)?.into(),
+ };
- Projection(ref proj) => {
- let place = self.eval_place(&proj.base)?;
- self.place_projection(place, &proj.elem)?
+ for proj in place_projection {
+ place = self.place_projection(place, &proj.elem)?
}
- _ => self.eval_place_to_mplace(mir_place)?.into(),
- };
-
- self.dump_place(place.place);
- Ok(place)
+ self.dump_place(place.place);
+ Ok(place)
+ })
}
/// Write a scalar to a place
Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Ptr(_))) =>
assert_eq!(self.pointer_size(), dest.layout.size,
"Size mismatch when writing pointer"),
- Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { size, .. })) =>
+ Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Raw { size, .. })) =>
assert_eq!(Size::from_bytes(size.into()), dest.layout.size,
"Size mismatch when writing bits"),
Immediate::Scalar(ScalarMaybeUndef::Undef) => {}, // undef can have any size
}
/// Write an immediate to memory.
- /// If you use this you are responsible for validating that things git copied at the
+ /// If you use this you are responsible for validating that things got copied at the
/// right type.
fn write_immediate_to_mplace_no_validate(
&mut self,
/// Copies the data from an operand to a place. This does not support transmuting!
/// Use `copy_op_transmute` if the layouts could disagree.
- /// Also, if you use this you are responsible for validating that things git copied at the
+ /// Also, if you use this you are responsible for validating that things get copied at the
/// right type.
fn copy_op_no_validate(
&mut self,
) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
// This must be an allocation in `tcx`
assert!(self.tcx.alloc_map.lock().get(raw.alloc_id).is_some());
+ let ptr = self.tag_static_base_pointer(Pointer::from(raw.alloc_id));
let layout = self.layout_of(raw.ty)?;
- Ok(MPlaceTy::from_aligned_ptr(
- Pointer::new(raw.alloc_id, Size::ZERO).with_default_tag(),
- layout,
- ))
+ Ok(MPlaceTy::from_aligned_ptr(ptr, layout))
}
/// Turn a place with a `dyn Trait` type into a place with the actual dynamic type.