diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 9ec0fa337168c..28c46a9eb7210 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -70,6 +70,7 @@ pub enum lint { unnecessary_qualification, while_true, path_statement, + irrefutable_match_without_binding, unrecognized_lint, non_camel_case_types, non_uppercase_statics, @@ -167,6 +168,13 @@ static lint_table: &'static [(&'static str, LintSpec)] = &[ default: warn }), + ("irrefutable_match_without_binding", + LintSpec { + lint: irrefutable_match_without_binding, + desc: "irrefutable let or match without any bindings (equivalent to inner expression)", + default: allow + }), + ("unrecognized_lint", LintSpec { lint: unrecognized_lint, @@ -921,6 +929,18 @@ fn check_path_statement(cx: &Context, s: &ast::Stmt) { } } +fn check_irrefutable_match_without_binding(cx: &Context, sp: Span, pats: &[@ast::Pat]) { + // `pats` is one or more pattern-alternatives (i.e. pat1|pat2|pat3), *not* match arms + let mut any_bindings = false; + for pat in pats.iter() { + pat_util::pat_bindings(cx.tcx.def_map, *pat, |_,_,_,_| any_bindings = true) + } + if !any_bindings { + cx.span_lint(irrefutable_match_without_binding, sp, + "irrefutable let or match without any bindings (equivalent to inner expression)") + } +} + fn check_item_non_camel_case_types(cx: &Context, it: &ast::item) { fn is_camel_case(cx: ty::ctxt, ident: ast::Ident) -> bool { let ident = cx.sess.str_of(ident); @@ -1319,6 +1339,9 @@ impl<'a> Visitor<()> for Context<'a> { ast::ExprParen(expr) => if self.negated_expr_id == e.id { self.negated_expr_id = expr.id }, + ast::ExprMatch(_, [ast::Arm { ref pats, .. }]) => { + check_irrefutable_match_without_binding(self, e.span, *pats) + }, _ => () }; @@ -1334,6 +1357,11 @@ impl<'a> Visitor<()> for Context<'a> { visit::walk_expr(self, e, ()); } + fn visit_local(&mut self, l: @ast::Local, _: ()) { + check_irrefutable_match_without_binding(self, l.span, &[l.pat]); + visit::walk_local(self, l, ()) + } + fn visit_stmt(&mut self, s: @ast::Stmt, _: ()) { check_path_statement(self, s); diff --git a/src/test/compile-fail/lint-irrefutable-match-without-binding.rs b/src/test/compile-fail/lint-irrefutable-match-without-binding.rs new file mode 100644 index 0000000000000..dc825ce67ea32 --- /dev/null +++ b/src/test/compile-fail/lint-irrefutable-match-without-binding.rs @@ -0,0 +1,50 @@ +// Copyright 2013 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deny(irrefutable_match_without_binding)]; +#[allow(unused_variable)]; + +fn main() { + let a = 8; + let _ = a; //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression) + let _ = 99; //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression) + let (_, _) = (1, 2); //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression) + let ((_, _), ()) = (((), ()), ()); //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression) + let () = (); //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression) + match 23 { //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression) + _ => { } + } + match (1, 2) { //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression) + (_, _) => { } + } + match false { //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression) + false|true => { } + } + match [1, 2] { //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression) + [..] => { } + } + match [1, 2] { //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression) + [_, _] => { } + } + match ~666 { //~ ERROR: irrefutable let or match without any bindings (equivalent to inner expression) + ~_ => { } + } + + match false { // okay: more than one arm + false => { }, + _ => { } + } + match [1, 2] { + [..v] => { } + } + let ((_, (_, a)), ()) = ((1, (2, 3)), ()); // okay: has a binding + let ((_, (_, ref a)), ()) = ((1, (2, 3)), ()); // okay: has a binding + let ~ref x = ~789; +}