@@ -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 } ;
@@ -1516,25 +1515,45 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1516
1515
}
1517
1516
}
1518
1517
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
+
1519
1522
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
+ }
1524
1543
1525
1544
let mut visited = FxHashSet :: default ( ) ;
1526
1545
let mut move_locations = FxHashSet :: default ( ) ;
1527
1546
let mut reinits = vec ! [ ] ;
1528
1547
let mut result = vec ! [ ] ;
1529
1548
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 | {
1531
1550
debug ! (
1532
1551
"report_use_of_moved_or_uninitialized: (current_location={:?}, back_edge={})" ,
1533
1552
location, is_back_edge
1534
1553
) ;
1535
1554
1536
1555
if !visited. insert ( location) {
1537
- continue ;
1556
+ return true ;
1538
1557
}
1539
1558
1540
1559
// check for moves
@@ -1553,10 +1572,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1553
1572
// worry about the other case: that is, if there is a move of a.b.c, it is already
1554
1573
// marked as a move of a.b and a as well, so we will generate the correct errors
1555
1574
// 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
-
1560
1575
for moi in & self . move_data . loc_map [ location] {
1561
1576
debug ! ( "report_use_of_moved_or_uninitialized: moi={:?}" , moi) ;
1562
1577
let path = self . move_data . moves [ * moi] . path ;
@@ -1584,33 +1599,70 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
1584
1599
// Because we stop the DFS here, we only highlight `let c = a`,
1585
1600
// and not `let b = a`. We will of course also report an error at
1586
1601
// `let c = a` which highlights `let b = a` as the move.
1587
- continue ' dfs ;
1602
+ return true ;
1588
1603
}
1589
1604
}
1590
1605
}
1591
1606
1592
1607
// check for inits
1593
1608
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
+ }
1602
1616
}
1603
- } ,
1604
- ) ;
1617
+ InitKind :: Shallow => {
1618
+ if mpi == init. path {
1619
+ any_match = true ;
1620
+ }
1621
+ }
1622
+ }
1623
+ }
1605
1624
if any_match {
1606
1625
reinits. push ( location) ;
1607
- continue ' dfs ;
1626
+ return true ;
1608
1627
}
1628
+ return false ;
1629
+ } ;
1609
1630
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
+ }
1614
1666
}
1615
1667
1616
1668
// Check if we can reach these reinits from a move location.
0 commit comments