@@ -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