mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-23 05:55:25 +00:00
Auto merge of #44999 - pnkfelix:mir-borrowck-fix-assert-left-right, r=nikomatsakis
Overlapping borrows can point to different lvalues. Overlapping borrows can point to different lvalues. There's always a basis for the overlap, so instead of removing the assert entirely, I instead pass in the prefix that we found and check that it actually is a prefix of both lvalues. Fix #44829
This commit is contained in:
commit
f1938cf13b
@ -385,7 +385,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
|
|||||||
// borrow of immutable ref, moves through non-`Box`-ref)
|
// borrow of immutable ref, moves through non-`Box`-ref)
|
||||||
let (sd, rw) = kind;
|
let (sd, rw) = kind;
|
||||||
self.each_borrow_involving_path(
|
self.each_borrow_involving_path(
|
||||||
context, (sd, lvalue_span.0), flow_state, |this, _index, borrow| {
|
context, (sd, lvalue_span.0), flow_state, |this, _index, borrow, common_prefix| {
|
||||||
match (rw, borrow.kind) {
|
match (rw, borrow.kind) {
|
||||||
(Read(_), BorrowKind::Shared) => {
|
(Read(_), BorrowKind::Shared) => {
|
||||||
Control::Continue
|
Control::Continue
|
||||||
@ -399,6 +399,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
|
|||||||
ReadKind::Borrow(bk) =>
|
ReadKind::Borrow(bk) =>
|
||||||
this.report_conflicting_borrow(
|
this.report_conflicting_borrow(
|
||||||
context, lvalue_span,
|
context, lvalue_span,
|
||||||
|
common_prefix,
|
||||||
(lvalue_span.0, bk), (&borrow.lvalue, borrow.kind)),
|
(lvalue_span.0, bk), (&borrow.lvalue, borrow.kind)),
|
||||||
}
|
}
|
||||||
Control::Break
|
Control::Break
|
||||||
@ -408,6 +409,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
|
|||||||
WriteKind::MutableBorrow(bk) =>
|
WriteKind::MutableBorrow(bk) =>
|
||||||
this.report_conflicting_borrow(
|
this.report_conflicting_borrow(
|
||||||
context, lvalue_span,
|
context, lvalue_span,
|
||||||
|
common_prefix,
|
||||||
(lvalue_span.0, bk), (&borrow.lvalue, borrow.kind)),
|
(lvalue_span.0, bk), (&borrow.lvalue, borrow.kind)),
|
||||||
WriteKind::StorageDead |
|
WriteKind::StorageDead |
|
||||||
WriteKind::Mutate =>
|
WriteKind::Mutate =>
|
||||||
@ -704,7 +706,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
|
|||||||
access_lvalue: (ShallowOrDeep, &Lvalue<'gcx>),
|
access_lvalue: (ShallowOrDeep, &Lvalue<'gcx>),
|
||||||
flow_state: &InProgress<'b, 'gcx>,
|
flow_state: &InProgress<'b, 'gcx>,
|
||||||
mut op: F)
|
mut op: F)
|
||||||
where F: FnMut(&mut Self, BorrowIndex, &BorrowData<'gcx>) -> Control
|
where F: FnMut(&mut Self, BorrowIndex, &BorrowData<'gcx>, &Lvalue) -> Control
|
||||||
{
|
{
|
||||||
let (access, lvalue) = access_lvalue;
|
let (access, lvalue) = access_lvalue;
|
||||||
|
|
||||||
@ -726,9 +728,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
|
|||||||
// to #38899. Will probably need back-compat mode flag.
|
// to #38899. Will probably need back-compat mode flag.
|
||||||
for accessed_prefix in self.prefixes(lvalue, PrefixSet::All) {
|
for accessed_prefix in self.prefixes(lvalue, PrefixSet::All) {
|
||||||
if *accessed_prefix == borrowed.lvalue {
|
if *accessed_prefix == borrowed.lvalue {
|
||||||
// FIXME: pass in prefix here too? And/or enum
|
// FIXME: pass in enum describing case we are in?
|
||||||
// describing case we are in?
|
let ctrl = op(self, i, borrowed, accessed_prefix);
|
||||||
let ctrl = op(self, i, borrowed);
|
|
||||||
if ctrl == Control::Break { return; }
|
if ctrl == Control::Break { return; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -753,9 +754,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
|
|||||||
|
|
||||||
for borrowed_prefix in self.prefixes(&borrowed.lvalue, prefix_kind) {
|
for borrowed_prefix in self.prefixes(&borrowed.lvalue, prefix_kind) {
|
||||||
if borrowed_prefix == lvalue {
|
if borrowed_prefix == lvalue {
|
||||||
// FIXME: pass in prefix here too? And/or enum
|
// FIXME: pass in enum describing case we are in?
|
||||||
// describing case we are in?
|
let ctrl = op(self, i, borrowed, borrowed_prefix);
|
||||||
let ctrl = op(self, i, borrowed);
|
|
||||||
if ctrl == Control::Break { return; }
|
if ctrl == Control::Break { return; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -780,6 +780,30 @@ mod prefixes {
|
|||||||
use rustc::ty::{self, TyCtxt};
|
use rustc::ty::{self, TyCtxt};
|
||||||
use rustc::mir::{Lvalue, Mir, ProjectionElem};
|
use rustc::mir::{Lvalue, Mir, ProjectionElem};
|
||||||
|
|
||||||
|
pub trait IsPrefixOf<'tcx> {
|
||||||
|
fn is_prefix_of(&self, other: &Lvalue<'tcx>) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> IsPrefixOf<'tcx> for Lvalue<'tcx> {
|
||||||
|
fn is_prefix_of(&self, other: &Lvalue<'tcx>) -> bool {
|
||||||
|
let mut cursor = other;
|
||||||
|
loop {
|
||||||
|
if self == cursor {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
match *cursor {
|
||||||
|
Lvalue::Local(_) |
|
||||||
|
Lvalue::Static(_) => return false,
|
||||||
|
Lvalue::Projection(ref proj) => {
|
||||||
|
cursor = &proj.base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub(super) struct Prefixes<'c, 'tcx: 'c> {
|
pub(super) struct Prefixes<'c, 'tcx: 'c> {
|
||||||
mir: &'c Mir<'tcx>,
|
mir: &'c Mir<'tcx>,
|
||||||
tcx: TyCtxt<'c, 'tcx, 'tcx>,
|
tcx: TyCtxt<'c, 'tcx, 'tcx>,
|
||||||
@ -943,12 +967,16 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
|
|||||||
fn report_conflicting_borrow(&mut self,
|
fn report_conflicting_borrow(&mut self,
|
||||||
_context: Context,
|
_context: Context,
|
||||||
(lvalue, span): (&Lvalue, Span),
|
(lvalue, span): (&Lvalue, Span),
|
||||||
|
common_prefix: &Lvalue,
|
||||||
loan1: (&Lvalue, BorrowKind),
|
loan1: (&Lvalue, BorrowKind),
|
||||||
loan2: (&Lvalue, BorrowKind)) {
|
loan2: (&Lvalue, BorrowKind)) {
|
||||||
|
use self::prefixes::IsPrefixOf;
|
||||||
|
|
||||||
let (loan1_lvalue, loan1_kind) = loan1;
|
let (loan1_lvalue, loan1_kind) = loan1;
|
||||||
let (loan2_lvalue, loan2_kind) = loan2;
|
let (loan2_lvalue, loan2_kind) = loan2;
|
||||||
// FIXME: obviously falsifiable. Generalize for non-eq lvalues later.
|
|
||||||
assert_eq!(loan1_lvalue, loan2_lvalue);
|
assert!(common_prefix.is_prefix_of(loan1_lvalue));
|
||||||
|
assert!(common_prefix.is_prefix_of(loan2_lvalue));
|
||||||
|
|
||||||
// FIXME: supply non-"" `opt_via` when appropriate
|
// FIXME: supply non-"" `opt_via` when appropriate
|
||||||
let mut err = match (loan1_kind, "immutable", "mutable",
|
let mut err = match (loan1_kind, "immutable", "mutable",
|
||||||
|
Loading…
Reference in New Issue
Block a user