Skip to content

Commit 8f09388

Browse files
handle partial moves from other BIDs
1 parent 0c227e9 commit 8f09388

File tree

1 file changed

+37
-9
lines changed

1 file changed

+37
-9
lines changed

compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs

+37-9
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,22 @@ use rustc_hir::def_id::{DefId, LocalDefId};
44
use rustc_index::bit_set::BitSet;
55
use rustc_macros::LintDiagnostic;
66
use rustc_middle::mir::{
7-
BasicBlock, Body, ClearCrossCrate, Local, Location, Place, StatementKind, TerminatorKind,
7+
BasicBlock, Body, ClearCrossCrate, Local, Location, Place, ProjectionElem, StatementKind,
8+
TerminatorKind, dump_mir,
89
};
910
use rustc_middle::ty::{self, Ty, TyCtxt};
1011
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
11-
use rustc_mir_dataflow::move_paths::MoveData;
12+
use rustc_mir_dataflow::move_paths::{MoveData, MovePathIndex};
1213
use rustc_mir_dataflow::{Analysis, MaybeReachable};
1314
use rustc_session::lint;
1415
use rustc_span::Span;
1516
use tracing::debug;
1617

18+
fn place_has_common_prefix<'tcx>(left: &Place<'tcx>, right: &Place<'tcx>) -> bool {
19+
left.local == right.local
20+
&& left.projection.iter().zip(right.projection).all(|(left, right)| left == right)
21+
}
22+
1723
fn drops_reachable_from_location<'tcx>(
1824
body: &Body<'tcx>,
1925
block: BasicBlock,
@@ -42,12 +48,7 @@ fn drops_reachable_from_location<'tcx>(
4248
unwind: _,
4349
replace: _,
4450
} = &terminator.kind
45-
&& dropped_place.local == place.local
46-
&& dropped_place
47-
.projection
48-
.iter()
49-
.zip(place.projection)
50-
.all(|(dropped, linted)| dropped == linted)
51+
&& place_has_common_prefix(dropped_place, place)
5152
{
5253
reachable.insert(succ);
5354
// Now we have discovered a simple control flow path from a future drop point
@@ -114,6 +115,24 @@ fn extract_component_with_significant_dtor<'tcx>(
114115
(ty_names, ty_spans)
115116
}
116117

118+
fn place_descendent_of_bids<'tcx>(
119+
mut idx: MovePathIndex,
120+
move_data: &MoveData<'tcx>,
121+
bids: &UnordSet<&Place<'tcx>>,
122+
) -> bool {
123+
loop {
124+
let path = &move_data.move_paths[idx];
125+
if bids.contains(&path.place) {
126+
return true;
127+
}
128+
if let Some(parent) = path.parent {
129+
idx = parent;
130+
} else {
131+
return false;
132+
}
133+
}
134+
}
135+
117136
pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<'tcx>) {
118137
if matches!(tcx.def_kind(def_id), rustc_hir::def::DefKind::SyntheticCoroutineBody) {
119138
// A synthetic coroutine has no HIR body and it is enough to just analyse the original body
@@ -144,6 +163,7 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<
144163
return;
145164
}
146165

166+
dump_mir(tcx, false, "lint_tail_expr_drop_order", &0 as _, body, |_, _| Ok(()));
147167
let param_env = tcx.param_env(def_id);
148168
let is_closure_like = tcx.is_closure_like(def_id.to_def_id());
149169
let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
@@ -153,19 +173,27 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<
153173
for &(candidate, place) in &backwards_incompatible_drops {
154174
maybe_init.seek_after_primary_effect(candidate);
155175
let MaybeReachable::Reachable(maybe_init_in_future) = maybe_init.get() else { continue };
176+
debug!(maybe_init_in_future = ?maybe_init_in_future.iter().map(|idx| &move_data.move_paths[idx]).collect::<Vec<_>>());
156177
let maybe_init_in_future = maybe_init_in_future.clone();
157178
for block in drops_reachable_from_location(body, candidate.block, place).iter() {
158179
let data = &body.basic_blocks[block];
180+
debug!(?candidate, ?block, "inspect");
159181
maybe_init.seek_before_primary_effect(Location {
160182
block,
161183
statement_index: data.statements.len(),
162184
});
163185
let MaybeReachable::Reachable(maybe_init_now) = maybe_init.get() else { continue };
164186
let mut locals_dropped = maybe_init_in_future.clone();
187+
debug!(maybe_init_now = ?maybe_init_now.iter().map(|idx| &move_data.move_paths[idx]).collect::<Vec<_>>());
165188
locals_dropped.subtract(maybe_init_now);
189+
debug!(locals_dropped = ?locals_dropped.iter().map(|idx| &move_data.move_paths[idx]).collect::<Vec<_>>());
166190
for path_idx in locals_dropped.iter() {
167191
let move_path = &move_data.move_paths[path_idx];
168-
if bid_places.contains(&move_path.place) {
192+
if let [.., ProjectionElem::Downcast(_, _)] = **move_path.place.projection {
193+
debug!(?move_path.place, "skip downcast which is not a real place");
194+
continue;
195+
}
196+
if place_descendent_of_bids(path_idx, &move_data, &bid_places) {
169197
continue;
170198
}
171199
let dropped_local = move_path.place.local;

0 commit comments

Comments
 (0)