Rollup merge of #89859 - RalfJung:write-discriminant, r=oli-obk

add dedicated error variant for writing the discriminant of an uninhabited enum variant

This is conceptually different from hitting an `Unreachable` terminator. Also add some sanity check making sure we don't write discriminants of things that do not have discriminants.

r? ``@oli-obk``
This commit is contained in:
Matthias Krüger 2021-10-15 07:44:47 +02:00 committed by GitHub
commit 345d483e95
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 20 additions and 1 deletions

View file

@ -618,6 +618,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
/// Read discriminant, return the runtime value as well as the variant index.
/// Can also legally be called on non-enums (e.g. through the discriminant_value intrinsic)!
pub fn read_discriminant(
&self,
op: &OpTy<'tcx, M::PointerTag>,

View file

@ -988,10 +988,23 @@ where
variant_index: VariantIdx,
dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
// This must be an enum or generator.
match dest.layout.ty.kind() {
ty::Adt(adt, _) => assert!(adt.is_enum()),
ty::Generator(..) => {}
_ => span_bug!(
self.cur_span(),
"write_discriminant called on non-variant-type (neither enum nor generator)"
),
}
// Layout computation excludes uninhabited variants from consideration
// 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 cannot do anything here.
// When evaluating we will always error before even getting here, but ConstProp 'executes'
// dead code, so we cannot ICE here.
if dest.layout.for_variant(self, variant_index).abi.is_uninhabited() {
throw_ub!(Unreachable);
throw_ub!(UninhabitedEnumVariantWritten)
}
match dest.layout.variants {

View file

@ -287,6 +287,8 @@ pub enum UndefinedBehaviorInfo<'tcx> {
target_size: u64,
data_size: u64,
},
/// A discriminant of an uninhabited enum variant is written.
UninhabitedEnumVariantWritten,
}
impl fmt::Display for UndefinedBehaviorInfo<'_> {
@ -391,6 +393,9 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> {
"scalar size mismatch: expected {} bytes but got {} bytes instead",
target_size, data_size
),
UninhabitedEnumVariantWritten => {
write!(f, "writing discriminant of an uninhabited enum")
}
}
}
}