Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions compiler/rustc_abi/src/layout/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display {
}

impl<'a, Ty> TyAndLayout<'a, Ty> {
/// Synthetize a layout representing the variant-specific fields of an enum-like layout.
///
/// Note that the resulting layout *does not* fully describes `self.ty` at that specific
/// variant: prefix fields (e.g. in coroutines) and tag information are lost.
///
/// If you don't need type information about the variant's fields, prefer using
/// `self.layout.variants` directly.
pub fn for_variant<C>(self, cx: &C, variant_index: VariantIdx) -> Self
where
Ty: TyAbiInterface<'a, C>,
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2203,6 +2203,17 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
pub fn is_uninhabited(&self) -> bool {
self.uninhabited
}

/// Returns `true` if the given variant is uninhabited.
pub fn is_variant_uninhabited(&self, variant: VariantIdx) -> bool {
match self.variants {
Variants::Empty => true,
Variants::Single { index } => variant != index || self.uninhabited,
Variants::Multiple { ref variants, .. } => {
variants.get(variant).map(|v| v.uninhabited).unwrap_or(true)
}
}
}
}

impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutData<FieldIdx, VariantIdx>
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_cranelift/src/discriminant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub(crate) fn codegen_set_discriminant<'tcx>(
variant_index: VariantIdx,
) {
let layout = place.layout();
if layout.for_variant(fx, variant_index).is_uninhabited() {
if layout.is_variant_uninhabited(variant_index) {
return;
}
match layout.variants {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/mir/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ pub(super) fn codegen_tag_value<'tcx, V>(
) -> Result<Option<(FieldIdx, V)>, UninhabitedVariantError> {
// By checking uninhabited-ness first we don't need to worry about types
// like `(u32, !)` which are single-variant but weird.
if layout.for_variant(cx, variant_index).is_uninhabited() {
if layout.is_variant_uninhabited(variant_index) {
return Err(UninhabitedVariantError);
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/interpret/discriminant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Reading the discriminant of an uninhabited variant is UB. This is the basis for the
// `uninhabited_enum_branching` MIR pass. It also ensures consistency with
// `write_discriminant`.
if op.layout().for_variant(self, index).is_uninhabited() {
if op.layout().is_variant_uninhabited(index) {
throw_ub!(UninhabitedEnumVariantRead(Some(index)))
}
interp_ok(index)
Expand Down Expand Up @@ -252,7 +252,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
// Therefore, there's no way to represent those variants in the given layout.
// Essentially, uninhabited variants do not have a tag that corresponds to their
// discriminant, so we have to bail out here.
if layout.for_variant(self, variant_index).is_uninhabited() {
if layout.is_variant_uninhabited(variant_index) {
throw_ub!(UninhabitedEnumVariantWritten(variant_index))
}

Expand Down
Loading