2 use rustc::mir::ProjectionElem;
3 use rustc::mir::{Local, Mir, Place, PlaceBase, Mutability, Static, StaticKind};
4 use rustc::ty::{self, TyCtxt};
5 use crate::borrow_check::borrow_set::LocalsStateAtExit;
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.
15 tcx: TyCtxt<'_, '_, 'tcx>,
17 locals_state_at_exit: &LocalsStateAtExit,
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>;
25 impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
28 tcx: TyCtxt<'_, '_, 'tcx>,
30 locals_state_at_exit: &LocalsStateAtExit,
33 // If a local variable is immutable, then we only need to track borrows to guard
34 // against two kinds of errors:
35 // * The variable being dropped while still borrowed (e.g., because the fn returns
36 // a reference to a local variable)
37 // * The variable being moved while still borrowed
39 // In particular, the variable cannot be mutated -- the "access checks" will fail --
40 // so we don't have to worry about mutation while borrowed.
41 Place::Base(PlaceBase::Local(index)) => {
42 match locals_state_at_exit {
43 LocalsStateAtExit::AllAreInvalidated => false,
44 LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
45 let ignore = !has_storage_dead_or_moved.contains(*index) &&
46 mir.local_decls[*index].mutability == Mutability::Not;
47 debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
52 Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_), .. })) =>
54 Place::Base(PlaceBase::Static(box Static{ kind: StaticKind::Static(def_id), .. })) => {
55 tcx.is_mutable_static(*def_id)
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),
65 ProjectionElem::Deref => {
66 let ty = proj.base.ty(mir, tcx).ty;
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
78 ty::RawPtr(..) | ty::Ref(_, _, hir::MutImmutable) => true,
79 _ => proj.base.ignore_borrow(tcx, mir, locals_state_at_exit),
86 fn root_local(&self) -> Option<Local> {
90 Place::Projection(pi) => p = &pi.base,
91 Place::Base(PlaceBase::Static(_)) => return None,
92 Place::Base(PlaceBase::Local(l)) => return Some(*l),