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 rustc
::dep_graph
::DepNode
;
28 use rustc
::ty
::cast
::CastKind
;
29 use rustc_const_eval
::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs}
;
30 use rustc_const_eval
::{eval_const_expr_partial, lookup_const_by_id}
;
31 use rustc_const_eval
::ErrKind
::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math}
;
32 use rustc_const_eval
::ErrKind
::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath}
;
33 use rustc_const_eval
::ErrKind
::UnresolvedPath
;
34 use rustc_const_eval
::EvalHint
::ExprTypeChecked
;
35 use rustc_const_math
::{ConstMathErr, Op}
;
36 use rustc
::hir
::def
::Def
;
37 use rustc
::hir
::def_id
::DefId
;
38 use rustc
::middle
::expr_use_visitor
as euv
;
39 use rustc
::middle
::mem_categorization
as mc
;
40 use rustc
::middle
::mem_categorization
::Categorization
;
41 use rustc
::ty
::{self, Ty, TyCtxt}
;
42 use rustc
::traits
::Reveal
;
43 use rustc
::util
::common
::ErrorReported
;
44 use rustc
::util
::nodemap
::NodeMap
;
45 use rustc
::middle
::const_qualif
::ConstQualif
;
46 use rustc
::lint
::builtin
::CONST_ERR
;
48 use rustc
::hir
::{self, PatKind}
;
51 use rustc
::hir
::intravisit
::{self, FnKind, Visitor}
;
53 use std
::collections
::hash_map
::Entry
;
54 use std
::cmp
::Ordering
;
56 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
63 // An expression that occurs outside of any constant context
64 // (i.e. `const`, `static`, array lengths, etc.). The value
65 // can be variable at runtime, but will be promotable to
66 // static memory if we can prove it is actually constant.
70 struct CheckCrateVisitor
<'a
, 'tcx
: 'a
> {
71 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
74 rvalue_borrows
: NodeMap
<hir
::Mutability
>,
77 impl<'a
, 'gcx
> CheckCrateVisitor
<'a
, 'gcx
> {
78 fn with_mode
<F
, R
>(&mut self, mode
: Mode
, f
: F
) -> R
79 where F
: FnOnce(&mut CheckCrateVisitor
<'a
, 'gcx
>) -> R
81 let (old_mode
, old_qualif
) = (self.mode
, self.qualif
);
83 self.qualif
= ConstQualif
::empty();
86 self.qualif
= old_qualif
;
90 fn with_euv
<F
, R
>(&mut self, item_id
: Option
<ast
::NodeId
>, f
: F
) -> R
91 where F
: for<'b
, 'tcx
> FnOnce(&mut euv
::ExprUseVisitor
<'b
, 'gcx
, 'tcx
>) -> R
93 let param_env
= match item_id
{
94 Some(item_id
) => ty
::ParameterEnvironment
::for_item(self.tcx
, item_id
),
95 None
=> self.tcx
.empty_parameter_environment(),
99 .infer_ctxt(None
, Some(param_env
), Reveal
::NotSpecializable
)
100 .enter(|infcx
| f(&mut euv
::ExprUseVisitor
::new(self, &infcx
)))
103 fn global_expr(&mut self, mode
: Mode
, expr
: &hir
::Expr
) -> ConstQualif
{
104 assert
!(mode
!= Mode
::Var
);
105 match self.tcx
.const_qualif_map
.borrow_mut().entry(expr
.id
) {
106 Entry
::Occupied(entry
) => return *entry
.get(),
107 Entry
::Vacant(entry
) => {
108 // Prevent infinite recursion on re-entry.
109 entry
.insert(ConstQualif
::empty());
112 if let Err(err
) = eval_const_expr_partial(self.tcx
, expr
, ExprTypeChecked
, None
) {
114 UnimplementedConstVal(_
) => {}
115 IndexOpFeatureGated
=> {}
116 ErroneousReferencedConstant(_
) => {}
118 self.tcx
.sess
.add_lint(CONST_ERR
,
121 format
!("constant evaluation error: {}. This will \
122 become a HARD ERROR in the future",
123 err
.description().into_oneline()))
127 self.with_mode(mode
, |this
| {
128 this
.with_euv(None
, |euv
| euv
.consume_expr(expr
));
129 this
.visit_expr(expr
);
134 fn fn_like(&mut self,
141 match self.tcx
.const_qualif_map
.borrow_mut().entry(fn_id
) {
142 Entry
::Occupied(entry
) => return *entry
.get(),
143 Entry
::Vacant(entry
) => {
144 // Prevent infinite recursion on re-entry.
145 entry
.insert(ConstQualif
::empty());
149 let mode
= match fk
{
150 FnKind
::ItemFn(_
, _
, _
, hir
::Constness
::Const
, _
, _
, _
) => Mode
::ConstFn
,
151 FnKind
::Method(_
, m
, _
, _
) => {
152 if m
.constness
== hir
::Constness
::Const
{
161 let qualif
= self.with_mode(mode
, |this
| {
162 this
.with_euv(Some(fn_id
), |euv
| euv
.walk_fn(fd
, b
));
163 intravisit
::walk_fn(this
, fk
, fd
, b
, s
, fn_id
);
167 // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
168 // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
169 let qualif
= qualif
& (ConstQualif
::NON_ZERO_SIZED
| ConstQualif
::PREFER_IN_PLACE
);
171 self.tcx
.const_qualif_map
.borrow_mut().insert(fn_id
, qualif
);
175 fn add_qualif(&mut self, qualif
: ConstQualif
) {
176 self.qualif
= self.qualif
| qualif
;
179 /// Returns true if the call is to a const fn or method.
180 fn handle_const_fn_call(&mut self, _expr
: &hir
::Expr
, def_id
: DefId
, ret_ty
: Ty
<'gcx
>) -> bool
{
181 if let Some(fn_like
) = lookup_const_fn_by_id(self.tcx
, def_id
) {
182 let qualif
= self.fn_like(fn_like
.kind(),
187 self.add_qualif(qualif
);
189 if ret_ty
.type_contents(self.tcx
).interior_unsafe() {
190 self.add_qualif(ConstQualif
::MUTABLE_MEM
);
199 fn record_borrow(&mut self, id
: ast
::NodeId
, mutbl
: hir
::Mutability
) {
200 match self.rvalue_borrows
.entry(id
) {
201 Entry
::Occupied(mut entry
) => {
202 // Merge the two borrows, taking the most demanding
203 // one, mutability-wise.
204 if mutbl
== hir
::MutMutable
{
208 Entry
::Vacant(entry
) => {
215 impl<'a
, 'tcx
, 'v
> Visitor
<'v
> for CheckCrateVisitor
<'a
, 'tcx
> {
216 fn visit_item(&mut self, i
: &hir
::Item
) {
217 debug
!("visit_item(item={})", self.tcx
.map
.node_to_string(i
.id
));
218 assert_eq
!(self.mode
, Mode
::Var
);
220 hir
::ItemStatic(_
, hir
::MutImmutable
, ref expr
) => {
221 self.global_expr(Mode
::Static
, &expr
);
223 hir
::ItemStatic(_
, hir
::MutMutable
, ref expr
) => {
224 self.global_expr(Mode
::StaticMut
, &expr
);
226 hir
::ItemConst(_
, ref expr
) => {
227 self.global_expr(Mode
::Const
, &expr
);
229 hir
::ItemEnum(ref enum_definition
, _
) => {
230 for var
in &enum_definition
.variants
{
231 if let Some(ref ex
) = var
.node
.disr_expr
{
232 self.global_expr(Mode
::Const
, &ex
);
237 intravisit
::walk_item(self, i
);
242 fn visit_trait_item(&mut self, t
: &'v hir
::TraitItem
) {
244 hir
::ConstTraitItem(_
, ref default) => {
245 if let Some(ref expr
) = *default {
246 self.global_expr(Mode
::Const
, &expr
);
248 intravisit
::walk_trait_item(self, t
);
251 _
=> self.with_mode(Mode
::Var
, |v
| intravisit
::walk_trait_item(v
, t
)),
255 fn visit_impl_item(&mut self, i
: &'v hir
::ImplItem
) {
257 hir
::ImplItemKind
::Const(_
, ref expr
) => {
258 self.global_expr(Mode
::Const
, &expr
);
260 _
=> self.with_mode(Mode
::Var
, |v
| intravisit
::walk_impl_item(v
, i
)),
264 fn visit_fn(&mut self,
269 fn_id
: ast
::NodeId
) {
270 self.fn_like(fk
, fd
, b
, s
, fn_id
);
273 fn visit_pat(&mut self, p
: &hir
::Pat
) {
275 PatKind
::Lit(ref lit
) => {
276 self.global_expr(Mode
::Const
, &lit
);
278 PatKind
::Range(ref start
, ref end
) => {
279 self.global_expr(Mode
::Const
, &start
);
280 self.global_expr(Mode
::Const
, &end
);
282 match compare_lit_exprs(self.tcx
, p
.span
, start
, end
) {
284 Ok(Ordering
::Equal
) => {}
285 Ok(Ordering
::Greater
) => {
286 span_err
!(self.tcx
.sess
,
289 "lower range bound must be less than or equal to upper");
291 Err(ErrorReported
) => {}
294 _
=> intravisit
::walk_pat(self, p
),
298 fn visit_block(&mut self, block
: &hir
::Block
) {
299 // Check all statements in the block
300 for stmt
in &block
.stmts
{
302 hir
::StmtDecl(ref decl
, _
) => {
304 hir
::DeclLocal(_
) => {}
305 // Item statements are allowed
306 hir
::DeclItem(_
) => continue,
309 hir
::StmtExpr(_
, _
) => {}
310 hir
::StmtSemi(_
, _
) => {}
312 self.add_qualif(ConstQualif
::NOT_CONST
);
314 intravisit
::walk_block(self, block
);
317 fn visit_expr(&mut self, ex
: &hir
::Expr
) {
318 let mut outer
= self.qualif
;
319 self.qualif
= ConstQualif
::empty();
321 let node_ty
= self.tcx
.node_id_to_type(ex
.id
);
322 check_expr(self, ex
, node_ty
);
323 check_adjustments(self, ex
);
325 // Special-case some expressions to avoid certain flags bubbling up.
327 hir
::ExprCall(ref callee
, ref args
) => {
329 self.visit_expr(&arg
)
332 let inner
= self.qualif
;
333 self.visit_expr(&callee
);
334 // The callee's size doesn't count in the call.
335 let added
= self.qualif
- inner
;
336 self.qualif
= inner
| (added
- ConstQualif
::NON_ZERO_SIZED
);
338 hir
::ExprRepeat(ref element
, _
) => {
339 self.visit_expr(&element
);
340 // The count is checked elsewhere (typeck).
341 let count
= match node_ty
.sty
{
342 ty
::TyArray(_
, n
) => n
,
345 // [element; 0] is always zero-sized.
347 self.qualif
.remove(ConstQualif
::NON_ZERO_SIZED
| ConstQualif
::PREFER_IN_PLACE
);
350 hir
::ExprMatch(ref discr
, ref arms
, _
) => {
351 // Compute the most demanding borrow from all the arms'
352 // patterns and set that on the discriminator.
353 let mut borrow
= None
;
354 for pat
in arms
.iter().flat_map(|arm
| &arm
.pats
) {
355 let pat_borrow
= self.rvalue_borrows
.remove(&pat
.id
);
356 match (borrow
, pat_borrow
) {
358 (_
, Some(hir
::MutMutable
)) => {
364 if let Some(mutbl
) = borrow
{
365 self.record_borrow(discr
.id
, mutbl
);
367 intravisit
::walk_expr(self, ex
);
369 _
=> intravisit
::walk_expr(self, ex
),
372 // Handle borrows on (or inside the autorefs of) this expression.
373 match self.rvalue_borrows
.remove(&ex
.id
) {
374 Some(hir
::MutImmutable
) => {
375 // Constants cannot be borrowed if they contain interior mutability as
376 // it means that our "silent insertion of statics" could change
377 // initializer values (very bad).
378 // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
379 // propagated from another error, so erroring again would be just noise.
380 let tc
= node_ty
.type_contents(self.tcx
);
381 if self.qualif
.intersects(ConstQualif
::MUTABLE_MEM
) && tc
.interior_unsafe() {
382 outer
= outer
| ConstQualif
::NOT_CONST
;
384 // If the reference has to be 'static, avoid in-place initialization
385 // as that will end up pointing to the stack instead.
386 if !self.qualif
.intersects(ConstQualif
::NON_STATIC_BORROWS
) {
387 self.qualif
= self.qualif
- ConstQualif
::PREFER_IN_PLACE
;
388 self.add_qualif(ConstQualif
::HAS_STATIC_BORROWS
);
391 Some(hir
::MutMutable
) => {
392 // `&mut expr` means expr could be mutated, unless it's zero-sized.
393 if self.qualif
.intersects(ConstQualif
::NON_ZERO_SIZED
) {
394 if self.mode
== Mode
::Var
{
395 outer
= outer
| ConstQualif
::NOT_CONST
;
396 self.add_qualif(ConstQualif
::MUTABLE_MEM
);
399 if !self.qualif
.intersects(ConstQualif
::NON_STATIC_BORROWS
) {
400 self.add_qualif(ConstQualif
::HAS_STATIC_BORROWS
);
406 if self.mode
== Mode
::Var
&& !self.qualif
.intersects(ConstQualif
::NOT_CONST
) {
407 match eval_const_expr_partial(self.tcx
, ex
, ExprTypeChecked
, None
) {
409 Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }
) |
410 Err(ConstEvalErr { kind: MiscCatchAll, .. }
) |
411 Err(ConstEvalErr { kind: MiscBinaryOp, .. }
) |
412 Err(ConstEvalErr { kind: NonConstPath, .. }
) |
413 Err(ConstEvalErr { kind: UnresolvedPath, .. }
) |
414 Err(ConstEvalErr { kind: ErroneousReferencedConstant(_), .. }
) |
415 Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), .. }
) |
416 Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), .. }
) |
417 Err(ConstEvalErr { kind: IndexOpFeatureGated, .. }
) => {}
419 self.tcx
.sess
.add_lint(CONST_ERR
,
422 msg
.description().into_oneline().into_owned())
427 self.tcx
.const_qualif_map
.borrow_mut().insert(ex
.id
, self.qualif
);
428 // Don't propagate certain flags.
429 self.qualif
= outer
| (self.qualif
- ConstQualif
::HAS_STATIC_BORROWS
);
433 /// This function is used to enforce the constraints on
434 /// const/static items. It walks through the *value*
435 /// of the item walking down the expression and evaluating
436 /// every nested expression. If the expression is not part
437 /// of a const/static item, it is qualified for promotion
438 /// instead of producing errors.
439 fn check_expr
<'a
, 'tcx
>(v
: &mut CheckCrateVisitor
<'a
, 'tcx
>, e
: &hir
::Expr
, node_ty
: Ty
<'tcx
>) {
441 ty
::TyStruct(def
, _
) |
442 ty
::TyEnum(def
, _
) if def
.has_dtor() => {
443 v
.add_qualif(ConstQualif
::NEEDS_DROP
);
448 let method_call
= ty
::MethodCall
::expr(e
.id
);
451 hir
::ExprBinary(..) |
452 hir
::ExprIndex(..) if v
.tcx
.tables
.borrow().method_map
.contains_key(&method_call
) => {
453 v
.add_qualif(ConstQualif
::NOT_CONST
);
456 v
.add_qualif(ConstQualif
::NOT_CONST
);
458 hir
::ExprUnary(op
, ref inner
) => {
459 match v
.tcx
.node_id_to_type(inner
.id
).sty
{
461 assert
!(op
== hir
::UnDeref
);
463 v
.add_qualif(ConstQualif
::NOT_CONST
);
468 hir
::ExprBinary(op
, ref lhs
, _
) => {
469 match v
.tcx
.node_id_to_type(lhs
.id
).sty
{
471 assert
!(op
.node
== hir
::BiEq
|| op
.node
== hir
::BiNe
||
472 op
.node
== hir
::BiLe
|| op
.node
== hir
::BiLt
||
473 op
.node
== hir
::BiGe
|| op
.node
== hir
::BiGt
);
475 v
.add_qualif(ConstQualif
::NOT_CONST
);
480 hir
::ExprCast(ref from
, _
) => {
481 debug
!("Checking const cast(id={})", from
.id
);
482 match v
.tcx
.cast_kinds
.borrow().get(&from
.id
) {
483 None
=> span_bug
!(e
.span
, "no kind for cast"),
484 Some(&CastKind
::PtrAddrCast
) | Some(&CastKind
::FnPtrAddrCast
) => {
485 v
.add_qualif(ConstQualif
::NOT_CONST
);
490 hir
::ExprPath(..) => {
491 match v
.tcx
.expect_def(e
.id
) {
492 Def
::Variant(..) => {
493 // Count the discriminator or function pointer.
494 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
497 if let ty
::TyFnDef(..) = node_ty
.sty
{
498 // Count the function pointer.
499 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
502 Def
::Fn(..) | Def
::Method(..) => {
503 // Count the function pointer.
504 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
508 Mode
::Static
| Mode
::StaticMut
=> {}
509 Mode
::Const
| Mode
::ConstFn
=> {}
510 Mode
::Var
=> v
.add_qualif(ConstQualif
::NOT_CONST
)
513 Def
::Const(did
) | Def
::AssociatedConst(did
) => {
514 let substs
= Some(v
.tcx
.node_id_item_substs(e
.id
).substs
);
515 if let Some((expr
, _
)) = lookup_const_by_id(v
.tcx
, did
, substs
) {
516 let inner
= v
.global_expr(Mode
::Const
, expr
);
520 Def
::Local(..) if v
.mode
== Mode
::ConstFn
=> {
521 // Sadly, we can't determine whether the types are zero-sized.
522 v
.add_qualif(ConstQualif
::NOT_CONST
| ConstQualif
::NON_ZERO_SIZED
);
525 v
.add_qualif(ConstQualif
::NOT_CONST
);
529 hir
::ExprCall(ref callee
, _
) => {
530 let mut callee
= &**callee
;
532 callee
= match callee
.node
{
533 hir
::ExprBlock(ref block
) => match block
.expr
{
534 Some(ref tail
) => &tail
,
540 // The callee is an arbitrary expression, it doesn't necessarily have a definition.
541 let is_const
= match v
.tcx
.expect_def_or_none(callee
.id
) {
542 Some(Def
::Struct(..)) => true,
543 Some(Def
::Variant(..)) => {
544 // Count the discriminator.
545 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
548 Some(Def
::Fn(did
)) => {
549 v
.handle_const_fn_call(e
, did
, node_ty
)
551 Some(Def
::Method(did
)) => {
552 match v
.tcx
.impl_or_trait_item(did
).container() {
553 ty
::ImplContainer(_
) => {
554 v
.handle_const_fn_call(e
, did
, node_ty
)
556 ty
::TraitContainer(_
) => false
562 v
.add_qualif(ConstQualif
::NOT_CONST
);
565 hir
::ExprMethodCall(..) => {
566 let method
= v
.tcx
.tables
.borrow().method_map
[&method_call
];
567 let is_const
= match v
.tcx
.impl_or_trait_item(method
.def_id
).container() {
568 ty
::ImplContainer(_
) => v
.handle_const_fn_call(e
, method
.def_id
, node_ty
),
569 ty
::TraitContainer(_
) => false
572 v
.add_qualif(ConstQualif
::NOT_CONST
);
575 hir
::ExprStruct(..) => {
576 // unsafe_cell_type doesn't necessarily exist with no_core
577 if Some(v
.tcx
.expect_def(e
.id
).def_id()) == v
.tcx
.lang_items
.unsafe_cell_type() {
578 v
.add_qualif(ConstQualif
::MUTABLE_MEM
);
583 hir
::ExprAddrOf(..) => {
584 v
.add_qualif(ConstQualif
::NON_ZERO_SIZED
);
587 hir
::ExprRepeat(..) => {
588 v
.add_qualif(ConstQualif
::PREFER_IN_PLACE
);
591 hir
::ExprClosure(..) => {
592 // Paths in constant contexts cannot refer to local variables,
593 // as there are none, and thus closures can't have upvars there.
594 if v
.tcx
.with_freevars(e
.id
, |fv
| !fv
.is_empty()) {
595 assert
!(v
.mode
== Mode
::Var
,
596 "global closures can't capture anything");
597 v
.add_qualif(ConstQualif
::NOT_CONST
);
604 hir
::ExprTupField(..) |
607 hir
::ExprTup(..) => {}
609 // Conditional control flow (possible to implement).
613 // Loops (not very meaningful in constants).
617 // More control flow (also not very meaningful).
622 // Expressions with side-effects.
623 hir
::ExprAssign(..) |
624 hir
::ExprAssignOp(..) |
625 hir
::ExprInlineAsm(..) => {
626 v
.add_qualif(ConstQualif
::NOT_CONST
);
631 /// Check the adjustments of an expression
632 fn check_adjustments
<'a
, 'tcx
>(v
: &mut CheckCrateVisitor
<'a
, 'tcx
>, e
: &hir
::Expr
) {
633 match v
.tcx
.tables
.borrow().adjustments
.get(&e
.id
) {
635 Some(&ty
::adjustment
::AdjustNeverToAny(..)) |
636 Some(&ty
::adjustment
::AdjustReifyFnPointer
) |
637 Some(&ty
::adjustment
::AdjustUnsafeFnPointer
) |
638 Some(&ty
::adjustment
::AdjustMutToConstPointer
) => {}
640 Some(&ty
::adjustment
::AdjustDerefRef(ty
::adjustment
::AutoDerefRef { autoderefs, .. }
)) => {
641 if (0..autoderefs
as u32)
642 .any(|autoderef
| v
.tcx
.is_overloaded_autoderef(e
.id
, autoderef
)) {
643 v
.add_qualif(ConstQualif
::NOT_CONST
);
649 pub fn check_crate
<'a
, 'tcx
>(tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>) {
650 tcx
.visit_all_items_in_krate(DepNode
::CheckConst
,
651 &mut CheckCrateVisitor
{
654 qualif
: ConstQualif
::NOT_CONST
,
655 rvalue_borrows
: NodeMap(),
657 tcx
.sess
.abort_if_errors();
660 impl<'a
, 'gcx
, 'tcx
> euv
::Delegate
<'tcx
> for CheckCrateVisitor
<'a
, 'gcx
> {
661 fn consume(&mut self,
662 _consume_id
: ast
::NodeId
,
665 _mode
: euv
::ConsumeMode
) {
669 Categorization
::StaticItem
=> {
672 Categorization
::Deref(ref cmt
, _
, _
) |
673 Categorization
::Downcast(ref cmt
, _
) |
674 Categorization
::Interior(ref cmt
, _
) => cur
= cmt
,
676 Categorization
::Rvalue(..) |
677 Categorization
::Upvar(..) |
678 Categorization
::Local(..) => break,
683 borrow_id
: ast
::NodeId
,
686 _loan_region
: ty
::Region
,
688 loan_cause
: euv
::LoanCause
) {
689 // Kind of hacky, but we allow Unsafe coercions in constants.
690 // These occur when we convert a &T or *T to a *U, as well as
691 // when making a thin pointer (e.g., `*T`) into a fat pointer
694 euv
::LoanCause
::AutoUnsafe
=> {
703 Categorization
::Rvalue(..) => {
704 if loan_cause
== euv
::MatchDiscriminant
{
705 // Ignore the dummy immutable borrow created by EUV.
708 let mutbl
= bk
.to_mutbl_lossy();
709 if mutbl
== hir
::MutMutable
&& self.mode
== Mode
::StaticMut
{
710 // Mutable slices are the only `&mut` allowed in
711 // globals, but only in `static mut`, nowhere else.
712 // FIXME: This exception is really weird... there isn't
713 // any fundamental reason to restrict this based on
714 // type of the expression. `&mut [1]` has exactly the
715 // same representation as &mut 1.
718 ty
::TySlice(_
) => break,
722 self.record_borrow(borrow_id
, mutbl
);
725 Categorization
::StaticItem
=> {
728 Categorization
::Deref(ref cmt
, _
, _
) |
729 Categorization
::Downcast(ref cmt
, _
) |
730 Categorization
::Interior(ref cmt
, _
) => {
734 Categorization
::Upvar(..) |
735 Categorization
::Local(..) => break,
740 fn decl_without_init(&mut self, _id
: ast
::NodeId
, _span
: Span
) {}
742 _assignment_id
: ast
::NodeId
,
743 _assignment_span
: Span
,
744 _assignee_cmt
: mc
::cmt
,
745 _mode
: euv
::MutateMode
) {
748 fn matched_pat(&mut self, _
: &hir
::Pat
, _
: mc
::cmt
, _
: euv
::MatchMode
) {}
750 fn consume_pat(&mut self, _consume_pat
: &hir
::Pat
, _cmt
: mc
::cmt
, _mode
: euv
::ConsumeMode
) {}