about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-02-24 17:45:16 -0800
committerNiko Matsakis <niko@alum.mit.edu>2012-02-24 20:46:27 -0800
commitacb129c5412bdc4375bb3a31a192ea6e7f26ebcc (patch)
tree209fb4df357855f34b0381257219e83a02c7c867 /src
parentf3ca50c9ca4fd2084cfbc85030ff5ea21e589635 (diff)
downloadrust-acb129c5412bdc4375bb3a31a192ea6e7f26ebcc.tar.gz
rust-acb129c5412bdc4375bb3a31a192ea6e7f26ebcc.zip
Add temp cleanups for copy/move mode args when other args fail. Fixes #1374
Diffstat (limited to 'src')
-rw-r--r--src/comp/middle/trans/base.rs22
-rw-r--r--src/comp/middle/trans/impl.rs12
2 files changed, 29 insertions, 5 deletions
diff --git a/src/comp/middle/trans/base.rs b/src/comp/middle/trans/base.rs
index e05f4e12855..7037f3cc560 100644
--- a/src/comp/middle/trans/base.rs
+++ b/src/comp/middle/trans/base.rs
@@ -2563,8 +2563,10 @@ fn trans_cast(cx: block, e: @ast::expr, id: ast::node_id,
     ret store_in_dest(e_res.bcx, newval, dest);
 }
 
-fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef,
-                  e: @ast::expr) -> result {
+// temp_cleanups: cleanups that should run only if failure occurs before the
+// call takes place:
+fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
+                  &temp_cleanups: [ValueRef]) -> result {
     let ccx = cx.ccx();
     let e_ty = expr_ty(cx, e);
     let is_bot = ty::type_is_bot(e_ty);
@@ -2612,6 +2614,11 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef,
         if lv.kind != temporary && !move_out {
             bcx = take_ty(bcx, val, e_ty);
         }
+
+        // In the event that failure occurs before the call actually
+        // happens, have to cleanup this copy:
+        add_clean_temp_mem(bcx, val, e_ty);
+        temp_cleanups += [val];
     } else if ty::type_is_immediate(e_ty) && lv.kind != owned {
         let r = do_spill(bcx, val, e_ty);
         val = r.val;
@@ -2638,6 +2645,7 @@ fn trans_args(cx: block, llenv: ValueRef,
        args: [ValueRef],
        retslot: ValueRef} {
 
+    let temp_cleanups = [];
     let args = ty::ty_fn_args(fn_ty);
     let llargs: [ValueRef] = [];
     let lltydescs: [ValueRef] = [];
@@ -2718,11 +2726,19 @@ fn trans_args(cx: block, llenv: ValueRef,
     let arg_tys = type_of_explicit_args(ccx, args);
     let i = 0u;
     for e: @ast::expr in es {
-        let r = trans_arg_expr(bcx, args[i], arg_tys[i], e);
+        let r = trans_arg_expr(bcx, args[i], arg_tys[i], e, temp_cleanups);
         bcx = r.bcx;
         llargs += [r.val];
         i += 1u;
     }
+
+    // now that all arguments have been successfully built, we can revoke any
+    // temporary cleanups, as they are only needed if argument construction
+    // should fail (for example, cleanup of copy mode args).
+    vec::iter(temp_cleanups) {|c|
+        revoke_clean(bcx, c)
+    }
+
     ret {bcx: bcx,
          args: llargs,
          retslot: llretslot};
diff --git a/src/comp/middle/trans/impl.rs b/src/comp/middle/trans/impl.rs
index 00345e8ae02..2b522dcd611 100644
--- a/src/comp/middle/trans/impl.rs
+++ b/src/comp/middle/trans/impl.rs
@@ -63,8 +63,16 @@ fn trans_impl(ccx: crate_ctxt, path: path, name: ast::ident,
 fn trans_self_arg(bcx: block, base: @ast::expr) -> result {
     let basety = expr_ty(bcx, base);
     let m_by_ref = ast::expl(ast::by_ref);
-    trans_arg_expr(bcx, {mode: m_by_ref, ty: basety},
-                   T_ptr(type_of_or_i8(bcx.ccx(), basety)), base)
+    let temp_cleanups = [];
+    let result = trans_arg_expr(bcx, {mode: m_by_ref, ty: basety},
+                                T_ptr(type_of_or_i8(bcx.ccx(), basety)), base,
+                                temp_cleanups);
+
+    // by-ref self argument should not require cleanup in the case of
+    // other arguments failing:
+    assert temp_cleanups == [];
+
+    ret result;
 }
 
 fn trans_method_callee(bcx: block, callee_id: ast::node_id,