1 // Copyright 2012-2013 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.
17 use syntax
::visit
::{self, Visitor}
;
19 struct CheckCrateVisitor
<'a
, 'tcx
: 'a
> {
20 tcx
: &'a ty
::ctxt
<'tcx
>,
24 impl<'a
, 'tcx
> CheckCrateVisitor
<'a
, 'tcx
> {
25 fn with_const
<F
>(&mut self, in_const
: bool
, f
: F
) where
26 F
: FnOnce(&mut CheckCrateVisitor
<'a
, 'tcx
>),
28 let was_const
= self.in_const
;
29 self.in_const
= in_const
;
31 self.in_const
= was_const
;
33 fn inside_const
<F
>(&mut self, f
: F
) where
34 F
: FnOnce(&mut CheckCrateVisitor
<'a
, 'tcx
>),
36 self.with_const(true, f
);
40 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for CheckCrateVisitor
<'a
, 'tcx
> {
41 fn visit_item(&mut self, i
: &ast
::Item
) {
43 ast
::ItemStatic(_
, _
, ref ex
) |
44 ast
::ItemConst(_
, ref ex
) => {
45 self.inside_const(|v
| v
.visit_expr(&**ex
));
47 ast
::ItemEnum(ref enum_definition
, _
) => {
48 self.inside_const(|v
| {
49 for var
in enum_definition
.variants
.iter() {
50 if let Some(ref ex
) = var
.node
.disr_expr
{
56 _
=> self.with_const(false, |v
| visit
::walk_item(v
, i
))
59 fn visit_pat(&mut self, p
: &ast
::Pat
) {
60 let is_const
= match p
.node
{
61 ast
::PatLit(_
) | ast
::PatRange(..) => true,
64 self.with_const(is_const
, |v
| visit
::walk_pat(v
, p
))
66 fn visit_expr(&mut self, ex
: &ast
::Expr
) {
70 visit
::walk_expr(self, ex
);
74 pub fn check_crate(tcx
: &ty
::ctxt
) {
75 visit
::walk_crate(&mut CheckCrateVisitor { tcx: tcx, in_const: false }
,
77 tcx
.sess
.abort_if_errors();
80 fn check_expr(v
: &mut CheckCrateVisitor
, e
: &ast
::Expr
) {
82 ast
::ExprUnary(ast
::UnDeref
, _
) => {}
83 ast
::ExprUnary(ast
::UnUniq
, _
) => {
84 span_err
!(v
.tcx
.sess
, e
.span
, E0010
,
85 "cannot do allocations in constant expressions");
87 ast
::ExprBinary(..) | ast
::ExprUnary(..) => {
88 let method_call
= ty
::MethodCall
::expr(e
.id
);
89 if v
.tcx
.method_map
.borrow().contains_key(&method_call
) {
90 span_err
!(v
.tcx
.sess
, e
.span
, E0011
,
91 "user-defined operators are not allowed in constant \
96 ast
::ExprCast(ref from
, _
) => {
97 let toty
= ty
::expr_ty(v
.tcx
, e
);
98 let fromty
= ty
::expr_ty(v
.tcx
, &**from
);
100 ty
::type_is_numeric(toty
) ||
101 ty
::type_is_unsafe_ptr(toty
) ||
102 (ty
::type_is_bare_fn(toty
) && ty
::type_is_bare_fn_item(fromty
));
104 span_err
!(v
.tcx
.sess
, e
.span
, E0012
,
105 "can not cast to `{}` in a constant expression",
106 ppaux
::ty_to_string(v
.tcx
, toty
));
108 if ty
::type_is_unsafe_ptr(fromty
) && ty
::type_is_numeric(toty
) {
109 span_err
!(v
.tcx
.sess
, e
.span
, E0018
,
110 "can not cast a pointer to an integer in a constant \
114 ast
::ExprPath(_
) => {
115 match v
.tcx
.def_map
.borrow()[e
.id
] {
116 DefStatic(..) | DefConst(..) |
117 DefFn(..) | DefStaticMethod(..) | DefMethod(..) |
118 DefStruct(_
) | DefVariant(_
, _
, _
) => {}
121 debug
!("(checking const) found bad def: {:?}", def
);
122 span_err
!(v
.tcx
.sess
, e
.span
, E0014
,
123 "paths in constants may only refer to constants \
128 ast
::ExprCall(ref callee
, _
) => {
129 match v
.tcx
.def_map
.borrow()[callee
.id
] {
130 DefStruct(..) | DefVariant(..) => {}
// OK.
132 span_err
!(v
.tcx
.sess
, e
.span
, E0015
,
133 "function calls in constants are limited to \
134 struct and enum constructors");
138 ast
::ExprBlock(ref block
) => {
139 // Check all statements in the block
140 for stmt
in block
.stmts
.iter() {
141 let block_span_err
= |&: span
|
142 span_err
!(v
.tcx
.sess
, span
, E0016
,
143 "blocks in constants are limited to items and \
146 ast
::StmtDecl(ref decl
, _
) => {
148 ast
::DeclLocal(_
) => block_span_err(decl
.span
),
150 // Item statements are allowed
151 ast
::DeclItem(_
) => {}
154 ast
::StmtExpr(ref expr
, _
) => block_span_err(expr
.span
),
155 ast
::StmtSemi(ref semi
, _
) => block_span_err(semi
.span
),
156 ast
::StmtMac(..) => {
157 v
.tcx
.sess
.span_bug(e
.span
, "unexpanded statement \
164 ast
::ExprAddrOf(ast
::MutImmutable
, _
) |
167 ast
::ExprTupField(..) |
170 ast
::ExprRepeat(..) |
171 ast
::ExprStruct(..) => {}
173 ast
::ExprAddrOf(_
, ref inner
) => {
175 // Mutable slices are allowed.
176 ast
::ExprVec(_
) => {}
177 _
=> span_err
!(v
.tcx
.sess
, e
.span
, E0017
,
178 "references in constants may only refer \
179 to immutable values")
184 _
=> span_err
!(v
.tcx
.sess
, e
.span
, E0019
,
185 "constant contains unimplemented expression type")