@@ -26,6 +26,7 @@ use std::rc::Rc;
26
26
use consumers:: { BodyWithBorrowckFacts , ConsumerOptions } ;
27
27
use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
28
28
use rustc_data_structures:: graph:: dominators:: Dominators ;
29
+ use rustc_data_structures:: unord:: UnordMap ;
29
30
use rustc_errors:: Diag ;
30
31
use rustc_hir as hir;
31
32
use rustc_hir:: def_id:: LocalDefId ;
@@ -292,6 +293,7 @@ fn do_mir_borrowck<'tcx>(
292
293
regioncx : regioncx. clone ( ) ,
293
294
used_mut : Default :: default ( ) ,
294
295
used_mut_upvars : SmallVec :: new ( ) ,
296
+ local_from_upvars : UnordMap :: default ( ) ,
295
297
borrow_set : Rc :: clone ( & borrow_set) ,
296
298
upvars : & [ ] ,
297
299
local_names : IndexVec :: from_elem ( None , & promoted_body. local_decls ) ,
@@ -318,6 +320,12 @@ fn do_mir_borrowck<'tcx>(
318
320
}
319
321
}
320
322
323
+ let mut local_from_upvars = UnordMap :: default ( ) ;
324
+ for ( field, & local) in body. local_upvar_map . iter_enumerated ( ) {
325
+ let Some ( local) = local else { continue } ;
326
+ local_from_upvars. insert ( local, field) ;
327
+ }
328
+ debug ! ( ?local_from_upvars, "dxf" ) ;
321
329
let mut mbcx = MirBorrowckCtxt {
322
330
infcx : & infcx,
323
331
param_env,
@@ -333,6 +341,7 @@ fn do_mir_borrowck<'tcx>(
333
341
regioncx : Rc :: clone ( & regioncx) ,
334
342
used_mut : Default :: default ( ) ,
335
343
used_mut_upvars : SmallVec :: new ( ) ,
344
+ local_from_upvars,
336
345
borrow_set : Rc :: clone ( & borrow_set) ,
337
346
upvars : tcx. closure_captures ( def) ,
338
347
local_names,
@@ -568,6 +577,9 @@ struct MirBorrowckCtxt<'a, 'mir, 'infcx, 'tcx> {
568
577
/// If the function we're checking is a closure, then we'll need to report back the list of
569
578
/// mutable upvars that have been used. This field keeps track of them.
570
579
used_mut_upvars : SmallVec < [ FieldIdx ; 8 ] > ,
580
+ /// Since upvars are moved to real locals, we need to map mutations to the locals back to
581
+ /// the upvars, so that used_mut_upvars is up-to-date.
582
+ local_from_upvars : UnordMap < Local , FieldIdx > ,
571
583
/// Region inference context. This contains the results from region inference and lets us e.g.
572
584
/// find out which CFG points are contained in each borrow region.
573
585
regioncx : Rc < RegionInferenceContext < ' tcx > > ,
@@ -2230,16 +2242,19 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
2230
2242
}
2231
2243
2232
2244
/// Adds the place into the used mutable variables set
2245
+ #[ instrument( level = "debug" , skip( self , flow_state) ) ]
2233
2246
fn add_used_mut ( & mut self , root_place : RootPlace < ' tcx > , flow_state : & Flows < ' _ , ' mir , ' tcx > ) {
2234
2247
match root_place {
2235
2248
RootPlace { place_local : local, place_projection : [ ] , is_local_mutation_allowed } => {
2236
2249
// If the local may have been initialized, and it is now currently being
2237
2250
// mutated, then it is justified to be annotated with the `mut`
2238
2251
// keyword, since the mutation may be a possible reassignment.
2239
- if is_local_mutation_allowed != LocalMutationIsAllowed :: Yes
2240
- && self . is_local_ever_initialized ( local, flow_state) . is_some ( )
2241
- {
2242
- self . used_mut . insert ( local) ;
2252
+ if !matches ! ( is_local_mutation_allowed, LocalMutationIsAllowed :: Yes ) {
2253
+ if self . is_local_ever_initialized ( local, flow_state) . is_some ( ) {
2254
+ self . used_mut . insert ( local) ;
2255
+ } else if let Some ( & field) = self . local_from_upvars . get ( & local) {
2256
+ self . used_mut_upvars . push ( field) ;
2257
+ }
2243
2258
}
2244
2259
}
2245
2260
RootPlace {
@@ -2257,6 +2272,8 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
2257
2272
projection : place_projection,
2258
2273
} ) {
2259
2274
self . used_mut_upvars . push ( field) ;
2275
+ } else if let Some ( & field) = self . local_from_upvars . get ( & place_local) {
2276
+ self . used_mut_upvars . push ( field) ;
2260
2277
}
2261
2278
}
2262
2279
}
0 commit comments