2019-02-08 06:28:15 +09:00
|
|
|
use crate::borrow_check::borrow_set::{BorrowSet, BorrowData, TwoPhaseActivation};
|
|
|
|
use crate::borrow_check::places_conflict;
|
|
|
|
use crate::borrow_check::AccessDepth;
|
|
|
|
use crate::dataflow::indexes::BorrowIndex;
|
2019-05-17 23:55:04 +02:00
|
|
|
use rustc::mir::{BasicBlock, Location, Body, Place, PlaceBase};
|
2018-06-27 11:16:24 -04:00
|
|
|
use rustc::mir::{ProjectionElem, BorrowKind};
|
|
|
|
use rustc::ty::TyCtxt;
|
2018-07-02 06:14:49 -04:00
|
|
|
use rustc_data_structures::graph::dominators::Dominators;
|
2018-05-18 23:47:48 -07:00
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Returns `true` if the borrow represented by `kind` is
|
2018-06-27 11:16:24 -04:00
|
|
|
/// allowed to be split into separate Reservation and
|
|
|
|
/// Activation phases.
|
2019-06-11 12:47:30 +03:00
|
|
|
pub(super) fn allow_two_phase_borrow(kind: BorrowKind) -> bool {
|
2019-01-26 17:25:37 +00:00
|
|
|
kind.allows_two_phase_borrow()
|
2018-05-18 23:47:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Control for the path borrow checking code
|
|
|
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
|
|
pub(super) enum Control {
|
|
|
|
Continue,
|
|
|
|
Break,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Encapsulates the idea of iterating over every borrow that involves a particular path
|
2019-06-14 00:48:52 +03:00
|
|
|
pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
|
2018-05-18 23:47:48 -07:00
|
|
|
s: &mut S,
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2019-06-03 18:26:48 -04:00
|
|
|
body: &Body<'tcx>,
|
2019-05-02 06:03:17 +09:00
|
|
|
_location: Location,
|
2018-09-23 16:07:45 +01:00
|
|
|
access_place: (AccessDepth, &Place<'tcx>),
|
2018-05-18 23:47:48 -07:00
|
|
|
borrow_set: &BorrowSet<'tcx>,
|
|
|
|
candidates: I,
|
|
|
|
mut op: F,
|
|
|
|
) where
|
|
|
|
F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control,
|
2019-06-12 00:11:55 +03:00
|
|
|
I: Iterator<Item = BorrowIndex>,
|
2018-05-18 23:47:48 -07:00
|
|
|
{
|
|
|
|
let (access, place) = access_place;
|
|
|
|
|
|
|
|
// FIXME: analogous code in check_loans first maps `place` to
|
|
|
|
// its base_path.
|
|
|
|
|
|
|
|
// check for loan restricting path P being used. Accounts for
|
|
|
|
// borrows of P, P.a.b, etc.
|
|
|
|
for i in candidates {
|
|
|
|
let borrowed = &borrow_set[i];
|
|
|
|
|
2018-09-23 11:33:52 +01:00
|
|
|
if places_conflict::borrow_conflicts_with_place(
|
2018-09-10 22:33:45 +01:00
|
|
|
tcx,
|
2019-06-03 18:26:48 -04:00
|
|
|
body,
|
2018-09-10 22:33:45 +01:00
|
|
|
&borrowed.borrowed_place,
|
|
|
|
borrowed.kind,
|
2019-07-21 22:38:30 +02:00
|
|
|
place.as_ref(),
|
2018-09-10 22:33:45 +01:00
|
|
|
access,
|
2018-12-17 13:11:33 +01:00
|
|
|
places_conflict::PlaceConflictBias::Overlap,
|
2018-09-10 22:33:45 +01:00
|
|
|
) {
|
2018-05-18 23:47:48 -07:00
|
|
|
debug!(
|
|
|
|
"each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
|
|
|
|
i, borrowed, place, access
|
|
|
|
);
|
|
|
|
let ctrl = op(s, i, borrowed);
|
|
|
|
if ctrl == Control::Break {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) fn is_active<'tcx>(
|
|
|
|
dominators: &Dominators<BasicBlock>,
|
|
|
|
borrow_data: &BorrowData<'tcx>,
|
|
|
|
location: Location
|
|
|
|
) -> bool {
|
|
|
|
debug!("is_active(borrow_data={:?}, location={:?})", borrow_data, location);
|
|
|
|
|
|
|
|
let activation_location = match borrow_data.activation_location {
|
2018-05-11 23:32:13 +02:00
|
|
|
// If this is not a 2-phase borrow, it is always active.
|
2018-07-04 20:08:15 +01:00
|
|
|
TwoPhaseActivation::NotTwoPhase => return true,
|
2018-05-11 23:32:13 +02:00
|
|
|
// And if the unique 2-phase use is not an activation, then it is *never* active.
|
2018-07-04 20:08:15 +01:00
|
|
|
TwoPhaseActivation::NotActivated => return false,
|
|
|
|
// Otherwise, we derive info from the activation point `loc`:
|
|
|
|
TwoPhaseActivation::ActivatedAt(loc) => loc,
|
2018-05-18 23:47:48 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// Otherwise, it is active for every location *except* in between
|
|
|
|
// the reservation and the activation:
|
|
|
|
//
|
|
|
|
// X
|
|
|
|
// /
|
|
|
|
// R <--+ Except for this
|
|
|
|
// / \ | diamond
|
|
|
|
// \ / |
|
|
|
|
// A <------+
|
|
|
|
// |
|
|
|
|
// Z
|
|
|
|
//
|
|
|
|
// Note that we assume that:
|
|
|
|
// - the reservation R dominates the activation A
|
|
|
|
// - the activation A post-dominates the reservation R (ignoring unwinding edges).
|
|
|
|
//
|
|
|
|
// This means that there can't be an edge that leaves A and
|
|
|
|
// comes back into that diamond unless it passes through R.
|
|
|
|
//
|
|
|
|
// Suboptimal: In some cases, this code walks the dominator
|
|
|
|
// tree twice when it only has to be walked once. I am
|
|
|
|
// lazy. -nmatsakis
|
|
|
|
|
|
|
|
// If dominated by the activation A, then it is active. The
|
|
|
|
// activation occurs upon entering the point A, so this is
|
|
|
|
// also true if location == activation_location.
|
|
|
|
if activation_location.dominates(location, dominators) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The reservation starts *on exiting* the reservation block,
|
|
|
|
// so check if the location is dominated by R.successor. If so,
|
|
|
|
// this point falls in between the reservation and location.
|
|
|
|
let reserve_location = borrow_data.reserve_location.successor_within_block();
|
|
|
|
if reserve_location.dominates(location, dominators) {
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
// Otherwise, this point is outside the diamond, so
|
|
|
|
// consider the borrow active. This could happen for
|
|
|
|
// example if the borrow remains active around a loop (in
|
|
|
|
// which case it would be active also for the point R,
|
|
|
|
// which would generate an error).
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Determines if a given borrow is borrowing local data
|
|
|
|
/// This is called for all Yield statements on movable generators
|
2019-06-21 18:51:27 +02:00
|
|
|
pub(super) fn borrow_of_local_data(place: &Place<'_>) -> bool {
|
2019-05-23 21:43:21 +02:00
|
|
|
place.iterate(|place_base, place_projection| {
|
|
|
|
match place_base {
|
|
|
|
PlaceBase::Static(..) => return false,
|
|
|
|
PlaceBase::Local(..) => {},
|
|
|
|
}
|
2018-05-18 23:47:48 -07:00
|
|
|
|
2019-05-23 21:43:21 +02:00
|
|
|
for proj in place_projection {
|
|
|
|
// Reborrow of already borrowed data is ignored
|
|
|
|
// Any errors will be caught on the initial borrow
|
|
|
|
if proj.elem == ProjectionElem::Deref {
|
|
|
|
return false;
|
2018-05-18 23:47:48 -07:00
|
|
|
}
|
|
|
|
}
|
2019-05-23 21:43:21 +02:00
|
|
|
|
|
|
|
true
|
|
|
|
})
|
2018-05-18 23:47:48 -07:00
|
|
|
}
|