Skip to content

Commit f1938cf

Browse files
committed
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
2 parents 2db48d7 + aac64c4 commit f1938cf

File tree

1 file changed

+38
-10
lines changed

1 file changed

+38
-10
lines changed

src/librustc_mir/borrow_check.rs

+38-10
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
385385
// borrow of immutable ref, moves through non-`Box`-ref)
386386
let (sd, rw) = kind;
387387
self.each_borrow_involving_path(
388-
context, (sd, lvalue_span.0), flow_state, |this, _index, borrow| {
388+
context, (sd, lvalue_span.0), flow_state, |this, _index, borrow, common_prefix| {
389389
match (rw, borrow.kind) {
390390
(Read(_), BorrowKind::Shared) => {
391391
Control::Continue
@@ -399,6 +399,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
399399
ReadKind::Borrow(bk) =>
400400
this.report_conflicting_borrow(
401401
context, lvalue_span,
402+
common_prefix,
402403
(lvalue_span.0, bk), (&borrow.lvalue, borrow.kind)),
403404
}
404405
Control::Break
@@ -408,6 +409,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
408409
WriteKind::MutableBorrow(bk) =>
409410
this.report_conflicting_borrow(
410411
context, lvalue_span,
412+
common_prefix,
411413
(lvalue_span.0, bk), (&borrow.lvalue, borrow.kind)),
412414
WriteKind::StorageDead |
413415
WriteKind::Mutate =>
@@ -704,7 +706,7 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
704706
access_lvalue: (ShallowOrDeep, &Lvalue<'gcx>),
705707
flow_state: &InProgress<'b, 'gcx>,
706708
mut op: F)
707-
where F: FnMut(&mut Self, BorrowIndex, &BorrowData<'gcx>) -> Control
709+
where F: FnMut(&mut Self, BorrowIndex, &BorrowData<'gcx>, &Lvalue) -> Control
708710
{
709711
let (access, lvalue) = access_lvalue;
710712

@@ -726,9 +728,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
726728
// to #38899. Will probably need back-compat mode flag.
727729
for accessed_prefix in self.prefixes(lvalue, PrefixSet::All) {
728730
if *accessed_prefix == borrowed.lvalue {
729-
// FIXME: pass in prefix here too? And/or enum
730-
// describing case we are in?
731-
let ctrl = op(self, i, borrowed);
731+
// FIXME: pass in enum describing case we are in?
732+
let ctrl = op(self, i, borrowed, accessed_prefix);
732733
if ctrl == Control::Break { return; }
733734
}
734735
}
@@ -753,9 +754,8 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
753754

754755
for borrowed_prefix in self.prefixes(&borrowed.lvalue, prefix_kind) {
755756
if borrowed_prefix == lvalue {
756-
// FIXME: pass in prefix here too? And/or enum
757-
// describing case we are in?
758-
let ctrl = op(self, i, borrowed);
757+
// FIXME: pass in enum describing case we are in?
758+
let ctrl = op(self, i, borrowed, borrowed_prefix);
759759
if ctrl == Control::Break { return; }
760760
}
761761
}
@@ -780,6 +780,30 @@ mod prefixes {
780780
use rustc::ty::{self, TyCtxt};
781781
use rustc::mir::{Lvalue, Mir, ProjectionElem};
782782

783+
pub trait IsPrefixOf<'tcx> {
784+
fn is_prefix_of(&self, other: &Lvalue<'tcx>) -> bool;
785+
}
786+
787+
impl<'tcx> IsPrefixOf<'tcx> for Lvalue<'tcx> {
788+
fn is_prefix_of(&self, other: &Lvalue<'tcx>) -> bool {
789+
let mut cursor = other;
790+
loop {
791+
if self == cursor {
792+
return true;
793+
}
794+
795+
match *cursor {
796+
Lvalue::Local(_) |
797+
Lvalue::Static(_) => return false,
798+
Lvalue::Projection(ref proj) => {
799+
cursor = &proj.base;
800+
}
801+
}
802+
}
803+
}
804+
}
805+
806+
783807
pub(super) struct Prefixes<'c, 'tcx: 'c> {
784808
mir: &'c Mir<'tcx>,
785809
tcx: TyCtxt<'c, 'tcx, 'tcx>,
@@ -943,12 +967,16 @@ impl<'c, 'b, 'a: 'b+'c, 'gcx, 'tcx: 'a> MirBorrowckCtxt<'c, 'b, 'a, 'gcx, 'tcx>
943967
fn report_conflicting_borrow(&mut self,
944968
_context: Context,
945969
(lvalue, span): (&Lvalue, Span),
970+
common_prefix: &Lvalue,
946971
loan1: (&Lvalue, BorrowKind),
947972
loan2: (&Lvalue, BorrowKind)) {
973+
use self::prefixes::IsPrefixOf;
974+
948975
let (loan1_lvalue, loan1_kind) = loan1;
949976
let (loan2_lvalue, loan2_kind) = loan2;
950-
// FIXME: obviously falsifiable. Generalize for non-eq lvalues later.
951-
assert_eq!(loan1_lvalue, loan2_lvalue);
977+
978+
assert!(common_prefix.is_prefix_of(loan1_lvalue));
979+
assert!(common_prefix.is_prefix_of(loan2_lvalue));
952980

953981
// FIXME: supply non-"" `opt_via` when appropriate
954982
let mut err = match (loan1_kind, "immutable", "mutable",

0 commit comments

Comments
 (0)