]>
git.proxmox.com Git - rustc.git/blob - 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.
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
;
30 use middle
::expr_use_visitor
as euv
;
32 use middle
::mem_categorization
as mc
;
34 use middle
::ty
::{self, Ty}
;
35 use util
::nodemap
::NodeMap
;
38 use syntax
::codemap
::Span
;
39 use syntax
::visit
::{self, Visitor}
;
41 use std
::collections
::hash_map
::Entry
;
43 // Const qualification, from partial to completely promotable.
45 #[derive(RustcEncodable, RustcDecodable)]
46 flags ConstQualif
: u8 {
47 // Inner mutability (can not be placed behind a reference) or behind
48 // &mut in a non-global expression. Can be copied from static memory.
49 const MUTABLE_MEM
= 1 << 0,
50 // Constant value with a type that implements Drop. Can be copied
51 // from static memory, similar to MUTABLE_MEM.
52 const NEEDS_DROP
= 1 << 1,
53 // Even if the value can be placed in static memory, copying it from
54 // there is more expensive than in-place instantiation, and/or it may
55 // be too large. This applies to [T; N] and everything containing it.
56 // N.B.: references need to clear this flag to not end up on the stack.
57 const PREFER_IN_PLACE
= 1 << 2,
58 // May use more than 0 bytes of memory, doesn't impact the constness
59 // directly, but is not allowed to be borrowed mutably in a constant.
60 const NON_ZERO_SIZED
= 1 << 3,
61 // Actually borrowed, has to always be in static memory. Does not
62 // propagate, and requires the expression to behave like a 'static
63 // lvalue. The set of expressions with this flag is the minimum
64 // that have to be promoted.
65 const HAS_STATIC_BORROWS
= 1 << 4,
66 // Invalid const for miscellaneous reasons (e.g. not implemented).
67 const NOT_CONST
= 1 << 5,
69 // Borrowing the expression won't produce &'static T if any of these
70 // bits are set, though the value could be copied from static memory
71 // if `NOT_CONST` isn't set.
72 const NON_STATIC_BORROWS
= ConstQualif
::MUTABLE_MEM
.bits
|
73 ConstQualif
::NEEDS_DROP
.bits
|
74 ConstQualif
::NOT_CONST
.bits
78 #[derive(Copy, Clone, Eq, PartialEq)]
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.
92 struct CheckCrateVisitor
<'a
, 'tcx
: 'a
> {
93 tcx
: &'a ty
::ctxt
<'tcx
>,
96 rvalue_borrows
: NodeMap
<ast
::Mutability
>
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
,
103 let (old_mode
, old_qualif
) = (self.mode
, self.qualif
);
105 self.qualif
= ConstQualif
::empty();
107 self.mode
= old_mode
;
108 self.qualif
= old_qualif
;
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
,
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
)
120 f(&mut euv
::ExprUseVisitor
::new(self, ¶m_env
))
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(ConstQualif
::empty());
132 self.with_mode(mode
, |this
| {
133 this
.with_euv(None
, |euv
| euv
.consume_expr(expr
));
134 this
.visit_expr(expr
);
139 fn fn_like(&mut self,
146 match self.tcx
.const_qualif_map
.borrow_mut().entry(fn_id
) {
147 Entry
::Occupied(entry
) => return *entry
.get(),
148 Entry
::Vacant(entry
) => {
149 // Prevent infinite recursion on re-entry.
150 entry
.insert(ConstQualif
::empty());
154 let mode
= match fk
{
155 visit
::FkItemFn(_
, _
, _
, ast
::Constness
::Const
, _
, _
) => {
158 visit
::FkMethod(_
, m
, _
) => {
159 if m
.constness
== ast
::Constness
::Const
{
168 // Ensure the arguments are simple, not mutable/by-ref or patterns.
169 if mode
== Mode
::ConstFn
{
170 for arg
in &fd
.inputs
{
172 ast
::PatIdent(ast
::BindByValue(ast
::MutImmutable
), _
, None
) => {}
174 span_err
!(self.tcx
.sess
, arg
.pat
.span
, E0022
,
175 "arguments of constant functions can only \
176 be immutable by-value bindings");
182 let qualif
= self.with_mode(mode
, |this
| {
183 this
.with_euv(Some(fn_id
), |euv
| euv
.walk_fn(fd
, b
));
184 visit
::walk_fn(this
, fk
, fd
, b
, s
);
188 // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
189 // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
190 let qualif
= qualif
& (ConstQualif
::NON_ZERO_SIZED
| ConstQualif
::PREFER_IN_PLACE
);
192 self.tcx
.const_qualif_map
.borrow_mut().insert(fn_id
, qualif
);
196 fn add_qualif(&mut self, qualif
: ConstQualif
) {
197 self.qualif
= self.qualif
| qualif
;
200 /// Returns true if the call is to a const fn or method.
201 fn handle_const_fn_call(&mut self,
206 if let Some(fn_like
) = const_eval
::lookup_const_fn_by_id(self.tcx
, def_id
) {
208 // we are in a static/const initializer
209 self.mode
!= Mode
::Var
&&
211 // feature-gate is not enabled
212 !self.tcx
.sess
.features
.borrow().const_fn
&&
214 // this doesn't come from a macro that has #[allow_internal_unstable]
215 !self.tcx
.sess
.codemap().span_allows_unstable(expr
.span
)
217 self.tcx
.sess
.span_err(
219 &format
!("const fns are an unstable feature"));
223 "in Nightly builds, add `#![feature(const_fn)]` to the crate \
224 attributes to enable");
227 let qualif
= self.fn_like(fn_like
.kind(),
232 self.add_qualif(qualif
);
234 if ty
::type_contents(self.tcx
, ret_ty
).interior_unsafe() {
235 self.add_qualif(ConstQualif
::MUTABLE_MEM
);
244 fn record_borrow(&mut self, id
: ast
::NodeId
, mutbl
: ast
::Mutability
) {
245 match self.rvalue_borrows
.entry(id
) {
246 Entry
::Occupied(mut entry
) => {
247 // Merge the two borrows, taking the most demanding
248 // one, mutability-wise.
249 if mutbl
== ast
::MutMutable
{
253 Entry
::Vacant(entry
) => {
259 fn msg(&self) -> &'
static str {
261 Mode
::Const
=> "constant",
262 Mode
::ConstFn
=> "constant function",
263 Mode
::StaticMut
| Mode
::Static
=> "static",
264 Mode
::Var
=> unreachable
!(),
268 fn check_static_mut_type(&self, e
: &ast
::Expr
) {
269 let node_ty
= ty
::node_id_to_type(self.tcx
, e
.id
);
270 let tcontents
= ty
::type_contents(self.tcx
, node_ty
);
272 let suffix
= if tcontents
.has_dtor() {
274 } else if tcontents
.owns_owned() {
280 span_err
!(self.tcx
.sess
, e
.span
, E0397
,
281 "mutable statics are not allowed to have {}", suffix
);
284 fn check_static_type(&self, e
: &ast
::Expr
) {
285 let ty
= ty
::node_id_to_type(self.tcx
, e
.id
);
286 let infcx
= infer
::new_infer_ctxt(self.tcx
);
287 let mut fulfill_cx
= traits
::FulfillmentContext
::new(false);
288 let cause
= traits
::ObligationCause
::new(e
.span
, e
.id
, traits
::SharedStatic
);
289 fulfill_cx
.register_builtin_bound(&infcx
, ty
, ty
::BoundSync
, cause
);
290 let env
= ty
::empty_parameter_environment(self.tcx
);
291 match fulfill_cx
.select_all_or_error(&infcx
, &env
) {
294 traits
::report_fulfillment_errors(&infcx
, errors
);
300 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for CheckCrateVisitor
<'a
, 'tcx
> {
301 fn visit_item(&mut self, i
: &ast
::Item
) {
302 debug
!("visit_item(item={})", self.tcx
.map
.node_to_string(i
.id
));
304 ast
::ItemStatic(_
, ast
::MutImmutable
, ref expr
) => {
305 self.check_static_type(&**expr
);
306 self.global_expr(Mode
::Static
, &**expr
);
308 ast
::ItemStatic(_
, ast
::MutMutable
, ref expr
) => {
309 self.check_static_mut_type(&**expr
);
310 self.global_expr(Mode
::StaticMut
, &**expr
);
312 ast
::ItemConst(_
, ref expr
) => {
313 self.global_expr(Mode
::Const
, &**expr
);
315 ast
::ItemEnum(ref enum_definition
, _
) => {
316 for var
in &enum_definition
.variants
{
317 if let Some(ref ex
) = var
.node
.disr_expr
{
318 self.global_expr(Mode
::Const
, &**ex
);
323 self.with_mode(Mode
::Var
, |v
| visit
::walk_item(v
, i
));
328 fn visit_trait_item(&mut self, t
: &'v ast
::TraitItem
) {
330 ast
::ConstTraitItem(_
, ref default) => {
331 if let Some(ref expr
) = *default {
332 self.global_expr(Mode
::Const
, &*expr
);
334 visit
::walk_trait_item(self, t
);
337 _
=> self.with_mode(Mode
::Var
, |v
| visit
::walk_trait_item(v
, t
)),
341 fn visit_impl_item(&mut self, i
: &'v ast
::ImplItem
) {
343 ast
::ConstImplItem(_
, ref expr
) => {
344 self.global_expr(Mode
::Const
, &*expr
);
346 _
=> self.with_mode(Mode
::Var
, |v
| visit
::walk_impl_item(v
, i
)),
350 fn visit_fn(&mut self,
351 fk
: visit
::FnKind
<'v
>,
355 fn_id
: ast
::NodeId
) {
356 self.fn_like(fk
, fd
, b
, s
, fn_id
);
359 fn visit_pat(&mut self, p
: &ast
::Pat
) {
361 ast
::PatLit(ref lit
) => {
362 self.global_expr(Mode
::Const
, &**lit
);
364 ast
::PatRange(ref start
, ref end
) => {
365 self.global_expr(Mode
::Const
, &**start
);
366 self.global_expr(Mode
::Const
, &**end
);
368 _
=> visit
::walk_pat(self, p
)
372 fn visit_block(&mut self, block
: &ast
::Block
) {
373 // Check all statements in the block
374 for stmt
in &block
.stmts
{
375 let span
= match stmt
.node
{
376 ast
::StmtDecl(ref decl
, _
) => {
378 ast
::DeclLocal(_
) => decl
.span
,
380 // Item statements are allowed
381 ast
::DeclItem(_
) => continue
384 ast
::StmtExpr(ref expr
, _
) => expr
.span
,
385 ast
::StmtSemi(ref semi
, _
) => semi
.span
,
386 ast
::StmtMac(..) => {
387 self.tcx
.sess
.span_bug(stmt
.span
, "unexpanded statement \
391 self.add_qualif(ConstQualif
::NOT_CONST
);
392 if self.mode
!= Mode
::Var
{
393 span_err
!(self.tcx
.sess
, span
, E0016
,
394 "blocks in {}s are limited to items and \
395 tail expressions", self.msg());
398 visit
::walk_block(self, block
);
401 fn visit_expr(&mut self, ex
: &ast
::Expr
) {
402 let mut outer
= self.qualif
;
403 self.qualif
= ConstQualif
::empty();
405 let node_ty
= ty
::node_id_to_type(self.tcx
, ex
.id
);
406 check_expr(self, ex
, node_ty
);
408 // Special-case some expressions to avoid certain flags bubbling up.
410 ast
::ExprCall(ref callee
, ref args
) => {
412 self.visit_expr(&**arg
)
415 let inner
= self.qualif
;
416 self.visit_expr(&**callee
);
417 // The callee's size doesn't count in the call.
418 let added
= self.qualif
- inner
;
419 self.qualif
= inner
| (added
- ConstQualif
::NON_ZERO_SIZED
);
421 ast
::ExprRepeat(ref element
, _
) => {
422 self.visit_expr(&**element
);
423 // The count is checked elsewhere (typeck).
424 let count
= match node_ty
.sty
{
425 ty
::TyArray(_
, n
) => n
,
428 // [element; 0] is always zero-sized.
430 self.qualif
.remove(ConstQualif
::NON_ZERO_SIZED
| ConstQualif
::PREFER_IN_PLACE
);
433 ast
::ExprMatch(ref discr
, ref arms
, _
) => {
434 // Compute the most demanding borrow from all the arms'
435 // patterns and set that on the discriminator.
436 let mut borrow
= None
;
437 for pat
in arms
.iter().flat_map(|arm
| &arm
.pats
) {
438 let pat_borrow
= self.rvalue_borrows
.remove(&pat
.id
);
439 match (borrow
, pat_borrow
) {
440 (None
, _
) | (_
, Some(ast
::MutMutable
)) => {
446 if let Some(mutbl
) = borrow
{
447 self.record_borrow(discr
.id
, mutbl
);
449 visit
::walk_expr(self, ex
);
451 // Division by zero and overflow checking.
452 ast
::ExprBinary(op
, _
, _
) => {
453 visit
::walk_expr(self, ex
);
454 let div_or_rem
= op
.node
== ast
::BiDiv
|| op
.node
== ast
::BiRem
;
456 ty
::TyUint(_
) | ty
::TyInt(_
) if div_or_rem
=> {
457 if !self.qualif
.intersects(ConstQualif
::NOT_CONST
) {
458 match const_eval
::eval_const_expr_partial(self.tcx
, ex
, None
) {
461 span_err
!(self.tcx
.sess
, msg
.span
, E0020
,
462 "{} in a constant expression",
471 _
=> visit
::walk_expr(self, ex
)
474 // Handle borrows on (or inside the autorefs of) this expression.
475 match self.rvalue_borrows
.remove(&ex
.id
) {
476 Some(ast
::MutImmutable
) => {
477 // Constants cannot be borrowed if they contain interior mutability as
478 // it means that our "silent insertion of statics" could change
479 // initializer values (very bad).
480 // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
481 // propagated from another error, so erroring again would be just noise.
482 let tc
= ty
::type_contents(self.tcx
, node_ty
);
483 if self.qualif
.intersects(ConstQualif
::MUTABLE_MEM
) && tc
.interior_unsafe() {
484 outer
= outer
| ConstQualif
::NOT_CONST
;
485 if self.mode
!= Mode
::Var
{
486 self.tcx
.sess
.span_err(ex
.span
,
487 "cannot borrow a constant which contains \
488 interior mutability, create a static instead");
491 // If the reference has to be 'static, avoid in-place initialization
492 // as that will end up pointing to the stack instead.
493 if !self.qualif
.intersects(ConstQualif
::NON_STATIC_BORROWS
) {
494 self.qualif
= self.qualif
- ConstQualif
::PREFER_IN_PLACE
;
495 self.add_qualif(ConstQualif
::HAS_STATIC_BORROWS
);
498 Some(ast
::MutMutable
) => {
499 // `&mut expr` means expr could be mutated, unless it's zero-sized.
500 if self.qualif
.intersects(ConstQualif
::NON_ZERO_SIZED
) {
501 if self.mode
== Mode
::Var
{
502 outer
= outer
| ConstQualif
::NOT_CONST
;
503 self.add_qualif(ConstQualif
::MUTABLE_MEM
);
505 span_err
!(self.tcx
.sess
, ex
.span
, E0017
,
506 "references in {}s may only refer \
507 to immutable values", self.msg())
510 if !self.qualif
.intersects(ConstQualif
::NON_STATIC_BORROWS
) {
511 self.add_qualif(ConstQualif
::HAS_STATIC_BORROWS
);
516 self.tcx
.const_qualif_map
.borrow_mut().insert(ex
.id
, self.qualif
);
517 // Don't propagate certain flags.
518 self.qualif
= outer
| (self.qualif
- ConstQualif
::HAS_STATIC_BORROWS
);
522 /// This function is used to enforce the constraints on
523 /// const/static items. It walks through the *value*
524 /// of the item walking down the expression and evaluating
525 /// every nested expression. If the expression is not part
526 /// of a const/static item, it is qualified for promotion
527 /// instead of producing errors.
528 fn check_expr
<'a
, 'tcx
>(v
: &mut CheckCrateVisitor
<'a
, 'tcx
>,
529 e
: &ast
::Expr
, node_ty
: Ty
<'tcx
>) {
531 ty
::TyStruct(did
, _
) |
532 ty
::TyEnum(did
, _
) if ty
::has_dtor(v
.tcx
, did
) => {
533 v
.add_qualif(ConstQualif
::NEEDS_DROP
);
534 if v
.mode
!= Mode
::Var
{
535 v
.tcx
.sess
.span_err(e
.span
,
536 &format
!("{}s are not allowed to have destructors",
543 let method_call
= ty
::MethodCall
::expr(e
.id
);
546 ast
::ExprBinary(..) |
547 ast
::ExprIndex(..) if v
.tcx
.method_map
.borrow().contains_key(&method_call
) => {
548 v
.add_qualif(ConstQualif
::NOT_CONST
);
549 if v
.mode
!= Mode
::Var
{
550 span_err
!(v
.tcx
.sess
, e
.span
, E0011
,
551 "user-defined operators are not allowed in {}s", v
.msg());
555 ast
::ExprUnary(ast
::UnUniq
, _
) => {
556 v
.add_qualif(ConstQualif
::NOT_CONST
);
557 if v
.mode
!= Mode
::Var
{
558 span_err
!(v
.tcx
.sess
, e
.span
, E0010
,
559 "allocations are not allowed in {}s", v
.msg());
562 ast
::ExprUnary(op
, ref inner
) => {
563 match ty
::node_id_to_type(v
.tcx
, inner
.id
).sty
{
565 assert
!(op
== ast
::UnDeref
);
567 v
.add_qualif(ConstQualif
::NOT_CONST
);
568 if v
.mode
!= Mode
::Var
{
569 span_err
!(v
.tcx
.sess
, e
.span
, E0396
,
570 "raw pointers cannot be dereferenced in {}s", v
.msg());
576 ast
::ExprBinary(op
, ref lhs
, _
) => {
577 match ty
::node_id_to_type(v
.tcx
, lhs
.id
).sty
{
579 assert
!(op
.node
== ast
::BiEq
|| op
.node
== ast
::BiNe
||
580 op
.node
== ast
::BiLe
|| op
.node
== ast
::BiLt
||
581 op
.node
== ast
::BiGe
|| op
.node
== ast
::BiGt
);
583 v
.add_qualif(ConstQualif
::NOT_CONST
);
584 if v
.mode
!= Mode
::Var
{
585 span_err
!(v
.tcx
.sess
, e
.span
, E0395
,
586 "raw pointers cannot be compared in {}s", v
.msg());
592 ast
::ExprCast(ref from
, _
) => {
593 debug
!("Checking const cast(id={})", from
.id
);
594 match v
.tcx
.cast_kinds
.borrow().get(&from
.id
) {
595 None
=> v
.tcx
.sess
.span_bug(e
.span
, "no kind for cast"),
596 Some(&CastKind
::PtrAddrCast
) | Some(&CastKind
::FnPtrAddrCast
) => {
597 v
.add_qualif(ConstQualif
::NOT_CONST
);
598 if v
.mode
!= Mode
::Var
{
599 span_err
!(v
.tcx
.sess
, e
.span
, E0018
,
600 "raw pointers cannot be cast to integers in {}s", v
.msg());
606 ast
::ExprPath(..) => {
607 let def
= v
.tcx
.def_map
.borrow().get(&e
.id
).map(|d
| d
.full_def());
609 Some(def
::DefVariant(_
, _
, _
)) => {
610 // Count the discriminator or function pointer.
611 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
613 Some(def
::DefStruct(_
)) => {
614 if let ty
::TyBareFn(..) = node_ty
.sty
{
615 // Count the function pointer.
616 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
619 Some(def
::DefFn(..)) | Some(def
::DefMethod(..)) => {
620 // Count the function pointer.
621 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
623 Some(def
::DefStatic(..)) => {
625 Mode
::Static
| Mode
::StaticMut
=> {}
626 Mode
::Const
| Mode
::ConstFn
=> {
627 span_err
!(v
.tcx
.sess
, e
.span
, E0013
,
628 "{}s cannot refer to other statics, insert \
629 an intermediate constant instead", v
.msg());
631 Mode
::Var
=> v
.add_qualif(ConstQualif
::NOT_CONST
)
634 Some(def
::DefConst(did
)) |
635 Some(def
::DefAssociatedConst(did
, _
)) => {
636 if let Some(expr
) = const_eval
::lookup_const_by_id(v
.tcx
, did
,
638 let inner
= v
.global_expr(Mode
::Const
, expr
);
641 v
.tcx
.sess
.span_bug(e
.span
,
642 "DefConst or DefAssociatedConst \
643 doesn't point to a constant");
646 Some(def
::DefLocal(_
)) if v
.mode
== Mode
::ConstFn
=> {
647 // Sadly, we can't determine whether the types are zero-sized.
648 v
.add_qualif(ConstQualif
::NOT_CONST
| ConstQualif
::NON_ZERO_SIZED
);
651 v
.add_qualif(ConstQualif
::NOT_CONST
);
652 if v
.mode
!= Mode
::Var
{
653 debug
!("(checking const) found bad def: {:?}", def
);
654 span_err
!(v
.tcx
.sess
, e
.span
, E0014
,
655 "paths in {}s may only refer to constants \
656 or functions", v
.msg());
661 ast
::ExprCall(ref callee
, _
) => {
662 let mut callee
= &**callee
;
664 callee
= match callee
.node
{
665 ast
::ExprParen(ref inner
) => &**inner
,
666 ast
::ExprBlock(ref block
) => match block
.expr
{
667 Some(ref tail
) => &**tail
,
673 let def
= v
.tcx
.def_map
.borrow().get(&callee
.id
).map(|d
| d
.full_def());
674 let is_const
= match def
{
675 Some(def
::DefStruct(..)) => true,
676 Some(def
::DefVariant(..)) => {
677 // Count the discriminator.
678 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
681 Some(def
::DefMethod(did
, def
::FromImpl(_
))) |
682 Some(def
::DefFn(did
, _
)) => {
683 v
.handle_const_fn_call(e
, did
, node_ty
)
688 v
.add_qualif(ConstQualif
::NOT_CONST
);
689 if v
.mode
!= Mode
::Var
{
690 span_err
!(v
.tcx
.sess
, e
.span
, E0015
,
691 "function calls in {}s are limited to \
692 constant functions, \
693 struct and enum constructors", v
.msg());
697 ast
::ExprMethodCall(..) => {
698 let method_did
= match v
.tcx
.method_map
.borrow()[&method_call
].origin
{
699 ty
::MethodStatic(did
) => Some(did
),
702 let is_const
= match method_did
{
703 Some(did
) => v
.handle_const_fn_call(e
, did
, node_ty
),
707 v
.add_qualif(ConstQualif
::NOT_CONST
);
708 if v
.mode
!= Mode
::Var
{
709 span_err
!(v
.tcx
.sess
, e
.span
, E0378
,
710 "method calls in {}s are limited to \
711 constant inherent methods", v
.msg());
715 ast
::ExprStruct(..) => {
716 let did
= v
.tcx
.def_map
.borrow().get(&e
.id
).map(|def
| def
.def_id());
717 if did
== v
.tcx
.lang_items
.unsafe_cell_type() {
718 v
.add_qualif(ConstQualif
::MUTABLE_MEM
);
723 ast
::ExprAddrOf(..) => {
724 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
727 ast
::ExprRepeat(..) => {
728 v
.add_qualif(ConstQualif
::PREFER_IN_PLACE
);
731 ast
::ExprClosure(..) => {
732 // Paths in constant contexts cannot refer to local variables,
733 // as there are none, and thus closures can't have upvars there.
734 if ty
::with_freevars(v
.tcx
, e
.id
, |fv
| !fv
.is_empty()) {
735 assert
!(v
.mode
== Mode
::Var
,
736 "global closures can't capture anything");
737 v
.add_qualif(ConstQualif
::NOT_CONST
);
744 ast
::ExprTupField(..) |
747 ast
::ExprTup(..) => {}
749 // Conditional control flow (possible to implement).
754 // Loops (not very meaningful in constants).
756 ast
::ExprWhileLet(..) |
757 ast
::ExprForLoop(..) |
760 // More control flow (also not very meaningful).
765 // Miscellaneous expressions that could be implemented.
768 // Expressions with side-effects.
769 ast
::ExprAssign(..) |
770 ast
::ExprAssignOp(..) |
771 ast
::ExprInlineAsm(_
) |
773 v
.add_qualif(ConstQualif
::NOT_CONST
);
774 if v
.mode
!= Mode
::Var
{
775 span_err
!(v
.tcx
.sess
, e
.span
, E0019
,
776 "{} contains unimplemented expression type", v
.msg());
782 pub fn check_crate(tcx
: &ty
::ctxt
) {
783 visit
::walk_crate(&mut CheckCrateVisitor
{
786 qualif
: ConstQualif
::NOT_CONST
,
787 rvalue_borrows
: NodeMap()
790 tcx
.sess
.abort_if_errors();
793 impl<'a
, 'tcx
> euv
::Delegate
<'tcx
> for CheckCrateVisitor
<'a
, 'tcx
> {
794 fn consume(&mut self,
795 _consume_id
: ast
::NodeId
,
798 _mode
: euv
::ConsumeMode
) {
802 mc
::cat_static_item
=> {
803 if self.mode
!= Mode
::Var
{
804 // statics cannot be consumed by value at any time, that would imply
805 // that they're an initializer (what a const is for) or kept in sync
806 // over time (not feasible), so deny it outright.
807 span_err
!(self.tcx
.sess
, consume_span
, E0394
,
808 "cannot refer to other statics by value, use the \
809 address-of operator or a constant instead");
813 mc
::cat_deref(ref cmt
, _
, _
) |
814 mc
::cat_downcast(ref cmt
, _
) |
815 mc
::cat_interior(ref cmt
, _
) => cur
= cmt
,
819 mc
::cat_local(..) => break
824 borrow_id
: ast
::NodeId
,
827 _loan_region
: ty
::Region
,
829 loan_cause
: euv
::LoanCause
)
831 // Kind of hacky, but we allow Unsafe coercions in constants.
832 // These occur when we convert a &T or *T to a *U, as well as
833 // when making a thin pointer (e.g., `*T`) into a fat pointer
836 euv
::LoanCause
::AutoUnsafe
=> {
843 let mut is_interior
= false;
846 mc
::cat_rvalue(..) => {
847 if loan_cause
== euv
::MatchDiscriminant
{
848 // Ignore the dummy immutable borrow created by EUV.
851 let mutbl
= bk
.to_mutbl_lossy();
852 if mutbl
== ast
::MutMutable
&& self.mode
== Mode
::StaticMut
{
853 // Mutable slices are the only `&mut` allowed in
854 // globals, but only in `static mut`, nowhere else.
855 // FIXME: This exception is really weird... there isn't
856 // any fundamental reason to restrict this based on
857 // type of the expression. `&mut [1]` has exactly the
858 // same representation as &mut 1.
860 ty
::TyArray(_
, _
) | ty
::TySlice(_
) => break,
864 self.record_borrow(borrow_id
, mutbl
);
867 mc
::cat_static_item
=> {
868 if is_interior
&& self.mode
!= Mode
::Var
{
869 // Borrowed statics can specifically *only* have their address taken,
870 // not any number of other borrows such as borrowing fields, reading
871 // elements of an array, etc.
872 self.tcx
.sess
.span_err(borrow_span
,
873 "cannot refer to the interior of another \
874 static, use a constant instead");
878 mc
::cat_deref(ref cmt
, _
, _
) |
879 mc
::cat_downcast(ref cmt
, _
) |
880 mc
::cat_interior(ref cmt
, _
) => {
886 mc
::cat_local(..) => break
891 fn decl_without_init(&mut self,
895 _assignment_id
: ast
::NodeId
,
896 _assignment_span
: Span
,
897 _assignee_cmt
: mc
::cmt
,
898 _mode
: euv
::MutateMode
) {}
900 fn matched_pat(&mut self,
903 _
: euv
::MatchMode
) {}
905 fn consume_pat(&mut self,
906 _consume_pat
: &ast
::Pat
,
908 _mode
: euv
::ConsumeMode
) {}