@@ -15,6 +15,7 @@ use rustc_index::vec::Idx;
15
15
use rustc_infer:: infer:: InferCtxt ;
16
16
use rustc_middle:: hir:: place:: ProjectionKind ;
17
17
use rustc_middle:: ty:: { self , adjustment, TyCtxt } ;
18
+ use rustc_span:: Span ;
18
19
use rustc_target:: abi:: VariantIdx ;
19
20
20
21
use crate :: mem_categorization as mc;
@@ -570,6 +571,38 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
570
571
} ) ) ;
571
572
}
572
573
574
+ /// Walk closure captures but using `closure_caputes` instead
575
+ /// of `closure_min_captures`.
576
+ ///
577
+ /// This is needed because clippy uses `ExprUseVisitor` after TypeckResults
578
+ /// are written back. We don't currently writeback min_captures to
579
+ /// TypeckResults.
580
+ fn walk_captures_closure_captures ( & mut self , closure_expr : & hir:: Expr < ' _ > ) {
581
+ // FIXME(arora-aman): Remove this function once rust-lang/project-rfc-2229#18
582
+ // is completed.
583
+ debug ! ( "walk_captures_closure_captures({:?}), " , closure_expr) ;
584
+
585
+ let closure_def_id = self . tcx ( ) . hir ( ) . local_def_id ( closure_expr. hir_id ) . to_def_id ( ) ;
586
+ let cl_span = self . tcx ( ) . hir ( ) . span ( closure_expr. hir_id ) ;
587
+
588
+ let captures = & self . mc . typeck_results . closure_captures [ & closure_def_id] ;
589
+
590
+ for ( & var_id, & upvar_id) in captures {
591
+ let upvar_capture = self . mc . typeck_results . upvar_capture ( upvar_id) ;
592
+ let captured_place =
593
+ return_if_err ! ( self . cat_captured_var( closure_expr. hir_id, cl_span, var_id) ) ;
594
+ match upvar_capture {
595
+ ty:: UpvarCapture :: ByValue ( _) => {
596
+ let mode = copy_or_move ( & self . mc , & captured_place) ;
597
+ self . delegate . consume ( & captured_place, captured_place. hir_id , mode) ;
598
+ }
599
+ ty:: UpvarCapture :: ByRef ( upvar_borrow) => {
600
+ self . delegate . borrow ( & captured_place, captured_place. hir_id , upvar_borrow. kind ) ;
601
+ }
602
+ }
603
+ }
604
+ }
605
+
573
606
/// Handle the case where the current body contains a closure.
574
607
///
575
608
/// When the current body being handled is a closure, then we must make sure that
@@ -625,6 +658,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
625
658
PlaceBase :: Upvar ( upvar_id) ,
626
659
place. projections . clone ( ) ,
627
660
) ;
661
+
628
662
match capture_info. capture_kind {
629
663
ty:: UpvarCapture :: ByValue ( _) => {
630
664
let mode = copy_or_move ( & self . mc , & place_with_id) ;
@@ -640,8 +674,23 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
640
674
}
641
675
}
642
676
}
677
+ } else if self . mc . typeck_results . closure_captures . contains_key ( & closure_def_id) {
678
+ // Handle the case where clippy calls ExprUseVisitor after
679
+ self . walk_captures_closure_captures ( closure_expr)
643
680
}
644
681
}
682
+
683
+ fn cat_captured_var (
684
+ & mut self ,
685
+ closure_hir_id : hir:: HirId ,
686
+ closure_span : Span ,
687
+ var_id : hir:: HirId ,
688
+ ) -> mc:: McResult < PlaceWithHirId < ' tcx > > {
689
+ // Create the place for the variable being borrowed, from the
690
+ // perspective of the creator (parent) of the closure.
691
+ let var_ty = self . mc . node_ty ( var_id) ?;
692
+ self . mc . cat_res ( closure_hir_id, closure_span, var_ty, Res :: Local ( var_id) )
693
+ }
645
694
}
646
695
647
696
fn copy_or_move < ' a , ' tcx > (
0 commit comments