11use 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} ;
55use hir:: {
66 intravisit:: { self , NestedVisitorMap , Visitor } ,
@@ -9,20 +9,24 @@ use hir::{
99use rustc_hir as hir;
1010use rustc_index:: vec:: IndexVec ;
1111use 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>(
3539struct 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
4246impl < ' 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}
0 commit comments