diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index a21e1aee9b08a..1871d7b84cdac 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -140,7 +140,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?; match &self.variants { - Variants::Single { .. } | Variants::Empty => {} + Variants::Single { .. } | Variants::Empty { .. } => {} Variants::Multiple { variants, .. } => { // Treat enum variants like union members. // HACK(eddyb) pretend the `enum` field (discriminant) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index c2405553756b9..9a7a97ced8fd5 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -130,7 +130,7 @@ impl LayoutCalculator { element.size.checked_mul(count, &self.cx).ok_or(LayoutCalculatorError::SizeOverflow)?; Ok(LayoutData { - variants: Variants::Single { index: VariantIdx::new(0) }, + variants: Variants::Single { index: VariantIdx::new(0), variants: None }, fields: FieldsShape::Array { stride: element.size, count }, backend_repr: BackendRepr::Memory { sized: count_if_sized.is_some() }, largest_niche: element.largest_niche.filter(|_| count != 0), @@ -181,7 +181,7 @@ impl LayoutCalculator { let size = size.align_to(align.abi); Ok(LayoutData { - variants: Variants::Single { index: VariantIdx::new(0) }, + variants: Variants::Single { index: VariantIdx::new(0), variants: None }, fields: FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), memory_index: [0].into(), @@ -197,6 +197,54 @@ impl LayoutCalculator { }) } + pub fn simd_type_for_scalar( + &self, + element: Scalar, + count: u64, + repr_packed: bool, + ) -> LayoutCalculatorResult { + let elt = element; + if count == 0 { + return Err(LayoutCalculatorError::ZeroLengthSimdType); + } else if count > crate::MAX_SIMD_LANES { + return Err(LayoutCalculatorError::OversizedSimdType { + max_lanes: crate::MAX_SIMD_LANES, + }); + } + + // Compute the size and alignment of the vector + let dl = self.cx.data_layout(); + let size = elt + .size(&self.cx) + .checked_mul(count, dl) + .ok_or_else(|| LayoutCalculatorError::SizeOverflow)?; + let (repr, align) = if repr_packed && !count.is_power_of_two() { + // Non-power-of-two vectors have padding up to the next power-of-two. + // If we're a packed repr, remove the padding while keeping the alignment as close + // to a vector as possible. + (BackendRepr::Memory { sized: true }, AbiAlign { abi: Align::max_aligned_factor(size) }) + } else { + (BackendRepr::SimdVector { element, count }, dl.llvmlike_vector_align(size)) + }; + let size = size.align_to(align.abi); + + Ok(LayoutData { + variants: Variants::Single { index: VariantIdx::new(0), variants: None }, + fields: FieldsShape::Arbitrary { + offsets: [Size::ZERO].into(), + memory_index: [0].into(), + }, + backend_repr: repr, + largest_niche: None, + uninhabited: false, + size, + align, + max_repr_align: None, + unadjusted_abi_align: elt.align(&self.cx).abi, + randomization_seed: (Hash64::new(count)), + }) + } + /// Compute the layout for a coroutine. /// /// This uses dedicated code instead of [`Self::layout_of_struct_or_enum`], as coroutine @@ -469,7 +517,7 @@ impl LayoutCalculator { .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed)); Ok(LayoutData { - variants: Variants::Single { index: only_variant_idx }, + variants: Variants::Single { index: only_variant_idx, variants: None }, fields: FieldsShape::Union(union_field_count), backend_repr, largest_niche: None, @@ -510,7 +558,7 @@ impl LayoutCalculator { }; let mut st = self.univariant(&variants[v], repr, kind)?; - st.variants = Variants::Single { index: v }; + st.variants = Variants::Single { index: v, variants: None }; if is_special_no_niche { let hide_niches = |scalar: &mut _| match scalar { @@ -594,23 +642,13 @@ impl LayoutCalculator { discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool), discriminants: impl Iterator, ) -> LayoutCalculatorResult { - // Until we've decided whether to use the tagged or - // niche filling LayoutData, we don't want to intern the - // variant layouts, so we can't store them in the - // overall LayoutData. Store the overall LayoutData - // and the variant LayoutDatas here until then. - struct TmpLayout { - layout: LayoutData, - variants: IndexVec>, - } - let dl = self.cx.data_layout(); // bail if the enum has an incoherent repr that cannot be computed if repr.packed() { return Err(LayoutCalculatorError::ReprConflict); } - let calculate_niche_filling_layout = || -> Option> { + let calculate_niche_filling_layout = || -> Option> { if repr.inhibit_enum_layout_opt() { return None; } @@ -627,7 +665,7 @@ impl LayoutCalculator { .iter_enumerated() .map(|(j, v)| { let mut st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?; - st.variants = Variants::Single { index: j }; + st.variants = Variants::Single { index: j, variants: None }; align = align.max(st.align); max_repr_align = max_repr_align.max(st.max_repr_align); @@ -746,7 +784,7 @@ impl LayoutCalculator { niche_start, }, tag_field: FieldIdx::new(0), - variants: IndexVec::new(), + variants: variant_layouts, }, fields: FieldsShape::Arbitrary { offsets: [niche_offset].into(), @@ -762,7 +800,7 @@ impl LayoutCalculator { randomization_seed: combined_seed, }; - Some(TmpLayout { layout, variants: variant_layouts }) + Some(layout) }; let niche_filling_layout = calculate_niche_filling_layout(); @@ -819,6 +857,9 @@ impl LayoutCalculator { }); trace!(?largest_niche); + let single_variant_layout_eligible = + !repr.inhibit_enum_layout_opt() && valid_discriminants.len() == 1; + // `max` is the last valid discriminant before the largest niche // `min` is the first valid discriminant after the largest niche let (max, min) = largest_niche @@ -851,15 +892,24 @@ impl LayoutCalculator { } // Create the set of structs that represent each variant. + let mut single_inhabited_variant_no_tag_layout = None; let mut layout_variants = variants .iter_enumerated() .map(|(i, field_layouts)| { - let mut st = self.univariant( - field_layouts, - repr, - StructKind::Prefixed(min_ity.size(), prefix_align), - )?; - st.variants = Variants::Single { index: i }; + let uninhabited = field_layouts.iter().any(|f| f.is_uninhabited()); + if !uninhabited && single_variant_layout_eligible { + single_inhabited_variant_no_tag_layout = + Some((i, self.univariant(field_layouts, repr, StructKind::AlwaysSized))); + } + // We don't need to encode the tag in uninhabited variants in repr(Rust) enums + let struct_kind = if uninhabited && !repr.inhibit_enum_layout_opt() { + StructKind::AlwaysSized + } else { + StructKind::Prefixed(min_ity.size(), prefix_align) + }; + let mut st = self.univariant(field_layouts, repr, struct_kind)?; + + st.variants = Variants::Single { index: i, variants: None }; // Find the first field we can't move later // to make room for a larger discriminant. for field_idx in st.fields.index_by_increasing_offset() { @@ -877,6 +927,72 @@ impl LayoutCalculator { }) .collect::, _>>()?; + // If there is a single uninhabited variant, we can use it mostly unchanged as the layout, + // without using a tag or niche. + // + // We do still need to modify it to make all the uninhabited variants fit so they + // can be partially-initialized. + // + // FIXME: We shouldn't assume this is better than the tagged layout; it's worse for + // `enum Foo { A, B(i32, !) }` because it has no niche. + let no_tag_layout = if single_variant_layout_eligible + && let Some((single_inhabited_variant_idx, Ok(mut st))) = + single_inhabited_variant_no_tag_layout + { + // Keep track of original variant layouts (including the inhabited one) + // for `offset_of!`. + let mut variants = layout_variants.clone(); + variants[single_inhabited_variant_idx] = st.clone(); + + // We know that every other variant is uninhabited, and thus does not have a + // prefix for the tag, so we can use them to find the necessary size. + for (idx, layout) in layout_variants.iter_enumerated() { + if idx != single_inhabited_variant_idx { + st.size = cmp::max(st.size, layout.size); + st.align = st.align.max(layout.align); + st.max_repr_align = st.max_repr_align.max(layout.max_repr_align); + st.unadjusted_abi_align = + st.unadjusted_abi_align.max(layout.unadjusted_abi_align); + } + } + + // Align the maximum variant size to the largest alignment. + st.size = st.size.align_to(st.align.abi); + + // If the inhabited variant's layout would use a non-Memory BackendRepr, + // but we made it bigger or more-aligned due to uninhabited variants, + // force it to be BackendRepr::Memory + match st.backend_repr { + BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..) => { + if st.backend_repr.scalar_size(&self.cx) != Some(st.size) + || st.backend_repr.scalar_align(&self.cx) != Some(st.align.abi) + { + st.backend_repr = BackendRepr::Memory { sized: true } + } + } + BackendRepr::SimdVector { element, count } => { + // FIXME: is there a better way to do this than making a copy of + // `LayoutCalculator::simd_type` *just* for this? + let vector_layout = self.simd_type_for_scalar::( + element, + count, + repr.packed(), + )?; + if vector_layout.size != st.size || vector_layout.align != st.align { + st.backend_repr = BackendRepr::Memory { sized: true } + } + } + BackendRepr::Memory { .. } => {} + } + + st.variants = + Variants::Single { index: single_inhabited_variant_idx, variants: Some(variants) }; + + Some(st) + } else { + None + }; + // Align the maximum variant size to the largest alignment. size = size.align_to(align.abi); @@ -928,6 +1044,11 @@ impl LayoutCalculator { let old_ity_size = min_ity.size(); let new_ity_size = ity.size(); for variant in &mut layout_variants { + // Don't change field offsets of uninhabited variants in repr(Rust) enums, + // they don't encode the tag and their fields may overlap with the tag. + if variant.is_uninhabited() && !repr.inhibit_enum_layout_opt() { + continue; + } match variant.fields { FieldsShape::Arbitrary { ref mut offsets, .. } => { for i in offsets { @@ -972,6 +1093,12 @@ impl LayoutCalculator { let FieldsShape::Arbitrary { ref offsets, .. } = layout_variant.fields else { panic!("encountered a non-arbitrary layout during enum layout"); }; + // Don't look in uninhabited variants for repr(Rust) enums, they will never be + // passed over an ABI so they don't matter for the purpose of determining + // BackendRepr. + if layout_variant.is_uninhabited() && !repr.inhibit_enum_layout_opt() { + continue; + } // We skip *all* ZST here and later check if we are good in terms of alignment. // This lets us handle some cases involving aligned ZST. let mut fields = iter::zip(field_layouts, offsets).filter(|p| !p.0.is_zst()); @@ -1088,12 +1215,49 @@ impl LayoutCalculator { .map(|v| v.randomization_seed) .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed)); + // If all variants are uninhabited, the repr does not inhibit layout optimizations, + // and all fields are ZSTs, then the tagged layout will not have room for the tag. + // So in this case, we return an uninhabited layout that is big enough and aligned + // enough for all variant fields, but do not say it has any fields itself. + // Doing this only when the layout is too small to fit the tag gives better error + // messages during const-eval in some cases, "constructing invalid value at .: + // encountered an uninhabited enum variant" instead of "constructing invalid value: + // encountered a value of uninhabited type". + // Note the we only reach this case when there is at least one non-1-aligned ZST field, + // since the all-1-ZST case is handled by the "present_variants" check in + // `layout_of_struct_or_enum`. + if uninhabited && size < tag.size(&self.cx) { + // The only way for the size to be less than the tag's size is for it to be zero, + // which can only occur when the repr does not inhibit layout optimization. + debug_assert!( + size == Size::ZERO, + "size was non-zero but less than tag size: 0 < {size:?} < {:?}", + tag.size(&self.cx) + ); + debug_assert!( + !repr.inhibit_enum_layout_opt(), + "enum size was zero with layout optimizations disabled" + ); + return Ok(LayoutData { + fields: FieldsShape::Arbitrary { offsets: [].into(), memory_index: [].into() }, + variants: Variants::Empty { variants: Some(layout_variants) }, + backend_repr: BackendRepr::Memory { sized: true }, + largest_niche: None, + uninhabited: true, + align, + size, + max_repr_align, + unadjusted_abi_align, + randomization_seed: combined_seed, + }); + } + let tagged_layout = LayoutData { variants: Variants::Multiple { tag, tag_encoding: TagEncoding::Direct, tag_field: FieldIdx::new(0), - variants: IndexVec::new(), + variants: layout_variants, }, fields: FieldsShape::Arbitrary { offsets: [Size::ZERO].into(), @@ -1109,36 +1273,39 @@ impl LayoutCalculator { randomization_seed: combined_seed, }; - let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants }; + // Pick the smallest layout; otherwise, + // pick the layout with the largest niche; otherwise, + // pick no_tag as it has simpler codegen than tagged and niched; otherwise, + // pick tagged as it has simpler codegen than niched. - let mut best_layout = match (tagged_layout, niche_filling_layout) { - (tl, Some(nl)) => { - // Pick the smaller layout; otherwise, - // pick the layout with the larger niche; otherwise, - // pick tagged as it has simpler codegen. + let better_layout_or_first = + |l1: LayoutData, l2: LayoutData| { use cmp::Ordering::*; - let niche_size = |tmp_l: &TmpLayout| { - tmp_l.layout.largest_niche.map_or(0, |n| n.available(dl)) + let niche_size = |l: &LayoutData| { + l.largest_niche.map_or(0, |n| n.available(dl)) }; - match (tl.layout.size.cmp(&nl.layout.size), niche_size(&tl).cmp(&niche_size(&nl))) { - (Greater, _) => nl, - (Equal, Less) => nl, - _ => tl, + match (l1.size.cmp(&l2.size), niche_size(&l1).cmp(&niche_size(&l2))) { + (Greater, _) => l2, + (Equal, Less) => l2, + _ => l1, } - } - (tl, None) => tl, + }; + + let best_layout = match niche_filling_layout { + None => tagged_layout, + // Prefer tagged over niched if they have the same size and niche size, + // as the tagged layout has simpler codegen. + Some(niched_layout) => better_layout_or_first(tagged_layout, niched_layout), }; - // Now we can intern the variant layouts and store them in the enum layout. - best_layout.layout.variants = match best_layout.layout.variants { - Variants::Multiple { tag, tag_encoding, tag_field, .. } => { - Variants::Multiple { tag, tag_encoding, tag_field, variants: best_layout.variants } - } - Variants::Single { .. } | Variants::Empty => { - panic!("encountered a single-variant or empty enum during multi-variant layout") - } + let best_layout = match no_tag_layout { + None => best_layout, + // Prefer no-tag over tagged/niched if they have the same size and niche size, + // as the no-tag layout has simpler codegen. + Some(no_tag_layout) => better_layout_or_first(no_tag_layout, best_layout), }; - Ok(best_layout.layout) + + Ok(best_layout) } fn univariant_biased< @@ -1481,7 +1648,7 @@ impl LayoutCalculator { let seed = field_seed.wrapping_add(repr.field_shuffle_seed); Ok(LayoutData { - variants: Variants::Single { index: VariantIdx::new(0) }, + variants: Variants::Single { index: VariantIdx::new(0), variants: None }, fields: FieldsShape::Arbitrary { offsets, memory_index }, backend_repr: abi, largest_niche, diff --git a/compiler/rustc_abi/src/layout/coroutine.rs b/compiler/rustc_abi/src/layout/coroutine.rs index 2b22276d4aed7..c0aa31514016f 100644 --- a/compiler/rustc_abi/src/layout/coroutine.rs +++ b/compiler/rustc_abi/src/layout/coroutine.rs @@ -234,7 +234,7 @@ pub(super) fn layout< &ReprOptions::default(), StructKind::Prefixed(prefix_size, prefix_align.abi), )?; - variant.variants = Variants::Single { index }; + variant.variants = Variants::Single { index, variants: None }; let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else { unreachable!(); diff --git a/compiler/rustc_abi/src/layout/simple.rs b/compiler/rustc_abi/src/layout/simple.rs index 0d0706defc2e5..0aa35f9f97289 100644 --- a/compiler/rustc_abi/src/layout/simple.rs +++ b/compiler/rustc_abi/src/layout/simple.rs @@ -12,7 +12,7 @@ impl LayoutData { pub fn unit(cx: &C, sized: bool) -> Self { let dl = cx.data_layout(); LayoutData { - variants: Variants::Single { index: VariantIdx::new(0) }, + variants: Variants::Single { index: VariantIdx::new(0), variants: None }, fields: FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new(), @@ -32,7 +32,7 @@ impl LayoutData { let dl = cx.data_layout(); // This is also used for uninhabited enums, so we use `Variants::Empty`. LayoutData { - variants: Variants::Empty, + variants: Variants::Empty { variants: None }, fields: FieldsShape::Primitive, backend_repr: BackendRepr::Memory { sized: true }, largest_niche: None, @@ -74,7 +74,7 @@ impl LayoutData { .wrapping_add((range.end as u64).rotate_right(16)); LayoutData { - variants: Variants::Single { index: VariantIdx::new(0) }, + variants: Variants::Single { index: VariantIdx::new(0), variants: None }, fields: FieldsShape::Primitive, backend_repr: BackendRepr::Scalar(scalar), largest_niche, @@ -104,7 +104,7 @@ impl LayoutData { let combined_seed = a.size(dl).bytes().wrapping_add(b.size(dl).bytes()); LayoutData { - variants: Variants::Single { index: VariantIdx::new(0) }, + variants: Variants::Single { index: VariantIdx::new(0), variants: None }, fields: FieldsShape::Arbitrary { offsets: [Size::ZERO, b_offset].into(), memory_index: [0, 1].into(), @@ -120,14 +120,14 @@ impl LayoutData { } } - /// Returns a dummy layout for an uninhabited variant. + /// Returns a dummy layout for an absent variant. /// - /// Uninhabited variants get pruned as part of the layout calculation, + /// Absent variants get pruned as part of the layout calculation, /// so this can be used after the fact to reconstitute a layout. - pub fn uninhabited_variant(cx: &C, index: VariantIdx, fields: usize) -> Self { + pub fn absent_variant(cx: &C, index: VariantIdx, fields: usize) -> Self { let dl = cx.data_layout(); LayoutData { - variants: Variants::Single { index }, + variants: Variants::Single { index, variants: None }, fields: match NonZero::new(fields) { Some(fields) => FieldsShape::Union(fields), None => FieldsShape::Arbitrary { diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 14e256b8045df..e2add276bf06f 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1852,12 +1852,27 @@ impl BackendRepr { #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] pub enum Variants { /// A type with no valid variants. Must be uninhabited. - Empty, + /// + /// We still need to hold variant layout information for `offset_of!` + /// on uninhabited enum variants with non-zero-sized fields. + Empty { + /// Always `None` for non-enums. + /// For enums, this is `None` if all variants are "absent" + /// (have no non-1-ZST fields), and is `Some` otherwise. + variants: Option>>, + }, - /// Single enum variants, structs/tuples, unions, and all non-ADTs. + /// Enums with one inhabited variant and no tag, structs/tuples, unions, and all non-ADTs. + /// + /// We still need to hold variant layout information for `offset_of!` + /// on uninhabited enum variants with non-zero-sized fields. Single { /// Always `0` for types that cannot have multiple variants. index: VariantIdx, + /// Always `None` for non-enums. + /// For enums, this is `None` if all uninhabited variants are "absent" + /// (have no non-1-ZST fields), and is `Some` otherwise. + variants: Option>>, }, /// Enum-likes with more than one variant: each variant comes with diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs index a08b0e0cbfc59..86e4e03f97345 100644 --- a/compiler/rustc_codegen_cranelift/src/discriminant.rs +++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs @@ -18,8 +18,8 @@ pub(crate) fn codegen_set_discriminant<'tcx>( return; } match layout.variants { - Variants::Empty => unreachable!("we already handled uninhabited types"), - Variants::Single { index } => { + Variants::Empty { .. } => unreachable!("we already handled uninhabited types"), + Variants::Single { index, .. } => { assert_eq!(index, variant_index); } Variants::Multiple { @@ -86,8 +86,8 @@ pub(crate) fn codegen_get_discriminant<'tcx>( } let (tag_scalar, tag_field, tag_encoding) = match &layout.variants { - Variants::Empty => unreachable!("we already handled uninhabited types"), - Variants::Single { index } => { + Variants::Empty { .. } => unreachable!("we already handled uninhabited types"), + Variants::Single { index, .. } => { let discr_val = layout .ty .discriminant_for_variant(fx.tcx, *index) diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs index 093f902bc3d86..dbcd6dddf5b90 100644 --- a/compiler/rustc_codegen_gcc/src/type_of.rs +++ b/compiler/rustc_codegen_gcc/src/type_of.rs @@ -100,14 +100,14 @@ fn uncached_gcc_type<'gcc, 'tcx>( if !cx.sess().fewer_names() => { let mut name = with_no_trimmed_paths!(layout.ty.to_string()); - if let (&ty::Adt(def, _), &Variants::Single { index }) = + if let (&ty::Adt(def, _), &Variants::Single { index, .. }) = (layout.ty.kind(), &layout.variants) && def.is_enum() && !def.variants().is_empty() { write!(&mut name, "::{}", def.variant(index).name).unwrap(); } - if let (&ty::Coroutine(_, _), &Variants::Single { index }) = + if let (&ty::Coroutine(_, _), &Variants::Single { index, .. }) = (layout.ty.kind(), &layout.variants) { write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap(); @@ -228,7 +228,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> { // Check the cache. let variant_index = match self.variants { - Variants::Single { index } => Some(index), + Variants::Single { index, .. } => Some(index), _ => None, }; let cached_type = cx.types.borrow().get(&(self.ty, variant_index)).cloned(); diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index a5c808957410e..ada243dc53031 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -213,11 +213,11 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( ), |cx, enum_type_di_node| { match enum_type_and_layout.variants { - Variants::Empty => { + Variants::Empty { .. } => { // We don't generate any members for uninhabited types. return smallvec![]; } - Variants::Single { index: variant_index } => build_single_variant_union_fields( + Variants::Single { index: variant_index, .. } => build_single_variant_union_fields( cx, enum_adt_def, enum_type_and_layout, @@ -300,7 +300,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>( ) } Variants::Single { .. } - | Variants::Empty + | Variants::Empty { .. } | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => { bug!( "Encountered coroutine with non-direct-tag layout: {:?}", diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 7c701926d2c5e..175a30c69733d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -392,7 +392,7 @@ fn compute_discriminant_value<'ll, 'tcx>( variant_index: VariantIdx, ) -> DiscrResult { match enum_type_and_layout.layout.variants() { - &Variants::Single { .. } | &Variants::Empty => DiscrResult::NoDiscriminant, + &Variants::Single { .. } | &Variants::Empty { .. } => DiscrResult::NoDiscriminant, &Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => DiscrResult::Value( enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val, ), diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 62d38d463aba7..c934996942f70 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -357,7 +357,7 @@ fn build_discr_member_di_node<'ll, 'tcx>( match enum_or_coroutine_type_and_layout.layout.variants() { // A single-variant or no-variant enum has no discriminant. - &Variants::Single { .. } | &Variants::Empty => None, + &Variants::Single { .. } | &Variants::Empty { .. } => None, &Variants::Multiple { tag_field, .. } => { let tag_base_type = tag_base_type(cx.tcx, enum_or_coroutine_type_and_layout); diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 4e7096da502d0..1677cf13b1e48 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -35,14 +35,14 @@ fn uncached_llvm_type<'a, 'tcx>( if !cx.sess().fewer_names() => { let mut name = with_no_visible_paths!(with_no_trimmed_paths!(layout.ty.to_string())); - if let (&ty::Adt(def, _), &Variants::Single { index }) = + if let (&ty::Adt(def, _), &Variants::Single { index, .. }) = (layout.ty.kind(), &layout.variants) { if def.is_enum() { write!(&mut name, "::{}", def.variant(index).name).unwrap(); } } - if let (&ty::Coroutine(_, _), &Variants::Single { index }) = + if let (&ty::Coroutine(_, _), &Variants::Single { index, .. }) = (layout.ty.kind(), &layout.variants) { write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap(); @@ -213,7 +213,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // Check the cache. let variant_index = match self.variants { - Variants::Single { index } => Some(index), + Variants::Single { index, .. } => Some(index), _ => None, }; if let Some(llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) { diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs index 7c62c03d574c1..83a293c2a2deb 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs @@ -66,7 +66,7 @@ fn tag_base_type_opt<'tcx>( match enum_type_and_layout.layout.variants() { // A single-variant or no-variant enum has no discriminant. - Variants::Single { .. } | Variants::Empty => None, + Variants::Single { .. } | Variants::Empty { .. } => None, Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => { // Niche tags are always normalized to unsized integers of the correct size. diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs index c2c023af090a5..25b67a2633699 100644 --- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -144,7 +144,7 @@ impl<'a, 'b, 'tcx, Bx: BuilderMethods<'b, 'tcx>> LocalAnalyzer<'a, 'b, 'tcx, Bx> layout = match *elem { mir::PlaceElem::Field(fidx, ..) => layout.field(self.fx.cx, fidx.as_usize()), mir::PlaceElem::Downcast(_, vidx) - if let abi::Variants::Single { index: single_variant } = + if let abi::Variants::Single { index: single_variant, .. } = layout.variants && vidx == single_variant => { diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index d851c3329802c..ece02810492fe 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -404,8 +404,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants { - Variants::Empty => unreachable!("we already handled uninhabited types"), - Variants::Single { index } => { + Variants::Empty { .. } => unreachable!("we already handled uninhabited types"), + Variants::Single { index, .. } => { let discr_val = if let Some(discr) = self.layout.ty.discriminant_for_variant(bx.tcx(), index) { discr.val @@ -949,10 +949,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { o = o.extract_field(self, bx, f.index()); } mir::PlaceElem::Downcast(_, vidx) => { - debug_assert_eq!( - o.layout.variants, - abi::Variants::Single { index: vidx }, - ); + if cfg!(debug_assertions) { + match o.layout.variants { + abi::Variants::Single { index, .. } if index == vidx => {} + ref v => bug!( + "expected Variants::Single {{ index: {vidx:?}, .. }}, got {v:?}" + ), + } + } let layout = o.layout.for_variant(bx.cx(), vidx); o = OperandRef { val: o.val, layout } } diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 0090be9fdef06..5de28b002ce1e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -459,8 +459,8 @@ pub(super) fn codegen_tag_value<'tcx, V>( } Ok(match layout.variants { - Variants::Empty => unreachable!("we already handled uninhabited types"), - Variants::Single { index } => { + Variants::Empty { .. } => unreachable!("we already handled uninhabited types"), + Variants::Single { index, .. } => { assert_eq!(index, variant_index); None } diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index b7e7f65c95c78..6e97684380609 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -65,10 +65,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // We use "tag" to refer to how the discriminant is encoded in memory, which can be either // straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`). let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout().variants { - Variants::Empty => { + Variants::Empty { .. } => { throw_ub!(UninhabitedEnumVariantRead(None)); } - Variants::Single { index } => { + Variants::Single { index, .. } => { if op.layout().is_uninhabited() { // For consistency with `write_discriminant`, and to make sure that // `project_downcast` cannot fail due to strange layouts, we declare immediate UB @@ -241,7 +241,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } match layout.variants { - abi::Variants::Empty => unreachable!("we already handled uninhabited types"), + abi::Variants::Empty { .. } => unreachable!("we already handled uninhabited types"), abi::Variants::Single { .. } => { // The tag of a `Single` enum is like the tag of the niched // variant: there's no tag as the discriminant is encoded diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index ab0c0665d511c..568c8e8543a03 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -303,7 +303,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { }; } } - Variants::Single { .. } | Variants::Empty => {} + Variants::Single { .. } | Variants::Empty { .. } => {} } // Now we know we are projecting to a field, so figure out which one. @@ -341,11 +341,11 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { ty::Adt(def, ..) if def.is_enum() => { // we might be projecting *to* a variant, or to a field *in* a variant. match layout.variants { - Variants::Single { index } => { + Variants::Single { index, .. } => { // Inside a variant PathElem::Field(def.variant(index).fields[FieldIdx::from_usize(field)].name) } - Variants::Empty => panic!("there is no field in Variants::Empty types"), + Variants::Empty { .. } => panic!("there is no field in Variants::Empty types"), Variants::Multiple { .. } => bug!("we handled variants above"), } } @@ -1020,7 +1020,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } // Don't forget potential other variants. match &layout.variants { - Variants::Single { .. } | Variants::Empty => { + Variants::Single { .. } | Variants::Empty { .. } => { // Fully handled above. } Variants::Multiple { variants, .. } => { diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 82c50fac6c0ee..01729eda5575a 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -200,7 +200,7 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { self.visit_variant(v, idx, &inner)?; } // For single-variant layouts, we already did everything there is to do. - Variants::Single { .. } | Variants::Empty => {} + Variants::Single { .. } | Variants::Empty { .. } => {} } interp_ok(()) diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index b1f2959875051..3c8f2dd440268 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -157,7 +157,7 @@ fn check_validity_requirement_lax<'tcx>( } match &this.variants { - Variants::Empty => return Ok(false), + Variants::Empty { .. } => return Ok(false), Variants::Single { .. } => { // All fields of this single variant have already been checked above, there is nothing // else to do. diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index aed94f9aa04d8..9d327db1911b7 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -741,14 +741,17 @@ where ) -> TyAndLayout<'tcx> { let layout = match this.variants { // If all variants but one are uninhabited, the variant layout is the enum layout. - Variants::Single { index } if index == variant_index => { + Variants::Single { index, .. } if index == variant_index => { return this; } - Variants::Single { .. } | Variants::Empty => { + Variants::Single { variants: None, .. } | Variants::Empty { variants: None } => { // Single-variant and no-variant enums *can* have other variants, but those are - // uninhabited. Produce a layout that has the right fields for that variant, so that - // the rest of the compiler can project fields etc as usual. + // uninhabited. For such enums, `variants` will only be `None` if all such + // variants are "absent", i.e. only consist of 1-ZSTs. + // (If any is not absent, then `variants` would be `Some` and we'd not be here.) + // Produce a layout that has the right fields for that variant, all at offset 0, + // so that the rest of the compiler can project fields etc as usual. let tcx = cx.tcx(); let typing_env = cx.typing_env(); @@ -765,15 +768,17 @@ where ty::Adt(def, _) => def.variant(variant_index).fields.len(), _ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty), }; - tcx.mk_layout(LayoutData::uninhabited_variant(cx, variant_index, fields)) + tcx.mk_layout(LayoutData::absent_variant(cx, variant_index, fields)) } - Variants::Multiple { ref variants, .. } => { + Variants::Single { variants: Some(ref variants), .. } + | Variants::Empty { variants: Some(ref variants) } + | Variants::Multiple { ref variants, .. } => { cx.tcx().mk_layout(variants[variant_index].clone()) } }; - assert_eq!(*layout.variants(), Variants::Single { index: variant_index }); + assert_eq!(*layout.variants(), Variants::Single { index: variant_index, variants: None }); TyAndLayout { ty: this.ty, layout } } @@ -910,8 +915,8 @@ where ), ty::Coroutine(def_id, args) => match this.variants { - Variants::Empty => unreachable!(), - Variants::Single { index } => TyMaybeWithLayout::Ty( + Variants::Empty { .. } => unreachable!(), + Variants::Single { index, .. } => TyMaybeWithLayout::Ty( args.as_coroutine() .state_tys(def_id, tcx) .nth(index.as_usize()) @@ -932,11 +937,13 @@ where // ADTs. ty::Adt(def, args) => { match this.variants { - Variants::Single { index } => { + Variants::Single { index, .. } => { let field = &def.variant(index).fields[FieldIdx::from_usize(i)]; TyMaybeWithLayout::Ty(field.ty(tcx, args)) } - Variants::Empty => panic!("there is no field in Variants::Empty types"), + Variants::Empty { .. } => { + panic!("there is no field in Variants::Empty types") + } // Discriminant field for enums (where applicable). Variants::Multiple { tag, .. } => { diff --git a/compiler/rustc_mir_transform/src/check_enums.rs b/compiler/rustc_mir_transform/src/check_enums.rs index 33a87cb987306..a2ddb98bc504d 100644 --- a/compiler/rustc_mir_transform/src/check_enums.rs +++ b/compiler/rustc_mir_transform/src/check_enums.rs @@ -171,10 +171,10 @@ impl<'a, 'tcx> Visitor<'tcx> for EnumFinder<'a, 'tcx> { }; match enum_layout.variants { - Variants::Empty if op_layout.is_uninhabited() => return, + Variants::Empty { .. } if op_layout.is_uninhabited() => return, // An empty enum that tries to be constructed from an inhabited value, this // is never correct. - Variants::Empty => { + Variants::Empty { .. } => { // The enum layout is uninhabited but we construct it from sth inhabited. // This is always UB. self.enums.push(EnumCheckType::Uninhabited); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 952da2cdf7253..ba2b27e9aa8b2 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1529,7 +1529,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { variant: VariantIdx, ) -> Option<(FieldIdx, Ty<'tcx>)> { if let Ok(layout) = self.ecx.layout_of(ty) - && let abi::Variants::Single { index } = layout.variants + && let abi::Variants::Single { index, .. } = layout.variants && index == variant && let Some((field_idx, field_layout)) = layout.non_1zst_field(&self.ecx) && layout.size == field_layout.size diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index 1a91d6bd7da98..7bbf00e7c73ad 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -182,7 +182,7 @@ impl EnumSizeOpt { }; let layout = tcx.layout_of(typing_env.as_query_input(ty)).ok()?; let variants = match &layout.variants { - Variants::Single { .. } | Variants::Empty => return None, + Variants::Single { .. } | Variants::Empty { .. } => return None, Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => return None, Variants::Multiple { variants, .. } if variants.len() <= 1 => return None, diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs index 6ccec5b6f2129..95cfc8d9ddd59 100644 --- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs @@ -55,11 +55,11 @@ fn variant_discriminants<'tcx>( tcx: TyCtxt<'tcx>, ) -> FxHashSet { match &layout.variants { - Variants::Empty => { + Variants::Empty { .. } => { // Uninhabited, no valid discriminant. FxHashSet::default() } - Variants::Single { index } => { + Variants::Single { index, .. } => { let mut res = FxHashSet::default(); res.insert( ty.discriminant_for_variant(tcx, *index) diff --git a/compiler/rustc_public/src/abi.rs b/compiler/rustc_public/src/abi.rs index 7b0882caf1b3e..7f7d61ccbde49 100644 --- a/compiler/rustc_public/src/abi.rs +++ b/compiler/rustc_public/src/abi.rs @@ -181,10 +181,27 @@ impl FieldsShape { #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum VariantsShape { /// A type with no valid variants. Must be uninhabited. - Empty, + /// + /// We still need to hold variant layout information for `offset_of!` + /// on uninhabited enum variants with non-zero-sized fields. + Empty { + /// Always `None` for non-enums. + /// For enums, this is `None` if all variants are "absent" + /// (have no non-1-ZST fields), and is `Some` otherwise. + variants: Option>, + }, /// Single enum variants, structs/tuples, unions, and all non-ADTs. - Single { index: VariantIdx }, + /// + /// We still need to hold variant layout information for `offset_of!` + /// on uninhabited enum variants with non-zero-sized fields. + Single { + index: VariantIdx, + /// Always `None` for non-enums. + /// For enums, this is `None` if all uninhabited variants are "absent" + /// (have no non-1-ZST fields), and is `Some` otherwise. + variants: Option>, + }, /// Enum-likes with more than one inhabited variant: each variant comes with /// a *discriminant* (usually the same as the variant index but the user can diff --git a/compiler/rustc_public/src/unstable/convert/stable/abi.rs b/compiler/rustc_public/src/unstable/convert/stable/abi.rs index 782e75a930e07..101c3437aa571 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/abi.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/abi.rs @@ -203,10 +203,13 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Variants, ) -> Self::T { match self { - rustc_abi::Variants::Single { index } => { - VariantsShape::Single { index: index.stable(tables, cx) } - } - rustc_abi::Variants::Empty => VariantsShape::Empty, + rustc_abi::Variants::Single { index, variants } => VariantsShape::Single { + index: index.stable(tables, cx), + variants: variants.as_ref().map(|v| v.iter().as_slice().stable(tables, cx)), + }, + rustc_abi::Variants::Empty { variants } => VariantsShape::Empty { + variants: variants.as_ref().map(|v| v.iter().as_slice().stable(tables, cx)), + }, rustc_abi::Variants::Multiple { tag, tag_encoding, tag_field, variants } => { VariantsShape::Multiple { tag: tag.stable(tables, cx), diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index d567ad401bb1f..1e7519988e3ce 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -117,7 +117,7 @@ where FieldsShape::Arbitrary { .. } => { match arg_layout.variants { Variants::Multiple { .. } => return Err(CannotUseFpConv), - Variants::Single { .. } | Variants::Empty => (), + Variants::Single { .. } | Variants::Empty { .. } => (), } for i in arg_layout.fields.index_by_increasing_offset() { let field = arg_layout.field(cx, i); diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index 161e2c1645f9a..4313651bfab08 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -130,7 +130,7 @@ where FieldsShape::Arbitrary { .. } => { match arg_layout.variants { Variants::Multiple { .. } => return Err(CannotUseFpConv), - Variants::Single { .. } | Variants::Empty => (), + Variants::Single { .. } | Variants::Empty { .. } => (), } for i in arg_layout.fields.index_by_increasing_offset() { let field = arg_layout.field(cx, i); diff --git a/compiler/rustc_target/src/callconv/x86_64.rs b/compiler/rustc_target/src/callconv/x86_64.rs index d8db7ed6e4c0f..43a8d389f7d8b 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -66,7 +66,7 @@ where } match &layout.variants { - Variants::Single { .. } | Variants::Empty => {} + Variants::Single { .. } | Variants::Empty { .. } => {} Variants::Multiple { variants, .. } => { // Treat enum variants like union members. for variant_idx in variants.indices() { diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 3f83b4d50aad5..d2e16ce98bc63 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -446,8 +446,8 @@ pub(crate) mod rustc { }; match layout.variants() { - Variants::Empty => Ok(Self::uninhabited()), - Variants::Single { index } => { + Variants::Empty { .. } => Ok(Self::uninhabited()), + Variants::Single { index, .. } => { // `Variants::Single` on enums with variants denotes that // the enum delegates its layout to the variant at `index`. layout_of_variant(*index, None) @@ -609,11 +609,11 @@ pub(crate) mod rustc { match ty.kind() { ty::Adt(def, args) => { match layout.variants { - Variants::Single { index } => { + Variants::Single { index, .. } => { let field = &def.variant(index).fields[i]; field.ty(cx.tcx(), args) } - Variants::Empty => panic!("there is no field in Variants::Empty types"), + Variants::Empty { .. } => panic!("there is no field in Variants::Empty types"), // Discriminant field for enums (where applicable). Variants::Multiple { tag, .. } => { assert_eq!(i.as_usize(), 0); diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 79f7e228e2adc..c958bdd06b901 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -791,9 +791,10 @@ fn variant_info_for_adt<'tcx>( }; match layout.variants { - Variants::Empty => (vec![], None), + // FIXME: handle uninhabited non-absent enum variants. + Variants::Empty { .. } => (vec![], None), - Variants::Single { index } => { + Variants::Single { index, .. } => { debug!("print-type-size `{:#?}` variant {}", layout, adt_def.variant(index).name); let variant_def = &adt_def.variant(index); let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect(); diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 1311ee31182c6..3779953c09566 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -255,10 +255,10 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou check_layout_abi(cx, layout); match &layout.variants { - Variants::Empty => { + Variants::Empty { .. } => { assert!(layout.is_uninhabited()); } - Variants::Single { index } => { + Variants::Single { index, .. } => { if let Some(variants) = layout.ty.variant_range(tcx) { assert!(variants.contains(index)); } else { diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index a8e2151afe610..c7f42d31ca82a 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -613,7 +613,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `UnsafeCell` action. (self.unsafe_cell_action)(v) } - Variants::Single { .. } | Variants::Empty => { + Variants::Single { .. } | Variants::Empty { .. } => { // Proceed further, try to find where exactly that `UnsafeCell` // is hiding. self.walk_value(v) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index dfb8ae704b996..13596518ddd34 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -805,7 +805,7 @@ impl Evaluator<'_> { ProjectionElem::Field(Either::Left(f)) => { let layout = self.layout(&prev_ty)?; let variant_layout = match &layout.variants { - Variants::Single { .. } | Variants::Empty => &layout, + Variants::Single { .. } | Variants::Empty { .. } => &layout, Variants::Multiple { variants, .. } => { &variants[match f.parent { hir_def::VariantId::EnumVariantId(it) => { @@ -1628,8 +1628,8 @@ impl Evaluator<'_> { return Ok(0); }; match &layout.variants { - Variants::Empty => unreachable!(), - Variants::Single { index } => { + Variants::Empty { .. } => unreachable!(), + Variants::Single { index, .. } => { let r = self.const_eval_discriminant(e.enum_variants(self.db).variants[index.0].0)?; Ok(r) @@ -1790,7 +1790,7 @@ impl Evaluator<'_> { } let layout = self.layout_adt(adt, subst)?; Ok(match &layout.variants { - Variants::Single { .. } | Variants::Empty => (layout.size.bytes_usize(), layout, None), + Variants::Single { .. } | Variants::Empty { .. } => (layout.size.bytes_usize(), layout, None), Variants::Multiple { variants, tag, tag_encoding, .. } => { let enum_variant_id = match it { VariantId::EnumVariantId(it) => it, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 209ec7926e825..38ed6b3b67b4b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -354,8 +354,8 @@ pub(crate) fn detect_variant_from_bytes<'a>( e: EnumId, ) -> Option<(EnumVariantId, &'a Layout)> { let (var_id, var_layout) = match &layout.variants { - hir_def::layout::Variants::Empty => unreachable!(), - hir_def::layout::Variants::Single { index } => { + hir_def::layout::Variants::Empty { .. } => unreachable!(), + hir_def::layout::Variants::Single { index, .. } => { (e.enum_variants(db).variants[index.0].0, layout) } hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => { diff --git a/tests/codegen-llvm/enum/enum-aggregate.rs b/tests/codegen-llvm/enum/enum-aggregate.rs index 0161e5f3fa1a1..9752f83095c2c 100644 --- a/tests/codegen-llvm/enum/enum-aggregate.rs +++ b/tests/codegen-llvm/enum/enum-aggregate.rs @@ -114,7 +114,7 @@ fn make_uninhabited_err_indirectly(n: Never) -> Result { fn make_fully_uninhabited_result(v: u32, n: Never) -> Result<(u32, Never), (Never, u32)> { // Actually reaching this would be UB, so we don't actually build a result. - // CHECK-LABEL: { i32, i32 } @make_fully_uninhabited_result(i32 %v) + // CHECK-LABEL: i32 @make_fully_uninhabited_result(i32 %v) // CHECK-NEXT: start: // CHECK-NEXT: call void @llvm.trap() // CHECK-NEXT: call void @llvm.trap() diff --git a/tests/ui/abi/c-zst.aarch64-darwin.stderr b/tests/ui/abi/c-zst.aarch64-darwin.stderr index 5e09145a27122..0ec4fd5512da8 100644 --- a/tests/ui/abi/c-zst.aarch64-darwin.stderr +++ b/tests/ui/abi/c-zst.aarch64-darwin.stderr @@ -19,6 +19,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -47,6 +48,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr index b8d6c632b978c..1a0cba0f354e6 100644 --- a/tests/ui/abi/c-zst.powerpc-linux.stderr +++ b/tests/ui/abi/c-zst.powerpc-linux.stderr @@ -19,6 +19,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -58,6 +59,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr index b8d6c632b978c..1a0cba0f354e6 100644 --- a/tests/ui/abi/c-zst.s390x-linux.stderr +++ b/tests/ui/abi/c-zst.s390x-linux.stderr @@ -19,6 +19,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -58,6 +59,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr index b8d6c632b978c..1a0cba0f354e6 100644 --- a/tests/ui/abi/c-zst.sparc64-linux.stderr +++ b/tests/ui/abi/c-zst.sparc64-linux.stderr @@ -19,6 +19,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -58,6 +59,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, diff --git a/tests/ui/abi/c-zst.x86_64-linux.stderr b/tests/ui/abi/c-zst.x86_64-linux.stderr index 5e09145a27122..0ec4fd5512da8 100644 --- a/tests/ui/abi/c-zst.x86_64-linux.stderr +++ b/tests/ui/abi/c-zst.x86_64-linux.stderr @@ -19,6 +19,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -47,6 +48,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr index b8d6c632b978c..1a0cba0f354e6 100644 --- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr +++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr @@ -19,6 +19,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -58,6 +59,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, diff --git a/tests/ui/abi/debug.generic.stderr b/tests/ui/abi/debug.generic.stderr index 3b29efc810251..b06d6c32a687f 100644 --- a/tests/ui/abi/debug.generic.stderr +++ b/tests/ui/abi/debug.generic.stderr @@ -22,6 +22,7 @@ error: fn_abi_of(test) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -69,6 +70,7 @@ error: fn_abi_of(test) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -127,6 +129,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -165,6 +168,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -215,6 +219,7 @@ error: fn_abi_of(test_generic) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -250,6 +255,7 @@ error: fn_abi_of(test_generic) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -299,6 +305,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -334,6 +341,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -371,6 +379,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -406,6 +415,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -446,6 +456,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -485,6 +496,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -519,6 +531,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -558,6 +571,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -600,6 +614,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -635,6 +650,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -672,6 +688,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -707,6 +724,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -750,6 +768,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -785,6 +804,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -822,6 +842,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -857,6 +878,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -931,6 +953,7 @@ error: fn_abi_of(assoc_test) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -968,6 +991,7 @@ error: fn_abi_of(assoc_test) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, diff --git a/tests/ui/abi/debug.riscv64.stderr b/tests/ui/abi/debug.riscv64.stderr index 2417396de2f5a..688d05f7ea9ad 100644 --- a/tests/ui/abi/debug.riscv64.stderr +++ b/tests/ui/abi/debug.riscv64.stderr @@ -22,6 +22,7 @@ error: fn_abi_of(test) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -69,6 +70,7 @@ error: fn_abi_of(test) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -127,6 +129,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -165,6 +168,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -215,6 +219,7 @@ error: fn_abi_of(test_generic) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -250,6 +255,7 @@ error: fn_abi_of(test_generic) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -299,6 +305,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -334,6 +341,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -371,6 +379,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -406,6 +415,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -446,6 +456,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -485,6 +496,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -519,6 +531,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -558,6 +571,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -600,6 +614,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -635,6 +650,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -672,6 +688,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -707,6 +724,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -750,6 +768,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -785,6 +804,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -822,6 +842,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -857,6 +878,7 @@ error: ABIs are not compatible uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -931,6 +953,7 @@ error: fn_abi_of(assoc_test) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -968,6 +991,7 @@ error: fn_abi_of(assoc_test) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, diff --git a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr index 9bb2ab45d9841..e8da59d09a31c 100644 --- a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr +++ b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr @@ -22,6 +22,7 @@ error: fn_abi_of(i8) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -60,6 +61,7 @@ error: fn_abi_of(i8) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -111,6 +113,7 @@ error: fn_abi_of(u8) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -149,6 +152,7 @@ error: fn_abi_of(u8) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -200,6 +204,7 @@ error: fn_abi_of(i16) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -238,6 +243,7 @@ error: fn_abi_of(i16) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -289,6 +295,7 @@ error: fn_abi_of(u16) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -327,6 +334,7 @@ error: fn_abi_of(u16) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -378,6 +386,7 @@ error: fn_abi_of(i32) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -416,6 +425,7 @@ error: fn_abi_of(i32) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -467,6 +477,7 @@ error: fn_abi_of(u32) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -505,6 +516,7 @@ error: fn_abi_of(u32) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), diff --git a/tests/ui/abi/sysv64-zst.stderr b/tests/ui/abi/sysv64-zst.stderr index 2233e8e4f623e..a04782eba1fb1 100644 --- a/tests/ui/abi/sysv64-zst.stderr +++ b/tests/ui/abi/sysv64-zst.stderr @@ -19,6 +19,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, @@ -47,6 +48,7 @@ error: fn_abi_of(pass_zst) = FnAbi { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: $SOME_ALIGN, diff --git a/tests/ui/consts/const-eval/ub-enum.rs b/tests/ui/consts/const-eval/ub-enum.rs index 9c78bb6efed7e..f0bd6a0bf0711 100644 --- a/tests/ui/consts/const-eval/ub-enum.rs +++ b/tests/ui/consts/const-eval/ub-enum.rs @@ -95,11 +95,16 @@ const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute // All variants are uninhabited but also have data. // Use `0` as constant to make behavior endianness-independent. -const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; +const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u32) }; //~^ ERROR uninhabited enum variant -const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; +const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u32) }; //~^ ERROR uninhabited enum variant +// All variants have same-size data but only one inhabited. +// Use `0` as constant to make behavior endianness-independent. +const GOOD_SEMIINHABITED_WITH_DATA1: Result = unsafe { mem::transmute(0u32) }; +const GOOD_SEMIINHABITED_WITH_DATA2: Result<(i32, !), i32> = unsafe { mem::transmute(0u32) }; + const TEST_ICE_89765: () = { // This is a regression test for https://github.com/rust-lang/rust/issues/89765. unsafe { diff --git a/tests/ui/consts/const-eval/ub-enum.stderr b/tests/ui/consts/const-eval/ub-enum.stderr index 5cbd6176c92d1..1e4eb51c41834 100644 --- a/tests/ui/consts/const-eval/ub-enum.stderr +++ b/tests/ui/consts/const-eval/ub-enum.stderr @@ -111,17 +111,17 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant --> $DIR/ub-enum.rs:98:77 | -LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u64) }; +LL | const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem::transmute(0u32) }; | ^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_UNINHABITED_WITH_DATA1` failed here error[E0080]: constructing invalid value at .: encountered an uninhabited enum variant --> $DIR/ub-enum.rs:100:77 | -LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; +LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u32) }; | ^^^^^^^^^^^^^^^^^^^^ evaluation of `BAD_UNINHABITED_WITH_DATA2` failed here error[E0080]: read discriminant of an uninhabited enum variant - --> $DIR/ub-enum.rs:106:9 + --> $DIR/ub-enum.rs:111:9 | LL | std::mem::discriminant(&*(&() as *const () as *const Never)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `TEST_ICE_89765` failed inside this call diff --git a/tests/ui/enum-discriminant/wrapping_niche.stderr b/tests/ui/enum-discriminant/wrapping_niche.stderr index e3e1755e14dd4..44c64eae754b4 100644 --- a/tests/ui/enum-discriminant/wrapping_niche.stderr +++ b/tests/ui/enum-discriminant/wrapping_niche.stderr @@ -58,6 +58,7 @@ error: layout_of(UnsignedAroundZero) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -79,6 +80,7 @@ error: layout_of(UnsignedAroundZero) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -100,6 +102,7 @@ error: layout_of(UnsignedAroundZero) = Layout { uninhabited: false, variants: Single { index: 2, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -176,6 +179,7 @@ error: layout_of(SignedAroundZero) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -197,6 +201,7 @@ error: layout_of(SignedAroundZero) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -218,6 +223,7 @@ error: layout_of(SignedAroundZero) = Layout { uninhabited: false, variants: Single { index: 2, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index b2ce6385ab654..437d2a5b71309 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -5,7 +5,7 @@ LL | union EmptyUnion {} | ^^^^^^^^^^^^^^^^^^^ error: layout_of(E) = Layout { - size: Size(12 bytes), + size: Size(8 bytes), align: AbiAlign { abi: Align(4 bytes), }, @@ -58,35 +58,50 @@ error: layout_of(E) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: $SEED, }, Layout { - size: Size(12 bytes), + size: Size(8 bytes), align: AbiAlign { abi: Align(4 bytes), }, - backend_repr: Memory { - sized: true, - }, + backend_repr: ScalarPair( + Initialized { + value: Int( + I32, + true, + ), + valid_range: 0..=4294967295, + }, + Initialized { + value: Int( + I32, + true, + ), + valid_range: 0..=4294967295, + }, + ), fields: Arbitrary { offsets: [ - Size(4 bytes), - Size(4 bytes), Size(8 bytes), + Size(0 bytes), + Size(4 bytes), ], memory_index: [ + 2, 0, 1, - 2, ], }, largest_niche: None, uninhabited: true, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -140,6 +155,7 @@ error: layout_of(S) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -165,6 +181,7 @@ error: layout_of(U) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -259,6 +276,7 @@ error: layout_of(Result) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -297,6 +315,7 @@ error: layout_of(Result) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -332,6 +351,7 @@ error: layout_of(i32) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -357,6 +377,7 @@ error: layout_of(V) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -382,6 +403,7 @@ error: layout_of(W) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -407,6 +429,7 @@ error: layout_of(Y) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -432,6 +455,7 @@ error: layout_of(P1) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -457,6 +481,7 @@ error: layout_of(P2) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -482,6 +507,7 @@ error: layout_of(P3) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -493,7 +519,7 @@ LL | union P3 { x: F32x4 } | ^^^^^^^^ error: layout_of(P4) = Layout { - size: Size(12 bytes), + size: Size(8 bytes), align: AbiAlign { abi: Align(1 bytes), }, @@ -507,6 +533,7 @@ error: layout_of(P4) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -537,6 +564,7 @@ error: layout_of(P5) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -567,6 +595,7 @@ error: layout_of(MaybeUninit) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), diff --git a/tests/ui/layout/enum.rs b/tests/ui/layout/enum.rs index 005faf8ee508d..d6e03af6b883a 100644 --- a/tests/ui/layout/enum.rs +++ b/tests/ui/layout/enum.rs @@ -12,7 +12,7 @@ enum UninhabitedVariantAlign { //~ERROR: abi: Align(2 bytes) } #[rustc_layout(size)] -enum UninhabitedVariantSpace { //~ERROR: size: Size(16 bytes) +enum UninhabitedVariantSpace { //~ERROR: size: Size(15 bytes) A, B([u8; 15], !), // make sure there is space being reserved for this field. } @@ -22,3 +22,96 @@ enum ScalarPairDifferingSign { //~ERROR: abi: ScalarPair A(u8), B(i8), } + +// Enums with only a single inhabited variant can be laid out as just that variant, +// if the uninhabited variants are all "absent" (only have 1-ZST fields) +#[rustc_layout(size, abi)] +enum AbsentVariantUntagged { //~ERROR: size: Size(4 bytes) + //~^ ERROR: abi: Scalar(Initialized + A(i32), + B((), !), +} + +// Even if uninhabited variants are not absent, the enum can still be laid out without +// a tag. +#[rustc_layout(size, abi)] +enum UninhabitedVariantUntagged { //~ERROR: size: Size(4 bytes) + //~^ ERROR: abi: Scalar(Initialized + A(i32), + B(i32, !), +} + +// A single-inhabited-variant enum may still be laid out with a tag, +// if that leads to a better niche for the same size layout. +// This enum uses the tagged representation, since the untagged representation would be +// the same size, but without a niche. +#[rustc_layout(size, abi)] +enum UninhabitedVariantUntaggedBigger { //~ERROR: size: Size(8 bytes) + //~^ ERROR: abi: ScalarPair + A(i32), + B([u8; 5], !), +} + +#[rustc_layout(size, abi)] +enum UninhabitedVariantWithNiche { //~ERROR: size: Size(2 bytes) + //~^ERROR: abi: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=1 }, Initialized { value: Int(I8, true), valid_range: 0..=255 }) + A(i8, bool), + B(u8, u8, !), +} + +#[rustc_layout(debug)] +enum UninhabitedVariantLargeWithNiche { + //~^ ERROR: layout_of + //~| ERROR: size: Size(3 bytes) + //~| ERROR: backend_repr: Memory + //~| ERROR: valid_range: 0..=0 + // Should use the tagged representation, since that gives a 255-slot niche, + // instead of a 254-slot niche if it used the niche-filling representation on the `bool` + A(i8, bool), + B(u8, u8, u8, !), +} + +// This uses the tagged layout, but since all variants are uninhabited, none of them store the tag, +// so we only need space for the fields, and the abi is Memory. +#[rustc_layout(size, abi)] +enum AllUninhabitedVariants { //~ERROR: size: Size(2 bytes) + //~^ERROR: abi: Memory + A(i8, bool, !), + B(u8, u8, !), +} + +#[repr(align(2))] +struct AlignedNever(!); + +// Tagged `(i8, padding)` +#[rustc_layout(size, abi)] +enum AlignedI8 { //~ERROR: size: Size(2 bytes) + //~^ERROR: abi: Memory + A(i8), + B(AlignedNever) +} + +// Tagged `(u8, i8, padding, padding)` +#[rustc_layout(size, abi)] +enum TaggedI8 { //~ERROR: size: Size(4 bytes) + //~^ERROR: abi: Memory + A(i8), + B(i8, i8, i8, AlignedNever) +} + + +// Tagged `(u16, i16)` +#[rustc_layout(size, abi)] +enum TaggedI16 { //~ERROR: size: Size(4 bytes) + //~^ERROR: abi: ScalarPair + A(i16), + B(i8, i8, i8, AlignedNever) +} + +// This must not use tagged representation, since it's zero-sized. +#[rustc_layout(size, abi)] +enum AllUninhabitedVariantsAlignedZst { //~ERROR: size: Size(0 bytes) + //~^ERROR: abi: Memory + A(AlignedNever), + B(AlignedNever), +} diff --git a/tests/ui/layout/enum.stderr b/tests/ui/layout/enum.stderr index f95b577bfc9df..dbeefa73cdff0 100644 --- a/tests/ui/layout/enum.stderr +++ b/tests/ui/layout/enum.stderr @@ -4,7 +4,7 @@ error: align: AbiAlign { abi: Align(2 bytes) } LL | enum UninhabitedVariantAlign { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: size: Size(16 bytes) +error: size: Size(15 bytes) --> $DIR/enum.rs:15:1 | LL | enum UninhabitedVariantSpace { @@ -16,5 +16,231 @@ error: abi: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=1 } LL | enum ScalarPairDifferingSign { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: size: Size(4 bytes) + --> $DIR/enum.rs:29:1 + | +LL | enum AbsentVariantUntagged { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I32, true), valid_range: 0..=4294967295 }) + --> $DIR/enum.rs:29:1 + | +LL | enum AbsentVariantUntagged { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(4 bytes) + --> $DIR/enum.rs:38:1 + | +LL | enum UninhabitedVariantUntagged { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I32, true), valid_range: 0..=4294967295 }) + --> $DIR/enum.rs:38:1 + | +LL | enum UninhabitedVariantUntagged { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(8 bytes) + --> $DIR/enum.rs:49:1 + | +LL | enum UninhabitedVariantUntaggedBigger { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=0 }, Initialized { value: Int(I32, true), valid_range: 0..=4294967295 }) + --> $DIR/enum.rs:49:1 + | +LL | enum UninhabitedVariantUntaggedBigger { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(2 bytes) + --> $DIR/enum.rs:56:1 + | +LL | enum UninhabitedVariantWithNiche { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=1 }, Initialized { value: Int(I8, true), valid_range: 0..=255 }) + --> $DIR/enum.rs:56:1 + | +LL | enum UninhabitedVariantWithNiche { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: layout_of(UninhabitedVariantLargeWithNiche) = Layout { + size: Size(3 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=0, + }, + ), + uninhabited: false, + variants: Multiple { + tag: Initialized { + value: Int( + I8, + false, + ), + valid_range: 0..=0, + }, + tag_encoding: Direct, + tag_field: 0, + variants: [ + Layout { + size: Size(3 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(1 bytes), + Size(2 bytes), + ], + memory_index: [ + 0, + 1, + ], + }, + largest_niche: Some( + Niche { + offset: Size(2 bytes), + value: Int( + I8, + false, + ), + valid_range: 0..=1, + }, + ), + uninhabited: false, + variants: Single { + index: 0, + variants: None, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: 17394913183323368564, + }, + Layout { + size: Size(3 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(0 bytes), + Size(1 bytes), + Size(2 bytes), + Size(3 bytes), + ], + memory_index: [ + 0, + 1, + 2, + 3, + ], + }, + largest_niche: None, + uninhabited: true, + variants: Single { + index: 1, + variants: None, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: 17538183959353994357, + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + randomization_seed: 15362464571658798427, + } + --> $DIR/enum.rs:63:1 + | +LL | enum UninhabitedVariantLargeWithNiche { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(2 bytes) + --> $DIR/enum.rs:77:1 + | +LL | enum AllUninhabitedVariants { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: Memory { sized: true } + --> $DIR/enum.rs:77:1 + | +LL | enum AllUninhabitedVariants { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(2 bytes) + --> $DIR/enum.rs:88:1 + | +LL | enum AlignedI8 { + | ^^^^^^^^^^^^^^ + +error: abi: Memory { sized: true } + --> $DIR/enum.rs:88:1 + | +LL | enum AlignedI8 { + | ^^^^^^^^^^^^^^ + +error: size: Size(4 bytes) + --> $DIR/enum.rs:96:1 + | +LL | enum TaggedI8 { + | ^^^^^^^^^^^^^ + +error: abi: Memory { sized: true } + --> $DIR/enum.rs:96:1 + | +LL | enum TaggedI8 { + | ^^^^^^^^^^^^^ + +error: size: Size(4 bytes) + --> $DIR/enum.rs:105:1 + | +LL | enum TaggedI16 { + | ^^^^^^^^^^^^^^ + +error: abi: ScalarPair(Initialized { value: Int(I16, false), valid_range: 0..=0 }, Initialized { value: Int(I16, true), valid_range: 0..=65535 }) + --> $DIR/enum.rs:105:1 + | +LL | enum TaggedI16 { + | ^^^^^^^^^^^^^^ + +error: size: Size(0 bytes) + --> $DIR/enum.rs:113:1 + | +LL | enum AllUninhabitedVariantsAlignedZst { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: Memory { sized: true } + --> $DIR/enum.rs:113:1 + | +LL | enum AllUninhabitedVariantsAlignedZst { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 22 previous errors diff --git a/tests/ui/layout/hexagon-enum.stderr b/tests/ui/layout/hexagon-enum.stderr index d910456c0e6d1..22d6082d0c38e 100644 --- a/tests/ui/layout/hexagon-enum.stderr +++ b/tests/ui/layout/hexagon-enum.stderr @@ -58,6 +58,7 @@ error: layout_of(A) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -134,6 +135,7 @@ error: layout_of(B) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -210,6 +212,7 @@ error: layout_of(C) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -286,6 +289,7 @@ error: layout_of(P) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -362,6 +366,7 @@ error: layout_of(T) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), diff --git a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr index 2087fedeb19bc..bd8f379a4a274 100644 --- a/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr +++ b/tests/ui/layout/issue-96158-scalarpair-payload-might-be-uninit.stderr @@ -80,6 +80,7 @@ error: layout_of(MissingPayloadField) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -101,6 +102,7 @@ error: layout_of(MissingPayloadField) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -201,6 +203,7 @@ error: layout_of(CommonPayloadField) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -239,6 +242,7 @@ error: layout_of(CommonPayloadField) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -337,6 +341,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -374,6 +379,7 @@ error: layout_of(CommonPayloadFieldIsMaybeUninit) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -488,6 +494,7 @@ error: layout_of(NicheFirst) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -509,6 +516,7 @@ error: layout_of(NicheFirst) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -530,6 +538,7 @@ error: layout_of(NicheFirst) = Layout { uninhabited: false, variants: Single { index: 2, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -644,6 +653,7 @@ error: layout_of(NicheSecond) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -665,6 +675,7 @@ error: layout_of(NicheSecond) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -686,6 +697,7 @@ error: layout_of(NicheSecond) = Layout { uninhabited: false, variants: Single { index: 2, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), diff --git a/tests/ui/layout/issue-96185-overaligned-enum.stderr b/tests/ui/layout/issue-96185-overaligned-enum.stderr index 6bcc5b4906b50..6bd931f78f754 100644 --- a/tests/ui/layout/issue-96185-overaligned-enum.stderr +++ b/tests/ui/layout/issue-96185-overaligned-enum.stderr @@ -52,6 +52,7 @@ error: layout_of(Aligned1) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: Some( Align(8 bytes), @@ -75,6 +76,7 @@ error: layout_of(Aligned1) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: Some( Align(8 bytes), @@ -155,6 +157,7 @@ error: layout_of(Aligned2) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: Some( Align(1 bytes), @@ -178,6 +181,7 @@ error: layout_of(Aligned2) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: Some( Align(1 bytes), diff --git a/tests/ui/layout/thumb-enum.stderr b/tests/ui/layout/thumb-enum.stderr index 9bd8ced0c02d6..8ccb145cf85f5 100644 --- a/tests/ui/layout/thumb-enum.stderr +++ b/tests/ui/layout/thumb-enum.stderr @@ -58,6 +58,7 @@ error: layout_of(A) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -134,6 +135,7 @@ error: layout_of(B) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -210,6 +212,7 @@ error: layout_of(C) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -286,6 +289,7 @@ error: layout_of(P) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -362,6 +366,7 @@ error: layout_of(T) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), diff --git a/tests/ui/layout/zero-sized-array-enum-niche.stderr b/tests/ui/layout/zero-sized-array-enum-niche.stderr index 1707b8aff81cf..6d3e1121fbe69 100644 --- a/tests/ui/layout/zero-sized-array-enum-niche.stderr +++ b/tests/ui/layout/zero-sized-array-enum-niche.stderr @@ -56,6 +56,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -90,6 +91,7 @@ error: layout_of(Result<[u32; 0], bool>) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -164,6 +166,7 @@ error: layout_of(MultipleAlignments) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(2 bytes), @@ -189,6 +192,7 @@ error: layout_of(MultipleAlignments) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -223,6 +227,7 @@ error: layout_of(MultipleAlignments) = Layout { uninhabited: false, variants: Single { index: 2, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -297,6 +302,7 @@ error: layout_of(Result<[u32; 0], Packed>>) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -331,6 +337,7 @@ error: layout_of(Result<[u32; 0], Packed>>) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -409,6 +416,7 @@ error: layout_of(Result<[u32; 0], Packed>) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -443,6 +451,7 @@ error: layout_of(Result<[u32; 0], Packed>) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), diff --git a/tests/ui/offset-of/offset-of-enum-valid.rs b/tests/ui/offset-of/offset-of-enum-valid.rs new file mode 100644 index 0000000000000..154b5f9b39531 --- /dev/null +++ b/tests/ui/offset-of/offset-of-enum-valid.rs @@ -0,0 +1,61 @@ +//@ run-pass +#![feature(offset_of_enum)] +#![allow(unused)] + +use std::mem::offset_of; + +enum Never {} + +#[repr(align(2))] +struct AlignedNever(Never); + +enum Alpha { + One(u8), + Two(u8), + Three(u8, u8, Never), +} + +enum Beta { + One(u8), + Two(u8, Never), +} + +enum Gamma { + One(u32), + Two(u8, u8, u8, Never), +} + +enum Delta { + One(u8, Never), + Two(u8, u8, Never), +} + +fn main() { + assert!(offset_of!(Alpha, One.0) <= size_of::() - size_of::()); + assert!(offset_of!(Alpha, Two.0) <= size_of::() - size_of::()); + assert!(offset_of!(Alpha, Three.0) <= size_of::() - size_of::()); + assert!(offset_of!(Alpha, Three.1) <= size_of::() - size_of::()); + assert!(offset_of!(Alpha, Three.2) <= size_of::() - size_of::()); + assert!(offset_of!(Alpha, Three.0) != offset_of!(Alpha, Three.1)); + + assert!(offset_of!(Beta, One.0) <= size_of::() - size_of::()); + assert!(offset_of!(Beta, Two.0) <= size_of::() - size_of::()); + assert!(offset_of!(Beta, Two.1) <= size_of::() - size_of::()); + + assert!(offset_of!(Gamma, One.0) <= size_of::() - size_of::()); + assert!(offset_of!(Gamma, Two.0) <= size_of::() - size_of::()); + assert!(offset_of!(Gamma, Two.1) <= size_of::() - size_of::()); + assert!(offset_of!(Gamma, Two.2) <= size_of::() - size_of::()); + assert!(offset_of!(Gamma, Two.3) <= size_of::() - size_of::()); + assert!(offset_of!(Gamma, Two.0) != offset_of!(Gamma, Two.1)); + assert!(offset_of!(Gamma, Two.0) != offset_of!(Gamma, Two.2)); + assert!(offset_of!(Gamma, Two.1) != offset_of!(Gamma, Two.2)); + + assert!(offset_of!(Delta, One.0) <= size_of::() - size_of::()); + assert!(offset_of!(Delta, One.1) <= size_of::() - size_of::()); + assert!(offset_of!(Delta, Two.0) <= size_of::() - size_of::()); + assert!(offset_of!(Delta, Two.0) <= size_of::() - size_of::()); + assert!(offset_of!(Delta, Two.1) <= size_of::() - size_of::()); + assert!(offset_of!(Delta, Two.2) <= size_of::() - size_of::()); + assert!(offset_of!(Delta, Two.0) != offset_of!(Delta, Two.1)); +} diff --git a/tests/ui/offset-of/offset-of-enum.rs b/tests/ui/offset-of/offset-of-enum.rs index 64850e4782335..20335c0061610 100644 --- a/tests/ui/offset-of/offset-of-enum.rs +++ b/tests/ui/offset-of/offset-of-enum.rs @@ -2,9 +2,12 @@ use std::mem::offset_of; +enum Never {} + enum Alpha { One(u8), Two(u8), + Three(u8, u8, Never), } fn main() { @@ -15,4 +18,8 @@ fn main() { offset_of!(Alpha, Two.foo); //~ ERROR no field named `foo` on enum variant `Alpha::Two` offset_of!(Alpha, NonExistent); //~ ERROR no variant named `NonExistent` found for enum `Alpha` offset_of!(Beta, One); //~ ERROR cannot find type `Beta` in this scope + offset_of!(Alpha, Three.0); + offset_of!(Alpha, Three.1); + offset_of!(Alpha, Three.2); + offset_of!(Alpha, Three.2.NonExistent); //~ ERROR no variant named `NonExistent` found for enum `Never` } diff --git a/tests/ui/offset-of/offset-of-enum.stderr b/tests/ui/offset-of/offset-of-enum.stderr index 7e7ad41f5b6a9..4b345064a6a2a 100644 --- a/tests/ui/offset-of/offset-of-enum.stderr +++ b/tests/ui/offset-of/offset-of-enum.stderr @@ -1,5 +1,5 @@ error[E0573]: expected type, found variant `Alpha::One` - --> $DIR/offset-of-enum.rs:11:16 + --> $DIR/offset-of-enum.rs:14:16 | LL | offset_of!(Alpha::One, 0); | ^^^^^^^^^^ @@ -8,19 +8,19 @@ LL | offset_of!(Alpha::One, 0); | help: try using the variant's enum: `Alpha` error[E0412]: cannot find type `Beta` in this scope - --> $DIR/offset-of-enum.rs:17:16 + --> $DIR/offset-of-enum.rs:20:16 | LL | offset_of!(Beta, One); | ^^^^ not found in this scope error[E0795]: `One` is an enum variant; expected field at end of `offset_of` - --> $DIR/offset-of-enum.rs:12:23 + --> $DIR/offset-of-enum.rs:15:23 | LL | offset_of!(Alpha, One); | ^^^ enum variant error[E0609]: no field named `1` on enum variant `Alpha::Two` - --> $DIR/offset-of-enum.rs:14:23 + --> $DIR/offset-of-enum.rs:17:23 | LL | offset_of!(Alpha, Two.1); | ^^^ - ...does not have this field @@ -28,7 +28,7 @@ LL | offset_of!(Alpha, Two.1); | this enum variant... error[E0609]: no field named `foo` on enum variant `Alpha::Two` - --> $DIR/offset-of-enum.rs:15:23 + --> $DIR/offset-of-enum.rs:18:23 | LL | offset_of!(Alpha, Two.foo); | ^^^ --- ...does not have this field @@ -36,12 +36,18 @@ LL | offset_of!(Alpha, Two.foo); | this enum variant... error[E0599]: no variant named `NonExistent` found for enum `Alpha` - --> $DIR/offset-of-enum.rs:16:23 + --> $DIR/offset-of-enum.rs:19:23 | LL | offset_of!(Alpha, NonExistent); | ^^^^^^^^^^^ variant not found -error: aborting due to 6 previous errors +error[E0599]: no variant named `NonExistent` found for enum `Never` + --> $DIR/offset-of-enum.rs:24:31 + | +LL | offset_of!(Alpha, Three.2.NonExistent); + | ^^^^^^^^^^^ variant not found + +error: aborting due to 7 previous errors Some errors have detailed explanations: E0412, E0573, E0599, E0609, E0795. For more information about an error, try `rustc --explain E0412`. diff --git a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr index 63d685951d981..8bf7a8872f089 100644 --- a/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr +++ b/tests/ui/repr/repr-c-dead-variants.aarch64-unknown-linux-gnu.stderr @@ -68,6 +68,7 @@ error: layout_of(Univariant) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -166,6 +167,7 @@ error: layout_of(TwoVariants) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -203,6 +205,7 @@ error: layout_of(TwoVariants) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -279,6 +282,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: Some( Align(8 bytes), @@ -306,6 +310,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), diff --git a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr index 555471be0271d..db42fa74a9678 100644 --- a/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr +++ b/tests/ui/repr/repr-c-dead-variants.armebv7r-none-eabi.stderr @@ -68,6 +68,7 @@ error: layout_of(Univariant) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -166,6 +167,7 @@ error: layout_of(TwoVariants) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -203,6 +205,7 @@ error: layout_of(TwoVariants) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -279,6 +282,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: Some( Align(8 bytes), @@ -306,6 +310,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), diff --git a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr index 63d685951d981..8bf7a8872f089 100644 --- a/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr +++ b/tests/ui/repr/repr-c-dead-variants.i686-pc-windows-msvc.stderr @@ -68,6 +68,7 @@ error: layout_of(Univariant) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -166,6 +167,7 @@ error: layout_of(TwoVariants) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -203,6 +205,7 @@ error: layout_of(TwoVariants) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -279,6 +282,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: Some( Align(8 bytes), @@ -306,6 +310,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), diff --git a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr index 63d685951d981..8bf7a8872f089 100644 --- a/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr +++ b/tests/ui/repr/repr-c-dead-variants.x86_64-unknown-linux-gnu.stderr @@ -68,6 +68,7 @@ error: layout_of(Univariant) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -166,6 +167,7 @@ error: layout_of(TwoVariants) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -203,6 +205,7 @@ error: layout_of(TwoVariants) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -279,6 +282,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: Some( Align(8 bytes), @@ -306,6 +310,7 @@ error: layout_of(DeadBranchHasOtherField) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), diff --git a/tests/ui/repr/repr-c-int-dead-variants.stderr b/tests/ui/repr/repr-c-int-dead-variants.stderr index d88a842f88482..8845a39f7f5e7 100644 --- a/tests/ui/repr/repr-c-int-dead-variants.stderr +++ b/tests/ui/repr/repr-c-int-dead-variants.stderr @@ -68,6 +68,7 @@ error: layout_of(UnivariantU8) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -166,6 +167,7 @@ error: layout_of(TwoVariantsU8) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -203,6 +205,7 @@ error: layout_of(TwoVariantsU8) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -279,6 +282,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { uninhabited: true, variants: Single { index: 0, + variants: None, }, max_repr_align: Some( Align(8 bytes), @@ -306,6 +310,7 @@ error: layout_of(DeadBranchHasOtherFieldU8) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), diff --git a/tests/ui/type/pattern_types/or_patterns.stderr b/tests/ui/type/pattern_types/or_patterns.stderr index a417e502e3562..dd4394f9b7ded 100644 --- a/tests/ui/type/pattern_types/or_patterns.stderr +++ b/tests/ui/type/pattern_types/or_patterns.stderr @@ -67,6 +67,7 @@ error: layout_of((i8) is (i8::MIN..=-1 | 1..)) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -105,6 +106,7 @@ error: layout_of((i8) is (i8::MIN..=-2 | 0..)) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr index abd8b87fffc6f..83c5be45b22cb 100644 --- a/tests/ui/type/pattern_types/range_patterns.stderr +++ b/tests/ui/type/pattern_types/range_patterns.stderr @@ -33,6 +33,7 @@ error: layout_of(NonZero) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -71,6 +72,7 @@ error: layout_of((u32) is 1..) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -136,6 +138,7 @@ error: layout_of(Option<(u32) is 1..>) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -176,6 +179,7 @@ error: layout_of(Option<(u32) is 1..>) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -247,6 +251,7 @@ error: layout_of(Option>) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -287,6 +292,7 @@ error: layout_of(Option>) = Layout { uninhabited: false, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -338,6 +344,7 @@ error: layout_of(NonZeroU32New) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -404,6 +411,7 @@ error: layout_of((i8) is -10..=10) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -442,6 +450,7 @@ error: layout_of((i8) is i8::MIN..=0) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes),