diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index f13814527cdf..e594d462ff38 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -1163,6 +1163,7 @@ impl LintPass for UnusedParens { ast::MatchSource::Normal => (head, "`match` head expression", true), ast::MatchSource::IfLetDesugar { .. } => (head, "`if let` head expression", true), ast::MatchSource::WhileLetDesugar => (head, "`while let` head expression", true), + ast::MatchSource::ForLoopDesugar => (head, "`for` head expression", true), }, ast::ExprRet(Some(ref value)) => (value, "`return` value", false), ast::ExprAssign(_, ref value) => (value, "assigned value", false), diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index fec7b51157d8..86ab26ea40d9 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -221,7 +221,7 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &ast::Expr) { .flat_map(|arm| arm.0.iter()) .map(|pat| vec![&**pat]) .collect(); - check_exhaustive(cx, ex.span, &matrix); + check_exhaustive(cx, ex.span, &matrix, source); }, ast::ExprForLoop(ref pat, _, _, _) => { let mut static_inliner = StaticInliner::new(cx.tcx); @@ -327,6 +327,14 @@ fn check_arms(cx: &MatchCheckCtxt, span_err!(cx.tcx.sess, span, E0165, "irrefutable while-let pattern"); }, + ast::MatchSource::ForLoopDesugar => { + // this is a bug, because on `match iter.next()` we cover + // `Some(
)` and `None`. It's impossible to have an unreachable + // pattern + // (see libsyntax/ext/expand.rs for the full expansion of a for loop) + cx.tcx.sess.span_bug(pat.span, "unreachable for-loop pattern") + }, + ast::MatchSource::Normal => { span_err!(cx.tcx.sess, pat.span, E0001, "unreachable pattern") }, @@ -351,7 +359,7 @@ fn raw_pat<'a>(p: &'a Pat) -> &'a Pat { } } -fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix) { +fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix, source: ast::MatchSource) { match is_useful(cx, matrix, &[DUMMY_WILD_PAT], ConstructWitness) { UsefulWithWitness(pats) => { let witness = match &pats[] { @@ -359,10 +367,29 @@ fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, matrix: &Matrix) { [] => DUMMY_WILD_PAT, _ => unreachable!() }; - span_err!(cx.tcx.sess, sp, E0004, - "non-exhaustive patterns: `{}` not covered", - pat_to_string(witness) - ); + match source { + ast::MatchSource::ForLoopDesugar => { + // `witness` has the form `Some()`, peel off the `Some` + let witness = match witness.node { + ast::PatEnum(_, Some(ref pats)) => match &pats[] { + [ref pat] => &**pat, + _ => unreachable!(), + }, + _ => unreachable!(), + }; + + span_err!(cx.tcx.sess, sp, E0297, + "refutable pattern in `for` loop binding: \ + `{}` not covered", + pat_to_string(witness)); + }, + _ => { + span_err!(cx.tcx.sess, sp, E0004, + "non-exhaustive patterns: `{}` not covered", + pat_to_string(witness) + ); + }, + } } NotUseful => { // This is good, wildcard pattern isn't reachable diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 1be99a8e569f..dd9a52aa7055 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -100,6 +100,7 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region) ast::ExprMethodCall(..) => "method call", ast::ExprMatch(_, _, ast::MatchSource::IfLetDesugar { .. }) => "if let", ast::ExprMatch(_, _, ast::MatchSource::WhileLetDesugar) => "while let", + ast::ExprMatch(_, _, ast::MatchSource::ForLoopDesugar) => "for", ast::ExprMatch(..) => "match", _ => "expression", }, diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 11068880b0e2..d7283db25a5f 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -788,6 +788,7 @@ pub enum MatchSource { Normal, IfLetDesugar { contains_else_clause: bool }, WhileLetDesugar, + ForLoopDesugar, } #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 357bd2c17abd..5736400313e9 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -288,8 +288,8 @@ pub fn expand_expr(e: P