Skip to content

Commit a610961

Browse files
committed
make no-variant types a dedicated Variants variant
1 parent 2b6afa6 commit a610961

File tree

25 files changed

+96
-90
lines changed

25 files changed

+96
-90
lines changed

compiler/rustc_abi/src/callconv.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
206206
let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;
207207

208208
match &self.variants {
209-
abi::Variants::Single { .. } => {}
209+
abi::Variants::Single { .. } | abi::Variants::Empty => {}
210210
abi::Variants::Multiple { variants, .. } => {
211211
// Treat enum variants like union members.
212212
// HACK(eddyb) pretend the `enum` field (discriminant)

compiler/rustc_abi/src/layout.rs

+10-9
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
120120
.max_by_key(|niche| niche.available(dl));
121121

122122
LayoutData {
123-
variants: Variants::Single { index: Some(VariantIdx::new(0)) },
123+
variants: Variants::Single { index: VariantIdx::new(0) },
124124
fields: FieldsShape::Arbitrary {
125125
offsets: [Size::ZERO, b_offset].into(),
126126
memory_index: [0, 1].into(),
@@ -213,8 +213,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
213213
&self,
214214
) -> LayoutData<FieldIdx, VariantIdx> {
215215
let dl = self.cx.data_layout();
216+
// This is also used for uninhabited enums, so we use `Variants::Empty`.
216217
LayoutData {
217-
variants: Variants::Single { index: None },
218+
variants: Variants::Empty,
218219
fields: FieldsShape::Primitive,
219220
backend_repr: BackendRepr::Uninhabited,
220221
largest_niche: None,
@@ -385,7 +386,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
385386
};
386387

387388
Ok(LayoutData {
388-
variants: Variants::Single { index: Some(only_variant_idx) },
389+
variants: Variants::Single { index: only_variant_idx },
389390
fields: FieldsShape::Union(union_field_count),
390391
backend_repr: abi,
391392
largest_niche: None,
@@ -424,7 +425,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
424425
};
425426

426427
let mut st = self.univariant(&variants[v], repr, kind)?;
427-
st.variants = Variants::Single { index: Some(v) };
428+
st.variants = Variants::Single { index: v };
428429

429430
if is_unsafe_cell {
430431
let hide_niches = |scalar: &mut _| match scalar {
@@ -543,7 +544,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
543544
.iter_enumerated()
544545
.map(|(j, v)| {
545546
let mut st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?;
546-
st.variants = Variants::Single { index: Some(j) };
547+
st.variants = Variants::Single { index: j };
547548

548549
align = align.max(st.align);
549550
max_repr_align = max_repr_align.max(st.max_repr_align);
@@ -736,7 +737,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
736737
repr,
737738
StructKind::Prefixed(min_ity.size(), prefix_align),
738739
)?;
739-
st.variants = Variants::Single { index: Some(i) };
740+
st.variants = Variants::Single { index: i };
740741
// Find the first field we can't move later
741742
// to make room for a larger discriminant.
742743
for field_idx in st.fields.index_by_increasing_offset() {
@@ -1004,8 +1005,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
10041005
Variants::Multiple { tag, tag_encoding, tag_field, .. } => {
10051006
Variants::Multiple { tag, tag_encoding, tag_field, variants: best_layout.variants }
10061007
}
1007-
Variants::Single { .. } => {
1008-
panic!("encountered a single-variant enum during multi-variant layout")
1008+
Variants::Single { .. } | Variants::Empty => {
1009+
panic!("encountered a single-variant or empty enum during multi-variant layout")
10091010
}
10101011
};
10111012
Ok(best_layout.layout)
@@ -1344,7 +1345,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
13441345
};
13451346

13461347
Ok(LayoutData {
1347-
variants: Variants::Single { index: Some(VariantIdx::new(0)) },
1348+
variants: Variants::Single { index: VariantIdx::new(0) },
13481349
fields: FieldsShape::Arbitrary { offsets, memory_index },
13491350
backend_repr: abi,
13501351
largest_niche,

compiler/rustc_abi/src/lib.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1504,11 +1504,13 @@ impl BackendRepr {
15041504
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
15051505
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
15061506
pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
1507+
/// A type with no valid variants. Must be uninhabited.
1508+
Empty,
1509+
15071510
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
15081511
Single {
1509-
/// Always `Some(0)` for types without variants (i.e., everything except for `!`, enums, and
1510-
/// generators). `None` indicates an uninhabited type; this is used for zero-variant enums.
1511-
index: Option<VariantIdx>,
1512+
/// Always `0` for types that cannot have multiple variants.
1513+
index: VariantIdx,
15121514
},
15131515

15141516
/// Enum-likes with more than one variant: each variant comes with
@@ -1706,7 +1708,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
17061708
let size = scalar.size(cx);
17071709
let align = scalar.align(cx);
17081710
LayoutData {
1709-
variants: Variants::Single { index: Some(VariantIdx::new(0)) },
1711+
variants: Variants::Single { index: VariantIdx::new(0) },
17101712
fields: FieldsShape::Primitive,
17111713
backend_repr: BackendRepr::Scalar(scalar),
17121714
largest_niche,

compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs

+12-14
Original file line numberDiff line numberDiff line change
@@ -205,21 +205,18 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
205205
),
206206
|cx, enum_type_di_node| {
207207
match enum_type_and_layout.variants {
208-
Variants::Single { index: variant_index } => {
209-
let Some(variant_index) = variant_index else {
210-
// Uninhabited enums have Variants::Single. We don't generate
211-
// any members for them.
212-
return smallvec![];
213-
};
214-
215-
build_single_variant_union_fields(
216-
cx,
217-
enum_adt_def,
218-
enum_type_and_layout,
219-
enum_type_di_node,
220-
variant_index,
221-
)
208+
Variants::Empty => {
209+
// Uninhabited enums have Variants::Single. We don't generate
210+
// any members for them.
211+
return smallvec![];
222212
}
213+
Variants::Single { index: variant_index } => build_single_variant_union_fields(
214+
cx,
215+
enum_adt_def,
216+
enum_type_and_layout,
217+
enum_type_di_node,
218+
variant_index,
219+
),
223220
Variants::Multiple {
224221
tag_encoding: TagEncoding::Direct,
225222
ref variants,
@@ -287,6 +284,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
287284
)
288285
}
289286
Variants::Single { .. }
287+
| Variants::Empty
290288
| Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => {
291289
bug!(
292290
"Encountered coroutine with non-direct-tag layout: {:?}",

compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ fn compute_discriminant_value<'ll, 'tcx>(
366366
variant_index: VariantIdx,
367367
) -> DiscrResult {
368368
match enum_type_and_layout.layout.variants() {
369-
&Variants::Single { .. } => DiscrResult::NoDiscriminant,
369+
&Variants::Single { .. } | &Variants::Empty => DiscrResult::NoDiscriminant,
370370
&Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => DiscrResult::Value(
371371
enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val,
372372
),

compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,8 @@ fn build_discr_member_di_node<'ll, 'tcx>(
316316
let containing_scope = enum_or_coroutine_type_di_node;
317317

318318
match enum_or_coroutine_type_and_layout.layout.variants() {
319-
// A single-variant enum has no discriminant.
320-
&Variants::Single { .. } => None,
319+
// A single-variant or no-variant enum has no discriminant.
320+
&Variants::Single { .. } | &Variants::Empty => None,
321321

322322
&Variants::Multiple { tag_field, .. } => {
323323
let tag_base_type = tag_base_type(cx.tcx, enum_or_coroutine_type_and_layout);

compiler/rustc_codegen_llvm/src/type_of.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,14 @@ fn uncached_llvm_type<'a, 'tcx>(
3535
if !cx.sess().fewer_names() =>
3636
{
3737
let mut name = with_no_visible_paths!(with_no_trimmed_paths!(layout.ty.to_string()));
38-
if let (&ty::Adt(def, _), &Variants::Single { index: Some(index) }) =
38+
if let (&ty::Adt(def, _), &Variants::Single { index }) =
3939
(layout.ty.kind(), &layout.variants)
4040
{
4141
if def.is_enum() {
4242
write!(&mut name, "::{}", def.variant(index).name).unwrap();
4343
}
4444
}
45-
if let (&ty::Coroutine(_, _), &Variants::Single { index: Some(index) }) =
45+
if let (&ty::Coroutine(_, _), &Variants::Single { index }) =
4646
(layout.ty.kind(), &layout.variants)
4747
{
4848
write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap();
@@ -216,7 +216,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
216216

217217
// Check the cache.
218218
let variant_index = match self.variants {
219-
Variants::Single { index } => index,
219+
Variants::Single { index } => Some(index),
220220
_ => None,
221221
};
222222
if let Some(llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) {

compiler/rustc_codegen_ssa/src/debuginfo/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ fn tag_base_type_opt<'tcx>(
6565
});
6666

6767
match enum_type_and_layout.layout.variants() {
68-
// A single-variant enum has no discriminant.
69-
Variants::Single { .. } => None,
68+
// A single-variant or no-variant enum has no discriminant.
69+
Variants::Single { .. } | Variants::Empty => None,
7070

7171
Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => {
7272
// Niche tags are always normalized to unsized integers of the correct size.

compiler/rustc_codegen_ssa/src/mir/place.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
242242
return bx.cx().const_poison(cast_to);
243243
}
244244
let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
245+
Variants::Empty => unreachable!("we already handled uninhabited types"),
245246
Variants::Single { index } => {
246-
let index = index.unwrap(); // we already checked `is_uninhabited`
247+
// we already checked `is_uninhabited`
247248
let discr_val = self
248249
.layout
249250
.ty
@@ -365,9 +366,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
365366
return;
366367
}
367368
match self.layout.variants {
368-
Variants::Single { index } => {
369-
assert_eq!(index.unwrap(), variant_index);
370-
}
369+
Variants::Empty => unreachable!("we already handled uninhabited types"),
370+
Variants::Single { index } => assert_eq!(index, variant_index),
371+
371372
Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => {
372373
let ptr = self.project_field(bx, tag_field);
373374
let to =

compiler/rustc_const_eval/src/interpret/discriminant.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
6565
// We use "tag" to refer to how the discriminant is encoded in memory, which can be either
6666
// straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
6767
let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout().variants {
68+
Variants::Empty => {
69+
throw_ub!(UninhabitedEnumVariantRead(None));
70+
}
6871
Variants::Single { index } => {
6972
if op.layout().is_uninhabited() {
7073
// For consistency with `write_discriminant`, and to make sure that
@@ -73,7 +76,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
7376
throw_ub!(UninhabitedEnumVariantRead(None));
7477
}
7578
// Since the type is inhabited, there must be an index.
76-
return interp_ok(index.unwrap());
79+
return interp_ok(index);
7780
}
7881
Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => {
7982
(tag, tag_encoding, tag_field)
@@ -238,6 +241,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
238241
}
239242

240243
match layout.variants {
244+
abi::Variants::Empty => unreachable!("we already handled uninhabited types"),
241245
abi::Variants::Single { .. } => {
242246
// The tag of a `Single` enum is like the tag of the niched
243247
// variant: there's no tag as the discriminant is encoded

compiler/rustc_const_eval/src/interpret/validity.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
302302
};
303303
}
304304
}
305-
Variants::Single { .. } => {}
305+
Variants::Single { .. } | Variants::Empty => {}
306306
}
307307

308308
// 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> {
342342
match layout.variants {
343343
Variants::Single { index } => {
344344
// Inside a variant
345-
PathElem::Field(
346-
def.variant(index.unwrap()).fields[FieldIdx::from_usize(field)].name,
347-
)
345+
PathElem::Field(def.variant(index).fields[FieldIdx::from_usize(field)].name)
348346
}
347+
Variants::Empty => panic!("there is no field in Variants::Empty types"),
349348
Variants::Multiple { .. } => bug!("we handled variants above"),
350349
}
351350
}
@@ -1012,7 +1011,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
10121011
}
10131012
// Don't forget potential other variants.
10141013
match &layout.variants {
1015-
Variants::Single { .. } => {
1014+
Variants::Single { .. } | Variants::Empty => {
10161015
// Fully handled above.
10171016
}
10181017
Variants::Multiple { variants, .. } => {

compiler/rustc_const_eval/src/interpret/visitor.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -218,8 +218,8 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
218218
// recurse with the inner type
219219
self.visit_variant(v, idx, &inner)?;
220220
}
221-
// For single-variant layouts, we already did anything there is to do.
222-
Variants::Single { .. } => {}
221+
// For single-variant layouts, we already did everything there is to do.
222+
Variants::Single { .. } | Variants::Empty => {}
223223
}
224224

225225
interp_ok(())

compiler/rustc_const_eval/src/util/check_validity_requirement.rs

+1
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ fn check_validity_requirement_lax<'tcx>(
155155
}
156156

157157
match &this.variants {
158+
Variants::Empty => return Ok(false),
158159
Variants::Single { .. } => {
159160
// All fields of this single variant have already been checked above, there is nothing
160161
// else to do.

compiler/rustc_middle/src/ty/layout.rs

+9-11
Original file line numberDiff line numberDiff line change
@@ -732,23 +732,20 @@ where
732732
let layout = match this.variants {
733733
Variants::Single { index }
734734
// If all variants but one are uninhabited, the variant layout is the enum layout.
735-
if index == Some(variant_index) &&
736-
// Don't confuse variants of uninhabited enums with the enum itself.
737-
// For more details see https://github.com/rust-lang/rust/issues/69763.
738-
this.fields != FieldsShape::Primitive =>
735+
if index == variant_index =>
739736
{
740737
this.layout
741738
}
742739

743-
Variants::Single { index } => {
740+
Variants::Single { .. } | Variants::Empty => {
744741
// `Single` variant enums *can* have other variants, but those are uninhabited.
745742

746743
let tcx = cx.tcx();
747744
let typing_env = cx.typing_env();
748745

749746
// Deny calling for_variant more than once for non-Single enums.
750747
if let Ok(original_layout) = tcx.layout_of(typing_env.as_query_input(this.ty)) {
751-
assert_eq!(original_layout.variants, Variants::Single { index });
748+
assert_eq!(original_layout.variants, this.variants);
752749
}
753750

754751
let fields = match this.ty.kind() {
@@ -758,7 +755,7 @@ where
758755
_ => bug!("`ty_and_layout_for_variant` on unexpected type {}", this.ty),
759756
};
760757
tcx.mk_layout(LayoutData {
761-
variants: Variants::Single { index: Some(variant_index) },
758+
variants: Variants::Single { index: variant_index },
762759
fields: match NonZero::new(fields) {
763760
Some(fields) => FieldsShape::Union(fields),
764761
None => FieldsShape::Arbitrary { offsets: IndexVec::new(), memory_index: IndexVec::new() },
@@ -775,7 +772,7 @@ where
775772
Variants::Multiple { ref variants, .. } => cx.tcx().mk_layout(variants[variant_index].clone()),
776773
};
777774

778-
assert_eq!(*layout.variants(), Variants::Single { index: Some(variant_index) });
775+
assert_eq!(*layout.variants(), Variants::Single { index: variant_index });
779776

780777
TyAndLayout { ty: this.ty, layout }
781778
}
@@ -902,10 +899,11 @@ where
902899
),
903900

904901
ty::Coroutine(def_id, args) => match this.variants {
902+
Variants::Empty => unreachable!(),
905903
Variants::Single { index } => TyMaybeWithLayout::Ty(
906904
args.as_coroutine()
907905
.state_tys(def_id, tcx)
908-
.nth(index.unwrap().as_usize())
906+
.nth(index.as_usize())
909907
.unwrap()
910908
.nth(i)
911909
.unwrap(),
@@ -924,10 +922,10 @@ where
924922
ty::Adt(def, args) => {
925923
match this.variants {
926924
Variants::Single { index } => {
927-
let field =
928-
&def.variant(index.unwrap()).fields[FieldIdx::from_usize(i)];
925+
let field = &def.variant(index).fields[FieldIdx::from_usize(i)];
929926
TyMaybeWithLayout::Ty(field.ty(tcx, args))
930927
}
928+
Variants::Empty => panic!("there is no field in Variants::Empty types"),
931929

932930
// Discriminant field for enums (where applicable).
933931
Variants::Multiple { tag, .. } => {

compiler/rustc_mir_transform/src/large_enums.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ impl EnumSizeOpt {
216216
};
217217
let layout = tcx.layout_of(typing_env.as_query_input(ty)).ok()?;
218218
let variants = match &layout.variants {
219-
Variants::Single { .. } => return None,
219+
Variants::Single { .. } | Variants::Empty => return None,
220220
Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => return None,
221221

222222
Variants::Multiple { variants, .. } if variants.len() <= 1 => return None,

0 commit comments

Comments
 (0)