From 6b3202a2bfd33f435d3266f2583c0f5d3356251d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 27 Mar 2018 08:31:05 +0200 Subject: [PATCH 1/2] Trim discriminants to their final type size --- src/librustc_mir/hair/pattern/mod.rs | 35 +++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index eb87d5b044b45..7359b1ed1021c 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -851,13 +851,36 @@ 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::>(), + ); + }) + } + ty::layout::Variants::NicheFilling { dataful_variant, .. } => + dataful_variant, + }; let subpatterns = adt_subpatterns( adt_def.variants[variant_index].fields.len(), Some(variant_index), From 422efd793b0d65bd1d1725937a853244af8124c8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 27 Mar 2018 17:19:41 +0200 Subject: [PATCH 2/2] Use the actual discriminant instead of always choosing the dataful variant --- src/librustc_mir/hair/pattern/mod.rs | 6 ++++-- src/test/run-pass/match-arm-statics.rs | 7 +++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 7359b1ed1021c..798d635318180 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -878,8 +878,10 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { ); }) } - ty::layout::Variants::NicheFilling { dataful_variant, .. } => - dataful_variant, + 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(), diff --git a/src/test/run-pass/match-arm-statics.rs b/src/test/run-pass/match-arm-statics.rs index 78a37f5183786..ca6ef2e42777b 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() {