Skip to content

Commit f8fa574

Browse files
committed
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.)
1 parent 043d95a commit f8fa574

File tree

3 files changed

+29
-8
lines changed

3 files changed

+29
-8
lines changed

src/comp/middle/trans.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3631,7 +3631,7 @@ fn trans_for(cx: &@block_ctxt, local: &@ast::local, seq: &@ast::expr,
36313631
let loc_r = copy_val(local_res.bcx, INIT, local_res.val, curr, t);
36323632
add_clean(scope_cx, local_res.val, t);
36333633
let bcx = trans_alt::bind_irrefutable_pat
3634-
(loc_r.bcx, local.node.pat, local_res.val, cx.fcx.lllocals);
3634+
(loc_r.bcx, local.node.pat, local_res.val, cx.fcx.lllocals, false);
36353635
bcx = trans_block(bcx, body, return).bcx;
36363636
if !bcx.build.is_terminated() {
36373637
bcx.build.Br(next_cx.llbb);
@@ -3982,7 +3982,7 @@ fn trans_for_each(cx: &@block_ctxt, local: &@ast::local, seq: &@ast::expr,
39823982
// Add bindings for the loop variable alias.
39833983
bcx = trans_alt::bind_irrefutable_pat
39843984
(bcx, local.node.pat, llvm::LLVMGetParam(fcx.llfn, 3u),
3985-
bcx.fcx.llupvars);
3985+
bcx.fcx.llupvars, false);
39863986
let lltop = bcx.llbb;
39873987
let r = trans_block(bcx, body, return);
39883988
finish_fn(fcx, lltop);
@@ -5949,7 +5949,7 @@ fn init_local(bcx: @block_ctxt, local: &@ast::local) -> result {
59495949
_ { bcx = zero_alloca(bcx, llptr, ty).bcx; }
59505950
}
59515951
bcx = trans_alt::bind_irrefutable_pat(bcx, local.node.pat, llptr,
5952-
bcx.fcx.lllocals);
5952+
bcx.fcx.lllocals, false);
59535953
ret rslt(bcx, llptr);
59545954
}
59555955

src/comp/middle/trans_alt.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -437,20 +437,31 @@ fn trans_alt(cx: &@block_ctxt, expr: &@ast::expr, arms: &ast::arm[],
437437

438438
// Not alt-related, but similar to the pattern-munging code above
439439
fn bind_irrefutable_pat(bcx: @block_ctxt, pat: &@ast::pat, val: ValueRef,
440-
table: hashmap[ast::node_id, ValueRef])
440+
table: hashmap[ast::node_id, ValueRef], copy: bool)
441441
-> @block_ctxt {
442442
let ccx = bcx.fcx.lcx.ccx;
443443
alt pat.node {
444444
ast::pat_bind(_) {
445-
table.insert(pat.id, val);
445+
if copy {
446+
let ty = ty::node_id_to_monotype(ccx.tcx, pat.id);
447+
let llty = trans::type_of(ccx, pat.span, ty);
448+
let alloc = trans::alloca(bcx, llty);
449+
bcx = trans::memmove_ty(bcx, alloc, val, ty).bcx;
450+
let loaded = trans::load_if_immediate(bcx, alloc, ty);
451+
bcx = trans::copy_ty(bcx, loaded, ty).bcx;
452+
table.insert(pat.id, alloc);
453+
trans_common::add_clean(bcx, alloc, ty);
454+
} else {
455+
table.insert(pat.id, val);
456+
}
446457
}
447458
ast::pat_tag(_, sub) {
448459
if ivec::len(sub) == 0u { ret bcx; }
449460
let vdefs = ast::variant_def_ids(ccx.tcx.def_map.get(pat.id));
450461
let args = extract_variant_args(bcx, pat.id, vdefs, val);
451462
let i = 0;
452463
for argval: ValueRef in args.vals {
453-
bcx = bind_irrefutable_pat(bcx, sub.(i), argval, table);
464+
bcx = bind_irrefutable_pat(bcx, sub.(i), argval, table, copy);
454465
i += 1;
455466
}
456467
}
@@ -462,14 +473,14 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: &@ast::pat, val: ValueRef,
462473
let ix: uint =
463474
ty::field_idx(ccx.sess, pat.span, f.ident, rec_fields);
464475
let r = trans::GEP_tup_like(bcx, rec_ty, val, ~[0, ix as int]);
465-
bcx = bind_irrefutable_pat(r.bcx, f.pat, r.val, table);
476+
bcx = bind_irrefutable_pat(r.bcx, f.pat, r.val, table, copy);
466477
}
467478
}
468479
ast::pat_box(inner) {
469480
let box = bcx.build.Load(val);
470481
let unboxed = bcx.build.InBoundsGEP
471482
(box, ~[C_int(0), C_int(back::abi::box_rc_field_body)]);
472-
bcx = bind_irrefutable_pat(bcx, inner, unboxed, table);
483+
bcx = bind_irrefutable_pat(bcx, inner, unboxed, table, true);
473484
}
474485
ast::pat_wild. | ast::pat_lit(_) {}
475486
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
fn main() {
2+
let u = {x: 10, y: @{a: 20}};
3+
let {x, y: @{a}} = u;
4+
x = 100;
5+
a = 100;
6+
assert x == 100;
7+
assert a == 100;
8+
assert u.x == 10;
9+
assert u.y.a == 20;
10+
}

0 commit comments

Comments
 (0)