@@ -2516,15 +2516,43 @@ fn trans_cast(cx: block, e: @ast::expr, id: ast::node_id,
2516
2516
ret store_in_dest ( e_res. bcx , newval, dest) ;
2517
2517
}
2518
2518
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
+
2519
2534
// temp_cleanups: cleanups that should run only if failure occurs before the
2520
2535
// call takes place:
2521
2536
fn 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 {
2523
2539
let _icx = cx. insn_ctxt ( "trans_arg_expr" ) ;
2524
2540
let ccx = cx. ccx ( ) ;
2525
2541
let e_ty = expr_ty ( cx, e) ;
2526
2542
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
+ } ;
2528
2556
let mut bcx = lv. bcx ;
2529
2557
let mut val = lv. val ;
2530
2558
let arg_mode = ty:: resolved_mode ( ccx. tcx , arg. mode ) ;
@@ -2595,7 +2623,7 @@ enum call_args {
2595
2623
// - new_fn_ctxt
2596
2624
// - trans_args
2597
2625
fn trans_args ( cx : block , llenv : ValueRef , args : call_args , fn_ty : ty:: t ,
2598
- dest : dest )
2626
+ dest : dest , ret_flag : option < ValueRef > )
2599
2627
-> { bcx : block, args : [ ValueRef ] , retslot : ValueRef } {
2600
2628
let _icx = cx. insn_ctxt ( "trans_args" ) ;
2601
2629
let mut temp_cleanups = [ ] ;
@@ -2630,13 +2658,13 @@ fn trans_args(cx: block, llenv: ValueRef, args: call_args, fn_ty: ty::t,
2630
2658
alt args {
2631
2659
arg_exprs( es) {
2632
2660
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|
2635
2663
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 } ) ;
2637
2666
bcx = r. bcx ;
2638
2667
llargs += [ r. val ] ;
2639
- i += 1 u;
2640
2668
}
2641
2669
}
2642
2670
arg_vals ( vs) {
@@ -2664,14 +2692,44 @@ fn trans_call(in_cx: block, f: @ast::expr,
2664
2692
{ |cx| trans_callee ( cx, f) } , args, dest)
2665
2693
}
2666
2694
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
+
2667
2711
fn trans_call_inner ( in_cx : block , fn_expr_ty : ty:: t , ret_ty : ty:: t ,
2668
2712
get_callee : fn ( block ) -> lval_maybe_callee ,
2669
2713
args : call_args , dest : dest )
2670
2714
-> 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
+ } ;
2671
2724
with_scope ( in_cx, "call" ) { |cx|
2672
2725
let f_res = get_callee ( cx) ;
2673
2726
let mut bcx = f_res. bcx ;
2674
2727
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 } ;
2675
2733
2676
2734
let mut faddr = f_res. val ;
2677
2735
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,
2695
2753
} ;
2696
2754
2697
2755
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 )
2699
2757
} ;
2700
2758
bcx = args_res. bcx ;
2701
2759
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,
2718
2776
* cell = Load ( bcx, llretslot) ;
2719
2777
}
2720
2778
}
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
+ }
2722
2792
bcx
2723
2793
}
2724
2794
}
@@ -2991,25 +3061,20 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
2991
3061
ast:: expr_addr_of ( _, x) { ret trans_addr_of ( bcx, x, dest) ; }
2992
3062
ast:: expr_fn ( proto, decl, body, cap_clause) {
2993
3063
ret closure:: trans_expr_fn ( bcx, proto, decl, body, e. span , e. id ,
2994
- * cap_clause, false , dest) ;
3064
+ * cap_clause, none , dest) ;
2995
3065
}
2996
3066
ast:: expr_fn_block ( decl, body) {
2997
3067
alt check ty:: get ( expr_ty ( bcx, e) ) . struct {
2998
3068
ty:: ty_fn ( { proto, _} ) {
2999
3069
#debug ( "translating fn_block %s with type %s" ,
3000
3070
expr_to_str ( e) , ty_to_str ( tcx, expr_ty ( bcx, e) ) ) ;
3001
3071
ret closure:: trans_expr_fn ( bcx, proto, decl, body, e. span , e. id ,
3002
- { copies: [ ] , moves: [ ] } , false , dest) ;
3072
+ { copies: [ ] , moves: [ ] } , none , dest) ;
3003
3073
}
3004
3074
}
3005
3075
}
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) ;
3013
3078
}
3014
3079
ast:: expr_bind ( f, args) {
3015
3080
ret closure:: trans_bind (
@@ -3406,8 +3471,25 @@ fn trans_cont(cx: block) -> block {
3406
3471
fn trans_ret ( bcx : block , e : option < @ast:: expr > ) -> block {
3407
3472
let _icx = bcx. insn_ctxt ( "trans_ret" ) ;
3408
3473
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
+ } ;
3409
3489
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
+ }
3411
3493
_ { }
3412
3494
}
3413
3495
cleanup_and_leave ( bcx, none, some ( bcx. fcx . llreturn ) ) ;
@@ -3793,6 +3875,7 @@ fn new_fn_ctxt_w_id(ccx: @crate_ctxt, path: path,
3793
3875
mut llreturn : llbbs. rt ,
3794
3876
mut llself : none,
3795
3877
mut personality : none,
3878
+ mut loop_ret : none,
3796
3879
llargs : int_hash :: < local_val > ( ) ,
3797
3880
lllocals : int_hash :: < local_val > ( ) ,
3798
3881
llupvars : int_hash :: < ValueRef > ( ) ,
0 commit comments