@@ -853,6 +853,7 @@ enum InitializationRequiringAction {
853
853
MatchOn ,
854
854
Use ,
855
855
Assignment ,
856
+ PartialAssignment ,
856
857
}
857
858
858
859
struct RootPlace < ' d , ' tcx : ' d > {
@@ -868,6 +869,7 @@ impl InitializationRequiringAction {
868
869
InitializationRequiringAction :: MatchOn => "use" , // no good noun
869
870
InitializationRequiringAction :: Use => "use" ,
870
871
InitializationRequiringAction :: Assignment => "assign" ,
872
+ InitializationRequiringAction :: PartialAssignment => "assign to part" ,
871
873
}
872
874
}
873
875
@@ -878,6 +880,7 @@ impl InitializationRequiringAction {
878
880
InitializationRequiringAction :: MatchOn => "matched on" ,
879
881
InitializationRequiringAction :: Use => "used" ,
880
882
InitializationRequiringAction :: Assignment => "assigned" ,
883
+ InitializationRequiringAction :: PartialAssignment => "partially assigned" ,
881
884
}
882
885
}
883
886
}
@@ -1498,12 +1501,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1498
1501
1499
1502
debug ! ( "check_if_full_path_is_moved place: {:?}" , place_span. 0 ) ;
1500
1503
match self . move_path_closest_to ( place_span. 0 ) {
1501
- Ok ( mpi) => {
1504
+ Ok ( ( prefix , mpi) ) => {
1502
1505
if maybe_uninits. contains ( mpi) {
1503
1506
self . report_use_of_moved_or_uninitialized (
1504
1507
context,
1505
1508
desired_action,
1506
- place_span,
1509
+ ( prefix , place_span. 0 , place_span . 1 ) ,
1507
1510
mpi,
1508
1511
) ;
1509
1512
return ; // don't bother finding other problems.
@@ -1561,7 +1564,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1561
1564
self . report_use_of_moved_or_uninitialized (
1562
1565
context,
1563
1566
desired_action,
1564
- place_span,
1567
+ ( place_span. 0 , place_span . 0 , place_span . 1 ) ,
1565
1568
child_mpi,
1566
1569
) ;
1567
1570
return ; // don't bother finding other problems.
@@ -1579,14 +1582,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1579
1582
/// An Err result includes a tag indicated why the search failed.
1580
1583
/// Currently this can only occur if the place is built off of a
1581
1584
/// static variable, as we do not track those in the MoveData.
1582
- fn move_path_closest_to (
1585
+ fn move_path_closest_to < ' a > (
1583
1586
& mut self ,
1584
- place : & Place < ' tcx > ,
1585
- ) -> Result < MovePathIndex , NoMovePathFound > {
1587
+ place : & ' a Place < ' tcx > ,
1588
+ ) -> Result < ( & ' a Place < ' tcx > , MovePathIndex ) , NoMovePathFound > where ' cx : ' a {
1586
1589
let mut last_prefix = place;
1587
1590
for prefix in self . prefixes ( place, PrefixSet :: All ) {
1588
1591
if let Some ( mpi) = self . move_path_for_place ( prefix) {
1589
- return Ok ( mpi) ;
1592
+ return Ok ( ( prefix , mpi) ) ;
1590
1593
}
1591
1594
last_prefix = prefix;
1592
1595
}
@@ -1667,6 +1670,26 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1667
1670
// recur further)
1668
1671
break ;
1669
1672
}
1673
+
1674
+
1675
+ // Once `let s; s.x = V; read(s.x);`,
1676
+ // is allowed, remove this match arm.
1677
+ ty:: Adt ( ..) | ty:: Tuple ( ..) => {
1678
+ check_parent_of_field ( self , context, base, span, flow_state) ;
1679
+
1680
+ if let Some ( local) = place. base_local ( ) {
1681
+ // rust-lang/rust#21232,
1682
+ // #54499, #54986: during
1683
+ // period where we reject
1684
+ // partial initialization, do
1685
+ // not complain about
1686
+ // unnecessary `mut` on an
1687
+ // attempt to do a partial
1688
+ // initialization.
1689
+ self . used_mut . insert ( local) ;
1690
+ }
1691
+ }
1692
+
1670
1693
_ => { }
1671
1694
}
1672
1695
}
@@ -1677,8 +1700,73 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1677
1700
}
1678
1701
}
1679
1702
}
1680
- }
1681
1703
1704
+ fn check_parent_of_field < ' cx , ' gcx , ' tcx > ( this : & mut MirBorrowckCtxt < ' cx , ' gcx , ' tcx > ,
1705
+ context : Context ,
1706
+ base : & Place < ' tcx > ,
1707
+ span : Span ,
1708
+ flow_state : & Flows < ' cx , ' gcx , ' tcx > )
1709
+ {
1710
+ // rust-lang/rust#21232: Until Rust allows reads from the
1711
+ // initialized parts of partially initialized structs, we
1712
+ // will, starting with the 2018 edition, reject attempts
1713
+ // to write to structs that are not fully initialized.
1714
+ //
1715
+ // In other words, *until* we allow this:
1716
+ //
1717
+ // 1. `let mut s; s.x = Val; read(s.x);`
1718
+ //
1719
+ // we will for now disallow this:
1720
+ //
1721
+ // 2. `let mut s; s.x = Val;`
1722
+ //
1723
+ // and also this:
1724
+ //
1725
+ // 3. `let mut s = ...; drop(s); s.x=Val;`
1726
+ //
1727
+ // This does not use check_if_path_or_subpath_is_moved,
1728
+ // because we want to *allow* reinitializations of fields:
1729
+ // e.g. want to allow
1730
+ //
1731
+ // `let mut s = ...; drop(s.x); s.x=Val;`
1732
+ //
1733
+ // This does not use check_if_full_path_is_moved on
1734
+ // `base`, because that would report an error about the
1735
+ // `base` as a whole, but in this scenario we *really*
1736
+ // want to report an error about the actual thing that was
1737
+ // moved, which may be some prefix of `base`.
1738
+
1739
+ // Shallow so that we'll stop at any dereference; we'll
1740
+ // report errors about issues with such bases elsewhere.
1741
+ let maybe_uninits = & flow_state. uninits ;
1742
+
1743
+ // Find the shortest uninitialized prefix you can reach
1744
+ // without going over a Deref.
1745
+ let mut shortest_uninit_seen = None ;
1746
+ for prefix in this. prefixes ( base, PrefixSet :: Shallow ) {
1747
+ let mpi = match this. move_path_for_place ( prefix) {
1748
+ Some ( mpi) => mpi, None => continue ,
1749
+ } ;
1750
+
1751
+ if maybe_uninits. contains ( mpi) {
1752
+ debug ! ( "check_parent_of_field updating shortest_uninit_seen from {:?} to {:?}" ,
1753
+ shortest_uninit_seen, Some ( ( prefix, mpi) ) ) ;
1754
+ shortest_uninit_seen = Some ( ( prefix, mpi) ) ;
1755
+ } else {
1756
+ debug ! ( "check_parent_of_field {:?} is definitely initialized" , ( prefix, mpi) ) ;
1757
+ }
1758
+ }
1759
+
1760
+ if let Some ( ( prefix, mpi) ) = shortest_uninit_seen {
1761
+ this. report_use_of_moved_or_uninitialized (
1762
+ context,
1763
+ InitializationRequiringAction :: PartialAssignment ,
1764
+ ( prefix, base, span) ,
1765
+ mpi,
1766
+ ) ;
1767
+ }
1768
+ }
1769
+ }
1682
1770
1683
1771
/// Check the permissions for the given place and read or write kind
1684
1772
///
0 commit comments