1
Fork 0

Rollup merge of #133702 - RalfJung:single-variant, r=oli-obk

Variants::Single: do not use invalid VariantIdx for uninhabited enums

~~Stacked on top of https://github.com/rust-lang/rust/pull/133681, only the last commit is new.~~

Currently, `Variants::Single` for an empty enum contains a `VariantIdx` of 0; looking that up in the enum variant list will ICE. That's quite confusing. So let's fix that by adding a new `Variants::Empty` case for types that have 0 variants.

try-job: i686-msvc
This commit is contained in:
许杰友 Jieyou Xu (Joe) 2024-12-19 16:48:07 +08:00 committed by GitHub
commit 2a43ce03fb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 186 additions and 165 deletions

View file

@ -35,7 +35,6 @@
//! Likewise, applying the optimisation can create a lot of new MIR, so we bound the instruction
//! cost by `MAX_COST`.
use rustc_abi::{TagEncoding, Variants};
use rustc_arena::DroplessArena;
use rustc_const_eval::const_eval::DummyMachine;
use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable};
@ -565,31 +564,15 @@ impl<'a, 'tcx> TOFinder<'a, 'tcx> {
StatementKind::SetDiscriminant { box place, variant_index } => {
let Some(discr_target) = self.map.find_discr(place.as_ref()) else { return };
let enum_ty = place.ty(self.body, self.tcx).ty;
// `SetDiscriminant` may be a no-op if the assigned variant is the untagged variant
// of a niche encoding. If we cannot ensure that we write to the discriminant, do
// nothing.
let Ok(enum_layout) = self.ecx.layout_of(enum_ty) else {
// `SetDiscriminant` guarantees that the discriminant is now `variant_index`.
// Even if the discriminant write does nothing due to niches, it is UB to set the
// discriminant when the data does not encode the desired discriminant.
let Some(discr) =
self.ecx.discriminant_for_variant(enum_ty, *variant_index).discard_err()
else {
return;
};
let writes_discriminant = match enum_layout.variants {
Variants::Single { index } => {
assert_eq!(index, *variant_index);
true
}
Variants::Multiple { tag_encoding: TagEncoding::Direct, .. } => true,
Variants::Multiple {
tag_encoding: TagEncoding::Niche { untagged_variant, .. },
..
} => *variant_index != untagged_variant,
};
if writes_discriminant {
let Some(discr) =
self.ecx.discriminant_for_variant(enum_ty, *variant_index).discard_err()
else {
return;
};
self.process_immediate(bb, discr_target, discr, state);
}
self.process_immediate(bb, discr_target, discr, state);
}
// If we expect `lhs ?= true`, we have an opportunity if we assume `lhs == true`.
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(

View file

@ -216,7 +216,7 @@ impl EnumSizeOpt {
};
let layout = tcx.layout_of(typing_env.as_query_input(ty)).ok()?;
let variants = match &layout.variants {
Variants::Single { .. } => return None,
Variants::Single { .. } | Variants::Empty => return None,
Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => return None,
Variants::Multiple { variants, .. } if variants.len() <= 1 => return None,

View file

@ -54,6 +54,10 @@ fn variant_discriminants<'tcx>(
tcx: TyCtxt<'tcx>,
) -> FxHashSet<u128> {
match &layout.variants {
Variants::Empty => {
// Uninhabited, no valid discriminant.
FxHashSet::default()
}
Variants::Single { index } => {
let mut res = FxHashSet::default();
res.insert(