X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Flibrustc_mir%2Finterpret%2Foperand.rs;h=7c83bf1d27d941c2571ee23def2fc053e8bd0bd0;hb=adea1317c24738563a507b817bbf9c57471279f0;hp=289379f34a9a3bb8771d4dfe0253f7e97689fde4;hpb=525d7deb6de47a600945450807c2f3ca04047bba;p=rust.git diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 289379f34a9..7c83bf1d27d 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -9,7 +9,7 @@ use rustc::mir::interpret::{ GlobalId, AllocId, CheckInAllocMsg, ConstValue, Pointer, Scalar, - EvalResult, InterpError, InboundsCheck, + InterpResult, InterpError, InboundsCheck, sign_extend, truncate, }; use super::{ @@ -37,16 +37,6 @@ pub fn from_scalar(val: Scalar) -> Self { Immediate::Scalar(ScalarMaybeUndef::Scalar(val)) } - #[inline] - pub fn erase_tag(self) -> Immediate - { - match self { - Immediate::Scalar(x) => Immediate::Scalar(x.erase_tag()), - Immediate::ScalarPair(x, y) => - Immediate::ScalarPair(x.erase_tag(), y.erase_tag()), - } - } - pub fn new_slice( val: Scalar, len: u64, @@ -71,12 +61,12 @@ pub fn to_scalar_or_undef(self) -> ScalarMaybeUndef { } #[inline] - pub fn to_scalar(self) -> EvalResult<'tcx, Scalar> { + pub fn to_scalar(self) -> InterpResult<'tcx, Scalar> { self.to_scalar_or_undef().not_undef() } #[inline] - pub fn to_scalar_pair(self) -> EvalResult<'tcx, (Scalar, Scalar)> { + pub fn to_scalar_pair(self) -> InterpResult<'tcx, (Scalar, Scalar)> { match self { Immediate::Scalar(..) => bug!("Got a thin pointer where a scalar pair was expected"), Immediate::ScalarPair(a, b) => Ok((a.not_undef()?, b.not_undef()?)) @@ -86,7 +76,7 @@ pub fn to_scalar_pair(self) -> EvalResult<'tcx, (Scalar, Scalar)> { /// Converts the immediate into a pointer (or a pointer-sized integer). /// Throws away the second half of a ScalarPair! #[inline] - pub fn to_scalar_ptr(self) -> EvalResult<'tcx, Scalar> { + pub fn to_scalar_ptr(self) -> InterpResult<'tcx, Scalar> { match self { Immediate::Scalar(ptr) | Immediate::ScalarPair(ptr, _) => ptr.not_undef(), @@ -96,7 +86,7 @@ pub fn to_scalar_ptr(self) -> EvalResult<'tcx, Scalar> { /// Converts the value into its metadata. /// Throws away the first half of a ScalarPair! #[inline] - pub fn to_meta(self) -> EvalResult<'tcx, Option>> { + pub fn to_meta(self) -> InterpResult<'tcx, Option>> { Ok(match self { Immediate::Scalar(_) => None, Immediate::ScalarPair(_, meta) => Some(meta.not_undef()?), @@ -130,15 +120,6 @@ pub enum Operand { } impl Operand { - #[inline] - pub fn erase_tag(self) -> Operand - { - match self { - Operand::Immediate(x) => Operand::Immediate(x.erase_tag()), - Operand::Indirect(x) => Operand::Indirect(x.erase_tag()), - } - } - #[inline] pub fn to_mem_place(self) -> MemPlace where Tag: ::std::fmt::Debug @@ -204,30 +185,18 @@ pub fn from_scalar(val: Scalar, layout: TyLayout<'tcx>) -> Self { } #[inline] - pub fn to_bits(self) -> EvalResult<'tcx, u128> { + pub fn to_bits(self) -> InterpResult<'tcx, u128> { self.to_scalar()?.to_bits(self.layout.size) } } -impl<'tcx, Tag> OpTy<'tcx, Tag> -{ - #[inline] - pub fn erase_tag(self) -> OpTy<'tcx> - { - OpTy { - op: self.op.erase_tag(), - layout: self.layout, - } - } -} - // Use the existing layout if given (but sanity check in debug mode), // or compute the layout. #[inline(always)] pub(super) fn from_known_layout<'tcx>( layout: Option>, - compute: impl FnOnce() -> EvalResult<'tcx, TyLayout<'tcx>> -) -> EvalResult<'tcx, TyLayout<'tcx>> { + compute: impl FnOnce() -> InterpResult<'tcx, TyLayout<'tcx>> +) -> InterpResult<'tcx, TyLayout<'tcx>> { match layout { None => compute(), Some(layout) => { @@ -243,12 +212,12 @@ pub(super) fn from_known_layout<'tcx>( } impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> { - /// Try reading an immediate in memory; this is interesting particularly for ScalarPair. + /// 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. fn try_read_immediate_from_mplace( &self, mplace: MPlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, Option>> { + ) -> InterpResult<'tcx, Option>> { if mplace.layout.is_unsized() { // Don't touch unsized return Ok(None); @@ -299,10 +268,10 @@ 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(super) fn try_read_immediate( + pub(crate) fn try_read_immediate( &self, src: OpTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, Result, MemPlace>> { + ) -> InterpResult<'tcx, Result, MemPlace>> { Ok(match src.try_as_mplace() { Ok(mplace) => { if let Some(val) = self.try_read_immediate_from_mplace(mplace)? { @@ -320,7 +289,7 @@ pub(super) fn try_read_immediate( pub fn read_immediate( &self, op: OpTy<'tcx, M::PointerTag> - ) -> EvalResult<'tcx, ImmTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, ImmTy<'tcx, M::PointerTag>> { if let Ok(imm) = self.try_read_immediate(op)? { Ok(ImmTy { imm, layout: op.layout }) } else { @@ -332,7 +301,7 @@ pub fn read_immediate( pub fn read_scalar( &self, op: OpTy<'tcx, M::PointerTag> - ) -> EvalResult<'tcx, ScalarMaybeUndef> { + ) -> InterpResult<'tcx, ScalarMaybeUndef> { Ok(self.read_immediate(op)?.to_scalar_or_undef()) } @@ -340,7 +309,7 @@ pub fn read_scalar( pub fn read_str( &self, mplace: MPlaceTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, &str> { + ) -> InterpResult<'tcx, &str> { let len = mplace.len(self)?; let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len as u64))?; let str = ::std::str::from_utf8(bytes) @@ -353,7 +322,7 @@ pub fn operand_field( &self, op: OpTy<'tcx, M::PointerTag>, field: u64, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let base = match op.try_as_mplace() { Ok(mplace) => { // The easy case @@ -388,7 +357,7 @@ pub fn operand_downcast( &self, op: OpTy<'tcx, M::PointerTag>, variant: VariantIdx, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { // Downcasts only change the layout Ok(match op.try_as_mplace() { Ok(mplace) => { @@ -405,7 +374,7 @@ pub fn operand_projection( &self, base: OpTy<'tcx, M::PointerTag>, proj_elem: &mir::PlaceElem<'tcx>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { use rustc::mir::ProjectionElem::*; Ok(match *proj_elem { Field(field, _) => self.operand_field(base, field.index() as u64)?, @@ -432,7 +401,7 @@ pub fn access_local( frame: &super::Frame<'mir, 'tcx, M::PointerTag, M::FrameExtra>, local: mir::Local, layout: Option>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { assert_ne!(local, mir::RETURN_PLACE); let layout = self.layout_of_local(frame, local, layout)?; let op = if layout.is_zst() { @@ -444,12 +413,12 @@ pub fn access_local( Ok(OpTy { op, layout }) } - /// Every place can be read from, so we can turm them into an operand + /// Every place can be read from, so we can turn them into an operand #[inline(always)] pub fn place_to_op( &self, place: PlaceTy<'tcx, M::PointerTag> - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { let op = match *place { Place::Ptr(mplace) => { Operand::Indirect(mplace) @@ -466,7 +435,7 @@ pub(super) fn eval_place_to_op( &self, mir_place: &mir::Place<'tcx>, layout: Option>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { use rustc::mir::Place; use rustc::mir::PlaceBase; @@ -500,13 +469,13 @@ pub(super) fn eval_place_to_op( } /// Evaluate the operand, returning a place where you can then find the data. - /// if you already know the layout, you can save two some table lookups + /// If you already know the layout, you can save two table lookups /// by passing it in here. pub fn eval_operand( &self, mir_op: &mir::Operand<'tcx>, layout: Option>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { use rustc::mir::Operand::*; let op = match *mir_op { // FIXME: do some more logic on `move` to invalidate the old location @@ -524,7 +493,7 @@ pub fn eval_operand( pub(super) fn eval_operands( &self, ops: &[mir::Operand<'tcx>], - ) -> EvalResult<'tcx, Vec>> { + ) -> InterpResult<'tcx, Vec>> { ops.into_iter() .map(|op| self.eval_operand(op, None)) .collect() @@ -536,52 +505,63 @@ pub(super) fn eval_operands( &self, val: &'tcx ty::Const<'tcx>, layout: Option>, - ) -> EvalResult<'tcx, OpTy<'tcx, M::PointerTag>> { - let op = match val.val { - ConstValue::Param(_) => return err!(TooGeneric), - ConstValue::Infer(_) | ConstValue::Placeholder(_) => bug!(), - 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. - Operand::Indirect( - MemPlace::from_ptr(ptr.with_default_tag(), alloc.align) - ) - }, - ConstValue::Slice { data, start, end } => - Operand::Immediate(Immediate::ScalarPair( - Scalar::from(Pointer::new( - self.tcx.alloc_map.lock().allocate(data), - Size::from_bytes(start as u64), - )).with_default_tag().into(), - Scalar::from_uint( - (end - start) as u64, - self.tcx.data_layout.pointer_size, - ).with_default_tag().into(), - )), - ConstValue::Scalar(x) => - Operand::Immediate(Immediate::Scalar(x.with_default_tag().into())), + ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> { + let tag_scalar = |scalar| match scalar { + Scalar::Ptr(ptr) => Scalar::Ptr(self.tag_static_base_pointer(ptr)), + Scalar::Raw { data, size } => Scalar::Raw { data, size }, + }; + // Early-return cases. + match val.val { + ConstValue::Param(_) => return err!(TooGeneric), // FIXME(oli-obk): try to monomorphize ConstValue::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; return Ok(OpTy::from(self.const_eval_raw(GlobalId { instance, promoted: None, })?)); - }, - }; + } + _ => {} + } + // Other cases need layout. let layout = from_known_layout(layout, || { self.layout_of(self.monomorphize(val.ty)?) })?; - Ok(OpTy { - op, - layout, - }) + 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. + let ptr = self.tag_static_base_pointer(ptr); + Operand::Indirect(MemPlace::from_ptr(ptr, layout.align.abi)) + }, + ConstValue::Scalar(x) => + Operand::Immediate(Immediate::Scalar(tag_scalar(x).into())), + ConstValue::Slice { data, start, end } => { + // We rely on mutability being set correctly in `data` to prevent writes + // where none should happen. + let ptr = Pointer::new( + self.tcx.alloc_map.lock().create_memory_alloc(data), + Size::from_bytes(start as u64), // offset: `start` + ); + Operand::Immediate(Immediate::new_slice( + self.tag_static_base_pointer(ptr).into(), + (end - start) as u64, // len: `end - start` + self, + )) + } + ConstValue::Param(..) | + ConstValue::Infer(..) | + ConstValue::Placeholder(..) | + ConstValue::Unevaluated(..) => + bug!("eval_const_to_op: Unexpected ConstValue {:?}", val), + }; + Ok(OpTy { op, layout }) } /// Read discriminant, return the runtime value as well as the variant index. pub fn read_discriminant( &self, rval: OpTy<'tcx, M::PointerTag>, - ) -> EvalResult<'tcx, (u128, VariantIdx)> { + ) -> InterpResult<'tcx, (u128, VariantIdx)> { trace!("read_discriminant_value {:#?}", rval.layout); let (discr_kind, discr_index) = match rval.layout.variants {