diff options
| author | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2016-10-03 21:39:21 +0300 |
|---|---|---|
| committer | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2016-10-26 22:41:17 +0300 |
| commit | 76fb7d90ecde3659021341779fea598a6daab013 (patch) | |
| tree | deb904e289d86521621c143267d58068797df5af | |
| parent | 37418b850f43fd95596c688c230f5e8d94e1962f (diff) | |
| download | rust-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.rs | 8 | ||||
| -rw-r--r-- | src/librustc_const_eval/check_match.rs | 214 | ||||
| -rw-r--r-- | src/librustc_const_eval/diagnostics.rs | 4 | ||||
| -rw-r--r-- | src/librustc_const_eval/eval.rs | 12 | ||||
| -rw-r--r-- | src/librustc_const_eval/pattern.rs | 176 | ||||
| -rw-r--r-- | src/test/compile-fail/const-eval-overflow-2.rs | 4 | ||||
| -rw-r--r-- | src/test/compile-fail/const-pattern-not-const-evaluable.rs | 4 | ||||
| -rw-r--r-- | src/test/compile-fail/issue-6804.rs | 36 |
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 -} |
