about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Sullivan <sully@msully.net>2011-07-11 13:12:44 -0500
committerBrian Anderson <banderson@mozilla.com>2011-07-11 11:38:01 -0700
commit7340824cbcce104458d87200119b62dbfe0ef07a (patch)
treea545b2b60683d528c357dd5ed039145124bdc843
parent418aa525107319a224a3299eae8d9c8fdfe02c13 (diff)
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.
-rw-r--r--src/comp/middle/trans.rs22
-rw-r--r--src/test/run-pass/auto-deref-fn.rs1
-rw-r--r--src/test/run-pass/call-autoderef-tag.rs11
3 files changed, 16 insertions, 18 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 18a0c50ae76..4fd290389e0 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 {
 
@@ -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;
 
diff --git a/src/test/run-pass/auto-deref-fn.rs b/src/test/run-pass/auto-deref-fn.rs
index 6959e8e109f..8637c7d03d6 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 00000000000..3826b9a409c
--- /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);
+}