]> git.proxmox.com Git - rustc.git/blame - src/librustc_passes/loops.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / librustc_passes / loops.rs
CommitLineData
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 10use self::Context::*;
223e47cc 11
7453a54e 12use rustc::session::Session;
223e47cc 13
7453a54e 14use rustc::dep_graph::DepNode;
54a0048b
SL
15use rustc::hir::map::Map;
16use rustc::hir::intravisit::{self, Visitor};
17use rustc::hir;
3157f602 18use syntax_pos::Span;
223e47cc 19
1a4d82fc
JJ
20#[derive(Clone, Copy, PartialEq)]
21enum Context {
5bcae85e
SL
22 Normal,
23 Loop,
24 Closure,
1a4d82fc
JJ
25}
26
c34b1796 27#[derive(Copy, Clone)]
1a4d82fc
JJ
28struct CheckLoopVisitor<'a> {
29 sess: &'a Session,
5bcae85e 30 cx: Context,
1a4d82fc
JJ
31}
32
7453a54e
SL
33pub 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
42impl<'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 66impl<'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}