@@ -19,6 +19,7 @@ extern crate tracing;
19
19
20
20
use rustc_data_structures:: fx:: { FxIndexMap , FxIndexSet } ;
21
21
use rustc_data_structures:: graph:: dominators:: Dominators ;
22
+ use rustc_data_structures:: unord:: UnordMap ;
22
23
use rustc_errors:: Diag ;
23
24
use rustc_hir as hir;
24
25
use rustc_hir:: def_id:: LocalDefId ;
@@ -296,6 +297,7 @@ fn do_mir_borrowck<'tcx>(
296
297
regioncx : regioncx. clone ( ) ,
297
298
used_mut : Default :: default ( ) ,
298
299
used_mut_upvars : SmallVec :: new ( ) ,
300
+ local_from_upvars : UnordMap :: default ( ) ,
299
301
borrow_set : Rc :: clone ( & borrow_set) ,
300
302
upvars : & [ ] ,
301
303
local_names : IndexVec :: from_elem ( None , & promoted_body. local_decls ) ,
@@ -322,6 +324,12 @@ fn do_mir_borrowck<'tcx>(
322
324
}
323
325
}
324
326
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" ) ;
325
333
let mut mbcx = MirBorrowckCtxt {
326
334
infcx : & infcx,
327
335
param_env,
@@ -337,6 +345,7 @@ fn do_mir_borrowck<'tcx>(
337
345
regioncx : Rc :: clone ( & regioncx) ,
338
346
used_mut : Default :: default ( ) ,
339
347
used_mut_upvars : SmallVec :: new ( ) ,
348
+ local_from_upvars,
340
349
borrow_set : Rc :: clone ( & borrow_set) ,
341
350
upvars : tcx. closure_captures ( def) ,
342
351
local_names,
@@ -572,6 +581,9 @@ struct MirBorrowckCtxt<'a, 'mir, 'infcx, 'tcx> {
572
581
/// If the function we're checking is a closure, then we'll need to report back the list of
573
582
/// mutable upvars that have been used. This field keeps track of them.
574
583
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 > ,
575
587
/// Region inference context. This contains the results from region inference and lets us e.g.
576
588
/// find out which CFG points are contained in each borrow region.
577
589
regioncx : Rc < RegionInferenceContext < ' tcx > > ,
@@ -2227,16 +2239,19 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
2227
2239
}
2228
2240
2229
2241
/// Adds the place into the used mutable variables set
2242
+ #[ instrument( level = "debug" , skip( self , flow_state) ) ]
2230
2243
fn add_used_mut ( & mut self , root_place : RootPlace < ' tcx > , flow_state : & Flows < ' _ , ' mir , ' tcx > ) {
2231
2244
match root_place {
2232
2245
RootPlace { place_local : local, place_projection : [ ] , is_local_mutation_allowed } => {
2233
2246
// If the local may have been initialized, and it is now currently being
2234
2247
// mutated, then it is justified to be annotated with the `mut`
2235
2248
// keyword, since the mutation may be a possible reassignment.
2236
- if is_local_mutation_allowed != LocalMutationIsAllowed :: Yes
2237
- && self . is_local_ever_initialized ( local, flow_state) . is_some ( )
2238
- {
2239
- self . used_mut . insert ( local) ;
2249
+ if !matches ! ( is_local_mutation_allowed, LocalMutationIsAllowed :: Yes ) {
2250
+ if self . is_local_ever_initialized ( local, flow_state) . is_some ( ) {
2251
+ self . used_mut . insert ( local) ;
2252
+ } else if let Some ( & field) = self . local_from_upvars . get ( & local) {
2253
+ self . used_mut_upvars . push ( field) ;
2254
+ }
2240
2255
}
2241
2256
}
2242
2257
RootPlace {
@@ -2254,6 +2269,8 @@ impl<'mir, 'tcx> MirBorrowckCtxt<'_, 'mir, '_, 'tcx> {
2254
2269
projection : place_projection,
2255
2270
} ) {
2256
2271
self . used_mut_upvars . push ( field) ;
2272
+ } else if let Some ( & field) = self . local_from_upvars . get ( & place_local) {
2273
+ self . used_mut_upvars . push ( field) ;
2257
2274
}
2258
2275
}
2259
2276
}
0 commit comments