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.
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.
11 //! Verifies that const fn arguments are immutable by value bindings
12 //! and the const fn body doesn't contain any statements
14 use rustc
::session
::{Session, CompileResult}
;
16 use syntax
::ast
::{self, PatKind}
;
17 use syntax
::visit
::{self, Visitor, FnKind}
;
18 use syntax
::codemap
::Span
;
20 pub fn check_crate(sess
: &Session
, krate
: &ast
::Crate
) -> CompileResult
{
21 sess
.track_errors(|| {
22 visit
::walk_crate(&mut CheckConstFn{ sess: sess }
, krate
);
26 struct CheckConstFn
<'a
> {
30 struct CheckBlock
<'a
> {
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
);
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
);
44 visit
::walk_expr(self, e
);
47 fn visit_item(&mut self, _i
: &'v ast
::Item
) { bug!("should be handled in CheckConstFn") }
48 fn visit_fn(&mut self,
53 _fn_id
: ast
::NodeId
) { bug!("should be handled in CheckConstFn") }
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
, _
) => {
62 ast
::DeclKind
::Local(_
) => decl
.span
,
64 // Item statements are allowed
65 ast
::DeclKind
::Item(_
) => continue,
68 ast
::StmtKind
::Expr(ref expr
, _
) => expr
.span
,
69 ast
::StmtKind
::Semi(ref semi
, _
) => semi
.span
,
70 ast
::StmtKind
::Mac(..) => bug
!(),
72 span_err
!(sess
, span
, E0016
,
73 "blocks in {}s are limited to items and tail expressions", kind
);
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
);
81 ast
::ItemKind
::Const(_
, ref e
) => {
82 CheckBlock{ sess: self.sess, kind: "constant"}
.visit_expr(e
)
84 ast
::ItemKind
::Static(_
, _
, ref e
) => {
85 CheckBlock{ sess: self.sess, kind: "static"}
.visit_expr(e
)
91 fn visit_fn(&mut self,
96 _fn_id
: ast
::NodeId
) {
97 visit
::walk_fn(self, fk
, fd
, b
, s
);
99 FnKind
::ItemFn(_
, _
, _
, ast
::Constness
::Const
, _
, _
) => {}
,
100 FnKind
::Method(_
, m
, _
) if m
.constness
== ast
::Constness
::Const
=> {}
,
104 // Ensure the arguments are simple, not mutable/by-ref or patterns.
105 for arg
in &fd
.inputs
{
108 PatKind
::Ident(ast
::BindingMode
::ByValue(ast
::Mutability
::Immutable
), _
, None
) => {}
110 span_err
!(self.sess
, arg
.pat
.span
, E0022
,
111 "arguments of constant functions can only \
112 be immutable by-value bindings");
116 check_block(&self.sess
, b
, "const function");