about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2016-10-03 21:39:21 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2016-10-26 22:41:17 +0300
commit76fb7d90ecde3659021341779fea598a6daab013 (patch)
treedeb904e289d86521621c143267d58068797df5af
parent37418b850f43fd95596c688c230f5e8d94e1962f (diff)
downloadrust-76fb7d90ecde3659021341779fea598a6daab013.tar.gz
rust-76fb7d90ecde3659021341779fea598a6daab013.zip
remove StaticInliner and NaN checking
NaN checking was a lint for a deprecated feature. It can go away.
-rw-r--r--src/librustc_const_eval/_match.rs8
-rw-r--r--src/librustc_const_eval/check_match.rs214
-rw-r--r--src/librustc_const_eval/diagnostics.rs4
-rw-r--r--src/librustc_const_eval/eval.rs12
-rw-r--r--src/librustc_const_eval/pattern.rs176
-rw-r--r--src/test/compile-fail/const-eval-overflow-2.rs4
-rw-r--r--src/test/compile-fail/const-pattern-not-const-evaluable.rs4
-rw-r--r--src/test/compile-fail/issue-6804.rs36
8 files changed, 184 insertions, 274 deletions
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index cac486b743c..d70deb2f862 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -40,12 +40,10 @@ use std::cmp::Ordering;
 use std::fmt;
 use std::iter::{FromIterator, IntoIterator, repeat};
 
-pub fn lower_pat<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: &Pat)
-                           -> &'a Pattern<'tcx>
+pub fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pattern<'tcx>)
+                                -> &'a Pattern<'tcx>
 {
-    cx.pattern_arena.alloc(
-        LiteralExpander.fold_pattern(&Pattern::from_hir(cx.tcx, pat))
-    )
+    cx.pattern_arena.alloc(LiteralExpander.fold_pattern(&pat))
 }
 
 struct LiteralExpander;
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index a402db705b2..8021b36975a 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -8,20 +8,19 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use _match::{MatchCheckCtxt, Matrix, lower_pat, is_useful};
+use _match::{MatchCheckCtxt, Matrix, expand_pattern, is_useful};
 use _match::{DUMMY_WILD_PAT};
 use _match::Usefulness::*;
 use _match::WitnessPreference::*;
 
+use pattern::{Pattern, PatternContext, PatternError};
+
 use eval::report_const_eval_err;
-use eval::{eval_const_expr_partial, const_expr_to_pat, lookup_const_by_id};
-use eval::EvalHint::ExprTypeChecked;
 
 use rustc::dep_graph::DepNode;
 
 use rustc::hir::pat_util::{pat_bindings, pat_contains_bindings};
 
-use rustc::middle::const_val::ConstVal;
 use rustc::middle::expr_use_visitor::{ConsumeMode, Delegate, ExprUseVisitor};
 use rustc::middle::expr_use_visitor::{LoanCause, MutateMode};
 use rustc::middle::expr_use_visitor as euv;
@@ -39,9 +38,7 @@ use rustc::hir::{self, Pat, PatKind};
 use rustc_back::slice;
 
 use syntax::ast;
-use syntax::codemap::Spanned;
 use syntax::ptr::P;
-use syntax::util::move_map::MoveMap;
 use syntax_pos::Span;
 
 struct OuterVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
@@ -80,9 +77,6 @@ impl<'a, 'v, 'tcx> Visitor<'v> for OuterVisitor<'a, 'tcx> {
     }
 }
 
-impl<'a, 'tcx> OuterVisitor<'a, 'tcx> {
-}
-
 pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     tcx.visit_all_items_in_krate(DepNode::MatchCheck, &mut OuterVisitor { tcx: tcx });
     tcx.sess.abort_if_errors();
@@ -112,8 +106,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MatchVisitor<'a, 'tcx> {
     fn visit_local(&mut self, loc: &hir::Local) {
         intravisit::walk_local(self, loc);
 
-        let pat = StaticInliner::new(self.tcx).fold_pat(loc.pat.clone());
-        self.check_irrefutable(&pat, false);
+        self.check_irrefutable(&loc.pat, false);
 
         // Check legality of move bindings and `@` patterns.
         self.check_patterns(false, slice::ref_slice(&loc.pat));
@@ -138,6 +131,27 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
         }
     }
 
