rustc: hide details in Layout in favor of Abi or FieldPlacement.

This commit is contained in:
Eduard-Mihai Burtescu 2017-09-17 23:37:18 +03:00
parent ed788a62f6
commit 08f9f134fd
10 changed files with 353 additions and 484 deletions

View File

@ -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<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 @@ 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<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 @@ 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<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 @@ 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<C: HasDataLayout>(&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<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 @@ pub enum Layout<'a> {
discr: Primitive,
discr_offset: Size,
variants: Vec<CachedLayout<'a>>,
size: Size,
align: Align,
primitive_align: Align,
}
}
@ -1269,159 +1189,98 @@ impl<'a, 'tcx> Layout<'tcx> {
-> 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 @@ 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::<Result<Vec<_>, _>>()?,
&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::<Result<Vec<_>, _>>()?,
&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::<Result<Vec<_>, _>>()?,
&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::<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 @@ 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::<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 @@ 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<C: HasDataLayout>(&self, cx: C) -> Size {
self.abi.size(cx)
}
@ -2359,61 +2320,34 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> 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<StableHashingContext<'gcx>> 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
});

View File

@ -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()

View File

@ -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);
}
}

View File

@ -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<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 @@ 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

View File

@ -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;
}

View File

@ -939,20 +939,6 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> {
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 @@ 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<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,

View File

@ -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

View File

@ -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 {

View File

@ -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<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 @@ 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());
}
_ => {}

View File

@ -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(),