Copy locals created by destructuring on the content of a box

This is required so that assigning to these locals doesn't clobber
the content of the box.

(A possible optimization would be to only do this copying for
locals that actually are assigned to.)
This commit is contained in:
Marijn Haverbeke 2011-08-02 11:44:00 +02:00
parent 043d95a2bd
commit f8fa574864
3 changed files with 29 additions and 8 deletions

View file

@ -3631,7 +3631,7 @@ fn trans_for(cx: &@block_ctxt, local: &@ast::local, seq: &@ast::expr,
let loc_r = copy_val(local_res.bcx, INIT, local_res.val, curr, t);
add_clean(scope_cx, local_res.val, t);
let bcx = trans_alt::bind_irrefutable_pat
(loc_r.bcx, local.node.pat, local_res.val, cx.fcx.lllocals);
(loc_r.bcx, local.node.pat, local_res.val, cx.fcx.lllocals, false);
bcx = trans_block(bcx, body, return).bcx;
if !bcx.build.is_terminated() {
bcx.build.Br(next_cx.llbb);
@ -3982,7 +3982,7 @@ fn trans_for_each(cx: &@block_ctxt, local: &@ast::local, seq: &@ast::expr,
// Add bindings for the loop variable alias.
bcx = trans_alt::bind_irrefutable_pat
(bcx, local.node.pat, llvm::LLVMGetParam(fcx.llfn, 3u),
bcx.fcx.llupvars);
bcx.fcx.llupvars, false);
let lltop = bcx.llbb;
let r = trans_block(bcx, body, return);
finish_fn(fcx, lltop);
@ -5949,7 +5949,7 @@ fn init_local(bcx: @block_ctxt, local: &@ast::local) -> result {
_ { bcx = zero_alloca(bcx, llptr, ty).bcx; }
}
bcx = trans_alt::bind_irrefutable_pat(bcx, local.node.pat, llptr,
bcx.fcx.lllocals);
bcx.fcx.lllocals, false);
ret rslt(bcx, llptr);
}

View file

@ -437,12 +437,23 @@ fn trans_alt(cx: &@block_ctxt, expr: &@ast::expr, arms: &ast::arm[],
// Not alt-related, but similar to the pattern-munging code above
fn bind_irrefutable_pat(bcx: @block_ctxt, pat: &@ast::pat, val: ValueRef,
table: hashmap[ast::node_id, ValueRef])
table: hashmap[ast::node_id, ValueRef], copy: bool)
-> @block_ctxt {
let ccx = bcx.fcx.lcx.ccx;
alt pat.node {
ast::pat_bind(_) {
table.insert(pat.id, val);
if copy {
let ty = ty::node_id_to_monotype(ccx.tcx, pat.id);
let llty = trans::type_of(ccx, pat.span, ty);
let alloc = trans::alloca(bcx, llty);
bcx = trans::memmove_ty(bcx, alloc, val, ty).bcx;
let loaded = trans::load_if_immediate(bcx, alloc, ty);
bcx = trans::copy_ty(bcx, loaded, ty).bcx;
table.insert(pat.id, alloc);
trans_common::add_clean(bcx, alloc, ty);
} else {
table.insert(pat.id, val);
}
}
ast::pat_tag(_, sub) {
if ivec::len(sub) == 0u { ret bcx; }
@ -450,7 +461,7 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: &@ast::pat, val: ValueRef,
let args = extract_variant_args(bcx, pat.id, vdefs, val);
let i = 0;
for argval: ValueRef in args.vals {
bcx = bind_irrefutable_pat(bcx, sub.(i), argval, table);
bcx = bind_irrefutable_pat(bcx, sub.(i), argval, table, copy);
i += 1;
}
}
@ -462,14 +473,14 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: &@ast::pat, val: ValueRef,
let ix: uint =
ty::field_idx(ccx.sess, pat.span, f.ident, rec_fields);
let r = trans::GEP_tup_like(bcx, rec_ty, val, ~[0, ix as int]);
bcx = bind_irrefutable_pat(r.bcx, f.pat, r.val, table);
bcx = bind_irrefutable_pat(r.bcx, f.pat, r.val, table, copy);
}
}
ast::pat_box(inner) {
let box = bcx.build.Load(val);
let unboxed = bcx.build.InBoundsGEP
(box, ~[C_int(0), C_int(back::abi::box_rc_field_body)]);
bcx = bind_irrefutable_pat(bcx, inner, unboxed, table);
bcx = bind_irrefutable_pat(bcx, inner, unboxed, table, true);
}
ast::pat_wild. | ast::pat_lit(_) {}
}

View file

@ -0,0 +1,10 @@
fn main() {
let u = {x: 10, y: @{a: 20}};
let {x, y: @{a}} = u;
x = 100;
a = 100;
assert x == 100;
assert a == 100;
assert u.x == 10;
assert u.y.a == 20;
}