@@ -22,13 +22,20 @@ struct CFGBuilder<'a, 'tcx: 'a> {
2222 graph : CFGGraph ,
2323 fn_exit : CFGIndex ,
2424 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`
2532}
2633
2734#[ derive( Copy , Clone ) ]
2835struct LoopScope {
2936 loop_id : ast:: NodeId , // id of loop/while node
3037 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`
3239}
3340
3441pub fn construct < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
@@ -53,6 +60,7 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
5360 graph : graph,
5461 fn_exit : fn_exit,
5562 loop_scopes : Vec :: new ( ) ,
63+ breakable_block_scopes : Vec :: new ( ) ,
5664 } ;
5765 body_exit = cfg_builder. expr ( & body. value , entry) ;
5866 cfg_builder. add_contained_edge ( body_exit, fn_exit) ;
@@ -66,14 +74,34 @@ pub fn construct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
6674
6775impl < ' a , ' tcx > CFGBuilder < ' a , ' tcx > {
6876 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+ }
73100
74- let expr_exit = self . opt_expr ( & blk. expr , stmts_exit) ;
101+ let expr_exit = self . opt_expr ( & blk. expr , stmts_exit) ;
75102
76- self . add_ast_node ( blk. id , & [ expr_exit] )
103+ self . add_ast_node ( blk. id , & [ expr_exit] )
104+ }
77105 }
78106
79107 fn stmt ( & mut self , stmt : & hir:: Stmt , pred : CFGIndex ) -> CFGIndex {
@@ -295,18 +323,18 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
295323
296324 hir:: ExprBreak ( destination, ref opt_expr) => {
297325 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 ) ;
299328 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) ;
302330 self . add_unreachable_node ( )
303331 }
304332
305333 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 ) ;
307336 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) ;
310338 self . add_unreachable_node ( )
311339 }
312340
@@ -552,11 +580,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
552580 fn add_exiting_edge ( & mut self ,
553581 from_expr : & hir:: Expr ,
554582 from_index : CFGIndex ,
555- to_loop : LoopScope ,
583+ scope_id : ast :: NodeId ,
556584 to_index : CFGIndex ) {
557585 let mut data = CFGEdgeData { exiting_scopes : vec ! [ ] } ;
558586 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 ) ;
560588 while scope != target_scope {
561589 data. exiting_scopes . push ( scope. node_id ( & self . tcx . region_maps ) ) ;
562590 scope = self . tcx . region_maps . encl_scope ( scope) ;
@@ -576,20 +604,42 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
576604 self . graph . add_edge ( from_index, self . fn_exit , data) ;
577605 }
578606
579- fn find_scope ( & self ,
607+ fn find_scope_edge ( & self ,
580608 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) ) => {
585625 for l in & self . loop_scopes {
586626 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+ } ) ;
588631 }
589632 }
590633 span_bug ! ( expr. span, "no loop scope for id {}" , loop_id) ;
591634 }
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) ,
593637 }
594638 }
595639}
640+
641+ #[ derive( Copy , Clone , Eq , PartialEq ) ]
642+ enum ScopeCfKind {
643+ Break ,
644+ Continue ,
645+ }
0 commit comments