From a610961b5be7884e4d7aed19a4f360ad9960c533 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2024 17:33:01 +0100 Subject: [PATCH] make no-variant types a dedicated Variants variant --- compiler/rustc_abi/src/callconv.rs | 2 +- compiler/rustc_abi/src/layout.rs | 19 +++++++------- compiler/rustc_abi/src/lib.rs | 10 ++++--- .../src/debuginfo/metadata/enums/cpp_like.rs | 26 +++++++++---------- .../src/debuginfo/metadata/enums/mod.rs | 2 +- .../src/debuginfo/metadata/enums/native.rs | 4 +-- compiler/rustc_codegen_llvm/src/type_of.rs | 6 ++--- .../rustc_codegen_ssa/src/debuginfo/mod.rs | 4 +-- compiler/rustc_codegen_ssa/src/mir/place.rs | 9 ++++--- .../src/interpret/discriminant.rs | 6 ++++- .../src/interpret/validity.rs | 9 +++---- .../rustc_const_eval/src/interpret/visitor.rs | 4 +-- .../src/util/check_validity_requirement.rs | 1 + compiler/rustc_middle/src/ty/layout.rs | 20 +++++++------- .../rustc_mir_transform/src/large_enums.rs | 2 +- .../src/unreachable_enum_branching.rs | 4 +-- .../rustc_smir/src/rustc_smir/convert/abi.rs | 7 ++--- .../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 | 15 +++++------ compiler/rustc_ty_utils/src/layout.rs | 16 ++++++------ .../rustc_ty_utils/src/layout/invariant.rs | 8 +++--- compiler/stable_mir/src/abi.rs | 4 ++- src/tools/miri/src/helpers.rs | 2 +- 25 files changed, 96 insertions(+), 90 deletions(-) diff --git a/compiler/rustc_abi/src/callconv.rs b/compiler/rustc_abi/src/callconv.rs index ee63e46e88c1d..400395f99ff01 100644 --- a/compiler/rustc_abi/src/callconv.rs +++ b/compiler/rustc_abi/src/callconv.rs @@ -206,7 +206,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?; match &self.variants { - abi::Variants::Single { .. } => {} + abi::Variants::Single { .. } | abi::Variants::Empty => {} abi::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 f2b50ae408e9c..226a46f605cc4 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -120,7 +120,7 @@ impl LayoutCalculator { .max_by_key(|niche| niche.available(dl)); LayoutData { - variants: Variants::Single { index: Some(VariantIdx::new(0)) }, + variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets: [Size::ZERO, b_offset].into(), memory_index: [0, 1].into(), @@ -213,8 +213,9 @@ impl LayoutCalculator { &self, ) -> LayoutData { let dl = self.cx.data_layout(); + // This is also used for uninhabited enums, so we use `Variants::Empty`. LayoutData { - variants: Variants::Single { index: None }, + variants: Variants::Empty, fields: FieldsShape::Primitive, backend_repr: BackendRepr::Uninhabited, largest_niche: None, @@ -385,7 +386,7 @@ impl LayoutCalculator { }; Ok(LayoutData { - variants: Variants::Single { index: Some(only_variant_idx) }, + variants: Variants::Single { index: only_variant_idx }, fields: FieldsShape::Union(union_field_count), backend_repr: abi, largest_niche: None, @@ -424,7 +425,7 @@ impl LayoutCalculator { }; let mut st = self.univariant(&variants[v], repr, kind)?; - st.variants = Variants::Single { index: Some(v) }; + st.variants = Variants::Single { index: v }; if is_unsafe_cell { let hide_niches = |scalar: &mut _| match scalar { @@ -543,7 +544,7 @@ impl LayoutCalculator { .iter_enumerated() .map(|(j, v)| { let mut st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?; - st.variants = Variants::Single { index: Some(j) }; + st.variants = Variants::Single { index: j }; align = align.max(st.align); max_repr_align = max_repr_align.max(st.max_repr_align); @@ -736,7 +737,7 @@ impl LayoutCalculator { repr, StructKind::Prefixed(min_ity.size(), prefix_align), )?; - st.variants = Variants::Single { index: Some(i) }; + st.variants = Variants::Single { index: i }; // 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() { @@ -1004,8 +1005,8 @@ impl LayoutCalculator { Variants::Multiple { tag, tag_encoding, tag_field, .. } => { Variants::Multiple { tag, tag_encoding, tag_field, variants: best_layout.variants } } - Variants::Single { .. } => { - panic!("encountered a single-variant enum during multi-variant layout") + Variants::Single { .. } | Variants::Empty => { + panic!("encountered a single-variant or empty enum during multi-variant layout") } }; Ok(best_layout.layout) @@ -1344,7 +1345,7 @@ impl LayoutCalculator { }; Ok(LayoutData { - variants: Variants::Single { index: Some(VariantIdx::new(0)) }, + variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets, memory_index }, backend_repr: abi, largest_niche, diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 242e2cadd18a3..ca15f7d992051 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1504,11 +1504,13 @@ impl BackendRepr { #[derive(PartialEq, Eq, Hash, Clone, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_Generic))] pub enum Variants { + /// A type with no valid variants. Must be uninhabited. + Empty, + /// Single enum variants, structs/tuples, unions, and all non-ADTs. Single { - /// Always `Some(0)` for types without variants (i.e., everything except for `!`, enums, and - /// generators). `None` indicates an uninhabited type; this is used for zero-variant enums. - index: Option, + /// Always `0` for types that cannot have multiple variants. + index: VariantIdx, }, /// Enum-likes with more than one variant: each variant comes with @@ -1706,7 +1708,7 @@ impl LayoutData { let size = scalar.size(cx); let align = scalar.align(cx); LayoutData { - variants: Variants::Single { index: Some(VariantIdx::new(0)) }, + variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, backend_repr: BackendRepr::Scalar(scalar), largest_niche, 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 7e5def28de07a..839cd69184ad6 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 @@ -205,21 +205,18 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>( ), |cx, enum_type_di_node| { match enum_type_and_layout.variants { - Variants::Single { index: variant_index } => { - let Some(variant_index) = variant_index else { - // Uninhabited enums have Variants::Single. We don't generate - // any members for them. - return smallvec![]; - }; - - build_single_variant_union_fields( - cx, - enum_adt_def, - enum_type_and_layout, - enum_type_di_node, - variant_index, - ) + Variants::Empty => { + // Uninhabited enums have Variants::Single. We don't generate + // any members for them. + return smallvec![]; } + Variants::Single { index: variant_index } => build_single_variant_union_fields( + cx, + enum_adt_def, + enum_type_and_layout, + enum_type_di_node, + variant_index, + ), Variants::Multiple { tag_encoding: TagEncoding::Direct, ref variants, @@ -287,6 +284,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>( ) } Variants::Single { .. } + | 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 b3d4a6642a16c..703fbe498e530 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -366,7 +366,7 @@ fn compute_discriminant_value<'ll, 'tcx>( variant_index: VariantIdx, ) -> DiscrResult { match enum_type_and_layout.layout.variants() { - &Variants::Single { .. } => 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 d4006691d377e..f862d85b78f91 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -316,8 +316,8 @@ fn build_discr_member_di_node<'ll, 'tcx>( let containing_scope = enum_or_coroutine_type_di_node; match enum_or_coroutine_type_and_layout.layout.variants() { - // A single-variant enum has no discriminant. - &Variants::Single { .. } => None, + // A single-variant or no-variant enum has no discriminant. + &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 833a687fe7423..b0b6da869da68 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -35,14 +35,14 @@ fn uncached_llvm_type<'a, 'tcx>( if !cx.sess().fewer_names() => { let mut name = with_no_visible_paths!(with_no_trimmed_paths!(layout.ty.to_string())); - if let (&ty::Adt(def, _), &Variants::Single { index: Some(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: Some(index) }) = + if let (&ty::Coroutine(_, _), &Variants::Single { index }) = (layout.ty.kind(), &layout.variants) { write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap(); @@ -216,7 +216,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // Check the cache. let variant_index = match self.variants { - Variants::Single { index } => 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 88d36b19da432..7c62c03d574c1 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs @@ -65,8 +65,8 @@ fn tag_base_type_opt<'tcx>( }); match enum_type_and_layout.layout.variants() { - // A single-variant enum has no discriminant. - Variants::Single { .. } => None, + // A single-variant or no-variant enum has no discriminant. + 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/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 7c7a0c7c6f691..c82b9822b7274 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -242,8 +242,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { return bx.cx().const_poison(cast_to); } let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants { + Variants::Empty => unreachable!("we already handled uninhabited types"), Variants::Single { index } => { - let index = index.unwrap(); // we already checked `is_uninhabited` + // we already checked `is_uninhabited` let discr_val = self .layout .ty @@ -365,9 +366,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { return; } match self.layout.variants { - Variants::Single { index } => { - assert_eq!(index.unwrap(), variant_index); - } + Variants::Empty => unreachable!("we already handled uninhabited types"), + Variants::Single { index } => assert_eq!(index, variant_index), + Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => { let ptr = self.project_field(bx, tag_field); let to = diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs index 6cfd1613229b0..83150acc59c19 100644 --- a/compiler/rustc_const_eval/src/interpret/discriminant.rs +++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs @@ -65,6 +65,9 @@ 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 => { + throw_ub!(UninhabitedEnumVariantRead(None)); + } Variants::Single { index } => { if op.layout().is_uninhabited() { // For consistency with `write_discriminant`, and to make sure that @@ -73,7 +76,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { throw_ub!(UninhabitedEnumVariantRead(None)); } // Since the type is inhabited, there must be an index. - return interp_ok(index.unwrap()); + return interp_ok(index); } Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => { (tag, tag_encoding, tag_field) @@ -238,6 +241,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } match layout.variants { + 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 f285f5f0bac74..005a73d5a0ca9 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -302,7 +302,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { }; } } - Variants::Single { .. } => {} + Variants::Single { .. } | Variants::Empty => {} } // Now we know we are projecting to a field, so figure out which one. @@ -342,10 +342,9 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { match layout.variants { Variants::Single { index } => { // Inside a variant - PathElem::Field( - def.variant(index.unwrap()).fields[FieldIdx::from_usize(field)].name, - ) + PathElem::Field(def.variant(index).fields[FieldIdx::from_usize(field)].name) } + Variants::Empty => panic!("there is no field in Variants::Empty types"), Variants::Multiple { .. } => bug!("we handled variants above"), } } @@ -1012,7 +1011,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> { } // Don't forget potential other variants. match &layout.variants { - Variants::Single { .. } => { + 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 76ab0bb544f05..3647c109a6ed4 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -218,8 +218,8 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized { // recurse with the inner type self.visit_variant(v, idx, &inner)?; } - // For single-variant layouts, we already did anything there is to do. - Variants::Single { .. } => {} + // For single-variant layouts, we already did everything there is to do. + 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 651a797e97cf6..a729d9325c84a 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -155,6 +155,7 @@ fn check_validity_requirement_lax<'tcx>( } match &this.variants { + 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 e8f83a432160e..8b82ce93c015d 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -732,15 +732,12 @@ where let layout = match this.variants { Variants::Single { index } // If all variants but one are uninhabited, the variant layout is the enum layout. - if index == Some(variant_index) && - // Don't confuse variants of uninhabited enums with the enum itself. - // For more details see https://github.com/rust-lang/rust/issues/69763. - this.fields != FieldsShape::Primitive => + if index == variant_index => { this.layout } - Variants::Single { index } => { + Variants::Single { .. } | Variants::Empty => { // `Single` variant enums *can* have other variants, but those are uninhabited. let tcx = cx.tcx(); @@ -748,7 +745,7 @@ where // Deny calling for_variant more than once for non-Single enums. if let Ok(original_layout) = tcx.layout_of(typing_env.as_query_input(this.ty)) { - assert_eq!(original_layout.variants, Variants::Single { index }); + assert_eq!(original_layout.variants, this.variants); } let fields = match this.ty.kind() { @@ -758,7 +755,7 @@ where _ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty), }; tcx.mk_layout(LayoutData { - variants: Variants::Single { index: Some(variant_index) }, + variants: Variants::Single { index: variant_index }, fields: match NonZero::new(fields) { Some(fields) => FieldsShape::Union(fields), None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() }, @@ -775,7 +772,7 @@ where Variants::Multiple { ref variants, .. } => cx.tcx().mk_layout(variants[variant_index].clone()), }; - assert_eq!(*layout.variants(), Variants::Single { index: Some(variant_index) }); + assert_eq!(*layout.variants(), Variants::Single { index: variant_index }); TyAndLayout { ty: this.ty, layout } } @@ -902,10 +899,11 @@ where ), ty::Coroutine(def_id, args) => match this.variants { + Variants::Empty => unreachable!(), Variants::Single { index } => TyMaybeWithLayout::Ty( args.as_coroutine() .state_tys(def_id, tcx) - .nth(index.unwrap().as_usize()) + .nth(index.as_usize()) .unwrap() .nth(i) .unwrap(), @@ -924,10 +922,10 @@ where ty::Adt(def, args) => { match this.variants { Variants::Single { index } => { - let field = - &def.variant(index.unwrap()).fields[FieldIdx::from_usize(i)]; + 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"), // Discriminant field for enums (where applicable). Variants::Multiple { tag, .. } => { diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs index 8be5a63d00878..490e7dd8f7e07 100644 --- a/compiler/rustc_mir_transform/src/large_enums.rs +++ b/compiler/rustc_mir_transform/src/large_enums.rs @@ -216,7 +216,7 @@ impl EnumSizeOpt { }; let layout = tcx.layout_of(typing_env.as_query_input(ty)).ok()?; let variants = match &layout.variants { - Variants::Single { .. } => 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 0ce3955163b8e..55dcad0680a96 100644 --- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs +++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs @@ -54,11 +54,11 @@ fn variant_discriminants<'tcx>( tcx: TyCtxt<'tcx>, ) -> FxHashSet { match &layout.variants { - Variants::Single { index: None } => { + Variants::Empty => { // Uninhabited, no valid discriminant. FxHashSet::default() } - Variants::Single { index: Some(index) } => { + Variants::Single { index } => { let mut res = FxHashSet::default(); res.insert( ty.discriminant_for_variant(tcx, *index) diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs index 2717f4ab62f2c..b39a15a863326 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs @@ -164,9 +164,10 @@ impl<'tcx> Stable<'tcx> for rustc_abi::Variants) -> Self::T { match self { - rustc_abi::Variants::Single { index } => VariantsShape::Single { - index: index.unwrap_or(rustc_abi::VariantIdx::from_u32(0)).stable(tables), - }, + rustc_abi::Variants::Single { index } => { + VariantsShape::Single { index: index.stable(tables) } + } + rustc_abi::Variants::Empty => VariantsShape::Empty, rustc_abi::Variants::Multiple { tag, tag_encoding, tag_field, variants } => { VariantsShape::Multiple { tag: tag.stable(tables), diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index d1234c3cc91d4..8bf61cb133766 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -116,7 +116,7 @@ where FieldsShape::Arbitrary { .. } => { match arg_layout.variants { abi::Variants::Multiple { .. } => return Err(CannotUseFpConv), - abi::Variants::Single { .. } => (), + abi::Variants::Single { .. } | abi::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 c0298edb5ab77..4d858392c979a 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -122,7 +122,7 @@ where FieldsShape::Arbitrary { .. } => { match arg_layout.variants { abi::Variants::Multiple { .. } => return Err(CannotUseFpConv), - abi::Variants::Single { .. } => (), + abi::Variants::Single { .. } | abi::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 bd101b23ea16b..37aecf323a182 100644 --- a/compiler/rustc_target/src/callconv/x86_64.rs +++ b/compiler/rustc_target/src/callconv/x86_64.rs @@ -65,7 +65,7 @@ where } match &layout.variants { - abi::Variants::Single { .. } => {} + abi::Variants::Single { .. } | abi::Variants::Empty => {} abi::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 049f4734e7b54..4cc6292a3ee31 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -338,14 +338,11 @@ pub(crate) mod rustc { }; match layout.variants() { + Variants::Empty => Ok(Self::uninhabited()), Variants::Single { index } => { - if let Some(index) = index { - // `Variants::Single` on enums with variants denotes that - // the enum delegates its layout to the variant at `index`. - layout_of_variant(*index, None) - } else { - Ok(Self::uninhabited()) - } + // `Variants::Single` on enums with variants denotes that + // the enum delegates its layout to the variant at `index`. + layout_of_variant(*index, None) } Variants::Multiple { tag, tag_encoding, tag_field, .. } => { // `Variants::Multiple` denotes an enum with multiple @@ -498,13 +495,15 @@ pub(crate) mod rustc { (ty, layout): (Ty<'tcx>, Layout<'tcx>), i: FieldIdx, ) -> Ty<'tcx> { + // FIXME: Why does this not just use `ty_and_layout_field`? match ty.kind() { ty::Adt(def, args) => { match layout.variants { Variants::Single { index } => { - let field = &def.variant(index.unwrap()).fields[i]; + let field = &def.variant(index).fields[i]; field.ty(cx.tcx(), args) } + 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 4fc25a7f764a1..21fb257ff6e23 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -340,7 +340,7 @@ fn layout_of_uncached<'tcx>( let largest_niche = if count != 0 { element.largest_niche } else { None }; tcx.mk_layout(LayoutData { - variants: Variants::Single { index: Some(FIRST_VARIANT) }, + variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: element.size, count }, backend_repr: abi, largest_niche, @@ -353,7 +353,7 @@ fn layout_of_uncached<'tcx>( ty::Slice(element) => { let element = cx.layout_of(element)?; tcx.mk_layout(LayoutData { - variants: Variants::Single { index: Some(FIRST_VARIANT) }, + variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: element.size, count: 0 }, backend_repr: BackendRepr::Memory { sized: false }, largest_niche: None, @@ -364,7 +364,7 @@ fn layout_of_uncached<'tcx>( }) } ty::Str => tcx.mk_layout(LayoutData { - variants: Variants::Single { index: Some(FIRST_VARIANT) }, + variants: Variants::Single { index: FIRST_VARIANT }, fields: FieldsShape::Array { stride: Size::from_bytes(1), count: 0 }, backend_repr: BackendRepr::Memory { sized: false }, largest_niche: None, @@ -535,7 +535,7 @@ fn layout_of_uncached<'tcx>( }; tcx.mk_layout(LayoutData { - variants: Variants::Single { index: Some(FIRST_VARIANT) }, + variants: Variants::Single { index: FIRST_VARIANT }, fields, backend_repr: abi, largest_niche: e_ly.largest_niche, @@ -927,7 +927,7 @@ fn coroutine_layout<'tcx>( &ReprOptions::default(), StructKind::Prefixed(prefix_size, prefix_align.abi), )?; - variant.variants = Variants::Single { index: Some(index) }; + variant.variants = Variants::Single { index: index }; let FieldsShape::Arbitrary { offsets, memory_index } = variant.fields else { bug!(); @@ -1105,10 +1105,10 @@ fn variant_info_for_adt<'tcx>( }; match layout.variants { + Variants::Empty => (vec![], None), + Variants::Single { index } => { - if let Some(index) = index - && layout.fields != FieldsShape::Primitive - { + if layout.fields != FieldsShape::Primitive { 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 7e2375154c09c..8d5403ed32468 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -242,15 +242,15 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou check_layout_abi(cx, layout); match &layout.variants { - Variants::Single { index: None } => { + Variants::Empty => { assert!(layout.is_uninhabited()); } - Variants::Single { index: Some(idx) } => { + Variants::Single { index } => { if let Some(variants) = layout.ty.variant_range(tcx) { - assert!(variants.contains(idx)); + assert!(variants.contains(index)); } else { // Types without variants use `0` as dummy variant index. - assert!(idx.as_u32() == 0); + assert!(index.as_u32() == 0); } } Variants::Multiple { variants, tag, tag_encoding, .. } => { diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs index cf28a0c58856d..17e6a852022d7 100644 --- a/compiler/stable_mir/src/abi.rs +++ b/compiler/stable_mir/src/abi.rs @@ -180,8 +180,10 @@ impl FieldsShape { #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize)] pub enum VariantsShape { + /// A type with no valid variants. Must be uninhabited. + Empty, + /// Single enum variants, structs/tuples, unions, and all non-ADTs. - // FIXME: needs to become `Option` like in the internal type. Single { index: VariantIdx }, /// Enum-likes with more than one inhabited variant: each variant comes with diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index b57ce4e070c38..cd3a761ec6214 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -606,7 +606,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `UnsafeCell` action. (self.unsafe_cell_action)(v) } - Variants::Single { .. } => { + Variants::Single { .. } | Variants::Empty => { // Proceed further, try to find where exactly that `UnsafeCell` // is hiding. self.walk_value(v)