about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-12-03 19:41:55 +0100
committerGitHub <noreply@github.com>2019-12-03 19:41:55 +0100
commitded98853ec377556112970cb35be4814efa0843e (patch)
tree939b44221247382641d7197ebf5141d1002ba373
parent69f1323167c71b79561fb4ac297de2fbd75eb017 (diff)
parent0be80f2909e0b5246c884db241a602a2f6d90488 (diff)
downloadrust-ded98853ec377556112970cb35be4814efa0843e.tar.gz
rust-ded98853ec377556112970cb35be4814efa0843e.zip
Rollup merge of #66960 - wesleywiser:fix_66787_take2, r=oli-obk,RalfJung
[const-prop] Fix ICE calculating enum discriminant

Fixes #66787

Different approach than #66857

r? @oli-obk
cc @RalfJung @eddyb
-rw-r--r--src/librustc_mir/interpret/place.rs23
-rw-r--r--src/test/ui/consts/issue-66787.rs39
2 files changed, 52 insertions, 10 deletions
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index da601c3a9f0..902472d18be 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -1065,13 +1065,16 @@ where
         variant_index: VariantIdx,
         dest: PlaceTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
-        let variant_scalar = Scalar::from_u32(variant_index.as_u32()).into();
+
+        // Layout computation excludes uninhabited variants from consideration
+        // therefore there's no way to represent those variants in the given layout.
+        if dest.layout.for_variant(self, variant_index).abi.is_uninhabited() {
+            throw_ub!(Unreachable);
+        }
 
         match dest.layout.variants {
             layout::Variants::Single { index } => {
-                if index != variant_index {
-                    throw_ub!(InvalidDiscriminant(variant_scalar));
-                }
+                assert_eq!(index, variant_index);
             }
             layout::Variants::Multiple {
                 discr_kind: layout::DiscriminantKind::Tag,
@@ -1079,9 +1082,9 @@ where
                 discr_index,
                 ..
             } => {
-                if !dest.layout.ty.variant_range(*self.tcx).unwrap().contains(&variant_index) {
-                    throw_ub!(InvalidDiscriminant(variant_scalar));
-                }
+                // No need to validate that the discriminant here because the
+                // `TyLayout::for_variant()` call earlier already checks the variant is valid.
+
                 let discr_val =
                     dest.layout.ty.discriminant_for_variant(*self.tcx, variant_index).unwrap().val;
 
@@ -1104,9 +1107,9 @@ where
                 discr_index,
                 ..
             } => {
-                if !variant_index.as_usize() < dest.layout.ty.ty_adt_def().unwrap().variants.len() {
-                    throw_ub!(InvalidDiscriminant(variant_scalar));
-                }
+                // No need to validate that the discriminant here because the
+                // `TyLayout::for_variant()` call earlier already checks the variant is valid.
+
                 if variant_index != dataful_variant {
                     let variants_start = niche_variants.start().as_u32();
                     let variant_index_relative = variant_index.as_u32()
diff --git a/src/test/ui/consts/issue-66787.rs b/src/test/ui/consts/issue-66787.rs
new file mode 100644
index 00000000000..612b795eb5c
--- /dev/null
+++ b/src/test/ui/consts/issue-66787.rs
@@ -0,0 +1,39 @@
+// build-pass
+// compile-flags: --crate-type lib
+
+// Regression test for ICE which occurred when const propagating an enum with three variants
+// one of which is uninhabited.
+
+pub enum ApiError {}
+#[allow(dead_code)]
+pub struct TokioError {
+    b: bool,
+}
+pub enum Error {
+    Api {
+        source: ApiError,
+    },
+    Ethereum,
+    Tokio {
+        source: TokioError,
+    },
+}
+struct Api;
+impl IntoError<Error> for Api
+{
+    type Source = ApiError;
+    fn into_error(self, error: Self::Source) -> Error {
+        Error::Api {
+            source: (|v| v)(error),
+        }
+    }
+}
+
+pub trait IntoError<E>
+{
+    /// The underlying error
+    type Source;
+
+    /// Combine the information to produce the error
+    fn into_error(self, source: Self::Source) -> E;
+}