about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_mir/build/matches/mod.rs18
-rw-r--r--src/librustc_mir/build/matches/simplify.rs20
-rw-r--r--src/librustc_mir/build/matches/test.rs152
-rw-r--r--src/librustc_mir/hair/mod.rs2
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs12
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs36
-rw-r--r--src/test/mir-opt/match_test.rs85
-rw-r--r--src/test/run-pass/mir/mir_match_test.rs83
8 files changed, 339 insertions, 69 deletions
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index 7e7c0b15555..4d61bf8dae6 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -19,7 +19,6 @@ use build::{BlockAnd, BlockAndExtension, Builder};
 use build::{GuardFrame, GuardFrameLocal, LocalsForNode};
 use hair::*;
 use hair::pattern::PatternTypeProjections;
-use rustc::hir;
 use rustc::mir::*;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::VariantIdx;
@@ -100,7 +99,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             .collect();
 
         // create binding start block for link them by false edges
-        let candidate_count = arms.iter().fold(0, |ac, c| ac + c.patterns.len());
+        let candidate_count = arms.iter().map(|c| c.patterns.len()).sum::<usize>();
         let pre_binding_blocks: Vec<_> = (0..=candidate_count)
             .map(|_| self.cfg.start_new_block())
             .collect();
@@ -337,7 +336,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     pub fn place_into_pattern(
         &mut self,
-        mut block: BasicBlock,
+        block: BasicBlock,
         irrefutable_pat: Pattern<'tcx>,
         initializer: &Place<'tcx>,
         set_match_place: bool,
@@ -359,7 +358,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
         // Simplify the candidate. Since the pattern is irrefutable, this should
         // always convert all match-pairs into bindings.
-        unpack!(block = self.simplify_candidate(block, &mut candidate));
+        self.simplify_candidate(&mut candidate);
 
         if !candidate.match_pairs.is_empty() {
             span_bug!(
@@ -681,12 +680,7 @@ enum TestKind<'tcx> {
     },
 
     // test whether the value falls within an inclusive or exclusive range
-    Range {
-        lo: &'tcx ty::Const<'tcx>,
-        hi: &'tcx ty::Const<'tcx>,
-        ty: Ty<'tcx>,
-        end: hir::RangeEnd,
-    },
+    Range(PatternRange<'tcx>),
 
     // test length of the slice is equal to len
     Len {
@@ -745,7 +739,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // complete, all the match pairs which remain require some
         // form of test, whether it be a switch or pattern comparison.
         for candidate in &mut candidates {
-            unpack!(block = self.simplify_candidate(block, candidate));
+            self.simplify_candidate(candidate);
         }
 
         // The candidates are sorted by priority. Check to see
@@ -1035,7 +1029,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             test, match_pair
         );
         let target_blocks = self.perform_test(block, &match_pair.place, &test);
-        let mut target_candidates: Vec<_> = (0..target_blocks.len()).map(|_| vec![]).collect();
+        let mut target_candidates = vec![vec![]; target_blocks.len()];
 
         // Sort the candidates into the appropriate vector in
         // `target_candidates`. Note that at some point we may
diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs
index 328b330f762..0ce64283870 100644
--- a/src/librustc_mir/build/matches/simplify.rs
+++ b/src/librustc_mir/build/matches/simplify.rs
@@ -22,10 +22,9 @@
 //! sort of test: for example, testing which variant an enum is, or
 //! testing a value against a constant.
 
-use build::{BlockAnd, BlockAndExtension, Builder};
+use build::Builder;
 use build::matches::{Ascription, Binding, MatchPair, Candidate};
 use hair::*;
-use rustc::mir::*;
 use rustc::ty;
 use rustc::ty::layout::{Integer, IntegerExt, Size};
 use syntax::attr::{SignedInt, UnsignedInt};
@@ -35,24 +34,23 @@ use std::mem;
 
 impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     pub fn simplify_candidate<'pat>(&mut self,
-                                    block: BasicBlock,
-                                    candidate: &mut Candidate<'pat, 'tcx>)
-                                    -> BlockAnd<()> {
+                                    candidate: &mut Candidate<'pat, 'tcx>) {
         // repeatedly simplify match pairs until fixed point is reached
         loop {
             let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]);
-            let mut progress = match_pairs.len(); // count how many were simplified
+            let mut changed = false;
             for match_pair in match_pairs {
                 match self.simplify_match_pair(match_pair, candidate) {
-                    Ok(()) => {}
+                    Ok(()) => {
+                        changed = true;
+                    }
                     Err(match_pair) => {
                         candidate.match_pairs.push(match_pair);
-                        progress -= 1; // this one was not simplified
                     }
                 }
             }
-            if progress == 0 {
-                return block.unit(); // if we were not able to simplify any, done.
+            if !changed {
+                return; // if we were not able to simplify any, done.
             }
         }
     }
@@ -109,7 +107,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 Err(match_pair)
             }
 
