1
1
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 ,
4
4
} ;
5
5
use hir:: {
6
6
intravisit:: { self , NestedVisitorMap , Visitor } ,
@@ -9,20 +9,24 @@ use hir::{
9
9
use rustc_hir as hir;
10
10
use rustc_index:: vec:: IndexVec ;
11
11
use rustc_middle:: hir:: map:: Map ;
12
+ use std:: mem:: swap;
12
13
13
14
/// Traverses the body to find the control flow graph and locations for the
14
15
/// relevant places are dropped or reinitialized.
15
16
///
16
17
/// The resulting structure still needs to be iterated to a fixed point, which
17
18
/// 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 > (
19
20
hir : Map < ' tcx > ,
20
21
consumed_borrowed_places : ConsumedAndBorrowedPlaces ,
21
22
body : & ' tcx Body < ' tcx > ,
22
23
num_exprs : usize ,
23
- ) -> DropRanges {
24
+ ) -> DropRangesBuilder {
24
25
let mut drop_range_visitor = DropRangeVisitor :: new ( hir, consumed_borrowed_places, num_exprs) ;
25
26
intravisit:: walk_body ( & mut drop_range_visitor, body) ;
27
+
28
+ drop_range_visitor. drop_ranges . process_deferred_edges ( ) ;
29
+
26
30
drop_range_visitor. drop_ranges
27
31
}
28
32
@@ -35,35 +39,35 @@ pub fn build_control_flow_graph<'tcx>(
35
39
struct DropRangeVisitor < ' tcx > {
36
40
hir : Map < ' tcx > ,
37
41
places : ConsumedAndBorrowedPlaces ,
38
- drop_ranges : DropRanges ,
39
- expr_count : usize ,
42
+ drop_ranges : DropRangesBuilder ,
43
+ expr_index : PostOrderId ,
40
44
}
41
45
42
46
impl < ' tcx > DropRangeVisitor < ' tcx > {
43
47
fn new ( hir : Map < ' tcx > , places : ConsumedAndBorrowedPlaces , num_exprs : usize ) -> Self {
44
48
debug ! ( "consumed_places: {:?}" , places. consumed) ;
45
- let drop_ranges = DropRanges :: new (
49
+ let drop_ranges = DropRangesBuilder :: new (
46
50
places. consumed . iter ( ) . flat_map ( |( _, places) | places. iter ( ) . copied ( ) ) ,
47
51
hir,
48
52
num_exprs,
49
53
) ;
50
- Self { hir, places, drop_ranges, expr_count : 0 }
54
+ Self { hir, places, drop_ranges, expr_index : PostOrderId :: from_u32 ( 0 ) }
51
55
}
52
56
53
57
fn record_drop ( & mut self , hir_id : HirId ) {
54
58
if self . places . borrowed . contains ( & hir_id) {
55
59
debug ! ( "not marking {:?} as dropped because it is borrowed at some point" , hir_id) ;
56
60
} 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 ;
59
63
self . drop_ranges . drop_at ( hir_id, count) ;
60
64
}
61
65
}
62
66
63
67
/// ExprUseVisitor's consume callback doesn't go deep enough for our purposes in all
64
68
/// expressions. This method consumes a little deeper into the expression when needed.
65
69
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 ) ;
67
71
let places = self
68
72
. places
69
73
. consumed
@@ -80,8 +84,8 @@ impl<'tcx> DropRangeVisitor<'tcx> {
80
84
hir:: Path { res : hir:: def:: Res :: Local ( hir_id) , .. } ,
81
85
) ) = expr. kind
82
86
{
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) ;
85
89
self . drop_ranges . reinit_at ( * hir_id, location) ;
86
90
} else {
87
91
debug ! ( "reinitializing {:?} is not supported" , expr) ;
@@ -102,18 +106,18 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
102
106
ExprKind :: If ( test, if_true, if_false) => {
103
107
self . visit_expr ( test) ;
104
108
105
- let fork = self . expr_count ;
109
+ let fork = self . expr_index ;
106
110
107
- self . drop_ranges . add_control_edge ( fork, self . expr_count + 1 ) ;
111
+ self . drop_ranges . add_control_edge ( fork, self . expr_index + 1 ) ;
108
112
self . visit_expr ( if_true) ;
109
- let true_end = self . expr_count ;
113
+ let true_end = self . expr_index ;
110
114
111
- self . drop_ranges . add_control_edge ( fork, self . expr_count + 1 ) ;
115
+ self . drop_ranges . add_control_edge ( fork, self . expr_index + 1 ) ;
112
116
if let Some ( if_false) = if_false {
113
117
self . visit_expr ( if_false) ;
114
118
}
115
119
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 ) ;
117
121
}
118
122
ExprKind :: Assign ( lhs, rhs, _) => {
119
123
self . visit_expr ( lhs) ;
@@ -122,18 +126,18 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
122
126
reinit = Some ( lhs) ;
123
127
}
124
128
ExprKind :: Loop ( body, ..) => {
125
- let loop_begin = self . expr_count + 1 ;
129
+ let loop_begin = self . expr_index + 1 ;
126
130
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) ;
128
132
}
129
133
ExprKind :: Match ( scrutinee, arms, ..) => {
130
134
self . visit_expr ( scrutinee) ;
131
135
132
- let fork = self . expr_count ;
136
+ let fork = self . expr_index ;
133
137
let arm_end_ids = arms
134
138
. iter ( )
135
139
. 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 ) ;
137
141
self . visit_pat ( pat) ;
138
142
match guard {
139
143
Some ( Guard :: If ( expr) ) => self . visit_expr ( expr) ,
@@ -144,23 +148,23 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
144
148
None => ( ) ,
145
149
}
146
150
self . visit_expr ( body) ;
147
- self . expr_count
151
+ self . expr_index
148
152
} )
149
153
. collect :: < Vec < _ > > ( ) ;
150
154
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 )
152
156
} ) ;
153
157
}
154
158
ExprKind :: Break ( hir:: Destination { target_id : Ok ( target) , .. } , ..)
155
159
| 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) ;
157
161
}
158
162
159
163
_ => intravisit:: walk_expr ( self , expr) ,
160
164
}
161
165
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 ) ;
164
168
self . consume_expr ( expr) ;
165
169
if let Some ( expr) = reinit {
166
170
self . reinit_expr ( expr) ;
@@ -171,11 +175,11 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
171
175
intravisit:: walk_pat ( self , pat) ;
172
176
173
177
// Increment expr_count here to match what InteriorVisitor expects.
174
- self . expr_count += 1 ;
178
+ self . expr_index = self . expr_index + 1 ;
175
179
}
176
180
}
177
181
178
- impl DropRanges {
182
+ impl DropRangesBuilder {
179
183
fn new ( hir_ids : impl Iterator < Item = HirId > , hir : Map < ' _ > , num_exprs : usize ) -> Self {
180
184
let mut hir_id_map = HirIdMap :: < HirIdIndex > :: default ( ) ;
181
185
let mut next = <_ >:: from ( 0u32 ) ;
@@ -204,24 +208,24 @@ impl DropRanges {
204
208
/// Adds an entry in the mapping from HirIds to PostOrderIds
205
209
///
206
210
/// 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 ) {
208
212
self . post_order_map . insert ( hir_id, post_order_id) ;
209
213
}
210
214
211
215
/// Like add_control_edge, but uses a hir_id as the target.
212
216
///
213
217
/// This can be used for branches where we do not know the PostOrderId of the target yet,
214
218
/// 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 ) {
216
220
self . deferred_edges . push ( ( from, to) ) ;
217
221
}
218
222
219
- fn drop_at ( & mut self , value : HirId , location : usize ) {
223
+ fn drop_at ( & mut self , value : HirId , location : PostOrderId ) {
220
224
let value = self . hidx ( value) ;
221
225
self . node_mut ( location. into ( ) ) . drops . push ( value) ;
222
226
}
223
227
224
- fn reinit_at ( & mut self , value : HirId , location : usize ) {
228
+ fn reinit_at ( & mut self , value : HirId , location : PostOrderId ) {
225
229
let value = match self . hir_id_map . get ( & value) {
226
230
Some ( value) => * value,
227
231
// If there's no value, this is never consumed and therefore is never dropped. We can
@@ -230,4 +234,18 @@ impl DropRanges {
230
234
} ;
231
235
self . node_mut ( location. into ( ) ) . reinits . push ( value) ;
232
236
}
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
+ }
233
251
}
0 commit comments