2018-04-06 15:53:49 -04:00
|
|
|
use rustc::hir;
|
|
|
|
use rustc::mir::ProjectionElem;
|
2019-05-17 23:55:04 +02:00
|
|
|
use rustc::mir::{Body, Place, PlaceBase, Mutability, Static, StaticKind};
|
2018-04-06 15:53:49 -04:00
|
|
|
use rustc::ty::{self, TyCtxt};
|
2019-02-08 06:28:15 +09:00
|
|
|
use crate::borrow_check::borrow_set::LocalsStateAtExit;
|
2018-04-06 15:53:49 -04:00
|
|
|
|
|
|
|
/// Extension methods for the `Place` type.
|
|
|
|
crate trait PlaceExt<'tcx> {
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Returns `true` if we can safely ignore borrows of this place.
|
2018-08-07 18:01:29 -04:00
|
|
|
/// This is true whenever there is no action that the user can do
|
|
|
|
/// to the place `self` that would invalidate the borrow. This is true
|
|
|
|
/// for borrows of raw pointer dereferents as well as shared references.
|
2018-09-05 23:49:58 +01:00
|
|
|
fn ignore_borrow(
|
|
|
|
&self,
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2019-06-03 18:26:48 -04:00
|
|
|
body: &Body<'tcx>,
|
2018-09-05 23:49:58 +01:00
|
|
|
locals_state_at_exit: &LocalsStateAtExit,
|
2019-06-12 00:11:55 +03:00
|
|
|
) -> bool;
|
2018-04-06 15:53:49 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
|
2018-09-05 23:49:58 +01:00
|
|
|
fn ignore_borrow(
|
|
|
|
&self,
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2019-06-03 18:26:48 -04:00
|
|
|
body: &Body<'tcx>,
|
2018-09-05 23:49:58 +01:00
|
|
|
locals_state_at_exit: &LocalsStateAtExit,
|
|
|
|
) -> bool {
|
2019-07-30 00:07:28 +02:00
|
|
|
let ignore = match self.base {
|
|
|
|
// If a local variable is immutable, then we only need to track borrows to guard
|
|
|
|
// against two kinds of errors:
|
|
|
|
// * The variable being dropped while still borrowed (e.g., because the fn returns
|
|
|
|
// a reference to a local variable)
|
|
|
|
// * The variable being moved while still borrowed
|
|
|
|
//
|
|
|
|
// In particular, the variable cannot be mutated -- the "access checks" will fail --
|
|
|
|
// so we don't have to worry about mutation while borrowed.
|
|
|
|
PlaceBase::Local(index) => {
|
|
|
|
match locals_state_at_exit {
|
|
|
|
LocalsStateAtExit::AllAreInvalidated => false,
|
|
|
|
LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved } => {
|
|
|
|
let ignore = !has_storage_dead_or_moved.contains(index) &&
|
|
|
|
body.local_decls[index].mutability == Mutability::Not;
|
|
|
|
debug!("ignore_borrow: local {:?} => {:?}", index, ignore);
|
|
|
|
ignore
|
2018-09-05 23:49:58 +01:00
|
|
|
}
|
|
|
|
}
|
2019-07-30 00:07:28 +02:00
|
|
|
}
|
|
|
|
PlaceBase::Static(box Static{ kind: StaticKind::Promoted(_, _), .. }) =>
|
|
|
|
false,
|
|
|
|
PlaceBase::Static(box Static{ kind: StaticKind::Static, def_id, .. }) => {
|
|
|
|
tcx.is_mutable_static(def_id)
|
|
|
|
}
|
|
|
|
};
|
2018-08-07 18:01:29 -04:00
|
|
|
|
2019-07-30 00:07:28 +02:00
|
|
|
for (i, elem) in self.projection.iter().enumerate() {
|
|
|
|
let proj_base = &self.projection[..i];
|
|
|
|
|
|
|
|
if *elem == ProjectionElem::Deref {
|
|
|
|
let ty = Place::ty_from(&self.base, proj_base, body, tcx).ty;
|
2019-11-09 17:44:11 +01:00
|
|
|
if let ty::RawPtr(..) | ty::Ref(_, _, hir::Mutability::Immutable) = ty.kind {
|
2019-07-30 00:07:28 +02:00
|
|
|
// For both derefs of raw pointers and `&T`
|
|
|
|
// references, the original path is `Copy` and
|
|
|
|
// therefore not significant. In particular,
|
|
|
|
// there is nothing the user can do to the
|
|
|
|
// original path that would invalidate the
|
|
|
|
// newly created reference -- and if there
|
|
|
|
// were, then the user could have copied the
|
|
|
|
// original path into a new variable and
|
|
|
|
// borrowed *that* one, leaving the original
|
|
|
|
// path unborrowed.
|
2019-09-12 16:21:47 -03:00
|
|
|
return true;
|
2018-04-06 15:53:49 -04:00
|
|
|
}
|
2019-05-23 21:53:59 +02:00
|
|
|
}
|
2019-07-30 00:07:28 +02:00
|
|
|
}
|
2019-05-23 21:53:59 +02:00
|
|
|
|
2019-07-30 00:07:28 +02:00
|
|
|
ignore
|
2018-04-06 15:53:49 -04:00
|
|
|
}
|
|
|
|
}
|