rustc: hide details in Layout in favor of Abi or FieldPlacement.
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 096c74a..13d3ec6 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -627,27 +627,27 @@
#[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<Size>,
+ offsets: Vec<Size>,
/// 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<u32>,
- pub min_size: Size,
+ min_size: Size,
}
/// Info required to optimize struct layout.
@@ -799,7 +799,7 @@
}
/// 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 @@
layout: FullLayout<'tcx>)
-> Result<Option<(Size, Primitive)>, 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 @@
}
}
- (&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 @@
}
// 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 @@
// 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 @@
}
}
- (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
+ (_, _, &ty::TyProjection(_)) | (_, _, &ty::TyAnon(..)) => {
bug!("Struct::non_zero_field_in_type: {:?} not normalized", layout);
}
@@ -920,79 +920,6 @@
}
}
-/// 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<I>(&mut self, dl: &TargetDataLayout,
- fields: I,
- scapegoat: Ty<'tcx>)
- -> Result<(), LayoutError<'tcx>>
- where I: Iterator<Item=Result<FullLayout<'a>, 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 @@
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 @@
/// 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<C: HasDataLayout>(&self, cx: C) -> Size {
let dl = cx.data_layout();
@@ -1144,26 +1080,16 @@
#[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 @@
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 @@
// taking everything else as the (shortest) discriminant range.
discr_range: RangeInclusive<u64>,
variants: Vec<CachedLayout<'a>>,
- size: Size,
- align: Align,
- primitive_align: Align,
},
/// Two cases distinguished by a nullable pointer: the case with discriminant
@@ -1203,9 +1126,6 @@
discr: Primitive,
discr_offset: Size,
variants: Vec<CachedLayout<'a>>,
- size: Size,
- align: Align,
- primitive_align: Align,
}
}
@@ -1269,159 +1189,98 @@
-> Result<CachedLayout<'tcx>, 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 @@
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::<Result<Vec<_>, _>>()?,
&ReprOptions::default(),
@@ -1498,7 +1381,7 @@
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::<Result<Vec<_>, _>>()?,
&ReprOptions::default(),
@@ -1512,7 +1395,7 @@
StructKind::MaybeUnsizedUnivariant
};
- Univariant(Struct::new(dl,
+ univariant(Struct::new(dl,
&tys.iter().map(|ty| cx.layout_of(ty))
.collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(), kind, ty)?)
@@ -1520,19 +1403,23 @@
// 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 @@
// 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 @@
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 @@
}
}
- 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::<Result<Vec<_>, _>>()?,
+ 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 @@
}
}
- 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::<Result<Vec<_>, _>>()?,
- 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 @@
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 @@
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 @@
}, 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 @@
// 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 @@
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<C: HasDataLayout>(&self, cx: C) -> Size {
self.abi.size(cx)
}
@@ -2359,61 +2320,34 @@
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 @@
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 @@
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 f59b372..dd5e975 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -753,11 +753,11 @@
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 712108b..b727629 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -307,8 +307,8 @@
}
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 ff66090..cd68d04 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 @@
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 @@
} 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 @@
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 struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
layout: FullLayout<'tcx>) -> Vec<Type> {
- 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<Type> = 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 @@
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 bc6ddef..82a4095 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -65,9 +65,9 @@
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 89f1bb6..b9ff461 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -939,20 +939,6 @@
fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
-> Vec<MemberDescription> {
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::<Vec<layout::Size>>();
- &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 @@
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 @@
fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>)
-> Vec<MemberDescription> {
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 209083a..f374ed9 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -58,15 +58,9 @@
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 @@
// 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 8924fc3..d6e2257 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -1108,14 +1108,14 @@
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 @@
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 @@
// 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 ab31bcd..b21e4ff 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<'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<FullLayout<'a>> 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 @@
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 @@
}
};
- // 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 @@
// 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 a71bcf4..a1e8901 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -12,7 +12,7 @@
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 @@
};
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(),