From 210ae23b677de4d6fd813823e3cba00cc26336c5 Mon Sep 17 00:00:00 2001 From: Michael Sullivan Date: Mon, 11 Jul 2011 13:12:44 -0500 Subject: [PATCH] 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. --- src/comp/middle/trans.rs | 22 ++++------------------ src/test/run-pass/auto-deref-fn.rs | 1 + src/test/run-pass/call-autoderef-tag.rs | 11 +++++++++++ 3 files changed, 16 insertions(+), 18 deletions(-) create mode 100644 src/test/run-pass/call-autoderef-tag.rs diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 050cd59e1d46f..dad175f455a76 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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 { @@ -5946,7 +5931,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; diff --git a/src/test/run-pass/auto-deref-fn.rs b/src/test/run-pass/auto-deref-fn.rs index 6959e8e109f34..8637c7d03d650 100644 --- a/src/test/run-pass/auto-deref-fn.rs +++ b/src/test/run-pass/auto-deref-fn.rs @@ -8,4 +8,5 @@ fn main() { assert(f(5) == 6); assert(g(8) == 9); assert(h(0x1badd00d) == 0x1badd00e); + assert((@add1)(42) == 43); } diff --git a/src/test/run-pass/call-autoderef-tag.rs b/src/test/run-pass/call-autoderef-tag.rs new file mode 100644 index 0000000000000..3826b9a409c30 --- /dev/null +++ b/src/test/run-pass/call-autoderef-tag.rs @@ -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); +}