@@ -130,6 +130,7 @@ tag cleanup {
130
130
131
131
tag block_kind {
132
132
SCOPE_BLOCK ;
133
+ LOOP_SCOPE_BLOCK ( option. t [ @block_ctxt] , @block_ctxt) ;
133
134
NON_SCOPE_BLOCK ;
134
135
}
135
136
@@ -990,7 +991,7 @@ fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
990
991
}
991
992
992
993
fn find_scope_cx ( @block_ctxt cx ) -> @block_ctxt {
993
- if ( cx. kind == SCOPE_BLOCK ) {
994
+ if ( cx. kind != NON_SCOPE_BLOCK ) {
994
995
ret cx;
995
996
}
996
997
alt ( cx. parent ) {
@@ -3043,13 +3044,15 @@ fn trans_for(@block_ctxt cx,
3043
3044
@ast. decl decl,
3044
3045
@ast. expr seq,
3045
3046
& ast. block body) -> result {
3046
-
3047
3047
fn inner( @block_ctxt cx,
3048
3048
@ast. local local, ValueRef curr,
3049
- @ty. t t, ast. block body) -> result {
3049
+ @ty. t t, ast. block body,
3050
+ @block_ctxt outer_next_cx) -> result {
3050
3051
3051
- auto scope_cx = new_scope_block_ctxt( cx, "for loop scope") ;
3052
3052
auto next_cx = new_sub_block_ctxt( cx, "next") ;
3053
+ auto scope_cx =
3054
+ new_loop_scope_block_ctxt( cx, option. some[ @block_ctxt] ( next_cx) ,
3055
+ outer_next_cx, "for loop scope") ;
3053
3056
3054
3057
cx. build. Br ( scope_cx. llbb) ;
3055
3058
auto local_res = alloc_local( scope_cx, local) ;
@@ -3069,10 +3072,13 @@ fn trans_for(@block_ctxt cx,
3069
3072
}
3070
3073
}
3071
3074
3075
+ auto next_cx = new_sub_block_ctxt( cx, "next") ;
3072
3076
auto seq_ty = ty. expr_ty( seq) ;
3073
3077
auto seq_res = trans_expr( cx, seq) ;
3074
- ret iter_sequence( seq_res. bcx, seq_res. val, seq_ty,
3075
- bind inner( _, local, _, _, body) ) ;
3078
+ auto it = iter_sequence( seq_res. bcx, seq_res. val, seq_ty,
3079
+ bind inner( _, local, _, _, body, next_cx) ) ;
3080
+ it. bcx. build. Br ( next_cx. llbb) ;
3081
+ ret res( next_cx, it. val) ;
3076
3082
}
3077
3083
3078
3084
@@ -3308,8 +3314,9 @@ fn trans_while(@block_ctxt cx, @ast.expr cond,
3308
3314
& ast. block body) -> result {
3309
3315
3310
3316
auto cond_cx = new_scope_block_ctxt( cx, "while cond") ;
3311
- auto body_cx = new_scope_block_ctxt( cx, "while loop body") ;
3312
3317
auto next_cx = new_sub_block_ctxt( cx, "next") ;
3318
+ auto body_cx = new_loop_scope_block_ctxt( cx, option. none[ @block_ctxt] ,
3319
+ next_cx, "while loop body") ;
3313
3320
3314
3321
auto body_res = trans_block( body_cx, body) ;
3315
3322
auto cond_res = trans_expr( cond_cx, cond) ;
@@ -3326,8 +3333,9 @@ fn trans_while(@block_ctxt cx, @ast.expr cond,
3326
3333
fn trans_do_while( @block_ctxt cx, & ast. block body,
3327
3334
@ast. expr cond) -> result {
3328
3335
3329
- auto body_cx = new_scope_block_ctxt( cx, "do-while loop body") ;
3330
3336
auto next_cx = new_sub_block_ctxt( cx, "next") ;
3337
+ auto body_cx = new_loop_scope_block_ctxt( cx, option. none[ @block_ctxt] ,
3338
+ next_cx, "do-while loop body") ;
3331
3339
3332
3340
auto body_res = trans_block( body_cx, body) ;
3333
3341
auto cond_res = trans_expr( body_res. bcx, cond) ;
@@ -4599,6 +4607,14 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
4599
4607
ret trans_check_expr( cx, a) ;
4600
4608
}
4601
4609
4610
+ case ( ast. expr_break) {
4611
+ ret trans_break( cx) ;
4612
+ }
4613
+
4614
+ case ( ast. expr_cont) {
4615
+ ret trans_cont( cx) ;
4616
+ }
4617
+
4602
4618
case ( ast. expr_ret( ?e) ) {
4603
4619
ret trans_ret( cx, e) ;
4604
4620
}
@@ -4770,6 +4786,47 @@ fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
4770
4786
ret res( bcx, bcx. build. FastCall ( llcallee, llargs) ) ;
4771
4787
}
4772
4788
4789
+ fn trans_break_cont( @block_ctxt cx, bool to_end) -> result {
4790
+ auto bcx = cx;
4791
+ // Locate closest loop block, outputting cleanup as we go.
4792
+ auto cleanup_cx = cx;
4793
+ while ( true) {
4794
+ bcx = trans_block_cleanups( bcx, cleanup_cx) ;
4795
+ alt ( cleanup_cx. kind) {
4796
+ case ( LOOP_SCOPE_BLOCK ( ?_cont, ?_break) ) {
4797
+ if ( to_end) {
4798
+ bcx. build. Br ( _break. llbb) ;
4799
+ } else {
4800
+ alt ( _cont) {
4801
+ case ( option. some[ @block_ctxt] ( ?_cont) ) {
4802
+ bcx. build. Br ( _cont. llbb) ;
4803
+ }
4804
+ case ( _) {
4805
+ bcx. build. Br ( cleanup_cx. llbb) ;
4806
+ }
4807
+ }
4808
+ }
4809
+ ret res( new_sub_block_ctxt( cx, "unreachable") , C_nil ( ) ) ;
4810
+ }
4811
+ case ( _) {
4812
+ alt ( cleanup_cx. parent) {
4813
+ case ( parent_some( ?cx) ) { cleanup_cx = cx; }
4814
+ }
4815
+ }
4816
+ }
4817
+ }
4818
+ ret res( cx, C_nil ( ) ) ; // Never reached. Won't compile otherwise.
4819
+ }
4820
+
4821
+ fn trans_break( @block_ctxt cx) -> result {
4822
+ ret trans_break_cont( cx, true) ;
4823
+ }
4824
+
4825
+ fn trans_cont( @block_ctxt cx) -> result {
4826
+ ret trans_break_cont( cx, false) ;
4827
+ }
4828
+
4829
+
4773
4830
fn trans_ret( @block_ctxt cx, & option. t[ @ast. expr] e) -> result {
4774
4831
auto bcx = cx;
4775
4832
auto val = C_nil ( ) ;
@@ -5033,6 +5090,12 @@ fn new_scope_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
5033
5090
ret new_block_ctxt( bcx. fcx, parent_some( bcx) , SCOPE_BLOCK , n) ;
5034
5091
}
5035
5092
5093
+ fn new_loop_scope_block_ctxt( @block_ctxt bcx, option. t[ @block_ctxt] _cont,
5094
+ @block_ctxt _break, str n) -> @block_ctxt {
5095
+ ret new_block_ctxt( bcx. fcx, parent_some( bcx) ,
5096
+ LOOP_SCOPE_BLOCK ( _cont, _break) , n) ;
5097
+ }
5098
+
5036
5099
// Use this when you're making a general CFG BB within a scope.
5037
5100
fn new_sub_block_ctxt( @block_ctxt bcx, str n) -> @block_ctxt {
5038
5101
ret new_block_ctxt( bcx. fcx, parent_some( bcx) , NON_SCOPE_BLOCK , n) ;
@@ -5043,7 +5106,7 @@ fn trans_block_cleanups(@block_ctxt cx,
5043
5106
@block_ctxt cleanup_cx) -> @block_ctxt {
5044
5107
auto bcx = cx;
5045
5108
5046
- if ( cleanup_cx. kind != SCOPE_BLOCK ) {
5109
+ if ( cleanup_cx. kind == NON_SCOPE_BLOCK ) {
5047
5110
check ( _vec. len[ cleanup] ( cleanup_cx. cleanups) == 0 u) ;
5048
5111
}
5049
5112
0 commit comments