From dd1cf63515d7703344cf18f8f44e8a1a1dedcd5f Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 19 Sep 2011 14:20:15 -0700 Subject: [PATCH] Build records in two phases to avoid cleanups on partial records --- src/comp/middle/trans.rs | 47 ++++++++++++++++++++++++++++---- src/test/run-fail/unwind-rec2.rs | 16 +++++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 src/test/run-fail/unwind-rec2.rs diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 5cddc193529..fa56780e8db 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -3973,6 +3973,21 @@ fn trans_rec(cx: @block_ctxt, fields: [ast::field], } let ty_fields: [ty::field] = []; alt ty::struct(bcx_tcx(cx), t) { ty::ty_rec(flds) { ty_fields = flds; } } + + tag fieldsrc { + provided(lval_result); + inherited(ValueRef); + } + type fieldval = { + dst: ValueRef, + src: fieldsrc, + ty: ty::t + }; + let fieldvals: [fieldval] = []; + + // We build the record in two stages so that we don't have to clean up a + // partial record if we fail: first collect all the values, then construct + // the record. for tf: ty::field in ty_fields { let e_ty = tf.mt.ty; // FIXME: constraint on argument? @@ -3984,8 +3999,12 @@ fn trans_rec(cx: @block_ctxt, fields: [ast::field], if str::eq(f.node.ident, tf.ident) { expr_provided = true; let lv = trans_lval(bcx, f.node.expr); - bcx = - move_val_if_temp(lv.bcx, INIT, dst_res.val, lv, e_ty); + bcx = lv.bcx; + fieldvals += [{ + dst: dst_res.val, + src: provided(lv), + ty: e_ty + }]; break; } } @@ -3993,12 +4012,30 @@ fn trans_rec(cx: @block_ctxt, fields: [ast::field], // FIXME: constraint on argument? check type_is_tup_like(bcx, t); let src_res = GEP_tup_like(bcx, t, base_val, [0, i]); - src_res = - rslt(src_res.bcx, load_if_immediate(bcx, src_res.val, e_ty)); - bcx = copy_val(src_res.bcx, INIT, dst_res.val, src_res.val, e_ty); + bcx = src_res.bcx; + fieldvals += [{ + dst: dst_res.val, + src: inherited(src_res.val), + ty: e_ty + }]; } i += 1; } + + // Now build the record + for fieldval in fieldvals { + alt fieldval.src { + provided(lv) { + bcx = move_val_if_temp(bcx, INIT, fieldval.dst, + lv, fieldval.ty); + } + inherited(val) { + let val = load_if_immediate(bcx, val, fieldval.ty); + bcx = copy_val(bcx, INIT, fieldval.dst, val, fieldval.ty); + } + } + } + add_clean_temp(cx, rec_val, t); ret rslt(bcx, rec_val); } diff --git a/src/test/run-fail/unwind-rec2.rs b/src/test/run-fail/unwind-rec2.rs new file mode 100644 index 00000000000..4e4afd31a84 --- /dev/null +++ b/src/test/run-fail/unwind-rec2.rs @@ -0,0 +1,16 @@ +// error-pattern:fail + +fn build1() -> [int] { + [0,0,0,0,0,0,0] +} + +fn build2() -> [int] { + fail; +} + +fn main() { + let blk = { + node: build1(), + span: build2() + }; +} \ No newline at end of file