Skip to content

Commit 3d79cbc

Browse files
authored
Rollup merge of #106699 - eholk:await-chains-drop-tracking, r=wesleywiser
[drop tracking] Visit break expressions This fixes #102383 by remembering to visit the expression in `break expr` when building the drop tracking CFG. Missing this step was causing an off-by-one error which meant after a number of awaits we'd be looking for dropped values at the wrong point in the code. Additionally, this changes the order of traversal for assignment expressions to visit the rhs and then the lhs. This matches what is done elsewhere. Finally, this improves some of the debugging output (for example, the CFG visualizer) to make it easier to figure out these sorts of issues.
2 parents 51d50ea + d32f3fe commit 3d79cbc

File tree

4 files changed

+61
-12
lines changed

4 files changed

+61
-12
lines changed

compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
304304
let mut reinit = None;
305305
match expr.kind {
306306
ExprKind::Assign(lhs, rhs, _) => {
307-
self.visit_expr(lhs);
308307
self.visit_expr(rhs);
308+
self.visit_expr(lhs);
309309

310310
reinit = Some(lhs);
311311
}
@@ -433,7 +433,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
433433
self.drop_ranges.add_control_edge(self.expr_index, *target)
434434
}),
435435

436-
ExprKind::Break(destination, ..) => {
436+
ExprKind::Break(destination, value) => {
437437
// destination either points to an expression or to a block. We use
438438
// find_target_expression_from_destination to use the last expression of the block
439439
// if destination points to a block.
@@ -443,7 +443,11 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
443443
// will refer to the end of the block due to the post order traversal.
444444
self.find_target_expression_from_destination(destination).map_or((), |target| {
445445
self.drop_ranges.add_control_edge_hir_id(self.expr_index, target)
446-
})
446+
});
447+
448+
if let Some(value) = value {
449+
self.visit_expr(value);
450+
}
447451
}
448452

449453
ExprKind::Call(f, args) => {
@@ -465,6 +469,12 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
465469

466470
ExprKind::AddrOf(..)
467471
| ExprKind::Array(..)
472+
// FIXME(eholk): We probably need special handling for AssignOps. The ScopeTree builder
473+
// in region.rs runs both lhs then rhs and rhs then lhs and then sets all yields to be
474+
// the latest they show up in either traversal. With the older scope-based
475+
// approximation, this was fine, but it's probably not right now. What we probably want
476+
// to do instead is still run both orders, but consider anything that showed up as a
477+
// yield in either order.
468478
| ExprKind::AssignOp(..)
469479
| ExprKind::Binary(..)
470480
| ExprKind::Block(..)
@@ -502,6 +512,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
502512

503513
// Increment expr_count here to match what InteriorVisitor expects.
504514
self.expr_index = self.expr_index + 1;
515+
516+
// Save a node mapping to get better CFG visualization
517+
self.drop_ranges.add_node_mapping(pat.hir_id, self.expr_index);
505518
}
506519
}
507520

@@ -521,7 +534,7 @@ impl DropRangesBuilder {
521534
}
522535
});
523536
}
524-
debug!("hir_id_map: {:?}", tracked_value_map);
537+
debug!("hir_id_map: {:#?}", tracked_value_map);
525538
let num_values = tracked_value_map.len();
526539
Self {
527540
tracked_value_map,

compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_visualize.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//! flow graph when needed for debugging.
33
44
use rustc_graphviz as dot;
5+
use rustc_hir::{Expr, ExprKind, Node};
56
use rustc_middle::ty::TyCtxt;
67

78
use super::{DropRangesBuilder, PostOrderId};
@@ -80,10 +81,14 @@ impl<'a> dot::Labeller<'a> for DropRangesGraph<'_, '_> {
8081
.post_order_map
8182
.iter()
8283
.find(|(_hir_id, &post_order_id)| post_order_id == *n)
83-
.map_or("<unknown>".into(), |(hir_id, _)| self
84-
.tcx
85-
.hir()
86-
.node_to_string(*hir_id))
84+
.map_or("<unknown>".into(), |(hir_id, _)| format!(
85+
"{}{}",
86+
self.tcx.hir().node_to_string(*hir_id),
87+
match self.tcx.hir().find(*hir_id) {
88+
Some(Node::Expr(Expr { kind: ExprKind::Yield(..), .. })) => " (yield)",
89+
_ => "",
90+
}
91+
))
8792
)
8893
.into(),
8994
)

compiler/rustc_hir_typeck/src/generator_interior/mod.rs

+14-4
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,8 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
7171
yield_data.expr_and_pat_count, self.expr_count, source_span
7272
);
7373

74-
if self.fcx.sess().opts.unstable_opts.drop_tracking
75-
&& self
76-
.drop_ranges
77-
.is_dropped_at(hir_id, yield_data.expr_and_pat_count)
74+
if self
75+
.is_dropped_at_yield_location(hir_id, yield_data.expr_and_pat_count)
7876
{
7977
debug!("value is dropped at yield point; not recording");
8078
return false;
@@ -173,6 +171,18 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
173171
}
174172
}
175173
}
174+
175+
/// If drop tracking is enabled, consult drop_ranges to see if a value is
176+
/// known to be dropped at a yield point and therefore can be omitted from
177+
/// the generator witness.
178+
fn is_dropped_at_yield_location(&self, value_hir_id: HirId, yield_location: usize) -> bool {
179+
// short-circuit if drop tracking is not enabled.
180+
if !self.fcx.sess().opts.unstable_opts.drop_tracking {
181+
return false;
182+
}
183+
184+
self.drop_ranges.is_dropped_at(value_hir_id, yield_location)
185+
}
176186
}
177187

178188
pub fn resolve_interior<'a, 'tcx>(
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// edition:2021
2+
// compile-flags: -Z drop-tracking
3+
// build-pass
4+
5+
use std::collections::HashMap;
6+
7+
fn main() {
8+
let _ = real_main();
9+
}
10+
11+
async fn nop() {}
12+
13+
async fn real_main() {
14+
nop().await;
15+
nop().await;
16+
nop().await;
17+
nop().await;
18+
19+
let mut map: HashMap<(), ()> = HashMap::new();
20+
map.insert((), nop().await);
21+
}

0 commit comments

Comments
 (0)