+    fn report_inlining_errors(&self, patcx: PatternContext, pat_span: Span) {
+        for error in patcx.errors {
+            match error {
+                PatternError::BadConstInPattern(span, def_id) => {
+                    self.tcx.sess.span_err(
+                        span,
+                        &format!("constants of the type `{}` \
+                                  cannot be used in patterns",
+                                 self.tcx.item_path_str(def_id)));
+                }
+                PatternError::StaticInPattern(span) => {
+                    span_err!(self.tcx.sess, span, E0158,
+                              "statics cannot be referenced in patterns");
+                }
+                PatternError::ConstEval(err) => {
+                    report_const_eval_err(self.tcx, &err, pat_span, "pattern").emit();
+                }
+            }
+        }
+    }
+
     fn check_match(
         &self,
         scrut: &hir::Expr,
@@ -154,32 +168,36 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
             if let Some(ref guard) = arm.guard {
                 check_for_mutation_in_guard(self, &guard);
             }
-        }
-
-        let mut static_inliner = StaticInliner::new(self.tcx);
-        let inlined_arms = arms.iter().map(|arm| {
-            (arm.pats.iter().map(|pat| {
-                static_inliner.fold_pat((*pat).clone())
-            }).collect(), arm.guard.as_ref().map(|e| &**e))
-        }).collect::<Vec<(Vec<P<Pat>>, Option<&hir::Expr>)>>();
 
-        // Bail out early if inlining failed.
-        if static_inliner.failed {
-            return;
+            // Third, perform some lints.
+            for pat in &arm.pats {
+                check_for_bindings_named_the_same_as_variants(self, pat);
+            }
         }
 
-        for pat in inlined_arms.iter().flat_map(|&(ref pats, _)| pats) {
-            // Fourth, check if there are any references to NaN that we should warn about.
-            check_for_static_nan(self, &pat);
+        MatchCheckCtxt::create_and_enter(self.tcx, |ref cx| {
+            let mut have_errors = false;
+
+            let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
+                arm.pats.iter().map(|pat| {
+                    let mut patcx = PatternContext::new(self.tcx);
+                    let pattern = expand_pattern(cx, patcx.lower_pattern(&pat));
+                    if !patcx.errors.is_empty() {
+                        self.report_inlining_errors(patcx, pat.span);
+                        have_errors = true;
+                    }
+                    (pattern, &**pat)
+                }).collect(),
+                arm.guard.as_ref().map(|e| &**e)
+            )).collect();
 
-            // Fifth, check if for any of the patterns that match an enumerated type
-            // are bindings with the same name as one of the variants of said type.
-            check_for_bindings_named_the_same_as_variants(self, &pat);
-        }
+            // Bail out early if inlining failed.
+            if have_errors {
+                return;
+            }
 
-        MatchCheckCtxt::create_and_enter(self.tcx, |ref cx| {
             // Fourth, check for unreachable arms.
-            check_arms(cx, &inlined_arms[..], source);
+            check_arms(cx, &inlined_arms, source);
 
             // Finally, check if the whole match expression is exhaustive.
             // Check for empty enum, because is_useful only works on inhabited types.
@@ -204,7 +222,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
                 .iter()
                 .filter(|&&(_, guard)| guard.is_none())
                 .flat_map(|arm| &arm.0)
-                .map(|pat| vec![lower_pat(cx, &pat)])
+                .map(|pat| vec![pat.0])
                 .collect();
             check_exhaustive(cx, scrut.span, &matrix, source);
         })
