]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/place_ext.rs
5caba637ccc4abf1b7473d32e478d0da0d69daca
[rust.git] / src / librustc_mir / borrow_check / place_ext.rs
1 use rustc::hir;
2 use rustc::mir::ProjectionElem;
3 use rustc::mir::{Body, Place, PlaceBase, Mutability, Static, StaticKind};
4 use rustc::ty::{self, TyCtxt};
5 use crate::borrow_check::borrow_set::LocalsStateAtExit;
6
7 /// Extension methods for the `Place` type.
8 crate trait PlaceExt<'tcx> {
9     /// Returns `true` if we can safely ignore borrows of this place.
10     /// This is true whenever there is no action that the user can do
11     /// to the place `self` that would invalidate the borrow. This is true
12     /// for borrows of raw pointer dereferents as well as shared references.
13     fn ignore_borrow(
14         &self,
15         tcx: TyCtxt<'tcx>,
16         body: &Body<'tcx>,
17         locals_state_at_exit: &LocalsStateAtExit,
18     ) -> bool;
19 }
20
21 impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
22     fn ignore_borrow(
23         &self,
24         tcx: TyCtxt<'tcx>,
25         body: &Body<'tcx>,
26         locals_state_at_exit: &LocalsStateAtExit,
27     ) -> bool {
28         self.iterate(|place_base, place_projection| {
29             let ignore = match place_base {
30                 // If a local variable is immutable, then we only need to track borrows to guard
31                 // against two kinds of errors:
32                 // * The variable being dropped while still borrowed (e.g., because the fn returns
33                 //   a reference to a local variable)
34                 // * The variable being moved while still borrowed
35                 //
36                 // In particular, the variable cannot be mutated -- the "access checks" will fail --
37                 // so we don't have to worry about mutation while borrowed.
38                 PlaceBase::Local(index) => {
39                     match locals_state_at_exit {
40                         LocalsStateAtExit::AllAreInvalidated => false,
41                         LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
42                             let ignore = !has_storage_dead_or_moved.contains(*index) &&
43                                 body.local_decls[*index].mutability == Mutability::Not;
44                             debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
45                             ignore
46                         }
47                     }
48                 }
49                 PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) =>
50                     false,
51                 PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
52                     tcx.is_mutable_static(*def_id)
53                 }
54             };
55
56             for proj in place_projection {
57                 if proj.elem == ProjectionElem::Deref {
58                     let ty = Place::ty_from(place_base, &proj.base, body, tcx).ty;
59                     match ty.sty {
60                         // For both derefs of raw pointers and `&T`
61                         // references, the original path is `Copy` and
62                         // therefore not significant.  In particular,
63                         // there is nothing the user can do to the
64                         // original path that would invalidate the
65                         // newly created reference -- and if there
66                         // were, then the user could have copied the
67                         // original path into a new variable and
68                         // borrowed *that* one, leaving the original
69                         // path unborrowed.
70                         ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => return true,
71                         _ => {}
72                     }
73                 }
74             }
75
76             ignore
77         })
78     }
79 }