about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2021-10-13 16:53:09 -0400
committerRalf Jung <post@ralfj.de>2021-10-14 10:03:20 -0400
commitc5a68cf0a65fe94022f5c5fd0fc47ccfcda81929 (patch)
treef79ca26886d35ab23ac77af8864c9037f4595147
parenteeb16a2a892c2a29b1da3085e29f39efa3486e1c (diff)
downloadrust-c5a68cf0a65fe94022f5c5fd0fc47ccfcda81929.tar.gz
rust-c5a68cf0a65fe94022f5c5fd0fc47ccfcda81929.zip
add dedicated error variant for writing the discriminant of an uninhabited enum variant
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs1
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs15
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs5
3 files changed, 20 insertions, 1 deletions
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 @@ 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>,
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 @@ 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 {
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 @@ 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")
+            }
         }
     }
 }