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
::ty
::cast
::{CastKind}
;
28 use middle
::const_eval
::{self, ConstEvalErr}
;
29 use middle
::const_eval
::ErrKind
::IndexOpFeatureGated
;
30 use middle
::const_eval
::EvalHint
::ExprTypeChecked
;
32 use middle
::def_id
::DefId
;
33 use middle
::expr_use_visitor
as euv
;
35 use middle
::mem_categorization
as mc
;
36 use middle
::mem_categorization
::Categorization
;
38 use middle
::ty
::{self, Ty}
;
39 use util
::nodemap
::NodeMap
;
43 use syntax
::codemap
::Span
;
44 use syntax
::feature_gate
::UnstableFeatures
;
45 use rustc_front
::intravisit
::{self, FnKind, Visitor}
;
47 use std
::collections
::hash_map
::Entry
;
48 use std
::cmp
::Ordering
;
50 // Const qualification, from partial to completely promotable.
52 #[derive(RustcEncodable, RustcDecodable)]
53 flags ConstQualif
: u8 {
54 // Inner mutability (can not be placed behind a reference) or behind
55 // &mut in a non-global expression. Can be copied from static memory.
56 const MUTABLE_MEM
= 1 << 0,
57 // Constant value with a type that implements Drop. Can be copied
58 // from static memory, similar to MUTABLE_MEM.
59 const NEEDS_DROP
= 1 << 1,
60 // Even if the value can be placed in static memory, copying it from
61 // there is more expensive than in-place instantiation, and/or it may
62 // be too large. This applies to [T; N] and everything containing it.
63 // N.B.: references need to clear this flag to not end up on the stack.
64 const PREFER_IN_PLACE
= 1 << 2,
65 // May use more than 0 bytes of memory, doesn't impact the constness
66 // directly, but is not allowed to be borrowed mutably in a constant.
67 const NON_ZERO_SIZED
= 1 << 3,
68 // Actually borrowed, has to always be in static memory. Does not
69 // propagate, and requires the expression to behave like a 'static
70 // lvalue. The set of expressions with this flag is the minimum
71 // that have to be promoted.
72 const HAS_STATIC_BORROWS
= 1 << 4,
73 // Invalid const for miscellaneous reasons (e.g. not implemented).
74 const NOT_CONST
= 1 << 5,
76 // Borrowing the expression won't produce &'static T if any of these
77 // bits are set, though the value could be copied from static memory
78 // if `NOT_CONST` isn't set.
79 const NON_STATIC_BORROWS
= ConstQualif
::MUTABLE_MEM
.bits
|
80 ConstQualif
::NEEDS_DROP
.bits
|
81 ConstQualif
::NOT_CONST
.bits
85 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
92 // An expression that occurs outside of any constant context
93 // (i.e. `const`, `static`, array lengths, etc.). The value
94 // can be variable at runtime, but will be promotable to
95 // static memory if we can prove it is actually constant.
99 struct CheckCrateVisitor
<'a
, 'tcx
: 'a
> {
100 tcx
: &'a ty
::ctxt
<'tcx
>,
103 rvalue_borrows
: NodeMap
<hir
::Mutability
>
106 impl<'a
, 'tcx
> CheckCrateVisitor
<'a
, 'tcx
> {
107 fn with_mode
<F
, R
>(&mut self, mode
: Mode
, f
: F
) -> R
where
108 F
: FnOnce(&mut CheckCrateVisitor
<'a
, 'tcx
>) -> R
,
110 let (old_mode
, old_qualif
) = (self.mode
, self.qualif
);
112 self.qualif
= ConstQualif
::empty();
114 self.mode
= old_mode
;
115 self.qualif
= old_qualif
;
119 fn with_euv
<'b
, F
, R
>(&'b
mut self, item_id
: Option
<ast
::NodeId
>, f
: F
) -> R
where
120 F
: for<'t
> FnOnce(&mut euv
::ExprUseVisitor
<'b
, 't
, 'b
, 'tcx
>) -> R
,
122 let param_env
= match item_id
{
123 Some(item_id
) => ty
::ParameterEnvironment
::for_item(self.tcx
, item_id
),
124 None
=> self.tcx
.empty_parameter_environment()
127 let infcx
= infer
::new_infer_ctxt(self.tcx
, &self.tcx
.tables
, Some(param_env
), false);
129 f(&mut euv
::ExprUseVisitor
::new(self, &infcx
))
132 fn global_expr(&mut self, mode
: Mode
, expr
: &hir
::Expr
) -> ConstQualif
{
133 assert
!(mode
!= Mode
::Var
);
134 match self.tcx
.const_qualif_map
.borrow_mut().entry(expr
.id
) {
135 Entry
::Occupied(entry
) => return *entry
.get(),
136 Entry
::Vacant(entry
) => {
137 // Prevent infinite recursion on re-entry.
138 entry
.insert(ConstQualif
::empty());
141 self.with_mode(mode
, |this
| {
142 this
.with_euv(None
, |euv
| euv
.consume_expr(expr
));
143 this
.visit_expr(expr
);
148 fn fn_like(&mut self,
155 match self.tcx
.const_qualif_map
.borrow_mut().entry(fn_id
) {
156 Entry
::Occupied(entry
) => return *entry
.get(),
157 Entry
::Vacant(entry
) => {
158 // Prevent infinite recursion on re-entry.
159 entry
.insert(ConstQualif
::empty());
163 let mode
= match fk
{
164 FnKind
::ItemFn(_
, _
, _
, hir
::Constness
::Const
, _
, _
) => {
167 FnKind
::Method(_
, m
, _
) => {
168 if m
.constness
== hir
::Constness
::Const
{
177 // Ensure the arguments are simple, not mutable/by-ref or patterns.
178 if mode
== Mode
::ConstFn
{
179 for arg
in &fd
.inputs
{
182 hir
::PatIdent(hir
::BindByValue(hir
::MutImmutable
), _
, None
) => {}
184 span_err
!(self.tcx
.sess
, arg
.pat
.span
, E0022
,
185 "arguments of constant functions can only \
186 be immutable by-value bindings");
192 let qualif
= self.with_mode(mode
, |this
| {
193 this
.with_euv(Some(fn_id
), |euv
| euv
.walk_fn(fd
, b
));
194 intravisit
::walk_fn(this
, fk
, fd
, b
, s
);
198 // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
199 // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
200 let qualif
= qualif
& (ConstQualif
::NON_ZERO_SIZED
| ConstQualif
::PREFER_IN_PLACE
);
202 self.tcx
.const_qualif_map
.borrow_mut().insert(fn_id
, qualif
);
206 fn add_qualif(&mut self, qualif
: ConstQualif
) {
207 self.qualif
= self.qualif
| qualif
;
210 /// Returns true if the call is to a const fn or method.
211 fn handle_const_fn_call(&mut self,
216 if let Some(fn_like
) = const_eval
::lookup_const_fn_by_id(self.tcx
, def_id
) {
218 // we are in a static/const initializer
219 self.mode
!= Mode
::Var
&&
221 // feature-gate is not enabled
222 !self.tcx
.sess
.features
.borrow().const_fn
&&
224 // this doesn't come from a macro that has #[allow_internal_unstable]
225 !self.tcx
.sess
.codemap().span_allows_unstable(expr
.span
)
227 self.tcx
.sess
.span_err(
229 "const fns are an unstable feature");
233 "in Nightly builds, add `#![feature(const_fn)]` to the crate \
234 attributes to enable");
237 let qualif
= self.fn_like(fn_like
.kind(),
242 self.add_qualif(qualif
);
244 if ret_ty
.type_contents(self.tcx
).interior_unsafe() {
245 self.add_qualif(ConstQualif
::MUTABLE_MEM
);
254 fn record_borrow(&mut self, id
: ast
::NodeId
, mutbl
: hir
::Mutability
) {
255 match self.rvalue_borrows
.entry(id
) {
256 Entry
::Occupied(mut entry
) => {
257 // Merge the two borrows, taking the most demanding
258 // one, mutability-wise.
259 if mutbl
== hir
::MutMutable
{
263 Entry
::Vacant(entry
) => {
269 fn msg(&self) -> &'
static str {
271 Mode
::Const
=> "constant",
272 Mode
::ConstFn
=> "constant function",
273 Mode
::StaticMut
| Mode
::Static
=> "static",
274 Mode
::Var
=> unreachable
!(),
278 fn check_static_mut_type(&self, e
: &hir
::Expr
) {
279 let node_ty
= self.tcx
.node_id_to_type(e
.id
);
280 let tcontents
= node_ty
.type_contents(self.tcx
);
282 let suffix
= if tcontents
.has_dtor() {
284 } else if tcontents
.owns_owned() {
290 span_err
!(self.tcx
.sess
, e
.span
, E0397
,
291 "mutable statics are not allowed to have {}", suffix
);
294 fn check_static_type(&self, e
: &hir
::Expr
) {
295 let ty
= self.tcx
.node_id_to_type(e
.id
);
296 let infcx
= infer
::new_infer_ctxt(self.tcx
, &self.tcx
.tables
, None
, false);
297 let cause
= traits
::ObligationCause
::new(e
.span
, e
.id
, traits
::SharedStatic
);
298 let mut fulfill_cx
= infcx
.fulfillment_cx
.borrow_mut();
299 fulfill_cx
.register_builtin_bound(&infcx
, ty
, ty
::BoundSync
, cause
);
300 match fulfill_cx
.select_all_or_error(&infcx
) {
303 traits
::report_fulfillment_errors(&infcx
, errors
);
309 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for CheckCrateVisitor
<'a
, 'tcx
> {
310 fn visit_item(&mut self, i
: &hir
::Item
) {
311 debug
!("visit_item(item={})", self.tcx
.map
.node_to_string(i
.id
));
312 assert_eq
!(self.mode
, Mode
::Var
);
314 hir
::ItemStatic(_
, hir
::MutImmutable
, ref expr
) => {
315 self.check_static_type(&**expr
);
316 self.global_expr(Mode
::Static
, &**expr
);
318 hir
::ItemStatic(_
, hir
::MutMutable
, ref expr
) => {
319 self.check_static_mut_type(&**expr
);
320 self.global_expr(Mode
::StaticMut
, &**expr
);
322 hir
::ItemConst(_
, ref expr
) => {
323 self.global_expr(Mode
::Const
, &**expr
);
325 hir
::ItemEnum(ref enum_definition
, _
) => {
326 for var
in &enum_definition
.variants
{
327 if let Some(ref ex
) = var
.node
.disr_expr
{
328 self.global_expr(Mode
::Const
, &**ex
);
333 intravisit
::walk_item(self, i
);
338 fn visit_trait_item(&mut self, t
: &'v hir
::TraitItem
) {
340 hir
::ConstTraitItem(_
, ref default) => {
341 if let Some(ref expr
) = *default {
342 self.global_expr(Mode
::Const
, &*expr
);
344 intravisit
::walk_trait_item(self, t
);
347 _
=> self.with_mode(Mode
::Var
, |v
| intravisit
::walk_trait_item(v
, t
)),
351 fn visit_impl_item(&mut self, i
: &'v hir
::ImplItem
) {
353 hir
::ImplItemKind
::Const(_
, ref expr
) => {
354 self.global_expr(Mode
::Const
, &*expr
);
356 _
=> self.with_mode(Mode
::Var
, |v
| intravisit
::walk_impl_item(v
, i
)),
360 fn visit_fn(&mut self,
365 fn_id
: ast
::NodeId
) {
366 self.fn_like(fk
, fd
, b
, s
, fn_id
);
369 fn visit_pat(&mut self, p
: &hir
::Pat
) {
371 hir
::PatLit(ref lit
) => {
372 self.global_expr(Mode
::Const
, &**lit
);
374 hir
::PatRange(ref start
, ref end
) => {
375 self.global_expr(Mode
::Const
, &**start
);
376 self.global_expr(Mode
::Const
, &**end
);
378 match const_eval
::compare_lit_exprs(self.tcx
, start
, end
) {
379 Some(Ordering
::Less
) |
380 Some(Ordering
::Equal
) => {}
381 Some(Ordering
::Greater
) => {
382 span_err
!(self.tcx
.sess
, start
.span
, E0030
,
383 "lower range bound must be less than or equal to upper");
386 self.tcx
.sess
.delay_span_bug(start
.span
,
387 "non-constant path in constant expr");
391 _
=> intravisit
::walk_pat(self, p
)
395 fn visit_block(&mut self, block
: &hir
::Block
) {
396 // Check all statements in the block
397 for stmt
in &block
.stmts
{
398 let span
= match stmt
.node
{
399 hir
::StmtDecl(ref decl
, _
) => {
401 hir
::DeclLocal(_
) => decl
.span
,
403 // Item statements are allowed
404 hir
::DeclItem(_
) => continue
407 hir
::StmtExpr(ref expr
, _
) => expr
.span
,
408 hir
::StmtSemi(ref semi
, _
) => semi
.span
,
410 self.add_qualif(ConstQualif
::NOT_CONST
);
411 if self.mode
!= Mode
::Var
{
412 span_err
!(self.tcx
.sess
, span
, E0016
,
413 "blocks in {}s are limited to items and \
414 tail expressions", self.msg());
417 intravisit
::walk_block(self, block
);
420 fn visit_expr(&mut self, ex
: &hir
::Expr
) {
421 let mut outer
= self.qualif
;
422 self.qualif
= ConstQualif
::empty();
424 let node_ty
= self.tcx
.node_id_to_type(ex
.id
);
425 check_expr(self, ex
, node_ty
);
426 check_adjustments(self, ex
);
428 // Special-case some expressions to avoid certain flags bubbling up.
430 hir
::ExprCall(ref callee
, ref args
) => {
432 self.visit_expr(&**arg
)
435 let inner
= self.qualif
;
436 self.visit_expr(&**callee
);
437 // The callee's size doesn't count in the call.
438 let added
= self.qualif
- inner
;
439 self.qualif
= inner
| (added
- ConstQualif
::NON_ZERO_SIZED
);
441 hir
::ExprRepeat(ref element
, _
) => {
442 self.visit_expr(&**element
);
443 // The count is checked elsewhere (typeck).
444 let count
= match node_ty
.sty
{
445 ty
::TyArray(_
, n
) => n
,
448 // [element; 0] is always zero-sized.
450 self.qualif
.remove(ConstQualif
::NON_ZERO_SIZED
| ConstQualif
::PREFER_IN_PLACE
);
453 hir
::ExprMatch(ref discr
, ref arms
, _
) => {
454 // Compute the most demanding borrow from all the arms'
455 // patterns and set that on the discriminator.
456 let mut borrow
= None
;
457 for pat
in arms
.iter().flat_map(|arm
| &arm
.pats
) {
458 let pat_borrow
= self.rvalue_borrows
.remove(&pat
.id
);
459 match (borrow
, pat_borrow
) {
460 (None
, _
) | (_
, Some(hir
::MutMutable
)) => {
466 if let Some(mutbl
) = borrow
{
467 self.record_borrow(discr
.id
, mutbl
);
469 intravisit
::walk_expr(self, ex
);
471 // Division by zero and overflow checking.
472 hir
::ExprBinary(op
, _
, _
) => {
473 intravisit
::walk_expr(self, ex
);
474 let div_or_rem
= op
.node
== hir
::BiDiv
|| op
.node
== hir
::BiRem
;
476 ty
::TyUint(_
) | ty
::TyInt(_
) if div_or_rem
=> {
477 if !self.qualif
.intersects(ConstQualif
::NOT_CONST
) {
478 match const_eval
::eval_const_expr_partial(
479 self.tcx
, ex
, ExprTypeChecked
, None
) {
481 Err(ConstEvalErr { kind: IndexOpFeatureGated, ..}
) => {}
,
483 self.tcx
.sess
.add_lint(::lint
::builtin
::CONST_ERR
, ex
.id
,
485 msg
.description().into_owned())
493 _
=> intravisit
::walk_expr(self, ex
)
496 // Handle borrows on (or inside the autorefs of) this expression.
497 match self.rvalue_borrows
.remove(&ex
.id
) {
498 Some(hir
::MutImmutable
) => {
499 // Constants cannot be borrowed if they contain interior mutability as
500 // it means that our "silent insertion of statics" could change
501 // initializer values (very bad).
502 // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
503 // propagated from another error, so erroring again would be just noise.
504 let tc
= node_ty
.type_contents(self.tcx
);
505 if self.qualif
.intersects(ConstQualif
::MUTABLE_MEM
) && tc
.interior_unsafe() {
506 outer
= outer
| ConstQualif
::NOT_CONST
;
507 if self.mode
!= Mode
::Var
{
508 span_err
!(self.tcx
.sess
, ex
.span
, E0492
,
509 "cannot borrow a constant which contains \
510 interior mutability, create a static instead");
513 // If the reference has to be 'static, avoid in-place initialization
514 // as that will end up pointing to the stack instead.
515 if !self.qualif
.intersects(ConstQualif
::NON_STATIC_BORROWS
) {
516 self.qualif
= self.qualif
- ConstQualif
::PREFER_IN_PLACE
;
517 self.add_qualif(ConstQualif
::HAS_STATIC_BORROWS
);
520 Some(hir
::MutMutable
) => {
521 // `&mut expr` means expr could be mutated, unless it's zero-sized.
522 if self.qualif
.intersects(ConstQualif
::NON_ZERO_SIZED
) {
523 if self.mode
== Mode
::Var
{
524 outer
= outer
| ConstQualif
::NOT_CONST
;
525 self.add_qualif(ConstQualif
::MUTABLE_MEM
);
527 span_err
!(self.tcx
.sess
, ex
.span
, E0017
,
528 "references in {}s may only refer \
529 to immutable values", self.msg())
532 if !self.qualif
.intersects(ConstQualif
::NON_STATIC_BORROWS
) {
533 self.add_qualif(ConstQualif
::HAS_STATIC_BORROWS
);
538 self.tcx
.const_qualif_map
.borrow_mut().insert(ex
.id
, self.qualif
);
539 // Don't propagate certain flags.
540 self.qualif
= outer
| (self.qualif
- ConstQualif
::HAS_STATIC_BORROWS
);
544 /// This function is used to enforce the constraints on
545 /// const/static items. It walks through the *value*
546 /// of the item walking down the expression and evaluating
547 /// every nested expression. If the expression is not part
548 /// of a const/static item, it is qualified for promotion
549 /// instead of producing errors.
550 fn check_expr
<'a
, 'tcx
>(v
: &mut CheckCrateVisitor
<'a
, 'tcx
>,
551 e
: &hir
::Expr
, node_ty
: Ty
<'tcx
>) {
553 ty
::TyStruct(def
, _
) |
554 ty
::TyEnum(def
, _
) if def
.has_dtor() => {
555 v
.add_qualif(ConstQualif
::NEEDS_DROP
);
556 if v
.mode
!= Mode
::Var
{
557 span_err
!(v
.tcx
.sess
, e
.span
, E0493
,
558 "{}s are not allowed to have destructors",
565 let method_call
= ty
::MethodCall
::expr(e
.id
);
568 hir
::ExprBinary(..) |
569 hir
::ExprIndex(..) if v
.tcx
.tables
.borrow().method_map
.contains_key(&method_call
) => {
570 v
.add_qualif(ConstQualif
::NOT_CONST
);
571 if v
.mode
!= Mode
::Var
{
572 span_err
!(v
.tcx
.sess
, e
.span
, E0011
,
573 "user-defined operators are not allowed in {}s", v
.msg());
577 v
.add_qualif(ConstQualif
::NOT_CONST
);
578 if v
.mode
!= Mode
::Var
{
579 span_err
!(v
.tcx
.sess
, e
.span
, E0010
,
580 "allocations are not allowed in {}s", v
.msg());
583 hir
::ExprUnary(op
, ref inner
) => {
584 match v
.tcx
.node_id_to_type(inner
.id
).sty
{
586 assert
!(op
== hir
::UnDeref
);
588 v
.add_qualif(ConstQualif
::NOT_CONST
);
589 if v
.mode
!= Mode
::Var
{
590 span_err
!(v
.tcx
.sess
, e
.span
, E0396
,
591 "raw pointers cannot be dereferenced in {}s", v
.msg());
597 hir
::ExprBinary(op
, ref lhs
, _
) => {
598 match v
.tcx
.node_id_to_type(lhs
.id
).sty
{
600 assert
!(op
.node
== hir
::BiEq
|| op
.node
== hir
::BiNe
||
601 op
.node
== hir
::BiLe
|| op
.node
== hir
::BiLt
||
602 op
.node
== hir
::BiGe
|| op
.node
== hir
::BiGt
);
604 v
.add_qualif(ConstQualif
::NOT_CONST
);
605 if v
.mode
!= Mode
::Var
{
606 span_err
!(v
.tcx
.sess
, e
.span
, E0395
,
607 "raw pointers cannot be compared in {}s", v
.msg());
613 hir
::ExprCast(ref from
, _
) => {
614 debug
!("Checking const cast(id={})", from
.id
);
615 match v
.tcx
.cast_kinds
.borrow().get(&from
.id
) {
616 None
=> v
.tcx
.sess
.span_bug(e
.span
, "no kind for cast"),
617 Some(&CastKind
::PtrAddrCast
) | Some(&CastKind
::FnPtrAddrCast
) => {
618 v
.add_qualif(ConstQualif
::NOT_CONST
);
619 if v
.mode
!= Mode
::Var
{
620 span_err
!(v
.tcx
.sess
, e
.span
, E0018
,
621 "raw pointers cannot be cast to integers in {}s", v
.msg());
627 hir
::ExprPath(..) => {
628 let def
= v
.tcx
.def_map
.borrow().get(&e
.id
).map(|d
| d
.full_def());
630 Some(def
::DefVariant(_
, _
, _
)) => {
631 // Count the discriminator or function pointer.
632 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
634 Some(def
::DefStruct(_
)) => {
635 if let ty
::TyBareFn(..) = node_ty
.sty
{
636 // Count the function pointer.
637 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
640 Some(def
::DefFn(..)) | Some(def
::DefMethod(..)) => {
641 // Count the function pointer.
642 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
644 Some(def
::DefStatic(..)) => {
646 Mode
::Static
| Mode
::StaticMut
=> {}
647 Mode
::Const
| Mode
::ConstFn
=> {
648 span_err
!(v
.tcx
.sess
, e
.span
, E0013
,
649 "{}s cannot refer to other statics, insert \
650 an intermediate constant instead", v
.msg());
652 Mode
::Var
=> v
.add_qualif(ConstQualif
::NOT_CONST
)
655 Some(def
::DefConst(did
)) |
656 Some(def
::DefAssociatedConst(did
)) => {
657 if let Some(expr
) = const_eval
::lookup_const_by_id(v
.tcx
, did
,
659 let inner
= v
.global_expr(Mode
::Const
, expr
);
662 v
.tcx
.sess
.span_bug(e
.span
,
663 "DefConst or DefAssociatedConst \
664 doesn't point to a constant");
667 Some(def
::DefLocal(..)) if v
.mode
== Mode
::ConstFn
=> {
668 // Sadly, we can't determine whether the types are zero-sized.
669 v
.add_qualif(ConstQualif
::NOT_CONST
| ConstQualif
::NON_ZERO_SIZED
);
672 v
.add_qualif(ConstQualif
::NOT_CONST
);
673 if v
.mode
!= Mode
::Var
{
674 debug
!("(checking const) found bad def: {:?}", def
);
675 span_err
!(v
.tcx
.sess
, e
.span
, E0014
,
676 "paths in {}s may only refer to constants \
677 or functions", v
.msg());
682 hir
::ExprCall(ref callee
, _
) => {
683 let mut callee
= &**callee
;
685 callee
= match callee
.node
{
686 hir
::ExprBlock(ref block
) => match block
.expr
{
687 Some(ref tail
) => &**tail
,
693 let def
= v
.tcx
.def_map
.borrow().get(&callee
.id
).map(|d
| d
.full_def());
694 let is_const
= match def
{
695 Some(def
::DefStruct(..)) => true,
696 Some(def
::DefVariant(..)) => {
697 // Count the discriminator.
698 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
701 Some(def
::DefFn(did
, _
)) => {
702 v
.handle_const_fn_call(e
, did
, node_ty
)
704 Some(def
::DefMethod(did
)) => {
705 match v
.tcx
.impl_or_trait_item(did
).container() {
706 ty
::ImplContainer(_
) => {
707 v
.handle_const_fn_call(e
, did
, node_ty
)
709 ty
::TraitContainer(_
) => false
715 v
.add_qualif(ConstQualif
::NOT_CONST
);
716 if v
.mode
!= Mode
::Var
{
717 fn span_limited_call_error(tcx
: &ty
::ctxt
, span
: Span
, s
: &str) {
718 span_err
!(tcx
.sess
, span
, E0015
, "{}", s
);
721 // FIXME(#24111) Remove this check when const fn stabilizes
722 if let UnstableFeatures
::Disallow
= v
.tcx
.sess
.opts
.unstable_features
{
723 span_limited_call_error(&v
.tcx
, e
.span
,
724 &format
!("function calls in {}s are limited to \
725 struct and enum constructors",
727 v
.tcx
.sess
.span_note(e
.span
,
728 "a limited form of compile-time function \
729 evaluation is available on a nightly \
730 compiler via `const fn`");
732 span_limited_call_error(&v
.tcx
, e
.span
,
733 &format
!("function calls in {}s are limited \
734 to constant functions, \
735 struct and enum constructors",
741 hir
::ExprMethodCall(..) => {
742 let method
= v
.tcx
.tables
.borrow().method_map
[&method_call
];
743 let is_const
= match v
.tcx
.impl_or_trait_item(method
.def_id
).container() {
744 ty
::ImplContainer(_
) => v
.handle_const_fn_call(e
, method
.def_id
, node_ty
),
745 ty
::TraitContainer(_
) => false
748 v
.add_qualif(ConstQualif
::NOT_CONST
);
749 if v
.mode
!= Mode
::Var
{
750 span_err
!(v
.tcx
.sess
, e
.span
, E0378
,
751 "method calls in {}s are limited to \
752 constant inherent methods", v
.msg());
756 hir
::ExprStruct(..) => {
757 let did
= v
.tcx
.def_map
.borrow().get(&e
.id
).map(|def
| def
.def_id());
758 if did
== v
.tcx
.lang_items
.unsafe_cell_type() {
759 v
.add_qualif(ConstQualif
::MUTABLE_MEM
);
764 hir
::ExprAddrOf(..) => {
765 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
768 hir
::ExprRepeat(..) => {
769 v
.add_qualif(ConstQualif
::PREFER_IN_PLACE
);
772 hir
::ExprClosure(..) => {
773 // Paths in constant contexts cannot refer to local variables,
774 // as there are none, and thus closures can't have upvars there.
775 if v
.tcx
.with_freevars(e
.id
, |fv
| !fv
.is_empty()) {
776 assert
!(v
.mode
== Mode
::Var
,
777 "global closures can't capture anything");
778 v
.add_qualif(ConstQualif
::NOT_CONST
);
785 hir
::ExprTupField(..) |
787 hir
::ExprTup(..) => {}
789 // Conditional control flow (possible to implement).
793 // Loops (not very meaningful in constants).
797 // More control flow (also not very meaningful).
802 // Miscellaneous expressions that could be implemented.
805 // Expressions with side-effects.
806 hir
::ExprAssign(..) |
807 hir
::ExprAssignOp(..) |
808 hir
::ExprInlineAsm(_
) => {
809 v
.add_qualif(ConstQualif
::NOT_CONST
);
810 if v
.mode
!= Mode
::Var
{
811 span_err
!(v
.tcx
.sess
, e
.span
, E0019
,
812 "{} contains unimplemented expression type", v
.msg());
818 /// Check the adjustments of an expression
819 fn check_adjustments
<'a
, 'tcx
>(v
: &mut CheckCrateVisitor
<'a
, 'tcx
>, e
: &hir
::Expr
) {
820 match v
.tcx
.tables
.borrow().adjustments
.get(&e
.id
) {
822 Some(&ty
::adjustment
::AdjustReifyFnPointer
) |
823 Some(&ty
::adjustment
::AdjustUnsafeFnPointer
) => {}
825 Some(&ty
::adjustment
::AdjustDerefRef(
826 ty
::adjustment
::AutoDerefRef { autoderefs, .. }
828 if (0..autoderefs
as u32).any(|autoderef
| {
829 v
.tcx
.is_overloaded_autoderef(e
.id
, autoderef
)
831 v
.add_qualif(ConstQualif
::NOT_CONST
);
832 if v
.mode
!= Mode
::Var
{
833 span_err
!(v
.tcx
.sess
, e
.span
, E0400
,
834 "user-defined dereference operators are not allowed in {}s",
842 pub fn check_crate(tcx
: &ty
::ctxt
) {
843 tcx
.map
.krate().visit_all_items(&mut CheckCrateVisitor
{
846 qualif
: ConstQualif
::NOT_CONST
,
847 rvalue_borrows
: NodeMap()
850 tcx
.sess
.abort_if_errors();
853 impl<'a
, 'tcx
> euv
::Delegate
<'tcx
> for CheckCrateVisitor
<'a
, 'tcx
> {
854 fn consume(&mut self,
855 _consume_id
: ast
::NodeId
,
858 _mode
: euv
::ConsumeMode
) {
862 Categorization
::StaticItem
=> {
863 if self.mode
!= Mode
::Var
{
864 // statics cannot be consumed by value at any time, that would imply
865 // that they're an initializer (what a const is for) or kept in sync
866 // over time (not feasible), so deny it outright.
867 span_err
!(self.tcx
.sess
, consume_span
, E0394
,
868 "cannot refer to other statics by value, use the \
869 address-of operator or a constant instead");
873 Categorization
::Deref(ref cmt
, _
, _
) |
874 Categorization
::Downcast(ref cmt
, _
) |
875 Categorization
::Interior(ref cmt
, _
) => cur
= cmt
,
877 Categorization
::Rvalue(..) |
878 Categorization
::Upvar(..) |
879 Categorization
::Local(..) => break
884 borrow_id
: ast
::NodeId
,
887 _loan_region
: ty
::Region
,
889 loan_cause
: euv
::LoanCause
)
891 // Kind of hacky, but we allow Unsafe coercions in constants.
892 // These occur when we convert a &T or *T to a *U, as well as
893 // when making a thin pointer (e.g., `*T`) into a fat pointer
896 euv
::LoanCause
::AutoUnsafe
=> {
903 let mut is_interior
= false;
906 Categorization
::Rvalue(..) => {
907 if loan_cause
== euv
::MatchDiscriminant
{
908 // Ignore the dummy immutable borrow created by EUV.
911 let mutbl
= bk
.to_mutbl_lossy();
912 if mutbl
== hir
::MutMutable
&& self.mode
== Mode
::StaticMut
{
913 // Mutable slices are the only `&mut` allowed in
914 // globals, but only in `static mut`, nowhere else.
915 // FIXME: This exception is really weird... there isn't
916 // any fundamental reason to restrict this based on
917 // type of the expression. `&mut [1]` has exactly the
918 // same representation as &mut 1.
920 ty
::TyArray(_
, _
) | ty
::TySlice(_
) => break,
924 self.record_borrow(borrow_id
, mutbl
);
927 Categorization
::StaticItem
=> {
928 if is_interior
&& self.mode
!= Mode
::Var
{
929 // Borrowed statics can specifically *only* have their address taken,
930 // not any number of other borrows such as borrowing fields, reading
931 // elements of an array, etc.
932 span_err
!(self.tcx
.sess
, borrow_span
, E0494
,
933 "cannot refer to the interior of another \
934 static, use a constant instead");
938 Categorization
::Deref(ref cmt
, _
, _
) |
939 Categorization
::Downcast(ref cmt
, _
) |
940 Categorization
::Interior(ref cmt
, _
) => {
945 Categorization
::Upvar(..) |
946 Categorization
::Local(..) => break
951 fn decl_without_init(&mut self,
955 _assignment_id
: ast
::NodeId
,
956 _assignment_span
: Span
,
957 _assignee_cmt
: mc
::cmt
,
958 _mode
: euv
::MutateMode
) {}
960 fn matched_pat(&mut self,
963 _
: euv
::MatchMode
) {}
965 fn consume_pat(&mut self,
966 _consume_pat
: &hir
::Pat
,
968 _mode
: euv
::ConsumeMode
) {}