Skip to content

Commit 1002623

Browse files
committed
Make move-mode arguments unwind correctly. Closes #939
1 parent 99236d6 commit 1002623

File tree

3 files changed

+65
-31
lines changed

3 files changed

+65
-31
lines changed

Diff for: src/comp/middle/trans.rs

+52-27
Original file line numberDiff line numberDiff line change
@@ -3752,7 +3752,8 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
37523752
for the call itself is unreachable. */
37533753
let retval = C_nil();
37543754
if !is_terminated(bcx) {
3755-
bcx = invoke_fastcall(bcx, faddr, llargs).bcx;
3755+
bcx = invoke_fastcall(bcx, faddr, llargs,
3756+
args_res.to_zero, args_res.to_revoke).bcx;
37563757
alt lliterbody {
37573758
none. {
37583759
if !ty::type_is_nil(bcx_tcx(cx), ret_ty) {
@@ -3775,12 +3776,8 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
37753776
}
37763777

37773778
// Forget about anything we moved out.
3778-
for {v: v, t: t}: {v: ValueRef, t: ty::t} in args_res.to_zero {
3779-
bcx = zero_alloca(bcx, v, t).bcx;
3780-
}
3781-
for {v: v, t: t} in args_res.to_revoke {
3782-
bcx = revoke_clean(bcx, v, t);
3783-
}
3779+
bcx = zero_and_revoke(bcx, args_res.to_zero, args_res.to_revoke);
3780+
37843781
if !by_ref { bcx = trans_block_cleanups(bcx, cx); }
37853782
let next_cx = new_sub_block_ctxt(in_cx, "next");
37863783
Br(bcx, next_cx.llbb);
@@ -3789,45 +3786,70 @@ fn trans_call(in_cx: @block_ctxt, f: @ast::expr,
37893786
ret {res: rslt(bcx, retval), by_ref: by_ref};
37903787
}
37913788

3789+
fn zero_and_revoke(bcx: @block_ctxt,
3790+
to_zero: [{v: ValueRef, t: ty::t}],
3791+
to_revoke: [{v: ValueRef, t: ty::t}]) -> @block_ctxt {
3792+
let bcx = bcx;
3793+
for {v, t} in to_zero {
3794+
bcx = zero_alloca(bcx, v, t).bcx;
3795+
}
3796+
for {v, t} in to_revoke {
3797+
bcx = revoke_clean(bcx, v, t);
3798+
}
3799+
ret bcx;
3800+
}
3801+
37923802
fn invoke(bcx: @block_ctxt, llfn: ValueRef,
37933803
llargs: [ValueRef]) -> result {
3794-
ret invoke_(bcx, llfn, llargs, Invoke);
3804+
ret invoke_(bcx, llfn, llargs, [], [], Invoke);
37953805
}
37963806

37973807
fn invoke_fastcall(bcx: @block_ctxt, llfn: ValueRef,
3798-
llargs: [ValueRef]) -> result {
3799-
ret invoke_(bcx, llfn, llargs, FastInvoke);
3808+
llargs: [ValueRef],
3809+
to_zero: [{v: ValueRef, t: ty::t}],
3810+
to_revoke: [{v: ValueRef, t: ty::t}]) -> result {
3811+
ret invoke_(bcx, llfn, llargs,
3812+
to_zero, to_revoke,
3813+
FastInvoke);
38003814
}
38013815

3802-
fn invoke_(bcx: @block_ctxt, llfn: ValueRef,
3803-
llargs: [ValueRef],
3816+
fn invoke_(bcx: @block_ctxt, llfn: ValueRef, llargs: [ValueRef],
3817+
to_zero: [{v: ValueRef, t: ty::t}],
3818+
to_revoke: [{v: ValueRef, t: ty::t}],
38043819
invoker: fn(@block_ctxt, ValueRef, [ValueRef],
38053820
BasicBlockRef, BasicBlockRef) -> ValueRef) -> result {
38063821
// FIXME: May be worth turning this into a plain call when there are no
38073822
// cleanups to run
38083823
let normal_bcx = new_sub_block_ctxt(bcx, "normal return");
38093824
let retval = invoker(bcx, llfn, llargs,
38103825
normal_bcx.llbb,
3811-
get_landing_pad(bcx));
3826+
get_landing_pad(bcx, to_zero, to_revoke));
38123827
ret rslt(normal_bcx, retval);
38133828
}
38143829

3815-
fn get_landing_pad(bcx: @block_ctxt) -> BasicBlockRef {
3816-
let scope_bcx = find_scope_for_lpad(bcx);
3817-
if scope_bcx.cleanups_dirty {
3830+
fn get_landing_pad(bcx: @block_ctxt,
3831+
to_zero: [{v: ValueRef, t: ty::t}],
3832+
to_revoke: [{v: ValueRef, t: ty::t}]
3833+
) -> BasicBlockRef {
3834+
let have_zero_or_revoke = vec::is_not_empty(to_zero)
3835+
|| vec::is_not_empty(to_revoke);
3836+
let scope_bcx = find_scope_for_lpad(bcx, have_zero_or_revoke);
3837+
if scope_bcx.lpad_dirty || have_zero_or_revoke {
38183838
let unwind_bcx = new_sub_block_ctxt(bcx, "unwind");
3819-
let lpadbb = trans_landing_pad(unwind_bcx);
3839+
let lpadbb = trans_landing_pad(unwind_bcx, to_zero, to_revoke);
38203840
scope_bcx.lpad = some(lpadbb);
3821-
scope_bcx.cleanups_dirty = false;
3841+
scope_bcx.lpad_dirty = have_zero_or_revoke;
38223842
}
38233843
assert option::is_some(scope_bcx.lpad);
38243844
ret option::get(scope_bcx.lpad);
38253845

3826-
fn find_scope_for_lpad(bcx: @block_ctxt) -> @block_ctxt {
3846+
fn find_scope_for_lpad(bcx: @block_ctxt,
3847+
have_zero_or_revoke: bool) -> @block_ctxt {
38273848
let scope_bcx = bcx;
38283849
while true {
38293850
scope_bcx = find_scope_cx(scope_bcx);
3830-
if vec::is_not_empty(scope_bcx.cleanups) {
3851+
if vec::is_not_empty(scope_bcx.cleanups)
3852+
|| have_zero_or_revoke {
38313853
ret scope_bcx;
38323854
} else {
38333855
scope_bcx = alt scope_bcx.parent {
@@ -3842,7 +3864,10 @@ fn get_landing_pad(bcx: @block_ctxt) -> BasicBlockRef {
38423864
}
38433865
}
38443866

3845-
fn trans_landing_pad(bcx: @block_ctxt) -> BasicBlockRef {
3867+
fn trans_landing_pad(bcx: @block_ctxt,
3868+
to_zero: [{v: ValueRef, t: ty::t}],
3869+
to_revoke: [{v: ValueRef, t: ty::t}]
3870+
) -> BasicBlockRef {
38463871
// The landing pad return type (the type being propagated). Not sure what
38473872
// this represents but it's determined by the personality function and
38483873
// this is what the EH proposal example uses.
@@ -3863,7 +3888,7 @@ fn trans_landing_pad(bcx: @block_ctxt) -> BasicBlockRef {
38633888
// FIXME: This seems like a very naive and redundant way to generate the
38643889
// landing pads, as we're re-generating all in-scope cleanups for each
38653890
// function call. Probably good optimization opportunities here.
3866-
let bcx = bcx;
3891+
let bcx = zero_and_revoke(bcx, to_zero, to_revoke);
38673892
let scope_cx = bcx;
38683893
while true {
38693894
scope_cx = find_scope_cx(scope_cx);
@@ -4372,7 +4397,7 @@ fn trans_put(in_cx: @block_ctxt, e: option::t<@ast::expr>) -> result {
43724397
llargs += [r.val];
43734398
}
43744399
}
4375-
bcx = invoke_fastcall(bcx, llcallee, llargs).bcx;
4400+
bcx = invoke_fastcall(bcx, llcallee, llargs, [], []).bcx;
43764401
bcx = trans_block_cleanups(bcx, cx);
43774402
let next_cx = new_sub_block_ctxt(in_cx, "next");
43784403
Br(bcx, next_cx.llbb);
@@ -4638,7 +4663,7 @@ fn new_block_ctxt(cx: @fn_ctxt, parent: block_parent, kind: block_kind,
46384663
parent: parent,
46394664
kind: kind,
46404665
mutable cleanups: [],
4641-
mutable cleanups_dirty: true,
4666+
mutable lpad_dirty: true,
46424667
mutable lpad: option::none,
46434668
sp: cx.sp,
46444669
fcx: cx};
@@ -4674,7 +4699,7 @@ fn new_raw_block_ctxt(fcx: @fn_ctxt, llbb: BasicBlockRef) -> @block_ctxt {
46744699
parent: parent_none,
46754700
kind: NON_SCOPE_BLOCK,
46764701
mutable cleanups: [],
4677-
mutable cleanups_dirty: true,
4702+
mutable lpad_dirty: true,
46784703
mutable lpad: option::none,
46794704
sp: fcx.sp,
46804705
fcx: fcx};
@@ -4741,7 +4766,7 @@ fn llstaticallocas_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt {
47414766
parent: parent_none,
47424767
kind: SCOPE_BLOCK,
47434768
mutable cleanups: [],
4744-
mutable cleanups_dirty: true,
4769+
mutable lpad_dirty: true,
47454770
mutable lpad: option::none,
47464771
sp: fcx.sp,
47474772
fcx: fcx};
@@ -4753,7 +4778,7 @@ fn llderivedtydescs_block_ctxt(fcx: @fn_ctxt) -> @block_ctxt {
47534778
parent: parent_none,
47544779
kind: SCOPE_BLOCK,
47554780
mutable cleanups: [],
4756-
mutable cleanups_dirty: true,
4781+
mutable lpad_dirty: true,
47574782
mutable lpad: option::none,
47584783
sp: fcx.sp,
47594784
fcx: fcx};

Diff for: src/comp/middle/trans_common.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ tag cleanup {
273273
fn add_clean(cx: @block_ctxt, val: ValueRef, ty: ty::t) {
274274
let scope_cx = find_scope_cx(cx);
275275
scope_cx.cleanups += [clean(bind drop_ty(_, val, ty))];
276-
scope_cx.cleanups_dirty = true;
276+
scope_cx.lpad_dirty = true;
277277
}
278278
fn add_clean_temp(cx: @block_ctxt, val: ValueRef, ty: ty::t) {
279279
fn spill_and_drop(cx: @block_ctxt, val: ValueRef, ty: ty::t) ->
@@ -287,7 +287,7 @@ fn add_clean_temp(cx: @block_ctxt, val: ValueRef, ty: ty::t) {
287287
let scope_cx = find_scope_cx(cx);
288288
scope_cx.cleanups +=
289289
[clean_temp(val, bind spill_and_drop(_, val, ty))];
290-
scope_cx.cleanups_dirty = true;
290+
scope_cx.lpad_dirty = true;
291291
}
292292

293293
// Note that this only works for temporaries. We should, at some point, move
@@ -321,7 +321,7 @@ fn revoke_clean(cx: @block_ctxt, val: ValueRef, t: ty::t) -> @block_ctxt {
321321
std::vec::slice(sc_cx.cleanups, 0u, found as uint) +
322322
std::vec::slice(sc_cx.cleanups, (found as uint) + 1u,
323323
std::vec::len(sc_cx.cleanups));
324-
sc_cx.cleanups_dirty = true;
324+
sc_cx.lpad_dirty = true;
325325
ret cx;
326326
}
327327

@@ -396,7 +396,7 @@ type block_ctxt =
396396
parent: block_parent,
397397
kind: block_kind,
398398
mutable cleanups: [cleanup],
399-
mutable cleanups_dirty: bool,
399+
mutable lpad_dirty: bool,
400400
mutable lpad: option::t<BasicBlockRef>,
401401
sp: span,
402402
fcx: @fn_ctxt};

Diff for: src/test/run-fail/unwind-move.rs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// error-pattern:fail
2+
fn f(-a: @int) {
3+
fail;
4+
}
5+
6+
fn main() {
7+
let a = @0;
8+
f(a);
9+
}

0 commit comments

Comments
 (0)