-            PatternKind::Range { lo, hi, ty, end } => {
+            PatternKind::Range(PatternRange { lo, hi, ty, end }) => {
                 let range = match ty.sty {
                     ty::Char => {
                         Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32)))
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 5d9cb014f58..c8dec6d0b97 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -18,6 +18,7 @@
 use build::Builder;
 use build::matches::{Candidate, MatchPair, Test, TestKind};
 use hair::*;
+use hair::pattern::compare_const_vals;
 use rustc_data_structures::bit_set::BitSet;
 use rustc_data_structures::fx::FxHashMap;
 use rustc::ty::{self, Ty};
@@ -71,16 +72,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 }
             }
 
-            PatternKind::Range { lo, hi, ty, end } => {
-                assert!(ty == match_pair.pattern.ty);
+            PatternKind::Range(range) => {
+                assert!(range.ty == match_pair.pattern.ty);
                 Test {
                     span: match_pair.pattern.span,
-                    kind: TestKind::Range {
-                        lo,
-                        hi,
-                        ty,
-                        end,
-                    },
+                    kind: TestKind::Range(range),
                 }
             }
 
@@ -136,7 +132,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             PatternKind::Variant { .. } => {
                 panic!("you should have called add_variants_to_switch instead!");
             }
-            PatternKind::Range { .. } |
+            PatternKind::Range(range) => {
+                // Check that none of the switch values are in the range.
+                self.values_not_contained_in_range(range, indices)
+                    .unwrap_or(false)
+            }
             PatternKind::Slice { .. } |
             PatternKind::Array { .. } |
             PatternKind::Wild |
@@ -200,20 +200,18 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 for (idx, discr) in adt_def.discriminants(tcx) {
                     target_blocks.push(if variants.contains(idx) {
                         values.push(discr.val);
-                        targets.push(self.cfg.start_new_block());
-                        *targets.last().unwrap()
+                        let block = self.cfg.start_new_block();
+                        targets.push(block);
+                        block
                     } else {
-                        if otherwise_block.is_none() {
-                            otherwise_block = Some(self.cfg.start_new_block());
-                        }
-                        otherwise_block.unwrap()
+                        *otherwise_block
+                            .get_or_insert_with(|| self.cfg.start_new_block())
                     });
                 }
-                if let Some(otherwise_block) = otherwise_block {
-                    targets.push(otherwise_block);
-                } else {
-                    targets.push(self.unreachable_block());
-                }
+                targets.push(
+                    otherwise_block
+                        .unwrap_or_else(|| self.unreachable_block()),
+                );
                 debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
                        num_enum_variants, values, variants);
                 let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
@@ -378,7 +376,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 }
             }
 
