]> git.proxmox.com Git - rustc.git/blob - src/librustc_passes/const_fn.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_passes / const_fn.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
11 //! Verifies that const fn arguments are immutable by value bindings
12 //! and the const fn body doesn't contain any statements
13
14 use rustc::session::{Session, CompileResult};
15
16 use syntax::ast::{self, PatKind};
17 use syntax::visit::{self, Visitor, FnKind};
18 use syntax::codemap::Span;
19
20 pub fn check_crate(sess: &Session, krate: &ast::Crate) -> CompileResult {
21 sess.track_errors(|| {
22 visit::walk_crate(&mut CheckConstFn{ sess: sess }, krate);
23 })
24 }
25
26 struct CheckConstFn<'a> {
27 sess: &'a Session,
28 }
29
30 struct CheckBlock<'a> {
31 sess: &'a Session,
32 kind: &'static str,
33 }
34
35 impl<'a, 'v> Visitor<'v> for CheckBlock<'a> {
36 fn visit_block(&mut self, block: &'v ast::Block) {
37 check_block(&self.sess, block, self.kind);
38 CheckConstFn{ sess: self.sess}.visit_block(block);
39 }
40 fn visit_expr(&mut self, e: &'v ast::Expr) {
41 if let ast::ExprKind::Closure(..) = e.node {
42 CheckConstFn{ sess: self.sess}.visit_expr(e);
43 } else {
44 visit::walk_expr(self, e);
45 }
46 }
47 fn visit_item(&mut self, _i: &'v ast::Item) { bug!("should be handled in CheckConstFn") }
48 fn visit_fn(&mut self,
49 _fk: FnKind<'v>,
50 _fd: &'v ast::FnDecl,
51 _b: &'v ast::Block,
52 _s: Span,
53 _fn_id: ast::NodeId) { bug!("should be handled in CheckConstFn") }
54 }
55
56 fn check_block(sess: &Session, b: &ast::Block, kind: &'static str) {
57 // Check all statements in the block
58 for stmt in &b.stmts {
59 let span = match stmt.node {
60 ast::StmtKind::Decl(ref decl, _) => {
61 match decl.node {
62 ast::DeclKind::Local(_) => decl.span,
63
64 // Item statements are allowed
65 ast::DeclKind::Item(_) => continue,
66 }
67 }
68 ast::StmtKind::Expr(ref expr, _) => expr.span,
69 ast::StmtKind::Semi(ref semi, _) => semi.span,
70 ast::StmtKind::Mac(..) => bug!(),
71 };
72 span_err!(sess, span, E0016,
73 "blocks in {}s are limited to items and tail expressions", kind);
74 }
75 }
76
77 impl<'a, 'v> Visitor<'v> for CheckConstFn<'a> {
78 fn visit_item(&mut self, i: &'v ast::Item) {
79 visit::walk_item(self, i);
80 match i.node {
81 ast::ItemKind::Const(_, ref e) => {
82 CheckBlock{ sess: self.sess, kind: "constant"}.visit_expr(e)
83 },
84 ast::ItemKind::Static(_, _, ref e) => {
85 CheckBlock{ sess: self.sess, kind: "static"}.visit_expr(e)
86 },
87 _ => {},
88 }
89 }
90
91 fn visit_fn(&mut self,
92 fk: FnKind<'v>,
93 fd: &'v ast::FnDecl,
94 b: &'v ast::Block,
95 s: Span,
96 _fn_id: ast::NodeId) {
97 visit::walk_fn(self, fk, fd, b, s);
98 match fk {
99 FnKind::ItemFn(_, _, _, ast::Constness::Const, _, _) => {},
100 FnKind::Method(_, m, _) if m.constness == ast::Constness::Const => {},
101 _ => return,
102 }
103
104 // Ensure the arguments are simple, not mutable/by-ref or patterns.
105 for arg in &fd.inputs {
106 match arg.pat.node {
107 PatKind::Wild => {}
108 PatKind::Ident(ast::BindingMode::ByValue(ast::Mutability::Immutable), _, None) => {}
109 _ => {
110 span_err!(self.sess, arg.pat.span, E0022,
111 "arguments of constant functions can only \
112 be immutable by-value bindings");
113 }
114 }
115 }
116 check_block(&self.sess, b, "const function");
117 }
118 }