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