@@ -347,7 +347,9 @@ declare_lint! {
347
347
/// **Why is this bad?** If the condition is unchanged, entering the body of the loop
348
348
/// will lead to an infinite loop.
349
349
///
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.
351
353
///
352
354
/// **Example:**
353
355
/// ```rust
@@ -2150,17 +2152,6 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, b
2150
2152
return ;
2151
2153
}
2152
2154
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
-
2164
2155
let mut delegate = MutVarsDelegate {
2165
2156
used_mutably : mut_var_visitor. ids ,
2166
2157
skip : false ,
@@ -2169,6 +2160,9 @@ fn check_infinite_loop<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, cond: &'tcx Expr, b
2169
2160
let region_scope_tree = & cx. tcx . region_scope_tree ( def_id) ;
2170
2161
ExprUseVisitor :: new ( & mut delegate, cx. tcx , cx. param_env , region_scope_tree, cx. tables , None ) . walk_expr ( expr) ;
2171
2162
2163
+ if delegate. skip {
2164
+ return ;
2165
+ }
2172
2166
if !delegate. used_mutably . iter ( ) . any ( |( _, v) | * v) {
2173
2167
span_lint (
2174
2168
cx,
@@ -2195,9 +2189,13 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
2195
2189
if let ExprPath ( ref qpath) = ex. node;
2196
2190
if let QPath :: Resolved ( None , _) = * qpath;
2197
2191
let def = self . cx. tables. qpath_def( qpath, ex. hir_id) ;
2198
- if let Def :: Local ( node_id) = def;
2199
2192
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
+ }
2201
2199
}
2202
2200
}
2203
2201
}
@@ -2206,10 +2204,7 @@ impl<'a, 'tcx> VarCollectorVisitor<'a, 'tcx> {
2206
2204
impl < ' a , ' tcx > Visitor < ' tcx > for VarCollectorVisitor < ' a , ' tcx > {
2207
2205
fn visit_expr ( & mut self , ex : & ' tcx Expr ) {
2208
2206
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) ,
2213
2208
// If there is any fuction/method call… we just stop analysis
2214
2209
ExprCall ( ..) | ExprMethodCall ( ..) => self . skip = true ,
2215
2210
@@ -2236,7 +2231,12 @@ impl<'tcx> MutVarsDelegate {
2236
2231
if let Some ( used) = self . used_mutably . get_mut ( & id) {
2237
2232
* used = true ;
2238
2233
} ,
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
+ } ,
2240
2240
Categorization :: Deref ( ref cmt, _) => self . update ( & cmt. cat , sp) ,
2241
2241
_ => { }
2242
2242
}
0 commit comments