]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/check_loop.rs
Auto merge of #30696 - steveklabnik:gh30655, r=brson
[rust.git] / src / librustc / middle / check_loop.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
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.
10 use self::Context::*;
11
12 use session::Session;
13
14 use syntax::codemap::Span;
15 use rustc_front::intravisit::{self, Visitor};
16 use rustc_front::hir;
17
18 #[derive(Clone, Copy, PartialEq)]
19 enum Context {
20     Normal, Loop, Closure
21 }
22
23 #[derive(Copy, Clone)]
24 struct CheckLoopVisitor<'a> {
25     sess: &'a Session,
26     cx: Context
27 }
28
29 pub fn check_crate(sess: &Session, krate: &hir::Crate) {
30     krate.visit_all_items(&mut CheckLoopVisitor { sess: sess, cx: Normal });
31 }
32
33 impl<'a, 'v> Visitor<'v> for CheckLoopVisitor<'a> {
34     fn visit_item(&mut self, i: &hir::Item) {
35         self.with_context(Normal, |v| intravisit::walk_item(v, i));
36     }
37
38     fn visit_expr(&mut self, e: &hir::Expr) {
39         match e.node {
40             hir::ExprWhile(ref e, ref b, _) => {
41                 self.visit_expr(&**e);
42                 self.with_context(Loop, |v| v.visit_block(&**b));
43             }
44             hir::ExprLoop(ref b, _) => {
45                 self.with_context(Loop, |v| v.visit_block(&**b));
46             }
47             hir::ExprClosure(_, _, ref b) => {
48                 self.with_context(Closure, |v| v.visit_block(&**b));
49             }
50             hir::ExprBreak(_) => self.require_loop("break", e.span),
51             hir::ExprAgain(_) => self.require_loop("continue", e.span),
52             _ => intravisit::walk_expr(self, e)
53         }
54     }
55 }
56
57 impl<'a> CheckLoopVisitor<'a> {
58     fn with_context<F>(&mut self, cx: Context, f: F) where
59         F: FnOnce(&mut CheckLoopVisitor<'a>),
60     {
61         let old_cx = self.cx;
62         self.cx = cx;
63         f(self);
64         self.cx = old_cx;
65     }
66
67     fn require_loop(&self, name: &str, span: Span) {
68         match self.cx {
69             Loop => {}
70             Closure => {
71                 span_err!(self.sess, span, E0267,
72                                    "`{}` inside of a closure", name);
73             }
74             Normal => {
75                 span_err!(self.sess, span, E0268,
76                                    "`{}` outside of loop", name);
77             }
78         }
79     }
80 }