Skip to content

Commit 1301a22

Browse files
dingxiangfei2009ehuss
authored andcommitted
apply some suggestions and add explantory notes
1 parent 4520f68 commit 1301a22

File tree

3 files changed

+49
-19
lines changed

3 files changed

+49
-19
lines changed

compiler/rustc_middle/src/query/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,6 +1453,9 @@ rustc_queries! {
14531453
/// by the user or does anything that will have any observable behavior (other than
14541454
/// freeing up memory). If the type is known to have a significant destructor then
14551455
/// `Err(AlwaysRequiresDrop)` is returned.
1456+
/// *IMPORTANT*: *DO NOT* run this query before promoted MIR body is constructed,
1457+
/// because this query partially depends on that query.
1458+
/// Otherwise, there is a risk of query cycles.
14561459
query list_significant_drop_tys(ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result<&'tcx ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
14571460
desc { |tcx| "computing when `{}` has a significant destructor", ty.value }
14581461
cache_on_disk_if { false }

compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use rustc_index::bit_set::ChunkedBitSet;
1010
use rustc_index::{IndexSlice, IndexVec};
1111
use rustc_macros::LintDiagnostic;
1212
use rustc_middle::mir::{
13-
BasicBlock, Body, ClearCrossCrate, Local, Location, Place, ProjectionElem, StatementKind,
14-
TerminatorKind, dump_mir,
13+
BasicBlock, Body, ClearCrossCrate, Local, Location, Place, StatementKind, TerminatorKind,
14+
dump_mir,
1515
};
1616
use rustc_middle::ty::{self, Ty, TyCtxt};
1717
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
@@ -43,16 +43,27 @@ impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> {
4343
fn visit(&mut self, block: BasicBlock) {
4444
let move_set_size = self.move_data.move_paths.len();
4545
let make_new_path_set = || Rc::new(RefCell::new(ChunkedBitSet::new_empty(move_set_size)));
46+
4647
let data = &self.body.basic_blocks[block];
4748
let Some(terminator) = &data.terminator else { return };
49+
// Given that we observe these dropped locals here at `block` so far,
50+
// we will try to update the successor blocks.
51+
// An occupied entry at `block` in `self.visited` signals that we have visited `block` before.
4852
let dropped_local_here =
4953
self.visited.entry(block).or_insert_with(make_new_path_set).clone();
54+
// We could have invoked reverse lookup for a `MovePathIndex` every time, but unfortunately it is expensive.
55+
// Let's cache them in `self.block_drop_value_info`.
5056
if let Some(dropped) = self.block_drop_value_info[block] {
5157
dropped_local_here.borrow_mut().insert(dropped);
5258
} else if let TerminatorKind::Drop { place, .. } = &terminator.kind
5359
&& let LookupResult::Exact(idx) | LookupResult::Parent(Some(idx)) =
5460
self.move_data.rev_lookup.find(place.as_ref())
5561
{
62+
// Since we are working with MIRs at a very early stage,
63+
// observing a `drop` terminator is not indicative enough that
64+
// the drop will definitely happen.
65+
// That is decided in the drop elaboration pass instead.
66+
// Therefore, we need to consult with the maybe-initialization information.
5667
self.maybe_init.seek_before_primary_effect(Location {
5768
block,
5869
statement_index: data.statements.len(),
@@ -71,10 +82,13 @@ impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> {
7182
continue;
7283
}
7384

74-
// As long as we are passing through a new block, or new dropped place to propagate, we will proceed
85+
// As long as we are passing through a new block, or new dropped places to propagate,
86+
// we will proceed with `succ`
7587
let dropped_local_there = match self.visited.entry(succ) {
7688
hash_map::Entry::Occupied(occupied_entry) => {
7789
if !occupied_entry.get().borrow_mut().union(&*dropped_local_here.borrow()) {
90+
// `succ` has been visited but no new drops observed so far,
91+
// so we can bail on `succ` until new drop information arrives
7892
continue;
7993
}
8094
occupied_entry.get().clone()
@@ -92,8 +106,12 @@ impl<'a, 'mir, 'tcx> DropsReachable<'a, 'mir, 'tcx> {
92106
} = &terminator.kind
93107
&& place_has_common_prefix(dropped_place, self.place)
94108
{
109+
// We have now reached the current drop of the `place`.
110+
// Let's check the observed dropped places in.
95111
self.collected_drops.union(&*dropped_local_there.borrow());
96112
if self.drop_span.is_none() {
113+
// FIXME(@dingxiangfei2009): it turns out that `self.body.source_scopes` are still a bit wonky.
114+
// There is a high chance that this span still points to a block rather than a statement semicolon.
97115
*self.drop_span =
98116
Some(self.body.source_scopes[terminator.source_info.scope].span);
99117
}
@@ -239,6 +257,7 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<
239257
{
240258
return;
241259
}
260+
// ## About BIDs in blocks ##
242261
// We are using blocks to identify locals with the same scope targeted by backwards-incompatible drops (BID)
243262
// because they tend to be scheduled in the same drop ladder block.
244263
let mut bid_per_block = IndexMap::default();
@@ -270,7 +289,7 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<
270289
let mut drop_span = None;
271290
for &(_, place) in candidates.iter() {
272291
let mut collected_drops = ChunkedBitSet::new_empty(move_data.move_paths.len());
273-
let mut search = DropsReachable {
292+
DropsReachable {
274293
body,
275294
place,
276295
drop_span: &mut drop_span,
@@ -279,44 +298,48 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<
279298
block_drop_value_info: &mut block_drop_value_info,
280299
collected_drops: &mut collected_drops,
281300
visited: Default::default(),
282-
};
283-
search.visit(block);
284-
let _ = search;
301+
}
302+
.visit(block);
285303

286304
all_locals_dropped.union(&collected_drops);
287305
}
288306
{
289307
let mut to_exclude = ChunkedBitSet::new_empty(all_locals_dropped.domain_size());
308+
// We will now do subtraction from the candidate dropped locals, because of the following reasons.
290309
for path_idx in all_locals_dropped.iter() {
291310
let move_path = &move_data.move_paths[path_idx];
292311
let dropped_local = move_path.place.local;
312+
// a) A return value _0 will eventually be used
293313
if dropped_local == Local::ZERO {
294314
debug!(?dropped_local, "skip return value");
295315
to_exclude.insert(path_idx);
296316
continue;
297317
}
318+
// b) If we are analysing a closure, the captures are still dropped last.
319+
// This is part of the closure capture lifetime contract.
298320
if is_closure_like && matches!(dropped_local, ty::CAPTURE_STRUCT_LOCAL) {
299321
debug!(?dropped_local, "skip closure captures");
300322
to_exclude.insert(path_idx);
301323
continue;
302324
}
303-
if let [.., ProjectionElem::Downcast(_, _)] = **move_path.place.projection {
304-
debug!(?move_path.place, "skip downcast which is not a real place");
305-
to_exclude.insert(path_idx);
306-
continue;
307-
}
325+
// c) Sometimes we collect places that are projections into the BID locals,
326+
// so they are considered dropped now.
308327
if place_descendent_of_bids(path_idx, &move_data, &bid_places) {
309328
debug!(?dropped_local, "skip descendent of bids");
310329
to_exclude.insert(path_idx);
311330
continue;
312331
}
313332
let observer_ty = move_path.place.ty(body, tcx).ty;
333+
// d) The collect local has no custom destructor.
314334
if !observer_ty.has_significant_drop(tcx, param_env) {
315335
debug!(?dropped_local, "skip non-droppy types");
316336
to_exclude.insert(path_idx);
317337
continue;
318338
}
319339
}
340+
// Suppose that all BIDs point into the same local,
341+
// we can remove the this local from the observed drops,
342+
// so that we can focus our diagnosis more on the others.
320343
if candidates.iter().all(|&(_, place)| candidates[0].1.local == place.local) {
321344
for path_idx in all_locals_dropped.iter() {
322345
if move_data.move_paths[path_idx].place.local == candidates[0].1.local {
@@ -333,24 +356,28 @@ pub(crate) fn run_lint<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &Body<
333356
let mut lint_root = None;
334357
let mut linted_spans = Vec::with_capacity(candidates.len());
335358
let mut tys = Vec::with_capacity(candidates.len());
359+
// We now collect the types with custom destructors.
336360
for &(_, place) in candidates {
337361
let linted_local_decl = &body.local_decls[place.local];
338362
linted_spans.push(linted_local_decl.source_info.span);
339-
if lint_root.is_none() {
340-
lint_root =
341-
match &body.source_scopes[linted_local_decl.source_info.scope].local_data {
342-
ClearCrossCrate::Set(data) => Some(data.lint_root),
343-
_ => continue,
344-
};
363+
364+
if lint_root.is_none()
365+
&& let ClearCrossCrate::Set(data) =
366+
&body.source_scopes[linted_local_decl.source_info.scope].local_data
367+
{
368+
lint_root = Some(data.lint_root);
345369
}
370+
346371
tys.extend(extract_component_with_significant_dtor(
347372
tcx,
348373
param_env,
349374
linted_local_decl.ty,
350375
));
351376
}
377+
// Collect spans of the custom destructors.
352378
let linted_dtors = tys.into_iter().filter_map(|ty| ty_dtor_span(tcx, ty)).collect();
353379

380+
// Similarly, custom destructors of the observed drops.
354381
let mut observer_spans = Vec::with_capacity(all_locals_dropped.count());
355382
let mut observer_tys = Vec::with_capacity(all_locals_dropped.count());
356383
for path_idx in all_locals_dropped.iter() {

compiler/rustc_ty_utils/src/needs_drop.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> {
113113
Self {
114114
tcx,
115115
param_env,
116-
reveal_coroutine_witnesses: false,
116+
reveal_coroutine_witnesses: exhaustive,
117117
seen_tys,
118118
query_ty: ty,
119119
unchecked_tys: vec![(ty, 0)],

0 commit comments

Comments
 (0)