2019-02-08 06:28:15 +09:00
|
|
|
use crate::borrow_check::ArtificialField;
|
|
|
|
use crate::borrow_check::Overlap;
|
|
|
|
use crate::borrow_check::{Deep, Shallow, AccessDepth};
|
2018-06-27 11:16:24 -04:00
|
|
|
use rustc::hir;
|
2019-02-26 23:41:38 +01:00
|
|
|
use rustc::mir::{
|
2019-05-17 23:55:04 +02:00
|
|
|
BorrowKind, Body, Place, PlaceBase, Projection, ProjectionElem, ProjectionsIter,
|
2019-03-01 02:37:35 +01:00
|
|
|
StaticKind
|
2019-02-26 23:41:38 +01:00
|
|
|
};
|
2018-06-27 11:16:24 -04:00
|
|
|
use rustc::ty::{self, TyCtxt};
|
2018-07-04 07:45:01 +01:00
|
|
|
use std::cmp::max;
|
2018-06-27 11:16:24 -04:00
|
|
|
|
2018-12-17 13:11:33 +01:00
|
|
|
/// When checking if a place conflicts with another place, this enum is used to influence decisions
|
|
|
|
/// where a place might be equal or disjoint with another place, such as if `a[i] == a[j]`.
|
|
|
|
/// `PlaceConflictBias::Overlap` would bias toward assuming that `i` might equal `j` and that these
|
|
|
|
/// places overlap. `PlaceConflictBias::NoOverlap` assumes that for the purposes of the predicate
|
|
|
|
/// being run in the calling context, the conservative choice is to assume the compared indices
|
|
|
|
/// are disjoint (and therefore, do not overlap).
|
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
|
|
|
crate enum PlaceConflictBias {
|
|
|
|
Overlap,
|
|
|
|
NoOverlap,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Helper function for checking if places conflict with a mutable borrow and deep access depth.
|
|
|
|
/// This is used to check for places conflicting outside of the borrow checking code (such as in
|
|
|
|
/// dataflow).
|
|
|
|
crate fn places_conflict<'gcx, 'tcx>(
|
2019-06-11 23:47:08 +03:00
|
|
|
tcx: TyCtxt<'gcx, 'tcx>,
|
2019-06-03 18:26:48 -04:00
|
|
|
body: &Body<'tcx>,
|
2018-12-17 13:11:33 +01:00
|
|
|
borrow_place: &Place<'tcx>,
|
|
|
|
access_place: &Place<'tcx>,
|
|
|
|
bias: PlaceConflictBias,
|
|
|
|
) -> bool {
|
|
|
|
borrow_conflicts_with_place(
|
|
|
|
tcx,
|
2019-06-03 18:26:48 -04:00
|
|
|
body,
|
2018-12-17 13:11:33 +01:00
|
|
|
borrow_place,
|
|
|
|
BorrowKind::Mut { allow_two_phase_borrow: true },
|
|
|
|
access_place,
|
|
|
|
AccessDepth::Deep,
|
|
|
|
bias,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks whether the `borrow_place` conflicts with the `access_place` given a borrow kind and
|
|
|
|
/// access depth. The `bias` parameter is used to determine how the unknowable (comparing runtime
|
|
|
|
/// array indices, for example) should be interpreted - this depends on what the caller wants in
|
|
|
|
/// order to make the conservative choice and preserve soundness.
|
2018-09-23 11:33:52 +01:00
|
|
|
pub(super) fn borrow_conflicts_with_place<'gcx, 'tcx>(
|
2019-06-11 23:47:08 +03:00
|
|
|
tcx: TyCtxt<'gcx, 'tcx>,
|
2019-06-03 18:26:48 -04:00
|
|
|
body: &Body<'tcx>,
|
2018-06-27 11:16:24 -04:00
|
|
|
borrow_place: &Place<'tcx>,
|
2018-09-10 22:33:45 +01:00
|
|
|
borrow_kind: BorrowKind,
|
2018-06-27 11:16:24 -04:00
|
|
|
access_place: &Place<'tcx>,
|
2018-09-23 16:07:45 +01:00
|
|
|
access: AccessDepth,
|
2018-12-17 13:11:33 +01:00
|
|
|
bias: PlaceConflictBias,
|
2018-06-27 11:16:24 -04:00
|
|
|
) -> bool {
|
|
|
|
debug!(
|
2018-12-17 13:11:33 +01:00
|
|
|
"borrow_conflicts_with_place({:?}, {:?}, {:?}, {:?})",
|
|
|
|
borrow_place, access_place, access, bias,
|
2018-06-27 11:16:24 -04:00
|
|
|
);
|
|
|
|
|
2018-08-27 16:40:42 +10:00
|
|
|
// This Local/Local case is handled by the more general code below, but
|
|
|
|
// it's so common that it's a speed win to check for it first.
|
2019-02-22 05:24:03 +01:00
|
|
|
if let Place::Base(PlaceBase::Local(l1)) = borrow_place {
|
|
|
|
if let Place::Base(PlaceBase::Local(l2)) = access_place {
|
2018-08-27 16:40:42 +10:00
|
|
|
return l1 == l2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-01 02:37:35 +01:00
|
|
|
borrow_place.iterate(|borrow_base, borrow_projections| {
|
|
|
|
access_place.iterate(|access_base, access_projections| {
|
2018-09-10 22:33:45 +01:00
|
|
|
place_components_conflict(
|
|
|
|
tcx,
|
2019-06-03 18:26:48 -04:00
|
|
|
body,
|
2019-03-01 02:37:35 +01:00
|
|
|
(borrow_base, borrow_projections),
|
2018-09-10 22:33:45 +01:00
|
|
|
borrow_kind,
|
2019-03-01 02:37:35 +01:00
|
|
|
(access_base, access_projections),
|
2018-12-17 13:11:33 +01:00
|
|
|
access,
|
|
|
|
bias,
|
2018-09-10 22:33:45 +01:00
|
|
|
)
|
2018-06-27 11:46:48 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
2018-06-27 11:16:24 -04:00
|
|
|
|
2018-06-27 11:46:48 -04:00
|
|
|
fn place_components_conflict<'gcx, 'tcx>(
|
2019-06-11 23:47:08 +03:00
|
|
|
tcx: TyCtxt<'gcx, 'tcx>,
|
2019-06-03 18:26:48 -04:00
|
|
|
body: &Body<'tcx>,
|
2019-05-01 15:34:51 +01:00
|
|
|
borrow_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>),
|
2018-09-10 22:33:45 +01:00
|
|
|
borrow_kind: BorrowKind,
|
2019-05-01 15:34:51 +01:00
|
|
|
access_projections: (&PlaceBase<'tcx>, ProjectionsIter<'_, 'tcx>),
|
2018-09-23 16:07:45 +01:00
|
|
|
access: AccessDepth,
|
2018-12-17 13:11:33 +01:00
|
|
|
bias: PlaceConflictBias,
|
2018-06-27 11:46:48 -04:00
|
|
|
) -> bool {
|
2018-06-27 11:16:24 -04:00
|
|
|
// The borrowck rules for proving disjointness are applied from the "root" of the
|
|
|
|
// borrow forwards, iterating over "similar" projections in lockstep until
|
|
|
|
// we can prove overlap one way or another. Essentially, we treat `Overlap` as
|
|
|
|
// a monoid and report a conflict if the product ends up not being `Disjoint`.
|
|
|
|
//
|
|
|
|
// At each step, if we didn't run out of borrow or place, we know that our elements
|
|
|
|
// have the same type, and that they only overlap if they are the identical.
|
|
|
|
//
|
|
|
|
// For example, if we are comparing these:
|
|
|
|
// BORROW: (*x1[2].y).z.a
|
|
|
|
// ACCESS: (*x1[i].y).w.b
|
|
|
|
//
|
|
|
|
// Then our steps are:
|
|
|
|
// x1 | x1 -- places are the same
|
|
|
|
// x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ)
|
|
|
|
// x1[2].y | x1[i].y -- equal or disjoint
|
|
|
|
// *x1[2].y | *x1[i].y -- equal or disjoint
|
|
|
|
// (*x1[2].y).z | (*x1[i].y).w -- we are disjoint and don't need to check more!
|
|
|
|
//
|
|
|
|
// Because `zip` does potentially bad things to the iterator inside, this loop
|
|
|
|
// also handles the case where the access might be a *prefix* of the borrow, e.g.
|
|
|
|
//
|
|
|
|
// BORROW: (*x1[2].y).z.a
|
|
|
|
// ACCESS: x1[i].y
|
|
|
|
//
|
|
|
|
// Then our steps are:
|
|
|
|
// x1 | x1 -- places are the same
|
|
|
|
// x1[2] | x1[i] -- equal or disjoint (disjoint if indexes differ)
|
|
|
|
// x1[2].y | x1[i].y -- equal or disjoint
|
|
|
|
//
|
|
|
|
// -- here we run out of access - the borrow can access a part of it. If this
|
|
|
|
// is a full deep access, then we *know* the borrow conflicts with it. However,
|
|
|
|
// if the access is shallow, then we can proceed:
|
|
|
|
//
|
|
|
|
// x1[2].y | (*x1[i].y) -- a deref! the access can't get past this, so we
|
|
|
|
// are disjoint
|
|
|
|
//
|
|
|
|
// Our invariant is, that at each step of the iteration:
|
|
|
|
// - If we didn't run out of access to match, our borrow and access are comparable
|
|
|
|
// and either equal or disjoint.
|
2018-08-19 15:30:23 +02:00
|
|
|
// - If we did run out of access, the borrow can access a part of it.
|
2019-03-01 02:37:35 +01:00
|
|
|
|
|
|
|
let borrow_base = borrow_projections.0;
|
|
|
|
let access_base = access_projections.0;
|
|
|
|
|
|
|
|
match place_base_conflict(tcx, borrow_base, access_base) {
|
|
|
|
Overlap::Arbitrary => {
|
|
|
|
bug!("Two base can't return Arbitrary");
|
|
|
|
}
|
|
|
|
Overlap::EqualOrDisjoint => {
|
|
|
|
// This is the recursive case - proceed to the next element.
|
|
|
|
}
|
|
|
|
Overlap::Disjoint => {
|
|
|
|
// We have proven the borrow disjoint - further
|
|
|
|
// projections will remain disjoint.
|
|
|
|
debug!("borrow_conflicts_with_place: disjoint");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut borrow_projections = borrow_projections.1;
|
|
|
|
let mut access_projections = access_projections.1;
|
|
|
|
|
2018-06-27 12:58:29 -04:00
|
|
|
loop {
|
2018-06-27 11:16:24 -04:00
|
|
|
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
|
2019-03-01 02:37:35 +01:00
|
|
|
if let Some(borrow_c) = borrow_projections.next() {
|
2018-09-23 11:33:52 +01:00
|
|
|
debug!("borrow_conflicts_with_place: borrow_c = {:?}", borrow_c);
|
2018-06-27 12:58:29 -04:00
|
|
|
|
2019-03-01 02:37:35 +01:00
|
|
|
if let Some(access_c) = access_projections.next() {
|
2018-09-23 11:33:52 +01:00
|
|
|
debug!("borrow_conflicts_with_place: access_c = {:?}", access_c);
|
2018-06-27 12:58:29 -04:00
|
|
|
|
2018-06-27 11:46:48 -04:00
|
|
|
// Borrow and access path both have more components.
|
2018-06-27 11:16:24 -04:00
|
|
|
//
|
2018-06-27 11:46:48 -04:00
|
|
|
// Examples:
|
2018-06-27 11:16:24 -04:00
|
|
|
//
|
2018-06-27 11:46:48 -04:00
|
|
|
// - borrow of `a.(...)`, access to `a.(...)`
|
|
|
|
// - borrow of `a.(...)`, access to `b.(...)`
|
|
|
|
//
|
|
|
|
// Here we only see the components we have checked so
|
|
|
|
// far (in our examples, just the first component). We
|
|
|
|
// check whether the components being borrowed vs
|
|
|
|
// accessed are disjoint (as in the second example,
|
|
|
|
// but not the first).
|
2019-06-03 18:26:48 -04:00
|
|
|
match place_projection_conflict(tcx, body, borrow_c, access_c, bias) {
|
2018-06-27 11:46:48 -04:00
|
|
|
Overlap::Arbitrary => {
|
|
|
|
// We have encountered different fields of potentially
|
|
|
|
// the same union - the borrow now partially overlaps.
|
|
|
|
//
|
|
|
|
// There is no *easy* way of comparing the fields
|
|
|
|
// further on, because they might have different types
|
2018-11-27 02:59:49 +00:00
|
|
|
// (e.g., borrows of `u.a.0` and `u.b.y` where `.0` and
|
2018-06-27 11:46:48 -04:00
|
|
|
// `.y` come from different structs).
|
|
|
|
//
|
2018-11-27 02:59:49 +00:00
|
|
|
// We could try to do some things here - e.g., count
|
2018-06-27 11:46:48 -04:00
|
|
|
// dereferences - but that's probably not a good
|
|
|
|
// idea, at least for now, so just give up and
|
|
|
|
// report a conflict. This is unsafe code anyway so
|
|
|
|
// the user could always use raw pointers.
|
2018-09-23 11:33:52 +01:00
|
|
|
debug!("borrow_conflicts_with_place: arbitrary -> conflict");
|
2018-06-27 11:46:48 -04:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
Overlap::EqualOrDisjoint => {
|
|
|
|
// This is the recursive case - proceed to the next element.
|
|
|
|
}
|
|
|
|
Overlap::Disjoint => {
|
|
|
|
// We have proven the borrow disjoint - further
|
|
|
|
// projections will remain disjoint.
|
2018-09-23 11:33:52 +01:00
|
|
|
debug!("borrow_conflicts_with_place: disjoint");
|
2018-06-27 11:46:48 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Borrow path is longer than the access path. Examples:
|
|
|
|
//
|
|
|
|
// - borrow of `a.b.c`, access to `a.b`
|
|
|
|
//
|
|
|
|
// Here, we know that the borrow can access a part of
|
|
|
|
// our place. This is a conflict if that is a part our
|
|
|
|
// access cares about.
|
2018-06-27 11:16:24 -04:00
|
|
|
|
2019-03-01 02:37:35 +01:00
|
|
|
let base = &borrow_c.base;
|
|
|
|
let elem = &borrow_c.elem;
|
2019-06-03 18:26:48 -04:00
|
|
|
let base_ty = base.ty(body, tcx).ty;
|
2018-06-27 11:16:24 -04:00
|
|
|
|
|
|
|
match (elem, &base_ty.sty, access) {
|
2018-12-13 20:53:07 +00:00
|
|
|
(_, _, Shallow(Some(ArtificialField::ArrayLength)))
|
2018-09-10 22:33:45 +01:00
|
|
|
| (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => {
|
2018-12-13 20:53:07 +00:00
|
|
|
// The array length is like additional fields on the
|
|
|
|
// type; it does not overlap any existing data there.
|
|
|
|
// Furthermore, if cannot actually be a prefix of any
|
|
|
|
// borrowed place (at least in MIR as it is currently.)
|
2018-06-27 13:32:00 -04:00
|
|
|
//
|
2018-11-27 02:59:49 +00:00
|
|
|
// e.g., a (mutable) borrow of `a[5]` while we read the
|
2018-06-27 13:32:00 -04:00
|
|
|
// array length of `a`.
|
2018-09-23 11:33:52 +01:00
|
|
|
debug!("borrow_conflicts_with_place: implicit field");
|
2018-06-27 13:32:00 -04:00
|
|
|
return false;
|
|
|
|
}
|
2018-06-27 11:16:24 -04:00
|
|
|
|
|
|
|
(ProjectionElem::Deref, _, Shallow(None)) => {
|
2018-11-27 02:59:49 +00:00
|
|
|
// e.g., a borrow of `*x.y` while we shallowly access `x.y` or some
|
2018-06-27 11:16:24 -04:00
|
|
|
// prefix thereof - the shallow access can't touch anything behind
|
|
|
|
// the pointer.
|
2018-09-23 11:33:52 +01:00
|
|
|
debug!("borrow_conflicts_with_place: shallow access behind ptr");
|
2018-06-27 11:16:24 -04:00
|
|
|
return false;
|
|
|
|
}
|
2018-08-22 01:35:02 +01:00
|
|
|
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutImmutable), _) => {
|
2018-09-23 16:07:45 +01:00
|
|
|
// Shouldn't be tracked
|
|
|
|
bug!("Tracking borrow behind shared reference.");
|
|
|
|
}
|
|
|
|
(ProjectionElem::Deref, ty::Ref(_, _, hir::MutMutable), AccessDepth::Drop) => {
|
2018-12-17 13:11:33 +01:00
|
|
|
// Values behind a mutable reference are not access either by dropping a
|
2018-09-23 16:07:45 +01:00
|
|
|
// value, or by StorageDead
|
2018-09-23 11:33:52 +01:00
|
|
|
debug!("borrow_conflicts_with_place: drop access behind ptr");
|
2018-06-27 11:16:24 -04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-09-23 16:07:45 +01:00
|
|
|
(ProjectionElem::Field { .. }, ty::Adt(def, _), AccessDepth::Drop) => {
|
|
|
|
// Drop can read/write arbitrary projections, so places
|
|
|
|
// conflict regardless of further projections.
|
|
|
|
if def.has_dtor(tcx) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-27 11:16:24 -04:00
|
|
|
(ProjectionElem::Deref, _, Deep)
|
2018-09-23 16:07:45 +01:00
|
|
|
| (ProjectionElem::Deref, _, AccessDepth::Drop)
|
2018-06-27 13:32:00 -04:00
|
|
|
| (ProjectionElem::Field { .. }, _, _)
|
|
|
|
| (ProjectionElem::Index { .. }, _, _)
|
|
|
|
| (ProjectionElem::ConstantIndex { .. }, _, _)
|
|
|
|
| (ProjectionElem::Subslice { .. }, _, _)
|
|
|
|
| (ProjectionElem::Downcast { .. }, _, _) => {
|
|
|
|
// Recursive case. This can still be disjoint on a
|
|
|
|
// further iteration if this a shallow access and
|
2018-11-27 02:59:49 +00:00
|
|
|
// there's a deref later on, e.g., a borrow
|
2018-06-27 13:32:00 -04:00
|
|
|
// of `*x.y` while accessing `x`.
|
|
|
|
}
|
2018-06-27 11:16:24 -04:00
|
|
|
}
|
|
|
|
}
|
2018-06-27 11:46:48 -04:00
|
|
|
} else {
|
|
|
|
// Borrow path ran out but access path may not
|
|
|
|
// have. Examples:
|
|
|
|
//
|
|
|
|
// - borrow of `a.b`, access to `a.b.c`
|
|
|
|
// - borrow of `a.b`, access to `a.b`
|
|
|
|
//
|
|
|
|
// In the first example, where we didn't run out of
|
|
|
|
// access, the borrow can access all of our place, so we
|
|
|
|
// have a conflict.
|
|
|
|
//
|
|
|
|
// If the second example, where we did, then we still know
|
|
|
|
// that the borrow can access a *part* of our place that
|
|
|
|
// our access cares about, so we still have a conflict.
|
2019-03-01 02:37:35 +01:00
|
|
|
if borrow_kind == BorrowKind::Shallow && access_projections.next().is_some() {
|
2018-09-23 11:33:52 +01:00
|
|
|
debug!("borrow_conflicts_with_place: shallow borrow");
|
2018-09-10 22:33:45 +01:00
|
|
|
return false;
|
|
|
|
} else {
|
2018-09-23 11:33:52 +01:00
|
|
|
debug!("borrow_conflicts_with_place: full borrow, CONFLICT");
|
2018-09-10 22:33:45 +01:00
|
|
|
return true;
|
|
|
|
}
|
2018-06-27 11:16:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Given that the bases of `elem1` and `elem2` are always either equal
|
|
|
|
// or disjoint (and have the same type!), return the overlap situation
|
|
|
|
// between `elem1` and `elem2`.
|
2019-06-11 23:35:39 +03:00
|
|
|
fn place_base_conflict<'gcx: 'tcx, 'tcx>(
|
2019-06-11 23:47:08 +03:00
|
|
|
tcx: TyCtxt<'gcx, 'tcx>,
|
2019-03-01 02:37:35 +01:00
|
|
|
elem1: &PlaceBase<'tcx>,
|
|
|
|
elem2: &PlaceBase<'tcx>,
|
2018-06-27 11:16:24 -04:00
|
|
|
) -> Overlap {
|
|
|
|
match (elem1, elem2) {
|
2019-03-01 02:37:35 +01:00
|
|
|
(PlaceBase::Local(l1), PlaceBase::Local(l2)) => {
|
2018-06-27 11:16:24 -04:00
|
|
|
if l1 == l2 {
|
|
|
|
// the same local - base case, equal
|
|
|
|
debug!("place_element_conflict: DISJOINT-OR-EQ-LOCAL");
|
|
|
|
Overlap::EqualOrDisjoint
|
|
|
|
} else {
|
|
|
|
// different locals - base case, disjoint
|
|
|
|
debug!("place_element_conflict: DISJOINT-LOCAL");
|
|
|
|
Overlap::Disjoint
|
|
|
|
}
|
|
|
|
}
|
2019-03-01 02:37:35 +01:00
|
|
|
(PlaceBase::Static(s1), PlaceBase::Static(s2)) => {
|
2019-03-24 08:59:11 +05:30
|
|
|
match (&s1.kind, &s2.kind) {
|
|
|
|
(StaticKind::Static(def_id_1), StaticKind::Static(def_id_2)) => {
|
|
|
|
if def_id_1 != def_id_2 {
|
|
|
|
debug!("place_element_conflict: DISJOINT-STATIC");
|
|
|
|
Overlap::Disjoint
|
2019-04-21 14:41:51 +03:00
|
|
|
} else if tcx.is_mutable_static(*def_id_1) {
|
2019-03-24 08:59:11 +05:30
|
|
|
// We ignore mutable statics - they can only be unsafe code.
|
|
|
|
debug!("place_element_conflict: IGNORE-STATIC-MUT");
|
|
|
|
Overlap::Disjoint
|
|
|
|
} else {
|
|
|
|
debug!("place_element_conflict: DISJOINT-OR-EQ-STATIC");
|
|
|
|
Overlap::EqualOrDisjoint
|
2019-03-16 17:40:41 +05:30
|
|
|
}
|
2019-03-24 08:59:11 +05:30
|
|
|
},
|
|
|
|
(StaticKind::Promoted(promoted_1), StaticKind::Promoted(promoted_2)) => {
|
|
|
|
if promoted_1 == promoted_2 {
|
2019-05-31 00:26:30 +01:00
|
|
|
if let ty::Array(_, len) = s1.ty.sty {
|
|
|
|
if let Some(0) = len.assert_usize(tcx) {
|
2019-03-24 08:59:11 +05:30
|
|
|
// Ignore conflicts with promoted [T; 0].
|
|
|
|
debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
|
|
|
|
return Overlap::Disjoint;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// the same promoted - base case, equal
|
|
|
|
debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED");
|
|
|
|
Overlap::EqualOrDisjoint
|
|
|
|
} else {
|
|
|
|
// different promoteds - base case, disjoint
|
|
|
|
debug!("place_element_conflict: DISJOINT-PROMOTED");
|
|
|
|
Overlap::Disjoint
|
|
|
|
}
|
|
|
|
},
|
|
|
|
(_, _) => {
|
|
|
|
debug!("place_element_conflict: DISJOINT-STATIC-PROMOTED");
|
|
|
|
Overlap::Disjoint
|
2018-07-31 21:35:22 +01:00
|
|
|
}
|
2018-07-22 12:20:50 +02:00
|
|
|
}
|
|
|
|
}
|
2019-03-01 02:37:35 +01:00
|
|
|
(PlaceBase::Local(_), PlaceBase::Static(_)) |
|
|
|
|
(PlaceBase::Static(_), PlaceBase::Local(_)) => {
|
2018-07-22 12:20:50 +02:00
|
|
|
debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED");
|
2018-06-27 11:16:24 -04:00
|
|
|
Overlap::Disjoint
|
|
|
|
}
|
2019-03-01 02:37:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Given that the bases of `elem1` and `elem2` are always either equal
|
|
|
|
// or disjoint (and have the same type!), return the overlap situation
|
|
|
|
// between `elem1` and `elem2`.
|
2019-06-11 23:35:39 +03:00
|
|
|
fn place_projection_conflict<'gcx: 'tcx, 'tcx>(
|
2019-06-11 23:47:08 +03:00
|
|
|
tcx: TyCtxt<'gcx, 'tcx>,
|
2019-06-03 18:26:48 -04:00
|
|
|
body: &Body<'tcx>,
|
2019-05-01 15:34:51 +01:00
|
|
|
pi1: &Projection<'tcx>,
|
|
|
|
pi2: &Projection<'tcx>,
|
2019-03-01 02:37:35 +01:00
|
|
|
bias: PlaceConflictBias,
|
|
|
|
) -> Overlap {
|
|
|
|
match (&pi1.elem, &pi2.elem) {
|
|
|
|
(ProjectionElem::Deref, ProjectionElem::Deref) => {
|
|
|
|
// derefs (e.g., `*x` vs. `*x`) - recur.
|
|
|
|
debug!("place_element_conflict: DISJOINT-OR-EQ-DEREF");
|
|
|
|
Overlap::EqualOrDisjoint
|
|
|
|
}
|
|
|
|
(ProjectionElem::Field(f1, _), ProjectionElem::Field(f2, _)) => {
|
|
|
|
if f1 == f2 {
|
|
|
|
// same field (e.g., `a.y` vs. `a.y`) - recur.
|
|
|
|
debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
|
|
|
|
Overlap::EqualOrDisjoint
|
|
|
|
} else {
|
2019-06-03 18:26:48 -04:00
|
|
|
let ty = pi1.base.ty(body, tcx).ty;
|
2019-03-01 02:37:35 +01:00
|
|
|
match ty.sty {
|
|
|
|
ty::Adt(def, _) if def.is_union() => {
|
|
|
|
// Different fields of a union, we are basically stuck.
|
|
|
|
debug!("place_element_conflict: STUCK-UNION");
|
|
|
|
Overlap::Arbitrary
|
2018-06-27 11:16:24 -04:00
|
|
|
}
|
2019-03-01 02:37:35 +01:00
|
|
|
_ => {
|
|
|
|
// Different fields of a struct (`a.x` vs. `a.y`). Disjoint!
|
2018-06-27 11:16:24 -04:00
|
|
|
debug!("place_element_conflict: DISJOINT-FIELD");
|
|
|
|
Overlap::Disjoint
|
|
|
|
}
|
|
|
|
}
|
2019-03-01 02:37:35 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
(ProjectionElem::Downcast(_, v1), ProjectionElem::Downcast(_, v2)) => {
|
|
|
|
// different variants are treated as having disjoint fields,
|
|
|
|
// even if they occupy the same "space", because it's
|
|
|
|
// impossible for 2 variants of the same enum to exist
|
|
|
|
// (and therefore, to be borrowed) at the same time.
|
|
|
|
//
|
|
|
|
// Note that this is different from unions - we *do* allow
|
|
|
|
// this code to compile:
|
|
|
|
//
|
|
|
|
// ```
|
|
|
|
// fn foo(x: &mut Result<i32, i32>) {
|
|
|
|
// let mut v = None;
|
|
|
|
// if let Ok(ref mut a) = *x {
|
|
|
|
// v = Some(a);
|
|
|
|
// }
|
|
|
|
// // here, you would *think* that the
|
|
|
|
// // *entirety* of `x` would be borrowed,
|
|
|
|
// // but in fact only the `Ok` variant is,
|
|
|
|
// // so the `Err` variant is *entirely free*:
|
|
|
|
// if let Err(ref mut a) = *x {
|
|
|
|
// v = Some(a);
|
|
|
|
// }
|
|
|
|
// drop(v);
|
|
|
|
// }
|
|
|
|
// ```
|
|
|
|
if v1 == v2 {
|
|
|
|
debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD");
|
|
|
|
Overlap::EqualOrDisjoint
|
|
|
|
} else {
|
|
|
|
debug!("place_element_conflict: DISJOINT-FIELD");
|
|
|
|
Overlap::Disjoint
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(ProjectionElem::Index(..), ProjectionElem::Index(..))
|
|
|
|
| (ProjectionElem::Index(..), ProjectionElem::ConstantIndex { .. })
|
|
|
|
| (ProjectionElem::Index(..), ProjectionElem::Subslice { .. })
|
|
|
|
| (ProjectionElem::ConstantIndex { .. }, ProjectionElem::Index(..))
|
|
|
|
| (ProjectionElem::Subslice { .. }, ProjectionElem::Index(..)) => {
|
|
|
|
// Array indexes (`a[0]` vs. `a[i]`). These can either be disjoint
|
|
|
|
// (if the indexes differ) or equal (if they are the same).
|
|
|
|
match bias {
|
|
|
|
PlaceConflictBias::Overlap => {
|
|
|
|
// If we are biased towards overlapping, then this is the recursive
|
|
|
|
// case that gives "equal *or* disjoint" its meaning.
|
|
|
|
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-INDEX");
|
|
|
|
Overlap::EqualOrDisjoint
|
2018-07-04 07:45:01 +01:00
|
|
|
}
|
2019-03-01 02:37:35 +01:00
|
|
|
PlaceConflictBias::NoOverlap => {
|
|
|
|
// If we are biased towards no overlapping, then this is disjoint.
|
|
|
|
debug!("place_element_conflict: DISJOINT-ARRAY-INDEX");
|
|
|
|
Overlap::Disjoint
|
2018-07-04 07:45:01 +01:00
|
|
|
}
|
2018-06-27 11:16:24 -04:00
|
|
|
}
|
|
|
|
}
|
2019-03-01 02:37:35 +01:00
|
|
|
(ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: false },
|
|
|
|
ProjectionElem::ConstantIndex { offset: o2, min_length: _, from_end: false })
|
|
|
|
| (ProjectionElem::ConstantIndex { offset: o1, min_length: _, from_end: true },
|
|
|
|
ProjectionElem::ConstantIndex {
|
|
|
|
offset: o2, min_length: _, from_end: true }) => {
|
|
|
|
if o1 == o2 {
|
|
|
|
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX");
|
|
|
|
Overlap::EqualOrDisjoint
|
|
|
|
} else {
|
|
|
|
debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX");
|
|
|
|
Overlap::Disjoint
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(ProjectionElem::ConstantIndex {
|
|
|
|
offset: offset_from_begin, min_length: min_length1, from_end: false },
|
|
|
|
ProjectionElem::ConstantIndex {
|
|
|
|
offset: offset_from_end, min_length: min_length2, from_end: true })
|
|
|
|
| (ProjectionElem::ConstantIndex {
|
|
|
|
offset: offset_from_end, min_length: min_length1, from_end: true },
|
|
|
|
ProjectionElem::ConstantIndex {
|
|
|
|
offset: offset_from_begin, min_length: min_length2, from_end: false }) => {
|
|
|
|
// both patterns matched so it must be at least the greater of the two
|
|
|
|
let min_length = max(min_length1, min_length2);
|
|
|
|
// `offset_from_end` can be in range `[1..min_length]`, 1 indicates the last
|
|
|
|
// element (like -1 in Python) and `min_length` the first.
|
|
|
|
// Therefore, `min_length - offset_from_end` gives the minimal possible
|
|
|
|
// offset from the beginning
|
|
|
|
if *offset_from_begin >= min_length - offset_from_end {
|
|
|
|
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-FE");
|
|
|
|
Overlap::EqualOrDisjoint
|
|
|
|
} else {
|
|
|
|
debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-FE");
|
|
|
|
Overlap::Disjoint
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false },
|
|
|
|
ProjectionElem::Subslice {from, .. })
|
|
|
|
| (ProjectionElem::Subslice {from, .. },
|
|
|
|
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: false }) => {
|
|
|
|
if offset >= from {
|
|
|
|
debug!(
|
|
|
|
"place_element_conflict: DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE");
|
|
|
|
Overlap::EqualOrDisjoint
|
|
|
|
} else {
|
|
|
|
debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE");
|
|
|
|
Overlap::Disjoint
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true },
|
|
|
|
ProjectionElem::Subslice {from: _, to })
|
|
|
|
| (ProjectionElem::Subslice {from: _, to },
|
|
|
|
ProjectionElem::ConstantIndex { offset, min_length: _, from_end: true }) => {
|
|
|
|
if offset > to {
|
|
|
|
debug!("place_element_conflict: \
|
|
|
|
DISJOINT-OR-EQ-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
|
|
|
|
Overlap::EqualOrDisjoint
|
|
|
|
} else {
|
|
|
|
debug!("place_element_conflict: DISJOINT-ARRAY-CONSTANT-INDEX-SUBSLICE-FE");
|
|
|
|
Overlap::Disjoint
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(ProjectionElem::Subslice { .. }, ProjectionElem::Subslice { .. }) => {
|
|
|
|
debug!("place_element_conflict: DISJOINT-OR-EQ-ARRAY-SUBSLICES");
|
|
|
|
Overlap::EqualOrDisjoint
|
|
|
|
}
|
|
|
|
(ProjectionElem::Deref, _)
|
|
|
|
| (ProjectionElem::Field(..), _)
|
|
|
|
| (ProjectionElem::Index(..), _)
|
|
|
|
| (ProjectionElem::ConstantIndex { .. }, _)
|
|
|
|
| (ProjectionElem::Subslice { .. }, _)
|
|
|
|
| (ProjectionElem::Downcast(..), _) => bug!(
|
|
|
|
"mismatched projections in place_element_conflict: {:?} and {:?}",
|
|
|
|
pi1,
|
|
|
|
pi2
|
2018-06-27 11:16:24 -04:00
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|