@@ -4,11 +4,12 @@ use rustc::lint::*;
4
4
use rustc:: middle:: const_eval:: EvalHint :: ExprTypeChecked ;
5
5
use rustc:: middle:: const_eval:: { ConstVal , eval_const_expr_partial} ;
6
6
use rustc:: middle:: def:: Def ;
7
+ use rustc:: middle:: region:: CodeExtent ;
7
8
use rustc:: middle:: ty;
8
9
use rustc_front:: hir:: * ;
9
10
use rustc_front:: intravisit:: { Visitor , walk_expr, walk_block, walk_decl} ;
10
11
use std:: borrow:: Cow ;
11
- use std:: collections:: { HashSet , HashMap } ;
12
+ use std:: collections:: HashMap ;
12
13
13
14
use utils:: { snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block,
14
15
span_help_and_lint, is_integer_literal, get_enclosing_block, span_lint_and_then, walk_ptrs_ty} ;
@@ -338,19 +339,27 @@ fn check_for_loop_range(cx: &LateContext, pat: &Pat, arg: &Expr, body: &Expr, ex
338
339
if let ExprRange ( Some ( ref l) , ref r) = arg. node {
339
340
// the var must be a single name
340
341
if let PatIdent ( _, ref ident, _) = pat. node {
342
+
341
343
let mut visitor = VarVisitor {
342
344
cx : cx,
343
345
var : ident. node . name ,
344
- indexed : HashSet :: new ( ) ,
346
+ indexed : HashMap :: new ( ) ,
345
347
nonindex : false ,
346
348
} ;
347
349
walk_expr ( & mut visitor, body) ;
350
+
348
351
// linting condition: we only indexed one variable
349
352
if visitor. indexed . len ( ) == 1 {
350
- let indexed = visitor. indexed
353
+ let ( indexed, indexed_extent ) = visitor. indexed
351
354
. into_iter ( )
352
355
. next ( )
353
- . expect ( "Len was nonzero, but no contents found" ) ;
356
+ . unwrap_or_else ( || unreachable ! ( ) /* len == 1 */ ) ;
357
+
358
+ // ensure that the indexed variable was declared before the loop, see #601
359
+ let pat_extent = cx. tcx . region_maps . var_scope ( pat. id ) ;
360
+ if cx. tcx . region_maps . is_subscope_of ( indexed_extent, pat_extent) {
361
+ return ;
362
+ }
354
363
355
364
let starts_at_zero = is_integer_literal ( l, 0 ) ;
356
365
@@ -673,7 +682,7 @@ fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> {
673
682
struct VarVisitor < ' v , ' t : ' v > {
674
683
cx : & ' v LateContext < ' v , ' t > , // context reference
675
684
var : Name , // var name to look for as index
676
- indexed : HashSet < Name > , // indexed variables
685
+ indexed : HashMap < Name , CodeExtent > , // indexed variables
677
686
nonindex : bool , // has the var been used otherwise?
678
687
}
679
688
@@ -689,8 +698,12 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> {
689
698
let ExprPath ( None , ref seqvar) = seqexpr. node,
690
699
seqvar. segments. len( ) == 1
691
700
] , {
692
- self . indexed. insert( seqvar. segments[ 0 ] . identifier. name) ;
693
- return ; // no need to walk further
701
+ let def_map = self . cx. tcx. def_map. borrow( ) ;
702
+ if let Some ( def) = def_map. get( & seqexpr. id) {
703
+ let extent = self . cx. tcx. region_maps. var_scope( def. base_def. var_id( ) ) ;
704
+ self . indexed. insert( seqvar. segments[ 0 ] . identifier. name, extent) ;
705
+ return ; // no need to walk further
706
+ }
694
707
}
695
708
}
696
709
// we are not indexing anything, record that
0 commit comments