about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2011-09-19 14:20:15 -0700
committerBrian Anderson <banderson@mozilla.com>2011-09-19 14:28:04 -0700
commitdd1cf63515d7703344cf18f8f44e8a1a1dedcd5f (patch)
tree4c6a59a66e5f373d6fc09936233833e19e469e2e /src/comp
parent432e931a2ab6a0e642a39f71b15e86dd3bfe3c9a (diff)
Build records in two phases to avoid cleanups on partial records
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/middle/trans.rs47
1 files changed, 42 insertions, 5 deletions
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 5cddc193529..fa56780e8db 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -3973,6 +3973,21 @@ fn trans_rec(cx: @block_ctxt, fields: [ast::field],
     }
     let ty_fields: [ty::field] = [];
     alt ty::struct(bcx_tcx(cx), t) { ty::ty_rec(flds) { ty_fields = flds; } }
+
+    tag fieldsrc {
+        provided(lval_result);
+        inherited(ValueRef);
+    }
+    type fieldval = {
+        dst: ValueRef,
+        src: fieldsrc,
+        ty: ty::t
+    };
+    let fieldvals: [fieldval] = [];
+
+    // We build the record in two stages so that we don't have to clean up a
+    // partial record if we fail: first collect all the values, then construct
+    // the record.
     for tf: ty::field in ty_fields {
         let e_ty = tf.mt.ty;
         // FIXME: constraint on argument?
@@ -3984,8 +3999,12 @@ fn trans_rec(cx: @block_ctxt, fields: [ast::field],
             if str::eq(f.node.ident, tf.ident) {
                 expr_provided = true;
                 let lv = trans_lval(bcx, f.node.expr);
-                bcx =
-                    move_val_if_temp(lv.bcx, INIT, dst_res.val, lv, e_ty);
+                bcx = lv.bcx;
+                fieldvals += [{
+                    dst: dst_res.val,
+                    src: provided(lv),
+                    ty: e_ty
+                }];
                 break;
             }
         }
@@ -3993,12 +4012,30 @@ fn trans_rec(cx: @block_ctxt, fields: [ast::field],
             // FIXME: constraint on argument?
             check type_is_tup_like(bcx, t);
             let src_res = GEP_tup_like(bcx, t, base_val, [0, i]);
-            src_res =
-                rslt(src_res.bcx, load_if_immediate(bcx, src_res.val, e_ty));
-            bcx = copy_val(src_res.bcx, INIT, dst_res.val, src_res.val, e_ty);
+            bcx = src_res.bcx;
+            fieldvals += [{
+                dst: dst_res.val,
+                src: inherited(src_res.val),
+                ty: e_ty
+            }];
         }
         i += 1;
     }
+
+    // Now build the record
+    for fieldval in fieldvals {
+        alt fieldval.src {
+          provided(lv) {
+            bcx = move_val_if_temp(bcx, INIT, fieldval.dst,
+                                   lv, fieldval.ty);
+          }
+          inherited(val) {
+            let val = load_if_immediate(bcx, val, fieldval.ty);
+            bcx = copy_val(bcx, INIT, fieldval.dst, val, fieldval.ty);
+          }
+        }
+    }
+
     add_clean_temp(cx, rec_val, t);
     ret rslt(bcx, rec_val);
 }