]>
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; | |
3157f602 | 18 | use syntax_pos::Span; |
223e47cc | 19 | |
1a4d82fc JJ |
20 | #[derive(Clone, Copy, PartialEq)] |
21 | enum Context { | |
5bcae85e SL |
22 | Normal, |
23 | Loop, | |
24 | Closure, | |
1a4d82fc JJ |
25 | } |
26 | ||
c34b1796 | 27 | #[derive(Copy, Clone)] |
1a4d82fc JJ |
28 | struct CheckLoopVisitor<'a> { |
29 | sess: &'a Session, | |
5bcae85e | 30 | cx: Context, |
1a4d82fc JJ |
31 | } |
32 | ||
7453a54e SL |
33 | pub fn check_crate(sess: &Session, map: &Map) { |
34 | let _task = map.dep_graph.in_task(DepNode::CheckLoops); | |
35 | let krate = map.krate(); | |
5bcae85e SL |
36 | krate.visit_all_items(&mut CheckLoopVisitor { |
37 | sess: sess, | |
38 | cx: Normal, | |
39 | }); | |
1a4d82fc JJ |
40 | } |
41 | ||
42 | impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> { | |
e9174d1e | 43 | fn visit_item(&mut self, i: &hir::Item) { |
92a42be0 | 44 | self.with_context(Normal, |v| intravisit::walk_item(v, i)); |
1a4d82fc JJ |
45 | } |
46 | ||
e9174d1e | 47 | fn visit_expr(&mut self, e: &hir::Expr) { |
1a4d82fc | 48 | match e.node { |
e9174d1e | 49 | hir::ExprWhile(ref e, ref b, _) => { |
7453a54e SL |
50 | self.visit_expr(&e); |
51 | self.with_context(Loop, |v| v.visit_block(&b)); | |
1a4d82fc | 52 | } |
e9174d1e | 53 | hir::ExprLoop(ref b, _) => { |
7453a54e | 54 | self.with_context(Loop, |v| v.visit_block(&b)); |
1a4d82fc | 55 | } |
9e0c209e | 56 | hir::ExprClosure(.., ref b, _) => { |
7453a54e | 57 | self.with_context(Closure, |v| v.visit_block(&b)); |
1a4d82fc | 58 | } |
e9174d1e SL |
59 | hir::ExprBreak(_) => self.require_loop("break", e.span), |
60 | hir::ExprAgain(_) => self.require_loop("continue", e.span), | |
5bcae85e | 61 | _ => intravisit::walk_expr(self, e), |
1a4d82fc JJ |
62 | } |
63 | } | |
223e47cc LB |
64 | } |
65 | ||
1a4d82fc | 66 | impl<'a> CheckLoopVisitor<'a> { |
5bcae85e SL |
67 | fn with_context<F>(&mut self, cx: Context, f: F) |
68 | where F: FnOnce(&mut CheckLoopVisitor<'a>) | |
1a4d82fc JJ |
69 | { |
70 | let old_cx = self.cx; | |
71 | self.cx = cx; | |
72 | f(self); | |
73 | self.cx = old_cx; | |
74 | } | |
75 | ||
76 | fn require_loop(&self, name: &str, span: Span) { | |
77 | match self.cx { | |
78 | Loop => {} | |
79 | Closure => { | |
5bcae85e SL |
80 | struct_span_err!(self.sess, span, E0267, "`{}` inside of a closure", name) |
81 | .span_label(span, &format!("cannot break inside of a closure")) | |
82 | .emit(); | |
1a4d82fc JJ |
83 | } |
84 | Normal => { | |
5bcae85e SL |
85 | struct_span_err!(self.sess, span, E0268, "`{}` outside of loop", name) |
86 | .span_label(span, &format!("cannot break outside of a loop")) | |
87 | .emit(); | |
223e47cc | 88 | } |
1a4d82fc JJ |
89 | } |
90 | } | |
223e47cc | 91 | } |