Skip to content

Commit beec7f3

Browse files
committed
it works for structs
1 parent 7864983 commit beec7f3

File tree

2 files changed

+59
-5
lines changed
  • compiler
    • rustc_borrowck/src
    • rustc_mir_dataflow/src/move_paths

2 files changed

+59
-5
lines changed

compiler/rustc_borrowck/src/lib.rs

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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

compiler/rustc_mir_dataflow/src/move_paths/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ impl<'tcx> MovePathLookup<'tcx> {
324324
};
325325

326326
for (_, elem) in self.un_derefer.iter_projections(place) {
327-
if let Some(&subpath) = self.projections.get(&(result, elem.lift())) {
327+
if let Some(subpath) = self.project(result, elem.lift()) {
328328
result = subpath;
329329
} else {
330330
return LookupResult::Parent(Some(result));
@@ -346,6 +346,10 @@ impl<'tcx> MovePathLookup<'tcx> {
346346
) -> impl DoubleEndedIterator<Item = (Local, MovePathIndex)> {
347347
self.locals.iter_enumerated().filter_map(|(l, &idx)| Some((l, idx?)))
348348
}
349+
350+
pub fn project(&self, mpi: MovePathIndex, elem: ProjectionKind) -> Option<MovePathIndex> {
351+
self.projections.get(&(mpi, elem)).copied()
352+
}
349353
}
350354

351355
impl<'tcx> MoveData<'tcx> {

0 commit comments

Comments
 (0)