1 use crate::borrow_check::borrow_set::{BorrowSet, BorrowData, TwoPhaseActivation};
2 use crate::borrow_check::places_conflict;
3 use crate::borrow_check::AccessDepth;
4 use crate::dataflow::indexes::BorrowIndex;
5 use rustc::mir::{BasicBlock, Location, Body, Place, PlaceBase};
6 use rustc::mir::{ProjectionElem, BorrowKind};
8 use rustc_data_structures::graph::dominators::Dominators;
10 /// Returns `true` if the borrow represented by `kind` is
11 /// allowed to be split into separate Reservation and
12 /// Activation phases.
13 pub(super) fn allow_two_phase_borrow(kind: BorrowKind) -> bool {
14 kind.allows_two_phase_borrow()
17 /// Control for the path borrow checking code
18 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
19 pub(super) enum Control {
24 /// Encapsulates the idea of iterating over every borrow that involves a particular path
25 pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
30 access_place: (AccessDepth, &Place<'tcx>),
31 borrow_set: &BorrowSet<'tcx>,
35 F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control,
36 I: Iterator<Item = BorrowIndex>,
38 let (access, place) = access_place;
40 // FIXME: analogous code in check_loans first maps `place` to
43 // check for loan restricting path P being used. Accounts for
44 // borrows of P, P.a.b, etc.
46 let borrowed = &borrow_set[i];
48 if places_conflict::borrow_conflicts_with_place(
51 &borrowed.borrowed_place,
55 places_conflict::PlaceConflictBias::Overlap,
58 "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
59 i, borrowed, place, access
61 let ctrl = op(s, i, borrowed);
62 if ctrl == Control::Break {
69 pub(super) fn is_active<'tcx>(
70 dominators: &Dominators<BasicBlock>,
71 borrow_data: &BorrowData<'tcx>,
74 debug!("is_active(borrow_data={:?}, location={:?})", borrow_data, location);
76 let activation_location = match borrow_data.activation_location {
77 // If this is not a 2-phase borrow, it is always active.
78 TwoPhaseActivation::NotTwoPhase => return true,
79 // And if the unique 2-phase use is not an activation, then it is *never* active.
80 TwoPhaseActivation::NotActivated => return false,
81 // Otherwise, we derive info from the activation point `loc`:
82 TwoPhaseActivation::ActivatedAt(loc) => loc,
85 // Otherwise, it is active for every location *except* in between
86 // the reservation and the activation:
90 // R <--+ Except for this
97 // Note that we assume that:
98 // - the reservation R dominates the activation A
99 // - the activation A post-dominates the reservation R (ignoring unwinding edges).
101 // This means that there can't be an edge that leaves A and
102 // comes back into that diamond unless it passes through R.
104 // Suboptimal: In some cases, this code walks the dominator
105 // tree twice when it only has to be walked once. I am
108 // If dominated by the activation A, then it is active. The
109 // activation occurs upon entering the point A, so this is
110 // also true if location == activation_location.
111 if activation_location.dominates(location, dominators) {
115 // The reservation starts *on exiting* the reservation block,
116 // so check if the location is dominated by R.successor. If so,
117 // this point falls in between the reservation and location.
118 let reserve_location = borrow_data.reserve_location.successor_within_block();
119 if reserve_location.dominates(location, dominators) {
122 // Otherwise, this point is outside the diamond, so
123 // consider the borrow active. This could happen for
124 // example if the borrow remains active around a loop (in
125 // which case it would be active also for the point R,
126 // which would generate an error).
131 /// Determines if a given borrow is borrowing local data
132 /// This is called for all Yield statements on movable generators
133 pub(super) fn borrow_of_local_data(place: &Place<'_>) -> bool {
134 place.iterate(|place_base, place_projection| {
136 PlaceBase::Static(..) => return false,
137 PlaceBase::Local(..) => {},
140 for proj in place_projection {
141 // Reborrow of already borrowed data is ignored
142 // Any errors will be caught on the initial borrow
143 if proj.elem == ProjectionElem::Deref {