Skip to content

Commit 984b65a

Browse files
committed
it works for structs
1 parent 3811ddc commit 984b65a

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
@@ -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

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)