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")