]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/interpret/operand.rs
Limit the visibility further and expand on a comment
[rust.git] / src / librustc_mir / interpret / operand.rs
index c0b26442dd918c75a4b859916dbdab81c65bf989..de362a7a96a7ffe299867e5a62fcaa66c8d0489c 100644 (file)
     ConstValue, Pointer, Scalar,
     EvalResult, EvalErrorKind,
 };
-use super::{EvalContext, Machine, MemPlace, MPlaceTy, MemoryKind};
+use super::{
+    EvalContext, Machine,
+    MemPlace, MPlaceTy, PlaceTy, Place, MemoryKind,
+};
 pub use rustc::mir::interpret::ScalarMaybeUndef;
 
 /// A `Value` represents a single immediate self-contained Rust value.
@@ -41,6 +44,11 @@ pub fn with_default_tag<Tag>(self) -> Immediate<Tag>
 }
 
 impl<'tcx, Tag> Immediate<Tag> {
+    #[inline]
+    pub fn from_scalar(val: Scalar<Tag>) -> Self {
+        Immediate::Scalar(ScalarMaybeUndef::Scalar(val))
+    }
+
     #[inline]
     pub fn erase_tag(self) -> Immediate
     {
@@ -112,7 +120,7 @@ pub fn to_meta(self) -> EvalResult<'tcx, Option<Scalar<Tag>>> {
 // as input for binary and cast operations.
 #[derive(Copy, Clone, Debug)]
 pub struct ImmTy<'tcx, Tag=()> {
-    immediate: Immediate<Tag>,
+    pub imm: Immediate<Tag>,
     pub layout: TyLayout<'tcx>,
 }
 
@@ -120,7 +128,7 @@ impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> {
     type Target = Immediate<Tag>;
     #[inline(always)]
     fn deref(&self) -> &Immediate<Tag> {
-        &self.immediate
+        &self.imm
     }
 }
 
@@ -180,7 +188,7 @@ pub fn to_immediate(self) -> Immediate<Tag>
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
 pub struct OpTy<'tcx, Tag=()> {
-    crate op: Operand<Tag>, // ideally we'd make this private, but const_prop needs this
+    op: Operand<Tag>,
     pub layout: TyLayout<'tcx>,
 }
 
@@ -206,12 +214,25 @@ impl<'tcx, Tag> From<ImmTy<'tcx, Tag>> for OpTy<'tcx, Tag> {
     #[inline(always)]
     fn from(val: ImmTy<'tcx, Tag>) -> Self {
         OpTy {
-            op: Operand::Immediate(val.immediate),
+            op: Operand::Immediate(val.imm),
             layout: val.layout
         }
     }
 }
 
