@@ -22,13 +22,20 @@ struct CFGBuilder<'a, 'tcx: 'a> {
22
22
graph : CFGGraph ,
23
23
fn_exit : CFGIndex ,
24
24
loop_scopes : Vec < LoopScope > ,
25
+ breakable_block_scopes : Vec < BlockScope > ,
26
+ }
27
+
28
+ #[ derive( Copy , Clone ) ]
29
+ struct BlockScope {
30
+ block_expr_id : ast:: NodeId , // id of breakable block expr node
31
+ break_index : CFGIndex , // where to go on `break`
25
32
}
26
33
27
34
#[ derive( Copy , Clone ) ]
28
35
struct LoopScope {
29
36
loop_id : ast:: NodeId , // id of loop/while node
30
37
continue_index : CFGIndex , // where to go on a `loop`
31
- break_index : CFGIndex , // where to go on a `break
38
+ break_index : CFGIndex , // where to go on a `break`
32
39
}
33
40
34
41
pub fn construct < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
@@ -53,6 +60,7 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
53
60
graph : graph,
54
61
fn_exit : fn_exit,
55
62
loop_scopes : Vec :: new ( ) ,
63
+ breakable_block_scopes : Vec :: new ( ) ,
56
64
} ;
57
65
body_exit = cfg_builder. expr ( & body. value , entry) ;
58
66
cfg_builder. add_contained_edge ( body_exit, fn_exit) ;
@@ -66,14 +74,34 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
66
74
67
75
impl < ' a , ' tcx > CFGBuilder < ' a , ' tcx > {
68
76
fn block ( & mut self , blk : & hir:: Block , pred : CFGIndex ) -> CFGIndex {
69
- let mut stmts_exit = pred;
70
- for stmt in & blk. stmts {
71
- stmts_exit = self . stmt ( stmt, stmts_exit) ;
72
- }
77
+ if let Some ( break_to_expr_id) = blk. break_to_expr_id {
78
+ let expr_exit = self . add_ast_node ( blk. id , & [ ] ) ;
79
+
80
+ self . breakable_block_scopes . push ( BlockScope {
81
+ block_expr_id : break_to_expr_id,
82
+ break_index : expr_exit,
83
+ } ) ;
84
+
85
+ let mut stmts_exit = pred;
86
+ for stmt in & blk. stmts {
87
+ stmts_exit = self . stmt ( stmt, stmts_exit) ;
88
+ }
89
+ let blk_expr_exit = self . opt_expr ( & blk. expr , stmts_exit) ;
90
+ self . add_contained_edge ( blk_expr_exit, blk_expr_exit) ;
91
+
92
+ self . breakable_block_scopes . pop ( ) ;
93
+
94
+ expr_exit
95
+ } else {
96
+ let mut stmts_exit = pred;
97
+ for stmt in & blk. stmts {
98
+ stmts_exit = self . stmt ( stmt, stmts_exit) ;
99
+ }
73
100
74
- let expr_exit = self . opt_expr ( & blk. expr , stmts_exit) ;
101
+ let expr_exit = self . opt_expr ( & blk. expr , stmts_exit) ;
75
102
76
- self . add_ast_node ( blk. id , & [ expr_exit] )
103
+ self . add_ast_node ( blk. id , & [ expr_exit] )
104
+ }
77
105
}
78
106
79
107
fn stmt ( & mut self , stmt : & hir:: Stmt , pred : CFGIndex ) -> CFGIndex {
@@ -295,18 +323,18 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
295
323
296
324
hir:: ExprBreak ( destination, ref opt_expr) => {
297
325
let v = self . opt_expr ( opt_expr, pred) ;
298
- let loop_scope = self . find_scope ( expr, destination) ;
326
+ let ( scope_id, break_dest) =
327
+ self . find_scope_edge ( expr, destination, ScopeCfKind :: Break ) ;
299
328
let b = self . add_ast_node ( expr. id , & [ v] ) ;
300
- self . add_exiting_edge ( expr, b,
301
- loop_scope, loop_scope. break_index ) ;
329
+ self . add_exiting_edge ( expr, b, scope_id, break_dest) ;
302
330
self . add_unreachable_node ( )
303
331
}
304
332
305
333
hir:: ExprAgain ( destination) => {
306
- let loop_scope = self . find_scope ( expr, destination) ;
334
+ let ( scope_id, cont_dest) =
335
+ self . find_scope_edge ( expr, destination, ScopeCfKind :: Continue ) ;
307
336
let a = self . add_ast_node ( expr. id , & [ pred] ) ;
308
- self . add_exiting_edge ( expr, a,
309
- loop_scope, loop_scope. continue_index ) ;
337
+ self . add_exiting_edge ( expr, a, scope_id, cont_dest) ;
310
338
self . add_unreachable_node ( )
311
339
}
312
340
@@ -552,11 +580,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
552
580
fn add_exiting_edge ( & mut self ,
553
581
from_expr : & hir:: Expr ,
554
582
from_index : CFGIndex ,
555
- to_loop : LoopScope ,
583
+ scope_id : ast :: NodeId ,
556
584
to_index : CFGIndex ) {
557
585
let mut data = CFGEdgeData { exiting_scopes : vec ! [ ] } ;
558
586
let mut scope = self . tcx . region_maps . node_extent ( from_expr. id ) ;
559
- let target_scope = self . tcx . region_maps . node_extent ( to_loop . loop_id ) ;
587
+ let target_scope = self . tcx . region_maps . node_extent ( scope_id ) ;
560
588
while scope != target_scope {
561
589
data. exiting_scopes . push ( scope. node_id ( & self . tcx . region_maps ) ) ;
562
590
scope = self . tcx . region_maps . encl_scope ( scope) ;
@@ -576,20 +604,42 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
576
604
self . graph . add_edge ( from_index, self . fn_exit , data) ;
577
605
}
578
606
579
- fn find_scope ( & self ,
607
+ fn find_scope_edge ( & self ,
580
608
expr : & hir:: Expr ,
581
- destination : hir:: Destination ) -> LoopScope {
582
-
583
- match destination. loop_id . into ( ) {
584
- Ok ( loop_id) => {
609
+ destination : hir:: Destination ,
610
+ scope_cf_kind : ScopeCfKind ) -> ( ast:: NodeId , CFGIndex ) {
611
+
612
+ match destination. target_id {
613
+ hir:: ScopeTarget :: Block ( block_expr_id) => {
614
+ for b in & self . breakable_block_scopes {
615
+ if b. block_expr_id == block_expr_id {
616
+ return ( block_expr_id, match scope_cf_kind {
617
+ ScopeCfKind :: Break => b. break_index ,
618
+ ScopeCfKind :: Continue => bug ! ( "can't continue to block" ) ,
619
+ } ) ;
620
+ }
621
+ }
622
+ span_bug ! ( expr. span, "no block expr for id {}" , block_expr_id) ;
623
+ }
624
+ hir:: ScopeTarget :: Loop ( hir:: LoopIdResult :: Ok ( loop_id) ) => {
585
625
for l in & self . loop_scopes {
586
626
if l. loop_id == loop_id {
587
- return * l;
627
+ return ( loop_id, match scope_cf_kind {
628
+ ScopeCfKind :: Break => l. break_index ,
629
+ ScopeCfKind :: Continue => l. continue_index ,
630
+ } ) ;
588
631
}
589
632
}
590
633
span_bug ! ( expr. span, "no loop scope for id {}" , loop_id) ;
591
634
}
592
- Err ( err) => span_bug ! ( expr. span, "loop scope error: {}" , err) ,
635
+ hir:: ScopeTarget :: Loop ( hir:: LoopIdResult :: Err ( err) ) =>
636
+ span_bug ! ( expr. span, "loop scope error: {}" , err) ,
593
637
}
594
638
}
595
639
}
640
+
641
+ #[ derive( Copy , Clone , Eq , PartialEq ) ]
642
+ enum ScopeCfKind {
643
+ Break ,
644
+ Continue ,
645
+ }
0 commit comments