]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/interpret/place.rs
Changed usages of `mir` in librustc::mir and librustc_mir to `body`
[rust.git] / src / librustc_mir / interpret / place.rs
index 0ae4e90b7c24d57afb72319874960c5893f79c6e..758230e2b7dcb8c271ed90531de5fc9908ba5784 100644 (file)
@@ -5,7 +5,6 @@
 use std::convert::TryFrom;
 use std::hash::Hash;
 
-use rustc::hir;
 use rustc::mir;
 use rustc::mir::interpret::truncate;
 use rustc::ty::{self, Ty};
@@ -13,7 +12,7 @@
 use rustc::ty::TypeFoldable;
 
 use super::{
-    GlobalId, AllocId, Allocation, Scalar, EvalResult, Pointer, PointerArithmetic,
+    GlobalId, AllocId, Allocation, Scalar, InterpResult, Pointer, PointerArithmetic,
     InterpretCx, Machine, AllocMap, AllocationExtra,
     RawConst, Immediate, ImmTy, ScalarMaybeUndef, Operand, OpTy, MemoryKind, LocalValue
 };
@@ -131,7 +130,7 @@ pub fn to_scalar_ptr_align(self) -> (Scalar<Tag>, Align) {
 
     /// metact the ptr part of the mplace
     #[inline(always)]
-    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
+    pub fn to_ptr(self) -> InterpResult<'tcx, Pointer<Tag>> {
         // At this point, we forget about the alignment information --
         // the place has been turned into a reference, and no matter where it came from,
         // it now must be aligned.
@@ -153,7 +152,7 @@ pub fn offset(
         offset: Size,
         meta: Option<Scalar<Tag>>,
         cx: &impl HasDataLayout,
-    ) -> EvalResult<'tcx, Self> {
+    ) -> InterpResult<'tcx, Self> {
         Ok(MemPlace {
             ptr: self.ptr.ptr_offset(offset, cx)?,
             align: self.align.restrict_for_offset(offset),
@@ -191,7 +190,7 @@ pub fn offset(
         meta: Option<Scalar<Tag>>,
         layout: TyLayout<'tcx>,
         cx: &impl HasDataLayout,
-    ) -> EvalResult<'tcx, Self> {
+    ) -> InterpResult<'tcx, Self> {
         Ok(MPlaceTy {
             mplace: self.mplace.offset(offset, meta, cx)?,
             layout,
@@ -204,7 +203,7 @@ fn from_aligned_ptr(ptr: Pointer<Tag>, layout: TyLayout<'tcx>) -> Self {
     }
 
     #[inline]
-    pub(super) fn len(self, cx: &impl HasDataLayout) -> EvalResult<'tcx, u64> {
+    pub(super) fn len(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
         if self.layout.is_unsized() {
             // We need to consult `meta` metadata
             match self.layout.ty.sty {
@@ -223,7 +222,7 @@ pub(super) fn len(self, cx: &impl HasDataLayout) -> EvalResult<'tcx, u64> {
     }
 
     #[inline]
-    pub(super) fn vtable(self) -> EvalResult<'tcx, Pointer<Tag>> {
+    pub(super) fn vtable(self) -> InterpResult<'tcx, Pointer<Tag>> {
         match self.layout.ty.sty {
             ty::Dynamic(..) => self.mplace.meta.unwrap().to_ptr(),
             _ => bug!("vtable not supported on type {:?}", self.layout.ty),
@@ -278,7 +277,7 @@ pub fn to_scalar_ptr_align(self) -> (Scalar<Tag>, Align) {
     }
 
     #[inline]
-    pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
+    pub fn to_ptr(self) -> InterpResult<'tcx, Pointer<Tag>> {
         self.to_mem_place().to_ptr()
     }
 }
@@ -294,7 +293,7 @@ pub fn to_mem_place(self) -> MPlaceTy<'tcx, Tag> {
 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>)>,
@@ -307,7 +306,7 @@ impl<'a, 'mir, 'tcx, Tag, M> InterpretCx<'a, 'mir, 'tcx, M>
     pub fn ref_to_mplace(
         &self,
         val: ImmTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
         let layout = self.layout_of(pointee_type)?;
 
@@ -325,36 +324,24 @@ pub fn ref_to_mplace(
 
     // 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>> {
+    ) -> InterpResult<'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(
         &self,
         base: MPlaceTy<'tcx, M::PointerTag>,
         field: u64,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         // Not using the layout method because we want to compute on u64
         let offset = match base.layout.fields {
             layout::FieldPlacement::Arbitrary { ref offsets, .. } =>
@@ -410,7 +397,7 @@ pub fn mplace_array_fields(
         &self,
         base: MPlaceTy<'tcx, Tag>,
     ) ->
-        EvalResult<'tcx, impl Iterator<Item=EvalResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
+        InterpResult<'tcx, impl Iterator<Item=InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'a>
     {
         let len = base.len(self)?; // also asserts that we have a type where this makes sense
         let stride = match base.layout.fields {
@@ -427,7 +414,7 @@ pub fn mplace_subslice(
         base: MPlaceTy<'tcx, M::PointerTag>,
         from: u64,
         to: u64,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let len = base.len(self)?; // also asserts that we have a type where this makes sense
         assert!(from <= len - to);
 
@@ -461,7 +448,7 @@ pub fn mplace_downcast(
         &self,
         base: MPlaceTy<'tcx, M::PointerTag>,
         variant: VariantIdx,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         // Downcasts only change the layout
         assert!(base.meta.is_none());
         Ok(MPlaceTy { layout: base.layout.for_variant(self, variant), ..base })
@@ -472,7 +459,7 @@ pub fn mplace_projection(
         &self,
         base: MPlaceTy<'tcx, M::PointerTag>,
         proj_elem: &mir::PlaceElem<'tcx>,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         use rustc::mir::ProjectionElem::*;
         Ok(match *proj_elem {
             Field(field, _) => self.mplace_field(base, field.index() as u64)?,
@@ -517,7 +504,7 @@ pub fn place_field(
         &mut self,
         base: PlaceTy<'tcx, M::PointerTag>,
         field: u64,
-    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         // FIXME: We could try to be smarter and avoid allocation for fields that span the
         // entire place.
         let mplace = self.force_allocation(base)?;
@@ -528,7 +515,7 @@ pub fn place_downcast(
         &self,
         base: PlaceTy<'tcx, M::PointerTag>,
         variant: VariantIdx,
-    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         // Downcast just changes the layout
         Ok(match base.place {
             Place::Ptr(mplace) =>
@@ -545,7 +532,7 @@ pub fn place_projection(
         &mut self,
         base: PlaceTy<'tcx, M::PointerTag>,
         proj_elem: &mir::ProjectionElem<mir::Local, Ty<'tcx>>,
-    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         use rustc::mir::ProjectionElem::*;
         Ok(match *proj_elem {
             Field(field, _) =>  self.place_field(base, field.index() as u64)?,
@@ -565,7 +552,7 @@ pub fn place_projection(
     pub(super) fn eval_static_to_mplace(
         &self,
         place_static: &mir::Static<'tcx>
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         use rustc::mir::StaticKind;
 
         Ok(match place_static.kind {
@@ -587,18 +574,23 @@ pub(super) fn eval_static_to_mplace(
                     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)
             }
         })
     }
@@ -608,7 +600,7 @@ pub(super) fn eval_static_to_mplace(
     pub fn eval_place(
         &mut self,
         mir_place: &mir::Place<'tcx>,
-    ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, PlaceTy<'tcx, M::PointerTag>> {
         use rustc::mir::PlaceBase;
 
         mir_place.iterate(|place_base, place_projection| {
@@ -620,7 +612,7 @@ pub fn eval_place(
                         PlaceTy {
                             place: *return_place,
                             layout: self
-                                .layout_of(self.monomorphize(self.frame().mir.return_ty())?)?,
+                                .layout_of(self.monomorphize(self.frame().body.return_ty())?)?,
                         }
                     }
                     None => return err!(InvalidNullPointerUsage),
@@ -650,7 +642,7 @@ pub fn write_scalar(
         &mut self,
         val: impl Into<ScalarMaybeUndef<M::PointerTag>>,
         dest: PlaceTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx> {
+    ) -> InterpResult<'tcx> {
         self.write_immediate(Immediate::Scalar(val.into()), dest)
     }
 
@@ -660,7 +652,7 @@ pub fn write_immediate(
         &mut self,
         src: Immediate<M::PointerTag>,
         dest: PlaceTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx> {
+    ) -> InterpResult<'tcx> {
         self.write_immediate_no_validate(src, dest)?;
 
         if M::enforce_validity(self) {
@@ -671,6 +663,23 @@ pub fn write_immediate(
         Ok(())
     }
 
+    /// Write an `Immediate` to memory.
+    #[inline(always)]
+    pub fn write_immediate_to_mplace(
+        &mut self,
+        src: Immediate<M::PointerTag>,
+        dest: MPlaceTy<'tcx, M::PointerTag>,
+    ) -> InterpResult<'tcx> {
+        self.write_immediate_to_mplace_no_validate(src, dest)?;
+
+        if M::enforce_validity(self) {
+            // Data got changed, better make sure it matches the type!
+            self.validate_operand(dest.into(), vec![], None, /*const_mode*/ false)?;
+        }
+
+        Ok(())
+    }
+
     /// Write an immediate to a place.
     /// If you use this you are responsible for validating that things got copied at the
     /// right type.
@@ -678,7 +687,7 @@ fn write_immediate_no_validate(
         &mut self,
         src: Immediate<M::PointerTag>,
         dest: PlaceTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx> {
+    ) -> InterpResult<'tcx> {
         if cfg!(debug_assertions) {
             // This is a very common path, avoid some checks in release mode
             assert!(!dest.layout.is_unsized(), "Cannot write unsized data");
@@ -722,13 +731,13 @@ fn write_immediate_no_validate(
     }
 
     /// 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,
         value: Immediate<M::PointerTag>,
         dest: MPlaceTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx> {
+    ) -> InterpResult<'tcx> {
         let (ptr, ptr_align) = dest.to_scalar_ptr_align();
         // Note that it is really important that the type here is the right one, and matches the
         // type things are read at. In case `src_val` is a `ScalarPair`, we don't do any magic here
@@ -792,7 +801,7 @@ pub fn copy_op(
         &mut self,
         src: OpTy<'tcx, M::PointerTag>,
         dest: PlaceTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx> {
+    ) -> InterpResult<'tcx> {
         self.copy_op_no_validate(src, dest)?;
 
         if M::enforce_validity(self) {
@@ -805,13 +814,13 @@ pub fn copy_op(
 
     /// 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,
         src: OpTy<'tcx, M::PointerTag>,
         dest: PlaceTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx> {
+    ) -> InterpResult<'tcx> {
         // 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.
         assert!(src.layout.details == dest.layout.details,
@@ -856,7 +865,7 @@ pub fn copy_op_transmute(
         &mut self,
         src: OpTy<'tcx, M::PointerTag>,
         dest: PlaceTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx> {
+    ) -> InterpResult<'tcx> {
         if src.layout.details == dest.layout.details {
             // Fast path: Just use normal `copy_op`
             return self.copy_op(src, dest);
@@ -903,7 +912,7 @@ pub fn force_allocation_maybe_sized(
         &mut self,
         place: PlaceTy<'tcx, M::PointerTag>,
         meta: Option<Scalar<M::PointerTag>>,
-    ) -> EvalResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> {
+    ) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::PointerTag>, Option<Size>)> {
         let (mplace, size) = match place.place {
             Place::Local { frame, local } => {
                 match self.stack[frame].locals[local].access_mut()? {
@@ -956,7 +965,7 @@ pub fn force_allocation_maybe_sized(
     pub fn force_allocation(
         &mut self,
         place: PlaceTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         Ok(self.force_allocation_maybe_sized(place, None)?.0)
     }
 
@@ -973,7 +982,7 @@ pub fn write_discriminant_index(
         &mut self,
         variant_index: VariantIdx,
         dest: PlaceTy<'tcx, M::PointerTag>,
-    ) -> EvalResult<'tcx> {
+    ) -> InterpResult<'tcx> {
         match dest.layout.variants {
             layout::Variants::Single { index } => {
                 assert_eq!(index, variant_index);
@@ -1029,20 +1038,18 @@ pub fn write_discriminant_index(
     pub fn raw_const_to_mplace(
         &self,
         raw: RawConst<'tcx>,
-    ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
+    ) -> InterpResult<'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.
     /// Also return some more information so drop doesn't have to run the same code twice.
     pub(super) fn unpack_dyn_trait(&self, mplace: MPlaceTy<'tcx, M::PointerTag>)
-    -> EvalResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
+    -> InterpResult<'tcx, (ty::Instance<'tcx>, MPlaceTy<'tcx, M::PointerTag>)> {
         let vtable = mplace.vtable()?; // also sanity checks the type
         let (instance, ty) = self.read_drop_type_from_vtable(vtable)?;
         let layout = self.layout_of(ty)?;