@@ -12,13 +12,11 @@ use borrow_check::ArtificialField;
1212use borrow_check:: Overlap ;
1313use borrow_check:: { Deep , Shallow , ShallowOrDeep } ;
1414use rustc:: hir;
15- use rustc:: mir:: { Mir , Place , PlaceBase , PlaceElem , ProjectionElem } ;
1615use rustc:: mir:: tcx:: PlaceTy ;
16+ use rustc:: mir:: { Mir , Place , PlaceBase , PlaceElem , ProjectionElem } ;
1717use rustc:: ty:: { self , Ty , TyCtxt } ;
1818use std:: cmp:: max;
1919
20- // FIXME(csmoe): rewrite place_conflict with slice
21-
2220pub ( super ) fn places_conflict < ' gcx , ' tcx > (
2321 tcx : TyCtxt < ' _ , ' gcx , ' tcx > ,
2422 mir : & Mir < ' tcx > ,
@@ -31,148 +29,12 @@ pub(super) fn places_conflict<'gcx, 'tcx>(
3129 borrow_place, access_place, access
3230 ) ;
3331
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-
17132 match place_base_conflict ( tcx, & borrow_place. base , & access_place. base ) {
17233 // if the place.base disjoint, further projections will remain disjoint.
17334 Overlap :: Disjoint => false ,
17435 // 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) ,
17638 // place.base overlap is obvious, no Abitrary.
17739 _ => unreachable ! ( ) ,
17840 }
@@ -452,3 +314,143 @@ fn place_element_conflict<'tcx>(
452314 ) ,
453315 }
454316}
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