]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
2 | // file at the top-level directory of this distribution and at |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
1a4d82fc | 10 | use self::Context::*; |
223e47cc | 11 | |
7453a54e | 12 | use rustc::session::Session; |
223e47cc | 13 | |
7453a54e | 14 | use rustc::dep_graph::DepNode; |
54a0048b SL |
15 | use rustc::hir::map::Map; |
16 | use rustc::hir::intravisit::{self, Visitor}; | |
17 | use rustc::hir; | |
7453a54e | 18 | use syntax::codemap::Span; |
223e47cc | 19 | |
1a4d82fc JJ |
20 | #[derive(Clone, Copy, PartialEq)] |
21 | enum Context { | |
22 | Normal, Loop, Closure | |
23 | } | |
24 | ||
c34b1796 | 25 | #[derive(Copy, Clone)] |
1a4d82fc JJ |
26 | struct CheckLoopVisitor<'a> { |
27 | sess: &'a Session, | |
28 | cx: Context | |
29 | } | |
30 | ||
7453a54e SL |
31 | pub fn check_crate(sess: &Session, map: &Map) { |
32 | let _task = map.dep_graph.in_task(DepNode::CheckLoops); | |
33 | let krate = map.krate(); | |
92a42be0 | 34 | krate.visit_all_items(&mut CheckLoopVisitor { sess: sess, cx: Normal }); |
1a4d82fc JJ |
35 | } |
36 | ||
37 | impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> { | |
e9174d1e | 38 | fn visit_item(&mut self, i: &hir::Item) { |
92a42be0 | 39 | self.with_context(Normal, |v| intravisit::walk_item(v, i)); |
1a4d82fc JJ |
40 | } |
41 | ||
e9174d1e | 42 | fn visit_expr(&mut self, e: &hir::Expr) { |
1a4d82fc | 43 | match e.node { |
e9174d1e | 44 | hir::ExprWhile(ref e, ref b, _) => { |
7453a54e SL |
45 | self.visit_expr(&e); |
46 | self.with_context(Loop, |v| v.visit_block(&b)); | |
1a4d82fc | 47 | } |
e9174d1e | 48 | hir::ExprLoop(ref b, _) => { |
7453a54e | 49 | self.with_context(Loop, |v| v.visit_block(&b)); |
1a4d82fc | 50 | } |
e9174d1e | 51 | hir::ExprClosure(_, _, ref b) => { |
7453a54e | 52 | self.with_context(Closure, |v| v.visit_block(&b)); |
1a4d82fc | 53 | } |
e9174d1e SL |
54 | hir::ExprBreak(_) => self.require_loop("break", e.span), |
55 | hir::ExprAgain(_) => self.require_loop("continue", e.span), | |
92a42be0 | 56 | _ => intravisit::walk_expr(self, e) |
1a4d82fc JJ |
57 | } |
58 | } | |
223e47cc LB |
59 | } |
60 | ||
1a4d82fc JJ |
61 | impl<'a> CheckLoopVisitor<'a> { |
62 | fn with_context<F>(&mut self, cx: Context, f: F) where | |
63 | F: FnOnce(&mut CheckLoopVisitor<'a>), | |
64 | { | |
65 | let old_cx = self.cx; | |
66 | self.cx = cx; | |
67 | f(self); | |
68 | self.cx = old_cx; | |
69 | } | |
70 | ||
71 | fn require_loop(&self, name: &str, span: Span) { | |
72 | match self.cx { | |
73 | Loop => {} | |
74 | Closure => { | |
85aaf69f SL |
75 | span_err!(self.sess, span, E0267, |
76 | "`{}` inside of a closure", name); | |
1a4d82fc JJ |
77 | } |
78 | Normal => { | |
85aaf69f SL |
79 | span_err!(self.sess, span, E0268, |
80 | "`{}` outside of loop", name); | |
223e47cc | 81 | } |
1a4d82fc JJ |
82 | } |
83 | } | |
223e47cc | 84 | } |