miri: use separate Pointer and Align instead of PtrAndAlign.

This commit is contained in:
Eduard-Mihai Burtescu 2017-12-16 23:34:43 +02:00
parent ff080d389d
commit 08646c6c2c
8 changed files with 113 additions and 177 deletions

View File

@ -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;

View File

@ -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),
}

View File

@ -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<Option<Value>, 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>(

View File

@ -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<Value>) -> 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());

View File

@ -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(

View File

@ -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> {

View File

@ -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)

View File

@ -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!(