@@ -12,13 +12,11 @@ use borrow_check::ArtificialField;
12
12
use borrow_check:: Overlap ;
13
13
use borrow_check:: { Deep , Shallow , ShallowOrDeep } ;
14
14
use rustc:: hir;
15
- use rustc:: mir:: { Mir , Place , PlaceBase , PlaceElem , ProjectionElem } ;
16
15
use rustc:: mir:: tcx:: PlaceTy ;
16
+ use rustc:: mir:: { Mir , Place , PlaceBase , PlaceElem , ProjectionElem } ;
17
17
use rustc:: ty:: { self , Ty , TyCtxt } ;
18
18
use std:: cmp:: max;
19
19
20
- // FIXME(csmoe): rewrite place_conflict with slice
21
-
22
20
pub ( super ) fn places_conflict < ' gcx , ' tcx > (
23
21
tcx : TyCtxt < ' _ , ' gcx , ' tcx > ,
24
22
mir : & Mir < ' tcx > ,
@@ -31,148 +29,12 @@ pub(super) fn places_conflict<'gcx, 'tcx>(
31
29
borrow_place, access_place, access
32
30
) ;
33
31
34
- let place_elements_conflict = |tcx : TyCtxt < ' _ , ' gcx , ' tcx > ,
35
- mir : & Mir < ' tcx > ,
36
- borrow_place : & Place < ' tcx > ,
37
- access_place : & Place < ' tcx > | {
38
- // Enumerate for later base_place generation
39
- let mut borrow_elems = borrow_place. elems . iter ( ) . cloned ( ) ;
40
-
41
- let mut access_elems = access_place. elems . iter ( ) . cloned ( ) ;
42
-
43
- let mut borrow_base_ty = borrow_place. base . ty ( mir) ;
44
-
45
- loop {
46
- if let Some ( borrow_elem) = borrow_elems. next ( ) {
47
- if let Some ( access_elem) = access_elems. next ( ) {
48
- debug ! ( "places_conflict: access_elem = {:?}" , access_elem) ;
49
-
50
- // Borrow and access path both have more components.
51
- //
52
- // Examples:
53
- //
54
- // - borrow of `a.(...)`, access to `a.(...)`
55
- // - borrow of `a.(...)`, access to `b.(...)`
56
- //
57
- // Here we only see the components we have checked so
58
- // far (in our examples, just the first component). We
59
- // check whether the components being borrowed vs
60
- // accessed are disjoint (as in the second example,
61
- // but not the first).
62
- match place_element_conflict ( borrow_base_ty, ( & borrow_elem, & access_elem) ) {
63
- Overlap :: Arbitrary => {
64
- // We have encountered different fields of potentially
65
- // the same union - the borrow now partially overlaps.
66
- //
67
- // There is no *easy* way of comparing the fields
68
- // further on, because they might have different types
69
- // (e.g. borrows of `u.a.0` and `u.b.y` where `.0` and
70
- // `.y` come from different structs).
71
- //
72
- // We could try to do some things here - e.g. count
73
- // dereferences - but that's probably not a good
74
- // idea, at least for now, so just give up and
75
- // report a conflict. This is unsafe code anyway so
76
- // the user could always use raw pointers.
77
- debug ! ( "places_conflict: arbitrary -> conflict" ) ;
78
- return true ;
79
- }
80
- Overlap :: EqualOrDisjoint => {
81
- // proceed to the next element.
82
- }
83
- Overlap :: Disjoint => {
84
- // We have proven the borrow disjoint - further
85
- // projections will remain disjoint.
86
- debug ! ( "places_conflict: disjoint" ) ;
87
- return false ;
88
- }
89
- }
90
- } else {
91
- // Borrow path is longer than the access path. Examples:
92
- //
93
- // - borrow of `a.b.c`, access to `a.b`
94
- //
95
- // Here, we know that the borrow can access a part of
96
- // our place. This is a conflict if that is a part our
97
- // access cares about.
98
-
99
- match ( borrow_elem, & borrow_base_ty. sty , access) {
100
- ( _, _, Shallow ( Some ( ArtificialField :: Discriminant ) ) )
101
- | ( _, _, Shallow ( Some ( ArtificialField :: ArrayLength ) ) ) => {
102
- // The discriminant and array length are like
103
- // additional fields on the type; they do not
104
- // overlap any existing data there. Furthermore,
105
- // they cannot actually be a prefix of any
106
- // borrowed place (at least in MIR as it is
107
- // currently.)
108
- //
109
- // e.g. a (mutable) borrow of `a[5]` while we read the
110
- // array length of `a`.
111
- debug ! ( "places_conflict: implicit field" ) ;
112
- return false ;
113
- }
114
-
115
- ( ProjectionElem :: Deref , _, Shallow ( None ) ) => {
116
- // e.g. a borrow of `*x.y` while we shallowly access `x.y` or some
117
- // prefix thereof - the shallow access can't touch anything behind
118
- // the pointer.
119
- debug ! ( "places_conflict: shallow access behind ptr" ) ;
120
- return false ;
121
- }
122
- ( ProjectionElem :: Deref , ty:: TyRef ( _, _, hir:: MutImmutable ) , _) => {
123
- // the borrow goes through a dereference of a shared reference.
124
- //
125
- // I'm not sure why we are tracking these borrows - shared
126
- // references can *always* be aliased, which means the
127
- // permission check already account for this borrow.
128
- debug ! ( "places_conflict: behind a shared ref" ) ;
129
- return false ;
130
- }
131
-
132
- ( ProjectionElem :: Deref , _, Deep )
133
- | ( ProjectionElem :: Field { .. } , _, _)
134
- | ( ProjectionElem :: Index { .. } , _, _)
135
- | ( ProjectionElem :: ConstantIndex { .. } , _, _)
136
- | ( ProjectionElem :: Subslice { .. } , _, _)
137
- | ( ProjectionElem :: Downcast { .. } , _, _) => {
138
- // Recursive case. This can still be disjoint on a
139
- // further iteration if this a shallow access and
140
- // there's a deref later on, e.g. a borrow
141
- // of `*x.y` while accessing `x`.
142
- }
143
- }
144
- }
145
- borrow_base_ty = PlaceTy :: from ( borrow_base_ty)
146
- . projection_ty ( tcx, & borrow_elem)
147
- . to_ty ( tcx) ;
148
- } else {
149
- // Borrow path ran out but access path may not
150
- // have. Examples:
151
- //
152
- // - borrow of `a.b`, access to `a.b.c`
153
- // - borrow of `a.b`, access to `a.b`
154
- //
155
- // In the first example, where we didn't run out of
156
- // access, the borrow can access all of our place, so we
157
- // have a conflict.
158
- //
159
- // If the second example, where we did, then we still know
160
- // that the borrow can access a *part* of our place that
161
- // our access cares about, so we still have a conflict.
162
- //
163
- // FIXME: Differs from AST-borrowck; includes drive-by fix
164
- // to #38899. Will probably need back-compat mode flag.
165
- debug ! ( "places_conflict: full borrow, CONFLICT" ) ;
166
- return true ;
167
- }
168
- }
169
- } ;
170
-
171
32
match place_base_conflict ( tcx, & borrow_place. base , & access_place. base ) {
172
33
// if the place.base disjoint, further projections will remain disjoint.
173
34
Overlap :: Disjoint => false ,
174
35
// process to projections to check further conflict.
175
- Overlap :: EqualOrDisjoint => place_elements_conflict ( tcx, mir, borrow_place, access_place) ,
36
+ Overlap :: EqualOrDisjoint =>
37
+ place_elements_conflict ( tcx, mir, borrow_place, access_place, access) ,
176
38
// place.base overlap is obvious, no Abitrary.
177
39
_ => unreachable ! ( ) ,
178
40
}
@@ -452,3 +314,143 @@ fn place_element_conflict<'tcx>(
452
314
) ,
453
315
}
454
316
}
317
+
318
+ fn place_elements_conflict < ' gcx , ' tcx > (
319
+ tcx : TyCtxt < ' _ , ' gcx , ' tcx > ,
320
+ mir : & Mir < ' tcx > ,
321
+ borrow_place : & Place < ' tcx > ,
322
+ access_place : & Place < ' tcx > ,
323
+ access : ShallowOrDeep ,
324
+ ) -> bool {
325
+ // Enumerate for later base_place generation
326
+ let mut borrow_elems = borrow_place. elems . iter ( ) . cloned ( ) ;
327
+
328
+ let mut access_elems = access_place. elems . iter ( ) . cloned ( ) ;
329
+
330
+ let mut borrow_base_ty = borrow_place. base . ty ( mir) ;
331
+
332
+ loop {
333
+ if let Some ( borrow_elem) = borrow_elems. next ( ) {
334
+ if let Some ( access_elem) = access_elems. next ( ) {
335
+ debug ! ( "places_conflict: access_elem = {:?}" , access_elem) ;
336
+
337
+ // Borrow and access path both have more components.
338
+ //
339
+ // Examples:
340
+ //
341
+ // - borrow of `a.(...)`, access to `a.(...)`
342
+ // - borrow of `a.(...)`, access to `b.(...)`
343
+ //
344
+ // Here we only see the components we have checked so
345
+ // far (in our examples, just the first component). We
346
+ // check whether the components being borrowed vs
347
+ // accessed are disjoint (as in the second example,
348
+ // but not the first).
349
+ match place_element_conflict ( borrow_base_ty, ( & borrow_elem, & access_elem) ) {
350
+ Overlap :: Arbitrary => {
351
+ // We have encountered different fields of potentially
352
+ // the same union - the borrow now partially overlaps.
353
+ //
354
+ // There is no *easy* way of comparing the fields
355
+ // further on, because they might have different types
356
+ // (e.g. borrows of `u.a.0` and `u.b.y` where `.0` and
357
+ // `.y` come from different structs).
358
+ //
359
+ // We could try to do some things here - e.g. count
360
+ // dereferences - but that's probably not a good
361
+ // idea, at least for now, so just give up and
362
+ // report a conflict. This is unsafe code anyway so
363
+ // the user could always use raw pointers.
364
+ debug ! ( "places_conflict: arbitrary -> conflict" ) ;
365
+ return true ;
366
+ }
367
+ Overlap :: EqualOrDisjoint => {
368
+ // proceed to the next element.
369
+ }
370
+ Overlap :: Disjoint => {
371
+ // We have proven the borrow disjoint - further
372
+ // projections will remain disjoint.
373
+ debug ! ( "places_conflict: disjoint" ) ;
374
+ return false ;
375
+ }
376
+ }
377
+ } else {
378
+ // Borrow path is longer than the access path. Examples:
379
+ //
380
+ // - borrow of `a.b.c`, access to `a.b`
381
+ //
382
+ // Here, we know that the borrow can access a part of
383
+ // our place. This is a conflict if that is a part our
384
+ // access cares about.
385
+
386
+ match ( borrow_elem, & borrow_base_ty. sty , access) {
387
+ ( _, _, Shallow ( Some ( ArtificialField :: Discriminant ) ) )
388
+ | ( _, _, Shallow ( Some ( ArtificialField :: ArrayLength ) ) ) => {
389
+ // The discriminant and array length are like
390
+ // additional fields on the type; they do not
391
+ // overlap any existing data there. Furthermore,
392
+ // they cannot actually be a prefix of any
393
+ // borrowed place (at least in MIR as it is
394
+ // currently.)
395
+ //
396
+ // e.g. a (mutable) borrow of `a[5]` while we read the
397
+ // array length of `a`.
398
+ debug ! ( "places_conflict: implicit field" ) ;
399
+ return false ;
400
+ }
401
+
402
+ ( ProjectionElem :: Deref , _, Shallow ( None ) ) => {
403
+ // e.g. a borrow of `*x.y` while we shallowly access `x.y` or some
404
+ // prefix thereof - the shallow access can't touch anything behind
405
+ // the pointer.
406
+ debug ! ( "places_conflict: shallow access behind ptr" ) ;
407
+ return false ;
408
+ }
409
+ ( ProjectionElem :: Deref , ty:: TyRef ( _, _, hir:: MutImmutable ) , _) => {
410
+ // the borrow goes through a dereference of a shared reference.
411
+ //
412
+ // I'm not sure why we are tracking these borrows - shared
413
+ // references can *always* be aliased, which means the
414
+ // permission check already account for this borrow.
415
+ debug ! ( "places_conflict: behind a shared ref" ) ;
416
+ return false ;
417
+ }
418
+
419
+ ( ProjectionElem :: Deref , _, Deep )
420
+ | ( ProjectionElem :: Field { .. } , _, _)
421
+ | ( ProjectionElem :: Index { .. } , _, _)
422
+ | ( ProjectionElem :: ConstantIndex { .. } , _, _)
423
+ | ( ProjectionElem :: Subslice { .. } , _, _)
424
+ | ( ProjectionElem :: Downcast { .. } , _, _) => {
425
+ // Recursive case. This can still be disjoint on a
426
+ // further iteration if this a shallow access and
427
+ // there's a deref later on, e.g. a borrow
428
+ // of `*x.y` while accessing `x`.
429
+ }
430
+ }
431
+ }
432
+ borrow_base_ty = PlaceTy :: from ( borrow_base_ty)
433
+ . projection_ty ( tcx, & borrow_elem)
434
+ . to_ty ( tcx) ;
435
+ } else {
436
+ // Borrow path ran out but access path may not
437
+ // have. Examples:
438
+ //
439
+ // - borrow of `a.b`, access to `a.b.c`
440
+ // - borrow of `a.b`, access to `a.b`
441
+ //
442
+ // In the first example, where we didn't run out of
443
+ // access, the borrow can access all of our place, so we
444
+ // have a conflict.
445
+ //
446
+ // If the second example, where we did, then we still know
447
+ // that the borrow can access a *part* of our place that
448
+ // our access cares about, so we still have a conflict.
449
+ //
450
+ // FIXME: Differs from AST-borrowck; includes drive-by fix
451
+ // to #38899. Will probably need back-compat mode flag.
452
+ debug ! ( "places_conflict: full borrow, CONFLICT" ) ;
453
+ return true ;
454
+ }
455
+ }
456
+ }
0 commit comments