1+ //! The borrowck rules for proving disjointness are applied from the "root" of the
2+ //! borrow forwards, iterating over "similar" projections in lockstep until
3+ //! we can prove overlap one way or another. Essentially, we treat `Overlap` as
4+ //! a monoid and report a conflict if the product ends up not being `Disjoint`.
5+ //!
6+ //! At each step, if we didn't run out of borrow or place, we know that our elements
7+ //! have the same type, and that they only overlap if they are the identical.
8+ //!
9+ //! For example, if we are comparing these:
10+ //! ```text
11+ //! BORROW: (*x1[2].y).z.a
12+ //! ACCESS: (*x1[i].y).w.b
13+ //! ```
14+ //!
15+ //! Then our steps are:
16+ //! ```text
17+ //! x1 | x1 -- places are the same
18+ //! x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ)
19+ //! x1[2].y | x1[i].y -- equal or disjoint
20+ //! *x1[2].y | *x1[i].y -- equal or disjoint
21+ //! (*x1[2].y).z | (*x1[i].y).w -- we are disjoint and don't need to check more!
22+ //! ```
23+ //!
24+ //! Because `zip` does potentially bad things to the iterator inside, this loop
25+ //! also handles the case where the access might be a *prefix* of the borrow, e.g.
26+ //!
27+ //! ```text
28+ //! BORROW: (*x1[2].y).z.a
29+ //! ACCESS: x1[i].y
30+ //! ```
31+ //!
32+ //! Then our steps are:
33+ //! ```text
34+ //! x1 | x1 -- places are the same
35+ //! x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ)
36+ //! x1[2].y | x1[i].y -- equal or disjoint
37+ //! ```
38+ //!
39+ //! -- here we run out of access - the borrow can access a part of it. If this
40+ //! is a full deep access, then we *know* the borrow conflicts with it. However,
41+ //! if the access is shallow, then we can proceed:
42+ //!
43+ //! ```text
44+ //! x1[2].y | (*x1[i].y) -- a deref! the access can't get past this, so we
45+ //! are disjoint
46+ //! ```
47+ //!
48+ //! Our invariant is, that at each step of the iteration:
49+ //! - If we didn't run out of access to match, our borrow and access are comparable
50+ //! and either equal or disjoint.
51+ //! - If we did run out of access, the borrow can access a part of it.
52+
153#![ deny( rustc:: untranslatable_diagnostic) ]
254#![ deny( rustc:: diagnostic_outside_of_impl) ]
355use crate :: ArtificialField ;
456use crate :: Overlap ;
557use crate :: { AccessDepth , Deep , Shallow } ;
658use rustc_hir as hir;
759use rustc_middle:: mir:: {
8- Body , BorrowKind , Local , MutBorrowKind , Place , PlaceElem , PlaceRef , ProjectionElem ,
60+ Body , BorrowKind , MutBorrowKind , Place , PlaceElem , PlaceRef , ProjectionElem ,
961} ;
1062use rustc_middle:: ty:: { self , TyCtxt } ;
1163use std:: cmp:: max;
@@ -48,7 +100,7 @@ pub fn places_conflict<'tcx>(
48100/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime
49101/// array indices, for example) should be interpreted - this depends on what the caller wants in
50102/// order to make the conservative choice and preserve soundness.
51- #[ instrument ( level = "debug" , skip ( tcx , body ) ) ]
103+ #[ inline ]
52104pub ( super ) fn borrow_conflicts_with_place < ' tcx > (
53105 tcx : TyCtxt < ' tcx > ,
54106 body : & Body < ' tcx > ,
@@ -58,15 +110,24 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
58110 access : AccessDepth ,
59111 bias : PlaceConflictBias ,
60112) -> bool {
113+ let borrow_local = borrow_place. local ;
114+ let access_local = access_place. local ;
115+
116+ if borrow_local != access_local {
117+ // We have proven the borrow disjoint - further projections will remain disjoint.
118+ return false ;
119+ }
120+
61121 // This Local/Local case is handled by the more general code below, but
62122 // it's so common that it's a speed win to check for it first.
63- if let Some ( l1 ) = borrow_place. as_local ( ) && let Some ( l2 ) = access_place. as_local ( ) {
64- return l1 == l2 ;
123+ if borrow_place. projection . is_empty ( ) && access_place. projection . is_empty ( ) {
124+ return true ;
65125 }
66126
67127 place_components_conflict ( tcx, body, borrow_place, borrow_kind, access_place, access, bias)
68128}
69129
130+ #[ instrument( level = "debug" , skip( tcx, body) ) ]
70131fn place_components_conflict < ' tcx > (
71132 tcx : TyCtxt < ' tcx > ,
72133 body : & Body < ' tcx > ,
@@ -76,65 +137,10 @@ fn place_components_conflict<'tcx>(
76137 access : AccessDepth ,
77138 bias : PlaceConflictBias ,
78139) -> bool {
79- // The borrowck rules for proving disjointness are applied from the "root" of the
80- // borrow forwards, iterating over "similar" projections in lockstep until
81- // we can prove overlap one way or another. Essentially, we treat `Overlap` as
82- // a monoid and report a conflict if the product ends up not being `Disjoint`.
83- //
84- // At each step, if we didn't run out of borrow or place, we know that our elements
85- // have the same type, and that they only overlap if they are the identical.
86- //
87- // For example, if we are comparing these:
88- // BORROW: (*x1[2].y).z.a
89- // ACCESS: (*x1[i].y).w.b
90- //
91- // Then our steps are:
92- // x1 | x1 -- places are the same
93- // x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ)
94- // x1[2].y | x1[i].y -- equal or disjoint
95- // *x1[2].y | *x1[i].y -- equal or disjoint
96- // (*x1[2].y).z | (*x1[i].y).w -- we are disjoint and don't need to check more!
97- //
98- // Because `zip` does potentially bad things to the iterator inside, this loop
99- // also handles the case where the access might be a *prefix* of the borrow, e.g.
100- //
101- // BORROW: (*x1[2].y).z.a
102- // ACCESS: x1[i].y
103- //
104- // Then our steps are:
105- // x1 | x1 -- places are the same
106- // x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ)
107- // x1[2].y | x1[i].y -- equal or disjoint
108- //
109- // -- here we run out of access - the borrow can access a part of it. If this
110- // is a full deep access, then we *know* the borrow conflicts with it. However,
111- // if the access is shallow, then we can proceed:
112- //
113- // x1[2].y | (*x1[i].y) -- a deref! the access can't get past this, so we
114- // are disjoint
115- //
116- // Our invariant is, that at each step of the iteration:
117- // - If we didn't run out of access to match, our borrow and access are comparable
118- // and either equal or disjoint.
119- // - If we did run out of access, the borrow can access a part of it.
120-
121140 let borrow_local = borrow_place. local ;
122141 let access_local = access_place. local ;
123-
124- match place_base_conflict ( borrow_local, access_local) {
125- Overlap :: Arbitrary => {
126- bug ! ( "Two base can't return Arbitrary" ) ;
127- }
128- Overlap :: EqualOrDisjoint => {
129- // This is the recursive case - proceed to the next element.
130- }
131- Overlap :: Disjoint => {
132- // We have proven the borrow disjoint - further
133- // projections will remain disjoint.
134- debug ! ( "borrow_conflicts_with_place: disjoint" ) ;
135- return false ;
136- }
137- }
142+ // borrow_conflicts_with_place should have checked that.
143+ assert_eq ! ( borrow_local, access_local) ;
138144
139145 // loop invariant: borrow_c is always either equal to access_c or disjoint from it.
140146 for ( ( borrow_place, borrow_c) , & access_c) in
@@ -277,21 +283,6 @@ fn place_components_conflict<'tcx>(
277283 }
278284}
279285
280- // Given that the bases of `elem1` and `elem2` are always either equal
281- // or disjoint (and have the same type!), return the overlap situation
282- // between `elem1` and `elem2`.
283- fn place_base_conflict ( l1 : Local , l2 : Local ) -> Overlap {
284- if l1 == l2 {
285- // the same local - base case, equal
286- debug ! ( "place_element_conflict: DISJOINT-OR-EQ-LOCAL" ) ;
287- Overlap :: EqualOrDisjoint
288- } else {
289- // different locals - base case, disjoint
290- debug ! ( "place_element_conflict: DISJOINT-LOCAL" ) ;
291- Overlap :: Disjoint
292- }
293- }
294-
295286// Given that the bases of `elem1` and `elem2` are always either equal
296287// or disjoint (and have the same type!), return the overlap situation
297288// between `elem1` and `elem2`.
0 commit comments