about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-03-30 11:48:10 +0000
committerbors <bors@rust-lang.org>2018-03-30 11:48:10 +0000
commit4379c86fe752d0e2eb969646d5a18014ac969a26 (patch)
tree6729641d89233b55bee1da33d127cc3c6ef8fe1d
parent051050dab9b39d29c8a5978bc79c7895dfa1118b (diff)
parent422efd793b0d65bd1d1725937a853244af8124c8 (diff)
downloadrust-4379c86fe752d0e2eb969646d5a18014ac969a26.tar.gz
rust-4379c86fe752d0e2eb969646d5a18014ac969a26.zip
Auto merge of #49403 - oli-obk:try2, r=eddyb
Trim discriminants to their final type size

r? @eddyb

fixes  #49181
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs37
-rw-r--r--src/test/run-pass/match-arm-statics.rs7
2 files changed, 38 insertions, 6 deletions
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index eb87d5b044b..798d6353181 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -851,13 +851,38 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
             ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
                 match cv.val {
                     ConstVal::Value(val) => {
-                        let discr = const_discr(
+                        let discr_val = const_discr(
                             self.tcx, self.param_env, instance, val, cv.ty
-                        ).unwrap();
-                        let variant_index = adt_def
-                            .discriminants(self.tcx)
-                            .position(|var| var.val == discr)
-                            .unwrap();
+                        ).expect("const_discr failed");
+                        let layout = self
+                            .tcx
+                            .layout_of(self.param_env.and(cv.ty))
+                            .expect("layout of enum not available");
+                        let variant_index = match layout.variants {
+                            ty::layout::Variants::Single { index } => index,
+                            ty::layout::Variants::Tagged { ref discr, .. } => {
+                                // raw discriminants for enums are isize or bigger during
+                                // their computation, but later shrunk to the smallest possible
+                                // representation
+                                let size = discr.value.size(self.tcx).bits();
+                                let amt = 128 - size;
+                                adt_def
+                                    .discriminants(self.tcx)
+                                    .position(|var| ((var.val << amt) >> amt) == discr_val)
+                                    .unwrap_or_else(|| {
+                                        bug!("discriminant {} not found in {:#?}",
+                                            discr_val,
+                                            adt_def
+                                                .discriminants(self.tcx)
+                                                .collect::<Vec<_>>(),
+                                            );
+                                    })
+                            }
+                            ty::layout::Variants::NicheFilling { .. } => {
+                                assert_eq!(discr_val as usize as u128, discr_val);
+                                discr_val as usize
+                            },
+                        };
                         let subpatterns = adt_subpatterns(
                             adt_def.variants[variant_index].fields.len(),
                             Some(variant_index),
diff --git a/src/test/run-pass/match-arm-statics.rs b/src/test/run-pass/match-arm-statics.rs
index 78a37f51837..ca6ef2e4277 100644
--- a/src/test/run-pass/match-arm-statics.rs
+++ b/src/test/run-pass/match-arm-statics.rs
@@ -94,6 +94,13 @@ fn issue_14576() {
     const F : C = C::D;
 
     assert_eq!(match C::D { F => 1, _ => 2, }, 1);
+
+    // test gaps
+    #[derive(PartialEq, Eq)]
+    enum G { H = 3, I = 5 }
+    const K : G = G::I;
+
+    assert_eq!(match G::I { K => 1, _ => 2, }, 1);
 }
 
 fn issue_13731() {