Skip to content

Commit

Permalink
make no-variant types a dedicated Variants variant
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Dec 1, 2024
1 parent 2b6afa6 commit b90ebfb
Show file tree
Hide file tree
Showing 53 changed files with 245 additions and 494 deletions.
2 changes: 1 addition & 1 deletion compiler/rustc_abi/src/callconv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
let (mut result, mut total) = from_fields_at(*self, Size::ZERO)?;

match &self.variants {
abi::Variants::Single { .. } => {}
abi::Variants::Single { .. } | abi::Variants::Empty => {}
abi::Variants::Multiple { variants, .. } => {
// Treat enum variants like union members.
// HACK(eddyb) pretend the `enum` field (discriminant)
Expand Down
19 changes: 10 additions & 9 deletions compiler/rustc_abi/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
.max_by_key(|niche| niche.available(dl));

LayoutData {
variants: Variants::Single { index: Some(VariantIdx::new(0)) },
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Arbitrary {
offsets: [Size::ZERO, b_offset].into(),
memory_index: [0, 1].into(),
Expand Down Expand Up @@ -213,8 +213,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
&self,
) -> LayoutData<FieldIdx, VariantIdx> {
let dl = self.cx.data_layout();
// This is also used for uninhabited enums, so we use `Variants::Empty`.
LayoutData {
variants: Variants::Single { index: None },
variants: Variants::Empty,
fields: FieldsShape::Primitive,
backend_repr: BackendRepr::Uninhabited,
largest_niche: None,
Expand Down Expand Up @@ -385,7 +386,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
};

Ok(LayoutData {
variants: Variants::Single { index: Some(only_variant_idx) },
variants: Variants::Single { index: only_variant_idx },
fields: FieldsShape::Union(union_field_count),
backend_repr: abi,
largest_niche: None,
Expand Down Expand Up @@ -424,7 +425,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
};

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

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

align = align.max(st.align);
max_repr_align = max_repr_align.max(st.max_repr_align);
Expand Down Expand Up @@ -736,7 +737,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
repr,
StructKind::Prefixed(min_ity.size(), prefix_align),
)?;
st.variants = Variants::Single { index: Some(i) };
st.variants = Variants::Single { index: i };
// Find the first field we can't move later
// to make room for a larger discriminant.
for field_idx in st.fields.index_by_increasing_offset() {
Expand Down Expand Up @@ -1004,8 +1005,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
Variants::Multiple { tag, tag_encoding, tag_field, .. } => {
Variants::Multiple { tag, tag_encoding, tag_field, variants: best_layout.variants }
}
Variants::Single { .. } => {
panic!("encountered a single-variant enum during multi-variant layout")
Variants::Single { .. } | Variants::Empty => {
panic!("encountered a single-variant or empty enum during multi-variant layout")
}
};
Ok(best_layout.layout)
Expand Down Expand Up @@ -1344,7 +1345,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
};

Ok(LayoutData {
variants: Variants::Single { index: Some(VariantIdx::new(0)) },
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Arbitrary { offsets, memory_index },
backend_repr: abi,
largest_niche,
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1504,11 +1504,13 @@ impl BackendRepr {
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
/// A type with no valid variants. Must be uninhabited.
Empty,

/// Single enum variants, structs/tuples, unions, and all non-ADTs.
Single {
/// Always `Some(0)` for types without variants (i.e., everything except for `!`, enums, and
/// generators). `None` indicates an uninhabited type; this is used for zero-variant enums.
index: Option<VariantIdx>,
/// Always `0` for types that cannot have multiple variants.
index: VariantIdx,
},

/// Enum-likes with more than one variant: each variant comes with
Expand Down Expand Up @@ -1706,7 +1708,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
let size = scalar.size(cx);
let align = scalar.align(cx);
LayoutData {
variants: Variants::Single { index: Some(VariantIdx::new(0)) },
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Primitive,
backend_repr: BackendRepr::Scalar(scalar),
largest_niche,
Expand Down
7 changes: 4 additions & 3 deletions compiler/rustc_codegen_cranelift/src/discriminant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ pub(crate) fn codegen_set_discriminant<'tcx>(
return;
}
match layout.variants {
Variants::Empty => unreachable!("we already handled uninhabited types"),
Variants::Single { index } => {
assert_eq!(index.unwrap(), variant_index);
assert_eq!(index, variant_index);
}
Variants::Multiple {
tag: _,
Expand Down Expand Up @@ -85,11 +86,11 @@ pub(crate) fn codegen_get_discriminant<'tcx>(
}

let (tag_scalar, tag_field, tag_encoding) = match &layout.variants {
Variants::Empty => unreachable!("we already handled uninhabited types"),
Variants::Single { index } => {
let index = index.unwrap();
let discr_val = layout
.ty
.discriminant_for_variant(fx.tcx, index)
.discriminant_for_variant(fx.tcx, *index)
.map_or(u128::from(index.as_u32()), |discr| discr.val);

let val = match dest_layout.ty.kind() {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_gcc/src/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,14 @@ fn uncached_gcc_type<'gcc, 'tcx>(
if !cx.sess().fewer_names() =>
{
let mut name = with_no_trimmed_paths!(layout.ty.to_string());
if let (&ty::Adt(def, _), &Variants::Single { index: Some(index) }) =
if let (&ty::Adt(def, _), &Variants::Single { index }) =
(layout.ty.kind(), &layout.variants)
{
if def.is_enum() && !def.variants().is_empty() {
write!(&mut name, "::{}", def.variant(index).name).unwrap();
}
}
if let (&ty::Coroutine(_, _), &Variants::Single { index: Some(index) }) =
if let (&ty::Coroutine(_, _), &Variants::Single { index }) =
(layout.ty.kind(), &layout.variants)
{
write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap();
Expand Down Expand Up @@ -230,7 +230,7 @@ impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {

// Check the cache.
let variant_index = match self.variants {
Variants::Single { index } => index,
Variants::Single { index } => Some(index),
_ => None,
};
let cached_type = cx.types.borrow().get(&(self.ty, variant_index)).cloned();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,21 +205,18 @@ pub(super) fn build_enum_type_di_node<'ll, 'tcx>(
),
|cx, enum_type_di_node| {
match enum_type_and_layout.variants {
Variants::Single { index: variant_index } => {
let Some(variant_index) = variant_index else {
// Uninhabited enums have Variants::Single. We don't generate
// any members for them.
return smallvec![];
};

build_single_variant_union_fields(
cx,
enum_adt_def,
enum_type_and_layout,
enum_type_di_node,
variant_index,
)
Variants::Empty => {
// Uninhabited enums have Variants::Single. We don't generate
// any members for them.
return smallvec![];
}
Variants::Single { index: variant_index } => build_single_variant_union_fields(
cx,
enum_adt_def,
enum_type_and_layout,
enum_type_di_node,
variant_index,
),
Variants::Multiple {
tag_encoding: TagEncoding::Direct,
ref variants,
Expand Down Expand Up @@ -287,6 +284,7 @@ pub(super) fn build_coroutine_di_node<'ll, 'tcx>(
)
}
Variants::Single { .. }
| Variants::Empty
| Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => {
bug!(
"Encountered coroutine with non-direct-tag layout: {:?}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ fn compute_discriminant_value<'ll, 'tcx>(
variant_index: VariantIdx,
) -> DiscrResult {
match enum_type_and_layout.layout.variants() {
&Variants::Single { .. } => DiscrResult::NoDiscriminant,
&Variants::Single { .. } | &Variants::Empty => DiscrResult::NoDiscriminant,
&Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => DiscrResult::Value(
enum_type_and_layout.ty.discriminant_for_variant(cx.tcx, variant_index).unwrap().val,
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,8 @@ fn build_discr_member_di_node<'ll, 'tcx>(
let containing_scope = enum_or_coroutine_type_di_node;

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

&Variants::Multiple { tag_field, .. } => {
let tag_base_type = tag_base_type(cx.tcx, enum_or_coroutine_type_and_layout);
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_codegen_llvm/src/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ fn uncached_llvm_type<'a, 'tcx>(
if !cx.sess().fewer_names() =>
{
let mut name = with_no_visible_paths!(with_no_trimmed_paths!(layout.ty.to_string()));
if let (&ty::Adt(def, _), &Variants::Single { index: Some(index) }) =
if let (&ty::Adt(def, _), &Variants::Single { index }) =
(layout.ty.kind(), &layout.variants)
{
if def.is_enum() {
write!(&mut name, "::{}", def.variant(index).name).unwrap();
}
}
if let (&ty::Coroutine(_, _), &Variants::Single { index: Some(index) }) =
if let (&ty::Coroutine(_, _), &Variants::Single { index }) =
(layout.ty.kind(), &layout.variants)
{
write!(&mut name, "::{}", ty::CoroutineArgs::variant_name(index)).unwrap();
Expand Down Expand Up @@ -216,7 +216,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {

// Check the cache.
let variant_index = match self.variants {
Variants::Single { index } => index,
Variants::Single { index } => Some(index),
_ => None,
};
if let Some(llty) = cx.type_lowering.borrow().get(&(self.ty, variant_index)) {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ fn tag_base_type_opt<'tcx>(
});

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

Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. } => {
// Niche tags are always normalized to unsized integers of the correct size.
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_codegen_ssa/src/mir/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
return bx.cx().const_poison(cast_to);
}
let (tag_scalar, tag_encoding, tag_field) = match self.layout.variants {
Variants::Empty => unreachable!("we already handled uninhabited types"),
Variants::Single { index } => {
let index = index.unwrap(); // we already checked `is_uninhabited`
let discr_val = self
.layout
.ty
Expand Down Expand Up @@ -365,9 +365,9 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
return;
}
match self.layout.variants {
Variants::Single { index } => {
assert_eq!(index.unwrap(), variant_index);
}
Variants::Empty => unreachable!("we already handled uninhabited types"),
Variants::Single { index } => assert_eq!(index, variant_index),

Variants::Multiple { tag_encoding: TagEncoding::Direct, tag_field, .. } => {
let ptr = self.project_field(bx, tag_field);
let to =
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_const_eval/src/interpret/discriminant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// We use "tag" to refer to how the discriminant is encoded in memory, which can be either
// straight-forward (`TagEncoding::Direct`) or with a niche (`TagEncoding::Niche`).
let (tag_scalar_layout, tag_encoding, tag_field) = match op.layout().variants {
Variants::Empty => {
throw_ub!(UninhabitedEnumVariantRead(None));
}
Variants::Single { index } => {
if op.layout().is_uninhabited() {
// For consistency with `write_discriminant`, and to make sure that
Expand All @@ -73,7 +76,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
throw_ub!(UninhabitedEnumVariantRead(None));
}
// Since the type is inhabited, there must be an index.
return interp_ok(index.unwrap());
return interp_ok(index);
}
Variants::Multiple { tag, ref tag_encoding, tag_field, .. } => {
(tag, tag_encoding, tag_field)
Expand Down Expand Up @@ -238,6 +241,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
}

match layout.variants {
abi::Variants::Empty => unreachable!("we already handled uninhabited types"),
abi::Variants::Single { .. } => {
// The tag of a `Single` enum is like the tag of the niched
// variant: there's no tag as the discriminant is encoded
Expand Down
9 changes: 4 additions & 5 deletions compiler/rustc_const_eval/src/interpret/validity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
};
}
}
Variants::Single { .. } => {}
Variants::Single { .. } | Variants::Empty => {}
}

// Now we know we are projecting to a field, so figure out which one.
Expand Down Expand Up @@ -342,10 +342,9 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
match layout.variants {
Variants::Single { index } => {
// Inside a variant
PathElem::Field(
def.variant(index.unwrap()).fields[FieldIdx::from_usize(field)].name,
)
PathElem::Field(def.variant(index).fields[FieldIdx::from_usize(field)].name)
}
Variants::Empty => panic!("there is no field in Variants::Empty types"),
Variants::Multiple { .. } => bug!("we handled variants above"),
}
}
Expand Down Expand Up @@ -1012,7 +1011,7 @@ impl<'rt, 'tcx, M: Machine<'tcx>> ValidityVisitor<'rt, 'tcx, M> {
}
// Don't forget potential other variants.
match &layout.variants {
Variants::Single { .. } => {
Variants::Single { .. } | Variants::Empty => {
// Fully handled above.
}
Variants::Multiple { variants, .. } => {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/interpret/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,8 @@ pub trait ValueVisitor<'tcx, M: Machine<'tcx>>: Sized {
// recurse with the inner type
self.visit_variant(v, idx, &inner)?;
}
// For single-variant layouts, we already did anything there is to do.
Variants::Single { .. } => {}
// For single-variant layouts, we already did everything there is to do.
Variants::Single { .. } | Variants::Empty => {}
}

interp_ok(())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ fn check_validity_requirement_lax<'tcx>(
}

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

0 comments on commit b90ebfb

Please sign in to comment.