From 7c6f242ca8a4eca33e8257906cc549b6b1418be2 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Fri, 1 Dec 2017 18:29:35 +0200 Subject: [PATCH] rustc: don't track whether layouts are "packed". --- src/librustc/ty/context.rs | 6 +- src/librustc/ty/layout.rs | 63 ++++--------------- src/librustc_mir/interpret/const_eval.rs | 19 +++--- src/librustc_mir/interpret/eval_context.rs | 71 ++++++++-------------- src/librustc_mir/interpret/place.rs | 27 ++++---- src/librustc_mir/interpret/step.rs | 18 +----- src/librustc_trans/glue.rs | 9 ++- src/librustc_trans/mir/constant.rs | 17 ++++-- src/librustc_trans/mir/place.rs | 42 ++++++------- src/librustc_trans/type_of.rs | 28 ++++----- 10 files changed, 116 insertions(+), 184 deletions(-) diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 9ebdd592922..5464fa601ec 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -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::PtrAndAlign>, + alloc_cache: FxHashMap, 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 { + ) -> Option { 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); diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index fe96cb083f5..42987e3dd78 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -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> 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); } } diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index fc4d1d98941..aaadddba0c1 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -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) } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 6b33fd246da..5fe1d6cd540 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -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(()) } } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 0e44b414d7f..7c19c9f3080 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -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 diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index 352e151e3a1..ae382bd12cd 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -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, diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 6c7d7700ade..9477adc17c0 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -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), diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 5521d842c95..68913c1d6b7 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -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 { diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_trans/mir/place.rs index 806aca54dc0..214686f4ca1 100644 --- a/src/librustc_trans/mir/place.rs +++ b/src/librustc_trans/mir/place.rs @@ -55,11 +55,7 @@ impl ops::BitOr for Alignment { impl<'a> From> 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. diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index e432cec3d5e..8d9bc07fe56 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -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 { + layout: TyLayout<'tcx>) + -> (Vec, 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 = 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