Fix autoderef of function calls when the function is not an lval.

As it turns out, the correct way to handle this is much simpler than what I
did originally.
Also add more tests.
This commit is contained in:
Michael Sullivan 2011-07-11 13:12:44 -05:00 committed by Brian Anderson
parent 418aa52510
commit 7340824cbc
3 changed files with 16 additions and 18 deletions

View File

@ -4206,19 +4206,13 @@ fn trans_eager_binop(&@block_ctxt cx, ast::binop op, &ty::t intype,
}
}
fn autoderef_lval(&@block_ctxt cx, ValueRef v, &ty::t t, bool is_lval)
-> result_t {
fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result_t {
let ValueRef v1 = v;
let ty::t t1 = t;
auto ccx = cx.fcx.lcx.ccx;
while (true) {
alt (ty::struct(ccx.tcx, t1)) {
case (ty::ty_box(?mt)) {
// If we are working with an lval, we want to
// unconditionally load at the top of the loop
// to get rid of the extra indirection
if (is_lval) { v1 = cx.build.Load(v1); }
auto body =
cx.build.GEP(v1,
~[C_int(0), C_int(abi::box_rc_field_body)]);
@ -4233,7 +4227,6 @@ fn autoderef_lval(&@block_ctxt cx, ValueRef v, &ty::t t, bool is_lval)
} else { v1 = body; }
}
case (ty::ty_res(?did, ?inner, ?tps)) {
if (is_lval) { v1 = cx.build.Load(v1); }
t1 = ty::substitute_type_params(ccx.tcx, tps, inner);
v1 = cx.build.GEP(v1, ~[C_int(0), C_int(1)]);
}
@ -4243,7 +4236,6 @@ fn autoderef_lval(&@block_ctxt cx, ValueRef v, &ty::t t, bool is_lval)
std::ivec::len(variants.(0).args) != 1u) {
break;
}
if (is_lval) { v1 = cx.build.Load(v1); }
t1 = ty::substitute_type_params
(ccx.tcx, tps, variants.(0).args.(0));
if (!ty::type_has_dynamic_size(ccx.tcx, t1)) {
@ -4253,18 +4245,11 @@ fn autoderef_lval(&@block_ctxt cx, ValueRef v, &ty::t t, bool is_lval)
}
case (_) { break; }
}
// But if we aren't working with an lval, we get rid of
// a layer of indirection at the bottom of the loop so
// that it is gone when we return...
if (!is_lval) { v1 = load_if_immediate(cx, v1, t1); }
v1 = load_if_immediate(cx, v1, t1);
}
ret rec(bcx=cx, val=v1, ty=t1);
}
fn autoderef(&@block_ctxt cx, ValueRef v, &ty::t t) -> result_t {
ret autoderef_lval(cx, v, t, false);
}
fn trans_binary(&@block_ctxt cx, ast::binop op, &@ast::expr a, &@ast::expr b)
-> result {
@ -5956,7 +5941,8 @@ fn trans_call(&@block_ctxt cx, &@ast::expr f, &option::t[ValueRef] lliterbody,
}
case (none) {
// It's a closure. We have to autoderef.
auto res = autoderef_lval(bcx, f_res.res.val, fn_ty, true);
if (f_res.is_mem) { faddr = load_if_immediate(bcx, faddr, fn_ty);}
auto res = autoderef(bcx, faddr, fn_ty);
bcx = res.bcx;
fn_ty = res.ty;

View File

@ -8,4 +8,5 @@ fn main() {
assert(f(5) == 6);
assert(g(8) == 9);
assert(h(0x1badd00d) == 0x1badd00e);
assert((@add1)(42) == 43);
}

View File

@ -0,0 +1,11 @@
// xfail-stage0
tag int_fn { f(fn(int) -> int); }
tag int_box_fn { fb(@fn(int) -> int); }
fn add1(int i) -> int { ret i+1; }
fn main() {
auto g = f(add1);
assert(g(4) == 5);
assert((f(add1))(5) == 6);
assert((@(f(add1)))(5) == 6);
assert((fb(@add1))(7) == 8);
}