Skip to content

Commit 6a624fe

Browse files
committed
Merge pull request #662 from mcarton/#601
Fix #601
2 parents 5521a75 + cbe2de7 commit 6a624fe

File tree

3 files changed

+27
-7
lines changed

3 files changed

+27
-7
lines changed

src/copies.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ declare_lint! {
4848
/// Bar => bar(),
4949
/// Quz => quz(),
5050
/// Baz => bar(), // <= oups
51+
/// }
5152
/// ```
5253
declare_lint! {
5354
pub MATCH_SAME_ARMS,

src/loops.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ use rustc::lint::*;
44
use rustc::middle::const_eval::EvalHint::ExprTypeChecked;
55
use rustc::middle::const_eval::{ConstVal, eval_const_expr_partial};
66
use rustc::middle::def::Def;
7+
use rustc::middle::region::CodeExtent;
78
use rustc::middle::ty;
89
use rustc_front::hir::*;
910
use rustc_front::intravisit::{Visitor, walk_expr, walk_block, walk_decl};
1011
use std::borrow::Cow;
11-
use std::collections::{HashSet, HashMap};
12+
use std::collections::HashMap;
1213

1314
use utils::{snippet, span_lint, get_parent_expr, match_trait_method, match_type, in_external_macro, expr_block,
1415
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
338339
if let ExprRange(Some(ref l), ref r) = arg.node {
339340
// the var must be a single name
340341
if let PatIdent(_, ref ident, _) = pat.node {
342+
341343
let mut visitor = VarVisitor {
342344
cx: cx,
343345
var: ident.node.name,
344-
indexed: HashSet::new(),
346+
indexed: HashMap::new(),
345347
nonindex: false,
346348
};
347349
walk_expr(&mut visitor, body);
350+
348351
// linting condition: we only indexed one variable
349352
if visitor.indexed.len() == 1 {
350-
let indexed = visitor.indexed
353+
let (indexed, indexed_extent) = visitor.indexed
351354
.into_iter()
352355
.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+
}
354363

355364
let starts_at_zero = is_integer_literal(l, 0);
356365

@@ -673,7 +682,7 @@ fn recover_for_loop(expr: &Expr) -> Option<(&Pat, &Expr, &Expr)> {
673682
struct VarVisitor<'v, 't: 'v> {
674683
cx: &'v LateContext<'v, 't>, // context reference
675684
var: Name, // var name to look for as index
676-
indexed: HashSet<Name>, // indexed variables
685+
indexed: HashMap<Name, CodeExtent>, // indexed variables
677686
nonindex: bool, // has the var been used otherwise?
678687
}
679688

@@ -689,8 +698,12 @@ impl<'v, 't> Visitor<'v> for VarVisitor<'v, 't> {
689698
let ExprPath(None, ref seqvar) = seqexpr.node,
690699
seqvar.segments.len() == 1
691700
], {
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+
}
694707
}
695708
}
696709
// we are not indexing anything, record that

tests/compile-fail/for_loop.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,12 @@ fn main() {
192192
println!("{}", i);
193193
}
194194

195+
// See #601
196+
for i in 0..10 { // no error, id_col does not exist outside the loop
197+
let mut id_col = vec![0f64; 10];
198+
id_col[i] = 1f64;
199+
}
200+
195201
/*
196202
for i in (10..0).map(|x| x * 2) {
197203
println!("{}", i);

0 commit comments

Comments
 (0)