about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs4
-rw-r--r--src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff95
-rw-r--r--src/test/mir-opt/const_prop/invalid_constant.rs41
3 files changed, 75 insertions, 65 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index ba1d5f45bbb..724f92243d0 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -147,6 +147,10 @@ pub(crate) fn try_destructure_const<'tcx>(
     // We go to `usize` as we cannot allocate anything bigger anyway.
     let (field_count, variant, down) = match val.ty().kind() {
         ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
+        // Checks if we have any variants, to avoid downcasting to a non-existing variant (when
+        // there are no variants `read_discriminant` successfully returns a non-existing variant
+        // index).
+        ty::Adt(def, _) if def.variants.is_empty() => throw_ub!(Unreachable),
         ty::Adt(def, _) => {
             let variant = ecx.read_discriminant(&op)?.1;
             let down = ecx.operand_downcast(&op, variant)?;
diff --git a/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
index 1b53318806f..03f827f63f3 100644
--- a/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
@@ -2,68 +2,63 @@
 + // MIR for `main` after ConstProp
   
   fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/invalid_constant.rs:15:11: 15:11
-      let _1: std::option::Option<()>;     // in scope 0 at $DIR/invalid_constant.rs:16:5: 16:12
-      let mut _2: std::option::Option<std::option::Option<()>>; // in scope 0 at $DIR/invalid_constant.rs:16:7: 16:11
-      let _3: main::Union;                 // in scope 0 at $DIR/invalid_constant.rs:22:9: 22:22
+      let mut _0: ();                      // return place in scope 0 at $DIR/invalid_constant.rs:13:11: 13:11
+      let _1: main::InvalidChar;           // in scope 0 at $DIR/invalid_constant.rs:19:9: 19:22
+      let mut _3: main::InvalidTag;        // in scope 0 at $DIR/invalid_constant.rs:26:25: 26:46
+      let mut _5: main::NoVariants;        // in scope 0 at $DIR/invalid_constant.rs:33:35: 33:56
       scope 1 {
-          debug _invalid_char => _3;       // in scope 1 at $DIR/invalid_constant.rs:22:9: 22:22
-      }
-      scope 2 (inlined f) {                // at $DIR/invalid_constant.rs:16:5: 16:12
-          debug x => _2;                   // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
-          let mut _4: isize;               // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
-          let _5: std::option::Option<()>; // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
-          scope 3 {
-              debug y => _5;               // in scope 3 at $DIR/invalid_constant.rs:16:5: 16:12
+          debug _invalid_char => _1;       // in scope 1 at $DIR/invalid_constant.rs:19:9: 19:22
+          let _2: [main::InvalidTag; 1];   // in scope 1 at $DIR/invalid_constant.rs:26:9: 26:21
+          scope 2 {
+              debug _invalid_tag => _2;    // in scope 2 at $DIR/invalid_constant.rs:26:9: 26:21
+              let _4: [main::NoVariants; 1]; // in scope 2 at $DIR/invalid_constant.rs:33:9: 33:31
+              scope 3 {
+                  debug _enum_without_variants => _4; // in scope 3 at $DIR/invalid_constant.rs:33:9: 33:31
+              }
           }
       }
   
       bb0: {
-          discriminant(_2) = 0;            // scope 0 at $DIR/invalid_constant.rs:16:7: 16:11
--         _4 = discriminant(_2);           // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
--         switchInt(move _4) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
-+         _4 = const 0_isize;              // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
-+         switchInt(const 0_isize) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
-      }
-  
-      bb1: {
--         _3 = const { Union { int: 0x110001 } }; // scope 0 at $DIR/invalid_constant.rs:22:25: 22:58
-+         _3 = const main::Union { int: 1114113_u32, chr: {transmute(0x00110001): char} }; // scope 0 at $DIR/invalid_constant.rs:22:25: 22:58
+          StorageLive(_1);                 // scope 0 at $DIR/invalid_constant.rs:19:9: 19:22
+-         _1 = const { InvalidChar { int: 0x110001 } }; // scope 0 at $DIR/invalid_constant.rs:19:25: 19:64
++         _1 = const InvalidChar { int: 1114113_u32, chr: {transmute(0x00110001): char} }; // scope 0 at $DIR/invalid_constant.rs:19:25: 19:64
                                            // ty::Const
-                                           // + ty: main::Union
--                                          // + val: Unevaluated(main::{constant#0}, [main::Union], None)
+                                           // + ty: main::InvalidChar
+-                                          // + val: Unevaluated(main::{constant#0}, [main::InvalidChar], None)
 +                                          // + val: Value(Scalar(0x00110001))
                                            // mir::Constant
-                                           // + span: $DIR/invalid_constant.rs:22:25: 22:58
--                                          // + literal: Const { ty: main::Union, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:8 ~ invalid_constant[726d]::main::{constant#0}), const_param_did: None }, substs: [main::Union], promoted: None }) }
-+                                          // + literal: Const { ty: main::Union, val: Value(Scalar(0x00110001)) }
-          nop;                             // scope 0 at $DIR/invalid_constant.rs:15:11: 23:2
-          return;                          // scope 0 at $DIR/invalid_constant.rs:23:2: 23:2
-      }
-  
-      bb2: {
--         _5 = ((_2 as Some).0: std::option::Option<()>); // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
--         _1 = _5;                         // scope 3 at $DIR/invalid_constant.rs:16:5: 16:12
-+         _5 = const Scalar(0x02): Option::<()>; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
+                                           // + span: $DIR/invalid_constant.rs:19:25: 19:64
+-                                          // + literal: Const { ty: main::InvalidChar, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ invalid_constant[726d]::main::{constant#0}), const_param_did: None }, substs: [main::InvalidChar], promoted: None }) }
++                                          // + literal: Const { ty: main::InvalidChar, val: Value(Scalar(0x00110001)) }
+          StorageLive(_2);                 // scope 1 at $DIR/invalid_constant.rs:26:9: 26:21
+          StorageLive(_3);                 // scope 1 at $DIR/invalid_constant.rs:26:25: 26:46
+          (_3.0: u32) = const 4_u32;       // scope 1 at $DIR/invalid_constant.rs:26:25: 26:46
+-         _2 = [move _3];                  // scope 1 at $DIR/invalid_constant.rs:26:24: 26:47
++         _2 = [const InvalidTag { int: 4_u32, e: Scalar(0x00000004): E }]; // scope 1 at $DIR/invalid_constant.rs:26:24: 26:47
 +                                          // ty::Const
-+                                          // + ty: std::option::Option<()>
-+                                          // + val: Value(Scalar(0x02))
++                                          // + ty: main::InvalidTag
++                                          // + val: Value(Scalar(0x00000004))
 +                                          // mir::Constant
-+                                          // + span: $DIR/invalid_constant.rs:16:5: 16:12
-+                                          // + literal: Const { ty: std::option::Option<()>, val: Value(Scalar(0x02)) }
-+         _1 = const Scalar(0x02): Option::<()>; // scope 3 at $DIR/invalid_constant.rs:16:5: 16:12
++                                          // + span: $DIR/invalid_constant.rs:26:24: 26:47
++                                          // + literal: Const { ty: main::InvalidTag, val: Value(Scalar(0x00000004)) }
+          StorageDead(_3);                 // scope 1 at $DIR/invalid_constant.rs:26:46: 26:47
+          StorageLive(_4);                 // scope 2 at $DIR/invalid_constant.rs:33:9: 33:31
+          StorageLive(_5);                 // scope 2 at $DIR/invalid_constant.rs:33:35: 33:56
+          (_5.0: u32) = const 0_u32;       // scope 2 at $DIR/invalid_constant.rs:33:35: 33:56
+-         _4 = [move _5];                  // scope 2 at $DIR/invalid_constant.rs:33:34: 33:57
++         _4 = [const NoVariants { int: 0_u32, empty: Scalar(<ZST>): Empty }]; // scope 2 at $DIR/invalid_constant.rs:33:34: 33:57
 +                                          // ty::Const
-+                                          // + ty: std::option::Option<()>
-+                                          // + val: Value(Scalar(0x02))
++                                          // + ty: main::NoVariants
++                                          // + val: Value(Scalar(0x00000000))
 +                                          // mir::Constant
-+                                          // + span: $DIR/invalid_constant.rs:16:5: 16:12
-+                                          // + literal: Const { ty: std::option::Option<()>, val: Value(Scalar(0x02)) }
-          goto -> bb1;                     // scope 0 at $DIR/invalid_constant.rs:10:20: 10:21
-      }
-  
-      bb3: {
-          discriminant(_1) = 0;            // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
-          goto -> bb1;                     // scope 0 at $DIR/invalid_constant.rs:9:17: 9:21
++                                          // + span: $DIR/invalid_constant.rs:33:34: 33:57
++                                          // + literal: Const { ty: main::NoVariants, val: Value(Scalar(0x00000000)) }
+          StorageDead(_5);                 // scope 2 at $DIR/invalid_constant.rs:33:56: 33:57
+          nop;                             // scope 0 at $DIR/invalid_constant.rs:13:11: 34:2
+          StorageDead(_4);                 // scope 2 at $DIR/invalid_constant.rs:34:1: 34:2
+          StorageDead(_2);                 // scope 1 at $DIR/invalid_constant.rs:34:1: 34:2
+          StorageDead(_1);                 // scope 0 at $DIR/invalid_constant.rs:34:1: 34:2
+          return;                          // scope 0 at $DIR/invalid_constant.rs:34:2: 34:2
       }
   }
   
diff --git a/src/test/mir-opt/const_prop/invalid_constant.rs b/src/test/mir-opt/const_prop/invalid_constant.rs
index 4aca9090019..e0879cf4800 100644
--- a/src/test/mir-opt/const_prop/invalid_constant.rs
+++ b/src/test/mir-opt/const_prop/invalid_constant.rs
@@ -1,23 +1,34 @@
-// Verify that we can pretty print invalid constant introduced
-// by constant propagation. Regression test for issue #93688.
-//
-// compile-flags: -Copt-level=0 -Zinline-mir
+// Verify that we can pretty print invalid constants.
+
 #![feature(inline_const)]
-#[inline(always)]
-pub fn f(x: Option<Option<()>>) -> Option<()> {
-    match x {
-        None => None,
-        Some(y) => y,
-    }
-}
+
+#[derive(Copy, Clone)]
+#[repr(u32)]
+enum E { A, B, C }
+
+#[derive(Copy, Clone)]
+enum Empty {}
 
 // EMIT_MIR invalid_constant.main.ConstProp.diff
 fn main() {
-    f(None);
-
-    union Union {
+    // An invalid char.
+    union InvalidChar {
         int: u32,
         chr: char,
     }
-    let _invalid_char = const { Union { int: 0x110001 } };
+    let _invalid_char = const { InvalidChar { int: 0x110001 } };
+
+    // An enum with an invalid tag. Regression test for #93688.
+    union InvalidTag {
+        int: u32,
+        e: E,
+    }
+    let _invalid_tag = [InvalidTag { int: 4 }];
+
+    // An enum without variants. Regression test for #94073.
+    union NoVariants {
+        int: u32,
+        empty: Empty,
+    }
+    let _enum_without_variants = [NoVariants { int: 0 }];
 }