@@ -10,8 +10,7 @@ use rustc_middle::mir::{
10
10
ProjectionElem , Rvalue , Statement , StatementKind , Terminator , TerminatorKind , VarBindingForm ,
11
11
} ;
12
12
use 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 } ;
15
14
use rustc_span:: source_map:: DesugaringKind ;
16
15
use rustc_span:: symbol:: sym;
17
16
use rustc_span:: { BytePos , MultiSpan , Span , DUMMY_SP } ;
@@ -1531,25 +1530,45 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1531
1530
}
1532
1531
}
1533
1532
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
+
1534
1537
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
+ }
1539
1558
1540
1559
let mut visited = FxHashSet :: default ( ) ;
1541
1560
let mut move_locations = FxHashSet :: default ( ) ;
1542
1561
let mut reinits = vec ! [ ] ;
1543
1562
let mut result = vec ! [ ] ;
1544
1563
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 | {
1546
1565
debug ! (
1547
1566
"report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})" ,
1548
1567
location, is_back_edge
1549
1568
) ;
1550
1569
1551
1570
if !visited. insert ( location) {
1552
- continue ;
1571
+ return true ;
1553
1572
}
1554
1573
1555
1574
// check for moves
@@ -1568,10 +1587,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1568
1587
// worry about the other case: that is, if there is a move of a.b.c, it is already
1569
1588
// marked as a move of a.b and a as well, so we will generate the correct errors
1570
1589
// 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
-
1575
1590
for moi in & self . move_data . loc_map [ location] {
1576
1591
debug ! ( "report_use_of_moved_or_uninitialized: moi={:?}" , moi) ;
1577
1592
let path = self . move_data . moves [ * moi] . path ;
@@ -1599,33 +1614,70 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1599
1614
// Because we stop the DFS here, we only highlight `let c = a`,
1600
1615
// and not `let b = a`. We will of course also report an error at
1601
1616
// `let c = a` which highlights `let b = a` as the move.
1602
- continue ' dfs ;
1617
+ return true ;
1603
1618
}
1604
1619
}
1605
1620
}
1606
1621
1607
1622
// check for inits
1608
1623
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
+ }
1617
1631
}
1618
- } ,
1619
- ) ;
1632
+ InitKind :: Shallow => {
1633
+ if mpi == init. path {
1634
+ any_match = true ;
1635
+ }
1636
+ }
1637
+ }
1638
+ }
1620
1639
if any_match {
1621
1640
reinits. push ( location) ;
1622
- continue ' dfs ;
1641
+ return true ;
1623
1642
}
1643
+ return false ;
1644
+ } ;
1624
1645
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
+ }
1629
1681
}
1630
1682
1631
1683
// Check if we can reach these reinits from a move location.
0 commit comments