Skip to content

Commit 7d29075

Browse files
committed
Skip the mutation in while body case for closures
1 parent d458f22 commit 7d29075

File tree

2 files changed

+37
-37
lines changed

2 files changed

+37
-37
lines changed

clippy_lints/src/loops.rs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,9 @@ declare_lint! {
347347
/// **Why is this bad?** If the condition is unchanged, entering the body of the loop
348348
/// will lead to an infinite loop.
349349
///
350-
/// **Known problems:** None
350+
/// **Known problems:** If the `while`-loop is in a closure, the check for mutation of the
351+
/// condition variables in the body can cause false negatives. For example when only `Upvar` `a` is
352+
/// in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger.
351353
///
352354
/// **Example:**
353355
/// ```rust
@@ -2150,17 +2152,6 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, b
21502152
return;
21512153
}
21522154

2153-
if mut_var_visitor.ids.is_empty() {
2154-
span_lint(
2155-
cx,
2156-
WHILE_IMMUTABLE_CONDITION,
2157-
cond.span,
2158-
"all variables in condition are immutable. This either leads to an infinite or to a never running loop.",
2159-
);
2160-
return;
2161-
}
2162-
2163-
21642155
let mut delegate = MutVarsDelegate {
21652156
used_mutably: mut_var_visitor.ids,
21662157
skip: false,
@@ -2169,6 +2160,9 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, b
21692160
let region_scope_tree = &cx.tcx.region_scope_tree(def_id);
21702161
ExprUseVisitor::new(&mut delegate, cx.tcx, cx.param_env, region_scope_tree, cx.tables, None).walk_expr(expr);
21712162

2163+
if delegate.skip {
2164+
return;
2165+
}
21722166
if !delegate.used_mutably.iter().any(|(_, v)| *v) {
21732167
span_lint(
21742168
cx,
@@ -2195,9 +2189,13 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
21952189
if let ExprPath(ref qpath) = ex.node;
21962190
if let QPath::Resolved(None, _) = *qpath;
21972191
let def = self.cx.tables.qpath_def(qpath, ex.hir_id);
2198-
if let Def::Local(node_id) = def;
21992192
then {
2200-
self.ids.insert(node_id, false);
2193+
match def {
2194+
Def::Local(node_id) | Def::Upvar(node_id, ..) => {
2195+
self.ids.insert(node_id, false);
2196+
},
2197+
_ => {},
2198+
}
22012199
}
22022200
}
22032201
}
@@ -2206,10 +2204,7 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
22062204
impl<'a, 'tcx> Visitor<'tcx> for VarCollectorVisitor<'a, 'tcx> {
22072205
fn visit_expr(&mut self, ex: &'tcx Expr) {
22082206
match ex.node {
2209-
ExprPath(_) => if let Some(node_id) = check_for_mutability(self.cx, ex) {
2210-
self.ids.insert(node_id, false);
2211-
},
2212-
2207+
ExprPath(_) => self.insert_def_id(ex),
22132208
// If there is any fuction/method call… we just stop analysis
22142209
ExprCall(..) | ExprMethodCall(..) => self.skip = true,
22152210

@@ -2236,7 +2231,12 @@ impl<'tcx> MutVarsDelegate {
22362231
if let Some(used) = self.used_mutably.get_mut(&id) {
22372232
*used = true;
22382233
},
2239-
Categorization::Upvar(_) => skip = true,
2234+
Categorization::Upvar(_) => {
2235+
//FIXME: This causes false negatives. We can't get the `NodeId` from
2236+
//`Categorization::Upvar(_)`. So we search for any `Upvar`s in the
2237+
//`while`-body, not just the ones in the condition.
2238+
self.skip = true
2239+
},
22402240
Categorization::Deref(ref cmt, _) => self.update(&cmt.cat, sp),
22412241
_ => {}
22422242
}

tests/ui/infinite_loop.stderr

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,57 @@
11
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
2-
--> $DIR/infinite_loop.rs:10:11
2+
--> $DIR/infinite_loop.rs:14:11
33
|
4-
10 | while y < 10 {
4+
14 | while y < 10 {
55
| ^^^^^^
66
|
77
= note: `-D while-immutable-condition` implied by `-D warnings`
88

99
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
10-
--> $DIR/infinite_loop.rs:15:11
10+
--> $DIR/infinite_loop.rs:19:11
1111
|
12-
15 | while y < 10 && x < 3 {
12+
19 | while y < 10 && x < 3 {
1313
| ^^^^^^^^^^^^^^^
1414

1515
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
16-
--> $DIR/infinite_loop.rs:22:11
16+
--> $DIR/infinite_loop.rs:26:11
1717
|
18-
22 | while !cond {
18+
26 | while !cond {
1919
| ^^^^^
2020

2121
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
22-
--> $DIR/infinite_loop.rs:52:11
22+
--> $DIR/infinite_loop.rs:64:11
2323
|
24-
52 | while i < 3 {
24+
64 | while i < 3 {
2525
| ^^^^^
2626

2727
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
28-
--> $DIR/infinite_loop.rs:57:11
28+
--> $DIR/infinite_loop.rs:69:11
2929
|
30-
57 | while i < 3 && j > 0 {
30+
69 | while i < 3 && j > 0 {
3131
| ^^^^^^^^^^^^^^
3232

3333
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
34-
--> $DIR/infinite_loop.rs:61:11
34+
--> $DIR/infinite_loop.rs:73:11
3535
|
36-
61 | while i < 3 {
36+
73 | while i < 3 {
3737
| ^^^^^
3838

3939
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
40-
--> $DIR/infinite_loop.rs:76:11
40+
--> $DIR/infinite_loop.rs:88:11
4141
|
42-
76 | while i < 3 {
42+
88 | while i < 3 {
4343
| ^^^^^
4444

4545
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
46-
--> $DIR/infinite_loop.rs:81:11
46+
--> $DIR/infinite_loop.rs:93:11
4747
|
48-
81 | while i < 3 {
48+
93 | while i < 3 {
4949
| ^^^^^
5050

5151
error: Variable in the condition are not mutated in the loop body. This either leads to an infinite or to a never running loop.
52-
--> $DIR/infinite_loop.rs:144:15
52+
--> $DIR/infinite_loop.rs:156:15
5353
|
54-
144 | while self.count < n {
54+
156 | while self.count < n {
5555
| ^^^^^^^^^^^^^^
5656

5757
error: aborting due to 9 previous errors

0 commit comments

Comments
 (0)