Skip to content

Commit dd1cf63

Browse files
committed
Build records in two phases to avoid cleanups on partial records
1 parent 432e931 commit dd1cf63

File tree

2 files changed

+58
-5
lines changed

2 files changed

+58
-5
lines changed

src/comp/middle/trans.rs

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3973,6 +3973,21 @@ fn trans_rec(cx: @block_ctxt, fields: [ast::field],
39733973
}
39743974
let ty_fields: [ty::field] = [];
39753975
alt ty::struct(bcx_tcx(cx), t) { ty::ty_rec(flds) { ty_fields = flds; } }
3976+
3977+
tag fieldsrc {
3978+
provided(lval_result);
3979+
inherited(ValueRef);
3980+
}
3981+
type fieldval = {
3982+
dst: ValueRef,
3983+
src: fieldsrc,
3984+
ty: ty::t
3985+
};
3986+
let fieldvals: [fieldval] = [];
3987+
3988+
// We build the record in two stages so that we don't have to clean up a
3989+
// partial record if we fail: first collect all the values, then construct
3990+
// the record.
39763991
for tf: ty::field in ty_fields {
39773992
let e_ty = tf.mt.ty;
39783993
// FIXME: constraint on argument?
@@ -3984,21 +3999,43 @@ fn trans_rec(cx: @block_ctxt, fields: [ast::field],
39843999
if str::eq(f.node.ident, tf.ident) {
39854000
expr_provided = true;
39864001
let lv = trans_lval(bcx, f.node.expr);
3987-
bcx =
3988-
move_val_if_temp(lv.bcx, INIT, dst_res.val, lv, e_ty);
4002+
bcx = lv.bcx;
4003+
fieldvals += [{
4004+
dst: dst_res.val,
4005+
src: provided(lv),
4006+
ty: e_ty
4007+
}];
39894008
break;
39904009
}
39914010
}
39924011
if !expr_provided {
39934012
// FIXME: constraint on argument?
39944013
check type_is_tup_like(bcx, t);
39954014
let src_res = GEP_tup_like(bcx, t, base_val, [0, i]);
3996-
src_res =
3997-
rslt(src_res.bcx, load_if_immediate(bcx, src_res.val, e_ty));
3998-
bcx = copy_val(src_res.bcx, INIT, dst_res.val, src_res.val, e_ty);
4015+
bcx = src_res.bcx;
4016+
fieldvals += [{
4017+
dst: dst_res.val,
4018+
src: inherited(src_res.val),
4019+
ty: e_ty
4020+
}];
39994021
}
40004022
i += 1;
40014023
}
4024+
4025+
// Now build the record
4026+
for fieldval in fieldvals {
4027+
alt fieldval.src {
4028+
provided(lv) {
4029+
bcx = move_val_if_temp(bcx, INIT, fieldval.dst,
4030+
lv, fieldval.ty);
4031+
}
4032+
inherited(val) {
4033+
let val = load_if_immediate(bcx, val, fieldval.ty);
4034+
bcx = copy_val(bcx, INIT, fieldval.dst, val, fieldval.ty);
4035+
}
4036+
}
4037+
}
4038+
40024039
add_clean_temp(cx, rec_val, t);
40034040
ret rslt(bcx, rec_val);
40044041
}

src/test/run-fail/unwind-rec2.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// error-pattern:fail
2+
3+
fn build1() -> [int] {
4+
[0,0,0,0,0,0,0]
5+
}
6+
7+
fn build2() -> [int] {
8+
fail;
9+
}
10+
11+
fn main() {
12+
let blk = {
13+
node: build1(),
14+
span: build2()
15+
};
16+
}

0 commit comments

Comments
 (0)