diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 5775fc957b5..bd99ae0204a 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -1128,9 +1128,12 @@ pub enum Layout { /// identity function. NullablePointer { nndiscr: u64, - nonnull: Struct, discr: Primitive, discr_offset: Size, + variants: Vec, + size: Size, + align: Align, + primitive_align: Align, } } @@ -1471,23 +1474,20 @@ impl<'a, 'tcx> Layout { !def.repr.inhibit_enum_layout_opt() && no_explicit_discriminants { // Nullable pointer optimization - let st0 = Struct::new(dl, &variants[0], - &def.repr, StructKind::AlwaysSizedUnivariant, ty)?; - let st1 = Struct::new(dl, &variants[1], - &def.repr, StructKind::AlwaysSizedUnivariant, ty)?; + let mut st = vec![ + Struct::new(dl, &variants[0], + &def.repr, StructKind::AlwaysSizedUnivariant, ty)?, + Struct::new(dl, &variants[1], + &def.repr, StructKind::AlwaysSizedUnivariant, ty)? + ]; let mut choice = None; for discr in 0..2 { - let (st, other) = if discr == 0 { - (&st0, &st1) - } else { - (&st1, &st0) - }; - if other.stride().bytes() > 0 { + if st[1 - discr].stride().bytes() > 0 { continue; } - let field = st.non_zero_field(tcx, param_env, + let field = st[discr].non_zero_field(tcx, param_env, variants[discr].iter().map(|&f| Ok(f)))?; if let Some((offset, primitive)) = field { choice = Some((discr, offset, primitive)); @@ -1496,23 +1496,22 @@ impl<'a, 'tcx> Layout { } if let Some((discr, offset, primitive)) = choice { - // HACK(eddyb) work around not being able to move - // out of arrays with just the indexing operator. - let mut st = if discr == 0 { st0 } else { st1 }; - let mut discr_align = primitive.align(dl); if offset.abi_align(discr_align) != offset { - st.packed = true; + st[discr].packed = true; discr_align = dl.i8_align; } - st.align = st.align.max(discr_align); - st.primitive_align = st.primitive_align.max(discr_align); + let align = st[discr].align.max(discr_align); + let primitive_align = st[discr].primitive_align.max(discr_align); return success(NullablePointer { nndiscr: discr as u64, - nonnull: st, discr: primitive, discr_offset: offset, + size: st[discr].stride(), + align, + primitive_align, + variants: st, }); } } @@ -1693,13 +1692,10 @@ impl<'a, 'tcx> Layout { metadata.size(dl)).abi_align(self.align(dl)) } + NullablePointer { size, .. } | General { size, .. } => size, UntaggedUnion(ref un) => un.stride(), - - Univariant(ref variant) | - NullablePointer { nonnull: ref variant, .. } => { - variant.stride() - } + Univariant(ref variant) => variant.stride() } } @@ -1726,13 +1722,11 @@ impl<'a, 'tcx> Layout { Pointer.align(dl).max(metadata.align(dl)) } - Array { align, .. } | General { align, .. } => align, + Array { align, .. } | + NullablePointer { align, .. } | + General { align, .. } => align, UntaggedUnion(ref un) => un.align, - - Univariant(ref variant) | - NullablePointer { nonnull: ref variant, .. } => { - variant.align - } + Univariant(ref variant) => variant.align } } @@ -1743,11 +1737,11 @@ impl<'a, 'tcx> Layout { /// Returns alignment before repr alignment is applied pub fn primitive_align(&self, cx: C) -> Align { match *self { - Array { primitive_align, .. } | General { primitive_align, .. } => primitive_align, - Univariant(ref variant) | - NullablePointer { nonnull: ref variant, .. } => { - variant.primitive_align - }, + Array { primitive_align, .. } | + NullablePointer { primitive_align, .. } | + General { primitive_align, .. } => primitive_align, + + Univariant(ref variant) => variant.primitive_align, _ => self.align(cx.data_layout()) } @@ -1850,23 +1844,6 @@ impl<'a, 'tcx> Layout { }; match *layout { - Layout::NullablePointer { nonnull: ref variant_layout, - nndiscr, - discr: _, - discr_offset: _ } => { - debug!("print-type-size t: `{:?}` adt nullable nndiscr {} is {:?}", - ty, nndiscr, variant_layout); - let variant_def = &adt_def.variants[nndiscr as usize]; - let fields: Vec<_> = - variant_def.fields.iter() - .map(|field_def| (field_def.name, field_def.ty(tcx, substs))) - .collect(); - record(adt_kind.into(), - None, - vec![build_variant_info(Some(variant_def.name), - &fields, - variant_layout)]); - } Layout::Univariant(ref variant_layout) => { let variant_names = || { adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::>() @@ -1893,7 +1870,8 @@ impl<'a, 'tcx> Layout { } } - Layout::General { ref variants, discr, .. } => { + Layout::NullablePointer { ref variants, .. } | + Layout::General { ref variants, .. } => { debug!("print-type-size t: `{:?}` adt general variants def {} layouts {} {:?}", ty, adt_def.variants.len(), variants.len(), variants); let variant_infos: Vec<_> = @@ -1910,7 +1888,10 @@ impl<'a, 'tcx> Layout { variant_layout) }) .collect(); - record(adt_kind.into(), Some(discr.size(tcx)), variant_infos); + record(adt_kind.into(), match *layout { + Layout::General { discr, .. } => Some(discr.size(tcx)), + _ => None + }, variant_infos); } Layout::UntaggedUnion(ref un) => { @@ -2215,19 +2196,13 @@ impl<'a, 'tcx> FullLayout<'tcx> { } } + NullablePointer { ref variants, .. } | General { ref variants, .. } => { FieldPlacement::Arbitrary { offsets: &variants[variant_index].offsets } } - NullablePointer { nndiscr, ref nonnull, .. } - if nndiscr as usize == variant_index => { - FieldPlacement::Arbitrary { - offsets: &nonnull.offsets - } - } - _ => FieldPlacement::union(count) }; @@ -2390,14 +2365,20 @@ impl<'gcx> HashStable> for Layout } NullablePointer { nndiscr, - ref nonnull, + ref variants, ref discr, discr_offset, + size, + align, + primitive_align } => { nndiscr.hash_stable(hcx, hasher); - nonnull.hash_stable(hcx, hasher); + variants.hash_stable(hcx, hasher); discr.hash_stable(hcx, hasher); discr_offset.hash_stable(hcx, hasher); + size.hash_stable(hcx, hasher); + align.hash_stable(hcx, hasher); + primitive_align.hash_stable(hcx, hasher); } } } diff --git a/src/librustc_trans/adt.rs b/src/librustc_trans/adt.rs index e1a65f37eff..634dba3660e 100644 --- a/src/librustc_trans/adt.rs +++ b/src/librustc_trans/adt.rs @@ -68,28 +68,24 @@ pub fn finish_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>, llty: &mut Type) { let l = cx.layout_of(t); debug!("finish_type_of: {} with layout {:#?}", t, l); + if let layout::Abi::Scalar(_) = l.abi { + return; + } match *l { - layout::General { .. } | layout::UntaggedUnion { .. } => { } - layout::Univariant { ..} | layout::NullablePointer { .. } => { - if let layout::Abi::Scalar(_) = l.abi { - return; - } - let (variant_layout, variant) = match *l { - layout::Univariant(ref variant) => { - let is_enum = if let ty::TyAdt(def, _) = t.sty { - def.is_enum() - } else { - false - }; - if is_enum { - (l.for_variant(0), variant) - } else { - (l, variant) - } - } - layout::NullablePointer { nndiscr, ref nonnull, .. } => - (l.for_variant(nndiscr as usize), nonnull), - _ => unreachable!() + layout::NullablePointer { .. } | + layout::General { .. } | + layout::UntaggedUnion { .. } => { } + + layout::Univariant(ref variant) => { + let is_enum = if let ty::TyAdt(def, _) = t.sty { + def.is_enum() + } else { + false + }; + let variant_layout = if is_enum { + l.for_variant(0) + } else { + l }; llty.set_struct_body(&struct_llfields(cx, variant_layout, variant), variant.packed) }, @@ -106,18 +102,6 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, return cx.llvm_type_of(value.to_ty(cx.tcx())); } match *l { - layout::NullablePointer { nndiscr, ref nonnull, .. } => { - match name { - None => { - Type::struct_(cx, &struct_llfields(cx, l.for_variant(nndiscr as usize), - nonnull), - nonnull.packed) - } - Some(name) => { - Type::named_struct(cx, name) - } - } - } layout::Univariant(ref variant) => { match name { None => { @@ -143,6 +127,7 @@ fn generic_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } } + layout::NullablePointer { size, align, .. } | layout::General { size, align, .. } => { let fill = union_fill(cx, size, align); match name { diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 16bca343dd0..0e74d985570 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1218,11 +1218,13 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { } } layout::NullablePointer { - nonnull: ref struct_def, nndiscr, discr, - discr_offset + discr_offset, + ref variants, + .. } => { + let struct_def = &variants[nndiscr as usize]; // Create a description of the non-null variant let (variant_type_metadata, member_description_factory) = describe_enum_variant(cx, diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index c8d8199a05e..4f7c91efccd 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -1124,9 +1124,9 @@ fn trans_const_adt<'a, 'tcx>( layout::Vector { .. } => { Const::new(C_vector(&vals.iter().map(|x| x.llval).collect::>()), t) } - layout::NullablePointer { ref nonnull, nndiscr, .. } => { + layout::NullablePointer { ref variants, nndiscr, .. } => { if variant_index as u64 == nndiscr { - build_const_struct(ccx, l, &nonnull, vals, None) + build_const_struct(ccx, l, &variants[variant_index], vals, None) } else { // Always use null even if it's not the `discrfield`th // field; see #8506. diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index f39e3cb7812..325ccd4fde3 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -273,7 +273,7 @@ impl<'a, 'tcx> LvalueRef<'tcx> { // Check whether the variant being used is packed, if applicable. let is_packed = match (&*l, l.variant_index) { (&layout::Univariant(ref variant), _) => variant.packed, - (&layout::NullablePointer { ref nonnull, .. }, _) => nonnull.packed, + (&layout::NullablePointer { ref variants, .. }, Some(v)) | (&layout::General { ref variants, .. }, Some(v)) => variants[v].packed, _ => return simple() }; @@ -471,11 +471,15 @@ 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 { ref variants, .. } = *layout { - let st = &variants[variant_index]; - let variant_ty = Type::struct_(bcx.ccx, - &adt::struct_llfields(bcx.ccx, layout, st), st.packed); - downcast.llval = bcx.pointercast(downcast.llval, variant_ty.ptr_to()); + match *layout { + layout::NullablePointer { ref variants, .. } | + layout::General { ref variants, .. } => { + let st = &variants[variant_index]; + let variant_ty = Type::struct_(bcx.ccx, + &adt::struct_llfields(bcx.ccx, layout, st), st.packed); + downcast.llval = bcx.pointercast(downcast.llval, variant_ty.ptr_to()); + } + _ => {} } downcast diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index eca6057db36..eb52d58098d 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -259,6 +259,7 @@ impl<'tcx> LayoutLlvmExt for FullLayout<'tcx> { 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) @@ -266,14 +267,6 @@ impl<'tcx> LayoutLlvmExt for FullLayout<'tcx> { bug!("FullLayout::llvm_field_index({:?}): not applicable", self) } } - - Layout::NullablePointer { nndiscr, ref nonnull, .. } => { - if self.variant_index == Some(nndiscr as usize) { - adt::memory_index_to_gep(nonnull.memory_index[index] as u64) - } else { - bug!("FullLayout::llvm_field_index({:?}): not applicable", self) - } - } } } } diff --git a/src/test/ui/print_type_sizes/nullable.stdout b/src/test/ui/print_type_sizes/nullable.stdout index 830678f174f..ec51adb25af 100644 --- a/src/test/ui/print_type_sizes/nullable.stdout +++ b/src/test/ui/print_type_sizes/nullable.stdout @@ -4,9 +4,11 @@ print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes print-type-size end padding: 1 bytes print-type-size type: `MyOption>`: 12 bytes, alignment: 4 bytes +print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 12 bytes print-type-size field `.0`: 12 bytes print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes +print-type-size variant `None`: 0 bytes print-type-size variant `Record`: 7 bytes print-type-size field `.val`: 4 bytes print-type-size field `.post`: 2 bytes @@ -18,6 +20,7 @@ print-type-size field `.post`: 2 bytes print-type-size field `.pre`: 1 bytes print-type-size end padding: 1 bytes print-type-size type: `MyOption>`: 4 bytes, alignment: 4 bytes +print-type-size variant `None`: 0 bytes print-type-size variant `Some`: 4 bytes print-type-size field `.0`: 4 bytes print-type-size type: `core::nonzero::NonZero`: 4 bytes, alignment: 4 bytes