diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 096c74a6163..13d3ec68a31 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -627,27 +627,27 @@ impl<'a, 'tcx> Primitive { #[derive(PartialEq, Eq, Hash, Debug)] pub struct Struct { /// Maximum alignment of fields and repr alignment. - pub align: Align, + align: Align, /// Primitive alignment of fields without repr alignment. - pub primitive_align: Align, + primitive_align: Align, /// If true, no alignment padding is used. - pub packed: bool, + packed: bool, /// If true, the size is exact, otherwise it's only a lower bound. - pub sized: bool, + sized: bool, /// Offsets for the first byte of each field, ordered to match the source definition order. /// This vector does not go in increasing order. /// FIXME(eddyb) use small vector optimization for the common case. - pub offsets: Vec, + offsets: Vec, /// Maps source order field indices to memory order indices, depending how fields were permuted. /// FIXME (camlorn) also consider small vector optimization here. pub memory_index: Vec, - pub min_size: Size, + min_size: Size, } /// Info required to optimize struct layout. @@ -799,7 +799,7 @@ impl<'a, 'tcx> Struct { } /// Get the size with trailing alignment padding. - pub fn stride(&self) -> Size { + fn stride(&self) -> Size { self.min_size.abi_align(self.align) } @@ -837,11 +837,11 @@ impl<'a, 'tcx> Struct { layout: FullLayout<'tcx>) -> Result, LayoutError<'tcx>> { let cx = (tcx, param_env); - match (layout.layout, &layout.ty.sty) { - (&Scalar(Pointer), _) if !layout.ty.is_unsafe_ptr() => { + match (layout.layout, layout.abi, &layout.ty.sty) { + (&Scalar, Abi::Scalar(Pointer), _) if !layout.ty.is_unsafe_ptr() => { Ok(Some((Size::from_bytes(0), Pointer))) } - (&General { discr, .. }, &ty::TyAdt(def, _)) => { + (&General { discr, .. }, _, &ty::TyAdt(def, _)) => { if def.discriminants(tcx).all(|d| d.to_u128_unchecked() != 0) { Ok(Some((layout.fields.offset(0), discr))) } else { @@ -849,18 +849,18 @@ impl<'a, 'tcx> Struct { } } - (&FatPointer(_), _) if !layout.ty.is_unsafe_ptr() => { + (&FatPointer, _, _) if !layout.ty.is_unsafe_ptr() => { Ok(Some((layout.fields.offset(FAT_PTR_ADDR), Pointer))) } // Is this the NonZero lang item wrapping a pointer or integer type? - (_, &ty::TyAdt(def, _)) if Some(def.did) == tcx.lang_items().non_zero() => { + (_, _, &ty::TyAdt(def, _)) if Some(def.did) == tcx.lang_items().non_zero() => { let field = layout.field(cx, 0)?; - match *field.layout { - Scalar(value) => { + match (field.layout, field.abi) { + (&Scalar, Abi::Scalar(value)) => { Ok(Some((layout.fields.offset(0), value))) } - FatPointer(_) => { + (&FatPointer, _) => { Ok(Some((layout.fields.offset(0) + field.fields.offset(FAT_PTR_ADDR), Pointer))) @@ -870,7 +870,7 @@ impl<'a, 'tcx> Struct { } // Perhaps one of the fields is non-zero, let's recurse and find out. - (&Univariant(ref variant), _) => { + (&Univariant(ref variant), _, _) => { variant.non_zero_field( tcx, param_env, @@ -879,7 +879,7 @@ impl<'a, 'tcx> Struct { // Is this a fixed-size array of something non-zero // with at least one element? - (_, &ty::TyArray(ety, mut count)) => { + (_, _, &ty::TyArray(ety, mut count)) => { if count.has_projections() { count = tcx.normalize_associated_type_in_env(&count, param_env); if count.has_projections() { @@ -893,7 +893,7 @@ impl<'a, 'tcx> Struct { } } - (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => { + (_, _, &ty::TyProjection(_)) | (_, _, &ty::TyAnon(..)) => { bug!("Struct::non_zero_field_in_type: {:?} not normalized", layout); } @@ -920,79 +920,6 @@ impl<'a, 'tcx> Struct { } } -/// An untagged union. -#[derive(PartialEq, Eq, Hash, Debug)] -pub struct Union { - pub align: Align, - pub primitive_align: Align, - - pub min_size: Size, - - /// If true, no alignment padding is used. - pub packed: bool, -} - -impl<'a, 'tcx> Union { - fn new(dl: &TargetDataLayout, repr: &ReprOptions) -> Union { - if repr.packed() && repr.align > 0 { - bug!("Union cannot be packed and aligned"); - } - - let primitive_align = if repr.packed() { - dl.i8_align - } else { - dl.aggregate_align - }; - - let align = if repr.align > 0 { - let repr_align = repr.align as u64; - debug!("Union::new repr_align: {:?}", repr_align); - primitive_align.max(Align::from_bytes(repr_align, repr_align).unwrap()) - } else { - primitive_align - }; - - Union { - align, - primitive_align, - min_size: Size::from_bytes(0), - packed: repr.packed(), - } - } - - /// Extend the Union with more fields. - fn extend(&mut self, dl: &TargetDataLayout, - fields: I, - scapegoat: Ty<'tcx>) - -> Result<(), LayoutError<'tcx>> - where I: Iterator, LayoutError<'tcx>>> { - for (index, field) in fields.enumerate() { - let field = field?; - if field.is_unsized() { - bug!("Union::extend: field #{} of `{}` is unsized", - index, scapegoat); - } - - debug!("Union::extend field: {:?} {:?}", field, field.size(dl)); - - if !self.packed { - self.align = self.align.max(field.align(dl)); - self.primitive_align = self.primitive_align.max(field.primitive_align(dl)); - } - self.min_size = cmp::max(self.min_size, field.size(dl)); - } - - debug!("Union::extend min-size: {:?}", self.min_size); - - Ok(()) - } - - /// Get the size with trailing alignment padding. - pub fn stride(&self) -> Size { - self.min_size.abi_align(self.align) - } -} - /// The first half of a fat pointer. /// - For a trait object, this is the address of the box. /// - For a slice, this is the base address. @@ -1068,6 +995,7 @@ pub enum Abi { Aggregate { /// If true, the size is exact, otherwise it's only a lower bound. sized: bool, + packed: bool, align: Align, primitive_align: Align, size: Size @@ -1078,11 +1006,19 @@ impl Abi { /// Returns true if the layout corresponds to an unsized type. pub fn is_unsized(&self) -> bool { match *self { - Abi::Scalar(_) | Abi::Vector {..} => false, + Abi::Scalar(_) | 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::Scalar(_) | Abi::Vector { .. } => false, + Abi::Aggregate { packed, .. } => packed + } + } + pub fn size(&self, cx: C) -> Size { let dl = cx.data_layout(); @@ -1144,26 +1080,16 @@ impl Abi { #[derive(PartialEq, Eq, Hash, Debug)] pub enum Layout<'a> { /// TyBool, TyChar, TyInt, TyUint, TyFloat, TyRawPtr, TyRef or TyFnPtr. - Scalar(Primitive), + Scalar, /// SIMD vectors, from structs marked with #[repr(simd)]. - Vector { - element: Primitive, - count: u64 - }, + Vector, /// TyArray, TySlice or TyStr. - Array { - /// If true, the size is exact, otherwise it's only a lower bound. - sized: bool, - align: Align, - primitive_align: Align, - element_size: Size, - count: u64 - }, + Array, /// TyRawPtr or TyRef with a !Sized pointee. The primitive is the metadata. - FatPointer(Primitive), + FatPointer, // Remaining variants are all ADTs such as structs, enums or tuples. @@ -1171,7 +1097,7 @@ pub enum Layout<'a> { Univariant(Struct), /// Untagged unions. - UntaggedUnion(Union), + UntaggedUnion, /// General-case enums: for each case there is a struct, and they all have /// all space reserved for the discriminant, and their first field starts @@ -1185,9 +1111,6 @@ pub enum Layout<'a> { // taking everything else as the (shortest) discriminant range. discr_range: RangeInclusive, variants: Vec>, - size: Size, - align: Align, - primitive_align: Align, }, /// Two cases distinguished by a nullable pointer: the case with discriminant @@ -1203,9 +1126,6 @@ pub enum Layout<'a> { discr: Primitive, discr_offset: Size, variants: Vec>, - size: Size, - align: Align, - primitive_align: Align, } } @@ -1269,159 +1189,98 @@ impl<'a, 'tcx> Layout<'tcx> { -> Result, LayoutError<'tcx>> { let cx = (tcx, param_env); let dl = cx.data_layout(); - let success = |layout| { - let layout = tcx.intern_layout(layout); + let scalar = |value| { + CachedLayout { + layout: &Layout::Scalar, + fields: FieldPlacement::union(0), + abi: Abi::Scalar(value) + } + }; + let univariant = |st| { + let layout = tcx.intern_layout(Layout::Univariant(st)); let fields = match *layout { - Scalar(_) => { - FieldPlacement::union(0) - } - - Vector { element, count } => { - FieldPlacement::Linear { - stride: element.size(tcx), - count - } - } - - Array { element_size, count, .. } => { - FieldPlacement::Linear { - stride: element_size, - count - } - } - - FatPointer { .. } => { - FieldPlacement::Linear { - stride: Pointer.size(tcx), - count: 2 - } - } - Univariant(ref variant) => { FieldPlacement::Arbitrary { offsets: &variant.offsets } } - - UntaggedUnion(_) => { - // Handle unions through the type rather than Layout. - let def = ty.ty_adt_def().unwrap(); - FieldPlacement::union(def.struct_variant().fields.len()) - } - - General { .. } => FieldPlacement::union(1), - - NullablePointer { ref discr_offset, .. } => { - FieldPlacement::Arbitrary { - offsets: ref_slice(discr_offset) - } - } + _ => bug!() }; let abi = match *layout { - Scalar(value) => Abi::Scalar(value), - Vector { element, count } => Abi::Vector { element, count }, - - Array { sized, align, primitive_align, element_size, count, .. } => { - let size = match element_size.checked_mul(count, dl) { - Some(size) => size, - None => return Err(LayoutError::SizeOverflow(ty)) - }; - Abi::Aggregate { - sized, - align, - primitive_align, - size - } - } - - FatPointer(metadata) => { - // Effectively a (ptr, meta) tuple. - let align = Pointer.align(dl).max(metadata.align(dl)); - Abi::Aggregate { - sized: true, - align, - primitive_align: align, - size: (Pointer.size(dl).abi_align(metadata.align(dl)) + - metadata.size(dl)) - .abi_align(align) - } - } - Univariant(ref st) => { Abi::Aggregate { sized: st.sized, + packed: st.packed, align: st.align, primitive_align: st.primitive_align, size: st.stride() } } - - UntaggedUnion(ref un ) => { - Abi::Aggregate { - sized: true, - align: un.align, - primitive_align: un.primitive_align, - size: un.stride() - } - } - - General { discr, align, primitive_align, size, .. } | - NullablePointer { discr, align, primitive_align, size, .. } => { - if fields.offset(0).bytes() == 0 && discr.size(cx) == size { - Abi::Scalar(discr) - } else { - Abi::Aggregate { - sized: true, - align, - primitive_align, - size - } - } - } + _ => bug!() }; - Ok(CachedLayout { + CachedLayout { layout, fields, abi - }) + } }; assert!(!ty.has_infer_types()); let ptr_layout = |pointee: Ty<'tcx>| { let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env); if pointee.is_sized(tcx, param_env, DUMMY_SP) { - Ok(Scalar(Pointer)) - } else { - let unsized_part = tcx.struct_tail(pointee); - let metadata = match unsized_part.sty { - ty::TyForeign(..) => return Ok(Scalar(Pointer)), - ty::TySlice(_) | ty::TyStr => { - Int(dl.ptr_sized_integer(), false) - } - ty::TyDynamic(..) => Pointer, - _ => return Err(LayoutError::Unknown(unsized_part)) - }; - Ok(FatPointer(metadata)) + return Ok(scalar(Pointer)); } + + let unsized_part = tcx.struct_tail(pointee); + let metadata = match unsized_part.sty { + ty::TyForeign(..) => return Ok(scalar(Pointer)), + ty::TySlice(_) | ty::TyStr => { + Int(dl.ptr_sized_integer(), false) + } + ty::TyDynamic(..) => Pointer, + _ => return Err(LayoutError::Unknown(unsized_part)) + }; + + // Effectively a (ptr, meta) tuple. + let align = Pointer.align(dl).max(metadata.align(dl)); + let fields = FieldPlacement::Linear { + stride: Pointer.size(dl), + count: 2 + }; + let meta_offset = fields.offset(1); + assert_eq!(meta_offset, meta_offset.abi_align(metadata.align(dl))); + Ok(CachedLayout { + layout: tcx.intern_layout(Layout::FatPointer), + fields, + abi: + Abi::Aggregate { + sized: true, + packed: false, + align, + primitive_align: align, + size: (meta_offset + metadata.size(dl)).abi_align(align) + } + }) }; - let layout = match ty.sty { + Ok(match ty.sty { // Basic scalars. - ty::TyBool => Scalar(Int(I1, false)), - ty::TyChar => Scalar(Int(I32, false)), + ty::TyBool => scalar(Int(I1, false)), + ty::TyChar => scalar(Int(I32, false)), ty::TyInt(ity) => { - Scalar(Int(Integer::from_attr(dl, attr::SignedInt(ity)), true)) + scalar(Int(Integer::from_attr(dl, attr::SignedInt(ity)), true)) } ty::TyUint(ity) => { - Scalar(Int(Integer::from_attr(dl, attr::UnsignedInt(ity)), false)) + scalar(Int(Integer::from_attr(dl, attr::UnsignedInt(ity)), false)) } - ty::TyFloat(FloatTy::F32) => Scalar(F32), - ty::TyFloat(FloatTy::F64) => Scalar(F64), - ty::TyFnPtr(_) => Scalar(Pointer), + ty::TyFloat(FloatTy::F32) => scalar(F32), + ty::TyFloat(FloatTy::F64) => scalar(F64), + ty::TyFnPtr(_) => scalar(Pointer), // The never type. ty::TyNever => { - Univariant(Struct::new(dl, &[], &ReprOptions::default(), + univariant(Struct::new(dl, &[], &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?) } @@ -1446,50 +1305,74 @@ impl<'a, 'tcx> Layout<'tcx> { let element = cx.layout_of(element)?; let element_size = element.size(dl); let count = count.val.to_const_int().unwrap().to_u64().unwrap(); - Array { - sized: true, - align: element.align(dl), - primitive_align: element.primitive_align(dl), - element_size, - count, + let size = element_size.checked_mul(count, dl) + .ok_or(LayoutError::SizeOverflow(ty))?; + + CachedLayout { + layout: &Layout::Array, + fields: FieldPlacement::Linear { + stride: element_size, + count + }, + abi: Abi::Aggregate { + sized: true, + packed: false, + align: element.align(dl), + primitive_align: element.primitive_align(dl), + size + } } } ty::TySlice(element) => { let element = cx.layout_of(element)?; - Array { - sized: false, - align: element.align(dl), - primitive_align: element.primitive_align(dl), - element_size: element.size(dl), - count: 0 + CachedLayout { + layout: &Layout::Array, + fields: FieldPlacement::Linear { + stride: element.size(dl), + count: 0 + }, + abi: Abi::Aggregate { + sized: false, + packed: false, + align: element.align(dl), + primitive_align: element.primitive_align(dl), + size: Size::from_bytes(0) + } } } ty::TyStr => { - Array { - sized: false, - align: dl.i8_align, - primitive_align: dl.i8_align, - element_size: Size::from_bytes(1), - count: 0 + CachedLayout { + layout: &Layout::Array, + fields: FieldPlacement::Linear { + stride: Size::from_bytes(1), + count: 0 + }, + abi: Abi::Aggregate { + sized: false, + packed: false, + align: dl.i8_align, + primitive_align: dl.i8_align, + size: Size::from_bytes(0) + } } } // Odd unit types. ty::TyFnDef(..) => { - Univariant(Struct::new(dl, &[], &ReprOptions::default(), + univariant(Struct::new(dl, &[], &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?) } ty::TyDynamic(..) | ty::TyForeign(..) => { let mut unit = Struct::new(dl, &[], &ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?; unit.sized = false; - Univariant(unit) + univariant(unit) } // Tuples, generators and closures. ty::TyGenerator(def_id, ref substs, _) => { let tys = substs.field_tys(def_id, tcx); - Univariant(Struct::new(dl, + univariant(Struct::new(dl, &tys.map(|ty| cx.layout_of(ty)) .collect::, _>>()?, &ReprOptions::default(), @@ -1498,7 +1381,7 @@ impl<'a, 'tcx> Layout<'tcx> { ty::TyClosure(def_id, ref substs) => { let tys = substs.upvar_tys(def_id, tcx); - Univariant(Struct::new(dl, + univariant(Struct::new(dl, &tys.map(|ty| cx.layout_of(ty)) .collect::, _>>()?, &ReprOptions::default(), @@ -1512,7 +1395,7 @@ impl<'a, 'tcx> Layout<'tcx> { StructKind::MaybeUnsizedUnivariant }; - Univariant(Struct::new(dl, + univariant(Struct::new(dl, &tys.iter().map(|ty| cx.layout_of(ty)) .collect::, _>>()?, &ReprOptions::default(), kind, ty)?) @@ -1520,19 +1403,23 @@ impl<'a, 'tcx> Layout<'tcx> { // SIMD vector types. ty::TyAdt(def, ..) if def.repr.simd() => { + let count = ty.simd_size(tcx) as u64; let element = ty.simd_type(tcx); - match cx.layout_of(element)?.abi { - Abi::Scalar(value) => { - return success(Vector { - element: value, - count: ty.simd_size(tcx) as u64 - }); - } + let element = match cx.layout_of(element)?.abi { + Abi::Scalar(value) => value, _ => { tcx.sess.fatal(&format!("monomorphising SIMD type `{}` with \ a non-machine element type `{}`", ty, element)); } + }; + CachedLayout { + layout: &Layout::Vector, + fields: FieldPlacement::Linear { + stride: element.size(tcx), + count + }, + abi: Abi::Vector { element, count } } } @@ -1549,10 +1436,54 @@ impl<'a, 'tcx> Layout<'tcx> { // Uninhabitable; represent as unit // (Typechecking will reject discriminant-sizing attrs.) - return success(Univariant(Struct::new(dl, &[], + return Ok(univariant(Struct::new(dl, &[], &def.repr, StructKind::AlwaysSizedUnivariant, ty)?)); } + if def.is_union() { + let packed = def.repr.packed(); + if packed && def.repr.align > 0 { + bug!("Union cannot be packed and aligned"); + } + + let mut primitive_align = if def.repr.packed() { + dl.i8_align + } else { + dl.aggregate_align + }; + + let mut align = if def.repr.align > 0 { + let repr_align = def.repr.align as u64; + primitive_align.max( + Align::from_bytes(repr_align, repr_align).unwrap()) + } else { + primitive_align + }; + + let mut size = Size::from_bytes(0); + for field in &variants[0] { + assert!(!field.is_unsized()); + + if !packed { + align = align.max(field.align(dl)); + primitive_align = primitive_align.max(field.primitive_align(dl)); + } + size = cmp::max(size, field.size(dl)); + } + + return Ok(CachedLayout { + layout: &Layout::UntaggedUnion, + fields: FieldPlacement::union(variants[0].len()), + abi: Abi::Aggregate { + sized: true, + packed, + align, + primitive_align, + size: size.abi_align(align) + } + }); + } + if !def.is_enum() || (variants.len() == 1 && !def.repr.inhibit_enum_layout_opt() && !variants[0].is_empty()) { @@ -1570,14 +1501,7 @@ impl<'a, 'tcx> Layout<'tcx> { else { StructKind::AlwaysSizedUnivariant } }; - let layout = if def.is_union() { - let mut un = Union::new(dl, &def.repr); - un.extend(dl, variants[0].iter().map(|&f| Ok(f)), ty)?; - UntaggedUnion(un) - } else { - Univariant(Struct::new(dl, &variants[0], &def.repr, kind, ty)?) - }; - return success(layout); + return Ok(univariant(Struct::new(dl, &variants[0], &def.repr, kind, ty)?)); } let no_explicit_discriminants = def.variants.iter().enumerate() @@ -1608,25 +1532,49 @@ impl<'a, 'tcx> Layout<'tcx> { } } - if let Some((discr, offset, primitive)) = choice { - let mut discr_align = primitive.align(dl); - if offset.abi_align(discr_align) != offset { - st[discr].packed = true; - discr_align = dl.i8_align; - } - let align = st[discr].align.max(discr_align); - let primitive_align = st[discr].primitive_align.max(discr_align); + if let Some((nndiscr, offset, discr)) = choice { + let variants: Vec<_> = st.into_iter().map(&univariant).collect(); + let mut abi = variants[nndiscr].abi; - return success(NullablePointer { - nndiscr: discr as u64, - discr: primitive, + let mut discr_align = discr.align(dl); + match abi { + Abi::Aggregate { + ref mut align, + ref mut primitive_align, + ref mut packed, + .. + } => { + if offset.abi_align(discr_align) != offset { + *packed = true; + discr_align = dl.i8_align; + } + *align = align.max(discr_align); + *primitive_align = primitive_align.max(discr_align); + } + _ => {} + } + + let layout = tcx.intern_layout(Layout::NullablePointer { + nndiscr: nndiscr as u64, + discr, discr_offset: offset, - size: st[discr].stride(), - align, - primitive_align, - variants: st.into_iter().map(|variant| { - success(Univariant(variant)) - }).collect::, _>>()?, + variants, + }); + return Ok(CachedLayout { + layout, + fields: match *layout { + Layout::NullablePointer { ref discr_offset, .. } => { + FieldPlacement::Arbitrary { + offsets: ref_slice(discr_offset) + } + } + _ => bug!() + }, + abi: if offset.bytes() == 0 && discr.size(dl) == abi.size(dl) { + Abi::Scalar(discr) + } else { + abi + } }); } } @@ -1727,17 +1675,27 @@ impl<'a, 'tcx> Layout<'tcx> { } } - General { - discr: Int(ity, signed), + let discr = Int(ity, signed); + CachedLayout { + layout: tcx.intern_layout(Layout::General { + discr, - // FIXME: should be u128? - discr_range: (min as u64)..=(max as u64), - variants: variants.into_iter().map(|variant| { - success(Univariant(variant)) - }).collect::, _>>()?, - size, - align, - primitive_align, + // FIXME: should be u128? + discr_range: (min as u64)..=(max as u64), + variants: variants.into_iter().map(&univariant).collect(), + }), + fields: FieldPlacement::union(1), + abi: if discr.size(dl) == size { + Abi::Scalar(discr) + } else { + Abi::Aggregate { + sized: true, + packed: false, + align, + primitive_align, + size + } + } } } @@ -1748,11 +1706,11 @@ impl<'a, 'tcx> Layout<'tcx> { return Err(LayoutError::Unknown(ty)); } let layout = cx.layout_of(normalized)?; - return Ok(CachedLayout { + CachedLayout { layout: layout.layout, fields: layout.fields, abi: layout.abi - }); + } } ty::TyParam(_) => { return Err(LayoutError::Unknown(ty)); @@ -1760,9 +1718,7 @@ impl<'a, 'tcx> Layout<'tcx> { ty::TyInfer(_) | ty::TyError => { bug!("Layout::compute: unexpected type `{}`", ty) } - }; - - success(layout) + }) } /// This is invoked by the `layout_raw` query to record the final @@ -1916,8 +1872,8 @@ impl<'a, 'tcx> Layout<'tcx> { }, variant_infos); } - Layout::UntaggedUnion(ref un) => { - debug!("print-type-size t: `{:?}` adt union {:?}", ty, un); + Layout::UntaggedUnion => { + debug!("print-type-size t: `{:?}` adt union", ty); // layout does not currently store info about each // variant... record(adt_kind.into(), None, Vec::new()); @@ -1925,9 +1881,9 @@ impl<'a, 'tcx> Layout<'tcx> { // other cases provide little interesting (i.e. adjustable // via representation tweaks) size info beyond total size. - Layout::Scalar(_) | - Layout::Vector { .. } | - Layout::Array { .. } | + Layout::Scalar | + Layout::Vector | + Layout::Array | Layout::FatPointer { .. } => { debug!("print-type-size t: `{:?}` adt other", ty); record(adt_kind.into(), None, Vec::new()) @@ -2333,6 +2289,11 @@ impl<'a, 'tcx> FullLayout<'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() + } + pub fn size(&self, cx: C) -> Size { self.abi.size(cx) } @@ -2359,61 +2320,34 @@ impl<'gcx> HashStable> for Layout<'gcx> { mem::discriminant(self).hash_stable(hcx, hasher); match *self { - Scalar(ref value) => { - value.hash_stable(hcx, hasher); - } - Vector { element, count } => { - element.hash_stable(hcx, hasher); - count.hash_stable(hcx, hasher); - } - Array { sized, align, primitive_align, element_size, count } => { - sized.hash_stable(hcx, hasher); - align.hash_stable(hcx, hasher); - primitive_align.hash_stable(hcx, hasher); - element_size.hash_stable(hcx, hasher); - count.hash_stable(hcx, hasher); - } - FatPointer(ref metadata) => { - metadata.hash_stable(hcx, hasher); - } + Scalar => {} + Vector => {} + Array => {} + FatPointer => {} Univariant(ref variant) => { variant.hash_stable(hcx, hasher); } - UntaggedUnion(ref un) => { - un.hash_stable(hcx, hasher); - } + UntaggedUnion => {} General { discr, discr_range: RangeInclusive { start, end }, ref variants, - size, - align, - primitive_align } => { discr.hash_stable(hcx, hasher); start.hash_stable(hcx, hasher); end.hash_stable(hcx, hasher); variants.hash_stable(hcx, hasher); - size.hash_stable(hcx, hasher); - align.hash_stable(hcx, hasher); - primitive_align.hash_stable(hcx, hasher); } NullablePointer { nndiscr, ref variants, ref discr, discr_offset, - size, - align, - primitive_align } => { nndiscr.hash_stable(hcx, hasher); variants.hash_stable(hcx, hasher); discr.hash_stable(hcx, hasher); discr_offset.hash_stable(hcx, hasher); - size.hash_stable(hcx, hasher); - align.hash_stable(hcx, hasher); - primitive_align.hash_stable(hcx, hasher); } } } @@ -2453,7 +2387,8 @@ impl<'gcx> HashStable> for Abi { element.hash_stable(hcx, hasher); count.hash_stable(hcx, hasher); } - Aggregate { sized, size, align, primitive_align } => { + Aggregate { packed, sized, size, align, primitive_align } => { + packed.hash_stable(hcx, hasher); sized.hash_stable(hcx, hasher); size.hash_stable(hcx, hasher); align.hash_stable(hcx, hasher); @@ -2518,10 +2453,3 @@ impl_stable_hash_for!(struct ::ty::layout::Struct { memory_index, min_size }); - -impl_stable_hash_for!(struct ::ty::layout::Union { - align, - primitive_align, - min_size, - packed -}); diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index f59b372e7d5..dd5e97544c8 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -753,11 +753,11 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { bug!("failed to get layout for `{}`: {}", t, e) }); - if let Layout::General { ref variants, size, discr, .. } = *layout.layout { + if let Layout::General { ref variants, discr, .. } = *layout.layout { let discr_size = discr.size(cx.tcx).bytes(); debug!("enum `{}` is {} bytes large with layout:\n{:#?}", - t, size.bytes(), layout); + t, layout.size(cx.tcx).bytes(), layout); let (largest, slargest, largest_index) = enum_definition.variants .iter() diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 712108bf437..b727629e233 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -307,8 +307,8 @@ impl<'tcx> LayoutExt<'tcx> for FullLayout<'tcx> { } layout::Abi::Aggregate { .. } => { - if let Layout::Array { count, .. } = *self.layout { - if count > 0 { + if let Layout::Array { .. } = *self.layout { + if self.fields.count() > 0 { return self.field(ccx, 0).homogeneous_aggregate(ccx); } } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index ff66090dc8c..cd68d042473 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -42,7 +42,7 @@ //! taken to it, implementing them for Rust seems difficult. use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, Align, HasDataLayout, LayoutOf, Size, FullLayout}; +use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Size, FullLayout}; use context::CrateContext; use type_::Type; @@ -72,11 +72,7 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return; } match *l.layout { - layout::NullablePointer { .. } | - layout::General { .. } | - layout::UntaggedUnion { .. } => { } - - layout::Univariant(ref variant) => { + layout::Univariant(_) => { let is_enum = if let ty::TyAdt(def, _) = t.sty { def.is_enum() } else { @@ -87,9 +83,11 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } else { l }; - llty.set_struct_body(&struct_llfields(cx, variant_layout), variant.packed) - }, - _ => bug!("This function cannot handle {} with layout {:#?}", t, l) + llty.set_struct_body(&struct_llfields(cx, variant_layout), + variant_layout.is_packed()) + } + + _ => {} } } @@ -102,63 +100,44 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return cx.llvm_type_of(value.to_ty(cx.tcx())); } match *l.layout { - layout::Univariant(ref variant) => { + layout::Univariant(_) => { match name { None => { - Type::struct_(cx, &struct_llfields(cx, l), variant.packed) + Type::struct_(cx, &struct_llfields(cx, l), l.is_packed()) } Some(name) => { Type::named_struct(cx, name) } } } - layout::UntaggedUnion(ref un) => { - // Use alignment-sized ints to fill all the union storage. - let fill = union_fill(cx, un.stride(), un.align); + _ => { + let align = l.align(cx); + let abi_align = align.abi(); + let elem_ty = if let Some(ity) = layout::Integer::for_abi_align(cx, align) { + Type::from_integer(cx, ity) + } else { + let vec_align = cx.data_layout().vector_align(Size::from_bytes(abi_align)); + assert_eq!(vec_align.abi(), abi_align); + Type::vector(&Type::i32(cx), abi_align / 4) + }; + + let size = l.size(cx).bytes(); + assert_eq!(size % abi_align, 0); + let fill = Type::array(&elem_ty, size / abi_align); match name { None => { - Type::struct_(cx, &[fill], un.packed) + Type::struct_(cx, &[fill], l.is_packed()) } Some(name) => { let mut llty = Type::named_struct(cx, name); - llty.set_struct_body(&[fill], un.packed); + llty.set_struct_body(&[fill], l.is_packed()); llty } } } - layout::NullablePointer { size, align, .. } | - layout::General { size, align, .. } => { - let fill = union_fill(cx, size, align); - match name { - None => { - Type::struct_(cx, &[fill], false) - } - Some(name) => { - let mut llty = Type::named_struct(cx, name); - llty.set_struct_body(&[fill], false); - llty - } - } - } - _ => bug!("Unsupported type {} represented as {:#?}", t, l) } } -fn union_fill(cx: &CrateContext, size: Size, align: Align) -> Type { - let abi_align = align.abi(); - let elem_ty = if let Some(ity) = layout::Integer::for_abi_align(cx, align) { - Type::from_integer(cx, ity) - } else { - let vec_align = cx.data_layout().vector_align(Size::from_bytes(abi_align)); - assert_eq!(vec_align.abi(), abi_align); - Type::vector(&Type::i32(cx), abi_align / 4) - }; - - let size = size.bytes(); - assert_eq!(size % abi_align, 0); - Type::array(&elem_ty, size / abi_align) -} - /// Double an index and add 1 to account for padding. pub fn memory_index_to_gep(index: u64) -> u64 { 1 + index * 2 @@ -166,17 +145,20 @@ pub fn memory_index_to_gep(index: u64) -> u64 { pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, layout: FullLayout<'tcx>) -> Vec { - let variant = match *layout.layout { - layout::Univariant(ref variant) => variant, - _ => bug!("unexpected {:#?}", layout) - }; + debug!("struct_llfields: {:#?}", layout); + let align = layout.align(cx); + let size = layout.size(cx); let field_count = layout.fields.count(); - debug!("struct_llfields: variant: {:?}", variant); + let mut offset = Size::from_bytes(0); let mut result: Vec = Vec::with_capacity(1 + field_count * 2); - for i in variant.field_index_by_increasing_offset() { + let field_index_by_increasing_offset = match *layout.layout { + layout::Univariant(ref variant) => variant.field_index_by_increasing_offset(), + _ => bug!("unexpected {:#?}", layout) + }; + for i in field_index_by_increasing_offset { let field = layout.field(cx, i); - let target_offset = variant.offsets[i as usize]; + let target_offset = layout.fields.offset(i as usize); debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?}", i, field, offset, target_offset); assert!(target_offset >= offset); @@ -187,30 +169,30 @@ pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let llty = cx.llvm_type_of(field.ty); result.push(llty); - if variant.packed { + if layout.is_packed() { assert_eq!(padding.bytes(), 0); } else { let field_align = field.align(cx); - assert!(field_align.abi() <= variant.align.abi(), + assert!(field_align.abi() <= align.abi(), "non-packed type has field with larger align ({}): {:#?}", - field_align.abi(), variant); + field_align.abi(), layout); } offset = target_offset + field.size(cx); } - if variant.sized && field_count > 0 { - if offset > variant.stride() { - bug!("variant: {:?} stride: {:?} offset: {:?}", - variant, variant.stride(), offset); + if !layout.is_unsized() && field_count > 0 { + if offset > size { + bug!("layout: {:#?} stride: {:?} offset: {:?}", + layout, size, offset); } - let padding = variant.stride() - offset; - debug!("struct_llfields: pad_bytes: {:?} offset: {:?} min_size: {:?} stride: {:?}", - padding, offset, variant.min_size, variant.stride()); + let padding = size - offset; + debug!("struct_llfields: pad_bytes: {:?} offset: {:?} stride: {:?}", + padding, offset, size); result.push(Type::array(&Type::i8(cx), padding.bytes())); assert!(result.len() == 1 + field_count * 2); } else { - debug!("struct_llfields: offset: {:?} min_size: {:?} stride: {:?}", - offset, variant.min_size, variant.stride()); + debug!("struct_llfields: offset: {:?} stride: {:?}", + offset, size); } result diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index bc6ddef0e72..82a4095aa01 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -65,9 +65,9 @@ pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) let layout = ccx.layout_of(ty); match *layout.layout { Layout::FatPointer { .. } => true, - Layout::Univariant(ref variant) => { + Layout::Univariant(_) => { // There must be only 2 fields. - if variant.offsets.len() != 2 { + if layout.fields.count() != 2 { return false; } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 89f1bb6fd51..b9ff46166a8 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -939,20 +939,6 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Vec { let layout = cx.layout_of(self.ty); - - let tmp; - let offsets = match *layout.layout { - layout::Univariant(ref variant) => &variant.offsets, - layout::Vector { element, count } => { - let element_size = element.size(cx).bytes(); - tmp = (0..count). - map(|i| layout::Size::from_bytes(i*element_size)) - .collect::>(); - &tmp - } - _ => bug!("{} is not a struct", self.ty) - }; - self.variant.fields.iter().enumerate().map(|(i, f)| { let name = if self.variant.ctor_kind == CtorKind::Fn { format!("__{}", i) @@ -964,7 +950,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { MemberDescription { name, type_metadata: type_metadata(cx, field.ty, self.span), - offset: offsets[i], + offset: layout.fields.offset(i), size, align, flags: DIFlags::FlagZero, @@ -1022,18 +1008,12 @@ impl<'tcx> TupleMemberDescriptionFactory<'tcx> { fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Vec { let layout = cx.layout_of(self.ty); - let offsets = if let layout::Univariant(ref variant) = *layout.layout { - &variant.offsets - } else { - bug!("{} is not a tuple", self.ty); - }; - self.component_types.iter().enumerate().map(|(i, &component_type)| { let (size, align) = cx.size_and_align_of(component_type); MemberDescription { name: format!("__{}", i), type_metadata: type_metadata(cx, component_type, self.span), - offset: offsets[i], + offset: layout.fields.offset(i), size, align, flags: DIFlags::FlagZero, diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 209083a8e25..f374ed90c34 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -58,15 +58,9 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf let layout = ccx.layout_of(t); debug!("DST {} layout: {:?}", t, layout); - let (sized_size, sized_align) = match *layout.layout { - ty::layout::Layout::Univariant(ref variant) => { - (variant.offsets.last().map_or(0, |o| o.bytes()), variant.align.abi()) - } - _ => { - bug!("size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}", - t, layout); - } - }; + let i = layout.fields.count() - 1; + let sized_size = layout.fields.offset(i).bytes(); + let sized_align = layout.align(ccx).abi(); debug!("DST {} statically sized prefix size: {} align: {}", t, sized_size, sized_align); let sized_size = C_usize(ccx, sized_size); @@ -74,7 +68,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, layout.fields.count() - 1).ty; + let field_ty = layout.field(ccx, i).ty; let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info); // FIXME (#26403, #27023): We should be adding padding diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 8924fc3b5ac..d6e2257ab24 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -1108,14 +1108,14 @@ fn trans_const_adt<'a, 'tcx>( build_const_struct(ccx, l.for_variant(variant_index), vals, Some(discr)) } } - layout::UntaggedUnion(ref un) => { + layout::UntaggedUnion => { assert_eq!(variant_index, 0); let contents = [ vals[0].llval, - padding(ccx, un.stride() - ccx.size_of(vals[0].ty)) + padding(ccx, l.size(ccx) - ccx.size_of(vals[0].ty)) ]; - Const::new(C_struct(ccx, &contents, un.packed), t) + Const::new(C_struct(ccx, &contents, l.is_packed()), t) } layout::Univariant(_) => { assert_eq!(variant_index, 0); @@ -1162,11 +1162,11 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, offset = ccx.size_of(discr.ty); } - let st = match *layout.layout { - layout::Univariant(ref variant) => variant, + let field_index_by_increasing_offset = match *layout.layout { + layout::Univariant(ref variant) => variant.field_index_by_increasing_offset(), _ => bug!("unexpected {:#?}", layout) }; - let parts = st.field_index_by_increasing_offset().map(|i| { + let parts = field_index_by_increasing_offset.map(|i| { (vals[i], layout.fields.offset(i)) }); for (val, target_offset) in parts { @@ -1178,7 +1178,7 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // 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, st.packed), layout.ty) + Const::new(C_struct(ccx, &cfields, layout.is_packed()), layout.ty) } fn padding(ccx: &CrateContext, size: Size) -> ValueRef { diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index ab31bcde52a..b21e4ffc2c3 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -10,7 +10,7 @@ use llvm::{self, ValueRef}; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::layout::{self, Align, Layout, LayoutOf}; +use rustc::ty::layout::{self, Align, FullLayout, Layout, LayoutOf}; use rustc::mir; use rustc::mir::tcx::LvalueTy; use rustc_data_structures::indexed_vec::Idx; @@ -55,14 +55,9 @@ impl ops::BitOr for Alignment { } } -impl<'a> From<&'a Layout<'a>> for Alignment { - fn from(layout: &Layout) -> Self { - let (packed, align) = match *layout { - Layout::UntaggedUnion(ref un) => (un.packed, un.align), - Layout::Univariant(ref variant) => (variant.packed, variant.align), - _ => return Alignment::AbiAligned - }; - if packed { +impl<'a> From> for Alignment { + fn from(layout: FullLayout) -> Self { + if let layout::Abi::Aggregate { packed: true, align, .. } = layout.abi { Alignment::Packed(align) } else { Alignment::AbiAligned @@ -208,7 +203,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> { let field = l.field(ccx, ix); let offset = l.fields.offset(ix).bytes(); - let alignment = self.alignment | Alignment::from(l.layout); + let alignment = self.alignment | Alignment::from(l); // Unions and newtypes only use an offset of 0. match *l.layout { @@ -267,16 +262,10 @@ impl<'a, 'tcx> LvalueRef<'tcx> { } }; - // Check whether the variant being used is packed, if applicable. - let is_packed = match *l.layout { - layout::Univariant(ref variant) => variant.packed, - _ => return simple() - }; - // Simple case - we can just GEP the field // * Packed struct - There is no alignment padding // * Field is sized - pointer is properly aligned already - if is_packed || !field.is_unsized() { + if l.is_packed() || !field.is_unsized() { return simple(); } @@ -466,12 +455,13 @@ impl<'a, 'tcx> LvalueRef<'tcx> { // If this is an enum, cast to the appropriate variant struct type. let layout = bcx.ccx.layout_of(ty); - let variant_layout = layout.for_variant(variant_index); - match (layout.layout, variant_layout.layout) { - (&layout::NullablePointer { .. }, &layout::Univariant(ref st)) | - (&layout::General { .. }, &layout::Univariant(ref st)) => { + match *layout.layout { + layout::NullablePointer { .. } | + layout::General { .. } => { + let variant_layout = layout.for_variant(variant_index); let variant_ty = Type::struct_(bcx.ccx, - &adt::struct_llfields(bcx.ccx, variant_layout), st.packed); + &adt::struct_llfields(bcx.ccx, variant_layout), + variant_layout.is_packed()); downcast.llval = bcx.pointercast(downcast.llval, variant_ty.ptr_to()); } _ => {} diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index a71bcf47838..a1e89013bdb 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -12,7 +12,7 @@ use libc::c_uint; use llvm::{self, ValueRef, BasicBlockRef}; use llvm::debuginfo::DIScope; use rustc::ty::{self, Ty, TypeFoldable}; -use rustc::ty::layout::{self, LayoutOf}; +use rustc::ty::layout::LayoutOf; use rustc::mir::{self, Mir}; use rustc::ty::subst::Substs; use rustc::infer::TransNormalize; @@ -576,13 +576,8 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, }; let layout = bcx.ccx.layout_of(closure_ty); - let offsets = match *layout.layout { - layout::Univariant(ref variant) => &variant.offsets[..], - _ => bug!("Closures are only supposed to be Univariant") - }; - for (i, (decl, ty)) in mir.upvar_decls.iter().zip(upvar_tys).enumerate() { - let byte_offset_of_var_in_env = offsets[i].bytes(); + let byte_offset_of_var_in_env = layout.fields.offset(i).bytes(); let ops = unsafe { [llvm::LLVMRustDIBuilderCreateOpDeref(),