1
Fork 0

rustc: store CachedLayout for each variant of enum Layout's instead of Struct.

This commit is contained in:
Eduard-Mihai Burtescu 2017-09-17 19:34:28 +03:00
parent bd51a2bc19
commit ed788a62f6
8 changed files with 131 additions and 175 deletions

View file

@ -78,7 +78,7 @@ use hir;
/// Internal storage /// Internal storage
pub struct GlobalArenas<'tcx> { pub struct GlobalArenas<'tcx> {
// internings // internings
layout: TypedArena<Layout>, layout: TypedArena<Layout<'tcx>>,
// references // references
generics: TypedArena<ty::Generics>, generics: TypedArena<ty::Generics>,
@ -918,7 +918,7 @@ pub struct GlobalCtxt<'tcx> {
stability_interner: RefCell<FxHashSet<&'tcx attr::Stability>>, stability_interner: RefCell<FxHashSet<&'tcx attr::Stability>>,
layout_interner: RefCell<FxHashSet<&'tcx Layout>>, layout_interner: RefCell<FxHashSet<&'tcx Layout<'tcx>>>,
/// A vector of every trait accessible in the whole crate /// A vector of every trait accessible in the whole crate
/// (i.e. including those from subcrates). This is used only for /// (i.e. including those from subcrates). This is used only for
@ -1016,7 +1016,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
interned interned
} }
pub fn intern_layout(self, layout: Layout) -> &'gcx Layout { pub fn intern_layout(self, layout: Layout<'gcx>) -> &'gcx Layout<'gcx> {
if let Some(layout) = self.layout_interner.borrow().get(&layout) { if let Some(layout) = self.layout_interner.borrow().get(&layout) {
return layout; return layout;
} }

View file

@ -1004,7 +1004,7 @@ pub const FAT_PTR_ADDR: usize = 0;
pub const FAT_PTR_EXTRA: usize = 1; pub const FAT_PTR_EXTRA: usize = 1;
/// Describes how the fields of a type are located in memory. /// Describes how the fields of a type are located in memory.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum FieldPlacement<'a> { pub enum FieldPlacement<'a> {
/// Array-like placement. Can also express /// Array-like placement. Can also express
/// unions, by using a stride of zero bytes. /// unions, by using a stride of zero bytes.
@ -1058,7 +1058,7 @@ impl<'a> FieldPlacement<'a> {
/// Describes how values of the type are passed by target ABIs, /// Describes how values of the type are passed by target ABIs,
/// in terms of categories of C types there are ABI rules for. /// in terms of categories of C types there are ABI rules for.
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Abi { pub enum Abi {
Scalar(Primitive), Scalar(Primitive),
Vector { Vector {
@ -1141,8 +1141,8 @@ impl Abi {
/// For ADTs, it also includes field placement and enum optimizations. /// For ADTs, it also includes field placement and enum optimizations.
/// NOTE: Because Layout is interned, redundant information should be /// NOTE: Because Layout is interned, redundant information should be
/// kept to a minimum, e.g. it includes no sub-component Ty or Layout. /// kept to a minimum, e.g. it includes no sub-component Ty or Layout.
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(PartialEq, Eq, Hash, Debug)]
pub enum Layout { pub enum Layout<'a> {
/// TyBool, TyChar, TyInt, TyUint, TyFloat, TyRawPtr, TyRef or TyFnPtr. /// TyBool, TyChar, TyInt, TyUint, TyFloat, TyRawPtr, TyRef or TyFnPtr.
Scalar(Primitive), Scalar(Primitive),
@ -1184,7 +1184,7 @@ pub enum Layout {
// the largest space between two consecutive discriminants and // the largest space between two consecutive discriminants and
// taking everything else as the (shortest) discriminant range. // taking everything else as the (shortest) discriminant range.
discr_range: RangeInclusive<u64>, discr_range: RangeInclusive<u64>,
variants: Vec<Struct>, variants: Vec<CachedLayout<'a>>,
size: Size, size: Size,
align: Align, align: Align,
primitive_align: Align, primitive_align: Align,
@ -1202,7 +1202,7 @@ pub enum Layout {
nndiscr: u64, nndiscr: u64,
discr: Primitive, discr: Primitive,
discr_offset: Size, discr_offset: Size,
variants: Vec<Struct>, variants: Vec<CachedLayout<'a>>,
size: Size, size: Size,
align: Align, align: Align,
primitive_align: Align, primitive_align: Align,
@ -1228,9 +1228,9 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
} }
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct CachedLayout<'tcx> { pub struct CachedLayout<'tcx> {
pub layout: &'tcx Layout, pub layout: &'tcx Layout<'tcx>,
pub fields: FieldPlacement<'tcx>, pub fields: FieldPlacement<'tcx>,
pub abi: Abi, pub abi: Abi,
} }
@ -1262,7 +1262,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
}; };
} }
impl<'a, 'tcx> Layout { impl<'a, 'tcx> Layout<'tcx> {
fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>) ty: Ty<'tcx>)
@ -1624,7 +1624,9 @@ impl<'a, 'tcx> Layout {
size: st[discr].stride(), size: st[discr].stride(),
align, align,
primitive_align, primitive_align,
variants: st, variants: st.into_iter().map(|variant| {
success(Univariant(variant))
}).collect::<Result<Vec<_>, _>>()?,
}); });
} }
} }
@ -1730,7 +1732,9 @@ impl<'a, 'tcx> Layout {
// FIXME: should be u128? // FIXME: should be u128?
discr_range: (min as u64)..=(max as u64), discr_range: (min as u64)..=(max as u64),
variants, variants: variants.into_iter().map(|variant| {
success(Univariant(variant))
}).collect::<Result<Vec<_>, _>>()?,
size, size,
align, align,
primitive_align, primitive_align,
@ -1897,6 +1901,10 @@ impl<'a, 'tcx> Layout {
.iter() .iter()
.map(|f| (f.name, f.ty(tcx, substs))) .map(|f| (f.name, f.ty(tcx, substs)))
.collect(); .collect();
let variant_layout = match *variant_layout.layout {
Univariant(ref variant) => variant,
_ => bug!()
};
build_variant_info(Some(variant_def.name), build_variant_info(Some(variant_def.name),
&fields, &fields,
variant_layout) variant_layout)
@ -2084,7 +2092,7 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> {
pub struct FullLayout<'tcx> { pub struct FullLayout<'tcx> {
pub ty: Ty<'tcx>, pub ty: Ty<'tcx>,
pub variant_index: Option<usize>, pub variant_index: Option<usize>,
pub layout: &'tcx Layout, pub layout: &'tcx Layout<'tcx>,
pub fields: FieldPlacement<'tcx>, pub fields: FieldPlacement<'tcx>,
pub abi: Abi, pub abi: Abi,
} }
@ -2198,27 +2206,22 @@ impl<'a, 'tcx> FullLayout<'tcx> {
variants[variant_index].fields.len() variants[variant_index].fields.len()
}; };
let (fields, abi) = match *self.layout { let (layout, fields, abi) = match *self.layout {
Univariant(_) => (self.fields, self.abi), Univariant(_) => (self.layout, self.fields, self.abi),
NullablePointer { ref variants, .. } | NullablePointer { ref variants, .. } |
General { ref variants, .. } => { General { ref variants, .. } => {
let variant = &variants[variant_index]; let variant = variants[variant_index];
(FieldPlacement::Arbitrary { (variant.layout, variant.fields, variant.abi)
offsets: &variant.offsets
}, Abi::Aggregate {
sized: true,
align: variant.align,
primitive_align: variant.primitive_align,
size: variant.stride(),
})
} }
_ => (FieldPlacement::union(count), self.abi) _ => bug!()
}; };
assert_eq!(fields.count(), count);
FullLayout { FullLayout {
variant_index: Some(variant_index), variant_index: Some(variant_index),
layout,
fields, fields,
abi, abi,
..*self ..*self
@ -2348,8 +2351,7 @@ impl<'a, 'tcx> FullLayout<'tcx> {
} }
} }
impl<'gcx> HashStable<StableHashingContext<'gcx>> for Layout impl<'gcx> HashStable<StableHashingContext<'gcx>> for Layout<'gcx> {
{
fn hash_stable<W: StableHasherResult>(&self, fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>, hcx: &mut StableHashingContext<'gcx>,
hasher: &mut StableHasher<W>) { hasher: &mut StableHasher<W>) {

View file

@ -764,7 +764,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
.zip(variants) .zip(variants)
.map(|(variant, variant_layout)| { .map(|(variant, variant_layout)| {
// Subtract the size of the enum discriminant // Subtract the size of the enum discriminant
let bytes = variant_layout.min_size let bytes = variant_layout.abi.size(cx.tcx)
.bytes() .bytes()
.saturating_sub(discr_size); .saturating_sub(discr_size);

View file

@ -87,7 +87,7 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
} else { } else {
l l
}; };
llty.set_struct_body(&struct_llfields(cx, variant_layout, variant), variant.packed) llty.set_struct_body(&struct_llfields(cx, variant_layout), variant.packed)
}, },
_ => bug!("This function cannot handle {} with layout {:#?}", t, l) _ => bug!("This function cannot handle {} with layout {:#?}", t, l)
} }
@ -105,8 +105,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
layout::Univariant(ref variant) => { layout::Univariant(ref variant) => {
match name { match name {
None => { None => {
Type::struct_(cx, &struct_llfields(cx, l, &variant), Type::struct_(cx, &struct_llfields(cx, l), variant.packed)
variant.packed)
} }
Some(name) => { Some(name) => {
Type::named_struct(cx, name) Type::named_struct(cx, name)
@ -166,8 +165,11 @@ pub fn memory_index_to_gep(index: u64) -> u64 {
} }
pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, pub fn struct_llfields<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
layout: FullLayout<'tcx>, layout: FullLayout<'tcx>) -> Vec<Type> {
variant: &layout::Struct) -> Vec<Type> { let variant = match *layout.layout {
layout::Univariant(ref variant) => variant,
_ => bug!("unexpected {:#?}", layout)
};
let field_count = layout.fields.count(); let field_count = layout.fields.count();
debug!("struct_llfields: variant: {:?}", variant); debug!("struct_llfields: variant: {:?}", variant);
let mut offset = Size::from_bytes(0); let mut offset = Size::from_bytes(0);

View file

@ -1153,37 +1153,33 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
layout::General { ref variants, .. } => { layout::General { ref variants, .. } => {
let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata
.expect("")); .expect(""));
variants (0..variants.len()).map(|i| {
.iter() let variant = self.type_rep.for_variant(i);
.enumerate() let (variant_type_metadata, member_desc_factory) =
.map(|(i, struct_def)| { describe_enum_variant(cx,
let (variant_type_metadata, member_desc_factory) = variant,
describe_enum_variant(cx, &adt.variants[i],
self.enum_type, discriminant_info,
struct_def, self.containing_scope,
i, self.span);
&adt.variants[i],
discriminant_info,
self.containing_scope,
self.span);
let member_descriptions = member_desc_factory let member_descriptions = member_desc_factory
.create_member_descriptions(cx); .create_member_descriptions(cx);
set_members_of_composite_type(cx, set_members_of_composite_type(cx,
variant_type_metadata, variant_type_metadata,
&member_descriptions); &member_descriptions);
MemberDescription { MemberDescription {
name: "".to_string(), name: "".to_string(),
type_metadata: variant_type_metadata, type_metadata: variant_type_metadata,
offset: Size::from_bytes(0), offset: Size::from_bytes(0),
size: struct_def.stride(), size: variant.size(cx),
align: struct_def.align, align: variant.align(cx),
flags: DIFlags::FlagZero flags: DIFlags::FlagZero
} }
}).collect() }).collect()
}, },
layout::Univariant(ref variant) => { layout::Univariant(_) => {
assert!(adt.variants.len() <= 1); assert!(adt.variants.len() <= 1);
if adt.variants.is_empty() { if adt.variants.is_empty() {
@ -1191,9 +1187,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
} else { } else {
let (variant_type_metadata, member_description_factory) = let (variant_type_metadata, member_description_factory) =
describe_enum_variant(cx, describe_enum_variant(cx,
self.enum_type, self.type_rep,
variant,
0,
&adt.variants[0], &adt.variants[0],
NoDiscriminant, NoDiscriminant,
self.containing_scope, self.containing_scope,
@ -1210,8 +1204,8 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
name: "".to_string(), name: "".to_string(),
type_metadata: variant_type_metadata, type_metadata: variant_type_metadata,
offset: Size::from_bytes(0), offset: Size::from_bytes(0),
size: variant.stride(), size: self.type_rep.size(cx),
align: variant.align, align: self.type_rep.align(cx),
flags: DIFlags::FlagZero flags: DIFlags::FlagZero
} }
] ]
@ -1221,16 +1215,13 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
nndiscr, nndiscr,
discr, discr,
discr_offset, discr_offset,
ref variants,
.. ..
} => { } => {
let struct_def = &variants[nndiscr as usize]; let variant = self.type_rep.for_variant(nndiscr as usize);
// Create a description of the non-null variant // Create a description of the non-null variant
let (variant_type_metadata, member_description_factory) = let (variant_type_metadata, member_description_factory) =
describe_enum_variant(cx, describe_enum_variant(cx,
self.enum_type, variant,
struct_def,
nndiscr as usize,
&adt.variants[nndiscr as usize], &adt.variants[nndiscr as usize],
OptimizedDiscriminant, OptimizedDiscriminant,
self.containing_scope, self.containing_scope,
@ -1278,8 +1269,8 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> {
name, name,
type_metadata: variant_type_metadata, type_metadata: variant_type_metadata,
offset: Size::from_bytes(0), offset: Size::from_bytes(0),
size: struct_def.stride(), size: variant.size(cx),
align: struct_def.align, align: variant.align(cx),
flags: DIFlags::FlagZero flags: DIFlags::FlagZero
} }
] ]
@ -1330,78 +1321,48 @@ enum EnumDiscriminantInfo {
// descriptions of the fields of the variant. This is a rudimentary version of a // descriptions of the fields of the variant. This is a rudimentary version of a
// full RecursiveTypeDescription. // full RecursiveTypeDescription.
fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
enum_type: Ty<'tcx>, layout: layout::FullLayout<'tcx>,
struct_def: &'tcx layout::Struct,
variant_index: usize,
variant: &'tcx ty::VariantDef, variant: &'tcx ty::VariantDef,
discriminant_info: EnumDiscriminantInfo, discriminant_info: EnumDiscriminantInfo,
containing_scope: DIScope, containing_scope: DIScope,
span: Span) span: Span)
-> (DICompositeType, MemberDescriptionFactory<'tcx>) { -> (DICompositeType, MemberDescriptionFactory<'tcx>) {
let layout = cx.layout_of(enum_type);
let maybe_discr = match *layout.layout {
layout::General { .. } => Some(layout.field(cx, 0).ty),
_ => None,
};
let layout = layout.for_variant(variant_index);
let mut field_tys = (0..layout.fields.count()).map(|i| {
layout.field(cx, i).ty
}).collect::<Vec<_>>();
if let Some(discr) = maybe_discr {
field_tys.insert(0, discr);
}
// Could do some consistency checks here: size, align, field count, discr type
let variant_name = variant.name.as_str(); let variant_name = variant.name.as_str();
let unique_type_id = debug_context(cx).type_map let unique_type_id = debug_context(cx).type_map
.borrow_mut() .borrow_mut()
.get_unique_type_id_of_enum_variant( .get_unique_type_id_of_enum_variant(
cx, cx,
enum_type, layout.ty,
&variant_name); &variant_name);
let metadata_stub = create_struct_stub(cx, let metadata_stub = create_struct_stub(cx,
enum_type, layout.ty,
&variant_name, &variant_name,
unique_type_id, unique_type_id,
containing_scope); containing_scope);
// Get the argument names from the enum variant info
let mut arg_names: Vec<_> = match variant.ctor_kind {
CtorKind::Const => vec![],
CtorKind::Fn => {
variant.fields
.iter()
.enumerate()
.map(|(i, _)| format!("__{}", i))
.collect()
}
CtorKind::Fictive => {
variant.fields
.iter()
.map(|f| f.name.to_string())
.collect()
}
};
// If this is not a univariant enum, there is also the discriminant field. // If this is not a univariant enum, there is also the discriminant field.
let mut offsets = struct_def.offsets.clone(); let (discr_offset, discr_arg) = match discriminant_info {
match discriminant_info {
RegularDiscriminant(_) => { RegularDiscriminant(_) => {
arg_names.insert(0, "RUST$ENUM$DISR".to_string()); let enum_layout = cx.layout_of(layout.ty);
offsets.insert(0, Size::from_bytes(0)); (Some(enum_layout.fields.offset(0)),
Some(("RUST$ENUM$DISR".to_string(), enum_layout.field(cx, 0).ty)))
} }
_ => { /* do nothing */ } _ => (None, None),
}; };
let offsets = discr_offset.into_iter().chain((0..layout.fields.count()).map(|i| {
layout.fields.offset(i)
})).collect();
// Build an array of (field name, field type) pairs to be captured in the factory closure. // Build an array of (field name, field type) pairs to be captured in the factory closure.
let args: Vec<(String, Ty)> = arg_names.iter() let args = discr_arg.into_iter().chain((0..layout.fields.count()).map(|i| {
.zip(field_tys.iter()) let name = if variant.ctor_kind == CtorKind::Fn {
.map(|(s, &t)| (s.to_string(), t)) format!("__{}", i)
.collect(); } else {
variant.fields[i].name.to_string()
};
(name, layout.field(cx, i).ty)
})).collect();
let member_description_factory = let member_description_factory =
VariantMDF(VariantMemberDescriptionFactory { VariantMDF(VariantMemberDescriptionFactory {

View file

@ -1091,7 +1091,7 @@ fn trans_const_adt<'a, 'tcx>(
_ => 0, _ => 0,
}; };
match *l.layout { match *l.layout {
layout::General { ref variants, .. } => { layout::General { .. } => {
let discr = match *kind { let discr = match *kind {
mir::AggregateKind::Adt(adt_def, _, _, _) => { mir::AggregateKind::Adt(adt_def, _, _, _) => {
adt_def.discriminant_for_variant(ccx.tcx(), variant_index) adt_def.discriminant_for_variant(ccx.tcx(), variant_index)
@ -1105,7 +1105,7 @@ fn trans_const_adt<'a, 'tcx>(
if let layout::Abi::Scalar(_) = l.abi { if let layout::Abi::Scalar(_) = l.abi {
discr discr
} else { } else {
build_const_struct(ccx, l, &variants[variant_index], vals, Some(discr)) build_const_struct(ccx, l.for_variant(variant_index), vals, Some(discr))
} }
} }
layout::UntaggedUnion(ref un) => { layout::UntaggedUnion(ref un) => {
@ -1117,16 +1117,16 @@ fn trans_const_adt<'a, 'tcx>(
Const::new(C_struct(ccx, &contents, un.packed), t) Const::new(C_struct(ccx, &contents, un.packed), t)
} }
layout::Univariant(ref variant) => { layout::Univariant(_) => {
assert_eq!(variant_index, 0); assert_eq!(variant_index, 0);
build_const_struct(ccx, l, &variant, vals, None) build_const_struct(ccx, l, vals, None)
} }
layout::Vector { .. } => { layout::Vector { .. } => {
Const::new(C_vector(&vals.iter().map(|x| x.llval).collect::<Vec<_>>()), t) Const::new(C_vector(&vals.iter().map(|x| x.llval).collect::<Vec<_>>()), t)
} }
layout::NullablePointer { ref variants, nndiscr, .. } => { layout::NullablePointer { nndiscr, .. } => {
if variant_index as u64 == nndiscr { if variant_index as u64 == nndiscr {
build_const_struct(ccx, l, &variants[variant_index], vals, None) build_const_struct(ccx, l.for_variant(variant_index), vals, None)
} else { } else {
// Always use null even if it's not the `discrfield`th // Always use null even if it's not the `discrfield`th
// field; see #8506. // field; see #8506.
@ -1147,24 +1147,27 @@ fn trans_const_adt<'a, 'tcx>(
/// will read the wrong memory. /// will read the wrong memory.
fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
layout: layout::FullLayout<'tcx>, layout: layout::FullLayout<'tcx>,
st: &layout::Struct,
vals: &[Const<'tcx>], vals: &[Const<'tcx>],
discr: Option<Const<'tcx>>) discr: Option<Const<'tcx>>)
-> Const<'tcx> { -> Const<'tcx> {
assert_eq!(vals.len(), st.offsets.len()); assert_eq!(vals.len(), layout.fields.count());
// offset of current value // offset of current value
let mut offset = Size::from_bytes(0); let mut offset = Size::from_bytes(0);
let mut cfields = Vec::new(); let mut cfields = Vec::new();
cfields.reserve(discr.is_some() as usize + 1 + st.offsets.len() * 2); cfields.reserve(discr.is_some() as usize + 1 + layout.fields.count() * 2);
if let Some(discr) = discr { if let Some(discr) = discr {
cfields.push(discr.llval); cfields.push(discr.llval);
offset = ccx.size_of(discr.ty); offset = ccx.size_of(discr.ty);
} }
let st = match *layout.layout {
layout::Univariant(ref variant) => variant,
_ => bug!("unexpected {:#?}", layout)
};
let parts = st.field_index_by_increasing_offset().map(|i| { let parts = st.field_index_by_increasing_offset().map(|i| {
(vals[i], st.offsets[i]) (vals[i], layout.fields.offset(i))
}); });
for (val, target_offset) in parts { for (val, target_offset) in parts {
cfields.push(padding(ccx, target_offset - offset)); cfields.push(padding(ccx, target_offset - offset));
@ -1172,8 +1175,8 @@ fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
offset = target_offset + ccx.size_of(val.ty); offset = target_offset + ccx.size_of(val.ty);
} }
let size = layout.size(ccx); // Pad to the size of the whole type, not e.g. the variant.
cfields.push(padding(ccx, size - offset)); 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, st.packed), layout.ty)
} }

View file

@ -55,7 +55,7 @@ impl ops::BitOr for Alignment {
} }
} }
impl<'a> From<&'a Layout> for Alignment { impl<'a> From<&'a Layout<'a>> for Alignment {
fn from(layout: &Layout) -> Self { fn from(layout: &Layout) -> Self {
let (packed, align) = match *layout { let (packed, align) = match *layout {
Layout::UntaggedUnion(ref un) => (un.packed, un.align), Layout::UntaggedUnion(ref un) => (un.packed, un.align),
@ -234,27 +234,24 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
} }
// Discriminant field of enums. // Discriminant field of enums.
match *l.layout { if let layout::NullablePointer { .. } = *l.layout {
layout::NullablePointer { .. } if l.variant_index.is_none() => { let ty = ccx.llvm_type_of(field.ty);
let ty = ccx.llvm_type_of(field.ty); let size = field.size(ccx).bytes();
let size = field.size(ccx).bytes();
// If the discriminant is not on a multiple of the primitive's size, // If the discriminant is not on a multiple of the primitive's size,
// we need to go through i8*. Also assume the worst alignment. // we need to go through i8*. Also assume the worst alignment.
if offset % size != 0 { if offset % size != 0 {
let byte_ptr = bcx.pointercast(self.llval, Type::i8p(ccx)); let byte_ptr = bcx.pointercast(self.llval, Type::i8p(ccx));
let byte_ptr = bcx.inbounds_gep(byte_ptr, &[C_usize(ccx, offset)]); let byte_ptr = bcx.inbounds_gep(byte_ptr, &[C_usize(ccx, offset)]);
let byte_align = Alignment::Packed(Align::from_bytes(1, 1).unwrap()); let byte_align = Alignment::Packed(Align::from_bytes(1, 1).unwrap());
return LvalueRef::new_sized(
bcx.pointercast(byte_ptr, ty.ptr_to()), field.ty, byte_align);
}
let discr_ptr = bcx.pointercast(self.llval, ty.ptr_to());
return LvalueRef::new_sized( return LvalueRef::new_sized(
bcx.inbounds_gep(discr_ptr, &[C_usize(ccx, offset / size)]), bcx.pointercast(byte_ptr, ty.ptr_to()), field.ty, byte_align);
field.ty, alignment);
} }
_ => {}
let discr_ptr = bcx.pointercast(self.llval, ty.ptr_to());
return LvalueRef::new_sized(
bcx.inbounds_gep(discr_ptr, &[C_usize(ccx, offset / size)]),
field.ty, alignment);
} }
let simple = || { let simple = || {
@ -271,10 +268,8 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
}; };
// Check whether the variant being used is packed, if applicable. // Check whether the variant being used is packed, if applicable.
let is_packed = match (l.layout, l.variant_index) { let is_packed = match *l.layout {
(&layout::Univariant(ref variant), _) => variant.packed, layout::Univariant(ref variant) => variant.packed,
(&layout::NullablePointer { ref variants, .. }, Some(v)) |
(&layout::General { ref variants, .. }, Some(v)) => variants[v].packed,
_ => return simple() _ => return simple()
}; };
@ -470,13 +465,13 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
}; };
// If this is an enum, cast to the appropriate variant struct type. // If this is an enum, cast to the appropriate variant struct type.
let layout = bcx.ccx.layout_of(ty).for_variant(variant_index); let layout = bcx.ccx.layout_of(ty);
match *layout.layout { let variant_layout = layout.for_variant(variant_index);
layout::NullablePointer { ref variants, .. } | match (layout.layout, variant_layout.layout) {
layout::General { ref variants, .. } => { (&layout::NullablePointer { .. }, &layout::Univariant(ref st)) |
let st = &variants[variant_index]; (&layout::General { .. }, &layout::Univariant(ref st)) => {
let variant_ty = Type::struct_(bcx.ccx, let variant_ty = Type::struct_(bcx.ccx,
&adt::struct_llfields(bcx.ccx, layout, st), st.packed); &adt::struct_llfields(bcx.ccx, variant_layout), st.packed);
downcast.llval = bcx.pointercast(downcast.llval, variant_ty.ptr_to()); downcast.llval = bcx.pointercast(downcast.llval, variant_ty.ptr_to());
} }
_ => {} _ => {}

View file

@ -242,7 +242,9 @@ impl<'tcx> LayoutLlvmExt for FullLayout<'tcx> {
} }
match *self.layout { match *self.layout {
Layout::Scalar { .. } | Layout::Scalar { .. } |
Layout::UntaggedUnion { .. } => { Layout::UntaggedUnion { .. } |
Layout::NullablePointer { .. } |
Layout::General { .. } => {
bug!("FullLayout::llvm_field_index({:?}): not applicable", self) bug!("FullLayout::llvm_field_index({:?}): not applicable", self)
} }
@ -258,15 +260,6 @@ impl<'tcx> LayoutLlvmExt for FullLayout<'tcx> {
Layout::Univariant(ref variant) => { Layout::Univariant(ref variant) => {
adt::memory_index_to_gep(variant.memory_index[index] as u64) adt::memory_index_to_gep(variant.memory_index[index] as u64)
} }
Layout::NullablePointer { ref variants, .. } |
Layout::General { ref variants, .. } => {
if let Some(v) = self.variant_index {
adt::memory_index_to_gep(variants[v].memory_index[index] as u64)
} else {
bug!("FullLayout::llvm_field_index({:?}): not applicable", self)
}
}
} }
} }
} }