@@ -218,8 +236,9 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
         };
 
         MatchCheckCtxt::create_and_enter(self.tcx, |ref cx| {
+            let mut patcx = PatternContext::new(self.tcx);
             let pats : Matrix = vec![vec![
-                lower_pat(cx, pat)
+                expand_pattern(cx, patcx.lower_pattern(pat))
             ]].into_iter().collect();
 
             let witness = match is_useful(cx, &pats, &[cx.wild_pattern], ConstructWitness) {
@@ -269,27 +288,6 @@ fn check_for_bindings_named_the_same_as_variants(cx: &MatchVisitor, pat: &Pat) {
     });
 }
 
-// Check that we do not match against a static NaN (#6804)
-fn check_for_static_nan(cx: &MatchVisitor, pat: &Pat) {
-    pat.walk(|p| {
-        if let PatKind::Lit(ref expr) = p.node {
-            match eval_const_expr_partial(cx.tcx, &expr, ExprTypeChecked, None) {
-                Ok(ConstVal::Float(f)) if f.is_nan() => {
-                    span_warn!(cx.tcx.sess, p.span, E0003,
-                               "unmatchable NaN in pattern, \
-                                use the is_nan method in a guard instead");
-                }
-                Ok(_) => {}
-
-                Err(err) => {
-                    report_const_eval_err(cx.tcx, &err, p.span, "pattern").emit();
-                }
-            }
-        }
-        true
-    });
-}
-
 /// Checks for common cases of "catchall" patterns that may not be intended as such.
 fn pat_is_catchall(dm: &DefMap, pat: &Pat) -> bool {
     match pat.node {
@@ -304,15 +302,16 @@ fn pat_is_catchall(dm: &DefMap, pat: &Pat) -> bool {
 }
 
 // Check for unreachable patterns
-fn check_arms(cx: &MatchCheckCtxt,
-              arms: &[(Vec<P<Pat>>, Option<&hir::Expr>)],
-              source: hir::MatchSource) {
+fn check_arms<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
+                        arms: &[(Vec<(&Pattern<'tcx>, &'a hir::Pat)>, Option<&hir::Expr>)],
+                        source: hir::MatchSource)
+{
     let mut seen = Matrix::empty();
     let mut catchall = None;
     let mut printed_if_let_err = false;
     for &(ref pats, guard) in arms {
-        for pat in pats {
-            let v = vec![lower_pat(cx, &pat)];
+        for &(pat, hir_pat) in pats {
+            let v = vec![pat];
 
             match is_useful(cx, &seen, &v[..], LeaveOutWitness) {
                 NotUseful => {
@@ -325,7 +324,7 @@ fn check_arms(cx: &MatchCheckCtxt,
                                 // find the first arm pattern so we can use its span
                                 let &(ref first_arm_pats, _) = &arms[0];
                                 let first_pat = &first_arm_pats[0];
-                                let span = first_pat.span;
+                                let span = first_pat.0.span;
                                 struct_span_err!(cx.tcx.sess, span, E0162,
                                                 "irrefutable if-let pattern")
                                     .span_label(span, &format!("irrefutable pattern"))
@@ -338,7 +337,7 @@ fn check_arms(cx: &MatchCheckCtxt,
                             // find the first arm pattern so we can use its span
                             let &(ref first_arm_pats, _) = &arms[0];
                             let first_pat = &first_arm_pats[0];
-                            let span = first_pat.span;
+                            let span = first_pat.0.span;
                             struct_span_err!(cx.tcx.sess, span, E0165,
                                              "irrefutable while-let pattern")
                                 .span_label(span, &format!("irrefutable pattern"))
@@ -374,7 +373,7 @@ fn check_arms(cx: &MatchCheckCtxt,
             }
             if guard.is_none() {
                 seen.push(v);
-                if catchall.is_none() && pat_is_catchall(&cx.tcx.def_map.borrow(), pat) {
+                if catchall.is_none() && pat_is_catchall(&cx.tcx.def_map.borrow(), hir_pat) {
                     catchall = Some(pat.span);
                 }
             }
@@ -448,97 +447,6 @@ fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
     }
 }
 
-
-struct StaticInliner<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    failed: bool
-}
-
-impl<'a, 'tcx> StaticInliner<'a, 'tcx> {
-    pub fn new<'b>(tcx: TyCtxt<'b, 'tcx, 'tcx>) -> StaticInliner<'b, 'tcx> {
-        StaticInliner {
-            tcx: tcx,
-            failed: false
-        }
-    }
-}
-
-impl<'a, 'tcx> StaticInliner<'a, 'tcx> {
-    fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
-        match pat.node {
-            PatKind::Path(..) => {
-                match self.tcx.expect_def(pat.id) {
-                    Def::AssociatedConst(did) | Def::Const(did) => {
-                        let substs = Some(self.tcx.node_id_item_substs(pat.id).substs);
-                        if let Some((const_expr, _)) = lookup_const_by_id(self.tcx, did, substs) {
-                            match const_expr_to_pat(self.tcx, const_expr, pat.id, pat.span) {
-                                Ok(new_pat) => return new_pat,
-                                Err(def_id) => {
-                                    self.failed = true;
-                                    self.tcx.sess.span_err(
-                                        pat.span,
-                                        &format!("constants of the type `{}` \
-                                                  cannot be used in patterns",
-                                                 self.tcx.item_path_str(def_id)));
-                                }
-                            }
-                        } else {
-                            self.failed = true;
-                            span_err!(self.tcx.sess, pat.span, E0158,
-                                "statics cannot be referenced in patterns");
-                        }
-                    }
-                    _ => {}
-                }
-            }
-            _ => {}
-        }
-
-        pat.map(|Pat { id, node, span }| {
-            let node = match node {
-                PatKind::Binding(binding_mode, pth1, sub) => {
-                    PatKind::Binding(binding_mode, pth1, sub.map(|x| self.fold_pat(x)))
-                }
-                PatKind::TupleStruct(pth, pats, ddpos) => {
-                    PatKind::TupleStruct(pth, pats.move_map(|x| self.fold_pat(x)), ddpos)
-                }
-                PatKind::Struct(pth, fields, etc) => {
-                    let fs = fields.move_map(|f| {
-                        Spanned {
-                            span: f.span,
-                            node: hir::FieldPat {
-                                name: f.node.name,
-                                pat: self.fold_pat(f.node.pat),
-                                is_shorthand: f.node.is_shorthand,
-                            },
-                        }
-                    });
-                    PatKind::Struct(pth, fs, etc)
-                }
-                PatKind::Tuple(elts, ddpos) => {
-                    PatKind::Tuple(elts.move_map(|x| self.fold_pat(x)), ddpos)
-                }
-                PatKind::Box(inner) => PatKind::Box(self.fold_pat(inner)),
-                PatKind::Ref(inner, mutbl) => PatKind::Ref(self.fold_pat(inner), mutbl),
-                PatKind::Slice(before, slice, after) => {
-                    PatKind::Slice(before.move_map(|x| self.fold_pat(x)),
-                                   slice.map(|x| self.fold_pat(x)),
-                                   after.move_map(|x| self.fold_pat(x)))
-                }
-                PatKind::Wild |
-                PatKind::Lit(_) |
-                PatKind::Range(..) |
-                PatKind::Path(..) => node
-            };
-            Pat {
-                id: id,
-                node: node,
-                span: span
-            }
-        })
-    }
-}
-
 // Legality of move bindings checking
 fn check_legality_of_move_bindings(cx: &MatchVisitor,
                                    has_guard: bool,
diff --git a/src/librustc_const_eval/diagnostics.rs b/src/librustc_const_eval/diagnostics.rs
index c2b39625e2e..f70583db70a 100644
--- a/src/librustc_const_eval/diagnostics.rs
+++ b/src/librustc_const_eval/diagnostics.rs
@@ -71,7 +71,7 @@ fn foo(x: Option<String>) {
 "##,*/
 
 
-E0003: r##"
+/*E0003: r##"
 Not-a-Number (NaN) values cannot be compared for equality and hence can never
 match the input to a match expression. So, the following will not compile:
 
@@ -100,7 +100,7 @@ match number {
 }
 ```
 "##,
-
+*/
 
 E0004: r##"
 This error indicates that the compiler cannot guarantee a matching pattern for
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 81dd642de5d..c02cca0da72 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -392,7 +392,7 @@ pub fn note_const_eval_err<'a, 'tcx>(
 
 pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                  e: &Expr) -> ConstVal {
-    match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
+    match eval_const_expr_checked(tcx, e) {
         Ok(r) => r,
         // non-const path still needs to be a fatal error, because enums are funky
         Err(s) => {
@@ -407,15 +407,21 @@ pub fn eval_const_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
+pub fn eval_const_expr_checked<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                         e: &Expr) -> EvalResult
+{
+    eval_const_expr_partial(tcx, e, ExprTypeChecked, None)
+}
+
 pub type FnArgMap<'a> = Option<&'a NodeMap<ConstVal>>;
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct ConstEvalErr {
     pub span: Span,
     pub kind: ErrKind,
 }
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub enum ErrKind {
     CannotCast,
     CannotCastTo(&'static str),
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 715659f5885..4bd797afd06 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -15,6 +15,7 @@ use rustc::mir::repr::{Field, BorrowKind, Mutability};
 use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region};
 use rustc::hir::{self, PatKind};
 use rustc::hir::def::Def;
+use rustc::hir::def_id::DefId;
 use rustc::hir::pat_util::EnumerateAndAdjustIterator;
 
 use rustc_data_structures::indexed_vec::Idx;
@@ -23,6 +24,13 @@ use syntax::ast;
 use syntax::ptr::P;
 use syntax_pos::Span;
 
+#[derive(Clone, Debug)]
+pub enum PatternError {
+    StaticInPattern(Span),
+    BadConstInPattern(Span, DefId),
+    ConstEval(eval::ConstEvalErr),
+}
+
 #[derive(Copy, Clone, Debug)]
 pub enum BindingMode<'tcx> {
     ByValue,
@@ -97,78 +105,112 @@ pub enum PatternKind<'tcx> {
     },
 }
 
+pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
+    pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    pub errors: Vec<PatternError>,
+}
+
 impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
     pub fn from_hir(tcx: TyCtxt<'a, 'gcx, 'tcx>, pat: &hir::Pat) -> Self {
-        let mut ty = tcx.node_id_to_type(pat.id);
+        let mut pcx = PatternContext::new(tcx);
+        let result = pcx.lower_pattern(pat);
+        if !pcx.errors.is_empty() {
+            span_bug!(pat.span, "encountered errors lowering pattern: {:?}", pcx.errors)
+        }
+        result
+    }
+}
+
+impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self {
+        PatternContext { tcx: tcx, errors: vec![] }
+    }
+
+    pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
+        let mut ty = self.tcx.node_id_to_type(pat.id);
 
         let kind = match pat.node {
             PatKind::Wild => PatternKind::Wild,
 
             PatKind::Lit(ref value) => {
-                let value = eval::eval_const_expr(tcx.global_tcx(), value);
-                PatternKind::Constant { value: value }
+                match eval::eval_const_expr_checked(self.tcx.global_tcx(), value) {
+                    Ok(value) => {
+                        PatternKind::Constant { value: value }
+                    }
+                    Err(e) => {
+                        self.errors.push(PatternError::ConstEval(e));
+                        PatternKind::Wild
+                    }
+                }
             }
 
             PatKind::Range(ref lo, ref hi) => {
-                let lo = eval::eval_const_expr(tcx.global_tcx(), lo);
-                let hi = eval::eval_const_expr(tcx.global_tcx(), hi);
-                PatternKind::Range { lo: lo, hi: hi }
-            },
+                let r_lo = eval::eval_const_expr_checked(self.tcx.global_tcx(), lo);
+                if let Err(ref e_lo) = r_lo {
+                    self.errors.push(PatternError::ConstEval(e_lo.clone()));
+                }
+
+                let r_hi = eval::eval_const_expr_checked(self.tcx.global_tcx(), hi);
+                if let Err(ref e_hi) = r_hi {
+                    self.errors.push(PatternError::ConstEval(e_hi.clone()));
+                }
+
+                if let (Ok(lo), Ok(hi)) = (r_lo, r_hi) {
+                    PatternKind::Range { lo: lo, hi: hi }
+                } else {
+                    PatternKind::Wild
+                }
+            }
 
             PatKind::Path(..) => {
-                match tcx.expect_def(pat.id) {
+                match self.tcx.expect_def(pat.id) {
                     Def::Const(def_id) | Def::AssociatedConst(def_id) => {
-                        let tcx = tcx.global_tcx();
-                        let substs = Some(tcx.node_id_item_substs(pat.id).substs);
+                        let tcx = self.tcx.global_tcx();
+                        let substs = Some(self.tcx.node_id_item_substs(pat.id).substs);
                         match eval::lookup_const_by_id(tcx, def_id, substs) {
                             Some((const_expr, _const_ty)) => {
-                                match eval::const_expr_to_pat(tcx,
-                                                              const_expr,
-                                                              pat.id,
-                                                              pat.span) {
-                                    Ok(pat) =>
-                                        return Pattern::from_hir(tcx, &pat),
-                                    Err(_) =>
-                                        span_bug!(
-                                            pat.span, "illegal constant"),
+                                match eval::const_expr_to_pat(
+                                    tcx, const_expr, pat.id, pat.span)
+                                {
+                                    Ok(pat) => return self.lower_pattern(&pat),
+                                    Err(_) => {
+                                        self.errors.push(PatternError::BadConstInPattern(
+                                            pat.span, def_id));
+                                        PatternKind::Wild
+                                    }
                                 }
                             }
                             None => {
-                                span_bug!(
-                                    pat.span,
-                                    "cannot eval constant: {:?}",
-                                    def_id)
+                                self.errors.push(PatternError::StaticInPattern(pat.span));
+                                PatternKind::Wild
                             }
                         }
                     }
-                    _ => {
-                        PatternKind::from_variant_or_leaf(tcx, pat, vec![])
-                    }
+                    _ => self.lower_variant_or_leaf(pat, vec![])
                 }
             }
 
             PatKind::Ref(ref subpattern, _) |
             PatKind::Box(ref subpattern) => {
-                PatternKind::Deref { subpattern: Self::from_hir(tcx, subpattern) }
+                PatternKind::Deref { subpattern: self.lower_pattern(subpattern) }
             }
 
             PatKind::Slice(ref prefix, ref slice, ref suffix) => {
-                let ty = tcx.node_id_to_type(pat.id);
+                let ty = self.tcx.node_id_to_type(pat.id);
                 match ty.sty {
                     ty::TyRef(_, mt) =>
                         PatternKind::Deref {
                             subpattern: Pattern {
                                 ty: mt.ty,
                                 span: pat.span,
-                                kind: Box::new(PatternKind::from_slice_or_array(
-                                    tcx, pat.span, mt.ty, prefix, slice, suffix))
+                                kind: Box::new(self.slice_or_array_pattern(
+                                    pat.span, mt.ty, prefix, slice, suffix))
                             },
                         },
 
                     ty::TySlice(..) |
                     ty::TyArray(..) =>
-                        PatternKind::from_slice_or_array(
-                            tcx, pat.span, ty, prefix, slice, suffix),
+                        self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix),
 
                     ref sty =>
                         span_bug!(
@@ -179,14 +221,14 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
             }
 
             PatKind::Tuple(ref subpatterns, ddpos) => {
-                match tcx.node_id_to_type(pat.id).sty {
+                match self.tcx.node_id_to_type(pat.id).sty {
                     ty::TyTuple(ref tys) => {
                         let subpatterns =
                             subpatterns.iter()
                                        .enumerate_and_adjust(tys.len(), ddpos)
                                        .map(|(i, subpattern)| FieldPattern {
                                             field: Field::new(i),
-                                            pattern: Self::from_hir(tcx, subpattern),
+                                            pattern: self.lower_pattern(subpattern)
                                        })
                                        .collect();
 
@@ -198,9 +240,9 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
             }
 
             PatKind::Binding(bm, ref ident, ref sub) => {
-                let def_id = tcx.expect_def(pat.id).def_id();
-                let id = tcx.map.as_local_node_id(def_id).unwrap();
-                let var_ty = tcx.node_id_to_type(pat.id);
+                let def_id = self.tcx.expect_def(pat.id).def_id();
+                let id = self.tcx.map.as_local_node_id(def_id).unwrap();
+                let var_ty = self.tcx.node_id_to_type(pat.id);
                 let region = match var_ty.sty {
                     ty::TyRef(r, _) => Some(r),
                     _ => None,
@@ -232,31 +274,31 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
                     name: ident.node,
                     var: id,
                     ty: var_ty,
-                    subpattern: Self::from_opt_pattern(tcx, sub),
+                    subpattern: self.lower_opt_pattern(sub),
                 }
             }
 
             PatKind::TupleStruct(_, ref subpatterns, ddpos) => {
-                let pat_ty = tcx.node_id_to_type(pat.id);
+                let pat_ty = self.tcx.node_id_to_type(pat.id);
                 let adt_def = match pat_ty.sty {
                     ty::TyAdt(adt_def, _) => adt_def,
                     _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT"),
                 };
-                let variant_def = adt_def.variant_of_def(tcx.expect_def(pat.id));
+                let variant_def = adt_def.variant_of_def(self.tcx.expect_def(pat.id));
 
                 let subpatterns =
                         subpatterns.iter()
                                    .enumerate_and_adjust(variant_def.fields.len(), ddpos)
                                    .map(|(i, field)| FieldPattern {
                                        field: Field::new(i),
-                                       pattern: Self::from_hir(tcx, field),
+                                       pattern: self.lower_pattern(field),
                                    })
                                    .collect();
-                PatternKind::from_variant_or_leaf(tcx, pat, subpatterns)
+                self.lower_variant_or_leaf(pat, subpatterns)
             }
 
             PatKind::Struct(_, ref fields, _) => {
-                let pat_ty = tcx.node_id_to_type(pat.id);
+                let pat_ty = self.tcx.node_id_to_type(pat.id);
                 let adt_def = match pat_ty.sty {
                     ty::TyAdt(adt_def, _) => adt_def,
                     _ => {
@@ -265,7 +307,7 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
                             "struct pattern not applied to an ADT");
                     }
                 };
-                let variant_def = adt_def.variant_of_def(tcx.expect_def(pat.id));
+                let variant_def = adt_def.variant_of_def(self.tcx.expect_def(pat.id));
 
                 let subpatterns =
                     fields.iter()
@@ -279,12 +321,12 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
                               });
                               FieldPattern {
                                   field: Field::new(index),
-                                  pattern: Self::from_hir(tcx, &field.node.pat),
+                                  pattern: self.lower_pattern(&field.node.pat),
                               }
                           })
                           .collect();
 
-                PatternKind::from_variant_or_leaf(tcx, pat, subpatterns)
+                self.lower_variant_or_leaf(pat, subpatterns)
             }
         };
 
@@ -295,33 +337,31 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
         }
     }
 
-    fn from_patterns(tcx: TyCtxt<'a, 'gcx, 'tcx>, pats: &[P<hir::Pat>]) -> Vec<Self> {
-        pats.iter().map(|p| Self::from_hir(tcx, p)).collect()
+    fn lower_patterns(&mut self, pats: &[P<hir::Pat>]) -> Vec<Pattern<'tcx>> {
+        pats.iter().map(|p| self.lower_pattern(p)).collect()
     }
 
-    fn from_opt_pattern(tcx: TyCtxt<'a, 'gcx, 'tcx>, pat: &Option<P<hir::Pat>>) -> Option<Self>
+    fn lower_opt_pattern(&mut self, pat: &Option<P<hir::Pat>>) -> Option<Pattern<'tcx>>
     {
-        pat.as_ref().map(|p| Self::from_hir(tcx, p))
+        pat.as_ref().map(|p| self.lower_pattern(p))
     }
-}
 
-impl<'a, 'gcx, 'tcx> PatternKind<'tcx> {
-    fn from_slice_or_array(
-        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    fn slice_or_array_pattern(
+        &mut self,
         span: Span,
         ty: Ty<'tcx>,
         prefix: &[P<hir::Pat>],
         slice: &Option<P<hir::Pat>>,
         suffix: &[P<hir::Pat>])
-        -> Self
+        -> PatternKind<'tcx>
     {
         match ty.sty {
             ty::TySlice(..) => {
                 // matching a slice or fixed-length array
                 PatternKind::Slice {
-                    prefix: Pattern::from_patterns(tcx, prefix),
-                    slice: Pattern::from_opt_pattern(tcx, slice),
-                    suffix: Pattern::from_patterns(tcx, suffix),
+                    prefix: self.lower_patterns(prefix),
+                    slice: self.lower_opt_pattern(slice),
+                    suffix: self.lower_patterns(suffix),
                 }
             }
 
@@ -329,28 +369,28 @@ impl<'a, 'gcx, 'tcx> PatternKind<'tcx> {
                 // fixed-length array
                 assert!(len >= prefix.len() + suffix.len());
                 PatternKind::Array {
-                    prefix: Pattern::from_patterns(tcx, prefix),
-                    slice: Pattern::from_opt_pattern(tcx, slice),
-                    suffix: Pattern::from_patterns(tcx, suffix),
+                    prefix: self.lower_patterns(prefix),
+                    slice: self.lower_opt_pattern(slice),
+                    suffix: self.lower_patterns(suffix),
                 }
             }
 
             _ => {
-                span_bug!(span, "unexpanded macro or bad constant etc");
+                span_bug!(span, "bad slice pattern type {:?}", ty);
             }
         }
     }
 
-    fn from_variant_or_leaf(
-        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    fn lower_variant_or_leaf(
+        &mut self,
         pat: &hir::Pat,
         subpatterns: Vec<FieldPattern<'tcx>>)
-        -> Self
+        -> PatternKind<'tcx>
     {
-        match tcx.expect_def(pat.id) {
+        match self.tcx.expect_def(pat.id) {
             Def::Variant(variant_id) | Def::VariantCtor(variant_id, ..) => {
-                let enum_id = tcx.parent_def_id(variant_id).unwrap();
-                let adt_def = tcx.lookup_adt_def(enum_id);
+                let enum_id = self.tcx.parent_def_id(variant_id).unwrap();
+                let adt_def = self.tcx.lookup_adt_def(enum_id);
                 if adt_def.variants.len() > 1 {
                     PatternKind::Variant {
                         adt_def: adt_def,
diff --git a/src/test/compile-fail/const-eval-overflow-2.rs b/src/test/compile-fail/const-eval-overflow-2.rs
index 264f02588ae..9b045ed1d02 100644
--- a/src/test/compile-fail/const-eval-overflow-2.rs
+++ b/src/test/compile-fail/const-eval-overflow-2.rs
@@ -21,10 +21,6 @@ const NEG_128: i8 = -128;
 const NEG_NEG_128: i8 = -NEG_128;
 //~^ ERROR constant evaluation error
 //~| attempt to negate with overflow
-//~| ERROR constant evaluation error
-//~| attempt to negate with overflow
-//~| ERROR constant evaluation error
-//~| attempt to negate with overflow
 
 fn main() {
     match -128i8 {
diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs
index 3f6f38f9a18..b40aa2a8e27 100644
--- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs
+++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs
@@ -19,9 +19,7 @@ use Cake::*;
 const BOO: (Cake, Cake) = (Marmor, BlackForest);
 //~^ ERROR: constant evaluation error [E0080]
 //~| unimplemented constant expression: enum variants
-//~^^^ ERROR: constant evaluation error [E0080]
-//~| unimplemented constant expression: enum variants
-const FOO: Cake = BOO.1; //~ NOTE for expression here
+const FOO: Cake = BOO.1;
 
 const fn foo() -> Cake {
     Marmor
diff --git a/src/test/compile-fail/issue-6804.rs b/src/test/compile-fail/issue-6804.rs
deleted file mode 100644
index f6b7e13c4f5..00000000000
--- a/src/test/compile-fail/issue-6804.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![feature(rustc_attrs)]
-#![feature(slice_patterns)]
-#![allow(dead_code)]
-
-// Matching against NaN should result in a warning
-
-use std::f64::NAN;
-
-#[rustc_error]
-fn main() { //~ ERROR compilation successful
-    let x = NAN;
-    match x {
-        NAN => {},
-        _ => {},
-    };
-    //~^^^ WARNING unmatchable NaN in pattern, use the is_nan method in a guard instead
-    //~| WARNING floating point constants cannot be used
-    //~| WARNING this was previously accepted
-    match [x, 1.0] {
-        [NAN, _] => {},
-        _ => {},
-    };
-    //~^^^ WARNING unmatchable NaN in pattern, use the is_nan method in a guard instead
-    //~| WARNING floating point constants cannot be used
-    //~| WARNING this was previously accepted
-}