@@ -605,8 +605,10 @@ enum WriteKind {
605605/// - Take flow state into consideration in `is_assignable()` for local variables
606606#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
607607enum LocalMutationIsAllowed {
608- Move ,
609608 Yes ,
609+ /// We want use of immutable upvars to cause a "write to immutable upvar"
610+ /// error, not an "reassignment" error.
611+ ExceptUpvars ,
610612 No
611613}
612614
@@ -802,7 +804,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
802804 context,
803805 place_span,
804806 ( 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 ,
806813 flow_state,
807814 ) ;
808815
@@ -922,7 +929,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
922929 context,
923930 ( place, span) ,
924931 ( Deep , Write ( WriteKind :: Move ) ) ,
925- LocalMutationIsAllowed :: Move ,
932+ LocalMutationIsAllowed :: Yes ,
926933 flow_state,
927934 ) ;
928935
@@ -1009,34 +1016,19 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
10091016 ( place, span) : ( & Place < ' tcx > , Span ) ,
10101017 flow_state : & Flows < ' cx , ' gcx , ' tcx > ,
10111018 ) {
1012- let move_data = self . move_data ;
1013-
1019+ debug ! ( "check_if_reassignment_to_immutable_state({:?})" , place) ;
10141020 // determine if this path has a non-mut owner (and thus needs checking).
10151021 if let Ok ( ( ) ) = self . is_mutable ( place, LocalMutationIsAllowed :: No ) {
10161022 return ;
10171023 }
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 ;
10401032 }
10411033 }
10421034 }
@@ -1341,7 +1333,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
13411333 match local. mutability {
13421334 Mutability :: Not => match is_local_mutation_allowed {
13431335 LocalMutationIsAllowed :: Yes |
1344- LocalMutationIsAllowed :: Move => Ok ( ( ) ) ,
1336+ LocalMutationIsAllowed :: ExceptUpvars => Ok ( ( ) ) ,
13451337 LocalMutationIsAllowed :: No => Err ( place) ,
13461338 } ,
13471339 Mutability :: Mut => Ok ( ( ) ) ,
@@ -1410,8 +1402,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
14101402 decl, is_local_mutation_allowed, place) ;
14111403 return match ( decl. mutability , is_local_mutation_allowed) {
14121404 ( 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 ) |
14151408 ( Mutability :: Mut , _) => self . is_unique ( & proj. base ) ,
14161409 } ;
14171410 }
@@ -1666,13 +1659,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
16661659 }
16671660 }
16681661 }
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
16741671 {
1675- debug ! ( "borrow_conflicts_with_place ({:?},{:?},{:?})" , borrow , place , access) ;
1672+ debug ! ( "places_conflict ({:?},{:?},{:?})" , borrow_place , access_place , access) ;
16761673
16771674 // Return all the prefixes of `place` in reverse order, including
16781675 // downcasts.
@@ -1694,9 +1691,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
16941691 }
16951692 }
16961693
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 {:?} / {:?}" ,
17001697 borrow_components, access_components) ;
17011698
17021699 let borrow_components = borrow_components. into_iter ( )
@@ -1746,7 +1743,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
17461743 // - If we did run out of accesss, the borrow can access a part of it.
17471744 for ( borrow_c, access_c) in borrow_components. zip ( access_components) {
17481745 // 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) ;
17501747 match ( borrow_c, access_c) {
17511748 ( None , _) => {
17521749 // 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> {
17591756 //
17601757 // FIXME: Differs from AST-borrowck; includes drive-by fix
17611758 // 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" ) ;
17631760 return true ;
17641761 }
17651762 ( Some ( borrow_c) , None ) => {
@@ -1784,15 +1781,15 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
17841781 //
17851782 // e.g. a (mutable) borrow of `a[5]` while we read the
17861783 // array length of `a`.
1787- debug ! ( "borrow_conflicts_with_place : implicit field" ) ;
1784+ debug ! ( "places_conflict : implicit field" ) ;
17881785 return false ;
17891786 }
17901787
17911788 ( ProjectionElem :: Deref , _, Shallow ( None ) ) => {
17921789 // e.g. a borrow of `*x.y` while we shallowly access `x.y` or some
17931790 // prefix thereof - the shallow access can't touch anything behind
17941791 // the pointer.
1795- debug ! ( "borrow_conflicts_with_place : shallow access behind ptr" ) ;
1792+ debug ! ( "places_conflict : shallow access behind ptr" ) ;
17961793 return false ;
17971794 }
17981795 ( ProjectionElem :: Deref , ty:: TyRef ( _, ty:: TypeAndMut {
@@ -1803,7 +1800,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
18031800 // I'm not sure why we are tracking these borrows - shared
18041801 // references can *always* be aliased, which means the
18051802 // 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" ) ;
18071804 return false ;
18081805 }
18091806
@@ -1836,7 +1833,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
18361833 // idea, at least for now, so just give up and
18371834 // report a conflict. This is unsafe code anyway so
18381835 // the user could always use raw pointers.
1839- debug ! ( "borrow_conflicts_with_place : arbitrary -> conflict" ) ;
1836+ debug ! ( "places_conflict : arbitrary -> conflict" ) ;
18401837 return true ;
18411838 }
18421839 Overlap :: EqualOrDisjoint => {
@@ -1845,7 +1842,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
18451842 Overlap :: Disjoint => {
18461843 // We have proven the borrow disjoint - further
18471844 // projections will remain disjoint.
1848- debug ! ( "borrow_conflicts_with_place : disjoint" ) ;
1845+ debug ! ( "places_conflict : disjoint" ) ;
18491846 return false ;
18501847 }
18511848 }
@@ -1874,10 +1871,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
18741871
18751872 // check for loan restricting path P being used. Accounts for
18761873 // 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 ( ) {
18781875 let borrowed = & data[ i] ;
18791876
1880- if self . borrow_conflicts_with_place ( borrowed, place, access) {
1877+ if self . places_conflict ( & borrowed. place , place, access) {
18811878 let ctrl = op ( self , i, borrowed) ;
18821879 if ctrl == Control :: Break { return ; }
18831880 }
0 commit comments