about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/const_eval.rs11
-rw-r--r--src/librustc_mir/interpret/machine.rs52
-rw-r--r--src/librustc_mir/interpret/memory.rs22
-rw-r--r--src/librustc_mir/interpret/mod.rs4
-rw-r--r--src/librustc_mir/interpret/place.rs36
-rw-r--r--src/librustc_mir/interpret/step.rs5
-rw-r--r--src/librustc_mir/interpret/terminator.rs5
7 files changed, 103 insertions, 32 deletions
diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs
index fd9af74c5d7..baf6a4ecaa0 100644
--- a/src/librustc_mir/const_eval.rs
+++ b/src/librustc_mir/const_eval.rs
@@ -33,7 +33,7 @@ use rustc::mir::interpret::{
     Scalar, Allocation, AllocId, ConstValue,
 };
 use interpret::{self,
-    PlaceTy, MemPlace, OpTy, Operand, Value,
+    PlaceTy, MPlaceTy, MemPlace, OpTy, Operand, Value,
     EvalContext, StackPopCleanup, MemoryKind,
     snapshot,
 };
@@ -464,6 +464,15 @@ impl<'a, 'mir, 'tcx> interpret::Machine<'a, 'mir, 'tcx>
             &ecx.stack[..],
         )
     }
+
+    #[inline(always)]
+    fn tag_reference(
+        _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        _place: MPlaceTy<'tcx, Self::PointerTag>,
+        _borrow_kind: mir::BorrowKind,
+    ) -> EvalResult<'tcx, Self::PointerTag> {
+        Ok(())
+    }
 }
 
 /// Project to a field of a (variant of a) const
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index 56909938df4..e30874ce7b3 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -16,11 +16,19 @@ use std::borrow::{Borrow, Cow};
 use std::hash::Hash;
 
 use rustc::hir::def_id::DefId;
-use rustc::mir::interpret::{Allocation, AllocId, EvalResult, Scalar};
 use rustc::mir;
-use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
+use rustc::ty::{self, layout::{Size, TyLayout}, query::TyCtxtAt};
 
-use super::{EvalContext, PlaceTy, OpTy, MemoryKind};
+use super::{
+    Allocation, AllocId, EvalResult, Scalar,
+    EvalContext, PlaceTy, OpTy, MPlaceTy, Pointer, MemoryKind,
+};
+
+/// Classifying memory accesses
+pub enum MemoryAccess {
+    Read,
+    Write,
+}
 
 /// Whether this kind of memory is allowed to leak
 pub trait MayLeak: Copy {
@@ -160,15 +168,47 @@ pub trait Machine<'a, 'mir, 'tcx>: Sized {
         right_layout: TyLayout<'tcx>,
     ) -> EvalResult<'tcx, (Scalar<Self::PointerTag>, bool)>;
 
-    /// Heap allocations via the `box` keyword
-    ///
-    /// Returns a pointer to the allocated memory
+    /// Heap allocations via the `box` keyword.
     fn box_alloc(
         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         dest: PlaceTy<'tcx, Self::PointerTag>,
     ) -> EvalResult<'tcx>;
 
+    /// Hook for performing extra checks on a memory access.
+    ///
+    /// Takes read-only access to the allocation so we can keep all the memory read
+    /// operations take `&self`.  Use a `RefCell` in `AllocExtra` if you
+    /// need to mutate.
+    #[inline]
+    fn memory_accessed(
+        _alloc: &Allocation<Self::PointerTag, Self::AllocExtra>,
+        _ptr: Pointer<Self::PointerTag>,
+        _size: Size,
+        _access: MemoryAccess,
+    ) -> EvalResult<'tcx> {
+        Ok(())
+    }
+
+    /// Hook for performing extra checks when memory gets deallocated.
+    #[inline]
+    fn memory_deallocated(
+        _alloc: &mut Allocation<Self::PointerTag, Self::AllocExtra>,
+        _id: AllocId,
+    ) -> EvalResult<'tcx> {
+        Ok(())
+    }
+
+    /// Executed when evaluating the `&` operator: Creating a new reference.
+    /// This has the chance to adjust the tag.  It is only ever called if the
+    /// pointer in `place` is really a pointer, not another scalar.
+    fn tag_reference(
+        ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
+        place: MPlaceTy<'tcx, Self::PointerTag>,
+        borrow_kind: mir::BorrowKind,
+    ) -> EvalResult<'tcx, Self::PointerTag>;
+
     /// Execute a validation operation
