Add temp cleanups for copy/move mode args when other args fail. Fixes #1374

This commit is contained in:
Niko Matsakis 2012-02-24 17:45:16 -08:00
parent f3ca50c9ca
commit acb129c541
2 changed files with 29 additions and 5 deletions

View File

@ -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};

View File

@ -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,