]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_borrowck/src/path_utils.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / compiler / rustc_borrowck / src / path_utils.rs
CommitLineData
487cf647
FG
1#![deny(rustc::untranslatable_diagnostic)]
2#![deny(rustc::diagnostic_outside_of_impl)]
c295e0f8
XL
3use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation};
4use crate::places_conflict;
5use crate::AccessDepth;
6use crate::BorrowIndex;
7use crate::Upvar;
8faf50e0 8use rustc_data_structures::graph::dominators::Dominators;
ba9703b0 9use rustc_middle::mir::BorrowKind;
353b0b11 10use rustc_middle::mir::{BasicBlock, Body, Location, Place, PlaceRef, ProjectionElem};
ba9703b0 11use rustc_middle::ty::TyCtxt;
353b0b11 12use rustc_target::abi::FieldIdx;
94b46f34 13
9fa01778 14/// Returns `true` if the borrow represented by `kind` is
8faf50e0
XL
15/// allowed to be split into separate Reservation and
16/// Activation phases.
dc9dc135 17pub(super) fn allow_two_phase_borrow(kind: BorrowKind) -> bool {
48663c56 18 kind.allows_two_phase_borrow()
94b46f34
XL
19}
20
21/// Control for the path borrow checking code
22#[derive(Copy, Clone, PartialEq, Eq, Debug)]
23pub(super) enum Control {
24 Continue,
25 Break,
26}
27
28/// Encapsulates the idea of iterating over every borrow that involves a particular path
dc9dc135 29pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
94b46f34 30 s: &mut S,
dc9dc135
XL
31 tcx: TyCtxt<'tcx>,
32 body: &Body<'tcx>,
48663c56 33 _location: Location,
ba9703b0 34 access_place: (AccessDepth, Place<'tcx>),
94b46f34
XL
35 borrow_set: &BorrowSet<'tcx>,
36 candidates: I,
37 mut op: F,
38) where
39 F: FnMut(&mut S, BorrowIndex, &BorrowData<'tcx>) -> Control,
dc9dc135 40 I: Iterator<Item = BorrowIndex>,
94b46f34
XL
41{
42 let (access, place) = access_place;
43
44 // FIXME: analogous code in check_loans first maps `place` to
45 // its base_path.
46
47 // check for loan restricting path P being used. Accounts for
48 // borrows of P, P.a.b, etc.
49 for i in candidates {
50 let borrowed = &borrow_set[i];
51
0bf4aa26
XL
52 if places_conflict::borrow_conflicts_with_place(
53 tcx,
dc9dc135 54 body,
ba9703b0 55 borrowed.borrowed_place,
0bf4aa26 56 borrowed.kind,
416331ca 57 place.as_ref(),
0bf4aa26 58 access,
0731742a 59 places_conflict::PlaceConflictBias::Overlap,
0bf4aa26 60 ) {
94b46f34
XL
61 debug!(
62 "each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
63 i, borrowed, place, access
64 );
65 let ctrl = op(s, i, borrowed);
66 if ctrl == Control::Break {
67 return;
68 }
69 }
70 }
71}
72
94b46f34
XL
73pub(super) fn is_active<'tcx>(
74 dominators: &Dominators<BasicBlock>,
75 borrow_data: &BorrowData<'tcx>,
dfeec247 76 location: Location,
94b46f34
XL
77) -> bool {
78 debug!("is_active(borrow_data={:?}, location={:?})", borrow_data, location);
79
80 let activation_location = match borrow_data.activation_location {
81 // If this is not a 2-phase borrow, it is always active.
8faf50e0 82 TwoPhaseActivation::NotTwoPhase => return true,
94b46f34 83 // And if the unique 2-phase use is not an activation, then it is *never* active.
8faf50e0
XL
84 TwoPhaseActivation::NotActivated => return false,
85 // Otherwise, we derive info from the activation point `loc`:
86 TwoPhaseActivation::ActivatedAt(loc) => loc,
94b46f34
XL
87 };
88
89 // Otherwise, it is active for every location *except* in between
90 // the reservation and the activation:
91 //
92 // X
93 // /
94 // R <--+ Except for this
95 // / \ | diamond
96 // \ / |
97 // A <------+
98 // |
99 // Z
100 //
101 // Note that we assume that:
102 // - the reservation R dominates the activation A
103 // - the activation A post-dominates the reservation R (ignoring unwinding edges).
104 //
105 // This means that there can't be an edge that leaves A and
106 // comes back into that diamond unless it passes through R.
107 //
108 // Suboptimal: In some cases, this code walks the dominator
109 // tree twice when it only has to be walked once. I am
110 // lazy. -nmatsakis
111
112 // If dominated by the activation A, then it is active. The
113 // activation occurs upon entering the point A, so this is
114 // also true if location == activation_location.
115 if activation_location.dominates(location, dominators) {
116 return true;
117 }
118
119 // The reservation starts *on exiting* the reservation block,
120 // so check if the location is dominated by R.successor. If so,
121 // this point falls in between the reservation and location.
122 let reserve_location = borrow_data.reserve_location.successor_within_block();
123 if reserve_location.dominates(location, dominators) {
124 false
125 } else {
126 // Otherwise, this point is outside the diamond, so
127 // consider the borrow active. This could happen for
128 // example if the borrow remains active around a loop (in
129 // which case it would be active also for the point R,
130 // which would generate an error).
131 true
132 }
133}
134
135/// Determines if a given borrow is borrowing local data
dfeec247 136/// This is called for all Yield expressions on movable generators
ba9703b0 137pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool {
dfeec247
XL
138 // Reborrow of already borrowed data is ignored
139 // Any errors will be caught on the initial borrow
140 !place.is_indirect()
94b46f34 141}
f035d41b
XL
142
143/// If `place` is a field projection, and the field is being projected from a closure type,
144/// then returns the index of the field being projected. Note that this closure will always
145/// be `self` in the current MIR, because that is the only time we directly access the fields
146/// of a closure type.
a2a8927a 147pub(crate) fn is_upvar_field_projection<'tcx>(
f035d41b 148 tcx: TyCtxt<'tcx>,
5869c6ff 149 upvars: &[Upvar<'tcx>],
f035d41b
XL
150 place_ref: PlaceRef<'tcx>,
151 body: &Body<'tcx>,
353b0b11 152) -> Option<FieldIdx> {
5869c6ff 153 let mut place_ref = place_ref;
f035d41b
XL
154 let mut by_ref = false;
155
5869c6ff
XL
156 if let Some((place_base, ProjectionElem::Deref)) = place_ref.last_projection() {
157 place_ref = place_base;
f035d41b
XL
158 by_ref = true;
159 }
160
5869c6ff
XL
161 match place_ref.last_projection() {
162 Some((place_base, ProjectionElem::Field(field, _ty))) => {
163 let base_ty = place_base.ty(body, tcx).ty;
f035d41b
XL
164 if (base_ty.is_closure() || base_ty.is_generator())
165 && (!by_ref || upvars[field.index()].by_ref)
166 {
5869c6ff 167 Some(field)
f035d41b
XL
168 } else {
169 None
170 }
171 }
f035d41b
XL
172 _ => None,
173 }
174}