From 08646c6c2c167d4c04897660dc524623d349bdb1 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Sat, 16 Dec 2017 23:34:43 +0200 Subject: [PATCH] miri: use separate Pointer and Align instead of PtrAndAlign. --- src/librustc/mir/interpret/mod.rs | 2 +- src/librustc/mir/interpret/value.rs | 20 +--- src/librustc_mir/interpret/const_eval.rs | 98 +++++++------------ src/librustc_mir/interpret/eval_context.rs | 58 ++++------- src/librustc_mir/interpret/memory.rs | 14 +-- src/librustc_mir/interpret/place.rs | 79 ++++++++------- src/librustc_mir/interpret/terminator/drop.rs | 9 +- src/librustc_mir/interpret/terminator/mod.rs | 10 +- 8 files changed, 113 insertions(+), 177 deletions(-) diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index c5d2ec1668c..6785e06ae35 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -10,7 +10,7 @@ mod value; pub use self::error::{EvalError, EvalResult, EvalErrorKind}; -pub use self::value::{PrimVal, PrimValKind, Value, Pointer, PtrAndAlign, bytes_to_f32, bytes_to_f64}; +pub use self::value::{PrimVal, PrimValKind, Value, Pointer, bytes_to_f32, bytes_to_f64}; use std::collections::BTreeMap; use ty::layout::HasDataLayout; diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 10da5e7843b..0bfff2a80e6 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -6,24 +6,6 @@ use super::{EvalResult, MemoryPointer, PointerArithmetic}; use syntax::ast::FloatTy; use rustc_const_math::ConstFloat; -#[derive(Copy, Clone, Debug)] -pub struct PtrAndAlign { - pub ptr: Pointer, - pub align: Align, -} - -impl PtrAndAlign { - pub fn to_ptr<'tcx>(self) -> EvalResult<'tcx, MemoryPointer> { - self.ptr.to_ptr() - } - pub fn offset<'tcx, C: HasDataLayout>(self, i: u64, cx: C) -> EvalResult<'tcx, Self> { - Ok(PtrAndAlign { - ptr: self.ptr.offset(i, cx)?, - align: self.align, - }) - } -} - pub fn bytes_to_f32(bits: u128) -> ConstFloat { ConstFloat { bits, @@ -49,7 +31,7 @@ pub fn bytes_to_f64(bits: u128) -> ConstFloat { /// operations and fat pointers. This idea was taken from rustc's trans. #[derive(Clone, Copy, Debug)] pub enum Value { - ByRef(PtrAndAlign), + ByRef(Pointer, Align), ByVal(PrimVal), ByValPair(PrimVal, PrimVal), } diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 4d9f55543e7..15840bffbde 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -12,8 +12,8 @@ use rustc_data_structures::indexed_vec::Idx; use syntax::ast::Mutability; use syntax::codemap::Span; -use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, Pointer, PrimVal, PtrAndAlign}; -use super::{Place, PlaceExtra, EvalContext, StackPopCleanup, ValTy, HasMemory}; +use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, Pointer, PrimVal}; +use super::{Place, EvalContext, StackPopCleanup, ValTy}; use rustc_const_math::ConstInt; @@ -357,11 +357,9 @@ pub fn const_eval_provider<'a, 'tcx>( (_, Err(err)) => Err(err), (Ok((miri_val, miri_ty)), Ok(ctfe)) => { let mut ecx = mk_eval_cx(tcx, instance, key.param_env).unwrap(); - let miri_ptr = PtrAndAlign { - ptr: miri_val, - align: ecx.layout_of(miri_ty).unwrap().align - }; - check_ctfe_against_miri(&mut ecx, miri_ptr, miri_ty, ctfe.val); + let layout = ecx.layout_of(miri_ty).unwrap(); + let miri_place = Place::from_primval_ptr(miri_val, layout.align); + check_ctfe_against_miri(&mut ecx, miri_place, miri_ty, ctfe.val); Ok(ctfe) } } @@ -372,19 +370,20 @@ pub fn const_eval_provider<'a, 'tcx>( fn check_ctfe_against_miri<'a, 'tcx>( ecx: &mut EvalContext<'a, 'tcx, CompileTimeEvaluator>, - miri_val: PtrAndAlign, + miri_place: Place, miri_ty: Ty<'tcx>, ctfe: ConstVal<'tcx>, ) { use rustc::middle::const_val::ConstAggregate::*; use rustc_const_math::ConstFloat; use rustc::ty::TypeVariants::*; + let miri_val = ValTy { + value: ecx.read_place(miri_place).unwrap(), + ty: miri_ty + }; match miri_ty.sty { TyInt(int_ty) => { - let value = ecx.read_with_align(miri_val.align, |ectx| { - ectx.try_read_value(miri_val.ptr, miri_ty) - }); - let prim = get_prim(ecx, value); + let prim = get_prim(ecx, miri_val); let c = ConstInt::new_signed_truncating(prim as i128, int_ty, ecx.tcx.sess.target.isize_ty); @@ -392,10 +391,7 @@ fn check_ctfe_against_miri<'a, 'tcx>( assert_eq!(c, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", c, ctfe); }, TyUint(uint_ty) => { - let value = ecx.read_with_align(miri_val.align, |ectx| { - ectx.try_read_value(miri_val.ptr, miri_ty) - }); - let prim = get_prim(ecx, value); + let prim = get_prim(ecx, miri_val); let c = ConstInt::new_unsigned_truncating(prim, uint_ty, ecx.tcx.sess.target.usize_ty); @@ -403,18 +399,12 @@ fn check_ctfe_against_miri<'a, 'tcx>( assert_eq!(c, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", c, ctfe); }, TyFloat(ty) => { - let value = ecx.read_with_align(miri_val.align, |ectx| { - ectx.try_read_value(miri_val.ptr, miri_ty) - }); - let prim = get_prim(ecx, value); + let prim = get_prim(ecx, miri_val); let f = ConstVal::Float(ConstFloat { bits: prim, ty }); assert_eq!(f, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", f, ctfe); }, TyBool => { - let value = ecx.read_with_align(miri_val.align, |ectx| { - ectx.try_read_value(miri_val.ptr, miri_ty) - }); - let bits = get_prim(ecx, value); + let bits = get_prim(ecx, miri_val); if bits > 1 { bug!("miri evaluated to {}, but expected a bool {:?}", bits, ctfe); } @@ -422,10 +412,7 @@ fn check_ctfe_against_miri<'a, 'tcx>( assert_eq!(b, ctfe, "miri evaluated to {:?}, but ctfe yielded {:?}", b, ctfe); }, TyChar => { - let value = ecx.read_with_align(miri_val.align, |ectx| { - ectx.try_read_value(miri_val.ptr, miri_ty) - }); - let bits = get_prim(ecx, value); + let bits = get_prim(ecx, miri_val); if let Some(cm) = ::std::char::from_u32(bits as u32) { assert_eq!( ConstVal::Char(cm), ctfe, @@ -436,10 +423,8 @@ fn check_ctfe_against_miri<'a, 'tcx>( } }, TyStr => { - let value = ecx.read_with_align(miri_val.align, |ectx| { - ectx.try_read_value(miri_val.ptr, miri_ty) - }); - if let Ok(Some(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len)))) = value { + let value = ecx.follow_by_ref_value(miri_val.value, miri_val.ty); + if let Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len))) = value { let bytes = ecx .memory .read_bytes(ptr.into(), len as u64) @@ -463,7 +448,6 @@ fn check_ctfe_against_miri<'a, 'tcx>( }, TyArray(elem_ty, n) => { let n = n.val.to_const_int().unwrap().to_u64().unwrap(); - let size = ecx.layout_of(elem_ty).unwrap().size.bytes(); let vec: Vec<(ConstVal, Ty<'tcx>)> = match ctfe { ConstVal::ByteStr(arr) => arr.data.iter().map(|&b| { (ConstVal::Integral(ConstInt::U8(b)), ecx.tcx.types.u8) @@ -476,10 +460,12 @@ fn check_ctfe_against_miri<'a, 'tcx>( }, _ => bug!("miri produced {:?}, but ctfe yielded {:?}", miri_ty, ctfe), }; + let layout = ecx.layout_of(miri_ty).unwrap(); for (i, elem) in vec.into_iter().enumerate() { assert!((i as u64) < n); - let ptr = miri_val.offset(size * i as u64, &ecx).unwrap(); - check_ctfe_against_miri(ecx, ptr, elem_ty, elem.0); + let (field_place, _) = + ecx.place_field(miri_place, Field::new(i), layout).unwrap(); + check_ctfe_against_miri(ecx, field_place, elem_ty, elem.0); } }, TyTuple(..) => { @@ -489,22 +475,22 @@ fn check_ctfe_against_miri<'a, 'tcx>( }; let layout = ecx.layout_of(miri_ty).unwrap(); for (i, elem) in vec.into_iter().enumerate() { - let offset = layout.fields.offset(i); - let ptr = miri_val.offset(offset.bytes(), &ecx).unwrap(); - check_ctfe_against_miri(ecx, ptr, elem.ty, elem.val); + let (field_place, _) = + ecx.place_field(miri_place, Field::new(i), layout).unwrap(); + check_ctfe_against_miri(ecx, field_place, elem.ty, elem.val); } }, TyAdt(def, _) => { - let (struct_variant, extra) = if def.is_enum() { - let discr = ecx.read_discriminant_value( - Place::Ptr { ptr: miri_val, extra: PlaceExtra::None }, - miri_ty).unwrap(); + let mut miri_place = miri_place; + let struct_variant = if def.is_enum() { + let discr = ecx.read_discriminant_value(miri_place, miri_ty).unwrap(); let variant = def.discriminants(ecx.tcx).position(|variant_discr| { variant_discr.to_u128_unchecked() == discr }).expect("miri produced invalid enum discriminant"); - (&def.variants[variant], PlaceExtra::DowncastVariant(variant)) + miri_place = ecx.place_downcast(miri_place, variant).unwrap(); + &def.variants[variant] } else { - (def.struct_variant(), PlaceExtra::None) + def.struct_variant() }; let vec = match ctfe { ConstVal::Aggregate(Struct(v)) => v, @@ -518,12 +504,9 @@ fn check_ctfe_against_miri<'a, 'tcx>( let layout = ecx.layout_of(miri_ty).unwrap(); for &(name, elem) in vec.into_iter() { let field = struct_variant.fields.iter().position(|f| f.name == name).unwrap(); - let (place, _) = ecx.place_field( - Place::Ptr { ptr: miri_val, extra }, - Field::new(field), - layout, - ).unwrap(); - check_ctfe_against_miri(ecx, place.to_ptr_align(), elem.ty, elem.val); + let (field_place, _) = + ecx.place_field(miri_place, Field::new(field), layout).unwrap(); + check_ctfe_against_miri(ecx, field_place, elem.ty, elem.val); } }, TySlice(_) => bug!("miri produced a slice?"), @@ -543,11 +526,9 @@ fn check_ctfe_against_miri<'a, 'tcx>( // should be fine TyFnDef(..) => {} TyFnPtr(_) => { - let value = ecx.read_with_align(miri_val.align, |ectx| { - ectx.try_read_value(miri_val.ptr, miri_ty) - }); + let value = ecx.value_to_primval(miri_val); let ptr = match value { - Ok(Some(Value::ByVal(PrimVal::Ptr(ptr)))) => ptr, + Ok(PrimVal::Ptr(ptr)) => ptr, value => bug!("expected fn ptr, got {:?}", value), }; let inst = ecx.memory.get_fn(ptr).unwrap(); @@ -569,13 +550,10 @@ fn check_ctfe_against_miri<'a, 'tcx>( fn get_prim<'a, 'tcx>( ecx: &mut EvalContext<'a, 'tcx, CompileTimeEvaluator>, - res: Result, EvalError<'tcx>>, + val: ValTy<'tcx>, ) -> u128 { - match res { - Ok(Some(Value::ByVal(prim))) => unwrap_miri(ecx, prim.to_bytes()), - Err(err) => unwrap_miri(ecx, Err(err)), - val => bug!("got {:?}", val), - } + let res = ecx.value_to_primval(val).and_then(|prim| prim.to_bytes()); + unwrap_miri(ecx, res) } fn unwrap_miri<'a, 'tcx, T>( diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index b1febf5da5a..bc0d82399b5 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -13,7 +13,7 @@ use rustc_data_structures::indexed_vec::Idx; use syntax::codemap::{self, DUMMY_SP}; use syntax::ast::Mutability; use rustc::mir::interpret::{ - PtrAndAlign, GlobalId, Value, Pointer, PrimVal, PrimValKind, + GlobalId, Value, Pointer, PrimVal, PrimValKind, EvalError, EvalResult, EvalErrorKind, MemoryPointer, }; @@ -498,7 +498,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } pub fn deallocate_local(&mut self, local: Option) -> EvalResult<'tcx> { - if let Some(Value::ByRef(ptr)) = local { + if let Some(Value::ByRef(ptr, _align)) = local { trace!("deallocating local"); let ptr = ptr.to_ptr()?; self.memory.dump_alloc(ptr.alloc_id); @@ -637,12 +637,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let src = self.eval_place(place)?; // We ignore the alignment of the place here -- special handling for packed structs ends // at the `&` operator. - let (ptr, extra) = self.force_allocation(src)?.to_ptr_align_extra(); + let (ptr, _align, extra) = self.force_allocation(src)?.to_ptr_align_extra(); let val = match extra { - PlaceExtra::None => ptr.ptr.to_value(), - PlaceExtra::Length(len) => ptr.ptr.to_value_with_len(len), - PlaceExtra::Vtable(vtable) => ptr.ptr.to_value_with_vtable(vtable), + PlaceExtra::None => ptr.to_value(), + PlaceExtra::Length(len) => ptr.to_value_with_len(len), + PlaceExtra::Vtable(vtable) => ptr.to_value_with_vtable(vtable), PlaceExtra::DowncastVariant(..) => { bug!("attempted to take a reference to an enum downcast place") } @@ -951,10 +951,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } pub fn read_global_as_value(&self, gid: GlobalId, layout: TyLayout) -> Value { - Value::ByRef(PtrAndAlign { - ptr: self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached"), - align: layout.align - }) + Value::ByRef(self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached"), + layout.align) } fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx> { @@ -972,9 +970,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { // -1 since we don't store the return value match self.stack[frame].locals[local.index() - 1] { None => return err!(DeadLocal), - Some(Value::ByRef(ptr)) => { + Some(Value::ByRef(ptr, align)) => { Place::Ptr { ptr, + align, extra: PlaceExtra::None, } } @@ -984,10 +983,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let layout = self.layout_of(ty)?; let ptr = self.alloc_ptr(ty)?; self.stack[frame].locals[local.index() - 1] = - Some(Value::ByRef(PtrAndAlign { - ptr: ptr.into(), - align: layout.align - })); // it stays live + Some(Value::ByRef(ptr.into(), layout.align)); // it stays live self.write_value_to_ptr(val, ptr.into(), ty)?; Place::from_ptr(ptr, layout.align) } @@ -1005,7 +1001,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { ty: Ty<'tcx>, ) -> EvalResult<'tcx, Value> { match value { - Value::ByRef(PtrAndAlign { ptr, align }) => { + Value::ByRef(ptr, align) => { self.read_with_align(align, |ectx| ectx.read_value(ptr, ty)) } other => Ok(other), @@ -1061,10 +1057,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { // correct if we never look at this data with the wrong type. match dest { - Place::Ptr { - ptr: PtrAndAlign { ptr, align }, - extra, - } => { + Place::Ptr { ptr, align, extra } => { assert_eq!(extra, PlaceExtra::None); self.write_with_align_mut(align, |ectx| ectx.write_value_to_ptr(src_val, ptr, dest_ty)) @@ -1090,11 +1083,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { old_dest_val: Value, dest_ty: Ty<'tcx>, ) -> EvalResult<'tcx> { - if let Value::ByRef(PtrAndAlign { - ptr: dest_ptr, - align, - }) = old_dest_val - { + if let Value::ByRef(dest_ptr, align) = old_dest_val { // If the value is already `ByRef` (that is, backed by an `Allocation`), // then we must write the new value into this allocation, because there may be // other pointers into the allocation. These other pointers are logically @@ -1106,11 +1095,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { ectx.write_value_to_ptr(src_val, dest_ptr, dest_ty) })?; - } else if let Value::ByRef(PtrAndAlign { - ptr: src_ptr, - align, - }) = src_val - { + } else if let Value::ByRef(src_ptr, align) = src_val { // If the value is not `ByRef`, then we know there are no pointers to it // and we can simply overwrite the `Value` in the locals array directly. // @@ -1129,10 +1114,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let dest_ptr = ectx.alloc_ptr(dest_ty)?.into(); ectx.copy(src_ptr, dest_ptr, dest_ty)?; let layout = ectx.layout_of(dest_ty)?; - write_dest(ectx, Value::ByRef(PtrAndAlign { - ptr: dest_ptr, - align: layout.align - }))?; + write_dest(ectx, Value::ByRef(dest_ptr, layout.align))?; } Ok(()) })?; @@ -1153,7 +1135,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { ) -> EvalResult<'tcx> { trace!("write_value_to_ptr: {:#?}", value); match value { - Value::ByRef(PtrAndAlign { ptr, align }) => { + Value::ByRef(ptr, align) => { self.read_with_align_mut(align, |ectx| ectx.copy(ptr, dest, dest_ty)) } Value::ByVal(primval) => { @@ -1485,7 +1467,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { continue; } let (src_f_value, src_field) = match src { - Value::ByRef(PtrAndAlign { ptr, align }) => { + Value::ByRef(ptr, align) => { let src_place = Place::from_primval_ptr(ptr, align); let (src_f_place, src_field) = self.place_field(src_place, mir::Field::new(i), src_layout)?; @@ -1537,7 +1519,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { Err(err) => { panic!("Failed to access local: {:?}", err); } - Ok(Value::ByRef(PtrAndAlign { ptr, align })) => { + Ok(Value::ByRef(ptr, align)) => { match ptr.into_inner_primval() { PrimVal::Ptr(ptr) => { write!(msg, " by align({}) ref:", align.abi()).unwrap(); @@ -1566,7 +1548,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { trace!("{}", msg); self.memory.dump_allocs(allocs); } - Place::Ptr { ptr: PtrAndAlign { ptr, align }, .. } => { + Place::Ptr { ptr, align, .. } => { match ptr.into_inner_primval() { PrimVal::Ptr(ptr) => { trace!("by align({}) ref:", align.abi()); diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 579977ba4a4..807b75a9e59 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -7,7 +7,7 @@ use rustc::ty::{Instance, TyCtxt}; use rustc::ty::layout::{self, Align, TargetDataLayout}; use syntax::ast::Mutability; -use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, UndefMask, PtrAndAlign, Value, Pointer, +use rustc::mir::interpret::{MemoryPointer, AllocId, Allocation, AccessKind, UndefMask, Value, Pointer, EvalResult, PrimVal, EvalErrorKind}; use super::{EvalContext, Machine}; @@ -1046,7 +1046,7 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> { value: Value, ) -> EvalResult<'tcx, Pointer> { Ok(match value { - Value::ByRef(PtrAndAlign { ptr, align }) => { + Value::ByRef(ptr, align) => { self.memory().read_with_align(align, |mem| mem.read_ptr_sized_unsigned(ptr.to_ptr()?))? } Value::ByVal(ptr) | @@ -1059,10 +1059,7 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> { value: Value, ) -> EvalResult<'tcx, (Pointer, MemoryPointer)> { match value { - Value::ByRef(PtrAndAlign { - ptr: ref_ptr, - align, - }) => { + Value::ByRef(ref_ptr, align) => { self.memory().read_with_align(align, |mem| { let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?)?.into(); let vtable = mem.read_ptr_sized_unsigned( @@ -1084,10 +1081,7 @@ pub trait HasMemory<'a, 'tcx: 'a, M: Machine<'tcx>> { value: Value, ) -> EvalResult<'tcx, (Pointer, u64)> { match value { - Value::ByRef(PtrAndAlign { - ptr: ref_ptr, - align, - }) => { + Value::ByRef(ref_ptr, align) => { self.memory().read_with_align(align, |mem| { let ptr = mem.read_ptr_sized_unsigned(ref_ptr.to_ptr()?)?.into(); let len = mem.read_ptr_sized_unsigned( diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index baccdd381d6..097f769adcf 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -2,9 +2,8 @@ use rustc::mir; use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; use rustc_data_structures::indexed_vec::Idx; -use rustc::mir::interpret::{GlobalId, PtrAndAlign}; -use rustc::mir::interpret::{Value, PrimVal, EvalResult, Pointer, MemoryPointer}; +use rustc::mir::interpret::{GlobalId, Value, PrimVal, EvalResult, Pointer, MemoryPointer}; use super::{EvalContext, Machine, ValTy}; use interpret::memory::HasMemory; @@ -15,7 +14,8 @@ pub enum Place { /// An place may have an invalid (integral or undef) pointer, /// since it might be turned back into a reference /// before ever being dereferenced. - ptr: PtrAndAlign, + ptr: Pointer, + align: Align, extra: PlaceExtra, }, @@ -40,7 +40,8 @@ impl<'tcx> Place { pub fn from_primval_ptr(ptr: Pointer, align: Align) -> Self { Place::Ptr { - ptr: PtrAndAlign { ptr, align }, + ptr, + align, extra: PlaceExtra::None, } } @@ -49,23 +50,23 @@ impl<'tcx> Place { Self::from_primval_ptr(ptr.into(), align) } - pub fn to_ptr_align_extra(self) -> (PtrAndAlign, PlaceExtra) { + pub fn to_ptr_align_extra(self) -> (Pointer, Align, PlaceExtra) { match self { - Place::Ptr { ptr, extra } => (ptr, extra), + Place::Ptr { ptr, align, extra } => (ptr, align, extra), _ => bug!("to_ptr_and_extra: expected Place::Ptr, got {:?}", self), } } - pub fn to_ptr_align(self) -> PtrAndAlign { - let (ptr, _extra) = self.to_ptr_align_extra(); - ptr + pub fn to_ptr_align(self) -> (Pointer, Align) { + let (ptr, align, _extra) = self.to_ptr_align_extra(); + (ptr, align) } pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> { // 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. - self.to_ptr_align().to_ptr() + self.to_ptr_align().0.to_ptr() } pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { @@ -169,9 +170,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { pub fn read_place(&self, place: Place) -> EvalResult<'tcx, Value> { match place { - Place::Ptr { ptr, extra } => { + Place::Ptr { ptr, align, extra } => { assert_eq!(extra, PlaceExtra::None); - Ok(Value::ByRef(ptr)) + Ok(Value::ByRef(ptr, align)) } Place::Local { frame, local } => self.stack[frame].get_local(local), } @@ -194,10 +195,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { }; let layout = self.layout_of(self.place_ty(mir_place))?; Place::Ptr { - ptr: PtrAndAlign { - ptr: self.tcx.interpret_interner.borrow().get_cached(gid).expect("uncached global"), - align: layout.align - }, + ptr: self.tcx.interpret_interner.borrow().get_cached(gid).expect("uncached global"), + align: layout.align, extra: PlaceExtra::None, } } @@ -233,8 +232,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let offset = base_layout.fields.offset(field_index); // Do not allocate in trivial cases - let (base_ptr, base_extra) = match base { - Place::Ptr { ptr, extra } => (ptr, extra), + let (base_ptr, base_align, base_extra) = match base { + Place::Ptr { ptr, align, extra } => (ptr, align, extra), Place::Local { frame, local } => { match (&self.stack[frame].get_local(local)?, &base_layout.abi) { // in case the field covers the entire type, just return the value @@ -253,16 +252,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { PlaceExtra::Vtable(tab) => { let (_, align) = self.size_and_align_of_dst( base_layout.ty, - base_ptr.ptr.to_value_with_vtable(tab), + base_ptr.to_value_with_vtable(tab), )?; offset.abi_align(align).bytes() } _ => offset.bytes(), }; - let mut ptr = base_ptr.offset(offset, &self)?; - ptr.align = ptr.align.min(base_layout.align).min(field.align); - + let ptr = base_ptr.offset(offset, &self)?; + let align = base_align.min(base_layout.align).min(field.align); let extra = if !field.is_unsized() { PlaceExtra::None } else { @@ -277,7 +275,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { base_extra }; - Ok((Place::Ptr { ptr, extra }, field)) + Ok((Place::Ptr { ptr, align, extra }, field)) } pub fn val_to_place(&self, val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Place> { @@ -286,14 +284,16 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { ty::TyDynamic(..) => { let (ptr, vtable) = self.into_ptr_vtable_pair(val)?; Place::Ptr { - ptr: PtrAndAlign { ptr, align: layout.align }, + ptr, + align: layout.align, extra: PlaceExtra::Vtable(vtable), } } ty::TyStr | ty::TySlice(_) => { let (ptr, len) = self.into_slice(val)?; Place::Ptr { - ptr: PtrAndAlign { ptr, align: layout.align }, + ptr, + align: layout.align, extra: PlaceExtra::Length(len), } } @@ -309,7 +309,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { ) -> EvalResult<'tcx, Place> { // Taking the outer type here may seem odd; it's needed because for array types, the outer type gives away the length. let base = self.force_allocation(base)?; - let base_ptr = base.to_ptr_align(); + let (base_ptr, align) = base.to_ptr_align(); let (elem_ty, len) = base.elem_ty_and_len(outer_ty); let elem_size = self.layout_of(elem_ty)?.size.bytes(); @@ -322,6 +322,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let ptr = base_ptr.offset(n * elem_size, &*self)?; Ok(Place::Ptr { ptr, + align, extra: PlaceExtra::None, }) } @@ -333,9 +334,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { ) -> EvalResult<'tcx, Place> { // FIXME(solson) let base = self.force_allocation(base)?; - let ptr = base.to_ptr_align(); + let (ptr, align) = base.to_ptr_align(); let extra = PlaceExtra::DowncastVariant(variant); - Ok(Place::Ptr { ptr, extra }) + Ok(Place::Ptr { ptr, align, extra }) } pub fn eval_place_projection( @@ -345,14 +346,14 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>, ) -> EvalResult<'tcx, Place> { use rustc::mir::ProjectionElem::*; - let (ptr, extra) = match *proj_elem { + match *proj_elem { Field(field, _) => { let layout = self.layout_of(base_ty)?; - return Ok(self.place_field(base, field, layout)?.0); + Ok(self.place_field(base, field, layout)?.0) } Downcast(_, variant) => { - return self.place_downcast(base, variant); + self.place_downcast(base, variant) } Deref => { @@ -367,14 +368,14 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { trace!("deref to {} on {:?}", pointee_type, val); - return self.val_to_place(val, pointee_type); + self.val_to_place(val, pointee_type) } Index(local) => { let value = self.frame().get_local(local)?; let ty = self.tcx.types.usize; let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; - return self.place_index(base, base_ty, n); + self.place_index(base, base_ty, n) } ConstantIndex { @@ -384,7 +385,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } => { // FIXME(solson) let base = self.force_allocation(base)?; - let base_ptr = base.to_ptr_align(); + let (base_ptr, align) = base.to_ptr_align(); let (elem_ty, n) = base.elem_ty_and_len(base_ty); let elem_size = self.layout_of(elem_ty)?.size.bytes(); @@ -397,13 +398,13 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { }; let ptr = base_ptr.offset(index * elem_size, &self)?; - (ptr, PlaceExtra::None) + Ok(Place::Ptr { ptr, align, extra: PlaceExtra::None }) } Subslice { from, to } => { // FIXME(solson) let base = self.force_allocation(base)?; - let base_ptr = base.to_ptr_align(); + let (base_ptr, align) = base.to_ptr_align(); let (elem_ty, n) = base.elem_ty_and_len(base_ty); let elem_size = self.layout_of(elem_ty)?.size.bytes(); @@ -415,11 +416,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { } else { PlaceExtra::Length(n - u64::from(to) - u64::from(from)) }; - (ptr, extra) + Ok(Place::Ptr { ptr, align, extra }) } - }; - - Ok(Place::Ptr { ptr, extra }) + } } pub fn place_ty(&self, place: &mir::Place<'tcx>) -> Ty<'tcx> { diff --git a/src/librustc_mir/interpret/terminator/drop.rs b/src/librustc_mir/interpret/terminator/drop.rs index 5db46149834..c5942712b87 100644 --- a/src/librustc_mir/interpret/terminator/drop.rs +++ b/src/librustc_mir/interpret/terminator/drop.rs @@ -21,16 +21,19 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { let val = match self.force_allocation(place)? { Place::Ptr { ptr, + align: _, extra: PlaceExtra::Vtable(vtable), - } => ptr.ptr.to_value_with_vtable(vtable), + } => ptr.to_value_with_vtable(vtable), Place::Ptr { ptr, + align: _, extra: PlaceExtra::Length(len), - } => ptr.ptr.to_value_with_len(len), + } => ptr.to_value_with_len(len), Place::Ptr { ptr, + align: _, extra: PlaceExtra::None, - } => ptr.ptr.to_value(), + } => ptr.to_value(), _ => bug!("force_allocation broken"), }; self.drop(val, instance, ty, span, target) diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index 64216b715a5..0c43490e1fd 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -4,7 +4,7 @@ use rustc::ty::layout::LayoutOf; use syntax::codemap::Span; use syntax::abi::Abi; -use rustc::mir::interpret::{PtrAndAlign, EvalResult, PrimVal, Value}; +use rustc::mir::interpret::{EvalResult, PrimVal, Value}; use super::{EvalContext, eval_context, Place, Machine, ValTy}; @@ -327,14 +327,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { if let ty::TyTuple(..) = args[1].ty.sty { if self.frame().mir.args_iter().count() == layout.fields.count() + 1 { match args[1].value { - Value::ByRef(PtrAndAlign { ptr, align }) => { + Value::ByRef(ptr, align) => { for (i, arg_local) in arg_locals.enumerate() { let field = layout.field(&self, i)?; let offset = layout.fields.offset(i).bytes(); - let arg = Value::ByRef(PtrAndAlign { - ptr: ptr.offset(offset, &self)?, - align: align.min(field.align) - }); + let arg = Value::ByRef(ptr.offset(offset, &self)?, + align.min(field.align)); let dest = self.eval_place(&mir::Place::Local(arg_local))?; trace!(