@@ -17,17 +17,55 @@ use rustc::mir::{Projection, ProjectionElem};
17
17
use rustc:: ty:: { self , TyCtxt } ;
18
18
use std:: cmp:: max;
19
19
20
+ /// When checking if a place conflicts with another place, this enum is used to influence decisions
21
+ /// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`.
22
+ /// `PlaceConflictBias::Overlap` would bias toward assuming that `i` might equal `j` and that these
23
+ /// places overlap. `PlaceConflictBias::NoOverlap` assumes that for the purposes of the predicate
24
+ /// being run in the calling context, the conservative choice is to assume the compared indices
25
+ /// are disjoint (and therefore, do not overlap).
26
+ #[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
27
+ crate enum PlaceConflictBias {
28
+ Overlap ,
29
+ NoOverlap ,
30
+ }
31
+
32
+ /// Helper function for checking if places conflict with a mutable borrow and deep access depth.
33
+ /// This is used to check for places conflicting outside of the borrow checking code (such as in
34
+ /// dataflow).
35
+ crate fn places_conflict < ' gcx , ' tcx > (
36
+ tcx : TyCtxt < ' _ , ' gcx , ' tcx > ,
37
+ mir : & Mir < ' tcx > ,
38
+ borrow_place : & Place < ' tcx > ,
39
+ access_place : & Place < ' tcx > ,
40
+ bias : PlaceConflictBias ,
41
+ ) -> bool {
42
+ borrow_conflicts_with_place (
43
+ tcx,
44
+ mir,
45
+ borrow_place,
46
+ BorrowKind :: Mut { allow_two_phase_borrow : true } ,
47
+ access_place,
48
+ AccessDepth :: Deep ,
49
+ bias,
50
+ )
51
+ }
52
+
53
+ /// Checks whether the `borrow_place` conflicts with the `access_place` given a borrow kind and
54
+ /// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime
55
+ /// array indices, for example) should be interpreted - this depends on what the caller wants in
56
+ /// order to make the conservative choice and preserve soundness.
20
57
pub ( super ) fn borrow_conflicts_with_place < ' gcx , ' tcx > (
21
58
tcx : TyCtxt < ' _ , ' gcx , ' tcx > ,
22
59
mir : & Mir < ' tcx > ,
23
60
borrow_place : & Place < ' tcx > ,
24
61
borrow_kind : BorrowKind ,
25
62
access_place : & Place < ' tcx > ,
26
63
access : AccessDepth ,
64
+ bias : PlaceConflictBias ,
27
65
) -> bool {
28
66
debug ! (
29
- "borrow_conflicts_with_place({:?},{:?},{:?})" ,
30
- borrow_place, access_place, access
67
+ "borrow_conflicts_with_place({:?}, {:?}, {:?}, {:?})" ,
68
+ borrow_place, access_place, access, bias ,
31
69
) ;
32
70
33
71
// This Local/Local case is handled by the more general code below, but
@@ -46,7 +84,8 @@ pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>(
46
84
borrow_components,
47
85
borrow_kind,
48
86
access_components,
49
- access
87
+ access,
88
+ bias,
50
89
)
51
90
} )
52
91
} )
@@ -59,6 +98,7 @@ fn place_components_conflict<'gcx, 'tcx>(
59
98
borrow_kind : BorrowKind ,
60
99
mut access_components : PlaceComponentsIter < ' _ , ' tcx > ,
61
100
access : AccessDepth ,
101
+ bias : PlaceConflictBias ,
62
102
) -> bool {
63
103
// The borrowck rules for proving disjointness are applied from the "root" of the
64
104
// borrow forwards, iterating over "similar" projections in lockstep until
@@ -121,7 +161,7 @@ fn place_components_conflict<'gcx, 'tcx>(
121
161
// check whether the components being borrowed vs
122
162
// accessed are disjoint (as in the second example,
123
163
// but not the first).
124
- match place_element_conflict ( tcx, mir, borrow_c, access_c) {
164
+ match place_element_conflict ( tcx, mir, borrow_c, access_c, bias ) {
125
165
Overlap :: Arbitrary => {
126
166
// We have encountered different fields of potentially
127
167
// the same union - the borrow now partially overlaps.
@@ -193,7 +233,7 @@ fn place_components_conflict<'gcx, 'tcx>(
193
233
bug ! ( "Tracking borrow behind shared reference." ) ;
194
234
}
195
235
( ProjectionElem :: Deref , ty:: Ref ( _, _, hir:: MutMutable ) , AccessDepth :: Drop ) => {
196
- // Values behind a mutatble reference are not access either by Dropping a
236
+ // Values behind a mutable reference are not access either by dropping a
197
237
// value, or by StorageDead
198
238
debug ! ( "borrow_conflicts_with_place: drop access behind ptr" ) ;
199
239
return false ;
@@ -331,6 +371,7 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
331
371
mir : & Mir < ' tcx > ,
332
372
elem1 : & Place < ' tcx > ,
333
373
elem2 : & Place < ' tcx > ,
374
+ bias : PlaceConflictBias ,
334
375
) -> Overlap {
335
376
match ( elem1, elem2) {
336
377
( Place :: Local ( l1) , Place :: Local ( l2) ) => {
@@ -448,10 +489,20 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
448
489
| ( ProjectionElem :: ConstantIndex { .. } , ProjectionElem :: Index ( ..) )
449
490
| ( ProjectionElem :: Subslice { .. } , ProjectionElem :: Index ( ..) ) => {
450
491
// Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint
451
- // (if the indexes differ) or equal (if they are the same), so this
452
- // is the recursive case that gives "equal *or* disjoint" its meaning.
453
- debug ! ( "place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX" ) ;
454
- Overlap :: EqualOrDisjoint
492
+ // (if the indexes differ) or equal (if they are the same).
493
+ match bias {
494
+ PlaceConflictBias :: Overlap => {
495
+ // If we are biased towards overlapping, then this is the recursive
496
+ // case that gives "equal *or* disjoint" its meaning.
497
+ debug ! ( "place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX" ) ;
498
+ Overlap :: EqualOrDisjoint
499
+ }
500
+ PlaceConflictBias :: NoOverlap => {
501
+ // If we are biased towards no overlapping, then this is disjoint.
502
+ debug ! ( "place_element_conflict: DISJOINT-ARRAY-INDEX" ) ;
503
+ Overlap :: Disjoint
504
+ }
505
+ }
455
506
}
456
507
( ProjectionElem :: ConstantIndex { offset : o1, min_length : _, from_end : false } ,
457
508
ProjectionElem :: ConstantIndex { offset : o2, min_length : _, from_end : false } )
0 commit comments