diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 419b8fb4ae40..a103c7d311b0 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3731,15 +3731,25 @@ fn invoke_(bcx: @block_ctxt, llfn: ValueRef, // FIXME: May be worth turning this into a plain call when there are no // cleanups to run let normal_bcx = new_sub_block_ctxt(bcx, "normal return"); - let unwind_bcx = new_sub_block_ctxt(bcx, "unwind"); let retval = invoker(bcx, llfn, llargs, normal_bcx.llbb, - unwind_bcx.llbb); - trans_landing_pad(unwind_bcx); + get_landing_pad(bcx)); ret rslt(normal_bcx, retval); } -fn trans_landing_pad(bcx: @block_ctxt) { +fn get_landing_pad(bcx: @block_ctxt) -> BasicBlockRef { + let scope_bcx = find_scope_cx(bcx); + if scope_bcx.cleanups_dirty { + let unwind_bcx = new_sub_block_ctxt(bcx, "unwind"); + let lpadbb = trans_landing_pad(unwind_bcx); + scope_bcx.lpad = some(lpadbb); + scope_bcx.cleanups_dirty = false; + } + assert option::is_some(scope_bcx.lpad); + ret option::get(scope_bcx.lpad); +} + +fn trans_landing_pad(bcx: @block_ctxt) -> BasicBlockRef { // The landing pad return type (the type being propagated). Not sure what // this represents but it's determined by the personality function and // this is what the EH proposal example uses. @@ -3773,6 +3783,7 @@ fn trans_landing_pad(bcx: @block_ctxt) { // Continue unwinding Resume(bcx, llretval); + ret bcx.llbb; } fn trans_tup(cx: @block_ctxt, elts: [@ast::expr], id: ast::node_id) -> @@ -4522,6 +4533,8 @@ fn new_block_ctxt(cx: @fn_ctxt, parent: block_parent, kind: block_kind, parent: parent, kind: kind, mutable cleanups: [], + mutable cleanups_dirty: true, + mutable lpad: option::none, sp: cx.sp, fcx: cx}; } @@ -4556,6 +4569,8 @@ fn new_raw_block_ctxt(fcx: @fn_ctxt, llbb: BasicBlockRef) -> @block_ctxt { parent: parent_none, kind: NON_SCOPE_BLOCK, mutable cleanups: [], + mutable cleanups_dirty: true, + mutable lpad: option::none, sp: fcx.sp, fcx: fcx}; } @@ -4622,6 +4637,8 @@ fn llstaticallocas_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt { parent: parent_none, kind: SCOPE_BLOCK, mutable cleanups: [], + mutable cleanups_dirty: true, + mutable lpad: option::none, sp: fcx.sp, fcx: fcx}; } @@ -4632,6 +4649,8 @@ fn llderivedtydescs_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt { parent: parent_none, kind: SCOPE_BLOCK, mutable cleanups: [], + mutable cleanups_dirty: true, + mutable lpad: option::none, sp: fcx.sp, fcx: fcx}; } diff --git a/src/comp/middle/trans_common.rs b/src/comp/middle/trans_common.rs index cb350bcea146..a02f51d77704 100644 --- a/src/comp/middle/trans_common.rs +++ b/src/comp/middle/trans_common.rs @@ -270,7 +270,9 @@ tag cleanup { } fn add_clean(cx: @block_ctxt, val: ValueRef, ty: ty::t) { - find_scope_cx(cx).cleanups += [clean(bind drop_ty(_, val, ty))]; + let scope_cx = find_scope_cx(cx); + scope_cx.cleanups += [clean(bind drop_ty(_, val, ty))]; + scope_cx.cleanups_dirty = true; } fn add_clean_temp(cx: @block_ctxt, val: ValueRef, ty: ty::t) { fn spill_and_drop(cx: @block_ctxt, val: ValueRef, ty: ty::t) -> @@ -281,8 +283,10 @@ fn add_clean_temp(cx: @block_ctxt, val: ValueRef, ty: ty::t) { bcx = r.bcx; ret drop_ty(bcx, spilled, ty); } - find_scope_cx(cx).cleanups += + let scope_cx = find_scope_cx(cx); + scope_cx.cleanups += [clean_temp(val, bind spill_and_drop(_, val, ty))]; + scope_cx.cleanups_dirty = true; } // Note that this only works for temporaries. We should, at some point, move @@ -316,7 +320,7 @@ fn revoke_clean(cx: @block_ctxt, val: ValueRef, t: ty::t) -> @block_ctxt { std::vec::slice(sc_cx.cleanups, 0u, found as uint) + std::vec::slice(sc_cx.cleanups, (found as uint) + 1u, std::vec::len(sc_cx.cleanups)); - + sc_cx.cleanups_dirty = true; ret cx; } @@ -389,6 +393,8 @@ type block_ctxt = parent: block_parent, kind: block_kind, mutable cleanups: [cleanup], + mutable cleanups_dirty: bool, + mutable lpad: option::t, sp: span, fcx: @fn_ctxt};