@@ -10,8 +10,7 @@ use rustc_middle::mir::{
1010 ProjectionElem , Rvalue , Statement , StatementKind , Terminator , TerminatorKind , VarBindingForm ,
1111} ;
1212use rustc_middle:: ty:: { self , suggest_constraining_type_param, Ty } ;
13- use rustc_mir_dataflow:: drop_flag_effects;
14- use rustc_mir_dataflow:: move_paths:: { MoveOutIndex , MovePathIndex } ;
13+ use rustc_mir_dataflow:: move_paths:: { InitKind , MoveOutIndex , MovePathIndex } ;
1514use rustc_span:: source_map:: DesugaringKind ;
1615use rustc_span:: symbol:: sym;
1716use rustc_span:: { BytePos , MultiSpan , Span , DUMMY_SP } ;
@@ -1531,25 +1530,45 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15311530 }
15321531 }
15331532
1533+ let mut mpis = vec ! [ mpi] ;
1534+ let move_paths = & self . move_data . move_paths ;
1535+ mpis. extend ( move_paths[ mpi] . parents ( move_paths) . map ( |( mpi, _) | mpi) ) ;
1536+
15341537 let mut stack = Vec :: new ( ) ;
1535- stack. extend ( predecessor_locations ( self . body , location) . map ( |predecessor| {
1536- let is_back_edge = location. dominates ( predecessor, & self . dominators ) ;
1537- ( predecessor, is_back_edge)
1538- } ) ) ;
1538+ let mut back_edge_stack = Vec :: new ( ) ;
1539+
1540+ predecessor_locations ( self . body , location) . for_each ( |predecessor| {
1541+ if location. dominates ( predecessor, & self . dominators ) {
1542+ back_edge_stack. push ( predecessor)
1543+ } else {
1544+ stack. push ( predecessor) ;
1545+ }
1546+ } ) ;
1547+
1548+ let mut reached_start = false ;
1549+
1550+ /* Check if the mpi is initialized as an argument */
1551+ let mut is_argument = false ;
1552+ for arg in self . body . args_iter ( ) {
1553+ let path = self . move_data . rev_lookup . find_local ( arg) ;
1554+ if mpis. contains ( & path) {
1555+ is_argument = true ;
1556+ }
1557+ }
15391558
15401559 let mut visited = FxHashSet :: default ( ) ;
15411560 let mut move_locations = FxHashSet :: default ( ) ;
15421561 let mut reinits = vec ! [ ] ;
15431562 let mut result = vec ! [ ] ;
15441563
1545- ' dfs : while let Some ( ( location, is_back_edge) ) = stack . pop ( ) {
1564+ let mut dfs_iter = | result : & mut Vec < MoveSite > , location : Location , is_back_edge : bool | {
15461565 debug ! (
15471566 "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})" ,
15481567 location, is_back_edge
15491568 ) ;
15501569
15511570 if !visited. insert ( location) {
1552- continue ;
1571+ return true ;
15531572 }
15541573
15551574 // check for moves
@@ -1568,10 +1587,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15681587 // worry about the other case: that is, if there is a move of a.b.c, it is already
15691588 // marked as a move of a.b and a as well, so we will generate the correct errors
15701589 // there.
1571- let mut mpis = vec ! [ mpi] ;
1572- let move_paths = & self . move_data . move_paths ;
1573- mpis. extend ( move_paths[ mpi] . parents ( move_paths) . map ( |( mpi, _) | mpi) ) ;
1574-
15751590 for moi in & self . move_data . loc_map [ location] {
15761591 debug ! ( "report_use_of_moved_or_uninitialized: moi={:?}" , moi) ;
15771592 let path = self . move_data . moves [ * moi] . path ;
@@ -1599,33 +1614,70 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15991614 // Because we stop the DFS here, we only highlight `let c = a`,
16001615 // and not `let b = a`. We will of course also report an error at
16011616 // `let c = a` which highlights `let b = a` as the move.
1602- continue ' dfs ;
1617+ return true ;
16031618 }
16041619 }
16051620 }
16061621
16071622 // check for inits
16081623 let mut any_match = false ;
1609- drop_flag_effects:: for_location_inits (
1610- self . infcx . tcx ,
1611- & self . body ,
1612- self . move_data ,
1613- location,
1614- |m| {
1615- if m == mpi {
1616- any_match = true ;
1624+ for ii in & self . move_data . init_loc_map [ location] {
1625+ let init = self . move_data . inits [ * ii] ;
1626+ match init. kind {
1627+ InitKind :: Deep | InitKind :: NonPanicPathOnly => {
1628+ if mpis. contains ( & init. path ) {
1629+ any_match = true ;
1630+ }
16171631 }
1618- } ,
1619- ) ;
1632+ InitKind :: Shallow => {
1633+ if mpi == init. path {
1634+ any_match = true ;
1635+ }
1636+ }
1637+ }
1638+ }
16201639 if any_match {
16211640 reinits. push ( location) ;
1622- continue ' dfs ;
1641+ return true ;
16231642 }
1643+ return false ;
1644+ } ;
16241645
1625- stack. extend ( predecessor_locations ( self . body , location) . map ( |predecessor| {
1626- let back_edge = location. dominates ( predecessor, & self . dominators ) ;
1627- ( predecessor, is_back_edge || back_edge)
1628- } ) ) ;
1646+ while let Some ( location) = stack. pop ( ) {
1647+ if dfs_iter ( & mut result, location, false ) {
1648+ continue ;
1649+ }
1650+
1651+ let mut has_predecessor = false ;
1652+ predecessor_locations ( self . body , location) . for_each ( |predecessor| {
1653+ if location. dominates ( predecessor, & self . dominators ) {
1654+ back_edge_stack. push ( predecessor)
1655+ } else {
1656+ stack. push ( predecessor) ;
1657+ }
1658+ has_predecessor = true ;
1659+ } ) ;
1660+
1661+ if !has_predecessor {
1662+ reached_start = true ;
1663+ }
1664+ }
1665+ if ( is_argument || !reached_start) && result. is_empty ( ) {
1666+ /* Process back edges (moves in future loop iterations) only if
1667+ the move path is definitely initialized upon loop entry,
1668+ to avoid spurious "in previous iteration" errors.
1669+ During DFS, if there's a path from the error back to the start
1670+ of the function with no intervening init or move, then the
1671+ move path may be uninitialized at loop entry.
1672+ */
1673+ while let Some ( location) = back_edge_stack. pop ( ) {
1674+ if dfs_iter ( & mut result, location, true ) {
1675+ continue ;
1676+ }
1677+
1678+ predecessor_locations ( self . body , location)
1679+ . for_each ( |predecessor| back_edge_stack. push ( predecessor) ) ;
1680+ }
16291681 }
16301682
16311683 // Check if we can reach these reinits from a move location.
0 commit comments