]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/borrow_check/place_ext.rs
Rollup merge of #57350 - folex:master, r=estebank
[rust.git] / src / librustc_mir / borrow_check / place_ext.rs
1 use rustc::hir;
2 use rustc::mir::ProjectionElem;
3 use rustc::mir::{Local, Mir, Place, Mutability};
4 use rustc::ty::{self, TyCtxt};
5 use 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         mir: &Mir<'tcx>,
17         locals_state_at_exit: &LocalsStateAtExit,
18         ) -> bool;
19
20     /// If this is a place like `x.f.g`, returns the local
21     /// `x`. Returns `None` if this is based in a static.
22     fn root_local(&self) -> Option<Local>;
23 }
24
25 impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
26     fn ignore_borrow(
27         &self,
28         tcx: TyCtxt<'_, '_, 'tcx>,
29         mir: &Mir<'tcx>,
30         locals_state_at_exit: &LocalsStateAtExit,
31     ) -> bool {
32         match self {
33             Place::Promoted(_) => false,
34
35             // If a local variable is immutable, then we only need to track borrows to guard
36             // against two kinds of errors:
37             // * The variable being dropped while still borrowed (e.g., because the fn returns
38             //   a reference to a local variable)
39             // * The variable being moved while still borrowed
40             //
41             // In particular, the variable cannot be mutated -- the "access checks" will fail --
42             // so we don't have to worry about mutation while borrowed.
43             Place::Local(index) => {
44                 match locals_state_at_exit {
45                     LocalsStateAtExit::AllAreInvalidated => false,
46                     LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
47                         let ignore = !has_storage_dead_or_moved.contains(*index) &&
48                             mir.local_decls[*index].mutability == Mutability::Not;
49                         debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
50                         ignore
51                     }
52                 }
53             }
54             Place::Static(static_) => {
55                 tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable)
56             }
57             Place::Projection(proj) => match proj.elem {
58                 ProjectionElem::Field(..)
59                 | ProjectionElem::Downcast(..)
60                 | ProjectionElem::Subslice { .. }
61                 | ProjectionElem::ConstantIndex { .. }
62                 | ProjectionElem::Index(_) => proj.base.ignore_borrow(
63                     tcx, mir, locals_state_at_exit),
64
65                 ProjectionElem::Deref => {
66                     let ty = proj.base.ty(mir, tcx).to_ty(tcx);
67                     match ty.sty {
68                         // For both derefs of raw pointers and `&T`
69                         // references, the original path is `Copy` and
70                         // therefore not significant.  In particular,
71                         // there is nothing the user can do to the
72                         // original path that would invalidate the
73                         // newly created reference -- and if there
74                         // were, then the user could have copied the
75                         // original path into a new variable and
76                         // borrowed *that* one, leaving the original
77                         // path unborrowed.
78                         ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => true,
79                         _ => proj.base.ignore_borrow(tcx, mir, locals_state_at_exit),
80                     }
81                 }
82             },
83         }
84     }
85
86     fn root_local(&self) -> Option<Local> {
87         let mut p = self;
88         loop {
89             match p {
90                 Place::Projection(pi) => p = &pi.base,
91                 Place::Promoted(_) |
92                 Place::Static(_) => return None,
93                 Place::Local(l) => return Some(*l),
94             }
95         }
96     }
97 }