@@ -209,6 +209,45 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
209
209
self . drop_ranges . add_control_edge ( self . expr_index + 1 , self . expr_index + 1 ) ;
210
210
}
211
211
}
212
+
213
+ /// Break and continue expression targets might be another expression or a block,
214
+ /// but this analysis only looks at expressions. In case a break has a block as a
215
+ /// target, this will find the last expression in the block and return its HirId
216
+ /// instead.
217
+ fn find_target_expression ( & self , hir_id : HirId ) -> HirId {
218
+ let node = self . hir . get ( hir_id) ;
219
+ match node {
220
+ hir:: Node :: Expr ( _) => hir_id,
221
+ hir:: Node :: Block ( b) => b. expr . map_or_else (
222
+ // If there is no tail expression, there will be at least one statement in the
223
+ // block because the block contains a break or continue statement.
224
+ || b. stmts . last ( ) . unwrap ( ) . hir_id ,
225
+ |expr| expr. hir_id ,
226
+ ) ,
227
+ hir:: Node :: Param ( ..)
228
+ | hir:: Node :: Item ( ..)
229
+ | hir:: Node :: ForeignItem ( ..)
230
+ | hir:: Node :: TraitItem ( ..)
231
+ | hir:: Node :: ImplItem ( ..)
232
+ | hir:: Node :: Variant ( ..)
233
+ | hir:: Node :: Field ( ..)
234
+ | hir:: Node :: AnonConst ( ..)
235
+ | hir:: Node :: Stmt ( ..)
236
+ | hir:: Node :: PathSegment ( ..)
237
+ | hir:: Node :: Ty ( ..)
238
+ | hir:: Node :: TraitRef ( ..)
239
+ | hir:: Node :: Binding ( ..)
240
+ | hir:: Node :: Pat ( ..)
241
+ | hir:: Node :: Arm ( ..)
242
+ | hir:: Node :: Local ( ..)
243
+ | hir:: Node :: Ctor ( ..)
244
+ | hir:: Node :: Lifetime ( ..)
245
+ | hir:: Node :: GenericParam ( ..)
246
+ | hir:: Node :: Visibility ( ..)
247
+ | hir:: Node :: Crate ( ..)
248
+ | hir:: Node :: Infer ( ..) => bug ! ( "Unsupported branch target: {:?}" , node) ,
249
+ }
250
+ }
212
251
}
213
252
214
253
impl < ' a , ' tcx > Visitor < ' tcx > for DropRangeVisitor < ' a , ' tcx > {
@@ -334,7 +373,8 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
334
373
}
335
374
ExprKind :: Break ( hir:: Destination { target_id : Ok ( target) , .. } , ..)
336
375
| ExprKind :: Continue ( hir:: Destination { target_id : Ok ( target) , .. } , ..) => {
337
- self . drop_ranges . add_control_edge_hir_id ( self . expr_index , target) ;
376
+ self . drop_ranges
377
+ . add_control_edge_hir_id ( self . expr_index , self . find_target_expression ( target) ) ;
338
378
}
339
379
340
380
ExprKind :: Call ( f, args) => {
@@ -462,11 +502,13 @@ impl DropRangesBuilder {
462
502
/// Should be called after visiting the HIR but before solving the control flow, otherwise some
463
503
/// edges will be missed.
464
504
fn process_deferred_edges ( & mut self ) {
505
+ trace ! ( "processing deferred edges. post_order_map={:#?}" , self . post_order_map) ;
465
506
let mut edges = vec ! [ ] ;
466
507
swap ( & mut edges, & mut self . deferred_edges ) ;
467
508
edges. into_iter ( ) . for_each ( |( from, to) | {
468
- let to = * self . post_order_map . get ( & to) . expect ( "Expression ID not found" ) ;
469
509
trace ! ( "Adding deferred edge from {:?} to {:?}" , from, to) ;
510
+ let to = * self . post_order_map . get ( & to) . expect ( "Expression ID not found" ) ;
511
+ trace ! ( "target edge PostOrderId={:?}" , to) ;
470
512
self . add_control_edge ( from, to)
471
513
} ) ;
472
514
}
0 commit comments