Skip to content

Commit e7f328e

Browse files
committed
Handle recursive case of dropping structs with field accesses when struct has no dtor.
1 parent 6493ab6 commit e7f328e

File tree

1 file changed

+71
-48
lines changed
  • src/librustc_mir/borrow_check

1 file changed

+71
-48
lines changed

src/librustc_mir/borrow_check/mod.rs

+71-48
Original file line numberDiff line numberDiff line change
@@ -463,13 +463,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
463463
target: _,
464464
unwind: _,
465465
} => {
466-
self.access_place(
467-
ContextKind::Drop.new(loc),
468-
(drop_place, span),
469-
(Deep, Write(WriteKind::StorageDeadOrDrop)),
470-
LocalMutationIsAllowed::Yes,
471-
flow_state,
472-
);
466+
self.visit_terminator_drop(loc, term, flow_state, drop_place, span);
473467
}
474468
TerminatorKind::DropAndReplace {
475469
location: ref drop_place,
@@ -717,6 +711,65 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
717711
self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
718712
}
719713

714+
fn visit_terminator_drop(
715+
&mut self,
716+
loc: Location,
717+
term: &Terminator<'tcx>,
718+
flow_state: &Flows<'cx, 'gcx, 'tcx>,
719+
drop_place: &Place<'tcx>,
720+
span: Span,
721+
) {
722+
let ty = drop_place.ty(self.mir, self.tcx).to_ty(self.tcx);
723+
match ty.sty {
724+
// When a struct is being dropped, we need to check whether it has a
725+
// destructor, if it does, then we can call it, if it does not then we
726+
// need to check the individual fields instead.
727+
// See #47703.
728+
ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => {
729+
for (index, field) in def.all_fields().enumerate() {
730+
let field_ty = field.ty(self.tcx, substs);
731+
let proj = Projection {
732+
base: drop_place.clone(),
733+
elem: ProjectionElem::Field(Field::new(index), field_ty),
734+
};
735+
let place = Place::Projection(Box::new(proj));
736+
737+
match field_ty.sty {
738+
// It may be the case that this issue occurs with a struct within a
739+
// struct, so we recurse to handle that.
740+
ty::TyAdt(def, _) if def.is_struct() && !def.has_dtor(self.tcx) => {
741+
self.visit_terminator_drop(
742+
loc,
743+
term,
744+
flow_state,
745+
&place,
746+
span,
747+
);
748+
},
749+
_ => {
750+
self.access_place(
751+
ContextKind::Drop.new(loc),
752+
(&place, span),
753+
(Shallow(None), Write(WriteKind::StorageDeadOrDrop)),
754+
LocalMutationIsAllowed::Yes,
755+
flow_state,
756+
);
757+
},
758+
}
759+
}
760+
},
761+
_ => {
762+
self.access_place(
763+
ContextKind::Drop.new(loc),
764+
(drop_place, span),
765+
(Deep, Write(WriteKind::StorageDeadOrDrop)),
766+
LocalMutationIsAllowed::Yes,
767+
flow_state,
768+
);
769+
},
770+
}
771+
}
772+
720773
/// Checks an access to the given place to see if it is allowed. Examines the set of borrows
721774
/// that are in scope, as well as which paths have been initialized, to ensure that (a) the
722775
/// place is initialized and (b) it is not borrowed in some way that would prevent this
@@ -2073,7 +2126,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
20732126
/// currently in, when such distinction matters.
20742127
fn each_borrow_involving_path<F>(
20752128
&mut self,
2076-
context: Context,
2129+
_context: Context,
20772130
access_place: (ShallowOrDeep, &Place<'tcx>),
20782131
flow_state: &Flows<'cx, 'gcx, 'tcx>,
20792132
mut op: F,
@@ -2085,50 +2138,20 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
20852138
// FIXME: analogous code in check_loans first maps `place` to
20862139
// its base_path.
20872140

2088-
// When this function is called as a result of an `access_terminator` call attempting
2089-
// to drop a struct, if that struct does not have a destructor, then we need to check
2090-
// each of the fields in the struct. See #47703.
2091-
let (access, places) = if let ContextKind::Drop = context.kind {
2092-
let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx);
2093-
2094-
match ty.sty {
2095-
ty::TyAdt(def, substs) if def.is_struct() && !def.has_dtor(self.tcx) => {
2096-
let mut places = Vec::new();
2097-
2098-
for (index, field) in def.all_fields().enumerate() {
2099-
let proj = Projection {
2100-
base: place.clone(),
2101-
elem: ProjectionElem::Field(Field::new(index),
2102-
field.ty(self.tcx, substs)),
2103-
};
2104-
2105-
places.push(Place::Projection(Box::new(proj)));
2106-
}
2107-
2108-
(ShallowOrDeep::Shallow(None), places)
2109-
},
2110-
_ => (access, vec![ place.clone() ]),
2111-
}
2112-
} else {
2113-
(access, vec![ place.clone() ])
2114-
};
2115-
21162141
let data = flow_state.borrows.operator().borrows();
21172142

21182143
// check for loan restricting path P being used. Accounts for
21192144
// borrows of P, P.a.b, etc.
2120-
for place in places {
2121-
let mut elems_incoming = flow_state.borrows.elems_incoming();
2122-
while let Some(i) = elems_incoming.next() {
2123-
let borrowed = &data[i.borrow_index()];
2124-
2125-
if self.places_conflict(&borrowed.borrowed_place, &place, access) {
2126-
debug!("each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
2127-
i, borrowed, place, access);
2128-
let ctrl = op(self, i, borrowed);
2129-
if ctrl == Control::Break {
2130-
return;
2131-
}
2145+
let mut elems_incoming = flow_state.borrows.elems_incoming();
2146+
while let Some(i) = elems_incoming.next() {
2147+
let borrowed = &data[i.borrow_index()];
2148+
2149+
if self.places_conflict(&borrowed.borrowed_place, &place, access) {
2150+
debug!("each_borrow_involving_path: {:?} @ {:?} vs. {:?}/{:?}",
2151+
i, borrowed, place, access);
2152+
let ctrl = op(self, i, borrowed);
2153+
if ctrl == Control::Break {
2154+
return;
21322155
}
21332156
}
21342157
}

0 commit comments

Comments
 (0)