@@ -1966,6 +1966,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1966
1966
1967
1967
debug ! ( "check_if_full_path_is_moved place: {:?}" , place_span. 0 ) ;
1968
1968
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
+
1969
1974
if maybe_uninits. contains ( mpi) {
1970
1975
self . report_use_of_moved_or_uninitialized (
1971
1976
location,
@@ -2079,9 +2084,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
2079
2084
2080
2085
debug ! ( "check_if_path_or_subpath_is_moved place: {:?}" , place_span. 0 ) ;
2081
2086
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
+ } ) ;
2085
2090
2086
2091
if let Some ( uninit_mpi) = uninit_mpi {
2087
2092
self . report_use_of_moved_or_uninitialized (
@@ -2095,6 +2100,51 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
2095
2100
}
2096
2101
}
2097
2102
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
+
2098
2148
/// Currently MoveData does not store entries for all places in
2099
2149
/// the input MIR. For example it will currently filter out
2100
2150
/// places that are Copy; thus we do not track places of shared
@@ -2184,7 +2234,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
2184
2234
2185
2235
// Once `let s; s.x = V; read(s.x);`,
2186
2236
// is allowed, remove this match arm.
2187
- ty:: Adt ( ..) | ty:: Tuple ( ..) => {
2237
+ ty:: Adt ( ..) | ty:: Tuple ( ..) if !tcx . features ( ) . structural_init ( ) => {
2188
2238
check_parent_of_field ( self , location, place_base, span, state) ;
2189
2239
}
2190
2240
0 commit comments