Skip to content

Commit 2af02cf

Browse files
committed
More comments and refactoring
The refactoring mainly keeps the separation between the modules clearer. For example, process_deferred_edges function moved to cfg_build.rs since that is really part of building the CFG, not finding the fixpoint. Also, we use PostOrderId instead of usize in a lot more places now.
1 parent 7d82e4f commit 2af02cf

File tree

4 files changed

+117
-75
lines changed

4 files changed

+117
-75
lines changed

compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub fn compute_drop_ranges<'a, 'tcx>(
4141

4242
drop_ranges.propagate_to_fixpoint();
4343

44-
drop_ranges
44+
DropRanges { hir_id_map: drop_ranges.hir_id_map, nodes: drop_ranges.nodes }
4545
}
4646

4747
/// Applies `f` to consumable portion of a HIR node.
@@ -77,12 +77,59 @@ rustc_index::newtype_index! {
7777
pub struct DropRanges {
7878
hir_id_map: HirIdMap<HirIdIndex>,
7979
nodes: IndexVec<PostOrderId, NodeInfo>,
80-
deferred_edges: Vec<(usize, HirId)>,
81-
// FIXME: This should only be used for loops and break/continue.
82-
post_order_map: HirIdMap<usize>,
8380
}
8481

85-
impl Debug for DropRanges {
82+
impl DropRanges {
83+
pub fn is_dropped_at(&self, hir_id: HirId, location: usize) -> bool {
84+
self.hir_id_map
85+
.get(&hir_id)
86+
.copied()
87+
.map_or(false, |hir_id| self.expect_node(location.into()).drop_state.contains(hir_id))
88+
}
89+
90+
/// Returns a reference to the NodeInfo for a node, panicking if it does not exist
91+
fn expect_node(&self, id: PostOrderId) -> &NodeInfo {
92+
&self.nodes[id]
93+
}
94+
}
95+
96+
/// Tracks information needed to compute drop ranges.
97+
struct DropRangesBuilder {
98+
/// The core of DropRangesBuilder is a set of nodes, which each represent
99+
/// one expression. We primarily refer to them by their index in a
100+
/// post-order traversal of the HIR tree, since this is what
101+
/// generator_interior uses to talk about yield positions.
102+
///
103+
/// This IndexVec keeps the relevant details for each node. See the
104+
/// NodeInfo struct for more details, but this information includes things
105+
/// such as the set of control-flow successors, which variables are dropped
106+
/// or reinitialized, and whether each variable has been inferred to be
107+
/// known-dropped or potentially reintiialized at each point.
108+
nodes: IndexVec<PostOrderId, NodeInfo>,
109+
/// We refer to values whose drop state we are tracking by the HirId of
110+
/// where they are defined. Within a NodeInfo, however, we store the
111+
/// drop-state in a bit vector indexed by a HirIdIndex
112+
/// (see NodeInfo::drop_state). The hir_id_map field stores the mapping
113+
/// from HirIds to the HirIdIndex that is used to represent that value in
114+
/// bitvector.
115+
hir_id_map: HirIdMap<HirIdIndex>,
116+
117+
/// When building the control flow graph, we don't always know the
118+
/// post-order index of the target node at the point we encounter it.
119+
/// For example, this happens with break and continue. In those cases,
120+
/// we store a pair of the PostOrderId of the source and the HirId
121+
/// of the target. Once we have gathered all of these edges, we make a
122+
/// pass over the set of deferred edges (see process_deferred_edges in
123+
/// cfg_build.rs), look up the PostOrderId for the target (since now the
124+
/// post-order index for all nodes is known), and add missing control flow
125+
/// edges.
126+
deferred_edges: Vec<(PostOrderId, HirId)>,
127+
/// This maps HirIds of expressions to their post-order index. It is
128+
/// used in process_deferred_edges to correctly add back-edges.
129+
post_order_map: HirIdMap<PostOrderId>,
130+
}
131+
132+
impl Debug for DropRangesBuilder {
86133
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87134
f.debug_struct("DropRanges")
88135
.field("hir_id_map", &self.hir_id_map)
@@ -98,32 +145,20 @@ impl Debug for DropRanges {
98145
/// by their index in the post-order traversal. At its core, DropRanges maps
99146
/// (hir_id, post_order_id) -> bool, where a true value indicates that the value is definitely
100147
/// dropped at the point of the node identified by post_order_id.
101-
impl DropRanges {
102-
pub fn is_dropped_at(&mut self, hir_id: HirId, location: usize) -> bool {
103-
self.hir_id_map
104-
.get(&hir_id)
105-
.copied()
106-
.map_or(false, |hir_id| self.expect_node(location.into()).drop_state.contains(hir_id))
107-
}
108-
148+
impl DropRangesBuilder {
109149
/// Returns the number of values (hir_ids) that are tracked
110150
fn num_values(&self) -> usize {
111151
self.hir_id_map.len()
112152
}
113153

114-
/// Returns a reference to the NodeInfo for a node, panicking if it does not exist
115-
fn expect_node(&self, id: PostOrderId) -> &NodeInfo {
116-
&self.nodes[id]
117-
}
118-
119154
fn node_mut(&mut self, id: PostOrderId) -> &mut NodeInfo {
120155
let size = self.num_values();
121156
self.nodes.ensure_contains_elem(id, || NodeInfo::new(size));
122157
&mut self.nodes[id]
123158
}
124159

125-
fn add_control_edge(&mut self, from: usize, to: usize) {
126-
trace!("adding control edge from {} to {}", from, to);
160+
fn add_control_edge(&mut self, from: PostOrderId, to: PostOrderId) {
161+
trace!("adding control edge from {:?} to {:?}", from, to);
127162
self.node_mut(from.into()).successors.push(to.into());
128163
}
129164
}

compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::{
2-
for_each_consumable, record_consumed_borrow::ConsumedAndBorrowedPlaces, DropRanges, HirIdIndex,
3-
NodeInfo,
2+
for_each_consumable, record_consumed_borrow::ConsumedAndBorrowedPlaces, DropRangesBuilder,
3+
HirIdIndex, NodeInfo, PostOrderId,
44
};
55
use hir::{
66
intravisit::{self, NestedVisitorMap, Visitor},
@@ -9,20 +9,24 @@ use hir::{
99
use rustc_hir as hir;
1010
use rustc_index::vec::IndexVec;
1111
use rustc_middle::hir::map::Map;
12+
use std::mem::swap;
1213

1314
/// Traverses the body to find the control flow graph and locations for the
1415
/// relevant places are dropped or reinitialized.
1516
///
1617
/// The resulting structure still needs to be iterated to a fixed point, which
1718
/// can be done with propagate_to_fixpoint in cfg_propagate.
18-
pub fn build_control_flow_graph<'tcx>(
19+
pub(super) fn build_control_flow_graph<'tcx>(
1920
hir: Map<'tcx>,
2021
consumed_borrowed_places: ConsumedAndBorrowedPlaces,
2122
body: &'tcx Body<'tcx>,
2223
num_exprs: usize,
23-
) -> DropRanges {
24+
) -> DropRangesBuilder {
2425
let mut drop_range_visitor = DropRangeVisitor::new(hir, consumed_borrowed_places, num_exprs);
2526
intravisit::walk_body(&mut drop_range_visitor, body);
27+
28+
drop_range_visitor.drop_ranges.process_deferred_edges();
29+
2630
drop_range_visitor.drop_ranges
2731
}
2832

@@ -35,35 +39,35 @@ pub fn build_control_flow_graph<'tcx>(
3539
struct DropRangeVisitor<'tcx> {
3640
hir: Map<'tcx>,
3741
places: ConsumedAndBorrowedPlaces,
38-
drop_ranges: DropRanges,
39-
expr_count: usize,
42+
drop_ranges: DropRangesBuilder,
43+
expr_index: PostOrderId,
4044
}
4145

4246
impl<'tcx> DropRangeVisitor<'tcx> {
4347
fn new(hir: Map<'tcx>, places: ConsumedAndBorrowedPlaces, num_exprs: usize) -> Self {
4448
debug!("consumed_places: {:?}", places.consumed);
45-
let drop_ranges = DropRanges::new(
49+
let drop_ranges = DropRangesBuilder::new(
4650
places.consumed.iter().flat_map(|(_, places)| places.iter().copied()),
4751
hir,
4852
num_exprs,
4953
);
50-
Self { hir, places, drop_ranges, expr_count: 0 }
54+
Self { hir, places, drop_ranges, expr_index: PostOrderId::from_u32(0) }
5155
}
5256

5357
fn record_drop(&mut self, hir_id: HirId) {
5458
if self.places.borrowed.contains(&hir_id) {
5559
debug!("not marking {:?} as dropped because it is borrowed at some point", hir_id);
5660
} else {
57-
debug!("marking {:?} as dropped at {}", hir_id, self.expr_count);
58-
let count = self.expr_count;
61+
debug!("marking {:?} as dropped at {:?}", hir_id, self.expr_index);
62+
let count = self.expr_index;
5963
self.drop_ranges.drop_at(hir_id, count);
6064
}
6165
}
6266

6367
/// ExprUseVisitor's consume callback doesn't go deep enough for our purposes in all
6468
/// expressions. This method consumes a little deeper into the expression when needed.
6569
fn consume_expr(&mut self, expr: &hir::Expr<'_>) {
66-
debug!("consuming expr {:?}, count={}", expr.hir_id, self.expr_count);
70+
debug!("consuming expr {:?}, count={:?}", expr.hir_id, self.expr_index);
6771
let places = self
6872
.places
6973
.consumed
@@ -80,8 +84,8 @@ impl<'tcx> DropRangeVisitor<'tcx> {
8084
hir::Path { res: hir::def::Res::Local(hir_id), .. },
8185
)) = expr.kind
8286
{
83-
let location = self.expr_count;
84-
debug!("reinitializing {:?} at {}", hir_id, location);
87+
let location = self.expr_index;
88+
debug!("reinitializing {:?} at {:?}", hir_id, location);
8589
self.drop_ranges.reinit_at(*hir_id, location);
8690
} else {
8791
debug!("reinitializing {:?} is not supported", expr);
@@ -102,18 +106,18 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
102106
ExprKind::If(test, if_true, if_false) => {
103107
self.visit_expr(test);
104108

105-
let fork = self.expr_count;
109+
let fork = self.expr_index;
106110

107-
self.drop_ranges.add_control_edge(fork, self.expr_count + 1);
111+
self.drop_ranges.add_control_edge(fork, self.expr_index + 1);
108112
self.visit_expr(if_true);
109-
let true_end = self.expr_count;
113+
let true_end = self.expr_index;
110114

111-
self.drop_ranges.add_control_edge(fork, self.expr_count + 1);
115+
self.drop_ranges.add_control_edge(fork, self.expr_index + 1);
112116
if let Some(if_false) = if_false {
113117
self.visit_expr(if_false);
114118
}
115119

116-
self.drop_ranges.add_control_edge(true_end, self.expr_count + 1);
120+
self.drop_ranges.add_control_edge(true_end, self.expr_index + 1);
117121
}
118122
ExprKind::Assign(lhs, rhs, _) => {
119123
self.visit_expr(lhs);
@@ -122,18 +126,18 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
122126
reinit = Some(lhs);
123127
}
124128
ExprKind::Loop(body, ..) => {
125-
let loop_begin = self.expr_count + 1;
129+
let loop_begin = self.expr_index + 1;
126130
self.visit_block(body);
127-
self.drop_ranges.add_control_edge(self.expr_count, loop_begin);
131+
self.drop_ranges.add_control_edge(self.expr_index, loop_begin);
128132
}
129133
ExprKind::Match(scrutinee, arms, ..) => {
130134
self.visit_expr(scrutinee);
131135

132-
let fork = self.expr_count;
136+
let fork = self.expr_index;
133137
let arm_end_ids = arms
134138
.iter()
135139
.map(|hir::Arm { pat, body, guard, .. }| {
136-
self.drop_ranges.add_control_edge(fork, self.expr_count + 1);
140+
self.drop_ranges.add_control_edge(fork, self.expr_index + 1);
137141
self.visit_pat(pat);
138142
match guard {
139143
Some(Guard::If(expr)) => self.visit_expr(expr),
@@ -144,23 +148,23 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
144148
None => (),
145149
}
146150
self.visit_expr(body);
147-
self.expr_count
151+
self.expr_index
148152
})
149153
.collect::<Vec<_>>();
150154
arm_end_ids.into_iter().for_each(|arm_end| {
151-
self.drop_ranges.add_control_edge(arm_end, self.expr_count + 1)
155+
self.drop_ranges.add_control_edge(arm_end, self.expr_index + 1)
152156
});
153157
}
154158
ExprKind::Break(hir::Destination { target_id: Ok(target), .. }, ..)
155159
| ExprKind::Continue(hir::Destination { target_id: Ok(target), .. }, ..) => {
156-
self.drop_ranges.add_control_edge_hir_id(self.expr_count, target);
160+
self.drop_ranges.add_control_edge_hir_id(self.expr_index, target);
157161
}
158162

159163
_ => intravisit::walk_expr(self, expr),
160164
}
161165

162-
self.expr_count += 1;
163-
self.drop_ranges.add_node_mapping(expr.hir_id, self.expr_count);
166+
self.expr_index = self.expr_index + 1;
167+
self.drop_ranges.add_node_mapping(expr.hir_id, self.expr_index);
164168
self.consume_expr(expr);
165169
if let Some(expr) = reinit {
166170
self.reinit_expr(expr);
@@ -171,11 +175,11 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
171175
intravisit::walk_pat(self, pat);
172176

173177
// Increment expr_count here to match what InteriorVisitor expects.
174-
self.expr_count += 1;
178+
self.expr_index = self.expr_index + 1;
175179
}
176180
}
177181

178-
impl DropRanges {
182+
impl DropRangesBuilder {
179183
fn new(hir_ids: impl Iterator<Item = HirId>, hir: Map<'_>, num_exprs: usize) -> Self {
180184
let mut hir_id_map = HirIdMap::<HirIdIndex>::default();
181185
let mut next = <_>::from(0u32);
@@ -204,24 +208,24 @@ impl DropRanges {
204208
/// Adds an entry in the mapping from HirIds to PostOrderIds
205209
///
206210
/// Needed so that `add_control_edge_hir_id` can work.
207-
fn add_node_mapping(&mut self, hir_id: HirId, post_order_id: usize) {
211+
fn add_node_mapping(&mut self, hir_id: HirId, post_order_id: PostOrderId) {
208212
self.post_order_map.insert(hir_id, post_order_id);
209213
}
210214

211215
/// Like add_control_edge, but uses a hir_id as the target.
212216
///
213217
/// This can be used for branches where we do not know the PostOrderId of the target yet,
214218
/// such as when handling `break` or `continue`.
215-
fn add_control_edge_hir_id(&mut self, from: usize, to: HirId) {
219+
fn add_control_edge_hir_id(&mut self, from: PostOrderId, to: HirId) {
216220
self.deferred_edges.push((from, to));
217221
}
218222

219-
fn drop_at(&mut self, value: HirId, location: usize) {
223+
fn drop_at(&mut self, value: HirId, location: PostOrderId) {
220224
let value = self.hidx(value);
221225
self.node_mut(location.into()).drops.push(value);
222226
}
223227

224-
fn reinit_at(&mut self, value: HirId, location: usize) {
228+
fn reinit_at(&mut self, value: HirId, location: PostOrderId) {
225229
let value = match self.hir_id_map.get(&value) {
226230
Some(value) => *value,
227231
// If there's no value, this is never consumed and therefore is never dropped. We can
@@ -230,4 +234,18 @@ impl DropRanges {
230234
};
231235
self.node_mut(location.into()).reinits.push(value);
232236
}
237+
238+
/// Looks up PostOrderId for any control edges added by HirId and adds a proper edge for them.
239+
///
240+
/// Should be called after visiting the HIR but before solving the control flow, otherwise some
241+
/// edges will be missed.
242+
fn process_deferred_edges(&mut self) {
243+
let mut edges = vec![];
244+
swap(&mut edges, &mut self.deferred_edges);
245+
edges.into_iter().for_each(|(from, to)| {
246+
let to = *self.post_order_map.get(&to).expect("Expression ID not found");
247+
trace!("Adding deferred edge from {:?} to {:?}", from, to);
248+
self.add_control_edge(from, to)
249+
});
250+
}
233251
}

compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_propagate.rs

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
use super::{DropRanges, PostOrderId};
1+
use super::{DropRangesBuilder, PostOrderId};
22
use rustc_index::{bit_set::BitSet, vec::IndexVec};
33
use std::collections::BTreeMap;
4-
use std::mem::swap;
54

6-
impl DropRanges {
5+
impl DropRangesBuilder {
76
pub fn propagate_to_fixpoint(&mut self) {
87
trace!("before fixpoint: {:#?}", self);
9-
self.process_deferred_edges();
108
let preds = self.compute_predecessors();
119

1210
trace!("predecessors: {:#?}", preds.iter_enumerated().collect::<BTreeMap<_, _>>());
@@ -53,6 +51,11 @@ impl DropRanges {
5351
fn compute_predecessors(&self) -> IndexVec<PostOrderId, Vec<PostOrderId>> {
5452
let mut preds = IndexVec::from_fn_n(|_| vec![], self.nodes.len());
5553
for (id, node) in self.nodes.iter_enumerated() {
54+
// If the node has no explicit successors, we assume that control
55+
// will from this node into the next one.
56+
//
57+
// If there are successors listed, then we assume that all
58+
// possible successors are given and we do not include the default.
5659
if node.successors.len() == 0 && id.index() != self.nodes.len() - 1 {
5760
preds[id + 1].push(id);
5861
} else {
@@ -63,18 +66,4 @@ impl DropRanges {
6366
}
6467
preds
6568
}
66-
67-
/// Looks up PostOrderId for any control edges added by HirId and adds a proper edge for them.
68-
///
69-
/// Should be called after visiting the HIR but before solving the control flow, otherwise some
70-
/// edges will be missed.
71-
fn process_deferred_edges(&mut self) {
72-
let mut edges = vec![];
73-
swap(&mut edges, &mut self.deferred_edges);
74-
edges.into_iter().for_each(|(from, to)| {
75-
let to = *self.post_order_map.get(&to).expect("Expression ID not found");
76-
trace!("Adding deferred edge from {} to {}", from, to);
77-
self.add_control_edge(from, to)
78-
});
79-
}
8069
}

0 commit comments

Comments
 (0)