@@ -1946,6 +1946,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
1946
1946
1947
1947
debug ! ( "check_if_full_path_is_moved place: {:?}" , place_span. 0 ) ;
1948
1948
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
+
1949
1954
if maybe_uninits. contains ( mpi) {
1950
1955
self . report_use_of_moved_or_uninitialized (
1951
1956
location,
@@ -2059,9 +2064,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
2059
2064
2060
2065
debug ! ( "check_if_path_or_subpath_is_moved place: {:?}" , place_span. 0 ) ;
2061
2066
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
+ } ) ;
2065
2070
2066
2071
if let Some ( uninit_mpi) = uninit_mpi {
2067
2072
self . report_use_of_moved_or_uninitialized (
@@ -2075,6 +2080,51 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
2075
2080
}
2076
2081
}
2077
2082
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
+
2078
2128
/// Currently MoveData does not store entries for all places in
2079
2129
/// the input MIR. For example it will currently filter out
2080
2130
/// places that are Copy; thus we do not track places of shared
@@ -2164,7 +2214,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
2164
2214
2165
2215
// Once `let s; s.x = V; read(s.x);`,
2166
2216
// is allowed, remove this match arm.
2167
- ty:: Adt ( ..) | ty:: Tuple ( ..) => {
2217
+ ty:: Adt ( ..) | ty:: Tuple ( ..) if !tcx . features ( ) . structural_init ( ) => {
2168
2218
check_parent_of_field ( self , location, place_base, span, state) ;
2169
2219
}
2170
2220
0 commit comments