@@ -21,7 +21,8 @@ struct CFGBuilder<'a> {
21
21
method_map : typeck:: MethodMap ,
22
22
exit_map : NodeMap < CFGIndex > ,
23
23
graph : CFGGraph ,
24
- loop_scopes : Vec < LoopScope > ,
24
+ fn_exit : CFGIndex ,
25
+ loop_scopes : Vec < LoopScope > ,
25
26
}
26
27
27
28
struct LoopScope {
@@ -33,20 +34,35 @@ struct LoopScope {
33
34
pub fn construct ( tcx : & ty:: ctxt ,
34
35
method_map : typeck:: MethodMap ,
35
36
blk : & ast:: Block ) -> CFG {
37
+ let mut graph = graph:: Graph :: new ( ) ;
38
+ let entry = add_initial_dummy_node ( & mut graph) ;
39
+
40
+ // `fn_exit` is target of return exprs, which lies somewhere
41
+ // outside input `blk`. (Distinguishing `fn_exit` and `block_exit`
42
+ // also resolves chicken-and-egg problem that arises if you try to
43
+ // have return exprs jump to `block_exit` during construction.)
44
+ let fn_exit = add_initial_dummy_node ( & mut graph) ;
45
+ let block_exit;
46
+
36
47
let mut cfg_builder = CFGBuilder {
37
48
exit_map : NodeMap :: new ( ) ,
38
- graph : graph:: Graph :: new ( ) ,
49
+ graph : graph,
50
+ fn_exit : fn_exit,
39
51
tcx : tcx,
40
52
method_map : method_map,
41
53
loop_scopes : Vec :: new ( )
42
54
} ;
43
- let entry = cfg_builder. add_node ( 0 , [ ] ) ;
44
- let exit = cfg_builder. block ( blk , entry ) ;
55
+ block_exit = cfg_builder. block ( blk , entry ) ;
56
+ cfg_builder. add_contained_edge ( block_exit , fn_exit ) ;
45
57
let CFGBuilder { exit_map, graph, ..} = cfg_builder;
46
58
CFG { exit_map : exit_map,
47
59
graph : graph,
48
60
entry : entry,
49
- exit : exit}
61
+ exit : fn_exit}
62
+ }
63
+
64
+ fn add_initial_dummy_node ( g : & mut CFGGraph ) -> CFGIndex {
65
+ g. add_node ( CFGNodeData { id : ast:: DUMMY_NODE_ID } )
50
66
}
51
67
52
68
impl < ' a > CFGBuilder < ' a > {
@@ -327,24 +343,25 @@ impl<'a> CFGBuilder<'a> {
327
343
328
344
ast:: ExprRet ( v) => {
329
345
let v_exit = self . opt_expr ( v, pred) ;
330
- let loop_scope = * self . loop_scopes . get ( 0 ) ;
331
- self . add_exiting_edge ( expr, v_exit,
332
- loop_scope, loop_scope. break_index ) ;
333
- self . add_node ( expr. id , [ ] )
346
+ let b = self . add_node ( expr. id , [ v_exit] ) ;
347
+ self . add_returning_edge ( expr, b) ;
348
+ self . add_node ( ast:: DUMMY_NODE_ID , [ ] )
334
349
}
335
350
336
351
ast:: ExprBreak ( label) => {
337
352
let loop_scope = self . find_scope ( expr, label) ;
338
- self . add_exiting_edge ( expr, pred,
353
+ let b = self . add_node ( expr. id , [ pred] ) ;
354
+ self . add_exiting_edge ( expr, b,
339
355
loop_scope, loop_scope. break_index ) ;
340
- self . add_node ( expr . id , [ ] )
356
+ self . add_node ( ast :: DUMMY_NODE_ID , [ ] )
341
357
}
342
358
343
359
ast:: ExprAgain ( label) => {
344
360
let loop_scope = self . find_scope ( expr, label) ;
345
- self . add_exiting_edge ( expr, pred,
361
+ let a = self . add_node ( expr. id , [ pred] ) ;
362
+ self . add_exiting_edge ( expr, a,
346
363
loop_scope, loop_scope. continue_index ) ;
347
- self . add_node ( expr . id , [ ] )
364
+ self . add_node ( ast :: DUMMY_NODE_ID , [ ] )
348
365
}
349
366
350
367
ast:: ExprVec ( ref elems) => {
@@ -453,13 +470,16 @@ impl<'a> CFGBuilder<'a> {
453
470
}
454
471
455
472
fn add_dummy_node ( & mut self , preds : & [ CFGIndex ] ) -> CFGIndex {
456
- self . add_node ( 0 , preds)
473
+ self . add_node ( ast :: DUMMY_NODE_ID , preds)
457
474
}
458
475
459
476
fn add_node ( & mut self , id : ast:: NodeId , preds : & [ CFGIndex ] ) -> CFGIndex {
460
477
assert ! ( !self . exit_map. contains_key( & id) ) ;
461
478
let node = self . graph . add_node ( CFGNodeData { id : id} ) ;
462
- self . exit_map . insert ( id, node) ;
479
+ if id != ast:: DUMMY_NODE_ID {
480
+ assert ! ( !self . exit_map. contains_key( & id) ) ;
481
+ self . exit_map . insert ( id, node) ;
482
+ }
463
483
for & pred in preds. iter ( ) {
464
484
self . add_contained_edge ( pred, node) ;
465
485
}
@@ -488,6 +508,16 @@ impl<'a> CFGBuilder<'a> {
488
508
self . graph . add_edge ( from_index, to_index, data) ;
489
509
}
490
510
511
+ fn add_returning_edge ( & mut self ,
512
+ _from_expr : @ast:: Expr ,
513
+ from_index : CFGIndex ) {
514
+ let mut data = CFGEdgeData { exiting_scopes : vec ! ( ) } ;
515
+ for & LoopScope { loop_id : id, .. } in self . loop_scopes . iter ( ) . rev ( ) {
516
+ data. exiting_scopes . push ( id) ;
517
+ }
518
+ self . graph . add_edge ( from_index, self . fn_exit , data) ;
519
+ }
520
+
491
521
fn find_scope ( & self ,
492
522
expr : @ast:: Expr ,
493
523
label : Option < ast:: Ident > ) -> LoopScope {
0 commit comments