Skip to content

Commit

Permalink
safe transmute: support Single enums
Browse files Browse the repository at this point in the history
  • Loading branch information
jswrenn committed Jun 12, 2024
1 parent 1d43fbb commit 9978521
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 59 deletions.
5 changes: 1 addition & 4 deletions compiler/rustc_const_eval/src/interpret/discriminant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
variant_index: VariantIdx,
) -> InterpResult<'tcx, Option<(ScalarInt, usize)>> {
match self.layout_of(ty)?.variants {
abi::Variants::Single { index } => {
assert_eq!(index, variant_index);
Ok(None)
}
abi::Variants::Single { .. } => Ok(None),

abi::Variants::Multiple {
tag_encoding: TagEncoding::Direct,
Expand Down
44 changes: 23 additions & 21 deletions compiler/rustc_transmute/src/layout/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -331,30 +331,32 @@ pub(crate) mod rustc {
assert!(def.is_enum());
let layout = ty_and_layout.layout;

if let Variants::Multiple { tag_field, .. } = layout.variants() {
// For enums (but not coroutines), the tag field is
// currently always the first field of the layout.
assert_eq!(*tag_field, 0);
}
// Computes the variant of a given index.
let layout_of_variant = |index| {
let tag = cx.tcx.tag_for_variant((ty_and_layout.ty, index));
let variant_def = Def::Variant(def.variant(index));
let variant_ty_and_layout = ty_and_layout.for_variant(&cx, index);
Self::from_variant(variant_def, tag, variant_ty_and_layout, layout.size, cx)
};

let variants = def.discriminants(cx.tcx()).try_fold(
Self::uninhabited(),
|variants, (idx, ref discriminant)| {
let tag = cx.tcx.tag_for_variant((ty_and_layout.ty, idx));
let variant_def = Def::Variant(def.variant(idx));
let variant_ty_and_layout = ty_and_layout.for_variant(&cx, idx);
let variant = Self::from_variant(
variant_def,
tag,
variant_ty_and_layout,
layout.size,
cx,
match layout.variants() {
Variants::Single { index } => layout_of_variant(*index),
Variants::Multiple { tag_field, .. } => {
// For enums (but not coroutines), the tag field is
// currently always the first field of the layout.
assert_eq!(*tag_field, 0);

let variants = def.discriminants(cx.tcx()).try_fold(
Self::uninhabited(),
|variants, (idx, ref discriminant)| {
let variant = layout_of_variant(idx)?;
Result::<Self, Err>::Ok(variants.or(variant))
},
)?;
Result::<Self, Err>::Ok(variants.or(variant))
},
)?;

return Ok(Self::def(Def::Adt(def)).then(variants));
return Ok(Self::def(Def::Adt(def)).then(variants));
}
}
}

/// Constructs a `Tree` from a 'variant-like' layout.
Expand Down
34 changes: 0 additions & 34 deletions tests/crashes/125811.rs

This file was deleted.

16 changes: 16 additions & 0 deletions tests/ui/transmutability/enums/uninhabited_optimization.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//@ check-pass
//! Tests that we do not regress rust-lang/rust#125811
#![feature(transmutability)]

fn assert_transmutable<T: std::mem::BikeshedIntrinsicFrom<Enum>>() {}

enum Uninhabited {}

enum Enum {
X,
Y(Uninhabited)
}

fn main() {
assert_transmutable::<()>();
}

0 comments on commit 9978521

Please sign in to comment.