-            TestKind::Range { ref lo, ref hi, ty, ref end } => {
+            TestKind::Range(PatternRange { ref lo, ref hi, ty, ref end }) => {
                 // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
                 let lo = self.literal_operand(test.span, ty.clone(), lo.clone());
                 let hi = self.literal_operand(test.span, ty.clone(), hi.clone());
@@ -490,8 +488,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
         // away.)
         let tested_match_pair = candidate.match_pairs.iter()
                                                      .enumerate()
-                                                     .filter(|&(_, mp)| mp.place == *test_place)
-                                                     .next();
+                                                     .find(|&(_, mp)| mp.place == *test_place);
         let (match_pair_index, match_pair) = match tested_match_pair {
             Some(pair) => pair,
             None => {
@@ -532,6 +529,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 resulting_candidates[index].push(new_candidate);
                 true
             }
+
+            (&TestKind::SwitchInt { switch_ty: _, ref options, ref indices },
+             &PatternKind::Range(range)) => {
+                let not_contained = self
+                    .values_not_contained_in_range(range, indices)
+                    .unwrap_or(false);
+
+                if not_contained {
+                    // No switch values are contained in the pattern range,
+                    // so the pattern can be matched only if this test fails.
+                    let otherwise = options.len();
+                    resulting_candidates[otherwise].push(candidate.clone());
+                    true
+                } else {
+                    false
+                }
+            }
+
             (&TestKind::SwitchInt { .. }, _) => false,
 
 
@@ -610,8 +625,63 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                 }
             }
 
+            (&TestKind::Range(test),
+             &PatternKind::Range(pat)) => {
+                if test == pat {
+                    resulting_candidates[0]
+                        .push(self.candidate_without_match_pair(
+                            match_pair_index,
+                            candidate,
+                        ));
+                    return true;
+                }
+
+                let no_overlap = (|| {
+                    use std::cmp::Ordering::*;
+                    use rustc::hir::RangeEnd::*;
+
+                    let param_env = ty::ParamEnv::empty().and(test.ty);
+                    let tcx = self.hir.tcx();
+
+                    let lo = compare_const_vals(tcx, test.lo, pat.hi, param_env)?;
+                    let hi = compare_const_vals(tcx, test.hi, pat.lo, param_env)?;
+
+                    match (test.end, pat.end, lo, hi) {
+                        // pat < test
+                        (_, _, Greater, _) |
+                        (_, Excluded, Equal, _) |
+                        // pat > test
+                        (_, _, _, Less) |
+                        (Excluded, _, _, Equal) => Some(true),
+                        _ => Some(false),
+                    }
+                })();
+
+                if no_overlap == Some(true) {
+                    // Testing range does not overlap with pattern range,
+                    // so the pattern can be matched only if this test fails.
+                    resulting_candidates[1].push(candidate.clone());
+                    true
+                } else {
+                    false
+                }
+            }
+
+            (&TestKind::Range(range), &PatternKind::Constant { ref value }) => {
+                if self.const_range_contains(range, value) == Some(false) {
+                    // `value` is not contained in the testing range,
+                    // so `value` can be matched only if this test fails.
+                    resulting_candidates[1].push(candidate.clone());
+                    true
+                } else {
+                    false
+                }
+            }
+
+            (&TestKind::Range { .. }, _) => false,
+
+
             (&TestKind::Eq { .. }, _) |
-            (&TestKind::Range { .. }, _) |
             (&TestKind::Len { .. }, _) => {
                 // These are all binary tests.
                 //
@@ -722,6 +792,40 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                   "simplifyable pattern found: {:?}",
                   match_pair.pattern)
     }
