@@ -1517,13 +1517,13 @@ fn trans_unary(bcx: block, op: ast::unop, e: @ast::expr,
1517
1517
let _icx = bcx. insn_ctxt ( "trans_unary" ) ;
1518
1518
// Check for user-defined method call
1519
1519
alt bcx. ccx ( ) . maps . method_map . find ( un_expr. id ) {
1520
- some ( origin ) {
1520
+ some ( mentry ) {
1521
1521
let callee_id = ast_util:: op_expr_callee_id ( un_expr) ;
1522
1522
let fty = node_id_type ( bcx, callee_id) ;
1523
1523
ret trans_call_inner (
1524
1524
bcx, un_expr. info ( ) , fty,
1525
1525
expr_ty ( bcx, un_expr) ,
1526
- { |bcx| impl:: trans_method_callee ( bcx, callee_id, e, origin ) } ,
1526
+ { |bcx| impl:: trans_method_callee ( bcx, callee_id, e, mentry ) } ,
1527
1527
arg_exprs ( [ ] ) , dest) ;
1528
1528
}
1529
1529
_ { }
@@ -1814,14 +1814,17 @@ fn root_value(bcx: block, val: ValueRef, ty: ty::t,
1814
1814
add_root_cleanup ( bcx, scope_id, root_loc, ty) ;
1815
1815
}
1816
1816
1817
+ // autoderefs the value `v`, either as many times as we can (if `max ==
1818
+ // uint::max_value`) or `max` times.
1817
1819
fn autoderef ( cx : block , e_id : ast:: node_id ,
1818
- v : ValueRef , t : ty:: t ) -> result_t {
1820
+ v : ValueRef , t : ty:: t ,
1821
+ max : uint ) -> result_t {
1819
1822
let _icx = cx. insn_ctxt ( "autoderef" ) ;
1820
1823
let mut v1: ValueRef = v;
1821
1824
let mut t1: ty:: t = t;
1822
1825
let ccx = cx. ccx ( ) ;
1823
1826
let mut derefs = 0 u;
1824
- loop {
1827
+ while derefs < max {
1825
1828
#debug[ "autoderef(e_id=%d, v1=%s, t1=%s, derefs=%u)" ,
1826
1829
e_id, val_str ( ccx. tn , v1) , ty_to_str ( ccx. tcx , t1) ,
1827
1830
derefs] ;
@@ -1872,6 +1875,11 @@ fn autoderef(cx: block, e_id: ast::node_id,
1872
1875
}
1873
1876
v1 = load_if_immediate ( cx, v1, t1) ;
1874
1877
}
1878
+
1879
+ // either we were asked to deref a specific number of times, in which case
1880
+ // we should have, or we asked to deref as many times as we can
1881
+ assert derefs == max || max == uint:: max_value;
1882
+
1875
1883
ret { bcx : cx, val : v1, ty : t1} ;
1876
1884
}
1877
1885
@@ -2572,7 +2580,9 @@ fn trans_rec_field(bcx: block, base: @ast::expr,
2572
2580
field : ast:: ident ) -> lval_result {
2573
2581
let _icx = bcx. insn_ctxt ( "trans_rec_field" ) ;
2574
2582
let { bcx, val} = trans_temp_expr ( bcx, base) ;
2575
- let { bcx, val, ty} = autoderef ( bcx, base. id , val, expr_ty ( bcx, base) ) ;
2583
+ let { bcx, val, ty} =
2584
+ autoderef ( bcx, base. id , val, expr_ty ( bcx, base) ,
2585
+ uint:: max_value) ;
2576
2586
trans_rec_field_inner ( bcx, val, ty, field, base. span )
2577
2587
}
2578
2588
@@ -2611,7 +2621,7 @@ fn trans_index(cx: block, ex: @ast::expr, base: @ast::expr,
2611
2621
let _icx = cx. insn_ctxt ( "trans_index" ) ;
2612
2622
let base_ty = expr_ty ( cx, base) ;
2613
2623
let exp = trans_temp_expr ( cx, base) ;
2614
- let lv = autoderef ( exp. bcx , base. id , exp. val , base_ty) ;
2624
+ let lv = autoderef ( exp. bcx , base. id , exp. val , base_ty, uint :: max_value ) ;
2615
2625
let ix = trans_temp_expr ( lv. bcx , idx) ;
2616
2626
let v = lv. val ;
2617
2627
let bcx = ix. bcx ;
@@ -2921,13 +2931,16 @@ fn trans_loop_body(bcx: block, e: @ast::expr, ret_flag: option<ValueRef>,
2921
2931
// temp_cleanups: cleanups that should run only if failure occurs before the
2922
2932
// call takes place:
2923
2933
fn trans_arg_expr( cx: block, arg: ty:: arg, lldestty: TypeRef , e: @ast:: expr,
2924
- & temp_cleanups: [ ValueRef ] , ret_flag: option<ValueRef >)
2934
+ & temp_cleanups: [ ValueRef ] , ret_flag: option<ValueRef >,
2935
+ derefs: uint)
2925
2936
-> result {
2926
2937
#debug( "+++ trans_arg_expr on %s" , expr_to_str ( e) ) ;
2927
2938
let _icx = cx. insn_ctxt ( "trans_arg_expr" ) ;
2928
2939
let ccx = cx. ccx ( ) ;
2929
2940
let e_ty = expr_ty ( cx, e) ;
2930
2941
let is_bot = ty:: type_is_bot ( e_ty) ;
2942
+
2943
+ // translate the arg expr as an lvalue
2931
2944
let lv = alt ret_flag {
2932
2945
// If there is a ret_flag, this *must* be a loop body
2933
2946
some( ptr) {
@@ -2939,93 +2952,111 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
2939
2952
}
2940
2953
}
2941
2954
}
2942
- none { trans_temp_lval( cx, e) }
2955
+ none {
2956
+ trans_temp_lval( cx, e)
2957
+ }
2943
2958
} ;
2959
+
2960
+ // auto-deref value as required (this only applies to method
2961
+ // call receivers) of method
2962
+ #debug( " pre-deref value: %s", val_str ( lv. bcx . ccx ( ) . tn , lv. val ) ) ;
2963
+ let { lv, e_ty} = if derefs == 0 u {
2964
+ { lv: lv, e_ty: e_ty}
2965
+ } else {
2966
+ let { bcx, val} = lval_result_to_result ( lv, e_ty) ;
2967
+ let { bcx, val, ty: e_ty } =
2968
+ autoderef ( bcx, e. id , val, e_ty, derefs) ;
2969
+ { lv : { bcx : bcx, val : val, kind : temporary} ,
2970
+ e_ty: e_ty}
2971
+ } ;
2972
+
2973
+ // borrow value (convert from @T to &T and so forth)
2944
2974
#debug ( " pre-adaptation value: %s" , val_str ( lv. bcx . ccx ( ) . tn , lv. val ) ) ;
2945
- let { lv, arg } = adapt_borrowed_value ( lv, arg , e ) ;
2975
+ let { lv, ty : e_ty } = adapt_borrowed_value ( lv, e , e_ty ) ;
2946
2976
let mut bcx = lv. bcx ;
2947
2977
let mut val = lv. val ;
2948
2978
#debug ( " adapted value: %s" , val_str ( bcx. ccx ( ) . tn , val) ) ;
2979
+
2980
+ // finally, deal with the various modes
2949
2981
let arg_mode = ty:: resolved_mode ( ccx. tcx , arg. mode ) ;
2950
2982
if is_bot {
2951
2983
// For values of type _|_, we generate an
2952
2984
// "undef" value, as such a value should never
2953
2985
// be inspected. It's important for the value
2954
2986
// to have type lldestty (the callee's expected type).
2955
2987
val = llvm:: LLVMGetUndef ( lldestty) ;
2956
- } else if arg_mode == ast:: by_ref || arg_mode == ast:: by_val {
2957
- let imm = ty:: type_is_immediate ( arg. ty ) ;
2958
- #debug[ " arg.ty=%s, imm=%b, arg_mode=%?, lv.kind=%?" ,
2959
- ty_to_str ( bcx. tcx ( ) , arg. ty ) , imm, arg_mode, lv. kind ] ;
2960
- if arg_mode == ast:: by_ref && lv. kind != owned && imm {
2961
- val = do_spill_noroot ( bcx, val) ;
2962
- }
2963
- if arg_mode == ast:: by_val && ( lv. kind == owned || !imm) {
2964
- val = Load ( bcx, val) ;
2965
- }
2966
- } else if arg_mode == ast:: by_copy || arg_mode == ast:: by_move {
2967
- let alloc = alloc_ty ( bcx, arg. ty ) ;
2968
- let move_out = arg_mode == ast:: by_move ||
2969
- ccx. maps . last_use_map . contains_key ( e. id ) ;
2970
- if lv. kind == temporary { revoke_clean ( bcx, val) ; }
2971
- if lv. kind == owned || !ty:: type_is_immediate ( arg. ty ) {
2972
- memmove_ty ( bcx, alloc, val, arg. ty ) ;
2973
- if move_out && ty:: type_needs_drop ( ccx. tcx , arg. ty ) {
2974
- bcx = zero_mem ( bcx, val, arg. ty ) ;
2988
+ } else {
2989
+ alt arg_mode {
2990
+ ast : : by_ref | ast:: by_mutbl_ref {
2991
+ // Ensure that the value is spilled into memory:
2992
+ if lv. kind != owned && ty:: type_is_immediate ( e_ty) {
2993
+ val = do_spill_noroot ( bcx, val) ;
2975
2994
}
2976
- } else { Store ( bcx, val, alloc) ; }
2977
- val = alloc;
2978
- if lv. kind != temporary && !move_out {
2979
- bcx = take_ty ( bcx, val, arg. ty ) ;
2980
- }
2995
+ }
2996
+
2997
+ ast:: by_val {
2998
+ // Ensure that the value is not spilled into memory:
2999
+ if lv. kind == owned || !ty:: type_is_immediate ( e_ty) {
3000
+ val = Load ( bcx, val) ;
3001
+ }
3002
+ }
2981
3003
2982
- // In the event that failure occurs before the call actually
2983
- // happens, have to cleanup this copy:
2984
- add_clean_temp_mem ( bcx, val, arg. ty ) ;
2985
- temp_cleanups += [ val] ;
2986
- } else if ty:: type_is_immediate ( arg. ty ) && lv. kind != owned {
2987
- val = do_spill ( bcx, val, arg. ty ) ;
3004
+ ast:: by_copy | ast:: by_move {
3005
+ // Ensure that an owned copy of the value is in memory:
3006
+ let alloc = alloc_ty ( bcx, arg. ty ) ;
3007
+ let move_out = arg_mode == ast:: by_move ||
3008
+ ccx. maps . last_use_map . contains_key ( e. id ) ;
3009
+ if lv. kind == temporary { revoke_clean ( bcx, val) ; }
3010
+ if lv. kind == owned || !ty:: type_is_immediate ( arg. ty ) {
3011
+ memmove_ty ( bcx, alloc, val, arg. ty ) ;
3012
+ if move_out && ty:: type_needs_drop ( ccx. tcx , arg. ty ) {
3013
+ bcx = zero_mem ( bcx, val, arg. ty ) ;
3014
+ }
3015
+ } else { Store ( bcx, val, alloc) ; }
3016
+ val = alloc;
3017
+ if lv. kind != temporary && !move_out {
3018
+ bcx = take_ty ( bcx, val, arg. ty ) ;
3019
+ }
3020
+
3021
+ // In the event that failure occurs before the call actually
3022
+ // happens, have to cleanup this copy:
3023
+ add_clean_temp_mem ( bcx, val, arg. ty ) ;
3024
+ temp_cleanups += [ val] ;
3025
+ }
3026
+ }
2988
3027
}
2989
3028
2990
3029
if !is_bot && arg. ty != e_ty || ty:: type_has_params ( arg. ty ) {
2991
3030
#debug ( " casting from %s" , val_str ( bcx. ccx ( ) . tn , val) ) ;
2992
3031
val = PointerCast ( bcx, val, lldestty) ;
2993
3032
}
3033
+
2994
3034
#debug( "--- trans_arg_expr passing %s" , val_str ( bcx. ccx ( ) . tn , val) ) ;
2995
3035
ret rslt( bcx, val) ;
2996
3036
}
2997
3037
2998
- fn load_value_from_lval_result ( lv : lval_result ) -> ValueRef {
2999
- alt lv. kind {
3000
- temporary { lv. val }
3001
- owned { Load ( lv. bcx , lv. val ) }
3002
- owned_imm { lv. val }
3003
- }
3004
- }
3005
-
3006
3038
// when invoking a method, an argument of type @T or ~T can be implicltly
3007
3039
// converted to an argument of type &T. Similarly, [T] can be converted to
3008
3040
// [T]/& and so on. If such a conversion (called borrowing) is necessary,
3009
3041
// then the borrowings table will have an appropriate entry inserted. This
3010
3042
// routine consults this table and performs these adaptations. It returns a
3011
3043
// new location for the borrowed result as well as a new type for the argument
3012
3044
// that reflects the borrowed value and not the original.
3013
- fn adapt_borrowed_value( lv: lval_result, arg: ty:: arg,
3014
- e: @ast:: expr) -> { lv: lval_result,
3015
- arg: ty:: arg} {
3045
+ fn adapt_borrowed_value ( lv : lval_result ,
3046
+ e : @ast:: expr ,
3047
+ e_ty : ty:: t ) -> { lv : lval_result ,
3048
+ ty: ty:: t } {
3016
3049
let bcx = lv. bcx ;
3017
3050
if !expr_is_borrowed ( bcx, e) {
3018
- ret { lv : lv, arg : arg } ;
3051
+ ret { lv : lv, ty : e_ty } ;
3019
3052
}
3020
3053
3021
- let e_ty = expr_ty ( bcx, e) ;
3022
3054
alt ty:: get ( e_ty) . struct {
3023
3055
ty:: ty_uniq ( mt) | ty:: ty_box ( mt) {
3024
- let box_ptr = load_value_from_lval_result ( lv) ;
3056
+ let box_ptr = load_value_from_lval_result ( lv, e_ty ) ;
3025
3057
let body_ptr = GEPi ( bcx, box_ptr, [ 0 u, abi:: box_field_body] ) ;
3026
3058
let rptr_ty = ty:: mk_rptr ( bcx. tcx ( ) , ty:: re_static, mt) ;
3027
- ret { lv : lval_temp ( bcx, body_ptr) ,
3028
- arg : { ty: rptr_ty with arg} } ;
3059
+ ret { lv : lval_temp ( bcx, body_ptr) , ty : rptr_ty} ;
3029
3060
}
3030
3061
3031
3062
ty:: ty_str | ty:: ty_vec ( _) |
@@ -3057,8 +3088,7 @@ fn adapt_borrowed_value(lv: lval_result, arg: ty::arg,
3057
3088
{ ty: unit_ty, mutbl: ast:: m_imm} ,
3058
3089
ty:: vstore_slice ( ty:: re_static) ) ;
3059
3090
3060
- ret { lv : lval_temp ( bcx, p) ,
3061
- arg : { ty: slice_ty with arg} } ;
3091
+ ret { lv : lval_temp ( bcx, p) , ty : slice_ty} ;
3062
3092
}
3063
3093
3064
3094
_ {
@@ -3120,7 +3150,7 @@ fn trans_args(cx: block, llenv: ValueRef, args: call_args, fn_ty: ty::t,
3120
3150
vec:: iteri ( es) { |i, e|
3121
3151
let r = trans_arg_expr ( bcx, arg_tys[ i] , llarg_tys[ i] ,
3122
3152
e, temp_cleanups, if i == last { ret_flag }
3123
- else { none } ) ;
3153
+ else { none } , 0 u ) ;
3124
3154
bcx = r. bcx ;
3125
3155
llargs += [ r. val ] ;
3126
3156
}
@@ -3494,11 +3524,20 @@ fn trans_temp_lval(bcx: block, e: @ast::expr) -> lval_result {
3494
3524
// expressions that must 'end up somewhere' (or get ignored).
3495
3525
fn trans_temp_expr ( bcx : block , e : @ast:: expr ) -> result {
3496
3526
let _icx = bcx. insn_ctxt ( "trans_temp_expr" ) ;
3497
- let mut { bcx, val, kind} = trans_temp_lval ( bcx, e) ;
3498
- if kind == owned {
3499
- val = load_if_immediate ( bcx, val, expr_ty ( bcx, e) ) ;
3527
+ lval_result_to_result ( trans_temp_lval ( bcx, e) , expr_ty ( bcx, e) )
3528
+ }
3529
+
3530
+ fn load_value_from_lval_result ( lv : lval_result , ty : ty:: t ) -> ValueRef {
3531
+ alt lv. kind {
3532
+ temporary { lv. val }
3533
+ owned { load_if_immediate( lv. bcx , lv. val , ty) }
3534
+ owned_imm { lv. val }
3500
3535
}
3501
- ret { bcx : bcx, val : val} ;
3536
+ }
3537
+
3538
+ fn lval_result_to_result ( lv : lval_result , ty : ty:: t ) -> result {
3539
+ let val = load_value_from_lval_result ( lv, ty) ;
3540
+ { bcx: lv. bcx , val: val}
3502
3541
}
3503
3542
3504
3543
// Arranges for the value found in `*root_loc` to be dropped once the scope
0 commit comments