Skip to content

Commit 13a9c20

Browse files
committed
Separate inner closure to fn
1 parent e912a26 commit 13a9c20

File tree

1 file changed

+143
-141
lines changed

1 file changed

+143
-141
lines changed

src/librustc_mir/borrow_check/places_conflict.rs

Lines changed: 143 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@ use borrow_check::ArtificialField;
1212
use borrow_check::Overlap;
1313
use borrow_check::{Deep, Shallow, ShallowOrDeep};
1414
use rustc::hir;
15-
use rustc::mir::{Mir, Place, PlaceBase, PlaceElem, ProjectionElem};
1615
use rustc::mir::tcx::PlaceTy;
16+
use rustc::mir::{Mir, Place, PlaceBase, PlaceElem, ProjectionElem};
1717
use rustc::ty::{self, Ty, TyCtxt};
1818
use std::cmp::max;
1919

20-
// FIXME(csmoe): rewrite place_conflict with slice
21-
2220
pub(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

Comments
 (0)