@@ -1966,6 +1966,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
19661966
19671967 debug ! ( "check_if_full_path_is_moved place: {:?}" , place_span. 0 ) ;
19681968 let ( prefix, mpi) = self . move_path_closest_to ( place_span. 0 ) ;
1969+
1970+ if prefix == place_span. 0 && !self . forbid_structural_initialization ( mpi) {
1971+ return ;
1972+ }
1973+
19691974 if maybe_uninits. contains ( mpi) {
19701975 self . report_use_of_moved_or_uninitialized (
19711976 location,
@@ -2079,9 +2084,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
20792084
20802085 debug ! ( "check_if_path_or_subpath_is_moved place: {:?}" , place_span. 0 ) ;
20812086 if let Some ( mpi) = self . move_path_for_place ( place_span. 0 ) {
2082- let uninit_mpi = self
2083- . move_data
2084- . find_in_move_path_or_its_descendants ( mpi , |mpi| maybe_uninits . contains ( mpi ) ) ;
2087+ let uninit_mpi = self . move_data . find_in_move_path_or_its_descendants ( mpi , |mpi| {
2088+ maybe_uninits . contains ( mpi ) && self . forbid_structural_initialization ( mpi )
2089+ } ) ;
20852090
20862091 if let Some ( uninit_mpi) = uninit_mpi {
20872092 self . report_use_of_moved_or_uninitialized (
@@ -2095,6 +2100,51 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
20952100 }
20962101 }
20972102
2103+ fn forbid_structural_initialization ( & self , mpi : MovePathIndex ) -> bool {
2104+ // FIXME: cache this
2105+
2106+ let tcx = self . infcx . tcx ;
2107+
2108+ if !tcx. features ( ) . structural_init ( ) {
2109+ return true ;
2110+ }
2111+
2112+ let path = & self . move_data . move_paths [ mpi] ;
2113+
2114+ let ty = path. place . ty ( self . body ( ) , tcx) . ty ;
2115+
2116+ let ty:: Adt ( adt, _) = ty. kind ( ) else {
2117+ return true ;
2118+ } ;
2119+
2120+ if !adt. is_struct ( ) {
2121+ return true ;
2122+ }
2123+
2124+ let variant = adt. non_enum_variant ( ) ;
2125+
2126+ if variant. field_list_has_applicable_non_exhaustive ( ) {
2127+ return true ;
2128+ }
2129+
2130+ // FIXME: destructors?
2131+
2132+ // A structurally initialized ADT is "uninit" but all of it's fields are init.
2133+ // This means all of it's fields must have MovePaths
2134+ // because fields that are never written to will not have MovePaths.
2135+ // Without this check, we may not detect that unwritten fields are uninit.
2136+ for field in variant. fields . indices ( ) {
2137+ // FIXME WrapUnsafeBinder?
2138+ if self . move_data . rev_lookup . project ( mpi, ProjectionElem :: Field ( field, ( ) ) ) . is_none ( ) {
2139+ return true ;
2140+ }
2141+ }
2142+
2143+ debug ! ( "sucess!!" ) ;
2144+
2145+ false
2146+ }
2147+
20982148 /// Currently MoveData does not store entries for all places in
20992149 /// the input MIR. For example it will currently filter out
21002150 /// places that are Copy; thus we do not track places of shared
@@ -2184,7 +2234,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
21842234
21852235 // Once `let s; s.x = V; read(s.x);`,
21862236 // is allowed, remove this match arm.
2187- ty:: Adt ( ..) | ty:: Tuple ( ..) => {
2237+ ty:: Adt ( ..) | ty:: Tuple ( ..) if !tcx . features ( ) . structural_init ( ) => {
21882238 check_parent_of_field ( self , location, place_base, span, state) ;
21892239 }
21902240
0 commit comments