+impl<'tcx, Tag: Copy> ImmTy<'tcx, Tag>
+{
+    #[inline]
+    pub fn from_scalar(val: Scalar<Tag>, layout: TyLayout<'tcx>) -> Self {
+        ImmTy { imm: Immediate::from_scalar(val), layout }
+    }
+
+    #[inline]
+    pub fn to_bits(self) -> EvalResult<'tcx, u128> {
+        self.to_scalar()?.to_bits(self.layout.size)
+    }
+}
+
 impl<'tcx, Tag> OpTy<'tcx, Tag>
 {
     #[inline]
@@ -248,7 +269,7 @@ pub(super) fn from_known_layout<'tcx>(
 impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     /// Try reading an immediate in memory; this is interesting particularly for ScalarPair.
     /// Returns `None` if the layout does not permit loading this as a value.
-    pub(super) fn try_read_immediate_from_mplace(
+    fn try_read_immediate_from_mplace(
         &self,
         mplace: MPlaceTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx, Option<Immediate<M::PointerTag>>> {
@@ -302,7 +323,7 @@ pub(super) fn try_read_immediate_from_mplace(
     /// Note that for a given layout, this operation will either always fail or always
     /// succeed!  Whether it succeeds depends on whether the layout can be represented
     /// in a `Immediate`, not on which data is stored there currently.
-    pub(crate) fn try_read_immediate(
+    pub(super) fn try_read_immediate(
         &self,
         src: OpTy<'tcx, M::PointerTag>,
     ) -> EvalResult<'tcx, Result<Immediate<M::PointerTag>, MemPlace<M::PointerTag>>> {
@@ -324,8 +345,8 @@ pub fn read_immediate(
         &self,
         op: OpTy<'tcx, M::PointerTag>
     ) -> EvalResult<'tcx, ImmTy<'tcx, M::PointerTag>> {
-        if let Ok(immediate) = self.try_read_immediate(op)? {
-            Ok(ImmTy { immediate, layout: op.layout })
+        if let Ok(imm) = self.try_read_immediate(op)? {
+            Ok(ImmTy { imm, layout: op.layout })
         } else {
             bug!("primitive read failed for type: {:?}", op.layout.ty);
         }
@@ -469,9 +490,25 @@ pub fn access_local(
         Ok(OpTy { op, layout })
     }
 
+    /// Every place can be read from, so we can turm them into an operand
+    #[inline(always)]
+    pub fn place_to_op(
+        &self,
+        place: PlaceTy<'tcx, M::PointerTag>
+    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+        let op = match *place {
+            Place::Ptr(mplace) => {
+                Operand::Indirect(mplace)
+            }
+            Place::Local { frame, local } =>
+                *self.stack[frame].locals[local].access()?
+        };
+        Ok(OpTy { op, layout: place.layout })
+    }
+
     // Evaluate a place with the goal of reading from it.  This lets us sometimes
     // avoid allocations.
-    fn eval_place_to_op(
+    pub(super) fn eval_place_to_op(
         &self,
         mir_place: &mir::Place<'tcx>,
         layout: Option<TyLayout<'tcx>>,
@@ -508,14 +545,7 @@ pub fn eval_operand(
             Move(ref place) =>
                 self.eval_place_to_op(place, layout)?,
 
-            Constant(ref constant) => {
-                let layout = from_known_layout(layout, || {
-                    let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx))?;
-                    self.layout_of(ty)
-                })?;
-                let op = self.const_value_to_op(*constant.literal)?;
-                OpTy { op, layout }
-            }
+            Constant(ref constant) => self.eval_lazy_const_to_op(*constant.literal, layout)?,
         };
         trace!("{:?}: {:?}", mir_op, *op);
         Ok(op)
@@ -531,40 +561,56 @@ pub(super) fn eval_operands(
             .collect()
     }
 
-    // Used when miri runs into a constant, and by CTFE.
-    // FIXME: CTFE should use allocations, then we can make this private (embed it into
-    // `eval_operand`, ideally).
-    pub(crate) fn const_value_to_op(
+    // Used when Miri runs into a constant, and by const propagation.
+    crate fn eval_lazy_const_to_op(
         &self,
         val: ty::LazyConst<'tcx>,
-    ) -> EvalResult<'tcx, Operand<M::PointerTag>> {
-        trace!("const_value_to_op: {:?}", val);
-        let val = match val {
+        layout: Option<TyLayout<'tcx>>,
+    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+        trace!("const_to_op: {:?}", val);
+        match val {
             ty::LazyConst::Unevaluated(def_id, substs) => {
                 let instance = self.resolve(def_id, substs)?;
-                return Ok(*OpTy::from(self.const_eval_raw(GlobalId {
+                return Ok(OpTy::from(self.const_eval_raw(GlobalId {
                     instance,
                     promoted: None,
                 })?));
             },
-            ty::LazyConst::Evaluated(c) => c,
-        };
-        match val.val {
-            ConstValue::ByRef(id, alloc, offset) => {
+            ty::LazyConst::Evaluated(c) => self.const_to_op(c, layout),
+        }
+    }
+
+    // Used when the miri-engine runs into a constant and for extracting information from constants
+    // in patterns via the `const_eval` module
+    crate fn const_to_op(
+        &self,
+        val: ty::Const<'tcx>,
+        layout: Option<TyLayout<'tcx>>,
+    ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> {
+        let layout = from_known_layout(layout, || {
+            let ty = self.monomorphize(val.ty)?;
+            self.layout_of(ty)
+        })?;
+        let op = match val.val {
+            ConstValue::ByRef(ptr, alloc) => {
                 // We rely on mutability being set correctly in that allocation to prevent writes
                 // where none should happen -- and for `static mut`, we copy on demand anyway.
-                Ok(Operand::Indirect(
-                    MemPlace::from_ptr(Pointer::new(id, offset), alloc.align)
-                ).with_default_tag())
+                Operand::Indirect(
+                    MemPlace::from_ptr(ptr, alloc.align)
+                ).with_default_tag()
             },
             ConstValue::Slice(a, b) =>
-                Ok(Operand::Immediate(Immediate::ScalarPair(
+                Operand::Immediate(Immediate::ScalarPair(
                     a.into(),
                     Scalar::from_uint(b, self.tcx.data_layout.pointer_size).into(),
-                )).with_default_tag()),
+                )).with_default_tag(),
             ConstValue::Scalar(x) =>
-                Ok(Operand::Immediate(Immediate::Scalar(x.into())).with_default_tag()),
-        }
+                Operand::Immediate(Immediate::Scalar(x.into())).with_default_tag(),
+        };
+        Ok(OpTy {
+            op,
+            layout,
+        })
     }
 
     /// Read discriminant, return the runtime value as well as the variant index.
@@ -664,5 +710,4 @@ pub fn read_discriminant(
             }
         })
     }
-
 }