From c5a68cf0a65fe94022f5c5fd0fc47ccfcda81929 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Oct 2021 16:53:09 -0400 Subject: [PATCH] add dedicated error variant for writing the discriminant of an uninhabited enum variant --- .../rustc_const_eval/src/interpret/operand.rs | 1 + compiler/rustc_const_eval/src/interpret/place.rs | 15 ++++++++++++++- compiler/rustc_middle/src/mir/interpret/error.rs | 5 +++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index de870bd5c6c..b6682b13ed2 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -618,6 +618,7 @@ pub fn mir_const_to_op( } /// 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>, diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index 0da6d8169bd..d425b84bdaf 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -988,10 +988,23 @@ pub fn write_discriminant( 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 { diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 5d17bb9b15f..9472a287e5a 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { "scalar size mismatch: expected {} bytes but got {} bytes instead", target_size, data_size ), + UninhabitedEnumVariantWritten => { + write!(f, "writing discriminant of an uninhabited enum") + } } } }