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
+
1
53
#![ deny( rustc:: untranslatable_diagnostic) ]
2
54
#![ deny( rustc:: diagnostic_outside_of_impl) ]
3
55
use crate :: ArtificialField ;
@@ -46,7 +98,7 @@ pub(crate) fn places_conflict<'tcx>(
46
98
/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime
47
99
/// array indices, for example) should be interpreted - this depends on what the caller wants in
48
100
/// order to make the conservative choice and preserve soundness.
49
- #[ instrument ( level = "debug" , skip ( tcx , body ) ) ]
101
+ #[ inline ]
50
102
pub ( super ) fn borrow_conflicts_with_place < ' tcx > (
51
103
tcx : TyCtxt < ' tcx > ,
52
104
body : & Body < ' tcx > ,
@@ -56,15 +108,24 @@ pub(super) fn borrow_conflicts_with_place<'tcx>(
56
108
access : AccessDepth ,
57
109
bias : PlaceConflictBias ,
58
110
) -> bool {
111
+ let borrow_local = borrow_place. local ;
112
+ let access_local = access_place. local ;
113
+
114
+ if borrow_local != access_local {
115
+ // We have proven the borrow disjoint - further projections will remain disjoint.
116
+ return false ;
117
+ }
118
+
59
119
// This Local/Local case is handled by the more general code below, but
60
120
// it's so common that it's a speed win to check for it first.
61
- if let Some ( l1 ) = borrow_place. as_local ( ) && let Some ( l2 ) = access_place. as_local ( ) {
62
- return l1 == l2 ;
121
+ if borrow_place. projection . is_empty ( ) && access_place. projection . is_empty ( ) {
122
+ return true ;
63
123
}
64
124
65
125
place_components_conflict ( tcx, body, borrow_place, borrow_kind, access_place, access, bias)
66
126
}
67
127
128
+ #[ instrument( level = "debug" , skip( tcx, body) ) ]
68
129
fn place_components_conflict < ' tcx > (
69
130
tcx : TyCtxt < ' tcx > ,
70
131
body : & Body < ' tcx > ,
@@ -74,65 +135,10 @@ fn place_components_conflict<'tcx>(
74
135
access : AccessDepth ,
75
136
bias : PlaceConflictBias ,
76
137
) -> bool {
77
- // The borrowck rules for proving disjointness are applied from the "root" of the
78
- // borrow forwards, iterating over "similar" projections in lockstep until
79
- // we can prove overlap one way or another. Essentially, we treat `Overlap` as
80
- // a monoid and report a conflict if the product ends up not being `Disjoint`.
81
- //
82
- // At each step, if we didn't run out of borrow or place, we know that our elements
83
- // have the same type, and that they only overlap if they are the identical.
84
- //
85
- // For example, if we are comparing these:
86
- // BORROW: (*x1[2].y).z.a
87
- // ACCESS: (*x1[i].y).w.b
88
- //
89
- // Then our steps are:
90
- // x1 | x1 -- places are the same
91
- // x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ)
92
- // x1[2].y | x1[i].y -- equal or disjoint
93
- // *x1[2].y | *x1[i].y -- equal or disjoint
94
- // (*x1[2].y).z | (*x1[i].y).w -- we are disjoint and don't need to check more!
95
- //
96
- // Because `zip` does potentially bad things to the iterator inside, this loop
97
- // also handles the case where the access might be a *prefix* of the borrow, e.g.
98
- //
99
- // BORROW: (*x1[2].y).z.a
100
- // ACCESS: x1[i].y
101
- //
102
- // Then our steps are:
103
- // x1 | x1 -- places are the same
104
- // x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ)
105
- // x1[2].y | x1[i].y -- equal or disjoint
106
- //
107
- // -- here we run out of access - the borrow can access a part of it. If this
108
- // is a full deep access, then we *know* the borrow conflicts with it. However,
109
- // if the access is shallow, then we can proceed:
110
- //
111
- // x1[2].y | (*x1[i].y) -- a deref! the access can't get past this, so we
112
- // are disjoint
113
- //
114
- // Our invariant is, that at each step of the iteration:
115
- // - If we didn't run out of access to match, our borrow and access are comparable
116
- // and either equal or disjoint.
117
- // - If we did run out of access, the borrow can access a part of it.
118
-
119
138
let borrow_local = borrow_place. local ;
120
139
let access_local = access_place. local ;
121
-
122
- match place_base_conflict ( borrow_local, access_local) {
123
- Overlap :: Arbitrary => {
124
- bug ! ( "Two base can't return Arbitrary" ) ;
125
- }
126
- Overlap :: EqualOrDisjoint => {
127
- // This is the recursive case - proceed to the next element.
128
- }
129
- Overlap :: Disjoint => {
130
- // We have proven the borrow disjoint - further
131
- // projections will remain disjoint.
132
- debug ! ( "borrow_conflicts_with_place: disjoint" ) ;
133
- return false ;
134
- }
135
- }
140
+ // borrow_conflicts_with_place should have checked that.
141
+ assert_eq ! ( borrow_local, access_local) ;
136
142
137
143
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
138
144
for ( i, ( borrow_c, & access_c) ) in
@@ -287,21 +293,6 @@ fn place_components_conflict<'tcx>(
287
293
}
288
294
}
289
295
290
- // Given that the bases of `elem1` and `elem2` are always either equal
291
- // or disjoint (and have the same type!), return the overlap situation
292
- // between `elem1` and `elem2`.
293
- fn place_base_conflict ( l1 : Local , l2 : Local ) -> Overlap {
294
- if l1 == l2 {
295
- // the same local - base case, equal
296
- debug ! ( "place_element_conflict: DISJOINT-OR-EQ-LOCAL" ) ;
297
- Overlap :: EqualOrDisjoint
298
- } else {
299
- // different locals - base case, disjoint
300
- debug ! ( "place_element_conflict: DISJOINT-LOCAL" ) ;
301
- Overlap :: Disjoint
302
- }
303
- }
304
-
305
296
// Given that the bases of `elem1` and `elem2` are always either equal
306
297
// or disjoint (and have the same type!), return the overlap situation
307
298
// between `elem1` and `elem2`.
0 commit comments