1
- use super :: { for_each_consumable, record_consumed_borrow:: ExprUseDelegate , DropRanges } ;
1
+ use super :: {
2
+ for_each_consumable, record_consumed_borrow:: ConsumedAndBorrowedPlaces , DropRanges , HirIdIndex ,
3
+ NodeInfo ,
4
+ } ;
2
5
use hir:: {
3
6
intravisit:: { self , NestedVisitorMap , Visitor } ,
4
- Expr , ExprKind , Guard , HirId , HirIdMap , HirIdSet ,
7
+ Body , Expr , ExprKind , Guard , HirId , HirIdMap ,
5
8
} ;
6
9
use rustc_hir as hir;
10
+ use rustc_index:: vec:: IndexVec ;
7
11
use rustc_middle:: hir:: map:: Map ;
8
12
13
+ /// Traverses the body to find the control flow graph and locations for the
14
+ /// relevant places are dropped or reinitialized.
15
+ ///
16
+ /// The resulting structure still needs to be iterated to a fixed point, which
17
+ /// can be done with propagate_to_fixpoint in cfg_propagate.
18
+ pub fn build_control_flow_graph < ' tcx > (
19
+ hir : Map < ' tcx > ,
20
+ consumed_borrowed_places : ConsumedAndBorrowedPlaces ,
21
+ body : & ' tcx Body < ' tcx > ,
22
+ num_exprs : usize ,
23
+ ) -> DropRanges {
24
+ let mut drop_range_visitor = DropRangeVisitor :: new ( hir, consumed_borrowed_places, num_exprs) ;
25
+ intravisit:: walk_body ( & mut drop_range_visitor, body) ;
26
+ drop_range_visitor. drop_ranges
27
+ }
28
+
9
29
/// This struct is used to gather the information for `DropRanges` to determine the regions of the
10
30
/// HIR tree for which a value is dropped.
11
31
///
12
32
/// We are interested in points where a variables is dropped or initialized, and the control flow
13
33
/// of the code. We identify locations in code by their post-order traversal index, so it is
14
34
/// important for this traversal to match that in `RegionResolutionVisitor` and `InteriorVisitor`.
15
- pub struct DropRangeVisitor < ' tcx > {
35
+ struct DropRangeVisitor < ' tcx > {
16
36
hir : Map < ' tcx > ,
17
- /// Maps a HirId to a set of HirIds that are dropped by that node.
18
- ///
19
- /// See also the more detailed comment on `ExprUseDelegate.consumed_places`.
20
- consumed_places : HirIdMap < HirIdSet > ,
21
- borrowed_places : HirIdSet ,
37
+ places : ConsumedAndBorrowedPlaces ,
22
38
drop_ranges : DropRanges ,
23
39
expr_count : usize ,
24
40
}
25
41
26
42
impl < ' tcx > DropRangeVisitor < ' tcx > {
27
- pub fn from_uses ( uses : ExprUseDelegate < ' tcx > , num_exprs : usize ) -> Self {
28
- debug ! ( "consumed_places: {:?}" , uses . consumed_places ) ;
43
+ fn new ( hir : Map < ' tcx > , places : ConsumedAndBorrowedPlaces , num_exprs : usize ) -> Self {
44
+ debug ! ( "consumed_places: {:?}" , places . consumed ) ;
29
45
let drop_ranges = DropRanges :: new (
30
- uses . consumed_places . iter ( ) . flat_map ( |( _, places) | places. iter ( ) . copied ( ) ) ,
31
- & uses . hir ,
46
+ places . consumed . iter ( ) . flat_map ( |( _, places) | places. iter ( ) . copied ( ) ) ,
47
+ hir,
32
48
num_exprs,
33
49
) ;
34
- Self {
35
- hir : uses. hir ,
36
- consumed_places : uses. consumed_places ,
37
- borrowed_places : uses. borrowed_places ,
38
- drop_ranges,
39
- expr_count : 0 ,
40
- }
41
- }
42
-
43
- pub fn into_drop_ranges ( self ) -> DropRanges {
44
- self . drop_ranges
50
+ Self { hir, places, drop_ranges, expr_count : 0 }
45
51
}
46
52
47
53
fn record_drop ( & mut self , hir_id : HirId ) {
48
- if self . borrowed_places . contains ( & hir_id) {
54
+ if self . places . borrowed . contains ( & hir_id) {
49
55
debug ! ( "not marking {:?} as dropped because it is borrowed at some point" , hir_id) ;
50
56
} else {
51
57
debug ! ( "marking {:?} as dropped at {}" , hir_id, self . expr_count) ;
@@ -59,7 +65,8 @@ impl<'tcx> DropRangeVisitor<'tcx> {
59
65
fn consume_expr ( & mut self , expr : & hir:: Expr < ' _ > ) {
60
66
debug ! ( "consuming expr {:?}, count={}" , expr. hir_id, self . expr_count) ;
61
67
let places = self
62
- . consumed_places
68
+ . places
69
+ . consumed
63
70
. get ( & expr. hir_id )
64
71
. map_or ( vec ! [ ] , |places| places. iter ( ) . cloned ( ) . collect ( ) ) ;
65
72
for place in places {
@@ -167,3 +174,60 @@ impl<'tcx> Visitor<'tcx> for DropRangeVisitor<'tcx> {
167
174
self . expr_count += 1 ;
168
175
}
169
176
}
177
+
178
+ impl DropRanges {
179
+ fn new ( hir_ids : impl Iterator < Item = HirId > , hir : Map < ' _ > , num_exprs : usize ) -> Self {
180
+ let mut hir_id_map = HirIdMap :: < HirIdIndex > :: default ( ) ;
181
+ let mut next = <_ >:: from ( 0u32 ) ;
182
+ for hir_id in hir_ids {
183
+ for_each_consumable ( hir_id, hir. find ( hir_id) , |hir_id| {
184
+ if !hir_id_map. contains_key ( & hir_id) {
185
+ hir_id_map. insert ( hir_id, next) ;
186
+ next = <_ >:: from ( next. index ( ) + 1 ) ;
187
+ }
188
+ } ) ;
189
+ }
190
+ debug ! ( "hir_id_map: {:?}" , hir_id_map) ;
191
+ let num_values = hir_id_map. len ( ) ;
192
+ Self {
193
+ hir_id_map,
194
+ nodes : IndexVec :: from_fn_n ( |_| NodeInfo :: new ( num_values) , num_exprs + 1 ) ,
195
+ deferred_edges : <_ >:: default ( ) ,
196
+ post_order_map : <_ >:: default ( ) ,
197
+ }
198
+ }
199
+
200
+ fn hidx ( & self , hir_id : HirId ) -> HirIdIndex {
201
+ * self . hir_id_map . get ( & hir_id) . unwrap ( )
202
+ }
203
+
204
+ /// Adds an entry in the mapping from HirIds to PostOrderIds
205
+ ///
206
+ /// Needed so that `add_control_edge_hir_id` can work.
207
+ fn add_node_mapping ( & mut self , hir_id : HirId , post_order_id : usize ) {
208
+ self . post_order_map . insert ( hir_id, post_order_id) ;
209
+ }
210
+
211
+ /// Like add_control_edge, but uses a hir_id as the target.
212
+ ///
213
+ /// This can be used for branches where we do not know the PostOrderId of the target yet,
214
+ /// such as when handling `break` or `continue`.
215
+ fn add_control_edge_hir_id ( & mut self , from : usize , to : HirId ) {
216
+ self . deferred_edges . push ( ( from, to) ) ;
217
+ }
218
+
219
+ fn drop_at ( & mut self , value : HirId , location : usize ) {
220
+ let value = self . hidx ( value) ;
221
+ self . node_mut ( location. into ( ) ) . drops . push ( value) ;
222
+ }
223
+
224
+ fn reinit_at ( & mut self , value : HirId , location : usize ) {
225
+ let value = match self . hir_id_map . get ( & value) {
226
+ Some ( value) => * value,
227
+ // If there's no value, this is never consumed and therefore is never dropped. We can
228
+ // ignore this.
229
+ None => return ,
230
+ } ;
231
+ self . node_mut ( location. into ( ) ) . reinits . push ( value) ;
232
+ }
233
+ }
0 commit comments