mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-30 10:45:18 +00:00
rustc: do not inject discriminant fields into Layout::General's variants.
This commit is contained in:
parent
8afa3a01e6
commit
44eef7c9ac
@ -651,14 +651,14 @@ pub struct Struct {
|
||||
}
|
||||
|
||||
/// Info required to optimize struct layout.
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
enum StructKind {
|
||||
/// A tuple, closure, or univariant which cannot be coerced to unsized.
|
||||
AlwaysSizedUnivariant,
|
||||
/// A univariant, the last field of which may be coerced to unsized.
|
||||
MaybeUnsizedUnivariant,
|
||||
/// A univariant, but part of an enum.
|
||||
EnumVariant,
|
||||
EnumVariant(Integer),
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Struct {
|
||||
@ -692,30 +692,27 @@ impl<'a, 'tcx> Struct {
|
||||
// Neither do 1-member and 2-member structs.
|
||||
// In addition, code in trans assume that 2-element structs can become pairs.
|
||||
// It's easier to just short-circuit here.
|
||||
let can_optimize = (fields.len() > 2 || StructKind::EnumVariant == kind)
|
||||
&& (repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty();
|
||||
|
||||
let (optimize, sort_ascending) = match kind {
|
||||
StructKind::AlwaysSizedUnivariant => (can_optimize, false),
|
||||
StructKind::MaybeUnsizedUnivariant => (can_optimize, false),
|
||||
StructKind::EnumVariant => {
|
||||
assert!(fields.len() >= 1, "Enum variants must have discriminants.");
|
||||
(can_optimize && fields[0].size(dl).bytes() == 1, true)
|
||||
let (mut optimize, sort_ascending) = match kind {
|
||||
StructKind::AlwaysSizedUnivariant |
|
||||
StructKind::MaybeUnsizedUnivariant => (fields.len() > 2, false),
|
||||
StructKind::EnumVariant(discr) => {
|
||||
(discr.size().bytes() == 1, true)
|
||||
}
|
||||
};
|
||||
|
||||
optimize &= (repr.flags & ReprFlags::IS_UNOPTIMISABLE).is_empty();
|
||||
|
||||
ret.offsets = vec![Size::from_bytes(0); fields.len()];
|
||||
let mut inverse_memory_index: Vec<u32> = (0..fields.len() as u32).collect();
|
||||
|
||||
if optimize {
|
||||
let start = if let StructKind::EnumVariant = kind { 1 } else { 0 };
|
||||
let end = if let StructKind::MaybeUnsizedUnivariant = kind {
|
||||
fields.len() - 1
|
||||
} else {
|
||||
fields.len()
|
||||
};
|
||||
if end > start {
|
||||
let optimizing = &mut inverse_memory_index[start..end];
|
||||
if end > 0 {
|
||||
let optimizing = &mut inverse_memory_index[..end];
|
||||
if sort_ascending {
|
||||
optimizing.sort_by_key(|&x| fields[x as usize].align(dl).abi());
|
||||
} else {
|
||||
@ -734,13 +731,17 @@ impl<'a, 'tcx> Struct {
|
||||
// field 5 with offset 0 puts 0 in offsets[5].
|
||||
// At the bottom of this function, we use inverse_memory_index to produce memory_index.
|
||||
|
||||
if let StructKind::EnumVariant = kind {
|
||||
assert_eq!(inverse_memory_index[0], 0,
|
||||
"Enum variant discriminants must have the lowest offset.");
|
||||
}
|
||||
|
||||
let mut offset = Size::from_bytes(0);
|
||||
|
||||
if let StructKind::EnumVariant(discr) = kind {
|
||||
offset = discr.size();
|
||||
if !ret.packed {
|
||||
let align = discr.align(dl);
|
||||
ret.align = ret.align.max(align);
|
||||
ret.primitive_align = ret.primitive_align.max(align);
|
||||
}
|
||||
}
|
||||
|
||||
for i in inverse_memory_index.iter() {
|
||||
let field = fields[*i as usize];
|
||||
if !ret.sized {
|
||||
@ -1112,8 +1113,9 @@ pub enum Layout {
|
||||
variants: Union,
|
||||
},
|
||||
|
||||
/// General-case enums: for each case there is a struct, and they
|
||||
/// all start with a field for the discriminant.
|
||||
/// 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
|
||||
/// at a non-0 offset, after where the discriminant would go.
|
||||
General {
|
||||
discr: Integer,
|
||||
variants: Vec<Struct>,
|
||||
@ -1495,21 +1497,17 @@ impl<'a, 'tcx> Layout {
|
||||
// We're interested in the smallest alignment, so start large.
|
||||
let mut start_align = Align::from_bytes(256, 256).unwrap();
|
||||
|
||||
// Create the set of structs that represent each variant
|
||||
// Use the minimum integer type we figured out above
|
||||
let discr = Scalar { value: Int(min_ity), non_zero: false };
|
||||
// Create the set of structs that represent each variant.
|
||||
let mut variants = variants.into_iter().map(|fields| {
|
||||
let mut fields = fields.into_iter().map(|field| {
|
||||
let fields = fields.into_iter().map(|field| {
|
||||
field.layout(tcx, param_env)
|
||||
}).collect::<Result<Vec<_>, _>>()?;
|
||||
fields.insert(0, &discr);
|
||||
let st = Struct::new(dl,
|
||||
&fields,
|
||||
&def.repr, StructKind::EnumVariant, ty)?;
|
||||
&def.repr, StructKind::EnumVariant(min_ity), ty)?;
|
||||
// Find the first field we can't move later
|
||||
// to make room for a larger discriminant.
|
||||
// It is important to skip the first field.
|
||||
for i in st.field_index_by_increasing_offset().skip(1) {
|
||||
for i in st.field_index_by_increasing_offset() {
|
||||
let field = fields[i];
|
||||
let field_align = field.align(dl);
|
||||
if field.size(dl).bytes() != 0 || field_align.abi() != 1 {
|
||||
@ -1569,9 +1567,8 @@ impl<'a, 'tcx> Layout {
|
||||
let new_ity_size = Int(ity).size(dl);
|
||||
for variant in &mut variants {
|
||||
for i in variant.offsets.iter_mut() {
|
||||
// The first field is the discrimminant, at offset 0.
|
||||
// These aren't in order, and we need to skip it.
|
||||
if *i <= old_ity_size && *i > Size::from_bytes(0) {
|
||||
if *i <= old_ity_size {
|
||||
assert_eq!(*i, old_ity_size);
|
||||
*i = new_ity_size;
|
||||
}
|
||||
}
|
||||
@ -1759,7 +1756,7 @@ impl<'a, 'tcx> Layout {
|
||||
|
||||
General { ref variants, .. } => {
|
||||
let v = variant_index.expect("variant index required");
|
||||
variants[v].offsets[i + 1]
|
||||
variants[v].offsets[i]
|
||||
}
|
||||
|
||||
StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
|
||||
@ -1857,21 +1854,12 @@ impl<'a, 'tcx> Layout {
|
||||
}
|
||||
};
|
||||
|
||||
enum Fields<'a> {
|
||||
WithDiscrim(&'a Struct),
|
||||
NoDiscrim(&'a Struct),
|
||||
}
|
||||
|
||||
let build_variant_info = |n: Option<ast::Name>,
|
||||
flds: &[(ast::Name, Ty<'tcx>)],
|
||||
layout: Fields| {
|
||||
let (s, field_offsets) = match layout {
|
||||
Fields::WithDiscrim(s) => (s, &s.offsets[1..]),
|
||||
Fields::NoDiscrim(s) => (s, &s.offsets[0..]),
|
||||
};
|
||||
s: &Struct| {
|
||||
let field_info: Vec<_> =
|
||||
flds.iter()
|
||||
.zip(field_offsets.iter())
|
||||
.zip(&s.offsets)
|
||||
.map(|(&field_name_ty, offset)| build_field_info(field_name_ty, offset))
|
||||
.collect();
|
||||
|
||||
@ -1904,7 +1892,7 @@ impl<'a, 'tcx> Layout {
|
||||
None,
|
||||
vec![build_variant_info(Some(variant_def.name),
|
||||
&fields,
|
||||
Fields::NoDiscrim(variant_layout))]);
|
||||
variant_layout)]);
|
||||
}
|
||||
Layout::RawNullablePointer { nndiscr, value } => {
|
||||
debug!("print-type-size t: `{:?}` adt raw nullable nndiscr {} is {:?}",
|
||||
@ -1931,7 +1919,7 @@ impl<'a, 'tcx> Layout {
|
||||
None,
|
||||
vec![build_variant_info(Some(variant_def.name),
|
||||
&fields,
|
||||
Fields::NoDiscrim(variant_layout))]);
|
||||
variant_layout)]);
|
||||
} else {
|
||||
// (This case arises for *empty* enums; so give it
|
||||
// zero variants.)
|
||||
@ -1953,7 +1941,7 @@ impl<'a, 'tcx> Layout {
|
||||
.collect();
|
||||
build_variant_info(Some(variant_def.name),
|
||||
&fields,
|
||||
Fields::WithDiscrim(variant_layout))
|
||||
variant_layout)
|
||||
})
|
||||
.collect();
|
||||
record(adt_kind.into(), Some(discr.size()), variant_infos);
|
||||
|
@ -90,8 +90,7 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
(l.for_variant(nndiscr as usize), nonnull),
|
||||
_ => unreachable!()
|
||||
};
|
||||
llty.set_struct_body(&struct_llfields(cx, variant_layout, variant, None),
|
||||
variant.packed)
|
||||
llty.set_struct_body(&struct_llfields(cx, variant_layout, variant), variant.packed)
|
||||
},
|
||||
_ => bug!("This function cannot handle {} with layout {:#?}", t, l)
|
||||
}
|
||||
@ -116,7 +115,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
match name {
|
||||
None => {
|
||||
Type::struct_(cx, &struct_llfields(cx, l.for_variant(nndiscr as usize),
|
||||
nonnull, None),
|
||||
nonnull),
|
||||
nonnull.packed)
|
||||
}
|
||||
Some(name) => {
|
||||
@ -127,7 +126,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
layout::Univariant { ref variant, .. } => {
|
||||
match name {
|
||||
None => {
|
||||
Type::struct_(cx, &struct_llfields(cx, l, &variant, None),
|
||||
Type::struct_(cx, &struct_llfields(cx, l, &variant),
|
||||
variant.packed)
|
||||
}
|
||||
Some(name) => {
|
||||
@ -209,23 +208,16 @@ pub fn memory_index_to_gep(index: u64) -> u64 {
|
||||
|
||||
pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
layout: TyLayout<'tcx>,
|
||||
variant: &layout::Struct,
|
||||
discr: Option<Ty<'tcx>>) -> Vec<Type> {
|
||||
let field_count = (discr.is_some() as usize) + layout.field_count();
|
||||
variant: &layout::Struct) -> Vec<Type> {
|
||||
let field_count = layout.field_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);
|
||||
let field_iter = variant.field_index_by_increasing_offset().map(|i| {
|
||||
let ty = if i == 0 && discr.is_some() {
|
||||
cx.layout_of(discr.unwrap())
|
||||
} else {
|
||||
layout.field(cx, i - discr.is_some() as usize)
|
||||
};
|
||||
(i, ty, variant.offsets[i as usize])
|
||||
});
|
||||
for (index, field, target_offset) in field_iter {
|
||||
for i in variant.field_index_by_increasing_offset() {
|
||||
let field = layout.field(cx, i);
|
||||
let target_offset = variant.offsets[i as usize];
|
||||
debug!("struct_llfields: {}: {:?} offset: {:?} target_offset: {:?}",
|
||||
index, field, offset, target_offset);
|
||||
i, field, offset, target_offset);
|
||||
assert!(target_offset >= offset);
|
||||
let padding = target_offset - offset;
|
||||
result.push(Type::array(&Type::i8(cx), padding.bytes()));
|
||||
|
@ -1340,7 +1340,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
|
||||
// Creates MemberDescriptions for the fields of a single enum variant.
|
||||
struct VariantMemberDescriptionFactory<'tcx> {
|
||||
// Cloned from the layout::Struct describing the variant.
|
||||
offsets: &'tcx [layout::Size],
|
||||
offsets: Vec<layout::Size>,
|
||||
args: Vec<(String, Ty<'tcx>)>,
|
||||
discriminant_type_metadata: Option<DIType>,
|
||||
span: Span,
|
||||
@ -1436,8 +1436,12 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
};
|
||||
|
||||
// If this is not a univariant enum, there is also the discriminant field.
|
||||
let mut offsets = struct_def.offsets.clone();
|
||||
match discriminant_info {
|
||||
RegularDiscriminant(_) => arg_names.insert(0, "RUST$ENUM$DISR".to_string()),
|
||||
RegularDiscriminant(_) => {
|
||||
arg_names.insert(0, "RUST$ENUM$DISR".to_string());
|
||||
offsets.insert(0, Size::from_bytes(0));
|
||||
}
|
||||
_ => { /* do nothing */ }
|
||||
};
|
||||
|
||||
@ -1449,7 +1453,7 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
let member_description_factory =
|
||||
VariantMDF(VariantMemberDescriptionFactory {
|
||||
offsets: &struct_def.offsets[..],
|
||||
offsets,
|
||||
args,
|
||||
discriminant_type_metadata: match discriminant_info {
|
||||
RegularDiscriminant(discriminant_type_metadata) => {
|
||||
|
@ -1108,11 +1108,8 @@ fn trans_const_adt<'a, 'tcx>(
|
||||
layout::General { discr: d, ref variants, .. } => {
|
||||
let variant = &variants[variant_index];
|
||||
let lldiscr = C_int(Type::from_integer(ccx, d), variant_index as i64);
|
||||
let mut vals_with_discr = vec![
|
||||
Const::new(lldiscr, d.to_ty(ccx.tcx(), false))
|
||||
];
|
||||
vals_with_discr.extend_from_slice(vals);
|
||||
build_const_struct(ccx, l, &variant, &vals_with_discr)
|
||||
build_const_struct(ccx, l, &variant, vals,
|
||||
Some(Const::new(lldiscr, d.to_ty(ccx.tcx(), false))))
|
||||
}
|
||||
layout::UntaggedUnion { ref variants, .. }=> {
|
||||
assert_eq!(variant_index, 0);
|
||||
@ -1125,7 +1122,7 @@ fn trans_const_adt<'a, 'tcx>(
|
||||
}
|
||||
layout::Univariant { ref variant, .. } => {
|
||||
assert_eq!(variant_index, 0);
|
||||
build_const_struct(ccx, l, &variant, vals)
|
||||
build_const_struct(ccx, l, &variant, vals, None)
|
||||
}
|
||||
layout::Vector { .. } => {
|
||||
Const::new(C_vector(&vals.iter().map(|x| x.llval).collect::<Vec<_>>()), t)
|
||||
@ -1140,7 +1137,7 @@ fn trans_const_adt<'a, 'tcx>(
|
||||
}
|
||||
layout::StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
|
||||
if variant_index as u64 == nndiscr {
|
||||
build_const_struct(ccx, l, &nonnull, vals)
|
||||
build_const_struct(ccx, l, &nonnull, vals, None)
|
||||
} else {
|
||||
// Always use null even if it's not the `discrfield`th
|
||||
// field; see #8506.
|
||||
@ -1162,14 +1159,20 @@ fn trans_const_adt<'a, 'tcx>(
|
||||
fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
layout: layout::TyLayout<'tcx>,
|
||||
st: &layout::Struct,
|
||||
vals: &[Const<'tcx>])
|
||||
vals: &[Const<'tcx>],
|
||||
discr: Option<Const<'tcx>>)
|
||||
-> Const<'tcx> {
|
||||
assert_eq!(vals.len(), st.offsets.len());
|
||||
|
||||
// offset of current value
|
||||
let mut offset = Size::from_bytes(0);
|
||||
let mut cfields = Vec::new();
|
||||
cfields.reserve(st.offsets.len()*2);
|
||||
cfields.reserve(discr.is_some() as usize + 1 + st.offsets.len() * 2);
|
||||
|
||||
if let Some(discr) = discr {
|
||||
cfields.push(discr.llval);
|
||||
offset = ccx.size_of(discr.ty);
|
||||
}
|
||||
|
||||
let parts = st.field_index_by_increasing_offset().map(|i| {
|
||||
(vals[i], st.offsets[i])
|
||||
|
@ -236,14 +236,6 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Adjust the index to account for enum discriminants in variants.
|
||||
let mut ix = ix;
|
||||
if let layout::General { .. } = *l {
|
||||
if l.variant_index.is_some() {
|
||||
ix += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let simple = || {
|
||||
LvalueRef {
|
||||
llval: bcx.struct_gep(self.llval, l.llvm_field_index(ix)),
|
||||
@ -474,11 +466,10 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
|
||||
|
||||
// If this is an enum, cast to the appropriate variant struct type.
|
||||
let layout = bcx.ccx.layout_of(ty).for_variant(variant_index);
|
||||
if let layout::General { discr, ref variants, .. } = *layout {
|
||||
if let layout::General { ref variants, .. } = *layout {
|
||||
let st = &variants[variant_index];
|
||||
let variant_ty = Type::struct_(bcx.ccx,
|
||||
&adt::struct_llfields(bcx.ccx, layout, st,
|
||||
Some(discr.to_ty(bcx.tcx(), false))), st.packed);
|
||||
&adt::struct_llfields(bcx.ccx, layout, st), st.packed);
|
||||
downcast.llval = bcx.pointercast(downcast.llval, variant_ty.ptr_to());
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ pub fn inline_enum_const() -> E<i8, i16> {
|
||||
#[no_mangle]
|
||||
pub fn low_align_const() -> E<i16, [i16; 3]> {
|
||||
// Check that low_align_const and high_align_const use the same constant
|
||||
// CHECK: load {{.*}} bitcast ({ [0 x i8], i16, [0 x i8], i16, [4 x i8] }** [[LOW_HIGH_REF]]
|
||||
// CHECK: load {{.*}} bitcast ({ i16, [0 x i8], i16, [4 x i8] }** [[LOW_HIGH_REF]]
|
||||
*&E::A(0)
|
||||
}
|
||||
|
||||
@ -62,6 +62,6 @@ pub fn low_align_const() -> E<i16, [i16; 3]> {
|
||||
#[no_mangle]
|
||||
pub fn high_align_const() -> E<i16, i32> {
|
||||
// Check that low_align_const and high_align_const use the same constant
|
||||
// CHECK: load {{.*}} bitcast ({ [0 x i8], i16, [0 x i8], i16, [4 x i8] }** [[LOW_HIGH_REF]]
|
||||
// CHECK: load {{.*}} bitcast ({ i16, [0 x i8], i16, [4 x i8] }** [[LOW_HIGH_REF]]
|
||||
*&E::A(0)
|
||||
}
|
||||
|
@ -108,6 +108,9 @@ pub fn main() {
|
||||
let array_expected_size = round_up(28, align_of::<Eu64NonCLike<[u32; 5]>>());
|
||||
assert_eq!(size_of::<Eu64NonCLike<[u32; 5]>>(), array_expected_size);
|
||||
assert_eq!(size_of::<Eu64NonCLike<[u32; 6]>>(), 32);
|
||||
|
||||
assert_eq!(align_of::<Eu32>(), align_of::<u32>());
|
||||
assert_eq!(align_of::<Eu64NonCLike<u8>>(), align_of::<u64>());
|
||||
}
|
||||
|
||||
// Rounds x up to the next multiple of a
|
||||
|
Loading…
Reference in New Issue
Block a user