+
+    fn const_range_contains(
+        &self,
+        range: PatternRange<'tcx>,
+        value: &'tcx ty::Const<'tcx>,
+    ) -> Option<bool> {
+        use std::cmp::Ordering::*;
+
+        let param_env = ty::ParamEnv::empty().and(range.ty);
+        let tcx = self.hir.tcx();
+
+        let a = compare_const_vals(tcx, range.lo, value, param_env)?;
+        let b = compare_const_vals(tcx, value, range.hi, param_env)?;
+
+        match (b, range.end) {
+            (Less, _) |
+            (Equal, RangeEnd::Included) if a != Greater => Some(true),
+            _ => Some(false),
+        }
+    }
+
+    fn values_not_contained_in_range(
+        &self,
+        range: PatternRange<'tcx>,
+        indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>,
+    ) -> Option<bool> {
+        for val in indices.keys() {
+            if self.const_range_contains(range, val)? {
+                return Some(false);
+            }
+        }
+
+        Some(true)
+    }
 }
 
 fn is_switch_ty<'tcx>(ty: Ty<'tcx>) -> bool {
diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs
index e604b118eac..b254fce4b76 100644
--- a/src/librustc_mir/hair/mod.rs
+++ b/src/librustc_mir/hair/mod.rs
@@ -29,7 +29,7 @@ pub mod cx;
 mod constant;
 
 pub mod pattern;
-pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
+pub use self::pattern::{BindingMode, Pattern, PatternKind, PatternRange, FieldPattern};
 pub(crate) use self::pattern::{PatternTypeProjection, PatternTypeProjections};
 
 mod util;
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 5cfcc16162e..7ec6bbfe3c1 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -173,7 +173,7 @@ use self::WitnessPreference::*;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::indexed_vec::Idx;
 
-use super::{FieldPattern, Pattern, PatternKind};
+use super::{FieldPattern, Pattern, PatternKind, PatternRange};
 use super::{PatternFoldable, PatternFolder, compare_const_vals};
 
 use rustc::hir::def_id::DefId;
@@ -604,12 +604,12 @@ impl<'tcx> Witness<'tcx> {
                 _ => {
                     match *ctor {
                         ConstantValue(value) => PatternKind::Constant { value },
-                        ConstantRange(lo, hi, ty, end) => PatternKind::Range {
+                        ConstantRange(lo, hi, ty, end) => PatternKind::Range(PatternRange {
                             lo: ty::Const::from_bits(cx.tcx, lo, ty::ParamEnv::empty().and(ty)),
                             hi: ty::Const::from_bits(cx.tcx, hi, ty::ParamEnv::empty().and(ty)),
                             ty,
                             end,
-                        },
+                        }),
                         _ => PatternKind::Wild,
                     }
                 }
@@ -872,7 +872,7 @@ impl<'tcx> IntRange<'tcx> {
                 -> Option<IntRange<'tcx>> {
         Self::from_ctor(tcx, &match pat.kind {
             box PatternKind::Constant { value } => ConstantValue(value),
-            box PatternKind::Range { lo, hi, ty, end } => ConstantRange(
+            box PatternKind::Range(PatternRange { lo, hi, ty, end }) => ConstantRange(
                 lo.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
                 hi.to_bits(tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
                 ty,
@@ -1311,7 +1311,7 @@ fn pat_constructors<'tcx>(cx: &mut MatchCheckCtxt<'_, 'tcx>,
             Some(vec![Variant(adt_def.variants[variant_index].did)])
         }
         PatternKind::Constant { value } => Some(vec![ConstantValue(value)]),
-        PatternKind::Range { lo, hi, ty, end } =>
+        PatternKind::Range(PatternRange { lo, hi, ty, end }) =>
             Some(vec![ConstantRange(
                 lo.to_bits(cx.tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
                 hi.to_bits(cx.tcx, ty::ParamEnv::empty().and(ty)).unwrap(),
@@ -1642,7 +1642,7 @@ fn constructor_covered_by_range<'a, 'tcx>(
 ) -> Result<bool, ErrorReported> {
     let (from, to, end, ty) = match pat.kind {
         box PatternKind::Constant { value } => (value, value, RangeEnd::Included, value.ty),
-        box PatternKind::Range { lo, hi, ty, end } => (lo, hi, end, ty),
+        box PatternKind::Range(PatternRange { lo, hi, end, ty }) => (lo, hi, end, ty),
         _ => bug!("`constructor_covered_by_range` called with {:?}", pat),
     };
     trace!("constructor_covered_by_range {:#?}, {:#?}, {:#?}, {}", ctor, from, to, ty);
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index ddd6a705b04..f78a70f6a25 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -24,7 +24,7 @@ use hair::constant::*;
 use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability};
 use rustc::mir::{ProjectionElem, UserTypeAnnotation, UserTypeProjection, UserTypeProjections};
 use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend};
-use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty};
+use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty, Lift};
 use rustc::ty::subst::{Substs, Kind};
 use rustc::ty::layout::VariantIdx;
 use rustc::hir::{self, PatKind, RangeEnd};
@@ -219,12 +219,7 @@ pub enum PatternKind<'tcx> {
         value: &'tcx ty::Const<'tcx>,
     },
 
-    Range {
-        lo: &'tcx ty::Const<'tcx>,
-        hi: &'tcx ty::Const<'tcx>,
-        ty: Ty<'tcx>,
-        end: RangeEnd,
-    },
+    Range(PatternRange<'tcx>),
 
     /// matches against a slice, checking the length and extracting elements.
     /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty.
@@ -243,6 +238,14 @@ pub enum PatternKind<'tcx> {
     },
 }
 
+#[derive(Clone, Copy, Debug, PartialEq)]
+pub struct PatternRange<'tcx> {
+    pub lo: &'tcx ty::Const<'tcx>,
+    pub hi: &'tcx ty::Const<'tcx>,
+    pub ty: Ty<'tcx>,
+    pub end: RangeEnd,
+}
+
 impl<'tcx> fmt::Display for Pattern<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self.kind {
@@ -354,7 +357,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
             PatternKind::Constant { value } => {
                 fmt_const_val(f, value)
             }
-            PatternKind::Range { lo, hi, ty: _, end } => {
+            PatternKind::Range(PatternRange { lo, hi, ty: _, end }) => {
                 fmt_const_val(f, lo)?;
                 match end {
                     RangeEnd::Included => write!(f, "..=")?,
@@ -483,7 +486,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                         );
                         match (end, cmp) {
                             (RangeEnd::Excluded, Some(Ordering::Less)) =>
-                                PatternKind::Range { lo, hi, ty, end },
+                                PatternKind::Range(PatternRange { lo, hi, ty, end }),
                             (RangeEnd::Excluded, _) => {
                                 span_err!(
                                     self.tcx.sess,
@@ -497,7 +500,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
                                 PatternKind::Constant { value: lo }
                             }
                             (RangeEnd::Included, Some(Ordering::Less)) => {
-                                PatternKind::Range { lo, hi, ty, end }
+                                PatternKind::Range(PatternRange { lo, hi, ty, end })
                             }
                             (RangeEnd::Included, _) => {
                                 let mut err = struct_span_err!(
@@ -1177,17 +1180,17 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
             } => PatternKind::Constant {
                 value: value.fold_with(folder)
             },
-            PatternKind::Range {
+            PatternKind::Range(PatternRange {
                 lo,
                 hi,
                 ty,
                 end,
-            } => PatternKind::Range {
+            }) => PatternKind::Range(PatternRange {
                 lo: lo.fold_with(folder),
                 hi: hi.fold_with(folder),
                 ty: ty.fold_with(folder),
                 end,
-            },
+            }),
             PatternKind::Slice {
                 ref prefix,
                 ref slice,
@@ -1210,8 +1213,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> {
     }
 }
 
-pub fn compare_const_vals<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+pub fn compare_const_vals<'a, 'gcx, 'tcx>(
+    tcx: TyCtxt<'a, 'gcx, 'tcx>,
     a: &'tcx ty::Const<'tcx>,
     b: &'tcx ty::Const<'tcx>,
     ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
@@ -1233,6 +1236,9 @@ pub fn compare_const_vals<'a, 'tcx>(
         return fallback();
     }
 
+    let tcx = tcx.global_tcx();
+    let (a, b, ty) = (a, b, ty).lift_to_tcx(tcx).unwrap();
+
     // FIXME: This should use assert_bits(ty) instead of use_bits
     // but triggers possibly bugs due to mismatching of arrays and slices
     if let (Some(a), Some(b)) = (a.to_bits(tcx, ty), b.to_bits(tcx, ty)) {
diff --git a/src/test/mir-opt/match_test.rs b/src/test/mir-opt/match_test.rs
new file mode 100644
index 00000000000..9bfb728e134
--- /dev/null
+++ b/src/test/mir-opt/match_test.rs
@@ -0,0 +1,85 @@
+// Make sure redundant testing paths in `match` expressions are sorted out.
+
+#![feature(exclusive_range_pattern)]
+
+fn main() {
+    let x = 3;
+    let b = true;
+
+    // When `(0..=10).contains(x) && !b`, we should jump to the last arm
+    // without testing two other candidates.
+    match x {
+        0..10 if b => 0,
+        10..=20 => 1,
+        -1 => 2,
+        _ => 3,
+    };
+}
+
+// END RUST SOURCE
+// START rustc.main.SimplifyCfg-initial.after.mir
+//    bb0: {
+//        ...
+//        _4 = Le(const 0i32, _1);
+//        switchInt(move _4) -> [false: bb10, otherwise: bb11];
+//    }
+//    bb1: {
+//        _3 = const 0i32;
+//        goto -> bb16;
+//    }
+//    bb2: {
+//        _3 = const 1i32;
+//        goto -> bb16;
+//    }
+//    bb3: {
+//        _3 = const 2i32;
+//        goto -> bb16;
+//    }
+//    bb4: {
+//        _3 = const 3i32;
+//        goto -> bb16;
+//    }
+//    bb5: {
+//        falseEdges -> [real: bb12, imaginary: bb6];
+//    }
+//    bb6: {
+//        falseEdges -> [real: bb2, imaginary: bb7];
+//    }
+//    bb7: {
+//        falseEdges -> [real: bb3, imaginary: bb8];
+//    }
+//    bb8: {
+//        falseEdges -> [real: bb4, imaginary: bb9];
+//    }
+//    bb9: {
+//        unreachable;
+//    }
+//    bb10: {
+//        _7 = Le(const 10i32, _1);
+//        switchInt(move _7) -> [false: bb14, otherwise: bb15];
+//    }
+//    bb11: {
+//        _5 = Lt(_1, const 10i32);
+//        switchInt(move _5) -> [false: bb10, otherwise: bb5];
+//    }
+//    bb12: {
+//        StorageLive(_6);
+//        _6 = _2;
+//        switchInt(move _6) -> [false: bb13, otherwise: bb1];
+//    }
+//    bb13: {
+//        falseEdges -> [real: bb8, imaginary: bb6];
+//    }
+//    bb14: {
+//        switchInt(_1) -> [-1i32: bb7, otherwise: bb8];
+//    }
+//    bb15: {
+//        _8 = Le(_1, const 20i32);
+//        switchInt(move _8) -> [false: bb14, otherwise: bb6];
+//    }
+//    bb16: {
+//        StorageDead(_6);
+//        ...
+//        return;
+//    }
+// END rustc.main.SimplifyCfg-initial.after.mir
diff --git a/src/test/run-pass/mir/mir_match_test.rs b/src/test/run-pass/mir/mir_match_test.rs
new file mode 100644
index 00000000000..1f96d6737e0
--- /dev/null
+++ b/src/test/run-pass/mir/mir_match_test.rs
@@ -0,0 +1,83 @@
+#![feature(exclusive_range_pattern)]
+
+// run-pass
+
+fn main() {
+    let incl_range = |x, b| {
+        match x {
+            0..=5 if b => 0,
+            5..=10 if b => 1,
+            1..=4 if !b => 2,
+            _ => 3,
+        }
+    };
+    assert_eq!(incl_range(3, false), 2);
+    assert_eq!(incl_range(3, true), 0);
+    assert_eq!(incl_range(5, false), 3);
+    assert_eq!(incl_range(5, true), 0);
+
+    let excl_range = |x, b| {
+        match x {
+            0..5 if b => 0,
+            5..10 if b => 1,
+            1..4 if !b => 2,
+            _ => 3,
+        }
+    };
+    assert_eq!(excl_range(3, false), 2);
+    assert_eq!(excl_range(3, true), 0);
+    assert_eq!(excl_range(5, false), 3);
+    assert_eq!(excl_range(5, true), 1);
+
+    let incl_range_vs_const = |x, b| {
+        match x {
+            0..=5 if b => 0,
+            7 => 1,
+            3 => 2,
+            _ => 3,
+        }
+    };
+    assert_eq!(incl_range_vs_const(5, false), 3);
+    assert_eq!(incl_range_vs_const(5, true), 0);
+    assert_eq!(incl_range_vs_const(3, false), 2);
+    assert_eq!(incl_range_vs_const(3, true), 0);
+    assert_eq!(incl_range_vs_const(7, false), 1);
+    assert_eq!(incl_range_vs_const(7, true), 1);
+
+    let excl_range_vs_const = |x, b| {
+        match x {
+            0..5 if b => 0,
+            7 => 1,
+            3 => 2,
+            _ => 3,
+        }
+    };
+    assert_eq!(excl_range_vs_const(5, false), 3);
+    assert_eq!(excl_range_vs_const(5, true), 3);
+    assert_eq!(excl_range_vs_const(3, false), 2);
+    assert_eq!(excl_range_vs_const(3, true), 0);
+    assert_eq!(excl_range_vs_const(7, false), 1);
+    assert_eq!(excl_range_vs_const(7, true), 1);
+
+    let const_vs_incl_range = |x, b| {
+        match x {
+            3 if b => 0,
+            5..=7 => 2,
+            1..=4 => 1,
+            _ => 3,
+        }
+    };
+    assert_eq!(const_vs_incl_range(3, false), 1);
+    assert_eq!(const_vs_incl_range(3, true), 0);
+
+    let const_vs_excl_range = |x, b| {
+        match x {
+            3 if b => 0,
+            5..7 => 2,
+            1..4 => 1,
+            _ => 3,
+        }
+    };
+    assert_eq!(const_vs_excl_range(3, false), 1);
+    assert_eq!(const_vs_excl_range(3, true), 0);
+}