@@ -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 } ;
@@ -1516,25 +1515,45 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15161515 }
15171516 }
15181517
1518+ let mut mpis = vec ! [ mpi] ;
1519+ let move_paths = & self . move_data . move_paths ;
1520+ mpis. extend ( move_paths[ mpi] . parents ( move_paths) . map ( |( mpi, _) | mpi) ) ;
1521+
15191522 let mut stack = Vec :: new ( ) ;
1520- stack. extend ( predecessor_locations ( self . body , location) . map ( |predecessor| {
1521- let is_back_edge = location. dominates ( predecessor, & self . dominators ) ;
1522- ( predecessor, is_back_edge)
1523- } ) ) ;
1523+ let mut back_edge_stack = Vec :: new ( ) ;
1524+
1525+ predecessor_locations ( self . body , location) . for_each ( |predecessor| {
1526+ if location. dominates ( predecessor, & self . dominators ) {
1527+ back_edge_stack. push ( predecessor)
1528+ } else {
1529+ stack. push ( predecessor) ;
1530+ }
1531+ } ) ;
1532+
1533+ let mut reached_start = false ;
1534+
1535+ /* Check if the mpi is initialized as an argument */
1536+ let mut is_argument = false ;
1537+ for arg in self . body . args_iter ( ) {
1538+ let path = self . move_data . rev_lookup . find_local ( arg) ;
1539+ if mpis. contains ( & path) {
1540+ is_argument = true ;
1541+ }
1542+ }
15241543
15251544 let mut visited = FxHashSet :: default ( ) ;
15261545 let mut move_locations = FxHashSet :: default ( ) ;
15271546 let mut reinits = vec ! [ ] ;
15281547 let mut result = vec ! [ ] ;
15291548
1530- ' dfs : while let Some ( ( location, is_back_edge) ) = stack . pop ( ) {
1549+ let mut dfs_iter = | result : & mut Vec < MoveSite > , location : Location , is_back_edge : bool | {
15311550 debug ! (
15321551 "report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})" ,
15331552 location, is_back_edge
15341553 ) ;
15351554
15361555 if !visited. insert ( location) {
1537- continue ;
1556+ return true ;
15381557 }
15391558
15401559 // check for moves
@@ -1553,10 +1572,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15531572 // worry about the other case: that is, if there is a move of a.b.c, it is already
15541573 // marked as a move of a.b and a as well, so we will generate the correct errors
15551574 // there.
1556- let mut mpis = vec ! [ mpi] ;
1557- let move_paths = & self . move_data . move_paths ;
1558- mpis. extend ( move_paths[ mpi] . parents ( move_paths) . map ( |( mpi, _) | mpi) ) ;
1559-
15601575 for moi in & self . move_data . loc_map [ location] {
15611576 debug ! ( "report_use_of_moved_or_uninitialized: moi={:?}" , moi) ;
15621577 let path = self . move_data . moves [ * moi] . path ;
@@ -1584,33 +1599,70 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15841599 // Because we stop the DFS here, we only highlight `let c = a`,
15851600 // and not `let b = a`. We will of course also report an error at
15861601 // `let c = a` which highlights `let b = a` as the move.
1587- continue ' dfs ;
1602+ return true ;
15881603 }
15891604 }
15901605 }
15911606
15921607 // check for inits
15931608 let mut any_match = false ;
1594- drop_flag_effects:: for_location_inits (
1595- self . infcx . tcx ,
1596- & self . body ,
1597- self . move_data ,
1598- location,
1599- |m| {
1600- if m == mpi {
1601- any_match = true ;
1609+ for ii in & self . move_data . init_loc_map [ location] {
1610+ let init = self . move_data . inits [ * ii] ;
1611+ match init. kind {
1612+ InitKind :: Deep | InitKind :: NonPanicPathOnly => {
1613+ if mpis. contains ( & init. path ) {
1614+ any_match = true ;
1615+ }
16021616 }
1603- } ,
1604- ) ;
1617+ InitKind :: Shallow => {
1618+ if mpi == init. path {
1619+ any_match = true ;
1620+ }
1621+ }
1622+ }
1623+ }
16051624 if any_match {
16061625 reinits. push ( location) ;
1607- continue ' dfs ;
1626+ return true ;
16081627 }
1628+ return false ;
1629+ } ;
16091630
1610- stack. extend ( predecessor_locations ( self . body , location) . map ( |predecessor| {
1611- let back_edge = location. dominates ( predecessor, & self . dominators ) ;
1612- ( predecessor, is_back_edge || back_edge)
1613- } ) ) ;
1631+ while let Some ( location) = stack. pop ( ) {
1632+ if dfs_iter ( & mut result, location, false ) {
1633+ continue ;
1634+ }
1635+
1636+ let mut has_predecessor = false ;
1637+ predecessor_locations ( self . body , location) . for_each ( |predecessor| {
1638+ if location. dominates ( predecessor, & self . dominators ) {
1639+ back_edge_stack. push ( predecessor)
1640+ } else {
1641+ stack. push ( predecessor) ;
1642+ }
1643+ has_predecessor = true ;
1644+ } ) ;
1645+
1646+ if !has_predecessor {
1647+ reached_start = true ;
1648+ }
1649+ }
1650+ if ( is_argument || !reached_start) && result. is_empty ( ) {
1651+ /* Process back edges (moves in future loop iterations) only if
1652+ the move path is definitely initialized upon loop entry,
1653+ to avoid spurious "in previous iteration" errors.
1654+ During DFS, if there's a path from the error back to the start
1655+ of the function with no intervening init or move, then the
1656+ move path may be uninitialized at loop entry.
1657+ */
1658+ while let Some ( location) = back_edge_stack. pop ( ) {
1659+ if dfs_iter ( & mut result, location, true ) {
1660+ continue ;
1661+ }
1662+
1663+ predecessor_locations ( self . body , location)
1664+ . for_each ( |predecessor| back_edge_stack. push ( predecessor) ) ;
1665+ }
16141666 }
16151667
16161668 // Check if we can reach these reinits from a move location.
0 commit comments