1 use crate::borrow_check
::borrow_set
::{BorrowData, BorrowSet, TwoPhaseActivation}
;
2 use crate::borrow_check
::places_conflict
;
3 use crate::borrow_check
::AccessDepth
;
4 use crate::borrow_check
::Upvar
;
5 use crate::dataflow
::indexes
::BorrowIndex
;
6 use rustc_data_structures
::graph
::dominators
::Dominators
;
7 use rustc_middle
::mir
::BorrowKind
;
8 use rustc_middle
::mir
::{BasicBlock, Body, Field, Location, Place, PlaceRef, ProjectionElem}
;
9 use rustc_middle
::ty
::TyCtxt
;
11 /// Returns `true` if the borrow represented by `kind` is
12 /// allowed to be split into separate Reservation and
13 /// Activation phases.
14 pub(super) fn allow_two_phase_borrow(kind
: BorrowKind
) -> bool
{
15 kind
.allows_two_phase_borrow()
18 /// Control for the path borrow checking code
19 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
20 pub(super) enum Control
{
25 /// Encapsulates the idea of iterating over every borrow that involves a particular path
26 pub(super) fn each_borrow_involving_path
<'tcx
, F
, I
, S
>(
31 access_place
: (AccessDepth
, Place
<'tcx
>),
32 borrow_set
: &BorrowSet
<'tcx
>,
36 F
: FnMut(&mut S
, BorrowIndex
, &BorrowData
<'tcx
>) -> Control
,
37 I
: Iterator
<Item
= BorrowIndex
>,
39 let (access
, place
) = access_place
;
41 // FIXME: analogous code in check_loans first maps `place` to
44 // check for loan restricting path P being used. Accounts for
45 // borrows of P, P.a.b, etc.
47 let borrowed
= &borrow_set
[i
];
49 if places_conflict
::borrow_conflicts_with_place(
52 borrowed
.borrowed_place
,
56 places_conflict
::PlaceConflictBias
::Overlap
,
59 "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
60 i
, borrowed
, place
, access
62 let ctrl
= op(s
, i
, borrowed
);
63 if ctrl
== Control
::Break
{
70 pub(super) fn is_active
<'tcx
>(
71 dominators
: &Dominators
<BasicBlock
>,
72 borrow_data
: &BorrowData
<'tcx
>,
75 debug
!("is_active(borrow_data={:?}, location={:?})", borrow_data
, location
);
77 let activation_location
= match borrow_data
.activation_location
{
78 // If this is not a 2-phase borrow, it is always active.
79 TwoPhaseActivation
::NotTwoPhase
=> return true,
80 // And if the unique 2-phase use is not an activation, then it is *never* active.
81 TwoPhaseActivation
::NotActivated
=> return false,
82 // Otherwise, we derive info from the activation point `loc`:
83 TwoPhaseActivation
::ActivatedAt(loc
) => loc
,
86 // Otherwise, it is active for every location *except* in between
87 // the reservation and the activation:
91 // R <--+ Except for this
98 // Note that we assume that:
99 // - the reservation R dominates the activation A
100 // - the activation A post-dominates the reservation R (ignoring unwinding edges).
102 // This means that there can't be an edge that leaves A and
103 // comes back into that diamond unless it passes through R.
105 // Suboptimal: In some cases, this code walks the dominator
106 // tree twice when it only has to be walked once. I am
109 // If dominated by the activation A, then it is active. The
110 // activation occurs upon entering the point A, so this is
111 // also true if location == activation_location.
112 if activation_location
.dominates(location
, dominators
) {
116 // The reservation starts *on exiting* the reservation block,
117 // so check if the location is dominated by R.successor. If so,
118 // this point falls in between the reservation and location.
119 let reserve_location
= borrow_data
.reserve_location
.successor_within_block();
120 if reserve_location
.dominates(location
, dominators
) {
123 // Otherwise, this point is outside the diamond, so
124 // consider the borrow active. This could happen for
125 // example if the borrow remains active around a loop (in
126 // which case it would be active also for the point R,
127 // which would generate an error).
132 /// Determines if a given borrow is borrowing local data
133 /// This is called for all Yield expressions on movable generators
134 pub(super) fn borrow_of_local_data(place
: Place
<'_
>) -> bool
{
135 // Reborrow of already borrowed data is ignored
136 // Any errors will be caught on the initial borrow
140 /// If `place` is a field projection, and the field is being projected from a closure type,
141 /// then returns the index of the field being projected. Note that this closure will always
142 /// be `self` in the current MIR, because that is the only time we directly access the fields
143 /// of a closure type.
144 pub(crate) fn is_upvar_field_projection(
147 place_ref
: PlaceRef
<'tcx
>,
150 let mut place_projection
= place_ref
.projection
;
151 let mut by_ref
= false;
153 if let [proj_base @
.., ProjectionElem
::Deref
] = place_projection
{
154 place_projection
= proj_base
;
158 match place_projection
{
159 [base @
.., ProjectionElem
::Field(field
, _ty
)] => {
160 let base_ty
= Place
::ty_from(place_ref
.local
, base
, body
, tcx
).ty
;
162 if (base_ty
.is_closure() || base_ty
.is_generator())
163 && (!by_ref
|| upvars
[field
.index()].by_ref
)