diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 22a3edd200c..9ad5e07d8fe 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -78,7 +78,7 @@ use hir; /// Internal storage pub struct GlobalArenas<'tcx> { // internings - layout: TypedArena, + layout: TypedArena>, // references generics: TypedArena, @@ -918,7 +918,7 @@ pub struct GlobalCtxt<'tcx> { stability_interner: RefCell>, - layout_interner: RefCell>, + layout_interner: RefCell>>, /// A vector of every trait accessible in the whole crate /// (i.e. including those from subcrates). This is used only for @@ -1016,7 +1016,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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) { return layout; } diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index eb22b6f2ce9..096c74a6163 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1004,7 +1004,7 @@ pub const FAT_PTR_ADDR: usize = 0; pub const FAT_PTR_EXTRA: usize = 1; /// 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> { /// Array-like placement. Can also express /// 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, /// 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 { Scalar(Primitive), Vector { @@ -1141,8 +1141,8 @@ impl Abi { /// For ADTs, it also includes field placement and enum optimizations. /// NOTE: Because Layout is interned, redundant information should be /// kept to a minimum, e.g. it includes no sub-component Ty or Layout. -#[derive(Debug, PartialEq, Eq, Hash)] -pub enum Layout { +#[derive(PartialEq, Eq, Hash, Debug)] +pub enum Layout<'a> { /// TyBool, TyChar, TyInt, TyUint, TyFloat, TyRawPtr, TyRef or TyFnPtr. Scalar(Primitive), @@ -1184,7 +1184,7 @@ pub enum Layout { // the largest space between two consecutive discriminants and // taking everything else as the (shortest) discriminant range. discr_range: RangeInclusive, - variants: Vec, + variants: Vec>, size: Size, align: Align, primitive_align: Align, @@ -1202,7 +1202,7 @@ pub enum Layout { nndiscr: u64, discr: Primitive, discr_offset: Size, - variants: Vec, + variants: Vec>, size: Size, 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 layout: &'tcx Layout, + pub layout: &'tcx Layout<'tcx>, pub fields: FieldPlacement<'tcx>, 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>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) @@ -1624,7 +1624,9 @@ impl<'a, 'tcx> Layout { size: st[discr].stride(), align, primitive_align, - variants: st, + variants: st.into_iter().map(|variant| { + success(Univariant(variant)) + }).collect::, _>>()?, }); } } @@ -1730,7 +1732,9 @@ impl<'a, 'tcx> Layout { // FIXME: should be u128? discr_range: (min as u64)..=(max as u64), - variants, + variants: variants.into_iter().map(|variant| { + success(Univariant(variant)) + }).collect::, _>>()?, size, align, primitive_align, @@ -1897,6 +1901,10 @@ impl<'a, 'tcx> Layout { .iter() .map(|f| (f.name, f.ty(tcx, substs))) .collect(); + let variant_layout = match *variant_layout.layout { + Univariant(ref variant) => variant, + _ => bug!() + }; build_variant_info(Some(variant_def.name), &fields, variant_layout) @@ -2084,7 +2092,7 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> { pub struct FullLayout<'tcx> { pub ty: Ty<'tcx>, pub variant_index: Option, - pub layout: &'tcx Layout, + pub layout: &'tcx Layout<'tcx>, pub fields: FieldPlacement<'tcx>, pub abi: Abi, } @@ -2198,27 +2206,22 @@ impl<'a, 'tcx> FullLayout<'tcx> { variants[variant_index].fields.len() }; - let (fields, abi) = match *self.layout { - Univariant(_) => (self.fields, self.abi), + let (layout, fields, abi) = match *self.layout { + Univariant(_) => (self.layout, self.fields, self.abi), NullablePointer { ref variants, .. } | General { ref variants, .. } => { - let variant = &variants[variant_index]; - (FieldPlacement::Arbitrary { - offsets: &variant.offsets - }, Abi::Aggregate { - sized: true, - align: variant.align, - primitive_align: variant.primitive_align, - size: variant.stride(), - }) + let variant = variants[variant_index]; + (variant.layout, variant.fields, variant.abi) } - _ => (FieldPlacement::union(count), self.abi) + _ => bug!() }; + assert_eq!(fields.count(), count); FullLayout { variant_index: Some(variant_index), + layout, fields, abi, ..*self @@ -2348,8 +2351,7 @@ impl<'a, 'tcx> FullLayout<'tcx> { } } -impl<'gcx> HashStable> for Layout -{ +impl<'gcx> HashStable> for Layout<'gcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'gcx>, hasher: &mut StableHasher) { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index b993b161877..f59b372e7d5 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -764,7 +764,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences { .zip(variants) .map(|(variant, variant_layout)| { // Subtract the size of the enum discriminant - let bytes = variant_layout.min_size + let bytes = variant_layout.abi.size(cx.tcx) .bytes() .saturating_sub(discr_size); diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index 314d929fe8c..ff66090dc8c 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -87,7 +87,7 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } else { 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) } @@ -105,8 +105,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), - variant.packed) + Type::struct_(cx, &struct_llfields(cx, l), variant.packed) } Some(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>, - layout: FullLayout<'tcx>, - variant: &layout::Struct) -> Vec { + layout: FullLayout<'tcx>) -> Vec { + let variant = match *layout.layout { + layout::Univariant(ref variant) => variant, + _ => bug!("unexpected {:#?}", layout) + }; let field_count = layout.fields.count(); debug!("struct_llfields: variant: {:?}", variant); let mut offset = Size::from_bytes(0); diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 6ab89f5c3eb..89f1bb6fd51 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1153,37 +1153,33 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { layout::General { ref variants, .. } => { let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata .expect("")); - variants - .iter() - .enumerate() - .map(|(i, struct_def)| { - let (variant_type_metadata, member_desc_factory) = - describe_enum_variant(cx, - self.enum_type, - struct_def, - i, - &adt.variants[i], - discriminant_info, - self.containing_scope, - self.span); + (0..variants.len()).map(|i| { + let variant = self.type_rep.for_variant(i); + let (variant_type_metadata, member_desc_factory) = + describe_enum_variant(cx, + variant, + &adt.variants[i], + discriminant_info, + self.containing_scope, + self.span); - let member_descriptions = member_desc_factory - .create_member_descriptions(cx); + let member_descriptions = member_desc_factory + .create_member_descriptions(cx); - set_members_of_composite_type(cx, - variant_type_metadata, - &member_descriptions); - MemberDescription { - name: "".to_string(), - type_metadata: variant_type_metadata, - offset: Size::from_bytes(0), - size: struct_def.stride(), - align: struct_def.align, - flags: DIFlags::FlagZero - } - }).collect() + set_members_of_composite_type(cx, + variant_type_metadata, + &member_descriptions); + MemberDescription { + name: "".to_string(), + type_metadata: variant_type_metadata, + offset: Size::from_bytes(0), + size: variant.size(cx), + align: variant.align(cx), + flags: DIFlags::FlagZero + } + }).collect() }, - layout::Univariant(ref variant) => { + layout::Univariant(_) => { assert!(adt.variants.len() <= 1); if adt.variants.is_empty() { @@ -1191,9 +1187,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { } else { let (variant_type_metadata, member_description_factory) = describe_enum_variant(cx, - self.enum_type, - variant, - 0, + self.type_rep, &adt.variants[0], NoDiscriminant, self.containing_scope, @@ -1210,8 +1204,8 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { name: "".to_string(), type_metadata: variant_type_metadata, offset: Size::from_bytes(0), - size: variant.stride(), - align: variant.align, + size: self.type_rep.size(cx), + align: self.type_rep.align(cx), flags: DIFlags::FlagZero } ] @@ -1221,16 +1215,13 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { nndiscr, discr, 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 let (variant_type_metadata, member_description_factory) = describe_enum_variant(cx, - self.enum_type, - struct_def, - nndiscr as usize, + variant, &adt.variants[nndiscr as usize], OptimizedDiscriminant, self.containing_scope, @@ -1278,8 +1269,8 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { name, type_metadata: variant_type_metadata, offset: Size::from_bytes(0), - size: struct_def.stride(), - align: struct_def.align, + size: variant.size(cx), + align: variant.align(cx), flags: DIFlags::FlagZero } ] @@ -1330,78 +1321,48 @@ enum EnumDiscriminantInfo { // descriptions of the fields of the variant. This is a rudimentary version of a // full RecursiveTypeDescription. fn describe_enum_variant<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - enum_type: Ty<'tcx>, - struct_def: &'tcx layout::Struct, - variant_index: usize, + layout: layout::FullLayout<'tcx>, variant: &'tcx ty::VariantDef, discriminant_info: EnumDiscriminantInfo, containing_scope: DIScope, span: Span) -> (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::>(); - - 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 unique_type_id = debug_context(cx).type_map .borrow_mut() .get_unique_type_id_of_enum_variant( cx, - enum_type, + layout.ty, &variant_name); let metadata_stub = create_struct_stub(cx, - enum_type, + layout.ty, &variant_name, unique_type_id, 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. - let mut offsets = struct_def.offsets.clone(); - match discriminant_info { + let (discr_offset, discr_arg) = match discriminant_info { RegularDiscriminant(_) => { - arg_names.insert(0, "RUST$ENUM$DISR".to_string()); - offsets.insert(0, Size::from_bytes(0)); + let enum_layout = cx.layout_of(layout.ty); + (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. - let args: Vec<(String, Ty)> = arg_names.iter() - .zip(field_tys.iter()) - .map(|(s, &t)| (s.to_string(), t)) - .collect(); + let args = discr_arg.into_iter().chain((0..layout.fields.count()).map(|i| { + let name = if variant.ctor_kind == CtorKind::Fn { + format!("__{}", i) + } else { + variant.fields[i].name.to_string() + }; + (name, layout.field(cx, i).ty) + })).collect(); let member_description_factory = VariantMDF(VariantMemberDescriptionFactory { diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index c64333fc044..8924fc3b5ac 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -1091,7 +1091,7 @@ fn trans_const_adt<'a, 'tcx>( _ => 0, }; match *l.layout { - layout::General { ref variants, .. } => { + layout::General { .. } => { let discr = match *kind { mir::AggregateKind::Adt(adt_def, _, _, _) => { 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 { discr } 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) => { @@ -1117,16 +1117,16 @@ fn trans_const_adt<'a, 'tcx>( Const::new(C_struct(ccx, &contents, un.packed), t) } - layout::Univariant(ref variant) => { + layout::Univariant(_) => { assert_eq!(variant_index, 0); - build_const_struct(ccx, l, &variant, vals, None) + build_const_struct(ccx, l, vals, None) } layout::Vector { .. } => { Const::new(C_vector(&vals.iter().map(|x| x.llval).collect::>()), t) } - layout::NullablePointer { ref variants, nndiscr, .. } => { + layout::NullablePointer { 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 { // Always use null even if it's not the `discrfield`th // field; see #8506. @@ -1147,24 +1147,27 @@ fn trans_const_adt<'a, 'tcx>( /// will read the wrong memory. fn build_const_struct<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, layout: layout::FullLayout<'tcx>, - st: &layout::Struct, vals: &[Const<'tcx>], discr: Option>) -> Const<'tcx> { - assert_eq!(vals.len(), st.offsets.len()); + assert_eq!(vals.len(), layout.fields.count()); // offset of current value let mut offset = Size::from_bytes(0); 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 { cfields.push(discr.llval); 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| { - (vals[i], st.offsets[i]) + (vals[i], layout.fields.offset(i)) }); for (val, target_offset) in parts { 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); } - let size = layout.size(ccx); - cfields.push(padding(ccx, size - offset)); + // 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) } diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index 00c76bee1a8..ab31bcde52a 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -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 { let (packed, align) = match *layout { Layout::UntaggedUnion(ref un) => (un.packed, un.align), @@ -234,27 +234,24 @@ impl<'a, 'tcx> LvalueRef<'tcx> { } // Discriminant field of enums. - match *l.layout { - layout::NullablePointer { .. } if l.variant_index.is_none() => { - let ty = ccx.llvm_type_of(field.ty); - let size = field.size(ccx).bytes(); + if let layout::NullablePointer { .. } = *l.layout { + let ty = ccx.llvm_type_of(field.ty); + let size = field.size(ccx).bytes(); - // If the discriminant is not on a multiple of the primitive's size, - // we need to go through i8*. Also assume the worst alignment. - if offset % size != 0 { - let byte_ptr = bcx.pointercast(self.llval, Type::i8p(ccx)); - let byte_ptr = bcx.inbounds_gep(byte_ptr, &[C_usize(ccx, offset)]); - 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()); + // If the discriminant is not on a multiple of the primitive's size, + // we need to go through i8*. Also assume the worst alignment. + if offset % size != 0 { + let byte_ptr = bcx.pointercast(self.llval, Type::i8p(ccx)); + let byte_ptr = bcx.inbounds_gep(byte_ptr, &[C_usize(ccx, offset)]); + let byte_align = Alignment::Packed(Align::from_bytes(1, 1).unwrap()); return LvalueRef::new_sized( - bcx.inbounds_gep(discr_ptr, &[C_usize(ccx, offset / size)]), - field.ty, alignment); + 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( + bcx.inbounds_gep(discr_ptr, &[C_usize(ccx, offset / size)]), + field.ty, alignment); } let simple = || { @@ -271,10 +268,8 @@ impl<'a, 'tcx> LvalueRef<'tcx> { }; // Check whether the variant being used is packed, if applicable. - let is_packed = match (l.layout, l.variant_index) { - (&layout::Univariant(ref variant), _) => variant.packed, - (&layout::NullablePointer { ref variants, .. }, Some(v)) | - (&layout::General { ref variants, .. }, Some(v)) => variants[v].packed, + let is_packed = match *l.layout { + layout::Univariant(ref variant) => variant.packed, _ => return simple() }; @@ -470,13 +465,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).for_variant(variant_index); - match *layout.layout { - layout::NullablePointer { ref variants, .. } | - layout::General { ref variants, .. } => { - let st = &variants[variant_index]; + 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)) => { 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()); } _ => {} diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index b829d33600c..679632d9113 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -242,7 +242,9 @@ impl<'tcx> LayoutLlvmExt for FullLayout<'tcx> { } match *self.layout { Layout::Scalar { .. } | - Layout::UntaggedUnion { .. } => { + Layout::UntaggedUnion { .. } | + Layout::NullablePointer { .. } | + Layout::General { .. } => { bug!("FullLayout::llvm_field_index({:?}): not applicable", self) } @@ -258,15 +260,6 @@ impl<'tcx> LayoutLlvmExt for FullLayout<'tcx> { Layout::Univariant(ref variant) => { 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) - } - } } } }