diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index 899245b22aaa9dfa292a3e8c569ed365dff060c4..0edd8f44f0ce192a99d0e4a3d079bc0ad7ba37ea 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -755,6 +755,7 @@ pub fn index_by_increasing_offset<'a>(&'a self) -> impl iter::Iterator bool { match *self { - Abi::Scalar(_) | Abi::Vector => false, + Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector => false, Abi::Aggregate { sized, .. } => !sized } } @@ -776,7 +777,7 @@ pub fn is_unsized(&self) -> bool { /// Returns true if the fields of the layout are packed. pub fn is_packed(&self) -> bool { match *self { - Abi::Scalar(_) | Abi::Vector => false, + Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector => false, Abi::Aggregate { packed, .. } => packed } } @@ -807,6 +808,7 @@ pub enum Variants { /// `Some` is the identity function (with a non-null reference). NicheFilling { dataful_variant: usize, + niche_variant: usize, niche: Scalar, niche_value: u128, variants: Vec, @@ -855,6 +857,18 @@ fn scalar(cx: C, scalar: Scalar) -> Self { primitive_align: align } } + + fn uninhabited(field_count: usize) -> Self { + let align = Align::from_bytes(1, 1).unwrap(); + CachedLayout { + variants: Variants::Single { index: 0 }, + fields: FieldPlacement::Union(field_count), + abi: Abi::Uninhabited, + align, + primitive_align: align, + size: Size::from_bytes(0) + } + } } fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -915,13 +929,14 @@ enum StructKind { bug!("struct cannot be packed and aligned"); } - let mut align = if packed { + let base_align = if packed { dl.i8_align } else { dl.aggregate_align }; - let mut primitive_align = align; + let mut align = base_align; + let mut primitive_align = base_align; let mut sized = true; // Anything with repr(C) or repr(packed) doesn't optimize. @@ -978,13 +993,17 @@ enum StructKind { } } - for i in inverse_memory_index.iter() { - let field = fields[*i as usize]; + for &i in &inverse_memory_index { + let field = fields[i as usize]; if !sized { bug!("univariant: field #{} of `{}` comes after unsized field", offsets.len(), ty); } + if field.abi == Abi::Uninhabited { + return Ok(CachedLayout::uninhabited(fields.len())); + } + if field.is_unsized() { sized = false; } @@ -997,7 +1016,7 @@ enum StructKind { } debug!("univariant offset: {:?} field: {:#?}", offset, field); - offsets[*i as usize] = offset; + offsets[i as usize] = offset; offset = offset.checked_add(field.size, dl) .ok_or(LayoutError::SizeOverflow(ty))?; @@ -1124,7 +1143,7 @@ enum StructKind { // The never type. ty::TyNever => { - univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)? + tcx.intern_layout(CachedLayout::uninhabited(0)) } // Potentially-fat pointers. @@ -1278,11 +1297,15 @@ enum StructKind { }).collect::, _>>() }).collect::, _>>()?; - if variants.is_empty() { - // Uninhabitable; represent as unit - // (Typechecking will reject discriminant-sizing attrs.) - - return univariant(&[], &def.repr, StructKind::AlwaysSized); + let (inh_first, inh_second, inh_third) = { + let mut inh_variants = (0..variants.len()).filter(|&v| { + variants[v].iter().all(|f| f.abi != Abi::Uninhabited) + }); + (inh_variants.next(), inh_variants.next(), inh_variants.next()) + }; + if inh_first.is_none() { + // Uninhabited because it has no variants, or only uninhabited ones. + return Ok(tcx.intern_layout(CachedLayout::uninhabited(0))); } if def.is_union() { @@ -1329,49 +1352,58 @@ enum StructKind { })); } - if !def.is_enum() || (variants.len() == 1 && - !def.repr.inhibit_enum_layout_opt() && - !variants[0].is_empty()) { - // Struct, or union, or univariant enum equivalent to a struct. + let is_struct = !def.is_enum() || + // Only one variant is inhabited. + (inh_second.is_none() && + // Representation optimizations are allowed. + !def.repr.inhibit_enum_layout_opt() && + // Inhabited variant either has data ... + (!variants[inh_first.unwrap()].is_empty() || + // ... or there other, uninhabited, variants. + variants.len() > 1)); + if is_struct { + // Struct, or univariant enum equivalent to a struct. // (Typechecking will reject discriminant-sizing attrs.) - let kind = if def.is_enum() || variants[0].len() == 0 { + let v = inh_first.unwrap(); + let kind = if def.is_enum() || variants[v].len() == 0 { StructKind::AlwaysSized } else { let param_env = tcx.param_env(def.did); - let last_field = def.variants[0].fields.last().unwrap(); + let last_field = def.variants[v].fields.last().unwrap(); let always_sized = tcx.type_of(last_field.did) .is_sized(tcx, param_env, DUMMY_SP); if !always_sized { StructKind::MaybeUnsized } else { StructKind::AlwaysSized } }; - return univariant(&variants[0], &def.repr, kind); + let mut st = univariant_uninterned(&variants[v], &def.repr, kind)?; + st.variants = Variants::Single { index: v }; + return Ok(tcx.intern_layout(st)); } let no_explicit_discriminants = def.variants.iter().enumerate() .all(|(i, v)| v.discr == ty::VariantDiscr::Relative(i)); - if variants.len() == 2 && + if inh_second.is_some() && inh_third.is_none() && !def.repr.inhibit_enum_layout_opt() && no_explicit_discriminants { // Nullable pointer optimization - for i in 0..2 { - if !variants[1 - i].iter().all(|f| f.is_zst()) { + let (a, b) = (inh_first.unwrap(), inh_second.unwrap()); + for &(i, other) in &[(a, b), (b, a)] { + if !variants[other].iter().all(|f| f.is_zst()) { continue; } for (field_index, field) in variants[i].iter().enumerate() { if let Some((offset, niche, niche_value)) = field.find_niche(cx)? { - let mut st = vec![ - univariant_uninterned(&variants[0], - &def.repr, StructKind::AlwaysSized)?, - univariant_uninterned(&variants[1], - &def.repr, StructKind::AlwaysSized)? - ]; - for (i, v) in st.iter_mut().enumerate() { - v.variants = Variants::Single { index: i }; - } + let st = variants.iter().enumerate().map(|(j, v)| { + let mut st = univariant_uninterned(v, + &def.repr, StructKind::AlwaysSized)?; + st.variants = Variants::Single { index: j }; + Ok(st) + }).collect::, _>>()?; + let offset = st[i].fields.offset(field_index) + offset; let CachedLayout { size, @@ -1400,6 +1432,7 @@ enum StructKind { return Ok(tcx.intern_layout(CachedLayout { variants: Variants::NicheFilling { dataful_variant: i, + niche_variant: other, niche, niche_value, variants: st, @@ -1419,11 +1452,15 @@ enum StructKind { } let (mut min, mut max) = (i128::max_value(), i128::min_value()); - for discr in def.discriminants(tcx) { + for (i, discr) in def.discriminants(tcx).enumerate() { + if variants[i].iter().any(|f| f.abi == Abi::Uninhabited) { + continue; + } let x = discr.to_u128_unchecked() as i128; if x < min { min = x; } if x > max { max = x; } } + assert!(min <= max, "discriminant range is {}...{}", min, max); let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max); let mut align = dl.aggregate_align; @@ -1498,6 +1535,9 @@ enum StructKind { let old_ity_size = min_ity.size(); let new_ity_size = ity.size(); for variant in &mut variants { + if variant.abi == Abi::Uninhabited { + continue; + } match variant.fields { FieldPlacement::Arbitrary { ref mut offsets, .. } => { for i in offsets { @@ -1663,16 +1703,11 @@ fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; match layout.variants { - Variants::Single { .. } => { - let variant_names = || { - adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::>() - }; - debug!("print-type-size `{:#?}` variants: {:?}", - layout, variant_names()); - assert!(adt_def.variants.len() <= 1, - "univariant with variants {:?}", variant_names()); - if adt_def.variants.len() == 1 { - let variant_def = &adt_def.variants[0]; + Variants::Single { index } => { + debug!("print-type-size `{:#?}` variant {}", + layout, adt_def.variants[index].name); + if !adt_def.variants.is_empty() { + let variant_def = &adt_def.variants[index]; let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect(); record(adt_kind.into(), @@ -1697,7 +1732,7 @@ fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>, variant_def.fields.iter().map(|f| f.name).collect(); build_variant_info(Some(variant_def.name), &fields, - layout.for_variant(i)) + layout.for_variant(cx, i)) }) .collect(); record(adt_kind.into(), match layout.variants { @@ -1989,15 +2024,35 @@ fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { } impl<'a, 'tcx> TyLayout<'tcx> { - pub fn for_variant(&self, variant_index: usize) -> Self { + pub fn for_variant(&self, cx: C, variant_index: usize) -> Self + where C: LayoutOf> + HasTyCtxt<'tcx>, + C::TyLayout: MaybeResult> + { let cached = match self.variants { - Variants::Single { .. } => self.cached, + Variants::Single { index } if index == variant_index => self.cached, + + Variants::Single { index } => { + // Deny calling for_variant more than once for non-Single enums. + cx.layout_of(self.ty).map_same(|layout| { + assert_eq!(layout.variants, Variants::Single { index }); + layout + }); + + let fields = match self.ty.sty { + ty::TyAdt(def, _) => def.variants[variant_index].fields.len(), + _ => bug!() + }; + let mut cached = CachedLayout::uninhabited(fields); + cached.variants = Variants::Single { index: variant_index }; + cx.tcx().intern_layout(cached) + } Variants::NicheFilling { ref variants, .. } | Variants::Tagged { ref variants, .. } => { &variants[variant_index] } }; + assert_eq!(cached.variants, Variants::Single { index: variant_index }); TyLayout { @@ -2138,6 +2193,7 @@ pub fn is_packed(&self) -> bool { /// Returns true if the type is a ZST and not unsized. pub fn is_zst(&self) -> bool { match self.abi { + Abi::Uninhabited => true, Abi::Scalar(_) => false, Abi::Vector => self.size.bytes() == 0, Abi::Aggregate { sized, .. } => sized && self.size.bytes() == 0 @@ -2241,11 +2297,13 @@ fn hash_stable(&self, } NicheFilling { dataful_variant, + niche_variant, ref niche, niche_value, ref variants, } => { dataful_variant.hash_stable(hcx, hasher); + niche_variant.hash_stable(hcx, hasher); niche.hash_stable(hcx, hasher); niche_value.hash_stable(hcx, hasher); variants.hash_stable(hcx, hasher); @@ -2285,6 +2343,7 @@ fn hash_stable(&self, mem::discriminant(self).hash_stable(hcx, hasher); match *self { + Uninhabited => {} Scalar(ref value) => { value.hash_stable(hcx, hasher); } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index c87f856b0054efee1678b003be00bdda67f937c0..c4b90d94dd4b38a00b9291cfb7360f14f1763772 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -278,6 +278,7 @@ pub trait LayoutExt<'tcx> { impl<'tcx> LayoutExt<'tcx> for TyLayout<'tcx> { fn is_aggregate(&self) -> bool { match self.abi { + layout::Abi::Uninhabited | layout::Abi::Scalar(_) | layout::Abi::Vector => false, layout::Abi::Aggregate { .. } => true @@ -286,6 +287,8 @@ fn is_aggregate(&self) -> bool { fn homogeneous_aggregate<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Option { match self.abi { + layout::Abi::Uninhabited => None, + // The primitive for this algorithm. layout::Abi::Scalar(ref scalar) => { let kind = match scalar.value { diff --git a/src/librustc_trans/cabi_x86_64.rs b/src/librustc_trans/cabi_x86_64.rs index bc445c7d2a76d36a350182e3bb4b1d5d4bfbcda0..62540fac8b53e59d8feee7294f9743bad2e93a69 100644 --- a/src/librustc_trans/cabi_x86_64.rs +++ b/src/librustc_trans/cabi_x86_64.rs @@ -65,6 +65,8 @@ fn classify<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } match layout.abi { + layout::Abi::Uninhabited => {} + layout::Abi::Scalar(ref scalar) => { let reg = match scalar.value { layout::Int(..) | diff --git a/src/librustc_trans/cabi_x86_win64.rs b/src/librustc_trans/cabi_x86_win64.rs index ceb649be197efd54368f90a6e249f54d28b923d3..e93eeb83619b6072c82e5dc9af2f452124cc8fcd 100644 --- a/src/librustc_trans/cabi_x86_win64.rs +++ b/src/librustc_trans/cabi_x86_win64.rs @@ -17,6 +17,7 @@ pub fn compute_abi_info(fty: &mut FnType) { let fixup = |a: &mut ArgType| { match a.layout.abi { + layout::Abi::Uninhabited => {} layout::Abi::Aggregate { .. } => { match a.layout.size.bits() { 8 => a.cast_to(Reg::i8()), diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index e0822b96eeb06dc0bfe6fe69d95a9fdfcc3f9c6b..25a35274d3233d036d476f0b08d1f42751b53dae 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -1130,43 +1130,38 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Vec { let adt = &self.enum_type.ty_adt_def().unwrap(); match self.layout.variants { - layout::Variants::Single { .. } => { - assert!(adt.variants.len() <= 1); - - if adt.variants.is_empty() { - vec![] - } else { - let (variant_type_metadata, member_description_factory) = - describe_enum_variant(cx, - self.layout, - &adt.variants[0], - NoDiscriminant, - self.containing_scope, - self.span); + layout::Variants::Single { .. } if adt.variants.is_empty() => vec![], + layout::Variants::Single { index } => { + let (variant_type_metadata, member_description_factory) = + describe_enum_variant(cx, + self.layout, + &adt.variants[index], + NoDiscriminant, + self.containing_scope, + self.span); - let member_descriptions = - member_description_factory.create_member_descriptions(cx); + let member_descriptions = + member_description_factory.create_member_descriptions(cx); - set_members_of_composite_type(cx, - variant_type_metadata, - &member_descriptions[..]); - vec![ - MemberDescription { - name: "".to_string(), - type_metadata: variant_type_metadata, - offset: Size::from_bytes(0), - size: self.layout.size, - align: self.layout.align, - flags: DIFlags::FlagZero - } - ] - } + set_members_of_composite_type(cx, + variant_type_metadata, + &member_descriptions[..]); + vec![ + MemberDescription { + name: "".to_string(), + type_metadata: variant_type_metadata, + offset: Size::from_bytes(0), + size: self.layout.size, + align: self.layout.align, + flags: DIFlags::FlagZero + } + ] } layout::Variants::Tagged { ref variants, .. } => { let discriminant_info = RegularDiscriminant(self.discriminant_type_metadata .expect("")); (0..variants.len()).map(|i| { - let variant = self.layout.for_variant(i); + let variant = self.layout.for_variant(cx, i); let (variant_type_metadata, member_desc_factory) = describe_enum_variant(cx, variant, @@ -1191,8 +1186,8 @@ fn create_member_descriptions<'a>(&self, cx: &CrateContext<'a, 'tcx>) } }).collect() } - layout::Variants::NicheFilling { dataful_variant, .. } => { - let variant = self.layout.for_variant(dataful_variant); + layout::Variants::NicheFilling { dataful_variant, niche_variant, .. } => { + let variant = self.layout.for_variant(cx, dataful_variant); // Create a description of the non-null variant let (variant_type_metadata, member_description_factory) = describe_enum_variant(cx, @@ -1236,7 +1231,7 @@ fn compute_field_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, self.layout, self.layout.fields.offset(0), self.layout.field(cx, 0).size); - name.push_str(&adt.variants[1 - dataful_variant].name.as_str()); + name.push_str(&adt.variants[niche_variant].name.as_str()); // Create the (singleton) list of descriptions of union members. vec![ diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs index 139c4c656db077832826eb67849f68a547d8494b..d1b6e9073b843114f0214ce5fab4df8dc480911c 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_trans/mir/block.rs @@ -710,7 +710,11 @@ fn trans_arguments_untupled(&mut self, Immediate(llval) => { for i in 0..tuple.layout.fields.count() { let field = tuple.layout.field(bcx.ccx, i); - let elem = bcx.extract_value(llval, tuple.layout.llvm_field_index(i)); + let elem = if field.is_zst() { + C_undef(field.llvm_type(bcx.ccx)) + } else { + bcx.extract_value(llval, tuple.layout.llvm_field_index(i)) + }; // If the tuple is immediate, the elements are as well let op = OperandRef { val: Immediate(base::to_immediate(bcx, elem, field)), diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 7e1569c8f8f5ee1dec53a22922b08aeeda9988c9..542893bd62b3918170cd91ebb44ff8ce61259bba 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -1099,6 +1099,11 @@ fn trans_const_adt<'a, 'tcx>( mir::AggregateKind::Adt(_, index, _, _) => index, _ => 0, }; + + if let layout::Abi::Uninhabited = l.abi { + return Const::new(C_undef(l.llvm_type(ccx)), t); + } + match l.variants { layout::Variants::Single { index } => { assert_eq!(variant_index, index); @@ -1114,7 +1119,6 @@ fn trans_const_adt<'a, 'tcx>( Const::new(C_struct(ccx, &contents, l.is_packed()), t) } else { - assert_eq!(variant_index, 0); build_const_struct(ccx, l, vals, None) } } @@ -1132,12 +1136,12 @@ fn trans_const_adt<'a, 'tcx>( Const::new(discr, t) } else { let discr = Const::new(discr, discr_field.ty); - build_const_struct(ccx, l.for_variant(variant_index), vals, Some(discr)) + build_const_struct(ccx, l.for_variant(ccx, variant_index), vals, Some(discr)) } } layout::Variants::NicheFilling { dataful_variant, niche_value, .. } => { if variant_index == dataful_variant { - build_const_struct(ccx, l.for_variant(dataful_variant), vals, None) + build_const_struct(ccx, l.for_variant(ccx, dataful_variant), vals, None) } else { let niche = l.field(ccx, 0); let niche_llty = niche.llvm_type(ccx); diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs index f9a179ee0eeca4fc8c3f76663c9e582a1d6d0db4..c6eb822ec876147866ca0fa14bfdd0ae2564e38b 100644 --- a/src/librustc_trans/mir/lvalue.rs +++ b/src/librustc_trans/mir/lvalue.rs @@ -115,7 +115,7 @@ pub fn len(&self, ccx: &CrateContext<'a, 'tcx>) -> ValueRef { assert_eq!(count, 0); self.llextra } else { - common::C_usize(ccx, count) + C_usize(ccx, count) } } else { bug!("unexpected layout `{:#?}` in LvalueRef::len", self.layout) @@ -304,7 +304,12 @@ pub fn trans_get_discr(self, bcx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> Valu }; bcx.intcast(lldiscr, cast_to, signed) } - layout::Variants::NicheFilling { dataful_variant, niche_value, .. } => { + layout::Variants::NicheFilling { + dataful_variant, + niche_variant, + niche_value, + .. + } => { let niche_llty = discr.layout.llvm_type(bcx.ccx); // FIXME(eddyb) Check the actual primitive type here. let niche_llval = if niche_value == 0 { @@ -313,8 +318,9 @@ pub fn trans_get_discr(self, bcx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> Valu } else { C_uint_big(niche_llty, niche_value) }; - let cmp = if dataful_variant == 0 { llvm::IntEQ } else { llvm::IntNE }; - bcx.intcast(bcx.icmp(cmp, lldiscr, niche_llval), cast_to, false) + bcx.select(bcx.icmp(llvm::IntEQ, lldiscr, niche_llval), + C_uint(cast_to, niche_variant as u64), + C_uint(cast_to, dataful_variant as u64)) } } } @@ -324,7 +330,12 @@ pub fn trans_get_discr(self, bcx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> Valu pub fn trans_set_discr(&self, bcx: &Builder<'a, 'tcx>, variant_index: usize) { match self.layout.variants { layout::Variants::Single { index } => { - assert_eq!(variant_index, index); + if index != variant_index { + // If the layout of an enum is `Single`, all + // other variants are necessarily uninhabited. + assert_eq!(self.layout.for_variant(bcx.ccx, variant_index).abi, + layout::Abi::Uninhabited); + } } layout::Variants::Tagged { .. } => { let ptr = self.project_field(bcx, 0); @@ -366,7 +377,7 @@ pub fn trans_set_discr(&self, bcx: &Builder<'a, 'tcx>, variant_index: usize) { pub fn project_index(&self, bcx: &Builder<'a, 'tcx>, llindex: ValueRef) -> LvalueRef<'tcx> { LvalueRef { - llval: bcx.inbounds_gep(self.llval, &[common::C_usize(bcx.ccx, 0), llindex]), + llval: bcx.inbounds_gep(self.llval, &[C_usize(bcx.ccx, 0), llindex]), llextra: ptr::null_mut(), layout: self.layout.field(bcx.ccx, 0), alignment: self.alignment @@ -376,7 +387,7 @@ pub fn project_index(&self, bcx: &Builder<'a, 'tcx>, llindex: ValueRef) pub fn project_downcast(&self, bcx: &Builder<'a, 'tcx>, variant_index: usize) -> LvalueRef<'tcx> { let mut downcast = *self; - downcast.layout = self.layout.for_variant(variant_index); + downcast.layout = self.layout.for_variant(bcx.ccx, variant_index); // Cast to the appropriate variant struct type. let variant_ty = downcast.layout.llvm_type(bcx.ccx); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index eab5cb159de39e86c57fa7dfa6fca8334ce94282..d2f9ca3546812b84094fe0ff772bfcc9e2ef5148 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -27,6 +27,7 @@ fn uncached_llvm_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, return Type::vector(&layout.field(ccx, 0).llvm_type(ccx), layout.fields.count() as u64); } + layout::Abi::Uninhabited | layout::Abi::Aggregate { .. } => {} } @@ -158,7 +159,9 @@ pub trait LayoutLlvmExt<'tcx> { impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { fn is_llvm_immediate(&self) -> bool { match self.abi { - layout::Abi::Scalar(_) | layout::Abi::Vector => true, + layout::Abi::Uninhabited | + layout::Abi::Scalar(_) | + layout::Abi::Vector => true, layout::Abi::Aggregate { .. } => self.is_zst() } @@ -230,7 +233,7 @@ fn llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Type { let llty = if self.ty != normal_ty { let mut layout = ccx.layout_of(normal_ty); if let Some(v) = variant_index { - layout = layout.for_variant(v); + layout = layout.for_variant(ccx, v); } layout.llvm_type(ccx) } else { diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs new file mode 100644 index 0000000000000000000000000000000000000000..69cc4c933601e0eb685346f9d29932e6e0179c01 --- /dev/null +++ b/src/test/ui/print_type_sizes/uninhabited.rs @@ -0,0 +1,18 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -Z print-type-sizes + +#![feature(never_type)] + +pub fn main() { + let _x: Option = None; + let _y: Result = Ok(42); +} diff --git a/src/test/ui/print_type_sizes/uninhabited.stdout b/src/test/ui/print_type_sizes/uninhabited.stdout new file mode 100644 index 0000000000000000000000000000000000000000..2a8706f7ac5514591adba5f5d323cb0b356b1116 --- /dev/null +++ b/src/test/ui/print_type_sizes/uninhabited.stdout @@ -0,0 +1,5 @@ +print-type-size type: `std::result::Result`: 4 bytes, alignment: 4 bytes +print-type-size variant `Ok`: 4 bytes +print-type-size field `.0`: 4 bytes +print-type-size type: `std::option::Option`: 0 bytes, alignment: 1 bytes +print-type-size variant `None`: 0 bytes