make force_allocation handle packed ByValPair
This commit is contained in:
parent
f906c5458c
commit
4672cb7bde
6 changed files with 73 additions and 42 deletions
|
|
@ -609,7 +609,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
let operand_ty = self.operand_ty(operand);
|
||||
assert_eq!(self.type_size(operand_ty)?, Some(0));
|
||||
}
|
||||
let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
|
||||
let (offset, ty, _packed) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
|
||||
// TODO: The packed flag is ignored
|
||||
|
||||
// FIXME(solson)
|
||||
let dest = self.force_allocation(dest)?.to_ptr()?;
|
||||
|
|
@ -702,7 +703,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
LvalueExtra::DowncastVariant(..) =>
|
||||
bug!("attempted to take a reference to an enum downcast lvalue"),
|
||||
};
|
||||
|
||||
self.write_value(val, dest, dest_ty)?;
|
||||
}
|
||||
|
||||
|
|
@ -826,7 +826,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
ty: Ty<'tcx>,
|
||||
nndiscr: u64,
|
||||
discrfield: &[u32],
|
||||
) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
|
||||
) -> EvalResult<'tcx, (Size, Ty<'tcx>, bool)> {
|
||||
// Skip the constant 0 at the start meant for LLVM GEP and the outer non-null variant
|
||||
let path = discrfield.iter().skip(2).map(|&i| i as usize);
|
||||
|
||||
|
|
@ -849,16 +849,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
mut offset: Size,
|
||||
mut ty: Ty<'tcx>,
|
||||
path: I,
|
||||
) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
|
||||
) -> EvalResult<'tcx, (Size, Ty<'tcx>, bool)> {
|
||||
// Skip the initial 0 intended for LLVM GEP.
|
||||
let mut packed = false;
|
||||
for field_index in path {
|
||||
let field_offset = self.get_field_offset(ty, field_index)?;
|
||||
trace!("field_path_offset_and_ty: {}, {}, {:?}, {:?}", field_index, ty, field_offset, offset);
|
||||
ty = self.get_field_ty(ty, field_index)?;
|
||||
let field_ty = self.get_field_ty(ty, field_index)?;
|
||||
ty = field_ty.0;
|
||||
packed = packed || field_ty.1;
|
||||
offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap();
|
||||
}
|
||||
|
||||
Ok((offset, ty))
|
||||
Ok((offset, ty, packed))
|
||||
}
|
||||
fn get_fat_field(&self, pointee_ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
|
||||
match (field_index, &self.tcx.struct_tail(pointee_ty).sty) {
|
||||
|
|
@ -870,33 +873,46 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
|
||||
/// Returns the field type and whether the field is packed
|
||||
pub fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, (Ty<'tcx>, bool)> {
|
||||
match ty.sty {
|
||||
ty::TyAdt(adt_def, _) if adt_def.is_box() => self.get_fat_field(ty.boxed_ty(), field_index),
|
||||
ty::TyAdt(adt_def, _) if adt_def.is_box() =>
|
||||
Ok((self.get_fat_field(ty.boxed_ty(), field_index)?, false)),
|
||||
ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
|
||||
use rustc::ty::layout::Layout::*;
|
||||
match *self.type_layout(ty)? {
|
||||
RawNullablePointer { nndiscr, .. } |
|
||||
StructWrappedNullablePointer { nndiscr, .. } => Ok(adt_def.variants[nndiscr as usize].fields[field_index].ty(self.tcx, substs)),
|
||||
RawNullablePointer { nndiscr, .. } =>
|
||||
Ok((adt_def.variants[nndiscr as usize].fields[field_index].ty(self.tcx, substs), false)),
|
||||
StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
|
||||
let ty = adt_def.variants[nndiscr as usize].fields[field_index].ty(self.tcx, substs);
|
||||
Ok((ty, nonnull.packed))
|
||||
},
|
||||
_ => Err(EvalError::Unimplemented(format!("get_field_ty can't handle enum type: {:?}, {:?}", ty, ty.sty))),
|
||||
}
|
||||
}
|
||||
ty::TyAdt(adt_def, substs) => {
|
||||
Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs))
|
||||
let variant_def = adt_def.struct_variant();
|
||||
use rustc::ty::layout::Layout::*;
|
||||
match *self.type_layout(ty)? {
|
||||
Univariant { ref variant, .. } =>
|
||||
Ok((variant_def.fields[field_index].ty(self.tcx, substs), variant.packed)),
|
||||
_ => Err(EvalError::Unimplemented(format!("get_field_ty can't handle struct type: {:?}, {:?}", ty, ty.sty))),
|
||||
}
|
||||
}
|
||||
|
||||
ty::TyTuple(fields, _) => Ok(fields[field_index]),
|
||||
ty::TyTuple(fields, _) => Ok((fields[field_index], false)),
|
||||
|
||||
ty::TyRef(_, ref tam) |
|
||||
ty::TyRawPtr(ref tam) => self.get_fat_field(tam.ty, field_index),
|
||||
ty::TyRawPtr(ref tam) => Ok((self.get_fat_field(tam.ty, field_index)?, false)),
|
||||
|
||||
ty::TyArray(ref inner, _) => Ok(inner),
|
||||
ty::TyArray(ref inner, _) => Ok((inner, false)),
|
||||
|
||||
_ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, {:?}", ty, ty.sty))),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Size> {
|
||||
// Also see lvalue_field in lvalue.rs, which handles more cases but needs an actual value at the given type
|
||||
let layout = self.type_layout(ty)?;
|
||||
|
||||
use rustc::ty::layout::Layout::*;
|
||||
|
|
@ -1236,20 +1252,28 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
ptr: MemoryPointer,
|
||||
mut ty: Ty<'tcx>
|
||||
) -> EvalResult<'tcx> {
|
||||
let mut packed = false;
|
||||
while self.get_field_count(ty)? == 1 {
|
||||
ty = self.get_field_ty(ty, 0)?;
|
||||
let field = self.get_field_ty(ty, 0)?;
|
||||
ty = field.0;
|
||||
packed = packed || field.1;
|
||||
}
|
||||
assert_eq!(self.get_field_count(ty)?, 2);
|
||||
let field_0 = self.get_field_offset(ty, 0)?.bytes();
|
||||
let field_1 = self.get_field_offset(ty, 1)?.bytes();
|
||||
let field_0 = self.get_field_offset(ty, 0)?;
|
||||
let field_1 = self.get_field_offset(ty, 1)?;
|
||||
let field_0_ty = self.get_field_ty(ty, 0)?;
|
||||
let field_1_ty = self.get_field_ty(ty, 1)?;
|
||||
let field_0_size = self.type_size(field_0_ty)?.expect("pair element type must be sized");
|
||||
let field_1_size = self.type_size(field_1_ty)?.expect("pair element type must be sized");
|
||||
let field_0_ptr = ptr.offset(field_0, &self)?.into();
|
||||
let field_1_ptr = ptr.offset(field_1, &self)?.into();
|
||||
self.memory.write_primval(field_0_ptr, a, field_0_size)?;
|
||||
self.memory.write_primval(field_1_ptr, b, field_1_size)?;
|
||||
// The .1 components say whether the field is packed
|
||||
assert_eq!(field_0_ty.1, field_1_ty.1, "the two fields must agree on being packed");
|
||||
packed = packed || field_0_ty.1;
|
||||
let field_0_size = self.type_size(field_0_ty.0)?.expect("pair element type must be sized");
|
||||
let field_1_size = self.type_size(field_1_ty.0)?.expect("pair element type must be sized");
|
||||
let field_0_ptr = ptr.offset(field_0.bytes(), &self)?.into();
|
||||
let field_1_ptr = ptr.offset(field_1.bytes(), &self)?.into();
|
||||
self.write_maybe_aligned(!packed,
|
||||
|ectx| ectx.memory.write_primval(field_0_ptr, a, field_0_size))?;
|
||||
self.write_maybe_aligned(!packed,
|
||||
|ectx| ectx.memory.write_primval(field_1_ptr, b, field_1_size))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -1529,8 +1553,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
return self.unsize_into_ptr(src, src_ty, dest, dest_ty, src_ty.boxed_ty(), dest_ty.boxed_ty());
|
||||
}
|
||||
if self.ty_to_primval_kind(src_ty).is_ok() {
|
||||
let sty = self.get_field_ty(src_ty, 0)?;
|
||||
let dty = self.get_field_ty(dest_ty, 0)?;
|
||||
// TODO: We ignore the packed flag here
|
||||
let sty = self.get_field_ty(src_ty, 0)?.0;
|
||||
let dty = self.get_field_ty(dest_ty, 0)?.0;
|
||||
return self.unsize_into(src, sty, dest, dty);
|
||||
}
|
||||
// unsizing of generic struct with pointer fields
|
||||
|
|
|
|||
|
|
@ -295,6 +295,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
|
||||
_ => bug!("field access on non-product type: {:?}", base_layout),
|
||||
};
|
||||
//trace!("Field {} of {:?} is at offset {}{}", field_index, base_ty, offset.bytes(),
|
||||
// if packed { " (packed)" } else { "" });
|
||||
|
||||
// Do not allocate in trivial cases
|
||||
let (base_ptr, base_extra, aligned) = match base {
|
||||
|
|
|
|||
|
|
@ -1402,20 +1402,20 @@ pub(crate) trait HasMemory<'a, 'tcx> {
|
|||
fn read_maybe_aligned<F, T>(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T>
|
||||
where F: FnOnce(&mut Self) -> EvalResult<'tcx, T>
|
||||
{
|
||||
assert!(self.memory_mut().reads_are_aligned, "Unaligned reads must not be nested");
|
||||
self.memory_mut().reads_are_aligned = aligned;
|
||||
let old = self.memory_mut().reads_are_aligned;
|
||||
self.memory_mut().reads_are_aligned = old && aligned;
|
||||
let t = f(self);
|
||||
self.memory_mut().reads_are_aligned = true;
|
||||
self.memory_mut().reads_are_aligned = old;
|
||||
t
|
||||
}
|
||||
|
||||
fn write_maybe_aligned<F, T>(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T>
|
||||
where F: FnOnce(&mut Self) -> EvalResult<'tcx, T>
|
||||
{
|
||||
assert!(self.memory_mut().writes_are_aligned, "Unaligned writes must not be nested");
|
||||
self.memory_mut().writes_are_aligned = aligned;
|
||||
let old = self.memory_mut().writes_are_aligned;
|
||||
self.memory_mut().writes_are_aligned = old && aligned;
|
||||
let t = f(self);
|
||||
self.memory_mut().writes_are_aligned = true;
|
||||
self.memory_mut().writes_are_aligned = old;
|
||||
t
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,12 +11,14 @@ use rustc::ty;
|
|||
use rustc::ty::layout::Layout;
|
||||
use rustc::ty::subst::Substs;
|
||||
|
||||
use syntax::codemap::Span;
|
||||
use syntax::ast::Mutability;
|
||||
|
||||
use error::{EvalResult, EvalError};
|
||||
use eval_context::{EvalContext, StackPopCleanup};
|
||||
use lvalue::{Global, GlobalId, Lvalue};
|
||||
use value::{Value, PrimVal};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::ast::Mutability;
|
||||
use memory::HasMemory;
|
||||
|
||||
impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
||||
pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> {
|
||||
|
|
@ -101,12 +103,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
|
||||
Layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
|
||||
if variant_index as u64 != nndiscr {
|
||||
let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
|
||||
let (offset, ty, packed) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
|
||||
let nonnull = self.force_allocation(dest)?.to_ptr()?.offset(offset.bytes(), &self)?;
|
||||
trace!("struct wrapped nullable pointer type: {}", ty);
|
||||
// only the pointer part of a fat pointer is used for this space optimization
|
||||
let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield");
|
||||
self.memory.write_uint(nonnull, 0, discr_size)?;
|
||||
self.write_maybe_aligned(!packed, |ectx| ectx.memory.write_uint(nonnull, 0, discr_size))?;
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ use syntax::abi::Abi;
|
|||
use error::{EvalError, EvalResult};
|
||||
use eval_context::{EvalContext, IntegerExt, StackPopCleanup, is_inhabited, self};
|
||||
use lvalue::Lvalue;
|
||||
use memory::{MemoryPointer, TlsKey, Kind};
|
||||
use memory::{MemoryPointer, TlsKey, Kind, HasMemory};
|
||||
use value::{PrimVal, Value};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use const_eval;
|
||||
|
|
@ -402,7 +402,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
let instance = self.memory.get_fn(fn_ptr.to_ptr()?)?;
|
||||
let mut arg_operands = arg_operands.to_vec();
|
||||
let ty = self.operand_ty(&arg_operands[0]);
|
||||
let ty = self.get_field_ty(ty, 0)?;
|
||||
let ty = self.get_field_ty(ty, 0)?.0; // TODO: packed flag is ignored
|
||||
match arg_operands[0] {
|
||||
mir::Operand::Consume(ref mut lval) => *lval = lval.clone().field(mir::Field::new(0), ty),
|
||||
_ => bug!("virtual call first arg cannot be a constant"),
|
||||
|
|
@ -464,7 +464,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
Ok(false)
|
||||
}
|
||||
|
||||
pub fn read_discriminant_value(&self, adt_ptr: MemoryPointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
|
||||
pub fn read_discriminant_value(&mut self, adt_ptr: MemoryPointer, adt_ty: Ty<'tcx>) -> EvalResult<'tcx, u128> {
|
||||
use rustc::ty::layout::Layout::*;
|
||||
let adt_layout = self.type_layout(adt_ty)?;
|
||||
//trace!("read_discriminant_value {:#?}", adt_layout);
|
||||
|
|
@ -487,12 +487,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
|
||||
let (offset, ty) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?;
|
||||
let nonnull = adt_ptr.offset(offset.bytes(), self)?;
|
||||
let (offset, ty, packed) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?;
|
||||
let nonnull = adt_ptr.offset(offset.bytes(), &*self)?;
|
||||
trace!("struct wrapped nullable pointer type: {}", ty);
|
||||
// only the pointer part of a fat pointer is used for this space optimization
|
||||
let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield");
|
||||
self.read_nonnull_discriminant_value(nonnull, nndiscr as u128, discr_size)?
|
||||
self.read_maybe_aligned(!packed,
|
||||
|ectx| ectx.read_nonnull_discriminant_value(nonnull, nndiscr as u128, discr_size))?
|
||||
}
|
||||
|
||||
// The discriminant_value intrinsic returns 0 for non-sum types.
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ fn test_unsizing() {
|
|||
|
||||
let arr = [1, 2, 3];
|
||||
let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr };
|
||||
let _uns: UnalignedPtr<[i32]> = arr_unaligned;
|
||||
let arr_unaligned: UnalignedPtr<[i32]> = arr_unaligned;
|
||||
let _unused = &arr_unaligned; // forcing an allocation, which could also yield "unaligned write"-errors
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue