Skip to content

Commit d9e24d8

Browse files
committed
Variants::Single: do not use invalid VariantIdx for uninhabited enums
1 parent 611a991 commit d9e24d8

File tree

47 files changed

+548
-280
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+548
-280
lines changed

compiler/rustc_abi/src/layout.rs

Lines changed: 7 additions & 7 deletions
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: VariantIdx::new(0) },
123+
variants: Variants::Single { index: Some(VariantIdx::new(0)) },
124124
fields: FieldsShape::Arbitrary {
125125
offsets: [Size::ZERO, b_offset].into(),
126126
memory_index: [0, 1].into(),
@@ -214,7 +214,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
214214
) -> LayoutData<FieldIdx, VariantIdx> {
215215
let dl = self.cx.data_layout();
216216
LayoutData {
217-
variants: Variants::Single { index: VariantIdx::new(0) },
217+
variants: Variants::Single { index: None },
218218
fields: FieldsShape::Primitive,
219219
backend_repr: BackendRepr::Uninhabited,
220220
largest_niche: None,
@@ -385,7 +385,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
385385
};
386386

387387
Ok(LayoutData {
388-
variants: Variants::Single { index: only_variant_idx },
388+
variants: Variants::Single { index: Some(only_variant_idx) },
389389
fields: FieldsShape::Union(union_field_count),
390390
backend_repr: abi,
391391
largest_niche: None,
@@ -424,7 +424,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
424424
};
425425

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

429429
if is_unsafe_cell {
430430
let hide_niches = |scalar: &mut _| match scalar {
@@ -543,7 +543,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
543543
.iter_enumerated()
544544
.map(|(j, v)| {
545545
let mut st = self.univariant(v, repr, StructKind::AlwaysSized).ok()?;
546-
st.variants = Variants::Single { index: j };
546+
st.variants = Variants::Single { index: Some(j) };
547547

548548
align = align.max(st.align);
549549
max_repr_align = max_repr_align.max(st.max_repr_align);
@@ -736,7 +736,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
736736
repr,
737737
StructKind::Prefixed(min_ity.size(), prefix_align),
738738
)?;
739-
st.variants = Variants::Single { index: i };
739+
st.variants = Variants::Single { index: Some(i) };
740740
// Find the first field we can't move later
741741
// to make room for a larger discriminant.
742742
for field_idx in st.fields.index_by_increasing_offset() {
@@ -1344,7 +1344,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
13441344
};
13451345

13461346
Ok(LayoutData {
1347-
variants: Variants::Single { index: VariantIdx::new(0) },
1347+
variants: Variants::Single { index: Some(VariantIdx::new(0)) },
13481348
fields: FieldsShape::Arbitrary { offsets, memory_index },
13491349
backend_repr: abi,
13501350
largest_niche,

compiler/rustc_abi/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,9 +1506,9 @@ impl BackendRepr {
15061506
pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
15071507
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
15081508
Single {
1509-
/// Always 0 for non-enums/generators.
1510-
/// For enums without a variant, this is an invalid index!
1511-
index: VariantIdx,
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>,
15121512
},
15131513

15141514
/// Enum-likes with more than one variant: each variant comes with
@@ -1706,7 +1706,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
17061706
let size = scalar.size(cx);
17071707
let align = scalar.align(cx);
17081708
LayoutData {
1709-
variants: Variants::Single { index: VariantIdx::new(0) },
1709+
variants: Variants::Single { index: Some(VariantIdx::new(0)) },
17101710
fields: FieldsShape::Primitive,
17111711
backend_repr: BackendRepr::Scalar(scalar),
17121712
largest_niche,

compiler/rustc_codegen_cranelift/src/discriminant.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub(crate) fn codegen_set_discriminant<'tcx>(
1919
}
2020
match layout.variants {
2121
Variants::Single { index } => {
22-
assert_eq!(index, variant_index);
22+
assert_eq!(index.unwrap(), variant_index);
2323
}
2424
Variants::Multiple {
2525
tag: _,
@@ -86,9 +86,10 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
8686

8787
let (tag_scalar, tag_field, tag_encoding) = match &layout.variants {
8888
Variants::Single { index } => {
89+
let index = index.unwrap();
8990
let discr_val = layout
9091
.ty
91-
.discriminant_for_variant(fx.tcx, *index)
92+
.discriminant_for_variant(fx.tcx, index)
9293
.map_or(u128::from(index.as_u32()), |discr| discr.val);
9394

9495
let val = match dest_layout.ty.kind() {

compiler/rustc_codegen_gcc/src/type_of.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,14 @@ fn uncached_gcc_type<'gcc, 'tcx>(
9999
if !cx.sess().fewer_names() =>
100100
{
101101
let mut name = with_no_trimmed_paths!(layout.ty.to_string());
102-
if let (&ty::Adt(def, _), &Variants::Single { index }) =
102+
if let (&ty::Adt(def, _), &Variants::Single { index: Some(index) }) =
103103
(layout.ty.kind(), &layout.variants)
104104
{
105105
if def.is_enum() && !def.variants().is_empty() {
106106
write!(&mut name, "::{}", def.variant(index).name).unwrap();
107107
}
108108
}
109-
if let (&ty::Coroutine(_, _), &Variants::Single { index }) =
109+
if let (&ty::Coroutine(_, _), &Variants::Single { index: Some(index) }) =
110110
(layout.ty.kind(), &layout.variants)
111111
{
112112
write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap();
@@ -230,7 +230,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
230230

231231
// Check the cache.
232232
let variant_index = match self.variants {
233-
Variants::Single { index } => Some(index),
233+
Variants::Single { index } => index,
234234
_ => None,
235235
};
236236
let cached_type = cx.types.borrow().get(&(self.ty, variant_index)).cloned();

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,11 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
206206
|cx, enum_type_di_node| {
207207
match enum_type_and_layout.variants {
208208
Variants::Single { index: variant_index } => {
209-
if enum_adt_def.variants().is_empty() {
209+
let Some(variant_index) = variant_index else {
210210
// Uninhabited enums have Variants::Single. We don't generate
211211
// any members for them.
212212
return smallvec![];
213-
}
213+
};
214214

215215
build_single_variant_union_fields(
216216
cx,

compiler/rustc_codegen_llvm/src/type_of.rs

Lines changed: 4 additions & 4 deletions
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 }) =
38+
if let (&ty::Adt(def, _), &Variants::Single { index: Some(index) }) =
3939
(layout.ty.kind(), &layout.variants)
4040
{
41-
if def.is_enum() && !def.variants().is_empty() {
41+
if def.is_enum() {
4242
write!(&mut name, "::{}", def.variant(index).name).unwrap();
4343
}
4444
}
45-
if let (&ty::Coroutine(_, _), &Variants::Single { index }) =
45+
if let (&ty::Coroutine(_, _), &Variants::Single { index: Some(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 } => Some(index),
219+
Variants::Single { index } => index,
220220
_ => None,
221221
};
222222
if let Some(llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) {

compiler/rustc_codegen_ssa/src/mir/place.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
243243
}
244244
let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
245245
Variants::Single { index } => {
246+
let index = index.unwrap(); // we already checked `is_uninhabited`
246247
let discr_val = self
247248
.layout
248249
.ty
@@ -365,7 +366,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
365366
}
366367
match self.layout.variants {
367368
Variants::Single { index } => {
368-
assert_eq!(index, variant_index);
369+
assert_eq!(index.unwrap(), variant_index);
369370
}
370371
Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => {
371372
let ptr = self.project_field(bx, tag_field);

compiler/rustc_const_eval/src/interpret/discriminant.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
4444
}
4545
}
4646

47-
/// Read discriminant, return the runtime value as well as the variant index.
47+
/// Read discriminant, return the variant index.
4848
/// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)!
4949
///
5050
/// Will never return an uninhabited variant.
@@ -66,21 +66,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
6666
// straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
6767
let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout().variants {
6868
Variants::Single { index } => {
69-
// Do some extra checks on enums.
70-
if ty.is_enum() {
71-
// Hilariously, `Single` is used even for 0-variant enums.
72-
// (See https://github.com/rust-lang/rust/issues/89765).
73-
if ty.ty_adt_def().unwrap().variants().is_empty() {
74-
throw_ub!(UninhabitedEnumVariantRead(index))
75-
}
69+
if op.layout().is_uninhabited() {
7670
// For consistency with `write_discriminant`, and to make sure that
7771
// `project_downcast` cannot fail due to strange layouts, we declare immediate UB
78-
// for uninhabited variants.
79-
if op.layout().for_variant(self, index).is_uninhabited() {
80-
throw_ub!(UninhabitedEnumVariantRead(index))
81-
}
72+
// for uninhabited enums.
73+
throw_ub!(UninhabitedEnumVariantRead(None));
8274
}
83-
return interp_ok(index);
75+
// Since the type is inhabited, there must be an index.
76+
return interp_ok(index.unwrap());
8477
}
8578
Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => {
8679
(tag, tag_encoding, tag_field)
@@ -199,11 +192,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
199192
// `uninhabited_enum_branching` MIR pass. It also ensures consistency with
200193
// `write_discriminant`.
201194
if op.layout().for_variant(self, index).is_uninhabited() {
202-
throw_ub!(UninhabitedEnumVariantRead(index))
195+
throw_ub!(UninhabitedEnumVariantRead(Some(index)))
203196
}
204197
interp_ok(index)
205198
}
206199

200+
/// Read discriminant, return the user-visible discriminant.
201+
/// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)!
207202
pub fn discriminant_for_variant(
208203
&self,
209204
ty: Ty<'tcx>,

compiler/rustc_const_eval/src/interpret/validity.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +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(def.variant(index).fields[FieldIdx::from_usize(field)].name)
345+
PathElem::Field(
346+
def.variant(index.unwrap()).fields[FieldIdx::from_usize(field)].name,
347+
)
346348
}
347349
Variants::Multiple { .. } => bug!("we handled variants above"),
348350
}

compiler/rustc_middle/src/mir/interpret/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ pub enum UndefinedBehaviorInfo<'tcx> {
399399
/// A discriminant of an uninhabited enum variant is written.
400400
UninhabitedEnumVariantWritten(VariantIdx),
401401
/// An uninhabited enum variant is projected.
402-
UninhabitedEnumVariantRead(VariantIdx),
402+
UninhabitedEnumVariantRead(Option<VariantIdx>),
403403
/// Trying to set discriminant to the niched variant, but the value does not match.
404404
InvalidNichedEnumVariantWritten { enum_ty: Ty<'tcx> },
405405
/// ABI-incompatible argument types.

0 commit comments

Comments
 (0)