rustc: don't track whether layouts are "packed".
This commit is contained in:
parent
53a6d14e5b
commit
7c6f242ca8
|
@ -895,7 +895,7 @@ pub struct InterpretInterner<'tcx> {
|
|||
/// Allows checking whether a constant already has an allocation
|
||||
///
|
||||
/// The pointers are to the beginning of an `alloc_by_id` allocation
|
||||
alloc_cache: FxHashMap<interpret::GlobalId<'tcx>, interpret::PtrAndAlign>,
|
||||
alloc_cache: FxHashMap<interpret::GlobalId<'tcx>, interpret::Pointer>,
|
||||
|
||||
/// A cache for basic byte allocations keyed by their contents. This is used to deduplicate
|
||||
/// allocations for string and bytestring literals.
|
||||
|
@ -931,14 +931,14 @@ impl<'tcx> InterpretInterner<'tcx> {
|
|||
pub fn get_cached(
|
||||
&self,
|
||||
global_id: interpret::GlobalId<'tcx>,
|
||||
) -> Option<interpret::PtrAndAlign> {
|
||||
) -> Option<interpret::Pointer> {
|
||||
self.alloc_cache.get(&global_id).cloned()
|
||||
}
|
||||
|
||||
pub fn cache(
|
||||
&mut self,
|
||||
global_id: interpret::GlobalId<'tcx>,
|
||||
ptr: interpret::PtrAndAlign,
|
||||
ptr: interpret::Pointer,
|
||||
) {
|
||||
if let Some(old) = self.alloc_cache.insert(global_id, ptr) {
|
||||
bug!("tried to cache {:?}, but was already existing as {:#?}", global_id, old);
|
||||
|
|
|
@ -778,7 +778,6 @@ pub enum Abi {
|
|||
Aggregate {
|
||||
/// If true, the size is exact, otherwise it's only a lower bound.
|
||||
sized: bool,
|
||||
packed: bool
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -790,18 +789,7 @@ impl Abi {
|
|||
Abi::Scalar(_) |
|
||||
Abi::ScalarPair(..) |
|
||||
Abi::Vector { .. } => false,
|
||||
Abi::Aggregate { sized, .. } => !sized
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if the fields of the layout are packed.
|
||||
pub fn is_packed(&self) -> bool {
|
||||
match *self {
|
||||
Abi::Uninhabited |
|
||||
Abi::Scalar(_) |
|
||||
Abi::ScalarPair(..) |
|
||||
Abi::Vector { .. } => false,
|
||||
Abi::Aggregate { packed, .. } => packed
|
||||
Abi::Aggregate { sized } => !sized
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1077,10 +1065,7 @@ impl<'a, 'tcx> LayoutDetails {
|
|||
}
|
||||
|
||||
let size = min_size.abi_align(align);
|
||||
let mut abi = Abi::Aggregate {
|
||||
sized,
|
||||
packed
|
||||
};
|
||||
let mut abi = Abi::Aggregate { sized };
|
||||
|
||||
// Unpack newtype ABIs and find scalar pairs.
|
||||
if sized && size.bytes() > 0 {
|
||||
|
@ -1254,10 +1239,7 @@ impl<'a, 'tcx> LayoutDetails {
|
|||
stride: element.size,
|
||||
count
|
||||
},
|
||||
abi: Abi::Aggregate {
|
||||
sized: true,
|
||||
packed: false
|
||||
},
|
||||
abi: Abi::Aggregate { sized: true },
|
||||
align: element.align,
|
||||
size
|
||||
})
|
||||
|
@ -1270,10 +1252,7 @@ impl<'a, 'tcx> LayoutDetails {
|
|||
stride: element.size,
|
||||
count: 0
|
||||
},
|
||||
abi: Abi::Aggregate {
|
||||
sized: false,
|
||||
packed: false
|
||||
},
|
||||
abi: Abi::Aggregate { sized: false },
|
||||
align: element.align,
|
||||
size: Size::from_bytes(0)
|
||||
})
|
||||
|
@ -1285,10 +1264,7 @@ impl<'a, 'tcx> LayoutDetails {
|
|||
stride: Size::from_bytes(1),
|
||||
count: 0
|
||||
},
|
||||
abi: Abi::Aggregate {
|
||||
sized: false,
|
||||
packed: false
|
||||
},
|
||||
abi: Abi::Aggregate { sized: false },
|
||||
align: dl.i8_align,
|
||||
size: Size::from_bytes(0)
|
||||
})
|
||||
|
@ -1302,7 +1278,7 @@ impl<'a, 'tcx> LayoutDetails {
|
|||
let mut unit = univariant_uninterned(&[], &ReprOptions::default(),
|
||||
StructKind::AlwaysSized)?;
|
||||
match unit.abi {
|
||||
Abi::Aggregate { ref mut sized, .. } => *sized = false,
|
||||
Abi::Aggregate { ref mut sized } => *sized = false,
|
||||
_ => bug!()
|
||||
}
|
||||
tcx.intern_layout(unit)
|
||||
|
@ -1418,10 +1394,7 @@ impl<'a, 'tcx> LayoutDetails {
|
|||
return Ok(tcx.intern_layout(LayoutDetails {
|
||||
variants: Variants::Single { index: 0 },
|
||||
fields: FieldPlacement::Union(variants[0].len()),
|
||||
abi: Abi::Aggregate {
|
||||
sized: true,
|
||||
packed
|
||||
},
|
||||
abi: Abi::Aggregate { sized: true },
|
||||
align,
|
||||
size: size.abi_align(align)
|
||||
}));
|
||||
|
@ -1525,15 +1498,10 @@ impl<'a, 'tcx> LayoutDetails {
|
|||
let abi = if offset.bytes() == 0 && niche.value.size(dl) == size {
|
||||
Abi::Scalar(niche.clone())
|
||||
} else {
|
||||
let mut packed = st[i].abi.is_packed();
|
||||
if offset.abi_align(niche_align) != offset {
|
||||
packed = true;
|
||||
niche_align = dl.i8_align;
|
||||
}
|
||||
Abi::Aggregate {
|
||||
sized: true,
|
||||
packed
|
||||
}
|
||||
Abi::Aggregate { sized: true }
|
||||
};
|
||||
align = align.max(niche_align);
|
||||
|
||||
|
@ -1681,10 +1649,7 @@ impl<'a, 'tcx> LayoutDetails {
|
|||
let abi = if discr.value.size(dl) == size {
|
||||
Abi::Scalar(discr.clone())
|
||||
} else {
|
||||
Abi::Aggregate {
|
||||
sized: true,
|
||||
packed: false
|
||||
}
|
||||
Abi::Aggregate { sized: true }
|
||||
};
|
||||
tcx.intern_layout(LayoutDetails {
|
||||
variants: Variants::Tagged {
|
||||
|
@ -2277,11 +2242,6 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
|||
self.abi.is_unsized()
|
||||
}
|
||||
|
||||
/// Returns true if the fields of the layout are packed.
|
||||
pub fn is_packed(&self) -> bool {
|
||||
self.abi.is_packed()
|
||||
}
|
||||
|
||||
/// Returns true if the type is a ZST and not unsized.
|
||||
pub fn is_zst(&self) -> bool {
|
||||
match self.abi {
|
||||
|
@ -2289,7 +2249,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
|
|||
Abi::Scalar(_) |
|
||||
Abi::ScalarPair(..) |
|
||||
Abi::Vector { .. } => false,
|
||||
Abi::Aggregate { sized, .. } => sized && self.size.bytes() == 0
|
||||
Abi::Aggregate { sized } => sized && self.size.bytes() == 0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2452,8 +2412,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Abi {
|
|||
element.hash_stable(hcx, hasher);
|
||||
count.hash_stable(hcx, hasher);
|
||||
}
|
||||
Aggregate { packed, sized } => {
|
||||
packed.hash_stable(hcx, hasher);
|
||||
Aggregate { sized } => {
|
||||
sized.hash_stable(hcx, hasher);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use rustc_data_structures::indexed_vec::Idx;
|
|||
use syntax::ast::Mutability;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, PrimVal, PtrAndAlign};
|
||||
use rustc::mir::interpret::{EvalResult, EvalError, EvalErrorKind, GlobalId, Value, Pointer, PrimVal, PtrAndAlign};
|
||||
use super::{Place, PlaceExtra, EvalContext, StackPopCleanup, ValTy, HasMemory};
|
||||
|
||||
use rustc_const_math::ConstInt;
|
||||
|
@ -45,7 +45,7 @@ pub fn eval_body<'a, 'tcx>(
|
|||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
) -> EvalResult<'tcx, (PtrAndAlign, Ty<'tcx>)> {
|
||||
) -> EvalResult<'tcx, (Pointer, Ty<'tcx>)> {
|
||||
debug!("eval_body: {:?}, {:?}", instance, param_env);
|
||||
let limits = super::ResourceLimits::default();
|
||||
let mut ecx = EvalContext::new(tcx, param_env, limits, CompileTimeEvaluator, ());
|
||||
|
@ -69,13 +69,7 @@ pub fn eval_body<'a, 'tcx>(
|
|||
layout.align.abi(),
|
||||
None,
|
||||
)?;
|
||||
tcx.interpret_interner.borrow_mut().cache(
|
||||
cid,
|
||||
PtrAndAlign {
|
||||
ptr: ptr.into(),
|
||||
aligned: !layout.is_packed(),
|
||||
},
|
||||
);
|
||||
tcx.interpret_interner.borrow_mut().cache(cid, ptr.into());
|
||||
let cleanup = StackPopCleanup::MarkStatic(Mutability::Immutable);
|
||||
let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id()));
|
||||
trace!("const_eval: pushing stack frame for global: {}", name);
|
||||
|
@ -101,7 +95,7 @@ pub fn eval_body_as_integer<'a, 'tcx>(
|
|||
let ptr_ty = eval_body(tcx, instance, param_env);
|
||||
let (ptr, ty) = ptr_ty?;
|
||||
let ecx = mk_eval_cx(tcx, instance, param_env)?;
|
||||
let prim = match ecx.read_maybe_aligned(ptr.aligned, |ectx| ectx.try_read_value(ptr.ptr, ty))? {
|
||||
let prim = match ecx.try_read_value(ptr, ty)? {
|
||||
Some(Value::ByVal(prim)) => prim.to_bytes()?,
|
||||
_ => return err!(TypeNotPrimitive(ty)),
|
||||
};
|
||||
|
@ -363,7 +357,10 @@ 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();
|
||||
check_ctfe_against_miri(&mut ecx, miri_val, miri_ty, ctfe.val);
|
||||
check_ctfe_against_miri(&mut ecx, PtrAndAlign {
|
||||
ptr: miri_val,
|
||||
aligned: true
|
||||
}, miri_ty, ctfe.val);
|
||||
Ok(ctfe)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -261,11 +261,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
|
||||
Unevaluated(def_id, substs) => {
|
||||
let instance = self.resolve(def_id, substs)?;
|
||||
let cid = GlobalId {
|
||||
return Ok(self.read_global_as_value(GlobalId {
|
||||
instance,
|
||||
promoted: None,
|
||||
};
|
||||
return Ok(Value::ByRef(self.tcx.interpret_interner.borrow().get_cached(cid).expect("static/const not cached")));
|
||||
}));
|
||||
}
|
||||
|
||||
Aggregate(..) |
|
||||
|
@ -834,11 +833,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
Literal::Value { ref value } => self.const_to_value(&value.val)?,
|
||||
|
||||
Literal::Promoted { index } => {
|
||||
let cid = GlobalId {
|
||||
self.read_global_as_value(GlobalId {
|
||||
instance: self.frame().instance,
|
||||
promoted: Some(index),
|
||||
};
|
||||
Value::ByRef(self.tcx.interpret_interner.borrow().get_cached(cid).expect("promoted not cached"))
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -951,7 +949,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
}
|
||||
|
||||
pub fn read_global_as_value(&self, gid: GlobalId) -> Value {
|
||||
Value::ByRef(self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached"))
|
||||
Value::ByRef(PtrAndAlign {
|
||||
ptr: self.tcx.interpret_interner.borrow().get_cached(gid).expect("global not cached"),
|
||||
aligned: true
|
||||
})
|
||||
}
|
||||
|
||||
fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx> {
|
||||
|
@ -1149,51 +1150,29 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
}
|
||||
Value::ByVal(primval) => {
|
||||
let layout = self.layout_of(dest_ty)?;
|
||||
if layout.is_zst() {
|
||||
assert!(primval.is_undef());
|
||||
Ok(())
|
||||
} else {
|
||||
// TODO: Do we need signedness?
|
||||
self.memory.write_maybe_aligned_mut(!layout.is_packed(), |mem| {
|
||||
mem.write_primval(dest.to_ptr()?, primval, layout.size.bytes(), false)
|
||||
})
|
||||
match layout.abi {
|
||||
layout::Abi::Scalar(_) => {}
|
||||
_ if primval.is_undef() => {}
|
||||
_ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
|
||||
}
|
||||
// TODO: Do we need signedness?
|
||||
self.memory.write_primval(dest.to_ptr()?, primval, layout.size.bytes(), false)
|
||||
}
|
||||
Value::ByValPair(a, b) => {
|
||||
Value::ByValPair(a_val, b_val) => {
|
||||
let ptr = dest.to_ptr()?;
|
||||
let mut layout = self.layout_of(dest_ty)?;
|
||||
trace!("write_value_to_ptr valpair: {:#?}", layout);
|
||||
let mut packed = layout.is_packed();
|
||||
'outer: loop {
|
||||
for i in 0..layout.fields.count() {
|
||||
let field = layout.field(&self, i)?;
|
||||
if layout.fields.offset(i).bytes() == 0 && layout.size == field.size {
|
||||
layout = field;
|
||||
packed |= layout.is_packed();
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
trace!("write_value_to_ptr valpair: {:#?}", layout);
|
||||
assert_eq!(layout.fields.count(), 2);
|
||||
let field_0 = layout.field(&self, 0)?;
|
||||
let field_1 = layout.field(&self, 1)?;
|
||||
trace!("write_value_to_ptr field 0: {:#?}", field_0);
|
||||
trace!("write_value_to_ptr field 1: {:#?}", field_1);
|
||||
assert_eq!(
|
||||
field_0.is_packed(),
|
||||
field_1.is_packed(),
|
||||
"the two fields must agree on being packed"
|
||||
);
|
||||
packed |= field_0.is_packed();
|
||||
let field_0_ptr = ptr.offset(layout.fields.offset(0).bytes(), &self)?.into();
|
||||
let field_1_ptr = ptr.offset(layout.fields.offset(1).bytes(), &self)?.into();
|
||||
let (a, b) = match layout.abi {
|
||||
layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
|
||||
_ => bug!("write_value_to_ptr: invalid ByValPair layout: {:#?}", layout)
|
||||
};
|
||||
let (a_size, b_size) = (a.size(&self), b.size(&self));
|
||||
let a_ptr = ptr;
|
||||
let b_offset = a_size.abi_align(b.align(&self));
|
||||
let b_ptr = ptr.offset(b_offset.bytes(), &self)?.into();
|
||||
// TODO: What about signedess?
|
||||
self.memory.write_maybe_aligned_mut(!packed, |mem| {
|
||||
mem.write_primval(field_0_ptr, a, field_0.size.bytes(), false)?;
|
||||
mem.write_primval(field_1_ptr, b, field_1.size.bytes(), false)
|
||||
})?;
|
||||
self.memory.write_primval(a_ptr, a_val, a_size.bytes(), false)?;
|
||||
self.memory.write_primval(b_ptr, b_val, b_size.bytes(), false)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use rustc::mir;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc::ty::layout::{LayoutOf, TyLayout};
|
||||
use rustc::ty::layout::{self, LayoutOf, TyLayout};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use rustc::mir::interpret::{GlobalId, PtrAndAlign};
|
||||
|
||||
|
@ -106,9 +106,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
instance,
|
||||
promoted: None,
|
||||
};
|
||||
Ok(Some(Value::ByRef(
|
||||
self.tcx.interpret_interner.borrow().get_cached(cid).expect("global not cached"),
|
||||
)))
|
||||
Ok(Some(self.read_global_as_value(cid)))
|
||||
}
|
||||
Projection(ref proj) => self.try_read_place_projection(proj),
|
||||
}
|
||||
|
@ -193,7 +191,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
promoted: None,
|
||||
};
|
||||
Place::Ptr {
|
||||
ptr: self.tcx.interpret_interner.borrow().get_cached(gid).expect("uncached global"),
|
||||
ptr: PtrAndAlign {
|
||||
ptr: self.tcx.interpret_interner.borrow().get_cached(gid).expect("uncached global"),
|
||||
aligned: true
|
||||
},
|
||||
extra: PlaceExtra::None,
|
||||
}
|
||||
}
|
||||
|
@ -232,15 +233,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
let (base_ptr, base_extra) = match base {
|
||||
Place::Ptr { ptr, extra } => (ptr, extra),
|
||||
Place::Local { frame, local } => {
|
||||
match self.stack[frame].get_local(local)? {
|
||||
match (&self.stack[frame].get_local(local)?, &base_layout.abi) {
|
||||
// in case the field covers the entire type, just return the value
|
||||
Value::ByVal(_) if offset.bytes() == 0 &&
|
||||
field.size == base_layout.size => {
|
||||
(&Value::ByVal(_), &layout::Abi::Scalar(_)) |
|
||||
(&Value::ByValPair(..), &layout::Abi::ScalarPair(..))
|
||||
if offset.bytes() == 0 && field.size == base_layout.size =>
|
||||
{
|
||||
return Ok((base, field));
|
||||
}
|
||||
Value::ByRef { .. } |
|
||||
Value::ByValPair(..) |
|
||||
Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(),
|
||||
_ => self.force_allocation(base)?.to_ptr_extra_aligned(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -257,9 +258,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
};
|
||||
|
||||
let mut ptr = base_ptr.offset(offset, &self)?;
|
||||
// if we were unaligned, stay unaligned
|
||||
// no matter what we were, if we are packed, we must not be aligned anymore
|
||||
ptr.aligned &= !base_layout.is_packed();
|
||||
ptr.aligned &= base_layout.align.abi() >= field.align.abi();
|
||||
|
||||
let extra = if !field.is_unsized() {
|
||||
PlaceExtra::None
|
||||
|
|
|
@ -8,7 +8,7 @@ use rustc::mir;
|
|||
use rustc::ty::{self, Instance};
|
||||
use rustc::ty::layout::LayoutOf;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::mir::interpret::{PtrAndAlign, GlobalId};
|
||||
use rustc::mir::interpret::GlobalId;
|
||||
|
||||
use rustc::mir::interpret::{EvalResult, EvalErrorKind};
|
||||
use super::{EvalContext, StackPopCleanup, Place, Machine};
|
||||
|
@ -182,13 +182,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
|
|||
layout.align.abi(),
|
||||
None,
|
||||
)?;
|
||||
self.tcx.interpret_interner.borrow_mut().cache(
|
||||
cid,
|
||||
PtrAndAlign {
|
||||
ptr: ptr.into(),
|
||||
aligned: !layout.is_packed(),
|
||||
},
|
||||
);
|
||||
self.tcx.interpret_interner.borrow_mut().cache(cid, ptr.into());
|
||||
let internally_mutable = !layout.ty.is_freeze(self.tcx, self.param_env, span);
|
||||
let mutability = if mutability == Mutability::Mutable || internally_mutable {
|
||||
Mutability::Mutable
|
||||
|
@ -273,13 +267,7 @@ impl<'a, 'b, 'tcx, M: Machine<'tcx>> Visitor<'tcx> for ConstantExtractor<'a, 'b,
|
|||
layout.align.abi(),
|
||||
None,
|
||||
)?;
|
||||
this.ecx.tcx.interpret_interner.borrow_mut().cache(
|
||||
cid,
|
||||
PtrAndAlign {
|
||||
ptr: ptr.into(),
|
||||
aligned: !layout.is_packed(),
|
||||
},
|
||||
);
|
||||
this.ecx.tcx.interpret_interner.borrow_mut().cache(cid, ptr.into());
|
||||
trace!("pushing stack frame for {:?}", index);
|
||||
this.ecx.push_stack_frame(
|
||||
this.instance,
|
||||
|
|
|
@ -69,7 +69,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
|
|||
// Recurse to get the size of the dynamically sized field (must be
|
||||
// the last field).
|
||||
let field_ty = layout.field(ccx, i).ty;
|
||||
let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
|
||||
let (unsized_size, mut unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
|
||||
|
||||
// FIXME (#26403, #27023): We should be adding padding
|
||||
// to `sized_size` (to accommodate the `unsized_align`
|
||||
|
@ -81,6 +81,13 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
|
|||
// Return the sum of sizes and max of aligns.
|
||||
let size = bcx.add(sized_size, unsized_size);
|
||||
|
||||
// Packed types ignore the alignment of their fields.
|
||||
if let ty::TyAdt(def, _) = t.sty {
|
||||
if def.repr.packed() {
|
||||
unsized_align = sized_align;
|
||||
}
|
||||
}
|
||||
|
||||
// Choose max of two known alignments (combined value must
|
||||
// be aligned according to more restrictive of the two).
|
||||
let align = match (const_to_opt_u128(sized_align, false),
|
||||
|
|
|
@ -1134,12 +1134,14 @@ fn trans_const_adt<'a, 'tcx>(
|
|||
if let layout::FieldPlacement::Union(_) = l.fields {
|
||||
assert_eq!(variant_index, 0);
|
||||
assert_eq!(vals.len(), 1);
|
||||
let (field_size, field_align) = ccx.size_and_align_of(vals[0].ty);
|
||||
let contents = [
|
||||
vals[0].llval,
|
||||
padding(ccx, l.size - ccx.size_of(vals[0].ty))
|
||||
padding(ccx, l.size - field_size)
|
||||
];
|
||||
|
||||
Const::new(C_struct(ccx, &contents, l.is_packed()), t)
|
||||
let packed = l.align.abi() < field_align.abi();
|
||||
Const::new(C_struct(ccx, &contents, packed), t)
|
||||
} else {
|
||||
if let layout::Abi::Vector { .. } = l.abi {
|
||||
if let layout::FieldPlacement::Array { .. } = l.fields {
|
||||
|
@ -1232,28 +1234,33 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
|
||||
// offset of current value
|
||||
let mut packed = false;
|
||||
let mut offset = Size::from_bytes(0);
|
||||
let mut cfields = Vec::new();
|
||||
cfields.reserve(discr.is_some() as usize + 1 + layout.fields.count() * 2);
|
||||
|
||||
if let Some(discr) = discr {
|
||||
let (field_size, field_align) = ccx.size_and_align_of(discr.ty);
|
||||
packed |= layout.align.abi() < field_align.abi();
|
||||
cfields.push(discr.llval);
|
||||
offset = ccx.size_of(discr.ty);
|
||||
offset = field_size;
|
||||
}
|
||||
|
||||
let parts = layout.fields.index_by_increasing_offset().map(|i| {
|
||||
(vals[i], layout.fields.offset(i))
|
||||
});
|
||||
for (val, target_offset) in parts {
|
||||
let (field_size, field_align) = ccx.size_and_align_of(val.ty);
|
||||
packed |= layout.align.abi() < field_align.abi();
|
||||
cfields.push(padding(ccx, target_offset - offset));
|
||||
cfields.push(val.llval);
|
||||
offset = target_offset + ccx.size_of(val.ty);
|
||||
offset = target_offset + field_size;
|
||||
}
|
||||
|
||||
// Pad to the size of the whole type, not e.g. the variant.
|
||||
cfields.push(padding(ccx, ccx.size_of(layout.ty) - offset));
|
||||
|
||||
Const::new(C_struct(ccx, &cfields, layout.is_packed()), layout.ty)
|
||||
Const::new(C_struct(ccx, &cfields, packed), layout.ty)
|
||||
}
|
||||
|
||||
fn padding(ccx: &CrateContext, size: Size) -> ValueRef {
|
||||
|
|
|
@ -55,11 +55,7 @@ impl ops::BitOr for Alignment {
|
|||
|
||||
impl<'a> From<TyLayout<'a>> for Alignment {
|
||||
fn from(layout: TyLayout) -> Self {
|
||||
if layout.is_packed() {
|
||||
Alignment::Packed(layout.align)
|
||||
} else {
|
||||
Alignment::AbiAligned
|
||||
}
|
||||
Alignment::Packed(layout.align)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,25 +228,27 @@ impl<'a, 'tcx> PlaceRef<'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
// Simple case - we can just GEP the field
|
||||
// * Packed struct - There is no alignment padding
|
||||
// * Field is sized - pointer is properly aligned already
|
||||
if self.layout.is_packed() || !field.is_unsized() {
|
||||
return simple();
|
||||
}
|
||||
|
||||
// If the type of the last field is [T], str or a foreign type, then we don't need to do
|
||||
// any adjusments
|
||||
// Simple cases, which don't need DST adjustment:
|
||||
// * no metadata available - just log the case
|
||||
// * known alignment - sized types, [T], str or a foreign type
|
||||
// * packed struct - there is no alignment padding
|
||||
match field.ty.sty {
|
||||
_ if !self.has_extra() => {
|
||||
debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
|
||||
ix, Value(self.llval));
|
||||
return simple();
|
||||
}
|
||||
_ if !field.is_unsized() => return simple(),
|
||||
ty::TySlice(..) | ty::TyStr | ty::TyForeign(..) => return simple(),
|
||||
_ => ()
|
||||
}
|
||||
|
||||
// There's no metadata available, log the case and just do the GEP.
|
||||
if !self.has_extra() {
|
||||
debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
|
||||
ix, Value(self.llval));
|
||||
return simple();
|
||||
ty::TyAdt(def, _) => {
|
||||
if def.repr.packed() {
|
||||
// FIXME(eddyb) generalize the adjustment when we
|
||||
// start supporting packing to larger alignments.
|
||||
assert_eq!(self.layout.align.abi(), 1);
|
||||
return simple();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// We need to get the pointer manually now.
|
||||
|
|
|
@ -79,13 +79,14 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
match layout.fields {
|
||||
layout::FieldPlacement::Union(_) => {
|
||||
let fill = Type::padding_filler(ccx, layout.size, layout.align);
|
||||
let packed = false;
|
||||
match name {
|
||||
None => {
|
||||
Type::struct_(ccx, &[fill], layout.is_packed())
|
||||
Type::struct_(ccx, &[fill], packed)
|
||||
}
|
||||
Some(ref name) => {
|
||||
let mut llty = Type::named_struct(ccx, name);
|
||||
llty.set_struct_body(&[fill], layout.is_packed());
|
||||
llty.set_struct_body(&[fill], packed);
|
||||
llty
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +97,8 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
layout::FieldPlacement::Arbitrary { .. } => {
|
||||
match name {
|
||||
None => {
|
||||
Type::struct_(ccx, &struct_llfields(ccx, layout), layout.is_packed())
|
||||
let (llfields, packed) = struct_llfields(ccx, layout);
|
||||
Type::struct_(ccx, &llfields, packed)
|
||||
}
|
||||
Some(ref name) => {
|
||||
let llty = Type::named_struct(ccx, name);
|
||||
|
@ -109,15 +111,19 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
|
||||
fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
layout: TyLayout<'tcx>) -> Vec<Type> {
|
||||
layout: TyLayout<'tcx>)
|
||||
-> (Vec<Type>, bool) {
|
||||
debug!("struct_llfields: {:#?}", layout);
|
||||
let field_count = layout.fields.count();
|
||||
|
||||
let mut packed = false;
|
||||
let mut offset = Size::from_bytes(0);
|
||||
let mut prev_align = layout.align;
|
||||
let mut result: Vec<Type> = Vec::with_capacity(1 + field_count * 2);
|
||||
for i in layout.fields.index_by_increasing_offset() {
|
||||
let field = layout.field(ccx, i);
|
||||
packed |= layout.align.abi() < field.align.abi();
|
||||
|
||||
let target_offset = layout.fields.offset(i as usize);
|
||||
debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?}",
|
||||
i, field, offset, target_offset);
|
||||
|
@ -129,15 +135,6 @@ fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
debug!(" padding before: {:?}", padding);
|
||||
|
||||
result.push(field.llvm_type(ccx));
|
||||
|
||||
if layout.is_packed() {
|
||||
assert_eq!(padding.bytes(), 0);
|
||||
} else {
|
||||
assert!(field.align.abi() <= layout.align.abi(),
|
||||
"non-packed type has field with larger align ({}): {:#?}",
|
||||
field.align.abi(), layout);
|
||||
}
|
||||
|
||||
offset = target_offset + field.size;
|
||||
prev_align = field.align;
|
||||
}
|
||||
|
@ -158,7 +155,7 @@ fn struct_llfields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
offset, layout.size);
|
||||
}
|
||||
|
||||
result
|
||||
(result, packed)
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> CrateContext<'a, 'tcx> {
|
||||
|
@ -301,7 +298,8 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
|
|||
ccx.lltypes().borrow_mut().insert((self.ty, variant_index), llty);
|
||||
|
||||
if let Some((mut llty, layout)) = defer {
|
||||
llty.set_struct_body(&struct_llfields(ccx, layout), layout.is_packed())
|
||||
let (llfields, packed) = struct_llfields(ccx, layout);
|
||||
llty.set_struct_body(&llfields, packed)
|
||||
}
|
||||
|
||||
llty
|
||||
|
|
Loading…
Reference in New Issue