@@ -2516,15 +2516,43 @@ fn trans_cast(cx: block, e: @ast::expr, id: ast::node_id,
25162516 ret store_in_dest ( e_res. bcx , newval, dest) ;
25172517}
25182518
2519+ fn trans_loop_body ( bcx : block , e : @ast:: expr , ret_flag : option < ValueRef > ,
2520+ dest : dest ) -> block {
2521+ alt check e. node {
2522+ ast:: expr_loop_body ( b @@{ node : ast:: expr_fn_block ( decl, body) , _} ) {
2523+ alt check ty:: get ( expr_ty ( bcx, e) ) . struct {
2524+ ty:: ty_fn ( { proto, _} ) {
2525+ closure:: trans_expr_fn ( bcx, proto, decl, body, e. span , b. id ,
2526+ { copies: [ ] , moves: [ ] } , some ( ret_flag) ,
2527+ dest)
2528+ }
2529+ }
2530+ }
2531+ }
2532+ }
2533+
25192534// temp_cleanups: cleanups that should run only if failure occurs before the
25202535// call takes place:
25212536fn trans_arg_expr ( cx : block , arg : ty:: arg , lldestty : TypeRef , e : @ast:: expr ,
2522- & temp_cleanups: [ ValueRef ] ) -> result {
2537+ & temp_cleanups: [ ValueRef ] , ret_flag : option < ValueRef > )
2538+ -> result {
25232539 let _icx = cx. insn_ctxt ( "trans_arg_expr" ) ;
25242540 let ccx = cx. ccx ( ) ;
25252541 let e_ty = expr_ty ( cx, e) ;
25262542 let is_bot = ty:: type_is_bot ( e_ty) ;
2527- let lv = trans_temp_lval ( cx, e) ;
2543+ let lv = alt ret_flag {
2544+ // If there is a ret_flag, this *must* be a loop body
2545+ some( ptr) {
2546+ alt check e. node {
2547+ ast:: expr_loop_body ( blk) {
2548+ let scratch = alloc_ty ( cx, expr_ty ( cx, blk) ) ;
2549+ let bcx = trans_loop_body ( cx, e, ret_flag, save_in ( scratch) ) ;
2550+ { bcx: bcx, val: scratch, kind: temporary}
2551+ }
2552+ }
2553+ }
2554+ none { trans_temp_lval( cx, e) }
2555+ } ;
25282556 let mut bcx = lv. bcx ;
25292557 let mut val = lv. val ;
25302558 let arg_mode = ty:: resolved_mode ( ccx. tcx , arg. mode ) ;
@@ -2595,7 +2623,7 @@ enum call_args {
25952623// - new_fn_ctxt
25962624// - trans_args
25972625fn trans_args ( cx : block , llenv : ValueRef , args : call_args , fn_ty : ty:: t ,
2598- dest : dest )
2626+ dest : dest , ret_flag : option < ValueRef > )
25992627 -> { bcx : block, args : [ ValueRef ] , retslot : ValueRef } {
26002628 let _icx = cx. insn_ctxt ( "trans_args" ) ;
26012629 let mut temp_cleanups = [ ] ;
@@ -2630,13 +2658,13 @@ fn trans_args(cx: block, llenv: ValueRef, args: call_args, fn_ty: ty::t,
26302658 alt args {
26312659 arg_exprs( es) {
26322660 let llarg_tys = type_of_explicit_args ( ccx, arg_tys) ;
2633- let mut i = 0 u ;
2634- for e : @ast :: expr in es {
2661+ let last = es . len ( ) - 1 u ;
2662+ vec :: iteri ( es ) { |i , e|
26352663 let r = trans_arg_expr ( bcx, arg_tys[ i] , llarg_tys[ i] ,
2636- e, temp_cleanups) ;
2664+ e, temp_cleanups, if i == last { ret_flag }
2665+ else { none } ) ;
26372666 bcx = r. bcx ;
26382667 llargs += [ r. val ] ;
2639- i += 1 u;
26402668 }
26412669 }
26422670 arg_vals ( vs) {
@@ -2664,14 +2692,44 @@ fn trans_call(in_cx: block, f: @ast::expr,
26642692 { |cx| trans_callee ( cx, f) } , args, dest)
26652693}
26662694
2695+ fn body_contains_ret ( body : ast:: blk ) -> bool {
2696+ let cx = { mut found: false } ;
2697+ visit:: visit_block ( body, cx, visit:: mk_vt ( @{
2698+ visit_item : { |_i, _cx, _v|} ,
2699+ visit_expr : { |e : @ast:: expr, cx : { mut found: bool} , v|
2700+ if !cx. found {
2701+ alt e. node {
2702+ ast:: expr_ret ( _) { cx. found = true ; }
2703+ _ { visit : : visit_expr ( e, cx, v) ; }
2704+ }
2705+ }
2706+ } with * visit:: default_visitor ( )
2707+ } ) ) ;
2708+ cx. found
2709+ }
2710+
26672711fn trans_call_inner ( in_cx : block , fn_expr_ty : ty:: t , ret_ty : ty:: t ,
26682712 get_callee : fn ( block ) -> lval_maybe_callee ,
26692713 args : call_args , dest : dest )
26702714 -> block {
2715+ let ret_in_loop = alt args {
2716+ arg_exprs( args) { args. len ( ) > 0 u && alt vec:: last ( args) . node {
2717+ ast:: expr_loop_body ( @{ node: ast:: expr_fn_block ( _, body) , _} ) {
2718+ body_contains_ret ( body)
2719+ }
2720+ _ { false }
2721+ } }
2722+ _ { false }
2723+ } ;
26712724 with_scope ( in_cx, "call" ) { |cx|
26722725 let f_res = get_callee ( cx) ;
26732726 let mut bcx = f_res. bcx ;
26742727 let ccx = cx. ccx ( ) ;
2728+ let ret_flag = if ret_in_loop {
2729+ let flag = alloca ( in_cx, T_bool ( ) ) ;
2730+ Store ( cx, C_bool ( false ) , flag) ;
2731+ some ( flag)
2732+ } else { none } ;
26752733
26762734 let mut faddr = f_res. val ;
26772735 let llenv = alt f_res. env {
@@ -2695,7 +2753,7 @@ fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t, ret_ty: ty::t,
26952753 } ;
26962754
26972755 let args_res = {
2698- trans_args ( bcx, llenv, args, fn_expr_ty, dest)
2756+ trans_args ( bcx, llenv, args, fn_expr_ty, dest, ret_flag )
26992757 } ;
27002758 bcx = args_res. bcx ;
27012759 let mut llargs = args_res. args ;
@@ -2718,7 +2776,19 @@ fn trans_call_inner(in_cx: block, fn_expr_ty: ty::t, ret_ty: ty::t,
27182776 * cell = Load ( bcx, llretslot) ;
27192777 }
27202778 }
2721- if ty:: type_is_bot ( ret_ty) { Unreachable ( bcx) ; }
2779+ if ty:: type_is_bot ( ret_ty) {
2780+ Unreachable ( bcx) ;
2781+ } else if ret_in_loop {
2782+ bcx = with_cond ( bcx, Load ( bcx, option:: get ( ret_flag) ) ) { |bcx|
2783+ option:: may ( bcx. fcx . loop_ret ) { |lret|
2784+ Store ( bcx, C_bool ( true ) , lret. flagptr ) ;
2785+ Store ( bcx, C_bool ( false ) , bcx. fcx . llretptr ) ;
2786+ }
2787+ cleanup_and_leave ( bcx, none, some ( bcx. fcx . llreturn ) ) ;
2788+ Unreachable ( bcx) ;
2789+ bcx
2790+ }
2791+ }
27222792 bcx
27232793 }
27242794}
@@ -2991,25 +3061,20 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
29913061 ast:: expr_addr_of ( _, x) { ret trans_addr_of ( bcx, x, dest) ; }
29923062 ast:: expr_fn ( proto, decl, body, cap_clause) {
29933063 ret closure:: trans_expr_fn ( bcx, proto, decl, body, e. span , e. id ,
2994- * cap_clause, false , dest) ;
3064+ * cap_clause, none , dest) ;
29953065 }
29963066 ast:: expr_fn_block ( decl, body) {
29973067 alt check ty:: get ( expr_ty ( bcx, e) ) . struct {
29983068 ty:: ty_fn ( { proto, _} ) {
29993069 #debug ( "translating fn_block %s with type %s" ,
30003070 expr_to_str ( e) , ty_to_str ( tcx, expr_ty ( bcx, e) ) ) ;
30013071 ret closure:: trans_expr_fn ( bcx, proto, decl, body, e. span , e. id ,
3002- { copies: [ ] , moves: [ ] } , false , dest) ;
3072+ { copies: [ ] , moves: [ ] } , none , dest) ;
30033073 }
30043074 }
30053075 }
3006- ast:: expr_loop_body ( b @@{ node : ast:: expr_fn_block ( decl, body) , _} ) {
3007- alt check ty:: get ( expr_ty ( bcx, e) ) . struct {
3008- ty:: ty_fn ( { proto, _} ) {
3009- ret closure:: trans_expr_fn ( bcx, proto, decl, body, e. span , b. id ,
3010- { copies: [ ] , moves: [ ] } , true , dest) ;
3011- }
3012- }
3076+ ast:: expr_loop_body ( blk) {
3077+ ret trans_loop_body ( bcx, e, none, dest) ;
30133078 }
30143079 ast:: expr_bind ( f, args) {
30153080 ret closure:: trans_bind (
@@ -3406,8 +3471,25 @@ fn trans_cont(cx: block) -> block {
34063471fn trans_ret ( bcx : block , e : option < @ast:: expr > ) -> block {
34073472 let _icx = bcx. insn_ctxt ( "trans_ret" ) ;
34083473 let mut bcx = bcx;
3474+ let retptr = alt bcx. fcx . loop_ret {
3475+ some ( { flagptr, retptr} ) {
3476+ // This is a loop body return. Must set continue flag (our retptr)
3477+ // to false, return flag to true, and then store the value in the
3478+ // parent's retptr.
3479+ Store ( bcx, C_bool ( true ) , flagptr) ;
3480+ Store ( bcx, C_bool ( false ) , bcx. fcx . llretptr ) ;
3481+ alt e {
3482+ some( x) { PointerCast ( bcx, retptr,
3483+ T_ptr ( type_of ( bcx. ccx ( ) , expr_ty ( bcx, x) ) ) ) }
3484+ none { retptr }
3485+ }
3486+ }
3487+ none { bcx. fcx . llretptr }
3488+ } ;
34093489 alt e {
3410- some( x) { bcx = trans_expr_save_in ( bcx, x, bcx. fcx . llretptr ) ; }
3490+ some( x) {
3491+ bcx = trans_expr_save_in ( bcx, x, retptr) ;
3492+ }
34113493 _ { }
34123494 }
34133495 cleanup_and_leave ( bcx, none, some ( bcx. fcx . llreturn ) ) ;
@@ -3793,6 +3875,7 @@ fn new_fn_ctxt_w_id(ccx: @crate_ctxt, path: path,
37933875 mut llreturn : llbbs. rt ,
37943876 mut llself : none,
37953877 mut personality : none,
3878+ mut loop_ret : none,
37963879 llargs : int_hash :: < local_val > ( ) ,
37973880 lllocals : int_hash :: < local_val > ( ) ,
37983881 llupvars : int_hash :: < ValueRef > ( ) ,
0 commit comments