mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-11 15:23:05 +00:00
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:
parent
418aa52510
commit
7340824cbc
@ -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;
|
||||
|
||||
|
@ -8,4 +8,5 @@ fn main() {
|
||||
assert(f(5) == 6);
|
||||
assert(g(8) == 9);
|
||||
assert(h(0x1badd00d) == 0x1badd00e);
|
||||
assert((@add1)(42) == 43);
|
||||
}
|
||||
|
11
src/test/run-pass/call-autoderef-tag.rs
Normal file
11
src/test/run-pass/call-autoderef-tag.rs
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user