rustc: store CachedLayout for each variant of enum Layout's instead of Struct.
This commit is contained in:
parent
bd51a2bc19
commit
ed788a62f6
8 changed files with 131 additions and 175 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue