@@ -15,6 +15,7 @@ use rustc::mir::{BindingForm, BorrowKind, ClearCrossCrate, Field, Local};
1515use rustc:: mir:: { LocalDecl , LocalKind , Location , Operand , Place } ;
1616use rustc:: mir:: { ProjectionElem , Rvalue , Statement , StatementKind } ;
1717use rustc:: ty;
18+ use rustc_data_structures:: fx:: FxHashSet ;
1819use rustc_data_structures:: indexed_vec:: Idx ;
1920use rustc_data_structures:: sync:: Lrc ;
2021use rustc_errors:: DiagnosticBuilder ;
@@ -24,8 +25,9 @@ use super::borrow_set::BorrowData;
2425use super :: { Context , MirBorrowckCtxt } ;
2526use super :: { InitializationRequiringAction , PrefixSet } ;
2627
28+ use dataflow:: drop_flag_effects;
2729use dataflow:: move_paths:: MovePathIndex ;
28- use dataflow:: { FlowAtLocation , MovingOutStatements } ;
30+ use dataflow:: move_paths :: indexes :: MoveOutIndex ;
2931use util:: borrowck_errors:: { BorrowckErrors , Origin } ;
3032
3133impl < ' cx , ' gcx , ' tcx > MirBorrowckCtxt < ' cx , ' gcx , ' tcx > {
@@ -35,17 +37,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
3537 desired_action : InitializationRequiringAction ,
3638 ( place, span) : ( & Place < ' tcx > , Span ) ,
3739 mpi : MovePathIndex ,
38- curr_move_out : & FlowAtLocation < MovingOutStatements < ' _ , ' gcx , ' tcx > > ,
3940 ) {
4041 let use_spans = self
4142 . move_spans ( place, context. loc )
4243 . or_else ( || self . borrow_spans ( span, context. loc ) ) ;
4344 let span = use_spans. args_or_use ( ) ;
4445
45- let mois = self . move_data . path_map [ mpi]
46- . iter ( )
47- . filter ( |moi| curr_move_out. contains ( moi) )
48- . collect :: < Vec < _ > > ( ) ;
46+ let mois = self . get_moved_indexes ( context, mpi) ;
47+ debug ! ( "report_use_of_moved_or_uninitialized: mois={:?}" , mois) ;
4948
5049 if mois. is_empty ( ) {
5150 let root_place = self . prefixes ( & place, PrefixSet :: All ) . last ( ) . unwrap ( ) ;
@@ -93,7 +92,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
9392
9493 let mut is_loop_move = false ;
9594 for moi in & mois {
96- let move_out = self . move_data . moves [ * * moi] ;
95+ let move_out = self . move_data . moves [ * moi] ;
9796 let moved_place = & self . move_data . move_paths [ move_out. path ] . place ;
9897
9998 let move_spans = self . move_spans ( moved_place, move_out. source ) ;
@@ -148,7 +147,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
148147 } ;
149148
150149 if needs_note {
151- let mpi = self . move_data . moves [ * mois[ 0 ] ] . path ;
150+ let mpi = self . move_data . moves [ mois[ 0 ] ] . path ;
152151 let place = & self . move_data . move_paths [ mpi] . place ;
153152
154153 if let Some ( ty) = self . retrieve_type_for_place ( place) {
@@ -521,6 +520,81 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
521520 err
522521 }
523522
523+ fn get_moved_indexes (
524+ & mut self ,
525+ context : Context ,
526+ mpi : MovePathIndex ,
527+ ) -> Vec < MoveOutIndex > {
528+ let mir = self . mir ;
529+
530+ let mut stack = Vec :: new ( ) ;
531+ stack. extend ( mir. predecessor_locations ( context. loc ) ) ;
532+
533+ let mut visited = FxHashSet ( ) ;
534+ let mut result = vec ! [ ] ;
535+
536+ ' dfs:
537+ while let Some ( l) = stack. pop ( ) {
538+ debug ! ( "report_use_of_moved_or_uninitialized: current_location={:?}" , l) ;
539+
540+ if !visited. insert ( l) {
541+ continue ;
542+ }
543+
544+ // check for moves
545+ let stmt_kind = mir[ l. block ] . statements . get ( l. statement_index ) . map ( |s| & s. kind ) ;
546+ if let Some ( StatementKind :: StorageDead ( ..) ) = stmt_kind {
547+ // this analysis only tries to find moves explicitly
548+ // written by the user, so we ignore the move-outs
549+ // created by `StorageDead` and at the beginning
550+ // of a function.
551+ } else {
552+ for moi in & self . move_data . loc_map [ l] {
553+ debug ! ( "report_use_of_moved_or_uninitialized: moi={:?}" , moi) ;
554+ if self . move_data . moves [ * moi] . path == mpi {
555+ debug ! ( "report_use_of_moved_or_uninitialized: found" ) ;
556+ result. push ( * moi) ;
557+
558+ // Strictly speaking, we could continue our DFS here. There may be
559+ // other moves that can reach the point of error. But it is kind of
560+ // confusing to highlight them.
561+ //
562+ // Example:
563+ //
564+ // ```
565+ // let a = vec![];
566+ // let b = a;
567+ // let c = a;
568+ // drop(a); // <-- current point of error
569+ // ```
570+ //
571+ // Because we stop the DFS here, we only highlight `let c = a`,
572+ // and not `let b = a`. We will of course also report an error at
573+ // `let c = a` which highlights `let b = a` as the move.
574+ continue ' dfs;
575+ }
576+ }
577+ }
578+
579+ // check for inits
580+ let mut any_match = false ;
581+ drop_flag_effects:: for_location_inits (
582+ self . tcx ,
583+ self . mir ,
584+ self . move_data ,
585+ l,
586+ |m| if m == mpi { any_match = true ; } ,
587+ ) ;
588+ if any_match {
589+ continue ' dfs;
590+ }
591+
592+ stack. extend ( mir. predecessor_locations ( l) ) ;
593+ }
594+
595+ result
596+ }
597+
524598 pub ( super ) fn report_illegal_mutation_of_borrowed (
525599 & mut self ,
526600 context : Context ,
0 commit comments