]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/check_const.rs
Auto merge of #27981 - dotdash:gepi, r=brson
[rust.git] / src / librustc / middle / check_const.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 the types and values of const and static items
12 // are safe. The rules enforced by this module are:
13 //
14 // - For each *mutable* static item, it checks that its **type**:
15 //     - doesn't have a destructor
16 //     - doesn't own a box
17 //
18 // - For each *immutable* static item, it checks that its **value**:
19 //       - doesn't own a box
20 //       - doesn't contain a struct literal or a call to an enum variant / struct constructor where
21 //           - the type of the struct/enum has a dtor
22 //
23 // Rules Enforced Elsewhere:
24 // - It's not possible to take the address of a static item with unsafe interior. This is enforced
25 // by borrowck::gather_loans
26
27 use middle::cast::{CastKind};
28 use middle::const_eval;
29 use middle::const_eval::EvalHint::ExprTypeChecked;
30 use middle::def;
31 use middle::def_id::DefId;
32 use middle::expr_use_visitor as euv;
33 use middle::infer;
34 use middle::mem_categorization as mc;
35 use middle::traits;
36 use middle::ty::{self, Ty};
37 use util::nodemap::NodeMap;
38
39 use syntax::ast;
40 use syntax::codemap::Span;
41 use syntax::visit::{self, Visitor};
42
43 use std::collections::hash_map::Entry;
44 use std::cmp::Ordering;
45
46 // Const qualification, from partial to completely promotable.
47 bitflags! {
48     #[derive(RustcEncodable, RustcDecodable)]
49     flags ConstQualif: u8 {
50         // Inner mutability (can not be placed behind a reference) or behind
51         // &mut in a non-global expression. Can be copied from static memory.
52         const MUTABLE_MEM        = 1 << 0,
53         // Constant value with a type that implements Drop. Can be copied
54         // from static memory, similar to MUTABLE_MEM.
55         const NEEDS_DROP         = 1 << 1,
56         // Even if the value can be placed in static memory, copying it from
57         // there is more expensive than in-place instantiation, and/or it may
58         // be too large. This applies to [T; N] and everything containing it.
59         // N.B.: references need to clear this flag to not end up on the stack.
60         const PREFER_IN_PLACE    = 1 << 2,
61         // May use more than 0 bytes of memory, doesn't impact the constness
62         // directly, but is not allowed to be borrowed mutably in a constant.
63         const NON_ZERO_SIZED     = 1 << 3,
64         // Actually borrowed, has to always be in static memory. Does not
65         // propagate, and requires the expression to behave like a 'static
66         // lvalue. The set of expressions with this flag is the minimum
67         // that have to be promoted.
68         const HAS_STATIC_BORROWS = 1 << 4,
69         // Invalid const for miscellaneous reasons (e.g. not implemented).
70         const NOT_CONST          = 1 << 5,
71
72         // Borrowing the expression won't produce &'static T if any of these
73         // bits are set, though the value could be copied from static memory
74         // if `NOT_CONST` isn't set.
75         const NON_STATIC_BORROWS = ConstQualif::MUTABLE_MEM.bits |
76                                    ConstQualif::NEEDS_DROP.bits |
77                                    ConstQualif::NOT_CONST.bits
78     }
79 }
80
81 #[derive(Copy, Clone, Eq, PartialEq)]
82 enum Mode {
83     Const,
84     ConstFn,
85     Static,
86     StaticMut,
87
88     // An expression that occurs outside of any constant context
89     // (i.e. `const`, `static`, array lengths, etc.). The value
90     // can be variable at runtime, but will be promotable to
91     // static memory if we can prove it is actually constant.
92     Var,
93 }
94
95 struct CheckCrateVisitor<'a, 'tcx: 'a> {
96     tcx: &'a ty::ctxt<'tcx>,
97     mode: Mode,
98     qualif: ConstQualif,
99     rvalue_borrows: NodeMap<ast::Mutability>
100 }
101
102 impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
103     fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R where
104         F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>) -> R,
105     {
106         let (old_mode, old_qualif) = (self.mode, self.qualif);
107         self.mode = mode;
108         self.qualif = ConstQualif::empty();
109         let r = f(self);
110         self.mode = old_mode;
111         self.qualif = old_qualif;
112         r
113     }
114
115     fn with_euv<'b, F, R>(&'b mut self, item_id: Option<ast::NodeId>, f: F) -> R where
116         F: for<'t> FnOnce(&mut euv::ExprUseVisitor<'b, 't, 'b, 'tcx>) -> R,
117     {
118         let param_env = match item_id {
119             Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
120             None => self.tcx.empty_parameter_environment()
121         };
122
123         let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env), false);
124
125         f(&mut euv::ExprUseVisitor::new(self, &infcx))
126     }
127
128     fn global_expr(&mut self, mode: Mode, expr: &ast::Expr) -> ConstQualif {
129         assert!(mode != Mode::Var);
130         match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) {
131             Entry::Occupied(entry) => return *entry.get(),
132             Entry::Vacant(entry) => {
133                 // Prevent infinite recursion on re-entry.
134                 entry.insert(ConstQualif::empty());
135             }
136         }
137         self.with_mode(mode, |this| {
138             this.with_euv(None, |euv| euv.consume_expr(expr));
139             this.visit_expr(expr);
140             this.qualif
141         })
142     }
143
144     fn fn_like(&mut self,
145                fk: visit::FnKind,
146                fd: &ast::FnDecl,
147                b: &ast::Block,
148                s: Span,
149                fn_id: ast::NodeId)
150                -> ConstQualif {
151         match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) {
152             Entry::Occupied(entry) => return *entry.get(),
153             Entry::Vacant(entry) => {
154                 // Prevent infinite recursion on re-entry.
155                 entry.insert(ConstQualif::empty());
156             }
157         }
158
159         let mode = match fk {
160             visit::FkItemFn(_, _, _, ast::Constness::Const, _, _) => {
161                 Mode::ConstFn
162             }
163             visit::FkMethod(_, m, _) => {
164                 if m.constness == ast::Constness::Const {
165                     Mode::ConstFn
166                 } else {
167                     Mode::Var
168                 }
169             }
170             _ => Mode::Var
171         };
172
173         // Ensure the arguments are simple, not mutable/by-ref or patterns.
174         if mode == Mode::ConstFn {
175             for arg in &fd.inputs {
176                 match arg.pat.node {
177                     ast::PatIdent(ast::BindByValue(ast::MutImmutable), _, None) => {}
178                     _ => {
179                         span_err!(self.tcx.sess, arg.pat.span, E0022,
180                                   "arguments of constant functions can only \
181                                    be immutable by-value bindings");
182                     }
183                 }
184             }
185         }
186
187         let qualif = self.with_mode(mode, |this| {
188             this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
189             visit::walk_fn(this, fk, fd, b, s);
190             this.qualif
191         });
192
193         // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
194         // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
195         let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
196
197         self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
198         qualif
199     }
200
201     fn add_qualif(&mut self, qualif: ConstQualif) {
202         self.qualif = self.qualif | qualif;
203     }
204
205     /// Returns true if the call is to a const fn or method.
206     fn handle_const_fn_call(&mut self,
207                             expr: &ast::Expr,
208                             def_id: DefId,
209                             ret_ty: Ty<'tcx>)
210                             -> bool {
211         if let Some(fn_like) = const_eval::lookup_const_fn_by_id(self.tcx, def_id) {
212             if
213                 // we are in a static/const initializer
214                 self.mode != Mode::Var &&
215
216                 // feature-gate is not enabled
217                 !self.tcx.sess.features.borrow().const_fn &&
218
219                 // this doesn't come from a macro that has #[allow_internal_unstable]
220                 !self.tcx.sess.codemap().span_allows_unstable(expr.span)
221             {
222                 self.tcx.sess.span_err(
223                     expr.span,
224                     &format!("const fns are an unstable feature"));
225                 fileline_help!(
226                     self.tcx.sess,
227                     expr.span,
228                     "in Nightly builds, add `#![feature(const_fn)]` to the crate \
229                      attributes to enable");
230             }
231
232             let qualif = self.fn_like(fn_like.kind(),
233                                       fn_like.decl(),
234                                       fn_like.body(),
235                                       fn_like.span(),
236                                       fn_like.id());
237             self.add_qualif(qualif);
238
239             if ret_ty.type_contents(self.tcx).interior_unsafe() {
240                 self.add_qualif(ConstQualif::MUTABLE_MEM);
241             }
242
243             true
244         } else {
245             false
246         }
247     }
248
249     fn record_borrow(&mut self, id: ast::NodeId, mutbl: ast::Mutability) {
250         match self.rvalue_borrows.entry(id) {
251             Entry::Occupied(mut entry) => {
252                 // Merge the two borrows, taking the most demanding
253                 // one, mutability-wise.
254                 if mutbl == ast::MutMutable {
255                     entry.insert(mutbl);
256                 }
257             }
258             Entry::Vacant(entry) => {
259                 entry.insert(mutbl);
260             }
261         }
262     }
263
264     fn msg(&self) -> &'static str {
265         match self.mode {
266             Mode::Const => "constant",
267             Mode::ConstFn => "constant function",
268             Mode::StaticMut | Mode::Static => "static",
269             Mode::Var => unreachable!(),
270         }
271     }
272
273     fn check_static_mut_type(&self, e: &ast::Expr) {
274         let node_ty = self.tcx.node_id_to_type(e.id);
275         let tcontents = node_ty.type_contents(self.tcx);
276
277         let suffix = if tcontents.has_dtor() {
278             "destructors"
279         } else if tcontents.owns_owned() {
280             "boxes"
281         } else {
282             return
283         };
284
285         span_err!(self.tcx.sess, e.span, E0397,
286                  "mutable statics are not allowed to have {}", suffix);
287     }
288
289     fn check_static_type(&self, e: &ast::Expr) {
290         let ty = self.tcx.node_id_to_type(e.id);
291         let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None, false);
292         let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
293         let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();
294         fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
295         match fulfill_cx.select_all_or_error(&infcx) {
296             Ok(()) => { },
297             Err(ref errors) => {
298                 traits::report_fulfillment_errors(&infcx, errors);
299             }
300         }
301     }
302 }
303
304 impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
305     fn visit_item(&mut self, i: &ast::Item) {
306         debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
307         match i.node {
308             ast::ItemStatic(_, ast::MutImmutable, ref expr) => {
309                 self.check_static_type(&**expr);
310                 self.global_expr(Mode::Static, &**expr);
311             }
312             ast::ItemStatic(_, ast::MutMutable, ref expr) => {
313                 self.check_static_mut_type(&**expr);
314                 self.global_expr(Mode::StaticMut, &**expr);
315             }
316             ast::ItemConst(_, ref expr) => {
317                 self.global_expr(Mode::Const, &**expr);
318             }
319             ast::ItemEnum(ref enum_definition, _) => {
320                 for var in &enum_definition.variants {
321                     if let Some(ref ex) = var.node.disr_expr {
322                         self.global_expr(Mode::Const, &**ex);
323                     }
324                 }
325             }
326             _ => {
327                 self.with_mode(Mode::Var, |v| visit::walk_item(v, i));
328             }
329         }
330     }
331
332     fn visit_trait_item(&mut self, t: &'v ast::TraitItem) {
333         match t.node {
334             ast::ConstTraitItem(_, ref default) => {
335                 if let Some(ref expr) = *default {
336                     self.global_expr(Mode::Const, &*expr);
337                 } else {
338                     visit::walk_trait_item(self, t);
339                 }
340             }
341             _ => self.with_mode(Mode::Var, |v| visit::walk_trait_item(v, t)),
342         }
343     }
344
345     fn visit_impl_item(&mut self, i: &'v ast::ImplItem) {
346         match i.node {
347             ast::ConstImplItem(_, ref expr) => {
348                 self.global_expr(Mode::Const, &*expr);
349             }
350             _ => self.with_mode(Mode::Var, |v| visit::walk_impl_item(v, i)),
351         }
352     }
353
354     fn visit_fn(&mut self,
355                 fk: visit::FnKind<'v>,
356                 fd: &'v ast::FnDecl,
357                 b: &'v ast::Block,
358                 s: Span,
359                 fn_id: ast::NodeId) {
360         self.fn_like(fk, fd, b, s, fn_id);
361     }
362
363     fn visit_pat(&mut self, p: &ast::Pat) {
364         match p.node {
365             ast::PatLit(ref lit) => {
366                 self.global_expr(Mode::Const, &**lit);
367             }
368             ast::PatRange(ref start, ref end) => {
369                 self.global_expr(Mode::Const, &**start);
370                 self.global_expr(Mode::Const, &**end);
371
372                 match const_eval::compare_lit_exprs(self.tcx, start, end) {
373                     Some(Ordering::Less) |
374                     Some(Ordering::Equal) => {}
375                     Some(Ordering::Greater) => {
376                         span_err!(self.tcx.sess, start.span, E0030,
377                             "lower range bound must be less than or equal to upper");
378                     }
379                     None => {
380                         self.tcx.sess.span_bug(
381                             start.span, "literals of different types in range pat");
382                     }
383                 }
384             }
385             _ => visit::walk_pat(self, p)
386         }
387     }
388
389     fn visit_block(&mut self, block: &ast::Block) {
390         // Check all statements in the block
391         for stmt in &block.stmts {
392             let span = match stmt.node {
393                 ast::StmtDecl(ref decl, _) => {
394                     match decl.node {
395                         ast::DeclLocal(_) => decl.span,
396
397                         // Item statements are allowed
398                         ast::DeclItem(_) => continue
399                     }
400                 }
401                 ast::StmtExpr(ref expr, _) => expr.span,
402                 ast::StmtSemi(ref semi, _) => semi.span,
403                 ast::StmtMac(..) => {
404                     self.tcx.sess.span_bug(stmt.span, "unexpanded statement \
405                                                        macro in const?!")
406                 }
407             };
408             self.add_qualif(ConstQualif::NOT_CONST);
409             if self.mode != Mode::Var {
410                 span_err!(self.tcx.sess, span, E0016,
411                           "blocks in {}s are limited to items and \
412                            tail expressions", self.msg());
413             }
414         }
415         visit::walk_block(self, block);
416     }
417
418     fn visit_expr(&mut self, ex: &ast::Expr) {
419         let mut outer = self.qualif;
420         self.qualif = ConstQualif::empty();
421
422         let node_ty = self.tcx.node_id_to_type(ex.id);
423         check_expr(self, ex, node_ty);
424         check_adjustments(self, ex);
425
426         // Special-case some expressions to avoid certain flags bubbling up.
427         match ex.node {
428             ast::ExprCall(ref callee, ref args) => {
429                 for arg in args {
430                     self.visit_expr(&**arg)
431                 }
432
433                 let inner = self.qualif;
434                 self.visit_expr(&**callee);
435                 // The callee's size doesn't count in the call.
436                 let added = self.qualif - inner;
437                 self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
438             }
439             ast::ExprRepeat(ref element, _) => {
440                 self.visit_expr(&**element);
441                 // The count is checked elsewhere (typeck).
442                 let count = match node_ty.sty {
443                     ty::TyArray(_, n) => n,
444                     _ => unreachable!()
445                 };
446                 // [element; 0] is always zero-sized.
447                 if count == 0 {
448                     self.qualif.remove(ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
449                 }
450             }
451             ast::ExprMatch(ref discr, ref arms, _) => {
452                 // Compute the most demanding borrow from all the arms'
453                 // patterns and set that on the discriminator.
454                 let mut borrow = None;
455                 for pat in arms.iter().flat_map(|arm| &arm.pats) {
456                     let pat_borrow = self.rvalue_borrows.remove(&pat.id);
457                     match (borrow, pat_borrow) {
458                         (None, _) | (_, Some(ast::MutMutable)) => {
459                             borrow = pat_borrow;
460                         }
461                         _ => {}
462                     }
463                 }
464                 if let Some(mutbl) = borrow {
465                     self.record_borrow(discr.id, mutbl);
466                 }
467                 visit::walk_expr(self, ex);
468             }
469             // Division by zero and overflow checking.
470             ast::ExprBinary(op, _, _) => {
471                 visit::walk_expr(self, ex);
472                 let div_or_rem = op.node == ast::BiDiv || op.node == ast::BiRem;
473                 match node_ty.sty {
474                     ty::TyUint(_) | ty::TyInt(_) if div_or_rem => {
475                         if !self.qualif.intersects(ConstQualif::NOT_CONST) {
476                             match const_eval::eval_const_expr_partial(
477                                     self.tcx, ex, ExprTypeChecked) {
478                                 Ok(_) => {}
479                                 Err(msg) => {
480                                     span_err!(self.tcx.sess, msg.span, E0020,
481                                               "{} in a constant expression",
482                                               msg.description())
483                                 }
484                             }
485                         }
486                     }
487                     _ => {}
488                 }
489             }
490             _ => visit::walk_expr(self, ex)
491         }
492
493         // Handle borrows on (or inside the autorefs of) this expression.
494         match self.rvalue_borrows.remove(&ex.id) {
495             Some(ast::MutImmutable) => {
496                 // Constants cannot be borrowed if they contain interior mutability as
497                 // it means that our "silent insertion of statics" could change
498                 // initializer values (very bad).
499                 // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
500                 // propagated from another error, so erroring again would be just noise.
501                 let tc = node_ty.type_contents(self.tcx);
502                 if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
503                     outer = outer | ConstQualif::NOT_CONST;
504                     if self.mode != Mode::Var {
505                         self.tcx.sess.span_err(ex.span,
506                             "cannot borrow a constant which contains \
507                              interior mutability, create a static instead");
508                     }
509                 }
510                 // If the reference has to be 'static, avoid in-place initialization
511                 // as that will end up pointing to the stack instead.
512                 if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
513                     self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
514                     self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
515                 }
516             }
517             Some(ast::MutMutable) => {
518                 // `&mut expr` means expr could be mutated, unless it's zero-sized.
519                 if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) {
520                     if self.mode == Mode::Var {
521                         outer = outer | ConstQualif::NOT_CONST;
522                         self.add_qualif(ConstQualif::MUTABLE_MEM);
523                     } else {
524                         span_err!(self.tcx.sess, ex.span, E0017,
525                             "references in {}s may only refer \
526                              to immutable values", self.msg())
527                     }
528                 }
529                 if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
530                     self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
531                 }
532             }
533             None => {}
534         }
535         self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
536         // Don't propagate certain flags.
537         self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
538     }
539 }
540
541 /// This function is used to enforce the constraints on
542 /// const/static items. It walks through the *value*
543 /// of the item walking down the expression and evaluating
544 /// every nested expression. If the expression is not part
545 /// of a const/static item, it is qualified for promotion
546 /// instead of producing errors.
547 fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
548                         e: &ast::Expr, node_ty: Ty<'tcx>) {
549     match node_ty.sty {
550         ty::TyStruct(def, _) |
551         ty::TyEnum(def, _) if def.has_dtor(v.tcx) => {
552             v.add_qualif(ConstQualif::NEEDS_DROP);
553             if v.mode != Mode::Var {
554                 v.tcx.sess.span_err(e.span,
555                                     &format!("{}s are not allowed to have destructors",
556                                              v.msg()));
557             }
558         }
559         _ => {}
560     }
561
562     let method_call = ty::MethodCall::expr(e.id);
563     match e.node {
564         ast::ExprUnary(..) |
565         ast::ExprBinary(..) |
566         ast::ExprIndex(..) if v.tcx.tables.borrow().method_map.contains_key(&method_call) => {
567             v.add_qualif(ConstQualif::NOT_CONST);
568             if v.mode != Mode::Var {
569                 span_err!(v.tcx.sess, e.span, E0011,
570                             "user-defined operators are not allowed in {}s", v.msg());
571             }
572         }
573         ast::ExprBox(..) |
574         ast::ExprUnary(ast::UnUniq, _) => {
575             v.add_qualif(ConstQualif::NOT_CONST);
576             if v.mode != Mode::Var {
577                 span_err!(v.tcx.sess, e.span, E0010,
578                           "allocations are not allowed in {}s", v.msg());
579             }
580         }
581         ast::ExprUnary(op, ref inner) => {
582             match v.tcx.node_id_to_type(inner.id).sty {
583                 ty::TyRawPtr(_) => {
584                     assert!(op == ast::UnDeref);
585
586                     v.add_qualif(ConstQualif::NOT_CONST);
587                     if v.mode != Mode::Var {
588                         span_err!(v.tcx.sess, e.span, E0396,
589                                   "raw pointers cannot be dereferenced in {}s", v.msg());
590                     }
591                 }
592                 _ => {}
593             }
594         }
595         ast::ExprBinary(op, ref lhs, _) => {
596             match v.tcx.node_id_to_type(lhs.id).sty {
597                 ty::TyRawPtr(_) => {
598                     assert!(op.node == ast::BiEq || op.node == ast::BiNe ||
599                             op.node == ast::BiLe || op.node == ast::BiLt ||
600                             op.node == ast::BiGe || op.node == ast::BiGt);
601
602                     v.add_qualif(ConstQualif::NOT_CONST);
603                     if v.mode != Mode::Var {
604                         span_err!(v.tcx.sess, e.span, E0395,
605                                   "raw pointers cannot be compared in {}s", v.msg());
606                     }
607                 }
608                 _ => {}
609             }
610         }
611         ast::ExprCast(ref from, _) => {
612             debug!("Checking const cast(id={})", from.id);
613             match v.tcx.cast_kinds.borrow().get(&from.id) {
614                 None => v.tcx.sess.span_bug(e.span, "no kind for cast"),
615                 Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
616                     v.add_qualif(ConstQualif::NOT_CONST);
617                     if v.mode != Mode::Var {
618                         span_err!(v.tcx.sess, e.span, E0018,
619                                   "raw pointers cannot be cast to integers in {}s", v.msg());
620                     }
621                 }
622                 _ => {}
623             }
624         }
625         ast::ExprPath(..) => {
626             let def = v.tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
627             match def {
628                 Some(def::DefVariant(_, _, _)) => {
629                     // Count the discriminator or function pointer.
630                     v.add_qualif(ConstQualif::NON_ZERO_SIZED);
631                 }
632                 Some(def::DefStruct(_)) => {
633                     if let ty::TyBareFn(..) = node_ty.sty {
634                         // Count the function pointer.
635                         v.add_qualif(ConstQualif::NON_ZERO_SIZED);
636                     }
637                 }
638                 Some(def::DefFn(..)) | Some(def::DefMethod(..)) => {
639                     // Count the function pointer.
640                     v.add_qualif(ConstQualif::NON_ZERO_SIZED);
641                 }
642                 Some(def::DefStatic(..)) => {
643                     match v.mode {
644                         Mode::Static | Mode::StaticMut => {}
645                         Mode::Const | Mode::ConstFn => {
646                             span_err!(v.tcx.sess, e.span, E0013,
647                                 "{}s cannot refer to other statics, insert \
648                                  an intermediate constant instead", v.msg());
649                         }
650                         Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
651                     }
652                 }
653                 Some(def::DefConst(did)) |
654                 Some(def::DefAssociatedConst(did)) => {
655                     if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
656                                                                        Some(e.id)) {
657                         let inner = v.global_expr(Mode::Const, expr);
658                         v.add_qualif(inner);
659                     } else {
660                         v.tcx.sess.span_bug(e.span,
661                                             "DefConst or DefAssociatedConst \
662                                              doesn't point to a constant");
663                     }
664                 }
665                 Some(def::DefLocal(_)) if v.mode == Mode::ConstFn => {
666                     // Sadly, we can't determine whether the types are zero-sized.
667                     v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
668                 }
669                 def => {
670                     v.add_qualif(ConstQualif::NOT_CONST);
671                     if v.mode != Mode::Var {
672                         debug!("(checking const) found bad def: {:?}", def);
673                         span_err!(v.tcx.sess, e.span, E0014,
674                                   "paths in {}s may only refer to constants \
675                                    or functions", v.msg());
676                     }
677                 }
678             }
679         }
680         ast::ExprCall(ref callee, _) => {
681             let mut callee = &**callee;
682             loop {
683                 callee = match callee.node {
684                     ast::ExprParen(ref inner) => &**inner,
685                     ast::ExprBlock(ref block) => match block.expr {
686                         Some(ref tail) => &**tail,
687                         None => break
688                     },
689                     _ => break
690                 };
691             }
692             let def = v.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def());
693             let is_const = match def {
694                 Some(def::DefStruct(..)) => true,
695                 Some(def::DefVariant(..)) => {
696                     // Count the discriminator.
697                     v.add_qualif(ConstQualif::NON_ZERO_SIZED);
698                     true
699                 }
700                 Some(def::DefFn(did, _)) => {
701                     v.handle_const_fn_call(e, did, node_ty)
702                 }
703                 Some(def::DefMethod(did)) => {
704                     match v.tcx.impl_or_trait_item(did).container() {
705                         ty::ImplContainer(_) => {
706                             v.handle_const_fn_call(e, did, node_ty)
707                         }
708                         ty::TraitContainer(_) => false
709                     }
710                 }
711                 _ => false
712             };
713             if !is_const {
714                 v.add_qualif(ConstQualif::NOT_CONST);
715                 if v.mode != Mode::Var {
716                     span_err!(v.tcx.sess, e.span, E0015,
717                               "function calls in {}s are limited to \
718                                constant functions, \
719                                struct and enum constructors", v.msg());
720                 }
721             }
722         }
723         ast::ExprMethodCall(..) => {
724             let method = v.tcx.tables.borrow().method_map[&method_call];
725             let is_const = match v.tcx.impl_or_trait_item(method.def_id).container() {
726                 ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
727                 ty::TraitContainer(_) => false
728             };
729             if !is_const {
730                 v.add_qualif(ConstQualif::NOT_CONST);
731                 if v.mode != Mode::Var {
732                     span_err!(v.tcx.sess, e.span, E0378,
733                               "method calls in {}s are limited to \
734                                constant inherent methods", v.msg());
735                 }
736             }
737         }
738         ast::ExprStruct(..) => {
739             let did = v.tcx.def_map.borrow().get(&e.id).map(|def| def.def_id());
740             if did == v.tcx.lang_items.unsafe_cell_type() {
741                 v.add_qualif(ConstQualif::MUTABLE_MEM);
742             }
743         }
744
745         ast::ExprLit(_) |
746         ast::ExprAddrOf(..) => {
747             v.add_qualif(ConstQualif::NON_ZERO_SIZED);
748         }
749
750         ast::ExprRepeat(..) => {
751             v.add_qualif(ConstQualif::PREFER_IN_PLACE);
752         }
753
754         ast::ExprClosure(..) => {
755             // Paths in constant contexts cannot refer to local variables,
756             // as there are none, and thus closures can't have upvars there.
757             if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) {
758                 assert!(v.mode == Mode::Var,
759                         "global closures can't capture anything");
760                 v.add_qualif(ConstQualif::NOT_CONST);
761             }
762         }
763
764         ast::ExprBlock(_) |
765         ast::ExprIndex(..) |
766         ast::ExprField(..) |
767         ast::ExprTupField(..) |
768         ast::ExprVec(_) |
769         ast::ExprParen(..) |
770         ast::ExprTup(..) => {}
771
772         // Conditional control flow (possible to implement).
773         ast::ExprMatch(..) |
774         ast::ExprIf(..) |
775         ast::ExprIfLet(..) |
776
777         // Loops (not very meaningful in constants).
778         ast::ExprWhile(..) |
779         ast::ExprWhileLet(..) |
780         ast::ExprForLoop(..) |
781         ast::ExprLoop(..) |
782
783         // More control flow (also not very meaningful).
784         ast::ExprBreak(_) |
785         ast::ExprAgain(_) |
786         ast::ExprRet(_) |
787
788         // Miscellaneous expressions that could be implemented.
789         ast::ExprRange(..) |
790
791         // Expressions with side-effects.
792         ast::ExprAssign(..) |
793         ast::ExprAssignOp(..) |
794         ast::ExprInlineAsm(_) |
795         ast::ExprMac(_) => {
796             v.add_qualif(ConstQualif::NOT_CONST);
797             if v.mode != Mode::Var {
798                 span_err!(v.tcx.sess, e.span, E0019,
799                           "{} contains unimplemented expression type", v.msg());
800             }
801         }
802     }
803 }
804
805 /// Check the adjustments of an expression
806 fn check_adjustments<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &ast::Expr) {
807     match v.tcx.tables.borrow().adjustments.get(&e.id) {
808         None | Some(&ty::AdjustReifyFnPointer) | Some(&ty::AdjustUnsafeFnPointer) => {}
809         Some(&ty::AdjustDerefRef(ty::AutoDerefRef { autoderefs, .. })) => {
810             if (0..autoderefs as u32).any(|autoderef| {
811                     v.tcx.is_overloaded_autoderef(e.id, autoderef)
812             }) {
813                 v.add_qualif(ConstQualif::NOT_CONST);
814                 if v.mode != Mode::Var {
815                     span_err!(v.tcx.sess, e.span, E0400,
816                               "user-defined dereference operators are not allowed in {}s",
817                               v.msg());
818                 }
819             }
820         }
821     }
822 }
823
824 pub fn check_crate(tcx: &ty::ctxt) {
825     visit::walk_crate(&mut CheckCrateVisitor {
826         tcx: tcx,
827         mode: Mode::Var,
828         qualif: ConstQualif::NOT_CONST,
829         rvalue_borrows: NodeMap()
830     }, tcx.map.krate());
831
832     tcx.sess.abort_if_errors();
833 }
834
835 impl<'a, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'tcx> {
836     fn consume(&mut self,
837                _consume_id: ast::NodeId,
838                consume_span: Span,
839                cmt: mc::cmt,
840                _mode: euv::ConsumeMode) {
841         let mut cur = &cmt;
842         loop {
843             match cur.cat {
844                 mc::cat_static_item => {
845                     if self.mode != Mode::Var {
846                         // statics cannot be consumed by value at any time, that would imply
847                         // that they're an initializer (what a const is for) or kept in sync
848                         // over time (not feasible), so deny it outright.
849                         span_err!(self.tcx.sess, consume_span, E0394,
850                                   "cannot refer to other statics by value, use the \
851                                    address-of operator or a constant instead");
852                     }
853                     break;
854                 }
855                 mc::cat_deref(ref cmt, _, _) |
856                 mc::cat_downcast(ref cmt, _) |
857                 mc::cat_interior(ref cmt, _) => cur = cmt,
858
859                 mc::cat_rvalue(..) |
860                 mc::cat_upvar(..) |
861                 mc::cat_local(..) => break
862             }
863         }
864     }
865     fn borrow(&mut self,
866               borrow_id: ast::NodeId,
867               borrow_span: Span,
868               cmt: mc::cmt<'tcx>,
869               _loan_region: ty::Region,
870               bk: ty::BorrowKind,
871               loan_cause: euv::LoanCause)
872     {
873         // Kind of hacky, but we allow Unsafe coercions in constants.
874         // These occur when we convert a &T or *T to a *U, as well as
875         // when making a thin pointer (e.g., `*T`) into a fat pointer
876         // (e.g., `*Trait`).
877         match loan_cause {
878             euv::LoanCause::AutoUnsafe => {
879                 return;
880             }
881             _ => { }
882         }
883
884         let mut cur = &cmt;
885         let mut is_interior = false;
886         loop {
887             match cur.cat {
888                 mc::cat_rvalue(..) => {
889                     if loan_cause == euv::MatchDiscriminant {
890                         // Ignore the dummy immutable borrow created by EUV.
891                         break;
892                     }
893                     let mutbl = bk.to_mutbl_lossy();
894                     if mutbl == ast::MutMutable && self.mode == Mode::StaticMut {
895                         // Mutable slices are the only `&mut` allowed in
896                         // globals, but only in `static mut`, nowhere else.
897                         // FIXME: This exception is really weird... there isn't
898                         // any fundamental reason to restrict this based on
899                         // type of the expression.  `&mut [1]` has exactly the
900                         // same representation as &mut 1.
901                         match cmt.ty.sty {
902                             ty::TyArray(_, _) | ty::TySlice(_) => break,
903                             _ => {}
904                         }
905                     }
906                     self.record_borrow(borrow_id, mutbl);
907                     break;
908                 }
909                 mc::cat_static_item => {
910                     if is_interior && self.mode != Mode::Var {
911                         // Borrowed statics can specifically *only* have their address taken,
912                         // not any number of other borrows such as borrowing fields, reading
913                         // elements of an array, etc.
914                         self.tcx.sess.span_err(borrow_span,
915                             "cannot refer to the interior of another \
916                              static, use a constant instead");
917                     }
918                     break;
919                 }
920                 mc::cat_deref(ref cmt, _, _) |
921                 mc::cat_downcast(ref cmt, _) |
922                 mc::cat_interior(ref cmt, _) => {
923                     is_interior = true;
924                     cur = cmt;
925                 }
926
927                 mc::cat_upvar(..) |
928                 mc::cat_local(..) => break
929             }
930         }
931     }
932
933     fn decl_without_init(&mut self,
934                          _id: ast::NodeId,
935                          _span: Span) {}
936     fn mutate(&mut self,
937               _assignment_id: ast::NodeId,
938               _assignment_span: Span,
939               _assignee_cmt: mc::cmt,
940               _mode: euv::MutateMode) {}
941
942     fn matched_pat(&mut self,
943                    _: &ast::Pat,
944                    _: mc::cmt,
945                    _: euv::MatchMode) {}
946
947     fn consume_pat(&mut self,
948                    _consume_pat: &ast::Pat,
949                    _cmt: mc::cmt,
950                    _mode: euv::ConsumeMode) {}
951 }