Skip to content

Commit 176df98

Browse files
committed
auto merge of #14044 : hirschenberger/rust/lint_mut_match, r=alexcrichton
fixing #13866
2 parents 6520565 + de92d42 commit 176df98

File tree

2 files changed

+67
-21
lines changed

2 files changed

+67
-21
lines changed

src/librustc/middle/lint.rs

+51-21
Original file line numberDiff line numberDiff line change
@@ -1367,28 +1367,38 @@ fn check_unsafe_block(cx: &Context, e: &ast::Expr) {
13671367
}
13681368
}
13691369

1370-
fn check_unused_mut_pat(cx: &Context, p: &ast::Pat) {
1371-
match p.node {
1372-
ast::PatIdent(ast::BindByValue(ast::MutMutable),
1373-
ref path, _) if pat_util::pat_is_binding(&cx.tcx.def_map, p) => {
1374-
// `let mut _a = 1;` doesn't need a warning.
1375-
let initial_underscore = if path.segments.len() == 1 {
1376-
token::get_ident(path.segments
1377-
.get(0)
1378-
.identifier).get().starts_with("_")
1379-
} else {
1380-
cx.tcx.sess.span_bug(p.span,
1381-
"mutable binding that doesn't consist \
1382-
of exactly one segment")
1383-
};
1384-
1385-
if !initial_underscore &&
1386-
!cx.tcx.used_mut_nodes.borrow().contains(&p.id) {
1387-
cx.span_lint(UnusedMut, p.span,
1388-
"variable does not need to be mutable");
1370+
fn check_unused_mut_pat(cx: &Context, pats: &[@ast::Pat]) {
1371+
// collect all mutable pattern and group their NodeIDs by their Identifier to
1372+
// avoid false warnings in match arms with multiple patterns
1373+
let mut mutables = HashMap::new();
1374+
for &p in pats.iter() {
1375+
pat_util::pat_bindings(&cx.tcx.def_map, p, |mode, id, _, path| {
1376+
match mode {
1377+
ast::BindByValue(ast::MutMutable) => {
1378+
if path.segments.len() != 1 {
1379+
cx.tcx.sess.span_bug(p.span,
1380+
"mutable binding that doesn't consist \
1381+
of exactly one segment");
1382+
}
1383+
let ident = path.segments.get(0).identifier;
1384+
if !token::get_ident(ident).get().starts_with("_") {
1385+
mutables.insert_or_update_with(ident.name as uint, vec!(id), |_, old| {
1386+
old.push(id);
1387+
});
1388+
}
1389+
}
1390+
_ => {
1391+
}
13891392
}
1393+
});
1394+
}
1395+
1396+
let used_mutables = cx.tcx.used_mut_nodes.borrow();
1397+
for (_, v) in mutables.iter() {
1398+
if !v.iter().any(|e| used_mutables.contains(e)) {
1399+
cx.span_lint(UnusedMut, cx.tcx.map.span(*v.get(0)),
1400+
"variable does not need to be mutable");
13901401
}
1391-
_ => ()
13921402
}
13931403
}
13941404

@@ -1684,7 +1694,6 @@ impl<'a> Visitor<()> for Context<'a> {
16841694
fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
16851695
check_pat_non_uppercase_statics(self, p);
16861696
check_pat_uppercase_variable(self, p);
1687-
check_unused_mut_pat(self, p);
16881697

16891698
visit::walk_pat(self, p, ());
16901699
}
@@ -1700,6 +1709,11 @@ impl<'a> Visitor<()> for Context<'a> {
17001709
ast::ExprParen(expr) => if self.negated_expr_id == e.id {
17011710
self.negated_expr_id = expr.id
17021711
},
1712+
ast::ExprMatch(_, ref arms) => {
1713+
for a in arms.iter() {
1714+
check_unused_mut_pat(self, a.pats.as_slice());
1715+
}
1716+
},
17031717
_ => ()
17041718
};
17051719

@@ -1723,6 +1737,18 @@ impl<'a> Visitor<()> for Context<'a> {
17231737
check_unused_result(self, s);
17241738
check_unnecessary_parens_stmt(self, s);
17251739

1740+
match s.node {
1741+
ast::StmtDecl(d, _) => {
1742+
match d.node {
1743+
ast::DeclLocal(l) => {
1744+
check_unused_mut_pat(self, &[l.pat]);
1745+
},
1746+
_ => {}
1747+
}
1748+
},
1749+
_ => {}
1750+
}
1751+
17261752
visit::walk_stmt(self, s, ());
17271753
}
17281754

@@ -1732,6 +1758,10 @@ impl<'a> Visitor<()> for Context<'a> {
17321758
visit::walk_fn(this, fk, decl, body, span, id, ());
17331759
};
17341760

1761+
for a in decl.inputs.iter(){
1762+
check_unused_mut_pat(self, &[a.pat]);
1763+
}
1764+
17351765
match *fk {
17361766
visit::FkMethod(_, _, m) => {
17371767
self.with_lint_attrs(m.attrs.as_slice(), |cx| {

src/test/compile-fail/lint-unused-mut-variables.rs

+16
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ fn main() {
2828
match 30 {
2929
mut x => {} //~ ERROR: variable does not need to be mutable
3030
}
31+
match (30, 2) {
32+
(mut x, 1) | //~ ERROR: variable does not need to be mutable
33+
(mut x, 2) |
34+
(mut x, 3) => {
35+
}
36+
_ => {}
37+
}
3138

3239
let x = |mut y: int| 10; //~ ERROR: variable does not need to be mutable
3340
fn what(mut foo: int) {} //~ ERROR: variable does not need to be mutable
@@ -50,6 +57,15 @@ fn main() {
5057
}
5158
}
5259

60+
match (30, 2) {
61+
(mut x, 1) |
62+
(mut x, 2) |
63+
(mut x, 3) => {
64+
x = 21
65+
}
66+
_ => {}
67+
}
68+
5369
let x = |mut y: int| y = 32;
5470
fn nothing(mut foo: int) { foo = 37; }
5571

0 commit comments

Comments
 (0)