rustc: hide details in Layout in favor of Abi or FieldPlacement.
This commit is contained in:
parent
ed788a62f6
commit
08f9f134fd
@ -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
|
||||
});
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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());
|
||||
}
|
||||
_ => {}
|
||||
|
@ -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(),
|
||||
|
Loading…
Reference in New Issue
Block a user