From f8fa574864a5bd54752fc198438f8c53a8ed5ef0 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 2 Aug 2011 11:44:00 +0200 Subject: [PATCH] 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.) --- src/comp/middle/trans.rs | 6 +++--- src/comp/middle/trans_alt.rs | 21 ++++++++++++++++----- src/test/run-pass/let-destruct-fresh-mem.rs | 10 ++++++++++ 3 files changed, 29 insertions(+), 8 deletions(-) create mode 100644 src/test/run-pass/let-destruct-fresh-mem.rs diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index db06a6ca6cda..53f8b0b0d347 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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); } diff --git a/src/comp/middle/trans_alt.rs b/src/comp/middle/trans_alt.rs index c77a34512668..899ba437cb19 100644 --- a/src/comp/middle/trans_alt.rs +++ b/src/comp/middle/trans_alt.rs @@ -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(_) {} } diff --git a/src/test/run-pass/let-destruct-fresh-mem.rs b/src/test/run-pass/let-destruct-fresh-mem.rs new file mode 100644 index 000000000000..fa2798ecc66a --- /dev/null +++ b/src/test/run-pass/let-destruct-fresh-mem.rs @@ -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; +}