about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-08-02 11:44:00 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-08-02 12:09:15 +0200
commitf8fa574864a5bd54752fc198438f8c53a8ed5ef0 (patch)
tree01662bfbc8d189801822dc5b35fa88bb9f465c53 /src/comp
parent043d95a2bdc6a344f1bfc7800b0ed719dbb6c7aa (diff)
downloadrust-f8fa574864a5bd54752fc198438f8c53a8ed5ef0.tar.gz
rust-f8fa574864a5bd54752fc198438f8c53a8ed5ef0.zip
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.)
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/middle/trans.rs6
-rw-r--r--src/comp/middle/trans_alt.rs21
2 files changed, 19 insertions, 8 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index db06a6ca6cd..53f8b0b0d34 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 c77a3451266..899ba437cb1 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(_) {}
     }