@@ -605,8 +605,10 @@ enum WriteKind {
605
605
/// - Take flow state into consideration in `is_assignable()` for local variables
606
606
#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
607
607
enum LocalMutationIsAllowed {
608
- Move ,
609
608
Yes ,
609
+ /// We want use of immutable upvars to cause a "write to immutable upvar"
610
+ /// error, not an "reassignment" error.
611
+ ExceptUpvars ,
610
612
No
611
613
}
612
614
@@ -802,7 +804,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
802
804
context,
803
805
place_span,
804
806
( kind, Write ( WriteKind :: Mutate ) ) ,
805
- LocalMutationIsAllowed :: Yes ,
807
+ // We want immutable upvars to cause an "assignment to immutable var"
808
+ // error, not an "reassignment of immutable var" error, because the
809
+ // latter can't find a good previous assignment span.
810
+ //
811
+ // There's probably a better way to do this.
812
+ LocalMutationIsAllowed :: ExceptUpvars ,
806
813
flow_state,
807
814
) ;
808
815
@@ -922,7 +929,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
922
929
context,
923
930
( place, span) ,
924
931
( Deep , Write ( WriteKind :: Move ) ) ,
925
- LocalMutationIsAllowed :: Move ,
932
+ LocalMutationIsAllowed :: Yes ,
926
933
flow_state,
927
934
) ;
928
935
@@ -1009,34 +1016,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1009
1016
( place, span) : ( & Place < ' tcx > , Span ) ,
1010
1017
flow_state : & Flows < ' cx , ' gcx , ' tcx > ,
1011
1018
) {
1012
- let move_data = self . move_data ;
1013
-
1019
+ debug ! ( "check_if_reassignment_to_immutable_state({:?})" , place) ;
1014
1020
// determine if this path has a non-mut owner (and thus needs checking).
1015
1021
if let Ok ( ( ) ) = self . is_mutable ( place, LocalMutationIsAllowed :: No ) {
1016
1022
return ;
1017
1023
}
1018
-
1019
- match self . move_path_closest_to ( place) {
1020
- Ok ( mpi) => for ii in & move_data. init_path_map [ mpi] {
1021
- if flow_state. ever_inits . contains ( ii) {
1022
- let first_assign_span = self . move_data . inits [ * ii] . span ;
1023
- self . report_illegal_reassignment ( context, ( place, span) , first_assign_span) ;
1024
- break ;
1025
- }
1026
- } ,
1027
- Err ( NoMovePathFound :: ReachedStatic ) => {
1028
- let item_msg = match self . describe_place ( place) {
1029
- Some ( name) => format ! ( "immutable static item `{}`" , name) ,
1030
- None => "immutable static item" . to_owned ( ) ,
1031
- } ;
1032
- self . tcx . sess . delay_span_bug (
1033
- span,
1034
- & format ! (
1035
- "cannot assign to {}, should have been caught by \
1036
- `check_access_permissions()`",
1037
- item_msg
1038
- ) ,
1039
- ) ;
1024
+ debug ! ( "check_if_reassignment_to_immutable_state({:?}) - is an imm local" , place) ;
1025
+
1026
+ for i in flow_state. ever_inits . elems_incoming ( ) {
1027
+ let init = self . move_data . inits [ i] ;
1028
+ let init_place = & self . move_data . move_paths [ init. path ] . place ;
1029
+ if self . places_conflict ( & init_place, place, Deep ) {
1030
+ self . report_illegal_reassignment ( context, ( place, span) , init. span ) ;
1031
+ break ;
1040
1032
}
1041
1033
}
1042
1034
}
@@ -1341,7 +1333,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1341
1333
match local. mutability {
1342
1334
Mutability :: Not => match is_local_mutation_allowed {
1343
1335
LocalMutationIsAllowed :: Yes |
1344
- LocalMutationIsAllowed :: Move => Ok ( ( ) ) ,
1336
+ LocalMutationIsAllowed :: ExceptUpvars => Ok ( ( ) ) ,
1345
1337
LocalMutationIsAllowed :: No => Err ( place) ,
1346
1338
} ,
1347
1339
Mutability :: Mut => Ok ( ( ) ) ,
@@ -1410,8 +1402,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1410
1402
decl, is_local_mutation_allowed, place) ;
1411
1403
return match ( decl. mutability , is_local_mutation_allowed) {
1412
1404
( Mutability :: Not , LocalMutationIsAllowed :: No ) |
1413
- ( Mutability :: Not , LocalMutationIsAllowed :: Yes ) => Err ( place) ,
1414
- ( Mutability :: Not , LocalMutationIsAllowed :: Move ) |
1405
+ ( Mutability :: Not , LocalMutationIsAllowed :: ExceptUpvars )
1406
+ => Err ( place) ,
1407
+ ( Mutability :: Not , LocalMutationIsAllowed :: Yes ) |
1415
1408
( Mutability :: Mut , _) => self . is_unique ( & proj. base ) ,
1416
1409
} ;
1417
1410
}
@@ -1666,13 +1659,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1666
1659
}
1667
1660
}
1668
1661
}
1669
- fn borrow_conflicts_with_place ( & mut self ,
1670
- borrow : & BorrowData < ' tcx > ,
1671
- place : & Place < ' tcx > ,
1672
- access : ShallowOrDeep )
1673
- -> bool
1662
+
1663
+ /// Returns whether an access of kind `access` to `access_place` conflicts with
1664
+ /// a borrow/full access to `borrow_place` (for deep accesses to mutable
1665
+ /// locations, this function is symmetric between `borrow_place` & `access_place`).
1666
+ fn places_conflict ( & mut self ,
1667
+ borrow_place : & Place < ' tcx > ,
1668
+ access_place : & Place < ' tcx > ,
1669
+ access : ShallowOrDeep )
1670
+ -> bool
1674
1671
{
1675
- debug ! ( "borrow_conflicts_with_place ({:?},{:?},{:?})" , borrow , place , access) ;
1672
+ debug ! ( "places_conflict ({:?},{:?},{:?})" , borrow_place , access_place , access) ;
1676
1673
1677
1674
// Return all the prefixes of `place` in reverse order, including
1678
1675
// downcasts.
@@ -1694,9 +1691,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1694
1691
}
1695
1692
}
1696
1693
1697
- let borrow_components = place_elements ( & borrow . place ) ;
1698
- let access_components = place_elements ( place ) ;
1699
- debug ! ( "borrow_conflicts_with_place : components {:?} / {:?}" ,
1694
+ let borrow_components = place_elements ( borrow_place ) ;
1695
+ let access_components = place_elements ( access_place ) ;
1696
+ debug ! ( "places_conflict : components {:?} / {:?}" ,
1700
1697
borrow_components, access_components) ;
1701
1698
1702
1699
let borrow_components = borrow_components. into_iter ( )
@@ -1746,7 +1743,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1746
1743
// - If we did run out of accesss, the borrow can access a part of it.
1747
1744
for ( borrow_c, access_c) in borrow_components. zip ( access_components) {
1748
1745
// loop invariant: borrow_c is always either equal to access_c or disjoint from it.
1749
- debug ! ( "borrow_conflicts_with_place : {:?} vs. {:?}" , borrow_c, access_c) ;
1746
+ debug ! ( "places_conflict : {:?} vs. {:?}" , borrow_c, access_c) ;
1750
1747
match ( borrow_c, access_c) {
1751
1748
( None , _) => {
1752
1749
// If we didn't run out of access, the borrow can access all of our
@@ -1759,7 +1756,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1759
1756
//
1760
1757
// FIXME: Differs from AST-borrowck; includes drive-by fix
1761
1758
// to #38899. Will probably need back-compat mode flag.
1762
- debug ! ( "borrow_conflict_with_place : full borrow, CONFLICT" ) ;
1759
+ debug ! ( "places_conflict : full borrow, CONFLICT" ) ;
1763
1760
return true ;
1764
1761
}
1765
1762
( Some ( borrow_c) , None ) => {
@@ -1784,15 +1781,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1784
1781
//
1785
1782
// e.g. a (mutable) borrow of `a[5]` while we read the
1786
1783
// array length of `a`.
1787
- debug ! ( "borrow_conflicts_with_place : implicit field" ) ;
1784
+ debug ! ( "places_conflict : implicit field" ) ;
1788
1785
return false ;
1789
1786
}
1790
1787
1791
1788
( ProjectionElem :: Deref , _, Shallow ( None ) ) => {
1792
1789
// e.g. a borrow of `*x.y` while we shallowly access `x.y` or some
1793
1790
// prefix thereof - the shallow access can't touch anything behind
1794
1791
// the pointer.
1795
- debug ! ( "borrow_conflicts_with_place : shallow access behind ptr" ) ;
1792
+ debug ! ( "places_conflict : shallow access behind ptr" ) ;
1796
1793
return false ;
1797
1794
}
1798
1795
( ProjectionElem :: Deref , ty:: TyRef ( _, ty:: TypeAndMut {
@@ -1803,7 +1800,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1803
1800
// I'm not sure why we are tracking these borrows - shared
1804
1801
// references can *always* be aliased, which means the
1805
1802
// permission check already account for this borrow.
1806
- debug ! ( "borrow_conflicts_with_place : behind a shared ref" ) ;
1803
+ debug ! ( "places_conflict : behind a shared ref" ) ;
1807
1804
return false ;
1808
1805
}
1809
1806
@@ -1836,7 +1833,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1836
1833
// idea, at least for now, so just give up and
1837
1834
// report a conflict. This is unsafe code anyway so
1838
1835
// the user could always use raw pointers.
1839
- debug ! ( "borrow_conflicts_with_place : arbitrary -> conflict" ) ;
1836
+ debug ! ( "places_conflict : arbitrary -> conflict" ) ;
1840
1837
return true ;
1841
1838
}
1842
1839
Overlap :: EqualOrDisjoint => {
@@ -1845,7 +1842,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1845
1842
Overlap :: Disjoint => {
1846
1843
// We have proven the borrow disjoint - further
1847
1844
// projections will remain disjoint.
1848
- debug ! ( "borrow_conflicts_with_place : disjoint" ) ;
1845
+ debug ! ( "places_conflict : disjoint" ) ;
1849
1846
return false ;
1850
1847
}
1851
1848
}
@@ -1874,10 +1871,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1874
1871
1875
1872
// check for loan restricting path P being used. Accounts for
1876
1873
// borrows of P, P.a.b, etc.
1877
- ' next_borrow : for i in flow_state. borrows . elems_incoming ( ) {
1874
+ for i in flow_state. borrows . elems_incoming ( ) {
1878
1875
let borrowed = & data[ i] ;
1879
1876
1880
- if self . borrow_conflicts_with_place ( borrowed, place, access) {
1877
+ if self . places_conflict ( & borrowed. place , place, access) {
1881
1878
let ctrl = op ( self , i, borrowed) ;
1882
1879
if ctrl == Control :: Break { return ; }
1883
1880
}
0 commit comments