From 491113147d8e52fa597c021eb7d988ac8fa3408e Mon Sep 17 00:00:00 2001 From: Zachary S Date: Tue, 12 Aug 2025 21:27:43 -0500 Subject: [PATCH 1/9] Prepare offset_of for non-absent uninhabited variants in using tagless enum representations --- compiler/rustc_abi/src/callconv.rs | 2 +- compiler/rustc_abi/src/layout.rs | 14 ++++----- compiler/rustc_abi/src/layout/coroutine.rs | 2 +- compiler/rustc_abi/src/layout/simple.rs | 16 +++++----- compiler/rustc_abi/src/lib.rs | 19 ++++++++++-- .../src/discriminant.rs | 8 ++--- compiler/rustc_codegen_gcc/src/type_of.rs | 6 ++-- .../src/debuginfo/metadata/enums/cpp_like.rs | 6 ++-- .../src/debuginfo/metadata/enums/mod.rs | 2 +- .../src/debuginfo/metadata/enums/native.rs | 2 +- compiler/rustc_codegen_llvm/src/type_of.rs | 6 ++-- .../rustc_codegen_ssa/src/debuginfo/mod.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/analyze.rs | 2 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 16 ++++++---- compiler/rustc_codegen_ssa/src/mir/place.rs | 4 +-- .../src/interpret/discriminant.rs | 6 ++-- .../src/interpret/validity.rs | 8 ++--- .../rustc_const_eval/src/interpret/visitor.rs | 2 +- .../src/util/check_validity_requirement.rs | 2 +- compiler/rustc_middle/src/ty/layout.rs | 29 ++++++++++++------- .../rustc_mir_transform/src/check_enums.rs | 4 +-- compiler/rustc_mir_transform/src/gvn.rs | 2 +- .../rustc_mir_transform/src/large_enums.rs | 2 +- .../src/unreachable_enum_branching.rs | 4 +-- compiler/rustc_public/src/abi.rs | 21 ++++++++++++-- .../src/unstable/convert/stable/abi.rs | 11 ++++--- .../rustc_target/src/callconv/loongarch.rs | 2 +- compiler/rustc_target/src/callconv/riscv.rs | 2 +- compiler/rustc_target/src/callconv/x86_64.rs | 2 +- compiler/rustc_transmute/src/layout/tree.rs | 8 ++--- compiler/rustc_ty_utils/src/layout.rs | 5 ++-- .../rustc_ty_utils/src/layout/invariant.rs | 4 +-- src/tools/miri/src/helpers.rs | 2 +- .../crates/hir-ty/src/mir/eval.rs | 8 ++--- .../rust-analyzer/crates/hir-ty/src/utils.rs | 4 +-- tests/ui/abi/c-zst.aarch64-darwin.stderr | 2 ++ tests/ui/abi/c-zst.powerpc-linux.stderr | 2 ++ tests/ui/abi/c-zst.s390x-linux.stderr | 2 ++ tests/ui/abi/c-zst.sparc64-linux.stderr | 2 ++ tests/ui/abi/c-zst.x86_64-linux.stderr | 2 ++ .../ui/abi/c-zst.x86_64-pc-windows-gnu.stderr | 2 ++ tests/ui/abi/debug.generic.stderr | 24 +++++++++++++++ tests/ui/abi/debug.loongarch64.stderr | 24 +++++++++++++++ tests/ui/abi/debug.riscv64.stderr | 24 +++++++++++++++ .../x86-64-sysv64-arg-ext.other.stderr | 12 ++++++++ tests/ui/abi/sysv64-zst.stderr | 2 ++ .../enum-discriminant/wrapping_niche.stderr | 6 ++++ tests/ui/layout/debug.stderr | 16 ++++++++++ tests/ui/layout/hexagon-enum.stderr | 5 ++++ ...-scalarpair-payload-might-be-uninit.stderr | 12 ++++++++ .../issue-96185-overaligned-enum.stderr | 4 +++ tests/ui/layout/thumb-enum.stderr | 5 ++++ .../layout/zero-sized-array-enum-niche.stderr | 9 ++++++ ...-variants.aarch64-unknown-linux-gnu.stderr | 5 ++++ ...-c-dead-variants.armebv7r-none-eabi.stderr | 5 ++++ ...-dead-variants.i686-pc-windows-msvc.stderr | 5 ++++ ...d-variants.x86_64-unknown-linux-gnu.stderr | 5 ++++ tests/ui/repr/repr-c-int-dead-variants.stderr | 5 ++++ .../ui/type/pattern_types/or_patterns.stderr | 2 ++ .../type/pattern_types/range_patterns.stderr | 9 ++++++ 60 files changed, 332 insertions(+), 94 deletions(-) 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 14356813b7bb0..f33514cc4428c 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); 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(), @@ -467,7 +467,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, @@ -508,7 +508,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 { @@ -615,7 +615,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.abi); max_repr_align = max_repr_align.max(st.max_repr_align); @@ -847,7 +847,7 @@ impl LayoutCalculator { repr, StructKind::Prefixed(min_ity.size(), prefix_align), )?; - st.variants = Variants::Single { index: i }; + 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() { @@ -1457,7 +1457,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 b3807c8727396..83706e8a68ef6 100644 --- a/compiler/rustc_abi/src/layout/simple.rs +++ b/compiler/rustc_abi/src/layout/simple.rs @@ -13,7 +13,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(), @@ -33,7 +33,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, @@ -75,7 +75,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, @@ -105,7 +105,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(), @@ -121,14 +121,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 de44c8755a078..472d1f637c10c 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1851,12 +1851,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 93202483eed81..4ff729e92de90 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 4ecc3086e1bdf..d200b1f8cb0c5 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 caff358607974..a998e9ec41018 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -393,7 +393,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 1ae6e6e5eecab..9bc6607428114 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 84998b5499bdf..58e51da302ba4 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -36,14 +36,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(); @@ -218,7 +218,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 0a37a904193fa..a822e969e365c 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 88a8e2a844cbc..9cb5f641a5b6c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -411,8 +411,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 @@ -956,10 +956,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 50f56f913a51e..e60252e393dc4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -458,8 +458,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 5f088fe37e80b..5ea1e5ee00f16 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"), } } @@ -1024,7 +1024,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 b5de10c7dcd11..1f97b17515441 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 1dea7e4252d7f..2fdfe20411008 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 507a25a432594..b97c3a01dbcb9 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -772,14 +772,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(); @@ -796,15 +799,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 } } @@ -941,8 +946,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()) @@ -963,11 +968,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 12447dc7cbb0c..af6df52bbb1a7 100644 --- a/compiler/rustc_mir_transform/src/check_enums.rs +++ b/compiler/rustc_mir_transform/src/check_enums.rs @@ -186,10 +186,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 3ff8dc6dbb378..5ff24d4cfbcd9 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -1587,7 +1587,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 1b90e9158f6b8..f48d2b99464f0 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 bc3c9601fa3d3..3490dfdf60362 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -124,7 +124,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 16de3fe070dd4..2e6f1ff141fd9 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 7f626e8c4e886..d886b77146a76 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 317d101dafe05..dee0df31777d8 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -811,9 +811,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 b768269215fa2..58308ca0edca5 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 e0c077e99319a..c5ff7cd72f54c 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -614,7 +614,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 c93165a04c0fb..504715168c891 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 @@ -821,7 +821,7 @@ impl<'db> Evaluator<'db> { ProjectionElem::Field(Either::Left(f)) => { let layout = self.layout(prev_ty.to_nextsolver(interner))?; 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) => { @@ -1656,8 +1656,8 @@ impl<'db> Evaluator<'db> { 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) @@ -1825,7 +1825,7 @@ impl<'db> Evaluator<'db> { } 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 427c4bb68423d..e86a14d02693d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -328,8 +328,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/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 ec6b9b8f02742..10b71c96eb77c 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 ec6b9b8f02742..10b71c96eb77c 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 ec6b9b8f02742..10b71c96eb77c 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 ec6b9b8f02742..10b71c96eb77c 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 47341da221fb3..1b91259692b42 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.loongarch64.stderr b/tests/ui/abi/debug.loongarch64.stderr index 94a01a8087314..e77060f4c62fb 100644 --- a/tests/ui/abi/debug.loongarch64.stderr +++ b/tests/ui/abi/debug.loongarch64.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 94a01a8087314..e77060f4c62fb 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/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..c2116c126119d 100644 --- a/tests/ui/layout/debug.stderr +++ b/tests/ui/layout/debug.stderr @@ -58,6 +58,7 @@ error: layout_of(E) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -87,6 +88,7 @@ error: layout_of(E) = Layout { uninhabited: true, variants: Single { index: 1, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(4 bytes), @@ -140,6 +142,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 +168,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 +263,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 +302,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 +338,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 +364,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 +390,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 +416,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 +442,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 +468,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 +494,7 @@ error: layout_of(P3) = Layout { uninhabited: false, variants: Single { index: 0, + variants: None, }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), @@ -507,6 +520,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 +551,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 +582,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/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/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), From ec7c3209be59bb5e95655b8d8c1e298d3e61ac11 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Tue, 12 Aug 2025 21:15:17 -0500 Subject: [PATCH 2/9] Add/extend tests for offset_of! for enums with uninhabited variants --- tests/ui/offset-of/offset-of-enum-valid.rs | 61 ++++++++++++++++++++++ tests/ui/offset-of/offset-of-enum.rs | 7 +++ tests/ui/offset-of/offset-of-enum.stderr | 20 ++++--- 3 files changed, 81 insertions(+), 7 deletions(-) create mode 100644 tests/ui/offset-of/offset-of-enum-valid.rs 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`. From 1d130a53657fddf87ca94f08c188fee322aecbdc Mon Sep 17 00:00:00 2001 From: Zachary S Date: Tue, 12 Aug 2025 22:37:52 -0500 Subject: [PATCH 3/9] Add tests for Result layout. The comments will be accurate after the commits which add the relevant layout optimizations. --- tests/ui/consts/const-eval/ub-enum.rs | 5 +++++ tests/ui/consts/const-eval/ub-enum.stderr | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/ui/consts/const-eval/ub-enum.rs b/tests/ui/consts/const-eval/ub-enum.rs index 9c78bb6efed7e..b60116aa553f7 100644 --- a/tests/ui/consts/const-eval/ub-enum.rs +++ b/tests/ui/consts/const-eval/ub-enum.rs @@ -100,6 +100,11 @@ const BAD_UNINHABITED_WITH_DATA1: Result<(i32, Never), (i32, !)> = unsafe { mem: const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem::transmute(0u64) }; //~^ 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(0u64) }; +const GOOD_SEMIINHABITED_WITH_DATA2: Result<(i32, !), i32> = unsafe { mem::transmute(1u64) }; + 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 1efd93832291e..ffb6d2bc27e5a 100644 --- a/tests/ui/consts/const-eval/ub-enum.stderr +++ b/tests/ui/consts/const-eval/ub-enum.stderr @@ -121,7 +121,7 @@ LL | const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { | ^^^^^^^^^^^^^^^^^^^^ 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 From 02cafd5f16605a70a65e789d1bd7ff5cc0836ace Mon Sep 17 00:00:00 2001 From: Zachary S Date: Tue, 12 Aug 2025 21:52:56 -0500 Subject: [PATCH 4/9] Add more enum layout tests. The comments will be accurate after the commits which add the relevant layout optimizations. --- tests/ui/layout/enum.rs | 93 +++++++++++++++ tests/ui/layout/enum.stderr | 228 +++++++++++++++++++++++++++++++++++- 2 files changed, 320 insertions(+), 1 deletion(-) diff --git a/tests/ui/layout/enum.rs b/tests/ui/layout/enum.rs index 005faf8ee508d..53dbc324c0a61 100644 --- a/tests/ui/layout/enum.rs +++ b/tests/ui/layout/enum.rs @@ -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(8 bytes) + //~^ ERROR: abi: ScalarPair(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: Memory + A(i32), + B([u8; 5], !), +} + +#[rustc_layout(size, abi)] +enum UninhabitedVariantWithNiche { //~ERROR: size: Size(3 bytes) + //~^ERROR: abi: Memory + 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(3 bytes) + //~^ERROR: abi: Memory + A(i8, bool, !), + B(u8, u8, !), +} + +#[repr(align(2))] +struct AlignedNever(!); + +// Tagged `(u8, i8)` +#[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: Memory + 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(2 bytes) + //~^ERROR: abi: Scalar + A(AlignedNever), + B(AlignedNever), +} diff --git a/tests/ui/layout/enum.stderr b/tests/ui/layout/enum.stderr index f95b577bfc9df..49c19c7fdfbfd 100644 --- a/tests/ui/layout/enum.stderr +++ b/tests/ui/layout/enum.stderr @@ -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(8 bytes) + --> $DIR/enum.rs:38:1 + | +LL | enum UninhabitedVariantUntagged { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: ScalarPair(Initialized { value: Int(I32, false), valid_range: 0..=0 }, 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: Memory { sized: true } + --> $DIR/enum.rs:49:1 + | +LL | enum UninhabitedVariantUntaggedBigger { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(3 bytes) + --> $DIR/enum.rs:56:1 + | +LL | enum UninhabitedVariantWithNiche { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: Memory { sized: true } + --> $DIR/enum.rs:56:1 + | +LL | enum UninhabitedVariantWithNiche { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: layout_of(UninhabitedVariantLargeWithNiche) = Layout { + size: Size(4 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(4 bytes), + align: AbiAlign { + abi: Align(1 bytes), + }, + backend_repr: Memory { + sized: true, + }, + fields: Arbitrary { + offsets: [ + Size(1 bytes), + Size(2 bytes), + Size(3 bytes), + Size(4 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(3 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: Memory { sized: true } + --> $DIR/enum.rs:105:1 + | +LL | enum TaggedI16 { + | ^^^^^^^^^^^^^^ + +error: size: Size(2 bytes) + --> $DIR/enum.rs:113:1 + | +LL | enum AllUninhabitedVariantsAlignedZst { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I16, false), valid_range: 0..=0 }) + --> $DIR/enum.rs:113:1 + | +LL | enum AllUninhabitedVariantsAlignedZst { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 22 previous errors From 2955d8fff0d2205b76cf0878f185994f622c2efb Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sun, 26 Jan 2025 01:31:57 -0600 Subject: [PATCH 5/9] Don't encode enum tag for uninhabited repr(Rust) enum variants --- compiler/rustc_abi/src/layout.rs | 62 +++++++++++++++++++++-- tests/codegen-llvm/enum/enum-aggregate.rs | 2 +- tests/ui/consts/const-eval/ub-enum.rs | 4 +- tests/ui/consts/const-eval/ub-enum.stderr | 4 +- tests/ui/layout/debug.stderr | 31 ++++++++---- tests/ui/layout/enum.rs | 12 ++--- tests/ui/layout/enum.stderr | 18 +++---- 7 files changed, 99 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index f33514cc4428c..fd0b9f499c9cc 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -842,11 +842,15 @@ impl LayoutCalculator { 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), - )?; + let uninhabited = field_layouts.iter().any(|f| f.is_uninhabited()); + // 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. @@ -916,6 +920,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 { @@ -960,6 +969,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()); @@ -1076,6 +1091,43 @@ 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: AbiAlign::new(align), + size, + max_repr_align, + unadjusted_abi_align, + randomization_seed: combined_seed, + }); + } + let tagged_layout = LayoutData { variants: Variants::Multiple { tag, diff --git a/tests/codegen-llvm/enum/enum-aggregate.rs b/tests/codegen-llvm/enum/enum-aggregate.rs index 7d450a89e2e3c..07bd6377760ce 100644 --- a/tests/codegen-llvm/enum/enum-aggregate.rs +++ b/tests/codegen-llvm/enum/enum-aggregate.rs @@ -113,7 +113,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{{( signext)?}} %v) + // CHECK-LABEL: i32 @make_fully_uninhabited_result(i32{{( signext)?}} %v) // CHECK-NEXT: start: // CHECK-NEXT: call void @llvm.trap() // CHECK-NEXT: call void @llvm.trap() diff --git a/tests/ui/consts/const-eval/ub-enum.rs b/tests/ui/consts/const-eval/ub-enum.rs index b60116aa553f7..3dfe0c805151e 100644 --- a/tests/ui/consts/const-eval/ub-enum.rs +++ b/tests/ui/consts/const-eval/ub-enum.rs @@ -95,9 +95,9 @@ 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. diff --git a/tests/ui/consts/const-eval/ub-enum.stderr b/tests/ui/consts/const-eval/ub-enum.stderr index ffb6d2bc27e5a..5701c62fc3516 100644 --- a/tests/ui/consts/const-eval/ub-enum.stderr +++ b/tests/ui/consts/const-eval/ub-enum.stderr @@ -111,13 +111,13 @@ 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 diff --git a/tests/ui/layout/debug.stderr b/tests/ui/layout/debug.stderr index c2116c126119d..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), }, @@ -65,23 +65,36 @@ error: layout_of(E) = Layout { 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, @@ -506,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), }, diff --git a/tests/ui/layout/enum.rs b/tests/ui/layout/enum.rs index 53dbc324c0a61..4d43498cf79df 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. } @@ -47,7 +47,7 @@ enum UninhabitedVariantUntagged { //~ERROR: size: Size(8 bytes) // the same size, but without a niche. #[rustc_layout(size, abi)] enum UninhabitedVariantUntaggedBigger { //~ERROR: size: Size(8 bytes) - //~^ ERROR: abi: Memory + //~^ ERROR: abi: ScalarPair A(i32), B([u8; 5], !), } @@ -74,7 +74,7 @@ enum UninhabitedVariantLargeWithNiche { // 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(3 bytes) +enum AllUninhabitedVariants { //~ERROR: size: Size(2 bytes) //~^ERROR: abi: Memory A(i8, bool, !), B(u8, u8, !), @@ -103,15 +103,15 @@ enum TaggedI8 { //~ERROR: size: Size(4 bytes) // Tagged `(u16, i16)` #[rustc_layout(size, abi)] enum TaggedI16 { //~ERROR: size: Size(4 bytes) - //~^ERROR: abi: Memory + //~^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(2 bytes) - //~^ERROR: abi: Scalar +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 49c19c7fdfbfd..21c66ea3d0fdc 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 { @@ -46,7 +46,7 @@ error: size: Size(8 bytes) LL | enum UninhabitedVariantUntaggedBigger { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: abi: Memory { sized: true } +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 { @@ -65,7 +65,7 @@ LL | enum UninhabitedVariantWithNiche { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: layout_of(UninhabitedVariantLargeWithNiche) = Layout { - size: Size(4 bytes), + size: Size(3 bytes), align: AbiAlign { abi: Align(1 bytes), }, @@ -140,7 +140,7 @@ error: layout_of(UninhabitedVariantLargeWithNiche) = Layout { randomization_seed: 17394913183323368564, }, Layout { - size: Size(4 bytes), + size: Size(3 bytes), align: AbiAlign { abi: Align(1 bytes), }, @@ -149,10 +149,10 @@ error: layout_of(UninhabitedVariantLargeWithNiche) = Layout { }, fields: Arbitrary { offsets: [ + Size(0 bytes), Size(1 bytes), Size(2 bytes), Size(3 bytes), - Size(4 bytes), ], memory_index: [ 0, @@ -182,7 +182,7 @@ error: layout_of(UninhabitedVariantLargeWithNiche) = Layout { LL | enum UninhabitedVariantLargeWithNiche { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: size: Size(3 bytes) +error: size: Size(2 bytes) --> $DIR/enum.rs:77:1 | LL | enum AllUninhabitedVariants { @@ -224,19 +224,19 @@ error: size: Size(4 bytes) LL | enum TaggedI16 { | ^^^^^^^^^^^^^^ -error: abi: Memory { sized: true } +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(2 bytes) +error: size: Size(0 bytes) --> $DIR/enum.rs:113:1 | LL | enum AllUninhabitedVariantsAlignedZst { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: abi: Scalar(Initialized { value: Int(I16, false), valid_range: 0..=0 }) +error: abi: Memory { sized: true } --> $DIR/enum.rs:113:1 | LL | enum AllUninhabitedVariantsAlignedZst { From 0b658af5e3cd708603324f2b7735cf67cfdbb353 Mon Sep 17 00:00:00 2001 From: Zachary S Date: Tue, 12 Aug 2025 17:36:06 -0500 Subject: [PATCH 6/9] Do not store tag for single-inhabited-variant enums (if this results in a better layout) --- compiler/rustc_abi/src/layout.rs | 159 ++++++++++++++++++++++++-- tests/ui/consts/const-eval/ub-enum.rs | 4 +- tests/ui/layout/enum.rs | 8 +- tests/ui/layout/enum.stderr | 8 +- 4 files changed, 158 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index fd0b9f499c9cc..8c3c0effea067 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -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 }, Align::max_aligned_factor(size)) + } else { + (BackendRepr::SimdVector { element, count }, dl.llvmlike_vector_align(size)) + }; + let size = size.align_to(align); + + 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: AbiAlign::new(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 @@ -807,6 +855,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 @@ -839,10 +890,15 @@ 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 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 @@ -869,6 +925,73 @@ 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. + // + // We keep this as a prospective layout, and don't assume it's better than the tagged + // layout and return it immediately; e.g. 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); @@ -1149,22 +1272,36 @@ impl LayoutCalculator { randomization_seed: combined_seed, }; - let 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. + // 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 better_layout_or_first = + |l1: LayoutData, l2: LayoutData| { use cmp::Ordering::*; let niche_size = |l: &LayoutData| { l.largest_niche.map_or(0, |n| n.available(dl)) }; - match (tl.size.cmp(&nl.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), + }; + + 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) diff --git a/tests/ui/consts/const-eval/ub-enum.rs b/tests/ui/consts/const-eval/ub-enum.rs index 3dfe0c805151e..f0bd6a0bf0711 100644 --- a/tests/ui/consts/const-eval/ub-enum.rs +++ b/tests/ui/consts/const-eval/ub-enum.rs @@ -102,8 +102,8 @@ const BAD_UNINHABITED_WITH_DATA2: Result<(i32, !), (i32, Never)> = unsafe { mem: // 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(0u64) }; -const GOOD_SEMIINHABITED_WITH_DATA2: Result<(i32, !), i32> = unsafe { mem::transmute(1u64) }; +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. diff --git a/tests/ui/layout/enum.rs b/tests/ui/layout/enum.rs index 4d43498cf79df..405875cda8a6a 100644 --- a/tests/ui/layout/enum.rs +++ b/tests/ui/layout/enum.rs @@ -35,8 +35,8 @@ enum AbsentVariantUntagged { //~ERROR: size: Size(4 bytes) // 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(8 bytes) - //~^ ERROR: abi: ScalarPair(Initialized +enum UninhabitedVariantUntagged { //~ERROR: size: Size(4 bytes) + //~^ ERROR: abi: Scalar(Initialized A(i32), B(i32, !), } @@ -53,8 +53,8 @@ enum UninhabitedVariantUntaggedBigger { //~ERROR: size: Size(8 bytes) } #[rustc_layout(size, abi)] -enum UninhabitedVariantWithNiche { //~ERROR: size: Size(3 bytes) - //~^ERROR: abi: Memory +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, !), } diff --git a/tests/ui/layout/enum.stderr b/tests/ui/layout/enum.stderr index 21c66ea3d0fdc..dbeefa73cdff0 100644 --- a/tests/ui/layout/enum.stderr +++ b/tests/ui/layout/enum.stderr @@ -28,13 +28,13 @@ error: abi: Scalar(Initialized { value: Int(I32, true), valid_range: 0..=4294967 LL | enum AbsentVariantUntagged { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: size: Size(8 bytes) +error: size: Size(4 bytes) --> $DIR/enum.rs:38:1 | LL | enum UninhabitedVariantUntagged { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: abi: ScalarPair(Initialized { value: Int(I32, false), valid_range: 0..=0 }, Initialized { value: Int(I32, true), valid_range: 0..=4294967295 }) +error: abi: Scalar(Initialized { value: Int(I32, true), valid_range: 0..=4294967295 }) --> $DIR/enum.rs:38:1 | LL | enum UninhabitedVariantUntagged { @@ -52,13 +52,13 @@ error: abi: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=0 } LL | enum UninhabitedVariantUntaggedBigger { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: size: Size(3 bytes) +error: size: Size(2 bytes) --> $DIR/enum.rs:56:1 | LL | enum UninhabitedVariantWithNiche { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: abi: Memory { sized: true } +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 { From 94526458bec4f817b994b17ccf347cab01aa2c7c Mon Sep 17 00:00:00 2001 From: Zachary S Date: Fri, 29 Aug 2025 21:54:12 -0500 Subject: [PATCH 7/9] Do not hold space for niche in uninhabited variants when using niche-filling layout. --- compiler/rustc_abi/src/layout.rs | 37 ++++++++++++++++++++++------ tests/ui/structs-enums/type-sizes.rs | 12 +++++++-- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 8c3c0effea067..77b09b5ec0666 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -658,12 +658,16 @@ impl LayoutCalculator { let mut align = dl.aggregate_align; let mut max_repr_align = repr.align; let mut unadjusted_abi_align = align; + let mut inhabited_variants = 0; let mut variant_layouts = variants .iter_enumerated() .map(|(j, v)| { let mut st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?; st.variants = Variants::Single { index: j, variants: None }; + if !st.uninhabited { + inhabited_variants += 1; + } align = align.max(st.align.abi); max_repr_align = max_repr_align.max(st.max_repr_align); @@ -673,14 +677,29 @@ impl LayoutCalculator { }) .collect::>>()?; + if inhabited_variants < 2 { + // If there's only one inhabited variant, the no-tag layout will be equivalent to + // what the niched layout would be. Returning `None` here lets us assume there is + // another inhabited variant which simplifies the rest of the layout computation. + return None; + } + + // Choose the largest variant, picking an inhabited variant in a tie let largest_variant_index = variant_layouts .iter_enumerated() - .max_by_key(|(_i, layout)| layout.size.bytes()) + .max_by_key(|(_i, layout)| (layout.size.bytes(), !layout.uninhabited)) .map(|(i, _layout)| i)?; + if variant_layouts[largest_variant_index].uninhabited { + // If the largest variant is uninhabited, then filling its niche would give + // a worse layout than the tagged layout. + return None; + } + let all_indices = variants.indices(); - let needs_disc = - |index: VariantIdx| index != largest_variant_index && !absent(&variants[index]); + let needs_disc = |index: VariantIdx| { + index != largest_variant_index && !variant_layouts[index].uninhabited + }; let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap() ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap(); @@ -697,6 +716,10 @@ impl LayoutCalculator { let all_variants_fit = variant_layouts.iter_enumerated_mut().all(|(i, layout)| { if i == largest_variant_index { return true; + } else if layout.uninhabited { + // This variant doesn't need to hold space for the niche, + // it just needs to be at-most-as big and aligned as the enum. + return layout.size <= size && layout.align.abi <= align; } layout.largest_niche = None; @@ -741,14 +764,14 @@ impl LayoutCalculator { let largest_niche = Niche::from_scalar(dl, niche_offset, niche_scalar); - let others_zst = variant_layouts - .iter_enumerated() - .all(|(i, layout)| i == largest_variant_index || layout.size == Size::ZERO); + let others_zst_or_uninhabited = variant_layouts.iter_enumerated().all(|(i, layout)| { + i == largest_variant_index || layout.size == Size::ZERO || layout.uninhabited + }); let same_size = size == variant_layouts[largest_variant_index].size; let same_align = align == variant_layouts[largest_variant_index].align.abi; let uninhabited = variant_layouts.iter().all(|v| v.is_uninhabited()); - let abi = if same_size && same_align && others_zst { + let abi = if same_size && same_align && others_zst_or_uninhabited { match variant_layouts[largest_variant_index].backend_repr { // When the total alignment and size match, we can use the // same ABI as the scalar variant with the reserved niche. diff --git a/tests/ui/structs-enums/type-sizes.rs b/tests/ui/structs-enums/type-sizes.rs index a8fadcc1d1ec6..daa7a8b1cf6db 100644 --- a/tests/ui/structs-enums/type-sizes.rs +++ b/tests/ui/structs-enums/type-sizes.rs @@ -277,8 +277,16 @@ pub fn main() { assert_eq!(size_of::(), 1); assert_eq!(size_of::(), 1); - assert_eq!(size_of::>(), - size_of::>()); + assert_eq!(size_of::>(), 2 * size_of::<&'static ()>()); + assert_eq!(size_of::>(), size_of::<&'static ()>()); + assert_eq!( + size_of::>(), + 2 * size_of::<&'static ()>(), + ); + assert_eq!( + size_of::>(), + 2 * size_of::<&'static ()>(), + ); assert_eq!(size_of::(), size_of::<&'static ()>()); assert_eq!(size_of::(), 24); From fb682a30d057c2512054e3c95e36c742371c81ed Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sun, 5 Oct 2025 13:50:31 -0500 Subject: [PATCH 8/9] Fix enum layout to use niche-filling layout in guaranteed-NPO cases, even when the niche is in an uninhabited variant. --- compiler/rustc_abi/src/layout.rs | 87 ++++++++++++++++------- tests/ui/layout/enum.rs | 92 ++++++++++++++++++++++++ tests/ui/layout/enum.stderr | 116 ++++++++++++++++++++++++++++++- 3 files changed, 267 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 77b09b5ec0666..3133856d8c2f8 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -646,7 +646,10 @@ impl LayoutCalculator { return Err(LayoutCalculatorError::ReprConflict); } - let calculate_niche_filling_layout = || -> Option> { + // Returns `(layout, is_this_maybe_npo)`. + // If `is_this_maybe_npo` is true, this layout is preferred over the tagged and + // no-tag layouts. + let calculate_niche_filling_layout = || -> Option<(LayoutData<_, _>, bool)> { if repr.inhibit_enum_layout_opt() { return None; } @@ -658,16 +661,12 @@ impl LayoutCalculator { let mut align = dl.aggregate_align; let mut max_repr_align = repr.align; let mut unadjusted_abi_align = align; - let mut inhabited_variants = 0; let mut variant_layouts = variants .iter_enumerated() .map(|(j, v)| { let mut st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?; st.variants = Variants::Single { index: j, variants: None }; - if !st.uninhabited { - inhabited_variants += 1; - } align = align.max(st.align.abi); max_repr_align = max_repr_align.max(st.max_repr_align); @@ -677,41 +676,66 @@ impl LayoutCalculator { }) .collect::>>()?; - if inhabited_variants < 2 { - // If there's only one inhabited variant, the no-tag layout will be equivalent to - // what the niched layout would be. Returning `None` here lets us assume there is - // another inhabited variant which simplifies the rest of the layout computation. - return None; - } - - // Choose the largest variant, picking an inhabited variant in a tie + // Choose the largest variant, picking an inhabited variant in a tie. + // We still need to compute the niche-filling layout even if the largest variant + // is uninhabited, because `Result` needs to + // still be NPO-optimized. let largest_variant_index = variant_layouts .iter_enumerated() .max_by_key(|(_i, layout)| (layout.size.bytes(), !layout.uninhabited)) .map(|(i, _layout)| i)?; - if variant_layouts[largest_variant_index].uninhabited { - // If the largest variant is uninhabited, then filling its niche would give - // a worse layout than the tagged layout. - return None; - } + // Use the largest niche in the largest variant. + let niche = variant_layouts[largest_variant_index].largest_niche?; + let niche_offset = niche.offset; + let niche_size = niche.value.size(dl); + let size = variant_layouts[largest_variant_index].size.align_to(align); + // If the niche occupies the whole size of the enum, + // this could be a case of NPO, so we should prefer this layout over the + // tagged and no-tag layouts, even if it has a worse niche (due to the + // niched variant being uninhabited) + let is_maybe_npo = niche_size == size; let all_indices = variants.indices(); let needs_disc = |index: VariantIdx| { index != largest_variant_index && !variant_layouts[index].uninhabited }; - let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap() - ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap(); + let first_niche_variant = all_indices.clone().find(|v| needs_disc(*v)); + let last_niche_variant = all_indices.clone().rev().find(|v| needs_disc(*v)); + let niche_variants = match Option::zip(first_niche_variant, last_niche_variant) { + Some((f, l)) => f..=l, + // All non-largest variants are uninhabited. + // If there are exactly 2 variants, and the largest variant's niche covers its + // whole size, and the non-largest variant is 1-aligned and zero-sized, + // this could be NPO. + // However, that only happens if the non-largest variant is "absent", + // which was already handled in `layout_of_struct_or_enum`, so we just debug_assert + // that that is not the case. + None if variants.len() == 2 && is_maybe_npo => { + if cfg!(debug_assertions) { + let non_largest_variant_index = + all_indices.clone().find(|v| *v != largest_variant_index).unwrap(); + let non_largest_variant_layout = + &variant_layouts[non_largest_variant_index]; + debug_assert!( + non_largest_variant_layout.size > Size::ZERO + || non_largest_variant_layout.align.abi > Align::ONE + ); + } + // The non-largest variant is not 1-ZST, this cannot be NPO, + // use the no-tag layout. + return None; + } + // All non-largest variants are uninhabited. + // This cannot be NPO, use the no-tag layout. + None => return None, + }; let count = (niche_variants.end().index() as u128 - niche_variants.start().index() as u128) + 1; - // Use the largest niche in the largest variant. - let niche = variant_layouts[largest_variant_index].largest_niche?; + // Calculate the new niche. let (niche_start, niche_scalar) = niche.reserve(dl, count)?; - let niche_offset = niche.offset; - let niche_size = niche.value.size(dl); - let size = variant_layouts[largest_variant_index].size.align_to(align); let all_variants_fit = variant_layouts.iter_enumerated_mut().all(|(i, layout)| { if i == largest_variant_index { @@ -821,10 +845,19 @@ impl LayoutCalculator { randomization_seed: combined_seed, }; - Some(layout) + Some((layout, is_maybe_npo)) }; - let niche_filling_layout = calculate_niche_filling_layout(); + let niche_filling_layout = match calculate_niche_filling_layout() { + // If this is possibly NPO, we prefer this layout over the others, + // even if they might have a better niche. + // (They could never be smaller, since possibly-npo only occurs + // when the niche fills the whole size of the enum.) + Some((layout, true)) => return Ok(layout), + // This is definitely not NPO, try the other layouts. + Some((layout, false)) => Some(layout), + None => None, + }; let discr_type = repr.discr_type(); let discr_int = Integer::from_attr(dl, discr_type); diff --git a/tests/ui/layout/enum.rs b/tests/ui/layout/enum.rs index 405875cda8a6a..b6ffb6f7f6331 100644 --- a/tests/ui/layout/enum.rs +++ b/tests/ui/layout/enum.rs @@ -115,3 +115,95 @@ enum AllUninhabitedVariantsAlignedZst { //~ERROR: size: Size(0 bytes) A(AlignedNever), B(AlignedNever), } + + +#[repr(transparent)] +struct NPONever(&'static (), !); + +#[repr(transparent)] +struct NPONeverI16(std::num::NonZero, !); + +// All of these should be NPO-optimized, despite uninhabitedness of one or more variants +#[rustc_layout(abi)] +type NPONever1 = Result; +//~^ ERROR: abi: Scalar(Initialized { value: Pointer + +#[rustc_layout(abi)] +type NPONever2 = Result<(), NPONever>; +//~^ ERROR: abi: Scalar(Initialized { value: Pointer + +#[rustc_layout(abi)] +type NPONever3 = Result; +//~^ ERROR: abi: Scalar(Initialized { value: Pointer + +#[rustc_layout(abi)] +type NPONever4 = Result; +//~^ ERROR: abi: Scalar(Initialized { value: Pointer + +#[rustc_layout(abi)] +type NPONever5 = Result<&'static (), !>; +//~^ ERROR: abi: Scalar(Initialized { value: Pointer + +#[rustc_layout(abi)] +type NPONever6 = Result; +//~^ ERROR: abi: Scalar(Initialized { value: Pointer + +#[rustc_layout(abi)] +type NPONever7 = Result, !>; +//~^ERROR: abi: Scalar(Initialized { value: Int(I16 + +#[rustc_layout(abi)] +type NPONever8 = Result>; +//~^ERROR: abi: Scalar(Initialized { value: Int(I16 + +#[rustc_layout(abi)] +type NPONever9 = Result; +//~^ERROR: abi: Scalar(Initialized { value: Int(I16 + +#[rustc_layout(abi)] +type NPONever10 = Result; +//~^ERROR: abi: Scalar(Initialized { value: Int(I16 + +#[rustc_layout(abi)] +type NPONever11 = Result; +//~^ERROR: abi: Scalar(Initialized { value: Int(I16 + +#[rustc_layout(abi)] +type NPONever12 = Result<(), NPONeverI16>; +//~^ERROR: abi: Scalar(Initialized { value: Int(I16 + +#[rustc_layout(abi)] +enum NPONever13 { //~ERROR: abi: Scalar(Initialized { value: Pointer + A(!, &'static (), !), + B((), !, [u8; 0]), +} + +#[rustc_layout(abi)] +enum NPONever14 { //~ERROR: abi: Scalar(Initialized { value: Pointer + A(!, &'static (), !), + B((), (), [u8; 0]), +} + +#[rustc_layout(abi)] +enum NPONever15 { //~ERROR: abi: Scalar(Initialized { value: Pointer + A((), &'static (), ()), + B((), !, [u8; 0]), +} + + +// These are not guaranteed to be NPO-optimized +#[rustc_layout(abi)] +type NotNPONever1 = Result; +//~^ERROR: abi: Scalar( + +#[rustc_layout(abi)] +type NotNPONever2 = Result; +//~^ERROR: abi: Memory + +#[rustc_layout(abi)] +type NotNPONever3 = Result; +//~^ERROR: abi: Scalar( + +#[rustc_layout(abi)] +type NotNPONever4 = Result<&'static (), AlignedNever>; +//~^ERROR: abi: Scalar( diff --git a/tests/ui/layout/enum.stderr b/tests/ui/layout/enum.stderr index dbeefa73cdff0..4eb5d4d73c0d5 100644 --- a/tests/ui/layout/enum.stderr +++ b/tests/ui/layout/enum.stderr @@ -242,5 +242,119 @@ error: abi: Memory { sized: true } LL | enum AllUninhabitedVariantsAlignedZst { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 22 previous errors +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: (..=0) | (1..) }) + --> $DIR/enum.rs:128:1 + | +LL | type NPONever1 = Result; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: (..=0) | (1..) }) + --> $DIR/enum.rs:132:1 + | +LL | type NPONever2 = Result<(), NPONever>; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) + --> $DIR/enum.rs:136:1 + | +LL | type NPONever3 = Result; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) + --> $DIR/enum.rs:140:1 + | +LL | type NPONever4 = Result; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) + --> $DIR/enum.rs:144:1 + | +LL | type NPONever5 = Result<&'static (), !>; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) + --> $DIR/enum.rs:148:1 + | +LL | type NPONever6 = Result; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: 1..=65535 }) + --> $DIR/enum.rs:152:1 + | +LL | type NPONever7 = Result, !>; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: 1..=65535 }) + --> $DIR/enum.rs:156:1 + | +LL | type NPONever8 = Result>; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: 1..=65535 }) + --> $DIR/enum.rs:160:1 + | +LL | type NPONever9 = Result; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: 1..=65535 }) + --> $DIR/enum.rs:164:1 + | +LL | type NPONever10 = Result; + | ^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: (..=0) | (1..) }) + --> $DIR/enum.rs:168:1 + | +LL | type NPONever11 = Result; + | ^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: (..=0) | (1..) }) + --> $DIR/enum.rs:172:1 + | +LL | type NPONever12 = Result<(), NPONeverI16>; + | ^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) + --> $DIR/enum.rs:176:1 + | +LL | enum NPONever13 { + | ^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: (..=0) | (1..) }) + --> $DIR/enum.rs:182:1 + | +LL | enum NPONever14 { + | ^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) + --> $DIR/enum.rs:188:1 + | +LL | enum NPONever15 { + | ^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I64, false), valid_range: 0..=0 }) + --> $DIR/enum.rs:196:1 + | +LL | type NotNPONever1 = Result; + | ^^^^^^^^^^^^^^^^^ + +error: abi: Memory { sized: true } + --> $DIR/enum.rs:200:1 + | +LL | type NotNPONever2 = Result; + | ^^^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) + --> $DIR/enum.rs:204:1 + | +LL | type NotNPONever3 = Result; + | ^^^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) + --> $DIR/enum.rs:208:1 + | +LL | type NotNPONever4 = Result<&'static (), AlignedNever>; + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 41 previous errors From e8d40a60aa88e257e71ea9932b4725c9f986a6cd Mon Sep 17 00:00:00 2001 From: Zachary S Date: Sun, 5 Oct 2025 16:17:21 -0500 Subject: [PATCH 9/9] Revisions for pointer size --- tests/ui/layout/enum.bit32.stderr | 360 ++++++++++++++++++ .../layout/{enum.stderr => enum.bit64.stderr} | 82 ++-- tests/ui/layout/enum.rs | 5 +- 3 files changed, 405 insertions(+), 42 deletions(-) create mode 100644 tests/ui/layout/enum.bit32.stderr rename tests/ui/layout/{enum.stderr => enum.bit64.stderr} (90%) diff --git a/tests/ui/layout/enum.bit32.stderr b/tests/ui/layout/enum.bit32.stderr new file mode 100644 index 0000000000000..1228c16aaf939 --- /dev/null +++ b/tests/ui/layout/enum.bit32.stderr @@ -0,0 +1,360 @@ +error: align: AbiAlign { abi: Align(2 bytes) } + --> $DIR/enum.rs:12:1 + | +LL | enum UninhabitedVariantAlign { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(15 bytes) + --> $DIR/enum.rs:18:1 + | +LL | enum UninhabitedVariantSpace { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=1 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }) + --> $DIR/enum.rs:24:1 + | +LL | enum ScalarPairDifferingSign { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(4 bytes) + --> $DIR/enum.rs:32:1 + | +LL | enum AbsentVariantUntagged { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I32, true), valid_range: 0..=4294967295 }) + --> $DIR/enum.rs:32:1 + | +LL | enum AbsentVariantUntagged { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(4 bytes) + --> $DIR/enum.rs:41:1 + | +LL | enum UninhabitedVariantUntagged { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I32, true), valid_range: 0..=4294967295 }) + --> $DIR/enum.rs:41:1 + | +LL | enum UninhabitedVariantUntagged { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(8 bytes) + --> $DIR/enum.rs:52: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:52:1 + | +LL | enum UninhabitedVariantUntaggedBigger { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(2 bytes) + --> $DIR/enum.rs:59: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:59: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:66:1 + | +LL | enum UninhabitedVariantLargeWithNiche { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(2 bytes) + --> $DIR/enum.rs:80:1 + | +LL | enum AllUninhabitedVariants { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: Memory { sized: true } + --> $DIR/enum.rs:80:1 + | +LL | enum AllUninhabitedVariants { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: size: Size(2 bytes) + --> $DIR/enum.rs:91:1 + | +LL | enum AlignedI8 { + | ^^^^^^^^^^^^^^ + +error: abi: Memory { sized: true } + --> $DIR/enum.rs:91:1 + | +LL | enum AlignedI8 { + | ^^^^^^^^^^^^^^ + +error: size: Size(4 bytes) + --> $DIR/enum.rs:99:1 + | +LL | enum TaggedI8 { + | ^^^^^^^^^^^^^ + +error: abi: Memory { sized: true } + --> $DIR/enum.rs:99:1 + | +LL | enum TaggedI8 { + | ^^^^^^^^^^^^^ + +error: size: Size(4 bytes) + --> $DIR/enum.rs:108: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:108:1 + | +LL | enum TaggedI16 { + | ^^^^^^^^^^^^^^ + +error: size: Size(0 bytes) + --> $DIR/enum.rs:116:1 + | +LL | enum AllUninhabitedVariantsAlignedZst { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: Memory { sized: true } + --> $DIR/enum.rs:116:1 + | +LL | enum AllUninhabitedVariantsAlignedZst { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: (..=0) | (1..) }) + --> $DIR/enum.rs:131:1 + | +LL | type NPONever1 = Result; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: (..=0) | (1..) }) + --> $DIR/enum.rs:135:1 + | +LL | type NPONever2 = Result<(), NPONever>; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=4294967295 }) + --> $DIR/enum.rs:139:1 + | +LL | type NPONever3 = Result; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=4294967295 }) + --> $DIR/enum.rs:143:1 + | +LL | type NPONever4 = Result; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=4294967295 }) + --> $DIR/enum.rs:147:1 + | +LL | type NPONever5 = Result<&'static (), !>; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=4294967295 }) + --> $DIR/enum.rs:151:1 + | +LL | type NPONever6 = Result; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: 1..=65535 }) + --> $DIR/enum.rs:155:1 + | +LL | type NPONever7 = Result, !>; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: 1..=65535 }) + --> $DIR/enum.rs:159:1 + | +LL | type NPONever8 = Result>; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: 1..=65535 }) + --> $DIR/enum.rs:163:1 + | +LL | type NPONever9 = Result; + | ^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: 1..=65535 }) + --> $DIR/enum.rs:167:1 + | +LL | type NPONever10 = Result; + | ^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: (..=0) | (1..) }) + --> $DIR/enum.rs:171:1 + | +LL | type NPONever11 = Result; + | ^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: (..=0) | (1..) }) + --> $DIR/enum.rs:175:1 + | +LL | type NPONever12 = Result<(), NPONeverI16>; + | ^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=4294967295 }) + --> $DIR/enum.rs:179:1 + | +LL | enum NPONever13 { + | ^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: (..=0) | (1..) }) + --> $DIR/enum.rs:185:1 + | +LL | enum NPONever14 { + | ^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=4294967295 }) + --> $DIR/enum.rs:191:1 + | +LL | enum NPONever15 { + | ^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Int(I32, false), valid_range: 0..=0 }) + --> $DIR/enum.rs:199:1 + | +LL | type NotNPONever1 = Result; + | ^^^^^^^^^^^^^^^^^ + +error: abi: Memory { sized: true } + --> $DIR/enum.rs:203:1 + | +LL | type NotNPONever2 = Result; + | ^^^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=4294967295 }) + --> $DIR/enum.rs:207:1 + | +LL | type NotNPONever3 = Result; + | ^^^^^^^^^^^^^^^^^ + +error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=4294967295 }) + --> $DIR/enum.rs:211:1 + | +LL | type NotNPONever4 = Result<&'static (), AlignedNever>; + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 41 previous errors + diff --git a/tests/ui/layout/enum.stderr b/tests/ui/layout/enum.bit64.stderr similarity index 90% rename from tests/ui/layout/enum.stderr rename to tests/ui/layout/enum.bit64.stderr index 4eb5d4d73c0d5..6d205c7edea56 100644 --- a/tests/ui/layout/enum.stderr +++ b/tests/ui/layout/enum.bit64.stderr @@ -1,65 +1,65 @@ error: align: AbiAlign { abi: Align(2 bytes) } - --> $DIR/enum.rs:9:1 + --> $DIR/enum.rs:12:1 | LL | enum UninhabitedVariantAlign { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: size: Size(15 bytes) - --> $DIR/enum.rs:15:1 + --> $DIR/enum.rs:18:1 | LL | enum UninhabitedVariantSpace { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: abi: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=1 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }) - --> $DIR/enum.rs:21:1 + --> $DIR/enum.rs:24:1 | LL | enum ScalarPairDifferingSign { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: size: Size(4 bytes) - --> $DIR/enum.rs:29:1 + --> $DIR/enum.rs:32:1 | LL | enum AbsentVariantUntagged { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Int(I32, true), valid_range: 0..=4294967295 }) - --> $DIR/enum.rs:29:1 + --> $DIR/enum.rs:32:1 | LL | enum AbsentVariantUntagged { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: size: Size(4 bytes) - --> $DIR/enum.rs:38:1 + --> $DIR/enum.rs:41:1 | LL | enum UninhabitedVariantUntagged { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Int(I32, true), valid_range: 0..=4294967295 }) - --> $DIR/enum.rs:38:1 + --> $DIR/enum.rs:41:1 | LL | enum UninhabitedVariantUntagged { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: size: Size(8 bytes) - --> $DIR/enum.rs:49:1 + --> $DIR/enum.rs:52: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 + --> $DIR/enum.rs:52:1 | LL | enum UninhabitedVariantUntaggedBigger { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: size: Size(2 bytes) - --> $DIR/enum.rs:56:1 + --> $DIR/enum.rs:59: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 + --> $DIR/enum.rs:59:1 | LL | enum UninhabitedVariantWithNiche { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -177,181 +177,181 @@ error: layout_of(UninhabitedVariantLargeWithNiche) = Layout { unadjusted_abi_align: Align(1 bytes), randomization_seed: 15362464571658798427, } - --> $DIR/enum.rs:63:1 + --> $DIR/enum.rs:66:1 | LL | enum UninhabitedVariantLargeWithNiche { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: size: Size(2 bytes) - --> $DIR/enum.rs:77:1 + --> $DIR/enum.rs:80:1 | LL | enum AllUninhabitedVariants { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: abi: Memory { sized: true } - --> $DIR/enum.rs:77:1 + --> $DIR/enum.rs:80:1 | LL | enum AllUninhabitedVariants { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: size: Size(2 bytes) - --> $DIR/enum.rs:88:1 + --> $DIR/enum.rs:91:1 | LL | enum AlignedI8 { | ^^^^^^^^^^^^^^ error: abi: Memory { sized: true } - --> $DIR/enum.rs:88:1 + --> $DIR/enum.rs:91:1 | LL | enum AlignedI8 { | ^^^^^^^^^^^^^^ error: size: Size(4 bytes) - --> $DIR/enum.rs:96:1 + --> $DIR/enum.rs:99:1 | LL | enum TaggedI8 { | ^^^^^^^^^^^^^ error: abi: Memory { sized: true } - --> $DIR/enum.rs:96:1 + --> $DIR/enum.rs:99:1 | LL | enum TaggedI8 { | ^^^^^^^^^^^^^ error: size: Size(4 bytes) - --> $DIR/enum.rs:105:1 + --> $DIR/enum.rs:108: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 + --> $DIR/enum.rs:108:1 | LL | enum TaggedI16 { | ^^^^^^^^^^^^^^ error: size: Size(0 bytes) - --> $DIR/enum.rs:113:1 + --> $DIR/enum.rs:116:1 | LL | enum AllUninhabitedVariantsAlignedZst { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: abi: Memory { sized: true } - --> $DIR/enum.rs:113:1 + --> $DIR/enum.rs:116:1 | LL | enum AllUninhabitedVariantsAlignedZst { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: (..=0) | (1..) }) - --> $DIR/enum.rs:128:1 + --> $DIR/enum.rs:131:1 | LL | type NPONever1 = Result; | ^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: (..=0) | (1..) }) - --> $DIR/enum.rs:132:1 + --> $DIR/enum.rs:135:1 | LL | type NPONever2 = Result<(), NPONever>; | ^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) - --> $DIR/enum.rs:136:1 + --> $DIR/enum.rs:139:1 | LL | type NPONever3 = Result; | ^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) - --> $DIR/enum.rs:140:1 + --> $DIR/enum.rs:143:1 | LL | type NPONever4 = Result; | ^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) - --> $DIR/enum.rs:144:1 + --> $DIR/enum.rs:147:1 | LL | type NPONever5 = Result<&'static (), !>; | ^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) - --> $DIR/enum.rs:148:1 + --> $DIR/enum.rs:151:1 | LL | type NPONever6 = Result; | ^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: 1..=65535 }) - --> $DIR/enum.rs:152:1 + --> $DIR/enum.rs:155:1 | LL | type NPONever7 = Result, !>; | ^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: 1..=65535 }) - --> $DIR/enum.rs:156:1 + --> $DIR/enum.rs:159:1 | LL | type NPONever8 = Result>; | ^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: 1..=65535 }) - --> $DIR/enum.rs:160:1 + --> $DIR/enum.rs:163:1 | LL | type NPONever9 = Result; | ^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: 1..=65535 }) - --> $DIR/enum.rs:164:1 + --> $DIR/enum.rs:167:1 | LL | type NPONever10 = Result; | ^^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: (..=0) | (1..) }) - --> $DIR/enum.rs:168:1 + --> $DIR/enum.rs:171:1 | LL | type NPONever11 = Result; | ^^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Int(I16, true), valid_range: (..=0) | (1..) }) - --> $DIR/enum.rs:172:1 + --> $DIR/enum.rs:175:1 | LL | type NPONever12 = Result<(), NPONeverI16>; | ^^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) - --> $DIR/enum.rs:176:1 + --> $DIR/enum.rs:179:1 | LL | enum NPONever13 { | ^^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: (..=0) | (1..) }) - --> $DIR/enum.rs:182:1 + --> $DIR/enum.rs:185:1 | LL | enum NPONever14 { | ^^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) - --> $DIR/enum.rs:188:1 + --> $DIR/enum.rs:191:1 | LL | enum NPONever15 { | ^^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Int(I64, false), valid_range: 0..=0 }) - --> $DIR/enum.rs:196:1 + --> $DIR/enum.rs:199:1 | LL | type NotNPONever1 = Result; | ^^^^^^^^^^^^^^^^^ error: abi: Memory { sized: true } - --> $DIR/enum.rs:200:1 + --> $DIR/enum.rs:203:1 | LL | type NotNPONever2 = Result; | ^^^^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) - --> $DIR/enum.rs:204:1 + --> $DIR/enum.rs:207:1 | LL | type NotNPONever3 = Result; | ^^^^^^^^^^^^^^^^^ error: abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }) - --> $DIR/enum.rs:208:1 + --> $DIR/enum.rs:211:1 | LL | type NotNPONever4 = Result<&'static (), AlignedNever>; | ^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/layout/enum.rs b/tests/ui/layout/enum.rs index b6ffb6f7f6331..81ad547e2013a 100644 --- a/tests/ui/layout/enum.rs +++ b/tests/ui/layout/enum.rs @@ -1,4 +1,7 @@ //@ normalize-stderr: "pref: Align\([1-8] bytes\)" -> "pref: $$PREF_ALIGN" +//@ revisions: bit32 bit64 +//@[bit32] only-32bit +//@[bit64] only-64bit //! Various enum layout tests. #![feature(rustc_attrs)] @@ -194,7 +197,7 @@ enum NPONever15 { //~ERROR: abi: Scalar(Initialized { value: Pointer // These are not guaranteed to be NPO-optimized #[rustc_layout(abi)] type NotNPONever1 = Result; -//~^ERROR: abi: Scalar( +//~^ERROR: abi: Scalar(Initialized { value: Int #[rustc_layout(abi)] type NotNPONever2 = Result;