@@ -259,6 +259,31 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
259259
260260 mbcx. analyze_results ( & mut state) ; // entry point for DataflowResultsConsumer
261261
262+ // For each non-user used mutable variable, check if it's been assigned from
263+ // a user-declared local. If so, then put that local into the used_mut set.
264+ // Note that this set is expected to be small - only upvars from closures
265+ // would have a chance of erroneously adding non-user-defined mutable vars
266+ // to the set.
267+ let temporary_used_locals: FxHashSet < Local > =
268+ mbcx. used_mut . iter ( )
269+ . filter ( |& local| !mbcx. mir . local_decls [ * local] . is_user_variable )
270+ . cloned ( )
271+ . collect ( ) ;
272+
273+ for local in temporary_used_locals {
274+ for location in mbcx. mir . find_assignments ( local) {
275+ for moi in & mbcx. move_data . loc_map [ location] {
276+ let mpi = & mbcx. move_data . moves [ * moi] . path ;
277+ let path = & mbcx. move_data . move_paths [ * mpi] ;
278+ debug ! ( "assignment of {:?} to {:?}, adding {:?} to used mutable set" ,
279+ path. place, local, path. place) ;
280+ if let Place :: Local ( user_local) = path. place {
281+ mbcx. used_mut . insert ( user_local) ;
282+ }
283+ }
284+ }
285+ }
286+
262287 debug ! ( "mbcx.used_mut: {:?}" , mbcx. used_mut) ;
263288
264289 for local in mbcx. mir . mut_vars_and_args_iter ( ) . filter ( |local| !mbcx. used_mut . contains ( local) ) {
@@ -731,6 +756,11 @@ enum InitializationRequiringAction {
731756 Assignment ,
732757}
733758
759+ struct RootPlace < ' d , ' tcx : ' d > {
760+ place : & ' d Place < ' tcx > ,
761+ is_local_mutation_allowed : LocalMutationIsAllowed ,
762+ }
763+
734764impl InitializationRequiringAction {
735765 fn as_noun ( self ) -> & ' static str {
736766 match self {
@@ -1687,23 +1717,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
16871717 Reservation ( WriteKind :: MutableBorrow ( BorrowKind :: Mut { .. } ) )
16881718 | Write ( WriteKind :: MutableBorrow ( BorrowKind :: Mut { .. } ) ) => {
16891719 match self . is_mutable ( place, is_local_mutation_allowed) {
1690- Ok ( ( Place :: Local ( local) , mut_allowed) ) => {
1691- if mut_allowed != LocalMutationIsAllowed :: Yes {
1692- // If the local may be initialized, and it is now currently being
1693- // mutated, then it is justified to be annotated with the `mut`
1694- // keyword, since the mutation may be a possible reassignment.
1695- let mpi = self . move_data . rev_lookup . find_local ( * local) ;
1696- if flow_state. inits . contains ( & mpi) {
1697- self . used_mut . insert ( * local) ;
1698- }
1699- }
1700- }
1701- Ok ( ( Place :: Projection ( _) , _mut_allowed) ) => {
1702- if let Some ( field) = self . is_upvar_field_projection ( & place) {
1703- self . used_mut_upvars . push ( field) ;
1704- }
1705- }
1706- Ok ( ( Place :: Static ( ..) , _mut_allowed) ) => { }
1720+ Ok ( root_place) => self . add_used_mut ( root_place, flow_state) ,
17071721 Err ( place_err) => {
17081722 error_reported = true ;
17091723 let item_msg = self . get_default_err_msg ( place) ;
@@ -1724,55 +1738,35 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
17241738 }
17251739 Reservation ( WriteKind :: Mutate ) | Write ( WriteKind :: Mutate ) => {
17261740 match self . is_mutable ( place, is_local_mutation_allowed) {
1727- Ok ( ( Place :: Local ( local) , mut_allowed) ) => {
1728- if mut_allowed != LocalMutationIsAllowed :: Yes {
1729- // If the local may be initialized, and it is now currently being
1730- // mutated, then it is justified to be annotated with the `mut`
1731- // keyword, since the mutation may be a possible reassignment.
1732- let mpi = self . move_data . rev_lookup . find_local ( * local) ;
1733- if flow_state. inits . contains ( & mpi) {
1734- self . used_mut . insert ( * local) ;
1735- }
1736- }
1737- }
1738- Ok ( ( Place :: Projection ( _) , _mut_allowed) ) => {
1739- if let Some ( field) = self . is_upvar_field_projection ( & place) {
1740- self . used_mut_upvars . push ( field) ;
1741- }
1742- }
1743- Ok ( ( Place :: Static ( ..) , _mut_allowed) ) => { }
1741+ Ok ( root_place) => self . add_used_mut ( root_place, flow_state) ,
17441742 Err ( place_err) => {
17451743 error_reported = true ;
17461744
17471745 let err_info = if let Place :: Projection (
17481746 box Projection {
1749- ref base,
1747+ base : Place :: Local ( local ) ,
17501748 elem : ProjectionElem :: Deref
17511749 }
17521750 ) = * place_err {
1753- if let Place :: Local ( local) = * base {
1754- let locations = self . mir . find_assignments ( local) ;
1755- if locations. len ( ) > 0 {
1756- let item_msg = if error_reported {
1757- self . get_secondary_err_msg ( base)
1758- } else {
1759- self . get_default_err_msg ( place)
1760- } ;
1761- let sp = self . mir . source_info ( locations[ 0 ] ) . span ;
1762- let mut to_suggest_span = String :: new ( ) ;
1763- if let Ok ( src) =
1764- self . tcx . sess . codemap ( ) . span_to_snippet ( sp) {
1765- to_suggest_span = src[ 1 ..] . to_string ( ) ;
1766- } ;
1767- Some ( ( sp,
1768- "consider changing this to be a \
1769- mutable reference",
1770- to_suggest_span,
1771- item_msg,
1772- self . get_primary_err_msg ( base) ) )
1751+ let locations = self . mir . find_assignments ( local) ;
1752+ if locations. len ( ) > 0 {
1753+ let item_msg = if error_reported {
1754+ self . get_secondary_err_msg ( & Place :: Local ( local) )
17731755 } else {
1774- None
1775- }
1756+ self . get_default_err_msg ( place)
1757+ } ;
1758+ let sp = self . mir . source_info ( locations[ 0 ] ) . span ;
1759+ let mut to_suggest_span = String :: new ( ) ;
1760+ if let Ok ( src) =
1761+ self . tcx . sess . codemap ( ) . span_to_snippet ( sp) {
1762+ to_suggest_span = src[ 1 ..] . to_string ( ) ;
1763+ } ;
1764+ Some ( ( sp,
1765+ "consider changing this to be a \
1766+ mutable reference",
1767+ to_suggest_span,
1768+ item_msg,
1769+ self . get_primary_err_msg ( & Place :: Local ( local) ) ) )
17761770 } else {
17771771 None
17781772 }
@@ -1834,33 +1828,76 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
18341828 error_reported
18351829 }
18361830
1837- /// Can this value be written or borrowed mutably
1831+ /// Adds the place into the used mutable variables set
1832+ fn add_used_mut < ' d > (
1833+ & mut self ,
1834+ root_place : RootPlace < ' d , ' tcx > ,
1835+ flow_state : & Flows < ' cx , ' gcx , ' tcx >
1836+ ) {
1837+ match root_place {
1838+ RootPlace {
1839+ place : Place :: Local ( local) ,
1840+ is_local_mutation_allowed,
1841+ } => {
1842+ if is_local_mutation_allowed != LocalMutationIsAllowed :: Yes {
1843+ // If the local may be initialized, and it is now currently being
1844+ // mutated, then it is justified to be annotated with the `mut`
1845+ // keyword, since the mutation may be a possible reassignment.
1846+ let mpi = self . move_data . rev_lookup . find_local ( * local) ;
1847+ if flow_state. inits . contains ( & mpi) {
1848+ self . used_mut . insert ( * local) ;
1849+ }
1850+ }
1851+ }
1852+ RootPlace {
1853+ place : place @ Place :: Projection ( _) ,
1854+ is_local_mutation_allowed : _,
1855+ } => {
1856+ if let Some ( field) = self . is_upvar_field_projection ( & place) {
1857+ self . used_mut_upvars . push ( field) ;
1858+ }
1859+ }
1860+ RootPlace {
1861+ place : Place :: Static ( ..) ,
1862+ is_local_mutation_allowed : _,
1863+ } => { }
1864+ }
1865+ }
1866+
1867+ /// Whether this value be written or borrowed mutably.
1868+ /// Returns the root place if the place passed in is a projection.
18381869 fn is_mutable < ' d > (
18391870 & self ,
18401871 place : & ' d Place < ' tcx > ,
18411872 is_local_mutation_allowed : LocalMutationIsAllowed ,
1842- ) -> Result < ( & ' d Place < ' tcx > , LocalMutationIsAllowed ) , & ' d Place < ' tcx > > {
1873+ ) -> Result < RootPlace < ' d , ' tcx > , & ' d Place < ' tcx > > {
18431874 match * place {
18441875 Place :: Local ( local) => {
18451876 let local = & self . mir . local_decls [ local] ;
18461877 match local. mutability {
18471878 Mutability :: Not => match is_local_mutation_allowed {
18481879 LocalMutationIsAllowed :: Yes => {
1849- Ok ( ( place, LocalMutationIsAllowed :: Yes ) )
1880+ Ok ( RootPlace {
1881+ place,
1882+ is_local_mutation_allowed : LocalMutationIsAllowed :: Yes
1883+ } )
18501884 }
18511885 LocalMutationIsAllowed :: ExceptUpvars => {
1852- Ok ( ( place, LocalMutationIsAllowed :: ExceptUpvars ) )
1886+ Ok ( RootPlace {
1887+ place,
1888+ is_local_mutation_allowed : LocalMutationIsAllowed :: ExceptUpvars
1889+ } )
18531890 }
18541891 LocalMutationIsAllowed :: No => Err ( place) ,
18551892 } ,
1856- Mutability :: Mut => Ok ( ( place, is_local_mutation_allowed) ) ,
1893+ Mutability :: Mut => Ok ( RootPlace { place, is_local_mutation_allowed } ) ,
18571894 }
18581895 }
18591896 Place :: Static ( ref static_) =>
18601897 if self . tcx . is_static ( static_. def_id ) != Some ( hir:: Mutability :: MutMutable ) {
18611898 Err ( place)
18621899 } else {
1863- Ok ( ( place, is_local_mutation_allowed) )
1900+ Ok ( RootPlace { place, is_local_mutation_allowed } )
18641901 } ,
18651902 Place :: Projection ( ref proj) => {
18661903 match proj. elem {
@@ -1899,7 +1936,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
18991936 // `*mut` raw pointers are always mutable, regardless of
19001937 // context. The users have to check by themselves.
19011938 hir:: MutMutable => {
1902- return Ok ( ( place, is_local_mutation_allowed) ) ;
1939+ return Ok ( RootPlace { place, is_local_mutation_allowed } ) ;
19031940 }
19041941 }
19051942 }
@@ -1958,7 +1995,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
19581995 // }
19591996 // ```
19601997 let _ = self . is_mutable ( & proj. base , is_local_mutation_allowed) ?;
1961- Ok ( ( place, is_local_mutation_allowed) )
1998+ Ok ( RootPlace { place, is_local_mutation_allowed } )
19621999 }
19632000 }
19642001 } else {
0 commit comments