Skip to content

Commit 6de1eb6

Browse files
committed
fix safe-transmute handling of enums
1 parent a36652c commit 6de1eb6

File tree

3 files changed

+30
-31
lines changed

3 files changed

+30
-31
lines changed

compiler/rustc_const_eval/src/interpret/discriminant.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
7070
if ty.is_enum() {
7171
// Hilariously, `Single` is used even for 0-variant enums.
7272
// (See https://github.com/rust-lang/rust/issues/89765).
73-
if matches!(ty.kind(), ty::Adt(def, ..) if def.variants().is_empty()) {
73+
if ty.ty_adt_def().unwrap().variants().is_empty() {
7474
throw_ub!(UninhabitedEnumVariantRead(index))
7575
}
7676
// For consistency with `write_discriminant`, and to make sure that

compiler/rustc_middle/src/query/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,8 @@ rustc_queries! {
10861086
}
10871087

10881088
/// Computes the tag (if any) for a given type and variant.
1089+
/// `None` means that the variant doesn't need a tag (because it is niched).
1090+
/// Will panic for uninhabited variants.
10891091
query tag_for_variant(
10901092
key: (Ty<'tcx>, abi::VariantIdx)
10911093
) -> Option<ty::ScalarInt> {

compiler/rustc_transmute/src/layout/tree.rs

+27-30
Original file line numberDiff line numberDiff line change
@@ -319,38 +319,35 @@ pub(crate) mod rustc {
319319
) -> Result<Self, Err> {
320320
assert!(def.is_enum());
321321

322-
// Computes the variant of a given index.
323-
let layout_of_variant = |index, encoding: Option<TagEncoding<VariantIdx>>| {
324-
let tag = cx.tcx().tag_for_variant((cx.tcx().erase_regions(ty), index));
325-
let variant_def = Def::Variant(def.variant(index));
326-
let variant_layout = ty_variant(cx, (ty, layout), index);
327-
Self::from_variant(
328-
variant_def,
329-
tag.map(|tag| (tag, index, encoding.unwrap())),
330-
(ty, variant_layout),
331-
layout.size,
332-
cx,
333-
)
334-
};
322+
// Computes the layout of a variant.
323+
let layout_of_variant =
324+
|index, encoding: Option<TagEncoding<VariantIdx>>| -> Result<Self, Err> {
325+
let variant_layout = ty_variant(cx, (ty, layout), index);
326+
if variant_layout.is_uninhabited() {
327+
return Ok(Self::uninhabited());
328+
}
329+
let tag = cx.tcx().tag_for_variant((cx.tcx().erase_regions(ty), index));
330+
let variant_def = Def::Variant(def.variant(index));
331+
Self::from_variant(
332+
variant_def,
333+
tag.map(|tag| (tag, index, encoding.unwrap())),
334+
(ty, variant_layout),
335+
layout.size,
336+
cx,
337+
)
338+
};
335339

336-
// We consider three kinds of enums, each demanding a different
337-
// treatment of their layout computation:
338-
// 1. enums that are uninhabited ZSTs
339-
// 2. enums that delegate their layout to a variant
340-
// 3. enums with multiple variants
341340
match layout.variants() {
342-
Variants::Single { .. } if layout.is_uninhabited() && layout.size == Size::ZERO => {
343-
// The layout representation of uninhabited, ZST enums is
344-
// defined to be like that of the `!` type, as opposed of a
345-
// typical enum. Consequently, they cannot be descended into
346-
// as if they typical enums. We therefore special-case this
347-
// scenario and simply return an uninhabited `Tree`.
348-
Ok(Self::uninhabited())
349-
}
350341
Variants::Single { index } => {
351-
// `Variants::Single` on enums with variants denotes that
352-
// the enum delegates its layout to the variant at `index`.
353-
layout_of_variant(*index, None)
342+
// Hilariously, `Single` is used even for 0-variant enums;
343+
// `index` is just junk in that case.
344+
if ty.ty_adt_def().unwrap().variants().is_empty() {
345+
Ok(Self::uninhabited())
346+
} else {
347+
// `Variants::Single` on enums with variants denotes that
348+
// the enum delegates its layout to the variant at `index`.
349+
layout_of_variant(*index, None)
350+
}
354351
}
355352
Variants::Multiple { tag, tag_encoding, tag_field, .. } => {
356353
// `Variants::Multiple` denotes an enum with multiple
@@ -369,7 +366,7 @@ pub(crate) mod rustc {
369366
},
370367
)?;
371368

372-
return Ok(Self::def(Def::Adt(def)).then(variants));
369+
Ok(Self::def(Def::Adt(def)).then(variants))
373370
}
374371
}
375372
}

0 commit comments

Comments
 (0)