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.
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.
11 // Verifies that the types and values of const and static items
12 // are safe. The rules enforced by this module are:
14 // - For each *mutable* static item, it checks that its **type**:
15 // - doesn't have a destructor
16 // - doesn't own a box
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
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
27 use middle
::cast
::{CastKind}
;
28 use middle
::const_eval
;
29 use middle
::const_eval
::EvalHint
::ExprTypeChecked
;
31 use middle
::expr_use_visitor
as euv
;
33 use middle
::mem_categorization
as mc
;
35 use middle
::ty
::{self, Ty}
;
36 use util
::nodemap
::NodeMap
;
39 use syntax
::codemap
::Span
;
40 use syntax
::visit
::{self, Visitor}
;
42 use std
::collections
::hash_map
::Entry
;
43 use std
::cmp
::Ordering
;
45 // Const qualification, from partial to completely promotable.
47 #[derive(RustcEncodable, RustcDecodable)]
48 flags ConstQualif
: u8 {
49 // Inner mutability (can not be placed behind a reference) or behind
50 // &mut in a non-global expression. Can be copied from static memory.
51 const MUTABLE_MEM
= 1 << 0,
52 // Constant value with a type that implements Drop. Can be copied
53 // from static memory, similar to MUTABLE_MEM.
54 const NEEDS_DROP
= 1 << 1,
55 // Even if the value can be placed in static memory, copying it from
56 // there is more expensive than in-place instantiation, and/or it may
57 // be too large. This applies to [T; N] and everything containing it.
58 // N.B.: references need to clear this flag to not end up on the stack.
59 const PREFER_IN_PLACE
= 1 << 2,
60 // May use more than 0 bytes of memory, doesn't impact the constness
61 // directly, but is not allowed to be borrowed mutably in a constant.
62 const NON_ZERO_SIZED
= 1 << 3,
63 // Actually borrowed, has to always be in static memory. Does not
64 // propagate, and requires the expression to behave like a 'static
65 // lvalue. The set of expressions with this flag is the minimum
66 // that have to be promoted.
67 const HAS_STATIC_BORROWS
= 1 << 4,
68 // Invalid const for miscellaneous reasons (e.g. not implemented).
69 const NOT_CONST
= 1 << 5,
71 // Borrowing the expression won't produce &'static T if any of these
72 // bits are set, though the value could be copied from static memory
73 // if `NOT_CONST` isn't set.
74 const NON_STATIC_BORROWS
= ConstQualif
::MUTABLE_MEM
.bits
|
75 ConstQualif
::NEEDS_DROP
.bits
|
76 ConstQualif
::NOT_CONST
.bits
80 #[derive(Copy, Clone, Eq, PartialEq)]
87 // An expression that occurs outside of any constant context
88 // (i.e. `const`, `static`, array lengths, etc.). The value
89 // can be variable at runtime, but will be promotable to
90 // static memory if we can prove it is actually constant.
94 struct CheckCrateVisitor
<'a
, 'tcx
: 'a
> {
95 tcx
: &'a ty
::ctxt
<'tcx
>,
98 rvalue_borrows
: NodeMap
<ast
::Mutability
>
101 impl<'a
, 'tcx
> CheckCrateVisitor
<'a
, 'tcx
> {
102 fn with_mode
<F
, R
>(&mut self, mode
: Mode
, f
: F
) -> R
where
103 F
: FnOnce(&mut CheckCrateVisitor
<'a
, 'tcx
>) -> R
,
105 let (old_mode
, old_qualif
) = (self.mode
, self.qualif
);
107 self.qualif
= ConstQualif
::empty();
109 self.mode
= old_mode
;
110 self.qualif
= old_qualif
;
114 fn with_euv
<'b
, F
, R
>(&'b
mut self, item_id
: Option
<ast
::NodeId
>, f
: F
) -> R
where
115 F
: for<'t
> FnOnce(&mut euv
::ExprUseVisitor
<'b
, 't
, 'b
, 'tcx
>) -> R
,
117 let param_env
= match item_id
{
118 Some(item_id
) => ty
::ParameterEnvironment
::for_item(self.tcx
, item_id
),
119 None
=> self.tcx
.empty_parameter_environment()
122 let infcx
= infer
::new_infer_ctxt(self.tcx
, &self.tcx
.tables
, Some(param_env
), false);
124 f(&mut euv
::ExprUseVisitor
::new(self, &infcx
))
127 fn global_expr(&mut self, mode
: Mode
, expr
: &ast
::Expr
) -> ConstQualif
{
128 assert
!(mode
!= Mode
::Var
);
129 match self.tcx
.const_qualif_map
.borrow_mut().entry(expr
.id
) {
130 Entry
::Occupied(entry
) => return *entry
.get(),
131 Entry
::Vacant(entry
) => {
132 // Prevent infinite recursion on re-entry.
133 entry
.insert(ConstQualif
::empty());
136 self.with_mode(mode
, |this
| {
137 this
.with_euv(None
, |euv
| euv
.consume_expr(expr
));
138 this
.visit_expr(expr
);
143 fn fn_like(&mut self,
150 match self.tcx
.const_qualif_map
.borrow_mut().entry(fn_id
) {
151 Entry
::Occupied(entry
) => return *entry
.get(),
152 Entry
::Vacant(entry
) => {
153 // Prevent infinite recursion on re-entry.
154 entry
.insert(ConstQualif
::empty());
158 let mode
= match fk
{
159 visit
::FkItemFn(_
, _
, _
, ast
::Constness
::Const
, _
, _
) => {
162 visit
::FkMethod(_
, m
, _
) => {
163 if m
.constness
== ast
::Constness
::Const
{
172 // Ensure the arguments are simple, not mutable/by-ref or patterns.
173 if mode
== Mode
::ConstFn
{
174 for arg
in &fd
.inputs
{
176 ast
::PatIdent(ast
::BindByValue(ast
::MutImmutable
), _
, None
) => {}
178 span_err
!(self.tcx
.sess
, arg
.pat
.span
, E0022
,
179 "arguments of constant functions can only \
180 be immutable by-value bindings");
186 let qualif
= self.with_mode(mode
, |this
| {
187 this
.with_euv(Some(fn_id
), |euv
| euv
.walk_fn(fd
, b
));
188 visit
::walk_fn(this
, fk
, fd
, b
, s
);
192 // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
193 // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
194 let qualif
= qualif
& (ConstQualif
::NON_ZERO_SIZED
| ConstQualif
::PREFER_IN_PLACE
);
196 self.tcx
.const_qualif_map
.borrow_mut().insert(fn_id
, qualif
);
200 fn add_qualif(&mut self, qualif
: ConstQualif
) {
201 self.qualif
= self.qualif
| qualif
;
204 /// Returns true if the call is to a const fn or method.
205 fn handle_const_fn_call(&mut self,
210 if let Some(fn_like
) = const_eval
::lookup_const_fn_by_id(self.tcx
, def_id
) {
212 // we are in a static/const initializer
213 self.mode
!= Mode
::Var
&&
215 // feature-gate is not enabled
216 !self.tcx
.sess
.features
.borrow().const_fn
&&
218 // this doesn't come from a macro that has #[allow_internal_unstable]
219 !self.tcx
.sess
.codemap().span_allows_unstable(expr
.span
)
221 self.tcx
.sess
.span_err(
223 &format
!("const fns are an unstable feature"));
227 "in Nightly builds, add `#![feature(const_fn)]` to the crate \
228 attributes to enable");
231 let qualif
= self.fn_like(fn_like
.kind(),
236 self.add_qualif(qualif
);
238 if ret_ty
.type_contents(self.tcx
).interior_unsafe() {
239 self.add_qualif(ConstQualif
::MUTABLE_MEM
);
248 fn record_borrow(&mut self, id
: ast
::NodeId
, mutbl
: ast
::Mutability
) {
249 match self.rvalue_borrows
.entry(id
) {
250 Entry
::Occupied(mut entry
) => {
251 // Merge the two borrows, taking the most demanding
252 // one, mutability-wise.
253 if mutbl
== ast
::MutMutable
{
257 Entry
::Vacant(entry
) => {
263 fn msg(&self) -> &'
static str {
265 Mode
::Const
=> "constant",
266 Mode
::ConstFn
=> "constant function",
267 Mode
::StaticMut
| Mode
::Static
=> "static",
268 Mode
::Var
=> unreachable
!(),
272 fn check_static_mut_type(&self, e
: &ast
::Expr
) {
273 let node_ty
= self.tcx
.node_id_to_type(e
.id
);
274 let tcontents
= node_ty
.type_contents(self.tcx
);
276 let suffix
= if tcontents
.has_dtor() {
278 } else if tcontents
.owns_owned() {
284 span_err
!(self.tcx
.sess
, e
.span
, E0397
,
285 "mutable statics are not allowed to have {}", suffix
);
288 fn check_static_type(&self, e
: &ast
::Expr
) {
289 let ty
= self.tcx
.node_id_to_type(e
.id
);
290 let infcx
= infer
::new_infer_ctxt(self.tcx
, &self.tcx
.tables
, None
, false);
291 let cause
= traits
::ObligationCause
::new(e
.span
, e
.id
, traits
::SharedStatic
);
292 let mut fulfill_cx
= infcx
.fulfillment_cx
.borrow_mut();
293 fulfill_cx
.register_builtin_bound(&infcx
, ty
, ty
::BoundSync
, cause
);
294 match fulfill_cx
.select_all_or_error(&infcx
) {
297 traits
::report_fulfillment_errors(&infcx
, errors
);
303 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for CheckCrateVisitor
<'a
, 'tcx
> {
304 fn visit_item(&mut self, i
: &ast
::Item
) {
305 debug
!("visit_item(item={})", self.tcx
.map
.node_to_string(i
.id
));
307 ast
::ItemStatic(_
, ast
::MutImmutable
, ref expr
) => {
308 self.check_static_type(&**expr
);
309 self.global_expr(Mode
::Static
, &**expr
);
311 ast
::ItemStatic(_
, ast
::MutMutable
, ref expr
) => {
312 self.check_static_mut_type(&**expr
);
313 self.global_expr(Mode
::StaticMut
, &**expr
);
315 ast
::ItemConst(_
, ref expr
) => {
316 self.global_expr(Mode
::Const
, &**expr
);
318 ast
::ItemEnum(ref enum_definition
, _
) => {
319 for var
in &enum_definition
.variants
{
320 if let Some(ref ex
) = var
.node
.disr_expr
{
321 self.global_expr(Mode
::Const
, &**ex
);
326 self.with_mode(Mode
::Var
, |v
| visit
::walk_item(v
, i
));
331 fn visit_trait_item(&mut self, t
: &'v ast
::TraitItem
) {
333 ast
::ConstTraitItem(_
, ref default) => {
334 if let Some(ref expr
) = *default {
335 self.global_expr(Mode
::Const
, &*expr
);
337 visit
::walk_trait_item(self, t
);
340 _
=> self.with_mode(Mode
::Var
, |v
| visit
::walk_trait_item(v
, t
)),
344 fn visit_impl_item(&mut self, i
: &'v ast
::ImplItem
) {
346 ast
::ConstImplItem(_
, ref expr
) => {
347 self.global_expr(Mode
::Const
, &*expr
);
349 _
=> self.with_mode(Mode
::Var
, |v
| visit
::walk_impl_item(v
, i
)),
353 fn visit_fn(&mut self,
354 fk
: visit
::FnKind
<'v
>,
358 fn_id
: ast
::NodeId
) {
359 self.fn_like(fk
, fd
, b
, s
, fn_id
);
362 fn visit_pat(&mut self, p
: &ast
::Pat
) {
364 ast
::PatLit(ref lit
) => {
365 self.global_expr(Mode
::Const
, &**lit
);
367 ast
::PatRange(ref start
, ref end
) => {
368 self.global_expr(Mode
::Const
, &**start
);
369 self.global_expr(Mode
::Const
, &**end
);
371 match const_eval
::compare_lit_exprs(self.tcx
, start
, end
) {
372 Some(Ordering
::Less
) |
373 Some(Ordering
::Equal
) => {}
374 Some(Ordering
::Greater
) => {
375 span_err
!(self.tcx
.sess
, start
.span
, E0030
,
376 "lower range bound must be less than or equal to upper");
379 self.tcx
.sess
.span_bug(
380 start
.span
, "literals of different types in range pat");
384 _
=> visit
::walk_pat(self, p
)
388 fn visit_block(&mut self, block
: &ast
::Block
) {
389 // Check all statements in the block
390 for stmt
in &block
.stmts
{
391 let span
= match stmt
.node
{
392 ast
::StmtDecl(ref decl
, _
) => {
394 ast
::DeclLocal(_
) => decl
.span
,
396 // Item statements are allowed
397 ast
::DeclItem(_
) => continue
400 ast
::StmtExpr(ref expr
, _
) => expr
.span
,
401 ast
::StmtSemi(ref semi
, _
) => semi
.span
,
402 ast
::StmtMac(..) => {
403 self.tcx
.sess
.span_bug(stmt
.span
, "unexpanded statement \
407 self.add_qualif(ConstQualif
::NOT_CONST
);
408 if self.mode
!= Mode
::Var
{
409 span_err
!(self.tcx
.sess
, span
, E0016
,
410 "blocks in {}s are limited to items and \
411 tail expressions", self.msg());
414 visit
::walk_block(self, block
);
417 fn visit_expr(&mut self, ex
: &ast
::Expr
) {
418 let mut outer
= self.qualif
;
419 self.qualif
= ConstQualif
::empty();
421 let node_ty
= self.tcx
.node_id_to_type(ex
.id
);
422 check_expr(self, ex
, node_ty
);
423 check_adjustments(self, ex
);
425 // Special-case some expressions to avoid certain flags bubbling up.
427 ast
::ExprCall(ref callee
, ref args
) => {
429 self.visit_expr(&**arg
)
432 let inner
= self.qualif
;
433 self.visit_expr(&**callee
);
434 // The callee's size doesn't count in the call.
435 let added
= self.qualif
- inner
;
436 self.qualif
= inner
| (added
- ConstQualif
::NON_ZERO_SIZED
);
438 ast
::ExprRepeat(ref element
, _
) => {
439 self.visit_expr(&**element
);
440 // The count is checked elsewhere (typeck).
441 let count
= match node_ty
.sty
{
442 ty
::TyArray(_
, n
) => n
,
445 // [element; 0] is always zero-sized.
447 self.qualif
.remove(ConstQualif
::NON_ZERO_SIZED
| ConstQualif
::PREFER_IN_PLACE
);
450 ast
::ExprMatch(ref discr
, ref arms
, _
) => {
451 // Compute the most demanding borrow from all the arms'
452 // patterns and set that on the discriminator.
453 let mut borrow
= None
;
454 for pat
in arms
.iter().flat_map(|arm
| &arm
.pats
) {
455 let pat_borrow
= self.rvalue_borrows
.remove(&pat
.id
);
456 match (borrow
, pat_borrow
) {
457 (None
, _
) | (_
, Some(ast
::MutMutable
)) => {
463 if let Some(mutbl
) = borrow
{
464 self.record_borrow(discr
.id
, mutbl
);
466 visit
::walk_expr(self, ex
);
468 // Division by zero and overflow checking.
469 ast
::ExprBinary(op
, _
, _
) => {
470 visit
::walk_expr(self, ex
);
471 let div_or_rem
= op
.node
== ast
::BiDiv
|| op
.node
== ast
::BiRem
;
473 ty
::TyUint(_
) | ty
::TyInt(_
) if div_or_rem
=> {
474 if !self.qualif
.intersects(ConstQualif
::NOT_CONST
) {
475 match const_eval
::eval_const_expr_partial(
476 self.tcx
, ex
, ExprTypeChecked
) {
479 span_err
!(self.tcx
.sess
, msg
.span
, E0020
,
480 "{} in a constant expression",
489 _
=> visit
::walk_expr(self, ex
)
492 // Handle borrows on (or inside the autorefs of) this expression.
493 match self.rvalue_borrows
.remove(&ex
.id
) {
494 Some(ast
::MutImmutable
) => {
495 // Constants cannot be borrowed if they contain interior mutability as
496 // it means that our "silent insertion of statics" could change
497 // initializer values (very bad).
498 // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
499 // propagated from another error, so erroring again would be just noise.
500 let tc
= node_ty
.type_contents(self.tcx
);
501 if self.qualif
.intersects(ConstQualif
::MUTABLE_MEM
) && tc
.interior_unsafe() {
502 outer
= outer
| ConstQualif
::NOT_CONST
;
503 if self.mode
!= Mode
::Var
{
504 self.tcx
.sess
.span_err(ex
.span
,
505 "cannot borrow a constant which contains \
506 interior mutability, create a static instead");
509 // If the reference has to be 'static, avoid in-place initialization
510 // as that will end up pointing to the stack instead.
511 if !self.qualif
.intersects(ConstQualif
::NON_STATIC_BORROWS
) {
512 self.qualif
= self.qualif
- ConstQualif
::PREFER_IN_PLACE
;
513 self.add_qualif(ConstQualif
::HAS_STATIC_BORROWS
);
516 Some(ast
::MutMutable
) => {
517 // `&mut expr` means expr could be mutated, unless it's zero-sized.
518 if self.qualif
.intersects(ConstQualif
::NON_ZERO_SIZED
) {
519 if self.mode
== Mode
::Var
{
520 outer
= outer
| ConstQualif
::NOT_CONST
;
521 self.add_qualif(ConstQualif
::MUTABLE_MEM
);
523 span_err
!(self.tcx
.sess
, ex
.span
, E0017
,
524 "references in {}s may only refer \
525 to immutable values", self.msg())
528 if !self.qualif
.intersects(ConstQualif
::NON_STATIC_BORROWS
) {
529 self.add_qualif(ConstQualif
::HAS_STATIC_BORROWS
);
534 self.tcx
.const_qualif_map
.borrow_mut().insert(ex
.id
, self.qualif
);
535 // Don't propagate certain flags.
536 self.qualif
= outer
| (self.qualif
- ConstQualif
::HAS_STATIC_BORROWS
);
540 /// This function is used to enforce the constraints on
541 /// const/static items. It walks through the *value*
542 /// of the item walking down the expression and evaluating
543 /// every nested expression. If the expression is not part
544 /// of a const/static item, it is qualified for promotion
545 /// instead of producing errors.
546 fn check_expr
<'a
, 'tcx
>(v
: &mut CheckCrateVisitor
<'a
, 'tcx
>,
547 e
: &ast
::Expr
, node_ty
: Ty
<'tcx
>) {
549 ty
::TyStruct(did
, _
) |
550 ty
::TyEnum(did
, _
) if v
.tcx
.has_dtor(did
) => {
551 v
.add_qualif(ConstQualif
::NEEDS_DROP
);
552 if v
.mode
!= Mode
::Var
{
553 v
.tcx
.sess
.span_err(e
.span
,
554 &format
!("{}s are not allowed to have destructors",
561 let method_call
= ty
::MethodCall
::expr(e
.id
);
564 ast
::ExprBinary(..) |
565 ast
::ExprIndex(..) if v
.tcx
.tables
.borrow().method_map
.contains_key(&method_call
) => {
566 v
.add_qualif(ConstQualif
::NOT_CONST
);
567 if v
.mode
!= Mode
::Var
{
568 span_err
!(v
.tcx
.sess
, e
.span
, E0011
,
569 "user-defined operators are not allowed in {}s", v
.msg());
573 ast
::ExprUnary(ast
::UnUniq
, _
) => {
574 v
.add_qualif(ConstQualif
::NOT_CONST
);
575 if v
.mode
!= Mode
::Var
{
576 span_err
!(v
.tcx
.sess
, e
.span
, E0010
,
577 "allocations are not allowed in {}s", v
.msg());
580 ast
::ExprUnary(op
, ref inner
) => {
581 match v
.tcx
.node_id_to_type(inner
.id
).sty
{
583 assert
!(op
== ast
::UnDeref
);
585 v
.add_qualif(ConstQualif
::NOT_CONST
);
586 if v
.mode
!= Mode
::Var
{
587 span_err
!(v
.tcx
.sess
, e
.span
, E0396
,
588 "raw pointers cannot be dereferenced in {}s", v
.msg());
594 ast
::ExprBinary(op
, ref lhs
, _
) => {
595 match v
.tcx
.node_id_to_type(lhs
.id
).sty
{
597 assert
!(op
.node
== ast
::BiEq
|| op
.node
== ast
::BiNe
||
598 op
.node
== ast
::BiLe
|| op
.node
== ast
::BiLt
||
599 op
.node
== ast
::BiGe
|| op
.node
== ast
::BiGt
);
601 v
.add_qualif(ConstQualif
::NOT_CONST
);
602 if v
.mode
!= Mode
::Var
{
603 span_err
!(v
.tcx
.sess
, e
.span
, E0395
,
604 "raw pointers cannot be compared in {}s", v
.msg());
610 ast
::ExprCast(ref from
, _
) => {
611 debug
!("Checking const cast(id={})", from
.id
);
612 match v
.tcx
.cast_kinds
.borrow().get(&from
.id
) {
613 None
=> v
.tcx
.sess
.span_bug(e
.span
, "no kind for cast"),
614 Some(&CastKind
::PtrAddrCast
) | Some(&CastKind
::FnPtrAddrCast
) => {
615 v
.add_qualif(ConstQualif
::NOT_CONST
);
616 if v
.mode
!= Mode
::Var
{
617 span_err
!(v
.tcx
.sess
, e
.span
, E0018
,
618 "raw pointers cannot be cast to integers in {}s", v
.msg());
624 ast
::ExprPath(..) => {
625 let def
= v
.tcx
.def_map
.borrow().get(&e
.id
).map(|d
| d
.full_def());
627 Some(def
::DefVariant(_
, _
, _
)) => {
628 // Count the discriminator or function pointer.
629 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
631 Some(def
::DefStruct(_
)) => {
632 if let ty
::TyBareFn(..) = node_ty
.sty
{
633 // Count the function pointer.
634 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
637 Some(def
::DefFn(..)) | Some(def
::DefMethod(..)) => {
638 // Count the function pointer.
639 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
641 Some(def
::DefStatic(..)) => {
643 Mode
::Static
| Mode
::StaticMut
=> {}
644 Mode
::Const
| Mode
::ConstFn
=> {
645 span_err
!(v
.tcx
.sess
, e
.span
, E0013
,
646 "{}s cannot refer to other statics, insert \
647 an intermediate constant instead", v
.msg());
649 Mode
::Var
=> v
.add_qualif(ConstQualif
::NOT_CONST
)
652 Some(def
::DefConst(did
)) |
653 Some(def
::DefAssociatedConst(did
)) => {
654 if let Some(expr
) = const_eval
::lookup_const_by_id(v
.tcx
, did
,
656 let inner
= v
.global_expr(Mode
::Const
, expr
);
659 v
.tcx
.sess
.span_bug(e
.span
,
660 "DefConst or DefAssociatedConst \
661 doesn't point to a constant");
664 Some(def
::DefLocal(_
)) if v
.mode
== Mode
::ConstFn
=> {
665 // Sadly, we can't determine whether the types are zero-sized.
666 v
.add_qualif(ConstQualif
::NOT_CONST
| ConstQualif
::NON_ZERO_SIZED
);
669 v
.add_qualif(ConstQualif
::NOT_CONST
);
670 if v
.mode
!= Mode
::Var
{
671 debug
!("(checking const) found bad def: {:?}", def
);
672 span_err
!(v
.tcx
.sess
, e
.span
, E0014
,
673 "paths in {}s may only refer to constants \
674 or functions", v
.msg());
679 ast
::ExprCall(ref callee
, _
) => {
680 let mut callee
= &**callee
;
682 callee
= match callee
.node
{
683 ast
::ExprParen(ref inner
) => &**inner
,
684 ast
::ExprBlock(ref block
) => match block
.expr
{
685 Some(ref tail
) => &**tail
,
691 let def
= v
.tcx
.def_map
.borrow().get(&callee
.id
).map(|d
| d
.full_def());
692 let is_const
= match def
{
693 Some(def
::DefStruct(..)) => true,
694 Some(def
::DefVariant(..)) => {
695 // Count the discriminator.
696 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
699 Some(def
::DefFn(did
, _
)) => {
700 v
.handle_const_fn_call(e
, did
, node_ty
)
702 Some(def
::DefMethod(did
)) => {
703 match v
.tcx
.impl_or_trait_item(did
).container() {
704 ty
::ImplContainer(_
) => {
705 v
.handle_const_fn_call(e
, did
, node_ty
)
707 ty
::TraitContainer(_
) => false
713 v
.add_qualif(ConstQualif
::NOT_CONST
);
714 if v
.mode
!= Mode
::Var
{
715 span_err
!(v
.tcx
.sess
, e
.span
, E0015
,
716 "function calls in {}s are limited to \
717 constant functions, \
718 struct and enum constructors", v
.msg());
722 ast
::ExprMethodCall(..) => {
723 let method
= v
.tcx
.tables
.borrow().method_map
[&method_call
];
724 let is_const
= match v
.tcx
.impl_or_trait_item(method
.def_id
).container() {
725 ty
::ImplContainer(_
) => v
.handle_const_fn_call(e
, method
.def_id
, node_ty
),
726 ty
::TraitContainer(_
) => false
729 v
.add_qualif(ConstQualif
::NOT_CONST
);
730 if v
.mode
!= Mode
::Var
{
731 span_err
!(v
.tcx
.sess
, e
.span
, E0378
,
732 "method calls in {}s are limited to \
733 constant inherent methods", v
.msg());
737 ast
::ExprStruct(..) => {
738 let did
= v
.tcx
.def_map
.borrow().get(&e
.id
).map(|def
| def
.def_id());
739 if did
== v
.tcx
.lang_items
.unsafe_cell_type() {
740 v
.add_qualif(ConstQualif
::MUTABLE_MEM
);
745 ast
::ExprAddrOf(..) => {
746 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
749 ast
::ExprRepeat(..) => {
750 v
.add_qualif(ConstQualif
::PREFER_IN_PLACE
);
753 ast
::ExprClosure(..) => {
754 // Paths in constant contexts cannot refer to local variables,
755 // as there are none, and thus closures can't have upvars there.
756 if v
.tcx
.with_freevars(e
.id
, |fv
| !fv
.is_empty()) {
757 assert
!(v
.mode
== Mode
::Var
,
758 "global closures can't capture anything");
759 v
.add_qualif(ConstQualif
::NOT_CONST
);
766 ast
::ExprTupField(..) |
769 ast
::ExprTup(..) => {}
771 // Conditional control flow (possible to implement).
776 // Loops (not very meaningful in constants).
778 ast
::ExprWhileLet(..) |
779 ast
::ExprForLoop(..) |
782 // More control flow (also not very meaningful).
787 // Miscellaneous expressions that could be implemented.
790 // Expressions with side-effects.
791 ast
::ExprAssign(..) |
792 ast
::ExprAssignOp(..) |
793 ast
::ExprInlineAsm(_
) |
795 v
.add_qualif(ConstQualif
::NOT_CONST
);
796 if v
.mode
!= Mode
::Var
{
797 span_err
!(v
.tcx
.sess
, e
.span
, E0019
,
798 "{} contains unimplemented expression type", v
.msg());
804 /// Check the adjustments of an expression
805 fn check_adjustments
<'a
, 'tcx
>(v
: &mut CheckCrateVisitor
<'a
, 'tcx
>, e
: &ast
::Expr
) {
806 match v
.tcx
.tables
.borrow().adjustments
.get(&e
.id
) {
807 None
| Some(&ty
::AdjustReifyFnPointer
) | Some(&ty
::AdjustUnsafeFnPointer
) => {}
808 Some(&ty
::AdjustDerefRef(ty
::AutoDerefRef { autoderefs, .. }
)) => {
809 if (0..autoderefs
as u32).any(|autoderef
| {
810 v
.tcx
.is_overloaded_autoderef(e
.id
, autoderef
)
812 v
.add_qualif(ConstQualif
::NOT_CONST
);
813 if v
.mode
!= Mode
::Var
{
814 span_err
!(v
.tcx
.sess
, e
.span
, E0400
,
815 "user-defined dereference operators are not allowed in {}s",
823 pub fn check_crate(tcx
: &ty
::ctxt
) {
824 visit
::walk_crate(&mut CheckCrateVisitor
{
827 qualif
: ConstQualif
::NOT_CONST
,
828 rvalue_borrows
: NodeMap()
831 tcx
.sess
.abort_if_errors();
834 impl<'a
, 'tcx
> euv
::Delegate
<'tcx
> for CheckCrateVisitor
<'a
, 'tcx
> {
835 fn consume(&mut self,
836 _consume_id
: ast
::NodeId
,
839 _mode
: euv
::ConsumeMode
) {
843 mc
::cat_static_item
=> {
844 if self.mode
!= Mode
::Var
{
845 // statics cannot be consumed by value at any time, that would imply
846 // that they're an initializer (what a const is for) or kept in sync
847 // over time (not feasible), so deny it outright.
848 span_err
!(self.tcx
.sess
, consume_span
, E0394
,
849 "cannot refer to other statics by value, use the \
850 address-of operator or a constant instead");
854 mc
::cat_deref(ref cmt
, _
, _
) |
855 mc
::cat_downcast(ref cmt
, _
) |
856 mc
::cat_interior(ref cmt
, _
) => cur
= cmt
,
860 mc
::cat_local(..) => break
865 borrow_id
: ast
::NodeId
,
868 _loan_region
: ty
::Region
,
870 loan_cause
: euv
::LoanCause
)
872 // Kind of hacky, but we allow Unsafe coercions in constants.
873 // These occur when we convert a &T or *T to a *U, as well as
874 // when making a thin pointer (e.g., `*T`) into a fat pointer
877 euv
::LoanCause
::AutoUnsafe
=> {
884 let mut is_interior
= false;
887 mc
::cat_rvalue(..) => {
888 if loan_cause
== euv
::MatchDiscriminant
{
889 // Ignore the dummy immutable borrow created by EUV.
892 let mutbl
= bk
.to_mutbl_lossy();
893 if mutbl
== ast
::MutMutable
&& self.mode
== Mode
::StaticMut
{
894 // Mutable slices are the only `&mut` allowed in
895 // globals, but only in `static mut`, nowhere else.
896 // FIXME: This exception is really weird... there isn't
897 // any fundamental reason to restrict this based on
898 // type of the expression. `&mut [1]` has exactly the
899 // same representation as &mut 1.
901 ty
::TyArray(_
, _
) | ty
::TySlice(_
) => break,
905 self.record_borrow(borrow_id
, mutbl
);
908 mc
::cat_static_item
=> {
909 if is_interior
&& self.mode
!= Mode
::Var
{
910 // Borrowed statics can specifically *only* have their address taken,
911 // not any number of other borrows such as borrowing fields, reading
912 // elements of an array, etc.
913 self.tcx
.sess
.span_err(borrow_span
,
914 "cannot refer to the interior of another \
915 static, use a constant instead");
919 mc
::cat_deref(ref cmt
, _
, _
) |
920 mc
::cat_downcast(ref cmt
, _
) |
921 mc
::cat_interior(ref cmt
, _
) => {
927 mc
::cat_local(..) => break
932 fn decl_without_init(&mut self,
936 _assignment_id
: ast
::NodeId
,
937 _assignment_span
: Span
,
938 _assignee_cmt
: mc
::cmt
,
939 _mode
: euv
::MutateMode
) {}
941 fn matched_pat(&mut self,
944 _
: euv
::MatchMode
) {}
946 fn consume_pat(&mut self,
947 _consume_pat
: &ast
::Pat
,
949 _mode
: euv
::ConsumeMode
) {}