@@ -130,6 +130,7 @@ tag cleanup {
130130
131131tag block_kind {
132132 SCOPE_BLOCK ;
133+ LOOP_SCOPE_BLOCK ( option. t [ @block_ctxt] , @block_ctxt) ;
133134 NON_SCOPE_BLOCK ;
134135}
135136
@@ -990,7 +991,7 @@ fn trans_non_gc_free(@block_ctxt cx, ValueRef v) -> result {
990991}
991992
992993fn find_scope_cx ( @block_ctxt cx ) -> @block_ctxt {
993- if ( cx. kind == SCOPE_BLOCK ) {
994+ if ( cx. kind != NON_SCOPE_BLOCK ) {
994995 ret cx;
995996 }
996997 alt ( cx. parent ) {
@@ -3043,13 +3044,15 @@ fn trans_for(@block_ctxt cx,
30433044 @ast. decl decl,
30443045 @ast. expr seq,
30453046 & ast. block body) -> result {
3046-
30473047 fn inner( @block_ctxt cx,
30483048 @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 {
30503051
3051- auto scope_cx = new_scope_block_ctxt( cx, "for loop scope") ;
30523052 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") ;
30533056
30543057 cx. build. Br ( scope_cx. llbb) ;
30553058 auto local_res = alloc_local( scope_cx, local) ;
@@ -3069,10 +3072,13 @@ fn trans_for(@block_ctxt cx,
30693072 }
30703073 }
30713074
3075+ auto next_cx = new_sub_block_ctxt( cx, "next") ;
30723076 auto seq_ty = ty. expr_ty( seq) ;
30733077 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) ;
30763082}
30773083
30783084
@@ -3308,8 +3314,9 @@ fn trans_while(@block_ctxt cx, @ast.expr cond,
33083314 & ast. block body) -> result {
33093315
33103316 auto cond_cx = new_scope_block_ctxt( cx, "while cond") ;
3311- auto body_cx = new_scope_block_ctxt( cx, "while loop body") ;
33123317 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") ;
33133320
33143321 auto body_res = trans_block( body_cx, body) ;
33153322 auto cond_res = trans_expr( cond_cx, cond) ;
@@ -3326,8 +3333,9 @@ fn trans_while(@block_ctxt cx, @ast.expr cond,
33263333fn trans_do_while( @block_ctxt cx, & ast. block body,
33273334 @ast. expr cond) -> result {
33283335
3329- auto body_cx = new_scope_block_ctxt( cx, "do-while loop body") ;
33303336 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") ;
33313339
33323340 auto body_res = trans_block( body_cx, body) ;
33333341 auto cond_res = trans_expr( body_res. bcx, cond) ;
@@ -4599,6 +4607,14 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result {
45994607 ret trans_check_expr( cx, a) ;
46004608 }
46014609
4610+ case ( ast. expr_break) {
4611+ ret trans_break( cx) ;
4612+ }
4613+
4614+ case ( ast. expr_cont) {
4615+ ret trans_cont( cx) ;
4616+ }
4617+
46024618 case ( ast. expr_ret( ?e) ) {
46034619 ret trans_ret( cx, e) ;
46044620 }
@@ -4770,6 +4786,47 @@ fn trans_put(@block_ctxt cx, &option.t[@ast.expr] e) -> result {
47704786 ret res( bcx, bcx. build. FastCall ( llcallee, llargs) ) ;
47714787}
47724788
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+
47734830fn trans_ret( @block_ctxt cx, & option. t[ @ast. expr] e) -> result {
47744831 auto bcx = cx;
47754832 auto val = C_nil ( ) ;
@@ -5033,6 +5090,12 @@ fn new_scope_block_ctxt(@block_ctxt bcx, str n) -> @block_ctxt {
50335090 ret new_block_ctxt( bcx. fcx, parent_some( bcx) , SCOPE_BLOCK , n) ;
50345091}
50355092
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+
50365099// Use this when you're making a general CFG BB within a scope.
50375100fn new_sub_block_ctxt( @block_ctxt bcx, str n) -> @block_ctxt {
50385101 ret new_block_ctxt( bcx. fcx, parent_some( bcx) , NON_SCOPE_BLOCK , n) ;
@@ -5043,7 +5106,7 @@ fn trans_block_cleanups(@block_ctxt cx,
50435106 @block_ctxt cleanup_cx) -> @block_ctxt {
50445107 auto bcx = cx;
50455108
5046- if ( cleanup_cx. kind != SCOPE_BLOCK ) {
5109+ if ( cleanup_cx. kind == NON_SCOPE_BLOCK ) {
50475110 check ( _vec. len[ cleanup] ( cleanup_cx. cleanups) == 0 u) ;
50485111 }
50495112
0 commit comments