@@ -317,19 +317,20 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
317
317
// swap in a new set of IR maps for this body
318
318
let mut maps = IrMaps :: new ( self . tcx ) ;
319
319
let hir_id = maps. tcx . hir ( ) . body_owner ( body. id ( ) ) ;
320
- let def_id = maps. tcx . hir ( ) . local_def_id ( hir_id) ;
320
+ let local_def_id = maps. tcx . hir ( ) . local_def_id ( hir_id) ;
321
+ let def_id = local_def_id. to_def_id ( ) ;
321
322
322
323
// Don't run unused pass for #[derive()]
323
- if let Some ( parent) = self . tcx . parent ( def_id. to_def_id ( ) ) {
324
+ if let Some ( parent) = self . tcx . parent ( def_id) {
324
325
if let DefKind :: Impl = self . tcx . def_kind ( parent. expect_local ( ) ) {
325
326
if self . tcx . has_attr ( parent, sym:: automatically_derived) {
326
327
return ;
327
328
}
328
329
}
329
330
}
330
331
331
- if let Some ( upvars ) = maps. tcx . upvars_mentioned ( def_id) {
332
- for ( & var_hir_id, _upvar ) in upvars {
332
+ if let Some ( captures ) = maps. tcx . typeck ( local_def_id ) . closure_captures . get ( & def_id) {
333
+ for & var_hir_id in captures . keys ( ) {
333
334
let var_name = maps. tcx . hir ( ) . name ( var_hir_id) ;
334
335
maps. add_variable ( Upvar ( var_hir_id, var_name) ) ;
335
336
}
@@ -340,7 +341,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
340
341
intravisit:: walk_body ( & mut maps, body) ;
341
342
342
343
// compute liveness
343
- let mut lsets = Liveness :: new ( & mut maps, def_id ) ;
344
+ let mut lsets = Liveness :: new ( & mut maps, local_def_id ) ;
344
345
let entry_ln = lsets. compute ( & body, hir_id) ;
345
346
lsets. log_liveness ( entry_ln, body. id ( ) . hir_id ) ;
346
347
@@ -397,10 +398,18 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
397
398
// construction site.
398
399
let mut call_caps = Vec :: new ( ) ;
399
400
let closure_def_id = self . tcx . hir ( ) . local_def_id ( expr. hir_id ) ;
400
- if let Some ( upvars) = self . tcx . upvars_mentioned ( closure_def_id) {
401
- call_caps. extend ( upvars. iter ( ) . map ( |( & var_id, upvar) | {
401
+ if let Some ( captures) = self
402
+ . tcx
403
+ . typeck ( closure_def_id)
404
+ . closure_captures
405
+ . get ( & closure_def_id. to_def_id ( ) )
406
+ {
407
+ // If closure captures is Some, upvars_mentioned must also be Some
408
+ let upvars = self . tcx . upvars_mentioned ( closure_def_id) . unwrap ( ) ;
409
+ call_caps. extend ( captures. keys ( ) . map ( |var_id| {
410
+ let upvar = upvars[ var_id] ;
402
411
let upvar_ln = self . add_live_node ( UpvarNode ( upvar. span ) ) ;
403
- CaptureInfo { ln : upvar_ln, var_hid : var_id }
412
+ CaptureInfo { ln : upvar_ln, var_hid : * var_id }
404
413
} ) ) ;
405
414
}
406
415
self . set_captures ( expr. hir_id , call_caps) ;
@@ -564,6 +573,7 @@ struct Liveness<'a, 'tcx> {
564
573
typeck_results : & ' a ty:: TypeckResults < ' tcx > ,
565
574
param_env : ty:: ParamEnv < ' tcx > ,
566
575
upvars : Option < & ' tcx FxIndexMap < hir:: HirId , hir:: Upvar > > ,
576
+ closure_captures : Option < & ' tcx FxIndexMap < hir:: HirId , ty:: UpvarId > > ,
567
577
successors : IndexVec < LiveNode , Option < LiveNode > > ,
568
578
rwu_table : RWUTable ,
569
579
@@ -587,6 +597,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
587
597
let typeck_results = ir. tcx . typeck ( body_owner) ;
588
598
let param_env = ir. tcx . param_env ( body_owner) ;
589
599
let upvars = ir. tcx . upvars_mentioned ( body_owner) ;
600
+ let closure_captures = typeck_results. closure_captures . get ( & body_owner. to_def_id ( ) ) ;
590
601
591
602
let closure_ln = ir. add_live_node ( ClosureNode ) ;
592
603
let exit_ln = ir. add_live_node ( ExitNode ) ;
@@ -600,6 +611,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
600
611
typeck_results,
601
612
param_env,
602
613
upvars,
614
+ closure_captures,
603
615
successors : IndexVec :: from_elem_n ( None , num_live_nodes) ,
604
616
rwu_table : RWUTable :: new ( num_live_nodes * num_vars) ,
605
617
closure_ln,
@@ -850,14 +862,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
850
862
// if they are live on the entry to the closure, since only the closure
851
863
// itself can access them on subsequent calls.
852
864
853
- if let Some ( upvars ) = self . upvars {
865
+ if let Some ( closure_captures ) = self . closure_captures {
854
866
// Mark upvars captured by reference as used after closure exits.
855
- for ( & var_hir_id, upvar) in upvars. iter ( ) . rev ( ) {
856
- let upvar_id = ty:: UpvarId {
857
- var_path : ty:: UpvarPath { hir_id : var_hir_id } ,
858
- closure_expr_id : self . body_owner ,
859
- } ;
860
- match self . typeck_results . upvar_capture ( upvar_id) {
867
+ // Since closure_captures is Some, upvars must exists too.
868
+ let upvars = self . upvars . unwrap ( ) ;
869
+ for ( & var_hir_id, upvar_id) in closure_captures {
870
+ let upvar = upvars[ & var_hir_id] ;
871
+ match self . typeck_results . upvar_capture ( * upvar_id) {
861
872
ty:: UpvarCapture :: ByRef ( _) => {
862
873
let var = self . variable ( var_hir_id, upvar. span ) ;
863
874
self . acc ( self . exit_ln , var, ACC_READ | ACC_USE ) ;
@@ -869,7 +880,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
869
880
870
881
let succ = self . propagate_through_expr ( & body. value , self . exit_ln ) ;
871
882
872
- if self . upvars . is_none ( ) {
883
+ if self . closure_captures . is_none ( ) {
873
884
// Either not a closure, or closure without any captured variables.
874
885
// No need to determine liveness of captured variables, since there
875
886
// are none.
@@ -1341,7 +1352,21 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
1341
1352
acc : u32 ,
1342
1353
) -> LiveNode {
1343
1354
match path. res {
1344
- Res :: Local ( hid) => self . access_var ( hir_id, hid, succ, acc, path. span ) ,
1355
+ Res :: Local ( hid) => {
1356
+ let in_upvars = self . upvars . map_or ( false , |u| u. contains_key ( & hid) ) ;
1357
+ let in_captures = self . closure_captures . map_or ( false , |c| c. contains_key ( & hid) ) ;
1358
+
1359
+ match ( in_upvars, in_captures) {
1360
+ ( false , _) | ( true , true ) => self . access_var ( hir_id, hid, succ, acc, path. span ) ,
1361
+ ( true , false ) => {
1362
+ // This case is possible when with RFC-2229, a wild pattern
1363
+ // is used within a closure.
1364
+ // eg: `let _ = x`. The closure doesn't capture x here,
1365
+ // even though it's mentioned in the closure.
1366
+ succ
1367
+ }
1368
+ }
1369
+ }
1345
1370
_ => succ,
1346
1371
}
1347
1372
}
@@ -1531,11 +1556,15 @@ impl<'tcx> Liveness<'_, 'tcx> {
1531
1556
}
1532
1557
1533
1558
fn warn_about_unused_upvars ( & self , entry_ln : LiveNode ) {
1534
- let upvars = match self . upvars {
1559
+ let closure_captures = match self . closure_captures {
1535
1560
None => return ,
1536
- Some ( upvars ) => upvars ,
1561
+ Some ( closure_captures ) => closure_captures ,
1537
1562
} ;
1538
- for ( & var_hir_id, upvar) in upvars. iter ( ) {
1563
+
1564
+ // If closure_captures is Some(), upvars must be Some() too.
1565
+ let upvars = self . upvars . unwrap ( ) ;
1566
+ for & var_hir_id in closure_captures. keys ( ) {
1567
+ let upvar = upvars[ & var_hir_id] ;
1539
1568
let var = self . variable ( var_hir_id, upvar. span ) ;
1540
1569
let upvar_id = ty:: UpvarId {
1541
1570
var_path : ty:: UpvarPath { hir_id : var_hir_id } ,
0 commit comments