]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/check_const.rs
core: Fix size_hint for signed integer Range<T> iterators
[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 an owned pointer
17 //
18 // - For each *immutable* static item, it checks that its **value**:
19 //       - doesn't own owned, managed pointers
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::const_eval;
28 use middle::def;
29 use middle::expr_use_visitor as euv;
30 use middle::infer;
31 use middle::mem_categorization as mc;
32 use middle::traits;
33 use middle::ty::{self, Ty};
34 use util::nodemap::NodeMap;
35 use util::ppaux;
36
37 use syntax::ast;
38 use syntax::codemap::Span;
39 use syntax::print::pprust;
40 use syntax::visit::{self, Visitor};
41
42 use std::collections::hash_map::Entry;
43
44 // Const qualification, from partial to completely promotable.
45 bitflags! {
46     #[derive(RustcEncodable, RustcDecodable)]
47     flags ConstQualif: u8 {
48         // Const rvalue which can be placed behind a reference.
49         const PURE_CONST          = 0b000000,
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         = 0b000001,
53         // Constant value with a type that implements Drop. Can be copied
54         // from static memory, similar to MUTABLE_MEM.
55         const NEEDS_DROP          = 0b000010,
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     = 0b000100,
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      = 0b001000,
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  = 0b010000,
69         // Invalid const for miscellaneous reasons (e.g. not implemented).
70         const NOT_CONST           = 0b100000,
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 = MUTABLE_MEM.bits | NEEDS_DROP.bits | NOT_CONST.bits
76     }
77 }
78
79 #[derive(Copy, Clone, Eq, PartialEq)]
80 enum Mode {
81     Const,
82     Static,
83     StaticMut,
84
85     // An expression that occurs outside of any constant context
86     // (i.e. `const`, `static`, array lengths, etc.). The value
87     // can be variable at runtime, but will be promotable to
88     // static memory if we can prove it is actually constant.
89     Var,
90 }
91
92 struct CheckCrateVisitor<'a, 'tcx: 'a> {
93     tcx: &'a ty::ctxt<'tcx>,
94     mode: Mode,
95     qualif: ConstQualif,
96     rvalue_borrows: NodeMap<ast::Mutability>
97 }
98
99 impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
100     fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R where
101         F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>) -> R,
102     {
103         let (old_mode, old_qualif) = (self.mode, self.qualif);
104         self.mode = mode;
105         self.qualif = PURE_CONST;
106         let r = f(self);
107         self.mode = old_mode;
108         self.qualif = old_qualif;
109         r
110     }
111
112     fn with_euv<'b, F, R>(&'b mut self, item_id: Option<ast::NodeId>, f: F) -> R where
113         F: for<'t> FnOnce(&mut euv::ExprUseVisitor<'b, 't, 'tcx,
114                                     ty::ParameterEnvironment<'a, 'tcx>>) -> R,
115     {
116         let param_env = match item_id {
117             Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
118             None => ty::empty_parameter_environment(self.tcx)
119         };
120         f(&mut euv::ExprUseVisitor::new(self, &param_env))
121     }
122
123     fn global_expr(&mut self, mode: Mode, expr: &ast::Expr) -> ConstQualif {
124         assert!(mode != Mode::Var);
125         match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) {
126             Entry::Occupied(entry) => return *entry.get(),
127             Entry::Vacant(entry) => {
128                 // Prevent infinite recursion on re-entry.
129                 entry.insert(PURE_CONST);
130             }
131         }
132         self.with_mode(mode, |this| {
133             this.with_euv(None, |euv| euv.consume_expr(expr));
134             this.visit_expr(expr);
135             this.qualif
136         })
137     }
138
139     fn add_qualif(&mut self, qualif: ConstQualif) {
140         self.qualif = self.qualif | qualif;
141     }
142
143     fn record_borrow(&mut self, id: ast::NodeId, mutbl: ast::Mutability) {
144         match self.rvalue_borrows.entry(id) {
145             Entry::Occupied(mut entry) => {
146                 // Merge the two borrows, taking the most demanding
147                 // one, mutability-wise.
148                 if mutbl == ast::MutMutable {
149                     entry.insert(mutbl);
150                 }
151             }
152             Entry::Vacant(entry) => {
153                 entry.insert(mutbl);
154             }
155         }
156     }
157
158     fn msg(&self) -> &'static str {
159         match self.mode {
160             Mode::Const => "constant",
161             Mode::StaticMut | Mode::Static => "static",
162             Mode::Var => unreachable!(),
163         }
164     }
165
166     fn check_static_mut_type(&self, e: &ast::Expr) {
167         let node_ty = ty::node_id_to_type(self.tcx, e.id);
168         let tcontents = ty::type_contents(self.tcx, node_ty);
169
170         let suffix = if tcontents.has_dtor() {
171             "destructors"
172         } else if tcontents.owns_owned() {
173             "owned pointers"
174         } else {
175             return
176         };
177
178         self.tcx.sess.span_err(e.span, &format!("mutable statics are not allowed \
179                                                  to have {}", suffix));
180     }
181
182     fn check_static_type(&self, e: &ast::Expr) {
183         let ty = ty::node_id_to_type(self.tcx, e.id);
184         let infcx = infer::new_infer_ctxt(self.tcx);
185         let mut fulfill_cx = traits::FulfillmentContext::new();
186         let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic);
187         fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause);
188         let env = ty::empty_parameter_environment(self.tcx);
189         match fulfill_cx.select_all_or_error(&infcx, &env) {
190             Ok(()) => { },
191             Err(ref errors) => {
192                 traits::report_fulfillment_errors(&infcx, errors);
193             }
194         }
195     }
196 }
197
198 impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
199     fn visit_item(&mut self, i: &ast::Item) {
200         debug!("visit_item(item={})", pprust::item_to_string(i));
201         match i.node {
202             ast::ItemStatic(_, ast::MutImmutable, ref expr) => {
203                 self.check_static_type(&**expr);
204                 self.global_expr(Mode::Static, &**expr);
205             }
206             ast::ItemStatic(_, ast::MutMutable, ref expr) => {
207                 self.check_static_mut_type(&**expr);
208                 self.global_expr(Mode::StaticMut, &**expr);
209             }
210             ast::ItemConst(_, ref expr) => {
211                 self.global_expr(Mode::Const, &**expr);
212             }
213             ast::ItemEnum(ref enum_definition, _) => {
214                 for var in &enum_definition.variants {
215                     if let Some(ref ex) = var.node.disr_expr {
216                         self.global_expr(Mode::Const, &**ex);
217                     }
218                 }
219             }
220             _ => {
221                 self.with_mode(Mode::Var, |v| visit::walk_item(v, i));
222             }
223         }
224     }
225
226     fn visit_fn(&mut self,
227                 fk: visit::FnKind<'v>,
228                 fd: &'v ast::FnDecl,
229                 b: &'v ast::Block,
230                 s: Span,
231                 fn_id: ast::NodeId) {
232         assert!(self.mode == Mode::Var);
233         self.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, b));
234         visit::walk_fn(self, fk, fd, b, s);
235     }
236
237     fn visit_pat(&mut self, p: &ast::Pat) {
238         match p.node {
239             ast::PatLit(ref lit) => {
240                 self.global_expr(Mode::Const, &**lit);
241             }
242             ast::PatRange(ref start, ref end) => {
243                 self.global_expr(Mode::Const, &**start);
244                 self.global_expr(Mode::Const, &**end);
245             }
246             _ => visit::walk_pat(self, p)
247         }
248     }
249
250     fn visit_expr(&mut self, ex: &ast::Expr) {
251         let mut outer = self.qualif;
252         self.qualif = PURE_CONST;
253
254         let node_ty = ty::node_id_to_type(self.tcx, ex.id);
255         check_expr(self, ex, node_ty);
256
257         // Special-case some expressions to avoid certain flags bubbling up.
258         match ex.node {
259             ast::ExprCall(ref callee, ref args) => {
260                 for arg in args.iter() {
261                     self.visit_expr(&**arg)
262                 }
263
264                 let inner = self.qualif;
265                 self.visit_expr(&**callee);
266                 // The callee's size doesn't count in the call.
267                 let added = self.qualif - inner;
268                 self.qualif = inner | (added - NON_ZERO_SIZED);
269             }
270             ast::ExprRepeat(ref element, _) => {
271                 self.visit_expr(&**element);
272                 // The count is checked elsewhere (typeck).
273                 let count = match node_ty.sty {
274                     ty::ty_vec(_, Some(n)) => n,
275                     _ => unreachable!()
276                 };
277                 // [element; 0] is always zero-sized.
278                 if count == 0 {
279                     self.qualif = self.qualif - (NON_ZERO_SIZED | PREFER_IN_PLACE);
280                 }
281             }
282             ast::ExprMatch(ref discr, ref arms, _) => {
283                 // Compute the most demanding borrow from all the arms'
284                 // patterns and set that on the discriminator.
285                 let mut borrow = None;
286                 for pat in arms.iter().flat_map(|arm| arm.pats.iter()) {
287                     let pat_borrow = self.rvalue_borrows.remove(&pat.id);
288                     match (borrow, pat_borrow) {
289                         (None, _) | (_, Some(ast::MutMutable)) => {
290                             borrow = pat_borrow;
291                         }
292                         _ => {}
293                     }
294                 }
295                 if let Some(mutbl) = borrow {
296                     self.record_borrow(discr.id, mutbl);
297                 }
298                 visit::walk_expr(self, ex);
299             }
300             // Division by zero and overflow checking.
301             ast::ExprBinary(op, _, _) => {
302                 visit::walk_expr(self, ex);
303                 let div_or_rem = op.node == ast::BiDiv || op.node == ast::BiRem;
304                 match node_ty.sty {
305                     ty::ty_uint(_) | ty::ty_int(_) if div_or_rem => {
306                         if !self.qualif.intersects(NOT_CONST) {
307                             match const_eval::eval_const_expr_partial(self.tcx, ex, None) {
308                                 Ok(_) => {}
309                                 Err(msg) => {
310                                     span_err!(self.tcx.sess, msg.span, E0020,
311                                               "{} in a constant expression",
312                                               msg.description())
313                                 }
314                             }
315                         }
316                     }
317                     _ => {}
318                 }
319             }
320             _ => visit::walk_expr(self, ex)
321         }
322
323         // Handle borrows on (or inside the autorefs of) this expression.
324         match self.rvalue_borrows.remove(&ex.id) {
325             Some(ast::MutImmutable) => {
326                 // Constants cannot be borrowed if they contain interior mutability as
327                 // it means that our "silent insertion of statics" could change
328                 // initializer values (very bad).
329                 // If the type doesn't have interior mutability, then `MUTABLE_MEM` has
330                 // propagated from another error, so erroring again would be just noise.
331                 let tc = ty::type_contents(self.tcx, node_ty);
332                 if self.qualif.intersects(MUTABLE_MEM) && tc.interior_unsafe() {
333                     outer = outer | NOT_CONST;
334                     if self.mode != Mode::Var {
335                         self.tcx.sess.span_err(ex.span,
336                             "cannot borrow a constant which contains \
337                              interior mutability, create a static instead");
338                     }
339                 }
340                 // If the reference has to be 'static, avoid in-place initialization
341                 // as that will end up pointing to the stack instead.
342                 if !self.qualif.intersects(NON_STATIC_BORROWS) {
343                     self.qualif = self.qualif - PREFER_IN_PLACE;
344                     self.add_qualif(HAS_STATIC_BORROWS);
345                 }
346             }
347             Some(ast::MutMutable) => {
348                 // `&mut expr` means expr could be mutated, unless it's zero-sized.
349                 if self.qualif.intersects(NON_ZERO_SIZED) {
350                     if self.mode == Mode::Var {
351                         outer = outer | NOT_CONST;
352                         self.add_qualif(MUTABLE_MEM);
353                     } else {
354                         span_err!(self.tcx.sess, ex.span, E0017,
355                             "references in {}s may only refer \
356                              to immutable values", self.msg())
357                     }
358                 }
359                 if !self.qualif.intersects(NON_STATIC_BORROWS) {
360                     self.add_qualif(HAS_STATIC_BORROWS);
361                 }
362             }
363             None => {}
364         }
365         self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
366         // Don't propagate certain flags.
367         self.qualif = outer | (self.qualif - HAS_STATIC_BORROWS);
368     }
369 }
370
371 /// This function is used to enforce the constraints on
372 /// const/static items. It walks through the *value*
373 /// of the item walking down the expression and evaluating
374 /// every nested expression. If the expression is not part
375 /// of a const/static item, it is qualified for promotion
376 /// instead of producing errors.
377 fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
378                         e: &ast::Expr, node_ty: Ty<'tcx>) {
379     match node_ty.sty {
380         ty::ty_struct(did, _) |
381         ty::ty_enum(did, _) if ty::has_dtor(v.tcx, did) => {
382             v.add_qualif(NEEDS_DROP);
383             if v.mode != Mode::Var {
384                 v.tcx.sess.span_err(e.span,
385                                     &format!("{}s are not allowed to have destructors",
386                                              v.msg()));
387             }
388         }
389         _ => {}
390     }
391
392     let method_call = ty::MethodCall::expr(e.id);
393     match e.node {
394         ast::ExprUnary(..) |
395         ast::ExprBinary(..) |
396         ast::ExprIndex(..) if v.tcx.method_map.borrow().contains_key(&method_call) => {
397             v.add_qualif(NOT_CONST);
398             if v.mode != Mode::Var {
399                 span_err!(v.tcx.sess, e.span, E0011,
400                             "user-defined operators are not allowed in {}s", v.msg());
401             }
402         }
403         ast::ExprBox(..) |
404         ast::ExprUnary(ast::UnUniq, _) => {
405             v.add_qualif(NOT_CONST);
406             if v.mode != Mode::Var {
407                 span_err!(v.tcx.sess, e.span, E0010,
408                           "allocations are not allowed in {}s", v.msg());
409             }
410         }
411         ast::ExprUnary(ast::UnDeref, ref ptr) => {
412             match ty::node_id_to_type(v.tcx, ptr.id).sty {
413                 ty::ty_ptr(_) => {
414                     // This shouldn't be allowed in constants at all.
415                     v.add_qualif(NOT_CONST);
416                 }
417                 _ => {}
418             }
419         }
420         ast::ExprCast(ref from, _) => {
421             let toty = ty::expr_ty(v.tcx, e);
422             let fromty = ty::expr_ty(v.tcx, &**from);
423             let is_legal_cast =
424                 ty::type_is_numeric(toty) ||
425                 ty::type_is_unsafe_ptr(toty) ||
426                 (ty::type_is_bare_fn(toty) && ty::type_is_bare_fn_item(fromty));
427             if !is_legal_cast {
428                 v.add_qualif(NOT_CONST);
429                 if v.mode != Mode::Var {
430                     span_err!(v.tcx.sess, e.span, E0012,
431                               "can not cast to `{}` in {}s",
432                               ppaux::ty_to_string(v.tcx, toty), v.msg());
433                 }
434             }
435             if ty::type_is_unsafe_ptr(fromty) && ty::type_is_numeric(toty) {
436                 v.add_qualif(NOT_CONST);
437                 if v.mode != Mode::Var {
438                     span_err!(v.tcx.sess, e.span, E0018,
439                               "can not cast a pointer to an integer in {}s", v.msg());
440                 }
441             }
442         }
443         ast::ExprPath(..) => {
444             let def = v.tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
445             match def {
446                 Some(def::DefVariant(_, _, _)) => {
447                     // Count the discriminator or function pointer.
448                     v.add_qualif(NON_ZERO_SIZED);
449                 }
450                 Some(def::DefStruct(_)) => {
451                     if let ty::ty_bare_fn(..) = node_ty.sty {
452                         // Count the function pointer.
453                         v.add_qualif(NON_ZERO_SIZED);
454                     }
455                 }
456                 Some(def::DefFn(..)) | Some(def::DefMethod(..)) => {
457                     // Count the function pointer.
458                     v.add_qualif(NON_ZERO_SIZED);
459                 }
460                 Some(def::DefStatic(..)) => {
461                     match v.mode {
462                         Mode::Static | Mode::StaticMut => {}
463                         Mode::Const => {
464                             span_err!(v.tcx.sess, e.span, E0013,
465                                 "constants cannot refer to other statics, \
466                                  insert an intermediate constant instead");
467                         }
468                         Mode::Var => v.add_qualif(NOT_CONST)
469                     }
470                 }
471                 Some(def::DefConst(did)) => {
472                     if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did) {
473                         let inner = v.global_expr(Mode::Const, expr);
474                         v.add_qualif(inner);
475                     } else {
476                         v.tcx.sess.span_bug(e.span, "DefConst doesn't point \
477                                                      to an ItemConst");
478                     }
479                 }
480                 def => {
481                     v.add_qualif(NOT_CONST);
482                     if v.mode != Mode::Var {
483                         debug!("(checking const) found bad def: {:?}", def);
484                         span_err!(v.tcx.sess, e.span, E0014,
485                                   "paths in {}s may only refer to constants \
486                                    or functions", v.msg());
487                     }
488                 }
489             }
490         }
491         ast::ExprCall(ref callee, _) => {
492             let mut callee = &**callee;
493             loop {
494                 callee = match callee.node {
495                     ast::ExprParen(ref inner) => &**inner,
496                     ast::ExprBlock(ref block) => match block.expr {
497                         Some(ref tail) => &**tail,
498                         None => break
499                     },
500                     _ => break
501                 };
502             }
503             let def = v.tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def());
504             match def {
505                 Some(def::DefStruct(..)) => {}
506                 Some(def::DefVariant(..)) => {
507                     // Count the discriminator.
508                     v.add_qualif(NON_ZERO_SIZED);
509                 }
510                 _ => {
511                     v.add_qualif(NOT_CONST);
512                     if v.mode != Mode::Var {
513                         span_err!(v.tcx.sess, e.span, E0015,
514                                   "function calls in {}s are limited to \
515                                    struct and enum constructors", v.msg());
516                     }
517                 }
518             }
519         }
520         ast::ExprBlock(ref block) => {
521             // Check all statements in the block
522             let mut block_span_err = |span| {
523                 v.add_qualif(NOT_CONST);
524                 if v.mode != Mode::Var {
525                     span_err!(v.tcx.sess, span, E0016,
526                               "blocks in {}s are limited to items and \
527                                tail expressions", v.msg());
528                 }
529             };
530             for stmt in &block.stmts {
531                 match stmt.node {
532                     ast::StmtDecl(ref decl, _) => {
533                         match decl.node {
534                             ast::DeclLocal(_) => block_span_err(decl.span),
535
536                             // Item statements are allowed
537                             ast::DeclItem(_) => {}
538                         }
539                     }
540                     ast::StmtExpr(ref expr, _) => block_span_err(expr.span),
541                     ast::StmtSemi(ref semi, _) => block_span_err(semi.span),
542                     ast::StmtMac(..) => {
543                         v.tcx.sess.span_bug(e.span, "unexpanded statement \
544                                                      macro in const?!")
545                     }
546                 }
547             }
548         }
549         ast::ExprStruct(..) => {
550             let did = v.tcx.def_map.borrow().get(&e.id).map(|def| def.def_id());
551             if did == v.tcx.lang_items.unsafe_cell_type() {
552                 v.add_qualif(MUTABLE_MEM);
553             }
554         }
555
556         ast::ExprLit(_) |
557         ast::ExprAddrOf(..) => {
558             v.add_qualif(NON_ZERO_SIZED);
559         }
560
561         ast::ExprRepeat(..) => {
562             v.add_qualif(PREFER_IN_PLACE);
563         }
564
565         ast::ExprClosure(..) => {
566             // Paths in constant constexts cannot refer to local variables,
567             // as there are none, and thus closures can't have upvars there.
568             if ty::with_freevars(v.tcx, e.id, |fv| !fv.is_empty()) {
569                 assert!(v.mode == Mode::Var,
570                         "global closures can't capture anything");
571                 v.add_qualif(NOT_CONST);
572             }
573         }
574
575         ast::ExprUnary(..) |
576         ast::ExprBinary(..) |
577         ast::ExprIndex(..) |
578         ast::ExprField(..) |
579         ast::ExprTupField(..) |
580         ast::ExprVec(_) |
581         ast::ExprParen(..) |
582         ast::ExprTup(..) => {}
583
584         // Conditional control flow (possible to implement).
585         ast::ExprMatch(..) |
586         ast::ExprIf(..) |
587         ast::ExprIfLet(..) |
588
589         // Loops (not very meaningful in constants).
590         ast::ExprWhile(..) |
591         ast::ExprWhileLet(..) |
592         ast::ExprForLoop(..) |
593         ast::ExprLoop(..) |
594
595         // More control flow (also not very meaningful).
596         ast::ExprBreak(_) |
597         ast::ExprAgain(_) |
598         ast::ExprRet(_) |
599
600         // Miscellaneous expressions that could be implemented.
601         ast::ExprRange(..) |
602
603         // Various other expressions.
604         ast::ExprMethodCall(..) |
605         ast::ExprAssign(..) |
606         ast::ExprAssignOp(..) |
607         ast::ExprInlineAsm(_) |
608         ast::ExprMac(_) => {
609             v.add_qualif(NOT_CONST);
610             if v.mode != Mode::Var {
611                 span_err!(v.tcx.sess, e.span, E0019,
612                           "{} contains unimplemented expression type", v.msg());
613             }
614         }
615     }
616 }
617
618 pub fn check_crate(tcx: &ty::ctxt) {
619     visit::walk_crate(&mut CheckCrateVisitor {
620         tcx: tcx,
621         mode: Mode::Var,
622         qualif: NOT_CONST,
623         rvalue_borrows: NodeMap()
624     }, tcx.map.krate());
625
626     tcx.sess.abort_if_errors();
627 }
628
629 impl<'a, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'tcx> {
630     fn consume(&mut self,
631                _consume_id: ast::NodeId,
632                consume_span: Span,
633                cmt: mc::cmt,
634                _mode: euv::ConsumeMode) {
635         let mut cur = &cmt;
636         loop {
637             match cur.cat {
638                 mc::cat_static_item => {
639                     if self.mode != Mode::Var {
640                         // statics cannot be consumed by value at any time, that would imply
641                         // that they're an initializer (what a const is for) or kept in sync
642                         // over time (not feasible), so deny it outright.
643                         self.tcx.sess.span_err(consume_span,
644                             "cannot refer to other statics by value, use the \
645                              address-of operator or a constant instead");
646                     }
647                     break;
648                 }
649                 mc::cat_deref(ref cmt, _, _) |
650                 mc::cat_downcast(ref cmt, _) |
651                 mc::cat_interior(ref cmt, _) => cur = cmt,
652
653                 mc::cat_rvalue(..) |
654                 mc::cat_upvar(..) |
655                 mc::cat_local(..) => break
656             }
657         }
658     }
659     fn borrow(&mut self,
660               borrow_id: ast::NodeId,
661               borrow_span: Span,
662               cmt: mc::cmt<'tcx>,
663               _loan_region: ty::Region,
664               bk: ty::BorrowKind,
665               loan_cause: euv::LoanCause)
666     {
667         // Kind of hacky, but we allow Unsafe coercions in constants.
668         // These occur when we convert a &T or *T to a *U, as well as
669         // when making a thin pointer (e.g., `*T`) into a fat pointer
670         // (e.g., `*Trait`).
671         match loan_cause {
672             euv::LoanCause::AutoUnsafe => {
673                 return;
674             }
675             _ => { }
676         }
677
678         let mut cur = &cmt;
679         let mut is_interior = false;
680         loop {
681             match cur.cat {
682                 mc::cat_rvalue(..) => {
683                     if loan_cause == euv::MatchDiscriminant {
684                         // Ignore the dummy immutable borrow created by EUV.
685                         break;
686                     }
687                     let mutbl = bk.to_mutbl_lossy();
688                     if mutbl == ast::MutMutable && self.mode == Mode::StaticMut {
689                         // Mutable slices are the only `&mut` allowed in globals,
690                         // but only in `static mut`, nowhere else.
691                         match cmt.ty.sty {
692                             ty::ty_vec(_, _) => break,
693                             _ => {}
694                         }
695                     }
696                     self.record_borrow(borrow_id, mutbl);
697                     break;
698                 }
699                 mc::cat_static_item => {
700                     if is_interior && self.mode != Mode::Var {
701                         // Borrowed statics can specifically *only* have their address taken,
702                         // not any number of other borrows such as borrowing fields, reading
703                         // elements of an array, etc.
704                         self.tcx.sess.span_err(borrow_span,
705                             "cannot refer to the interior of another \
706                              static, use a constant instead");
707                     }
708                     break;
709                 }
710                 mc::cat_deref(ref cmt, _, _) |
711                 mc::cat_downcast(ref cmt, _) |
712                 mc::cat_interior(ref cmt, _) => {
713                     is_interior = true;
714                     cur = cmt;
715                 }
716
717                 mc::cat_upvar(..) |
718                 mc::cat_local(..) => break
719             }
720         }
721     }
722
723     fn decl_without_init(&mut self,
724                          _id: ast::NodeId,
725                          _span: Span) {}
726     fn mutate(&mut self,
727               _assignment_id: ast::NodeId,
728               _assignment_span: Span,
729               _assignee_cmt: mc::cmt,
730               _mode: euv::MutateMode) {}
731
732     fn matched_pat(&mut self,
733                    _: &ast::Pat,
734                    _: mc::cmt,
735                    _: euv::MatchMode) {}
736
737     fn consume_pat(&mut self,
738                    _consume_pat: &ast::Pat,
739                    _cmt: mc::cmt,
740                    _mode: euv::ConsumeMode) {}
741 }