@@ -510,6 +510,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
510510 )
511511 . as_str ( ) ,
512512 ) ;
513+ for ( var_hir_id, diagnostics_info) in need_migrations. iter ( ) {
514+ for ( captured_hir_id, captured_name) in diagnostics_info. iter ( ) {
515+ if let Some ( captured_hir_id) = captured_hir_id {
516+ let cause_span = self . tcx . hir ( ) . span ( * captured_hir_id) ;
517+ diagnostics_builder. span_label ( cause_span, format ! ( "in Rust 2018, closure captures all of `{}`, but in Rust 2021, it only captures `{}`" ,
518+ self . tcx. hir( ) . name( * var_hir_id) ,
519+ captured_name,
520+ ) ) ;
521+ }
522+ }
523+ }
513524 diagnostics_builder. note ( "for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>" ) ;
514525 let closure_body_span = self . tcx . hir ( ) . span ( body_id. hir_id ) ;
515526 let ( sugg, app) =
@@ -579,13 +590,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
579590 var_hir_id : hir:: HirId ,
580591 check_trait : Option < DefId > ,
581592 closure_clause : hir:: CaptureBy ,
582- ) -> bool {
593+ ) -> Option < ( Option < hir :: HirId > , String ) > {
583594 let root_var_min_capture_list = if let Some ( root_var_min_capture_list) =
584595 min_captures. and_then ( |m| m. get ( & var_hir_id) )
585596 {
586597 root_var_min_capture_list
587598 } else {
588- return false ;
599+ return None ;
589600 } ;
590601
591602 let ty = self . infcx . resolve_vars_if_possible ( self . node_ty ( var_hir_id) ) ;
@@ -639,10 +650,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
639650 . unwrap_or ( false ) ;
640651
641652 if !obligation_holds_for_capture && obligation_should_hold {
642- return true ;
653+ return Some ( ( capture . info . path_expr_id , capture . to_string ( self . tcx ) ) ) ;
643654 }
644655 }
645- false
656+ None
646657 }
647658
648659 /// Figures out the list of root variables (and their types) that aren't completely
@@ -660,68 +671,75 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
660671 min_captures : Option < & ty:: RootVariableMinCaptureList < ' tcx > > ,
661672 var_hir_id : hir:: HirId ,
662673 closure_clause : hir:: CaptureBy ,
663- ) -> Option < FxHashSet < & str > > {
674+ ) -> Option < ( FxHashSet < & str > , FxHashSet < ( Option < hir :: HirId > , String ) > ) > {
664675 let tcx = self . infcx . tcx ;
665676
666677 // Check whether catpured fields also implement the trait
667678 let mut auto_trait_reasons = FxHashSet :: default ( ) ;
679+ let mut diagnostics_info = FxHashSet :: default ( ) ;
668680
669- if self . need_2229_migrations_for_trait (
681+ if let Some ( info ) = self . need_2229_migrations_for_trait (
670682 min_captures,
671683 var_hir_id,
672684 tcx. lang_items ( ) . clone_trait ( ) ,
673685 closure_clause,
674686 ) {
675687 auto_trait_reasons. insert ( "`Clone`" ) ;
688+ diagnostics_info. insert ( info) ;
676689 }
677690
678- if self . need_2229_migrations_for_trait (
691+ if let Some ( info ) = self . need_2229_migrations_for_trait (
679692 min_captures,
680693 var_hir_id,
681694 tcx. lang_items ( ) . sync_trait ( ) ,
682695 closure_clause,
683696 ) {
684697 auto_trait_reasons. insert ( "`Sync`" ) ;
698+ diagnostics_info. insert ( info) ;
685699 }
686700
687- if self . need_2229_migrations_for_trait (
701+ if let Some ( info ) = self . need_2229_migrations_for_trait (
688702 min_captures,
689703 var_hir_id,
690704 tcx. get_diagnostic_item ( sym:: send_trait) ,
691705 closure_clause,
692706 ) {
693707 auto_trait_reasons. insert ( "`Send`" ) ;
708+ diagnostics_info. insert ( info) ;
694709 }
695710
696- if self . need_2229_migrations_for_trait (
711+ if let Some ( info ) = self . need_2229_migrations_for_trait (
697712 min_captures,
698713 var_hir_id,
699714 tcx. lang_items ( ) . unpin_trait ( ) ,
700715 closure_clause,
701716 ) {
702717 auto_trait_reasons. insert ( "`Unpin`" ) ;
718+ diagnostics_info. insert ( info) ;
703719 }
704720
705- if self . need_2229_migrations_for_trait (
721+ if let Some ( info ) = self . need_2229_migrations_for_trait (
706722 min_captures,
707723 var_hir_id,
708724 tcx. get_diagnostic_item ( sym:: unwind_safe_trait) ,
709725 closure_clause,
710726 ) {
711727 auto_trait_reasons. insert ( "`UnwindSafe`" ) ;
728+ diagnostics_info. insert ( info) ;
712729 }
713730
714- if self . need_2229_migrations_for_trait (
731+ if let Some ( info ) = self . need_2229_migrations_for_trait (
715732 min_captures,
716733 var_hir_id,
717734 tcx. get_diagnostic_item ( sym:: ref_unwind_safe_trait) ,
718735 closure_clause,
719736 ) {
720737 auto_trait_reasons. insert ( "`RefUnwindSafe`" ) ;
738+ diagnostics_info. insert ( info) ;
721739 }
722740
723741 if auto_trait_reasons. len ( ) > 0 {
724- return Some ( auto_trait_reasons) ;
742+ return Some ( ( auto_trait_reasons, diagnostics_info ) ) ;
725743 }
726744
727745 return None ;
@@ -746,11 +764,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
746764 min_captures : Option < & ty:: RootVariableMinCaptureList < ' tcx > > ,
747765 closure_clause : hir:: CaptureBy ,
748766 var_hir_id : hir:: HirId ,
749- ) -> bool {
767+ ) -> Option < FxHashSet < ( Option < hir :: HirId > , String ) > > {
750768 let ty = self . infcx . resolve_vars_if_possible ( self . node_ty ( var_hir_id) ) ;
751769
752770 if !ty. has_significant_drop ( self . tcx , self . tcx . param_env ( closure_def_id. expect_local ( ) ) ) {
753- return false ;
771+ return None ;
754772 }
755773
756774 let root_var_min_capture_list = if let Some ( root_var_min_capture_list) =
@@ -763,21 +781,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
763781
764782 match closure_clause {
765783 // Only migrate if closure is a move closure
766- hir:: CaptureBy :: Value => return true ,
784+ hir:: CaptureBy :: Value => return Some ( FxHashSet :: default ( ) ) ,
767785 hir:: CaptureBy :: Ref => { }
768786 }
769787
770- return false ;
788+ return None ;
771789 } ;
772790
773- let projections_list = root_var_min_capture_list
774- . iter ( )
775- . filter_map ( |captured_place| match captured_place. info . capture_kind {
791+ let mut projections_list = Vec :: new ( ) ;
792+ let mut diagnostics_info = FxHashSet :: default ( ) ;
793+
794+ for captured_place in root_var_min_capture_list. iter ( ) {
795+ match captured_place. info . capture_kind {
776796 // Only care about captures that are moved into the closure
777- ty:: UpvarCapture :: ByValue ( ..) => Some ( captured_place. place . projections . as_slice ( ) ) ,
778- ty:: UpvarCapture :: ByRef ( ..) => None ,
779- } )
780- . collect :: < Vec < _ > > ( ) ;
797+ ty:: UpvarCapture :: ByValue ( ..) => {
798+ projections_list. push ( captured_place. place . projections . as_slice ( ) ) ;
799+ diagnostics_info. insert ( (
800+ captured_place. info . path_expr_id ,
801+ captured_place. to_string ( self . tcx ) ,
802+ ) ) ;
803+ }
804+ ty:: UpvarCapture :: ByRef ( ..) => { }
805+ }
806+ }
781807
782808 let is_moved = !projections_list. is_empty ( ) ;
783809
@@ -793,10 +819,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
793819 projections_list,
794820 )
795821 {
796- return true ;
822+ return Some ( diagnostics_info ) ;
797823 }
798824
799- return false ;
825+ return None ;
800826 }
801827
802828 /// Figures out the list of root variables (and their types) that aren't completely
@@ -820,7 +846,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
820846 closure_span : Span ,
821847 closure_clause : hir:: CaptureBy ,
822848 min_captures : Option < & ty:: RootVariableMinCaptureList < ' tcx > > ,
823- ) -> ( Vec < hir:: HirId > , String ) {
849+ ) -> ( Vec < ( hir:: HirId , FxHashSet < ( Option < hir :: HirId > , String ) > ) > , String ) {
824850 let upvars = if let Some ( upvars) = self . tcx . upvars_mentioned ( closure_def_id) {
825851 upvars
826852 } else {
@@ -834,14 +860,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
834860 // Perform auto-trait analysis
835861 for ( & var_hir_id, _) in upvars. iter ( ) {
836862 let mut need_migration = false ;
837- if let Some ( trait_migration_cause) =
863+ let mut responsible_captured_hir_ids = FxHashSet :: default ( ) ;
864+
865+ if let Some ( ( trait_migration_cause, diagnostics_info) ) =
838866 self . compute_2229_migrations_for_trait ( min_captures, var_hir_id, closure_clause)
839867 {
840868 need_migration = true ;
841869 auto_trait_reasons. extend ( trait_migration_cause) ;
870+ responsible_captured_hir_ids. extend ( diagnostics_info) ;
842871 }
843872
844- if self . compute_2229_migrations_for_drop (
873+ if let Some ( diagnostics_info ) = self . compute_2229_migrations_for_drop (
845874 closure_def_id,
846875 closure_span,
847876 min_captures,
@@ -850,10 +879,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
850879 ) {
851880 need_migration = true ;
852881 drop_reorder_reason = true ;
882+ responsible_captured_hir_ids. extend ( diagnostics_info) ;
853883 }
854884
855885 if need_migration {
856- need_migrations. push ( var_hir_id) ;
886+ need_migrations. push ( ( var_hir_id, responsible_captured_hir_ids ) ) ;
857887 }
858888 }
859889
@@ -1877,10 +1907,10 @@ fn should_do_rust_2021_incompatible_closure_captures_analysis(
18771907/// - s2: Comma separated names of the variables being migrated.
18781908fn migration_suggestion_for_2229 (
18791909 tcx : TyCtxt < ' _ > ,
1880- need_migrations : & Vec < hir:: HirId > ,
1910+ need_migrations : & Vec < ( hir:: HirId , FxHashSet < ( Option < hir :: HirId > , String ) > ) > ,
18811911) -> ( String , String ) {
18821912 let need_migrations_variables =
1883- need_migrations. iter ( ) . map ( |v | var_name ( tcx, * v) ) . collect :: < Vec < _ > > ( ) ;
1913+ need_migrations. iter ( ) . map ( |( v , _ ) | var_name ( tcx, * v) ) . collect :: < Vec < _ > > ( ) ;
18841914
18851915 let migration_ref_concat =
18861916 need_migrations_variables. iter ( ) . map ( |v| format ! ( "&{}" , v) ) . collect :: < Vec < _ > > ( ) . join ( ", " ) ;
0 commit comments