Skip to content

Commit 2b483c0

Browse files
committed
fix safe-transmute handling of enums
1 parent a36652c commit 2b483c0

File tree

2 files changed

+28
-30
lines changed
  • compiler

2 files changed

+28
-30
lines changed

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

+26-30
Original file line numberDiff line numberDiff line change
@@ -319,38 +319,34 @@ 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; `index` is just junk in that case.
343+
if matches!(ty.kind(), ty::Adt(def, ..) if def.variants().is_empty()) {
344+
Ok(Self::uninhabited())
345+
} else {
346+
// `Variants::Single` on enums with variants denotes that
347+
// the enum delegates its layout to the variant at `index`.
348+
layout_of_variant(*index, None)
349+
}
354350
}
355351
Variants::Multiple { tag, tag_encoding, tag_field, .. } => {
356352
// `Variants::Multiple` denotes an enum with multiple
@@ -369,7 +365,7 @@ pub(crate) mod rustc {
369365
},
370366
)?;
371367

372-
return Ok(Self::def(Def::Adt(def)).then(variants));
368+
Ok(Self::def(Def::Adt(def)).then(variants))
373369
}
374370
}
375371
}

0 commit comments

Comments
 (0)