@@ -35,6 +35,17 @@ use dataflow::move_paths::indexes::MoveOutIndex;
3535use dataflow:: move_paths:: MovePathIndex ;
3636use util:: borrowck_errors:: { BorrowckErrors , Origin } ;
3737
38+ #[ derive( Debug ) ]
39+ struct MoveSite {
40+ /// Index of the "move out" that we found. The `MoveData` can
41+ /// then tell us where the move occurred.
42+ moi : MoveOutIndex ,
43+
44+ /// True if we traversed a back edge while walking from the point
45+ /// of error to the move site.
46+ traversed_back_edge : bool
47+ }
48+
3849impl < ' cx , ' gcx , ' tcx > MirBorrowckCtxt < ' cx , ' gcx , ' tcx > {
3950 pub ( super ) fn report_use_of_moved_or_uninitialized (
4051 & mut self ,
@@ -53,10 +64,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
5364 . or_else ( || self . borrow_spans ( span, context. loc ) ) ;
5465 let span = use_spans. args_or_use ( ) ;
5566
56- let mois = self . get_moved_indexes ( context, mpi) ;
57- debug ! ( "report_use_of_moved_or_uninitialized: mois={:?}" , mois) ;
67+ let move_site_vec = self . get_moved_indexes ( context, mpi) ;
68+ debug ! (
69+ "report_use_of_moved_or_uninitialized: move_site_vec={:?}" ,
70+ move_site_vec
71+ ) ;
72+ let move_out_indices: Vec < _ > = move_site_vec
73+ . iter ( )
74+ . map ( |move_site| move_site. moi )
75+ . collect ( ) ;
5876
59- if mois . is_empty ( ) {
77+ if move_out_indices . is_empty ( ) {
6078 let root_place = self . prefixes ( & place, PrefixSet :: All ) . last ( ) . unwrap ( ) ;
6179
6280 if self . uninitialized_error_reported
@@ -91,14 +109,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
91109
92110 err. buffer ( & mut self . errors_buffer ) ;
93111 } else {
94- if let Some ( ( reported_place, _) ) = self . move_error_reported . get ( & mois ) {
112+ if let Some ( ( reported_place, _) ) = self . move_error_reported . get ( & move_out_indices ) {
95113 if self . prefixes ( & reported_place, PrefixSet :: All )
96114 . any ( |p| p == place)
97115 {
98116 debug ! (
99117 "report_use_of_moved_or_uninitialized place: error suppressed \
100118 mois={:?}",
101- mois
119+ move_out_indices
102120 ) ;
103121 return ;
104122 }
@@ -115,8 +133,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
115133 ) ;
116134
117135 let mut is_loop_move = false ;
118- for moi in & mois {
119- let move_out = self . move_data . moves [ * moi] ;
136+ for move_site in & move_site_vec {
137+ let move_out = self . move_data . moves [ ( * move_site ) . moi ] ;
120138 let moved_place = & self . move_data . move_paths [ move_out. path ] . place ;
121139
122140 let move_spans = self . move_spans ( moved_place, move_out. source ) ;
@@ -131,9 +149,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
131149 if span == move_span {
132150 err. span_label (
133151 span,
134- format ! ( "value moved{} here in previous iteration of loop" , move_msg) ,
152+ format ! ( "value moved{} here, in previous iteration of loop" , move_msg) ,
135153 ) ;
136154 is_loop_move = true ;
155+ } else if move_site. traversed_back_edge {
156+ err. span_label (
157+ move_span,
158+ format ! (
159+ "value moved{} here, in previous iteration of loop" ,
160+ move_msg
161+ ) ,
162+ ) ;
137163 } else {
138164 err. span_label ( move_span, format ! ( "value moved{} here" , move_msg) ) ;
139165 move_spans. var_span_label ( & mut err, "variable moved due to use in closure" ) ;
@@ -171,7 +197,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
171197 } ;
172198
173199 if needs_note {
174- let mpi = self . move_data . moves [ mois [ 0 ] ] . path ;
200+ let mpi = self . move_data . moves [ move_out_indices [ 0 ] ] . path ;
175201 let place = & self . move_data . move_paths [ mpi] . place ;
176202
177203 if let Some ( ty) = self . retrieve_type_for_place ( place) {
@@ -192,8 +218,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
192218 }
193219 }
194220
195- if let Some ( ( _, mut old_err) ) =
196- self . move_error_reported . insert ( mois , ( place. clone ( ) , err) )
221+ if let Some ( ( _, mut old_err) ) = self . move_error_reported
222+ . insert ( move_out_indices , ( place. clone ( ) , err) )
197223 {
198224 // Cancel the old error so it doesn't ICE.
199225 old_err. cancel ( ) ;
@@ -733,29 +759,32 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
733759 err
734760 }
735761
736- fn get_moved_indexes ( & mut self , context : Context , mpi : MovePathIndex ) -> Vec < MoveOutIndex > {
762+ fn get_moved_indexes ( & mut self , context : Context , mpi : MovePathIndex ) -> Vec < MoveSite > {
737763 let mir = self . mir ;
738764
739765 let mut stack = Vec :: new ( ) ;
740- stack. extend ( mir. predecessor_locations ( context. loc ) ) ;
766+ stack. extend ( mir. predecessor_locations ( context. loc ) . map ( |predecessor| {
767+ let is_back_edge = context. loc . dominates ( predecessor, & self . dominators ) ;
768+ ( predecessor, is_back_edge)
769+ } ) ) ;
741770
742771 let mut visited = FxHashSet ( ) ;
743772 let mut result = vec ! [ ] ;
744773
745- ' dfs: while let Some ( l ) = stack. pop ( ) {
774+ ' dfs: while let Some ( ( location , is_back_edge ) ) = stack. pop ( ) {
746775 debug ! (
747- "report_use_of_moved_or_uninitialized: current_location={:?}" ,
748- l
776+ "report_use_of_moved_or_uninitialized: ( current_location={:?}, back_edge={}) " ,
777+ location , is_back_edge
749778 ) ;
750779
751- if !visited. insert ( l ) {
780+ if !visited. insert ( location ) {
752781 continue ;
753782 }
754783
755784 // check for moves
756- let stmt_kind = mir[ l . block ]
785+ let stmt_kind = mir[ location . block ]
757786 . statements
758- . get ( l . statement_index )
787+ . get ( location . statement_index )
759788 . map ( |s| & s. kind ) ;
760789 if let Some ( StatementKind :: StorageDead ( ..) ) = stmt_kind {
761790 // this analysis only tries to find moves explicitly
@@ -774,11 +803,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
774803 let move_paths = & self . move_data . move_paths ;
775804 mpis. extend ( move_paths[ mpi] . parents ( move_paths) ) ;
776805
777- for moi in & self . move_data . loc_map [ l ] {
806+ for moi in & self . move_data . loc_map [ location ] {
778807 debug ! ( "report_use_of_moved_or_uninitialized: moi={:?}" , moi) ;
779808 if mpis. contains ( & self . move_data . moves [ * moi] . path ) {
780809 debug ! ( "report_use_of_moved_or_uninitialized: found" ) ;
781- result. push ( * moi) ;
810+ result. push ( MoveSite {
811+ moi : * moi,
812+ traversed_back_edge : is_back_edge,
813+ } ) ;
782814
783815 // Strictly speaking, we could continue our DFS here. There may be
784816 // other moves that can reach the point of error. But it is kind of
@@ -807,7 +839,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
807839 self . infcx . tcx ,
808840 self . mir ,
809841 self . move_data ,
810- l ,
842+ location ,
811843 |m| {
812844 if m == mpi {
813845 any_match = true ;
@@ -818,7 +850,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
818850 continue ' dfs;
819851 }
820852
821- stack. extend ( mir. predecessor_locations ( l) ) ;
853+ stack. extend ( mir. predecessor_locations ( location) . map ( |predecessor| {
854+ let back_edge = location. dominates ( predecessor, & self . dominators ) ;
855+ ( predecessor, is_back_edge || back_edge)
856+ } ) ) ;
822857 }
823858
824859 result
0 commit comments