@@ -1946,6 +1946,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
19461946
19471947 debug ! ( "check_if_full_path_is_moved place: {:?}" , place_span. 0 ) ;
19481948 let ( prefix, mpi) = self . move_path_closest_to ( place_span. 0 ) ;
1949+
1950+ if prefix == place_span. 0 && !self . forbid_structural_initialization ( mpi) {
1951+ return ;
1952+ }
1953+
19491954 if maybe_uninits. contains ( mpi) {
19501955 self . report_use_of_moved_or_uninitialized (
19511956 location,
@@ -2059,9 +2064,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
20592064
20602065 debug ! ( "check_if_path_or_subpath_is_moved place: {:?}" , place_span. 0 ) ;
20612066 if let Some ( mpi) = self . move_path_for_place ( place_span. 0 ) {
2062- let uninit_mpi = self
2063- . move_data
2064- . find_in_move_path_or_its_descendants ( mpi , |mpi| maybe_uninits . contains ( mpi ) ) ;
2067+ let uninit_mpi = self . move_data . find_in_move_path_or_its_descendants ( mpi , |mpi| {
2068+ maybe_uninits . contains ( mpi ) && self . forbid_structural_initialization ( mpi )
2069+ } ) ;
20652070
20662071 if let Some ( uninit_mpi) = uninit_mpi {
20672072 self . report_use_of_moved_or_uninitialized (
@@ -2075,6 +2080,51 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
20752080 }
20762081 }
20772082
2083+ fn forbid_structural_initialization ( & self , mpi : MovePathIndex ) -> bool {
2084+ // FIXME: cache this
2085+
2086+ let tcx = self . infcx . tcx ;
2087+
2088+ if !tcx. features ( ) . structural_init ( ) {
2089+ return true ;
2090+ }
2091+
2092+ let path = & self . move_data . move_paths [ mpi] ;
2093+
2094+ let ty = path. place . ty ( self . body ( ) , tcx) . ty ;
2095+
2096+ let ty:: Adt ( adt, _) = ty. kind ( ) else {
2097+ return true ;
2098+ } ;
2099+
2100+ if !adt. is_struct ( ) {
2101+ return true ;
2102+ }
2103+
2104+ let variant = adt. non_enum_variant ( ) ;
2105+
2106+ if variant. field_list_has_applicable_non_exhaustive ( ) {
2107+ return true ;
2108+ }
2109+
2110+ // FIXME: destructors?
2111+
2112+ // A structurally initialized ADT is "uninit" but all of it's fields are init.
2113+ // This means all of it's fields must have MovePaths
2114+ // because fields that are never written to will not have MovePaths.
2115+ // Without this check, we may not detect that unwritten fields are uninit.
2116+ for field in variant. fields . indices ( ) {
2117+ // FIXME WrapUnsafeBinder?
2118+ if self . move_data . rev_lookup . project ( mpi, ProjectionElem :: Field ( field, ( ) ) ) . is_none ( ) {
2119+ return true ;
2120+ }
2121+ }
2122+
2123+ debug ! ( "sucess!!" ) ;
2124+
2125+ false
2126+ }
2127+
20782128 /// Currently MoveData does not store entries for all places in
20792129 /// the input MIR. For example it will currently filter out
20802130 /// places that are Copy; thus we do not track places of shared
@@ -2164,7 +2214,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
21642214
21652215 // Once `let s; s.x = V; read(s.x);`,
21662216 // is allowed, remove this match arm.
2167- ty:: Adt ( ..) | ty:: Tuple ( ..) => {
2217+ ty:: Adt ( ..) | ty:: Tuple ( ..) if !tcx . features ( ) . structural_init ( ) => {
21682218 check_parent_of_field ( self , location, place_base, span, state) ;
21692219 }
21702220
0 commit comments