+    #[inline]
     fn validation_op(
         _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
         _op: ::rustc::mir::ValidationOp,
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 51dd970e0bb..faa165723db 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -22,17 +22,16 @@ use std::borrow::Cow;
 
 use rustc::ty::{self, Instance, ParamEnv, query::TyCtxtAt};
 use rustc::ty::layout::{self, Align, TargetDataLayout, Size, HasDataLayout};
-use rustc::mir::interpret::{
-    Pointer, AllocId, Allocation, ConstValue, GlobalId,
-    EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
-    truncate
-};
-pub use rustc::mir::interpret::{write_target_uint, read_target_uint};
+pub use rustc::mir::interpret::{truncate, write_target_uint, read_target_uint};
 use rustc_data_structures::fx::{FxHashSet, FxHashMap};
 
 use syntax::ast::Mutability;
 
-use super::{Machine, AllocMap, MayLeak, ScalarMaybeUndef};
+use super::{
+    Pointer, AllocId, Allocation, ConstValue, GlobalId,
+    EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
+    Machine, MemoryAccess, AllocMap, MayLeak, ScalarMaybeUndef,
+};
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
 pub enum MemoryKind<T> {
@@ -197,7 +196,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             return err!(DeallocateNonBasePtr);
         }
 
-        let (alloc_kind, alloc) = match self.alloc_map.remove(&ptr.alloc_id) {
+        let (alloc_kind, mut alloc) = match self.alloc_map.remove(&ptr.alloc_id) {
             Some(alloc) => alloc,
             None => {
                 // Deallocating static memory -- always an error
@@ -232,6 +231,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             }
         }
 
+        // Let the machine take some extra action
+        M::memory_deallocated(&mut alloc, ptr.alloc_id)?;
+
         // Don't forget to remember size and align of this now-dead allocation
         let old = self.dead_alloc_map.insert(
             ptr.alloc_id,
@@ -632,6 +634,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         }
 
         let alloc = self.get(ptr.alloc_id)?;
+        M::memory_accessed(alloc, ptr, size, MemoryAccess::Read)?;
+
         assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
         assert_eq!(size.bytes() as usize as u64, size.bytes());
         let offset = ptr.offset.bytes() as usize;
@@ -676,6 +680,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         self.clear_relocations(ptr, size)?;
 
         let alloc = self.get_mut(ptr.alloc_id)?;
+        M::memory_accessed(alloc, ptr, size, MemoryAccess::Write)?;
+
         assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes());
         assert_eq!(size.bytes() as usize as u64, size.bytes());
         let offset = ptr.offset.bytes() as usize;
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index a174b12aaac..55037a99e01 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -24,6 +24,8 @@ mod traits;
 mod validity;
 mod intrinsics;
 
+pub use rustc::mir::interpret::*; // have all the `interpret` symbols in one place: here
+
 pub use self::eval_context::{
     EvalContext, Frame, StackPopCleanup, LocalValue,
 };
@@ -32,7 +34,7 @@ pub use self::place::{Place, PlaceTy, MemPlace, MPlaceTy};
 
 pub use self::memory::{Memory, MemoryKind};
 
-pub use self::machine::{Machine, AllocMap, MayLeak};
+pub use self::machine::{Machine, AllocMap, MemoryAccess, MayLeak};
 
 pub use self::operand::{ScalarMaybeUndef, Value, ValTy, Operand, OpTy};
 
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index c4f01d8ce31..51406a686bc 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -144,17 +144,6 @@ impl<Tag> MemPlace<Tag> {
         // it now must be aligned.
         self.to_scalar_ptr_align().0.to_ptr()
     }
-
-    /// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
-    /// This is the inverse of `ref_to_mplace`.
-    pub fn to_ref(self) -> Value<Tag> {
-        // We ignore the alignment of the place here -- special handling for packed structs ends
-        // at the `&` operator.
-        match self.meta {
-            None => Value::Scalar(self.ptr.into()),
-            Some(meta) => Value::ScalarPair(self.ptr.into(), meta.into()),
-        }
-    }
 }
 
 impl<'tcx, Tag> MPlaceTy<'tcx, Tag> {
@@ -270,9 +259,10 @@ where
     M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKinds>, Allocation<Tag, M::AllocExtra>)>,
 {
     /// Take a value, which represents a (thin or fat) reference, and make it a place.
-    /// Alignment is just based on the type.  This is the inverse of `MemPlace::to_ref`.
+    /// Alignment is just based on the type.  This is the inverse of `create_ref`.
     pub fn ref_to_mplace(
-        &self, val: ValTy<'tcx, M::PointerTag>
+        &self,
+        val: ValTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
         let pointee_type = val.layout.ty.builtin_deref(true).unwrap().ty;
         let layout = self.layout_of(pointee_type)?;
@@ -286,6 +276,26 @@ where
         Ok(MPlaceTy { mplace, layout })
     }
 
+    /// Turn a mplace into a (thin or fat) pointer, as a reference, pointing to the same space.
+    /// This is the inverse of `ref_to_mplace`.
+    pub fn create_ref(
+        &mut self,
+        place: MPlaceTy<'tcx, M::PointerTag>,
+        borrow_kind: mir::BorrowKind,
+    ) -> EvalResult<'tcx, Value<M::PointerTag>> {
+        let ptr = match place.ptr {
+            Scalar::Ptr(ptr) => {
+                let tag = M::tag_reference(self, place, borrow_kind)?;
+                Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag))
+            },
+            scalar @ Scalar::Bits { .. } => scalar,
+        };
+        Ok(match place.meta {
+            None => Value::Scalar(ptr.into()),
+            Some(meta) => Value::ScalarPair(ptr.into(), meta.into()),
+        })
+    }
+
     /// 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.
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index d15867eacdd..cb629e8313c 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -248,9 +248,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                 )?;
             }
 
-            Ref(_, _, ref place) => {
+            Ref(_, borrow_kind, ref place) => {
                 let src = self.eval_place(place)?;
-                let val = self.force_allocation(src)?.to_ref();
+                let val = self.force_allocation(src)?;
+                let val = self.create_ref(val, borrow_kind)?;
                 self.write_value(val, dest)?;
             }
 
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index a339fa34ae1..bb2dc732200 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -446,7 +446,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
         };
 
         let arg = OpTy {
-            op: Operand::Immediate(place.to_ref()),
+            op: Operand::Immediate(self.create_ref(
+                place,
+                mir::BorrowKind::Mut { allow_two_phase_borrow: false }
+            )?),
             layout: self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?,
         };