@@ -19,6 +19,7 @@ extern crate tracing;
1919
2020use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
2121use rustc_data_structures:: graph:: dominators:: Dominators ;
22+ use rustc_data_structures:: unord:: UnordMap ;
2223use rustc_errors:: Diag ;
2324use rustc_hir as hir;
2425use rustc_hir:: def_id:: LocalDefId ;
@@ -296,6 +297,7 @@ fn do_mir_borrowck<'tcx>(
296297 regioncx : regioncx. clone ( ) ,
297298 used_mut : Default :: default ( ) ,
298299 used_mut_upvars : SmallVec :: new ( ) ,
300+ local_from_upvars : UnordMap :: default ( ) ,
299301 borrow_set : Rc :: clone ( & borrow_set) ,
300302 upvars : & [ ] ,
301303 local_names : IndexVec :: from_elem ( None , & promoted_body. local_decls ) ,
@@ -322,6 +324,12 @@ fn do_mir_borrowck<'tcx>(
322324 }
323325 }
324326
327+ let mut local_from_upvars = UnordMap :: default ( ) ;
328+ for ( field, & local) in body. local_upvar_map . iter_enumerated ( ) {
329+ let Some ( local) = local else { continue } ;
330+ local_from_upvars. insert ( local, field) ;
331+ }
332+ debug ! ( ?local_from_upvars, "dxf" ) ;
325333 let mut mbcx = MirBorrowckCtxt {
326334 infcx : & infcx,
327335 param_env,
@@ -337,6 +345,7 @@ fn do_mir_borrowck<'tcx>(
337345 regioncx : Rc :: clone ( & regioncx) ,
338346 used_mut : Default :: default ( ) ,
339347 used_mut_upvars : SmallVec :: new ( ) ,
348+ local_from_upvars,
340349 borrow_set : Rc :: clone ( & borrow_set) ,
341350 upvars : tcx. closure_captures ( def) ,
342351 local_names,
@@ -572,6 +581,9 @@ struct MirBorrowckCtxt<'a, 'mir, 'infcx, 'tcx> {
572581 /// If the function we're checking is a closure, then we'll need to report back the list of
573582 /// mutable upvars that have been used. This field keeps track of them.
574583 used_mut_upvars : SmallVec < [ FieldIdx ; 8 ] > ,
584+ /// Since upvars are moved to real locals, we need to map mutations to the locals back to
585+ /// the upvars, so that used_mut_upvars is up-to-date.
586+ local_from_upvars : UnordMap < Local , FieldIdx > ,
575587 /// Region inference context. This contains the results from region inference and lets us e.g.
576588 /// find out which CFG points are contained in each borrow region.
577589 regioncx : Rc < RegionInferenceContext < ' tcx > > ,
@@ -2232,16 +2244,19 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
22322244 }
22332245
22342246 /// Adds the place into the used mutable variables set
2247+ #[ instrument( level = "debug" , skip( self , flow_state) ) ]
22352248 fn add_used_mut ( & mut self , root_place : RootPlace < ' tcx > , flow_state : & Flows < ' _ , ' mir , ' tcx > ) {
22362249 match root_place {
22372250 RootPlace { place_local : local, place_projection : [ ] , is_local_mutation_allowed } => {
22382251 // If the local may have been initialized, and it is now currently being
22392252 // mutated, then it is justified to be annotated with the `mut`
22402253 // keyword, since the mutation may be a possible reassignment.
2241- if is_local_mutation_allowed != LocalMutationIsAllowed :: Yes
2242- && self . is_local_ever_initialized ( local, flow_state) . is_some ( )
2243- {
2244- self . used_mut . insert ( local) ;
2254+ if !matches ! ( is_local_mutation_allowed, LocalMutationIsAllowed :: Yes ) {
2255+ if self . is_local_ever_initialized ( local, flow_state) . is_some ( ) {
2256+ self . used_mut . insert ( local) ;
2257+ } else if let Some ( & field) = self . local_from_upvars . get ( & local) {
2258+ self . used_mut_upvars . push ( field) ;
2259+ }
22452260 }
22462261 }
22472262 RootPlace {
@@ -2259,6 +2274,8 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
22592274 projection : place_projection,
22602275 } ) {
22612276 self . used_mut_upvars . push ( field) ;
2277+ } else if let Some ( & field) = self . local_from_upvars . get ( & place_local) {
2278+ self . used_mut_upvars . push ( field) ;
22622279 }
22632280 }
22642281 }
0 commit comments