Convert more expression types to use DPS
expr_rec, expr_tup, most of the exprs that don't return anything. Make trans_ret almost trivial by using destination adaptors (trans_save_in, trans_by_ref). Issue #667
This commit is contained in:
parent
345b5a47bd
commit
5837975f95
1 changed files with 219 additions and 204 deletions
|
|
@ -668,6 +668,14 @@ fn bump_ptr(bcx: @block_ctxt, t: ty::t, base: ValueRef, sz: ValueRef) ->
|
|||
} else { bumped }
|
||||
}
|
||||
|
||||
// GEP_tup_like is a pain to use if you always have to precede it with a
|
||||
// check.
|
||||
fn GEP_tup_like_1(cx: @block_ctxt, t: ty::t, base: ValueRef, ixs: [int])
|
||||
-> result {
|
||||
check type_is_tup_like(cx, t);
|
||||
ret GEP_tup_like(cx, t, base, ixs);
|
||||
}
|
||||
|
||||
// Replacement for the LLVM 'GEP' instruction when field-indexing into a
|
||||
// tuple-like structure (tup, rec) with a static index. This one is driven off
|
||||
// ty::struct and knows what to do when it runs into a ty_param stuck in the
|
||||
|
|
@ -1514,11 +1522,14 @@ fn compare_scalar_types(cx: @block_ctxt, lhs: ValueRef, rhs: ValueRef,
|
|||
}
|
||||
}
|
||||
ty::ty_type. {
|
||||
ret trans_fail(cx, none, "attempt to compare values of type type");
|
||||
ret rslt(trans_fail(cx, none,
|
||||
"attempt to compare values of type type"),
|
||||
C_nil());
|
||||
}
|
||||
ty::ty_native(_) {
|
||||
ret trans_fail(cx, none::<span>,
|
||||
"attempt to compare values of type native");
|
||||
let cx = trans_fail(cx, none::<span>,
|
||||
"attempt to compare values of type native");
|
||||
ret rslt(cx, C_nil());
|
||||
}
|
||||
_ {
|
||||
// Should never get here, because t is scalar.
|
||||
|
|
@ -3988,60 +3999,44 @@ fn trans_landing_pad(bcx: @block_ctxt,
|
|||
ret bcx.llbb;
|
||||
}
|
||||
|
||||
fn trans_tup(cx: @block_ctxt, elts: [@ast::expr], id: ast::node_id) ->
|
||||
result {
|
||||
let bcx = cx;
|
||||
fn trans_tup(bcx: @block_ctxt, elts: [@ast::expr], id: ast::node_id,
|
||||
dest: dest) -> @block_ctxt {
|
||||
let t = node_id_type(bcx.fcx.lcx.ccx, id);
|
||||
let tup_res = alloc_ty(bcx, t);
|
||||
let tup_val = tup_res.val;
|
||||
bcx = tup_res.bcx;
|
||||
let dst = alt dest { save_in(addr) { addr } };
|
||||
|
||||
// Like trans_rec, we'll collect the fields of the tuple then build it, so
|
||||
// that if we fail in between we don't have to deal with cleaning up a
|
||||
// partial tuple
|
||||
let tupfields: [(ValueRef, lval_result, ty::t)] = [];
|
||||
let i: int = 0;
|
||||
let tupfields = [], i = 0;
|
||||
for e in elts {
|
||||
let e_ty = ty::expr_ty(cx.fcx.lcx.ccx.tcx, e);
|
||||
let e_ty = ty::expr_ty(bcx_tcx(bcx), e);
|
||||
let src = trans_lval(bcx, e);
|
||||
bcx = src.bcx;
|
||||
// FIXME: constraint on argument?
|
||||
check type_is_tup_like(bcx, t);
|
||||
let dst_res = GEP_tup_like(bcx, t, tup_val, [0, i]);
|
||||
tupfields += [(dst_res.val, src, e_ty)];
|
||||
let dst_res = GEP_tup_like_1(src.bcx, t, dst, [0, i]);
|
||||
bcx = dst_res.bcx;
|
||||
tupfields += [(dst_res.val, src, e_ty)];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Fill in the tuple fields
|
||||
for (dst, src, t) in tupfields {
|
||||
bcx = move_val_if_temp(bcx, INIT, dst, src, t);
|
||||
}
|
||||
|
||||
// Only register the cleanups after the tuple is built
|
||||
add_clean_temp(cx, tup_val, t);
|
||||
ret rslt(bcx, tup_val);
|
||||
ret bcx;
|
||||
}
|
||||
|
||||
fn trans_rec(cx: @block_ctxt, fields: [ast::field],
|
||||
base: option::t<@ast::expr>, id: ast::node_id) -> result {
|
||||
let bcx = cx;
|
||||
fn trans_rec(bcx: @block_ctxt, fields: [ast::field],
|
||||
base: option::t<@ast::expr>, id: ast::node_id,
|
||||
dest: dest) -> @block_ctxt {
|
||||
let t = node_id_type(bcx_ccx(bcx), id);
|
||||
let rec_res = alloc_ty(bcx, t);
|
||||
let rec_val = rec_res.val;
|
||||
bcx = rec_res.bcx;
|
||||
let i: int = 0;
|
||||
let base_val = C_nil();
|
||||
alt base {
|
||||
none. { }
|
||||
let dst = alt dest { save_in(addr) { addr } };
|
||||
|
||||
let base_val = alt base {
|
||||
some(bexp) {
|
||||
let base_res = trans_expr(bcx, bexp);
|
||||
bcx = base_res.bcx;
|
||||
base_val = base_res.val;
|
||||
base_res.val
|
||||
}
|
||||
}
|
||||
let ty_fields: [ty::field] = [];
|
||||
alt ty::struct(bcx_tcx(cx), t) { ty::ty_rec(flds) { ty_fields = flds; } }
|
||||
none. { C_nil() }
|
||||
};
|
||||
|
||||
tag fieldsrc {
|
||||
provided(lval_result);
|
||||
|
|
@ -4052,45 +4047,36 @@ fn trans_rec(cx: @block_ctxt, fields: [ast::field],
|
|||
src: fieldsrc,
|
||||
ty: ty::t
|
||||
};
|
||||
let fieldvals: [fieldval] = [];
|
||||
|
||||
let ty_fields = alt ty::struct(bcx_tcx(bcx), t) { ty::ty_rec(f) { f } };
|
||||
let fieldvals = [], i = 0;
|
||||
// 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?
|
||||
check type_is_tup_like(bcx, t);
|
||||
let dst_res = GEP_tup_like(bcx, t, rec_val, [0, i]);
|
||||
bcx = dst_res.bcx;
|
||||
let expr_provided = false;
|
||||
for f: ast::field in fields {
|
||||
if str::eq(f.node.ident, tf.ident) {
|
||||
expr_provided = true;
|
||||
for tf in ty_fields {
|
||||
let {bcx: a_bcx, val: addr} = GEP_tup_like_1(bcx, t, dst, [0, i]);
|
||||
bcx = a_bcx;
|
||||
// FIXME make this happen in a single pass, again, somehow make the
|
||||
// dps helpers tie the cleanups together in the right way (we do not
|
||||
// want to create intermediates for these and then move them again)
|
||||
fn test(n: str, f: ast::field) -> bool { str::eq(f.node.ident, n) }
|
||||
// FIXME make this {|f| str::eq(f.node.ident, tf.ident)} again when
|
||||
// bug #913 is fixed
|
||||
let s = alt vec::find(bind test(tf.ident, _), fields) {
|
||||
some(f) {
|
||||
let lv = trans_lval(bcx, f.node.expr);
|
||||
bcx = lv.bcx;
|
||||
fieldvals += [{
|
||||
dst: dst_res.val,
|
||||
src: provided(lv),
|
||||
ty: e_ty
|
||||
}];
|
||||
break;
|
||||
provided(lv)
|
||||
}
|
||||
}
|
||||
if !expr_provided {
|
||||
// FIXME: constraint on argument?
|
||||
check type_is_tup_like(bcx, t);
|
||||
let src_res = GEP_tup_like(bcx, t, base_val, [0, i]);
|
||||
bcx = src_res.bcx;
|
||||
fieldvals += [{
|
||||
dst: dst_res.val,
|
||||
src: inherited(src_res.val),
|
||||
ty: e_ty
|
||||
}];
|
||||
}
|
||||
none. {
|
||||
let src_res = GEP_tup_like_1(bcx, t, base_val, [0, i]);
|
||||
bcx = src_res.bcx;
|
||||
inherited(src_res.val)
|
||||
}
|
||||
};
|
||||
fieldvals += [{dst: addr, src: s, ty: tf.mt.ty}];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
// Now build the record
|
||||
for fieldval in fieldvals {
|
||||
alt fieldval.src {
|
||||
|
|
@ -4104,9 +4090,7 @@ fn trans_rec(cx: @block_ctxt, fields: [ast::field],
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_clean_temp(cx, rec_val, t);
|
||||
ret rslt(bcx, rec_val);
|
||||
ret bcx;
|
||||
}
|
||||
|
||||
fn trans_expr(cx: @block_ctxt, e: @ast::expr) -> result {
|
||||
|
|
@ -4247,46 +4231,6 @@ fn trans_expr(cx: @block_ctxt, e: @ast::expr) -> result {
|
|||
ast::expr_bind(f, args) { ret trans_bind(cx, f, args, e.id); }
|
||||
ast::expr_cast(val, _) { ret trans_cast(cx, val, e.id); }
|
||||
ast::expr_vec(args, _) { ret tvec::trans_vec(cx, args, e.id); }
|
||||
ast::expr_rec(args, base) { ret trans_rec(cx, args, base, e.id); }
|
||||
ast::expr_tup(args) { ret trans_tup(cx, args, e.id); }
|
||||
ast::expr_mac(_) { ret bcx_ccx(cx).sess.bug("unexpanded macro"); }
|
||||
ast::expr_fail(expr) { ret trans_fail_expr(cx, some(e.span), expr); }
|
||||
ast::expr_log(lvl, a) { ret trans_log(lvl, cx, a); }
|
||||
ast::expr_assert(a) { ret trans_check_expr(cx, a, "Assertion"); }
|
||||
ast::expr_check(ast::checked., a) {
|
||||
ret trans_check_expr(cx, a, "Predicate");
|
||||
}
|
||||
ast::expr_check(ast::unchecked., a) {
|
||||
/* Claims are turned on and off by a global variable
|
||||
that the RTS sets. This case generates code to
|
||||
check the value of that variable, doing nothing
|
||||
if it's set to false and acting like a check
|
||||
otherwise. */
|
||||
let c =
|
||||
get_extern_const(bcx_ccx(cx).externs, bcx_ccx(cx).llmod,
|
||||
"check_claims", T_bool());
|
||||
let cond = Load(cx, c);
|
||||
|
||||
let then_cx = new_scope_block_ctxt(cx, "claim_then");
|
||||
let check_res = trans_check_expr(then_cx, a, "Claim");
|
||||
let else_cx = new_scope_block_ctxt(cx, "else");
|
||||
let els = rslt(else_cx, C_nil());
|
||||
|
||||
CondBr(cx, cond, then_cx.llbb, else_cx.llbb);
|
||||
ret rslt(join_branches(cx, [check_res, els]), C_nil());
|
||||
}
|
||||
ast::expr_break. { ret trans_break(e.span, cx); }
|
||||
ast::expr_cont. { ret trans_cont(e.span, cx); }
|
||||
ast::expr_ret(ex) { ret trans_ret(cx, ex); }
|
||||
ast::expr_put(ex) { ret trans_put(cx, ex); }
|
||||
ast::expr_be(ex) {
|
||||
// Ideally, the expr_be tag would have a precondition
|
||||
// that is_call_expr(ex) -- but we don't support that
|
||||
// yet
|
||||
// FIXME
|
||||
check (ast_util::is_call_expr(ex));
|
||||
ret trans_be(cx, ex);
|
||||
}
|
||||
ast::expr_anon_obj(anon_obj) {
|
||||
ret trans_anon_obj(cx, e.span, anon_obj, e.id);
|
||||
}
|
||||
|
|
@ -4309,6 +4253,33 @@ fn trans_expr(cx: @block_ctxt, e: @ast::expr) -> result {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME add support for INIT/DROP_EXISTING
|
||||
fn trans_expr_save_in(bcx: @block_ctxt, e: @ast::expr, dest: ValueRef)
|
||||
-> @block_ctxt {
|
||||
let tcx = bcx_tcx(bcx), t = ty::expr_ty(tcx, e);
|
||||
if ty::type_is_bot(tcx, t) || ty::type_is_nil(tcx, t) {
|
||||
ret trans_expr_dps(bcx, e, ignore);
|
||||
} else if type_is_immediate(bcx_ccx(bcx), t) {
|
||||
let cell = empty_dest_cell();
|
||||
bcx = trans_expr_dps(bcx, e, by_val(cell));
|
||||
Store(bcx, *cell, dest);
|
||||
ret bcx;
|
||||
} else {
|
||||
ret trans_expr_dps(bcx, e, save_in(dest));
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_expr_by_ref(bcx: @block_ctxt, e: @ast::expr) -> result {
|
||||
let cell = empty_dest_cell();
|
||||
bcx = trans_expr_dps(bcx, e, by_ref(cell));
|
||||
ret rslt(bcx, *cell);
|
||||
}
|
||||
|
||||
// Invariants:
|
||||
// - things returning nil get dest=ignore
|
||||
// - any lvalue expr may be given dest=by_ref
|
||||
// - exprs returning an immediate get by_val (or by_ref when lval)
|
||||
// - exprs returning non-immediates get save_in (or by_ref when lval)
|
||||
fn trans_expr_dps(bcx: @block_ctxt, e: @ast::expr, dest: dest)
|
||||
-> @block_ctxt {
|
||||
alt e.node {
|
||||
|
|
@ -4330,6 +4301,72 @@ fn trans_expr_dps(bcx: @block_ctxt, e: @ast::expr, dest: dest)
|
|||
if sub_cx.unreachable { Unreachable(next_cx); }
|
||||
ret next_cx;
|
||||
}
|
||||
ast::expr_rec(args, base) {
|
||||
ret trans_rec(bcx, args, base, e.id, dest);
|
||||
}
|
||||
ast::expr_tup(args) { ret trans_tup(bcx, args, e.id, dest); }
|
||||
ast::expr_break. {
|
||||
assert dest == ignore;
|
||||
ret trans_break(e.span, bcx);
|
||||
}
|
||||
ast::expr_cont. {
|
||||
assert dest == ignore;
|
||||
ret trans_cont(e.span, bcx);
|
||||
}
|
||||
ast::expr_ret(ex) {
|
||||
assert dest == ignore;
|
||||
ret trans_ret(bcx, ex);
|
||||
}
|
||||
ast::expr_be(ex) {
|
||||
// Ideally, the expr_be tag would have a precondition
|
||||
// that is_call_expr(ex) -- but we don't support that
|
||||
// yet
|
||||
// FIXME
|
||||
check (ast_util::is_call_expr(ex));
|
||||
ret trans_be(bcx, ex);
|
||||
}
|
||||
ast::expr_put(ex) {
|
||||
assert dest == ignore;
|
||||
ret trans_put(bcx, ex);
|
||||
}
|
||||
ast::expr_fail(expr) {
|
||||
assert dest == ignore;
|
||||
ret trans_fail_expr(bcx, some(e.span), expr);
|
||||
}
|
||||
ast::expr_log(lvl, a) {
|
||||
assert dest == ignore;
|
||||
ret trans_log(lvl, bcx, a);
|
||||
}
|
||||
ast::expr_assert(a) {
|
||||
assert dest == ignore;
|
||||
ret trans_check_expr(bcx, a, "Assertion");
|
||||
}
|
||||
ast::expr_check(ast::checked., a) {
|
||||
assert dest == ignore;
|
||||
ret trans_check_expr(bcx, a, "Predicate");
|
||||
}
|
||||
ast::expr_check(ast::unchecked., a) {
|
||||
assert dest == ignore;
|
||||
/* Claims are turned on and off by a global variable
|
||||
that the RTS sets. This case generates code to
|
||||
check the value of that variable, doing nothing
|
||||
if it's set to false and acting like a check
|
||||
otherwise. */
|
||||
let c =
|
||||
get_extern_const(bcx_ccx(bcx).externs, bcx_ccx(bcx).llmod,
|
||||
"check_claims", T_bool());
|
||||
let cond = Load(bcx, c);
|
||||
|
||||
let then_cx = new_scope_block_ctxt(bcx, "claim_then");
|
||||
let check_cx = trans_check_expr(then_cx, a, "Claim");
|
||||
let else_cx = new_scope_block_ctxt(bcx, "else");
|
||||
|
||||
CondBr(bcx, cond, then_cx.llbb, else_cx.llbb);
|
||||
ret join_branches(bcx, [rslt(check_cx, C_nil()),
|
||||
rslt(else_cx, C_nil())]);
|
||||
}
|
||||
|
||||
ast::expr_mac(_) { ret bcx_ccx(bcx).sess.bug("unexpanded macro"); }
|
||||
// Convert back from result to DPS
|
||||
_ {
|
||||
let lv = trans_lval(bcx, e);
|
||||
|
|
@ -4337,12 +4374,19 @@ fn trans_expr_dps(bcx: @block_ctxt, e: @ast::expr, dest: dest)
|
|||
let ty = ty::expr_ty(bcx_tcx(bcx), e);
|
||||
alt dest {
|
||||
by_val(cell) {
|
||||
if is_mem {
|
||||
bcx = take_ty(bcx, val, ty);
|
||||
*cell = Load(bcx, val);
|
||||
} else {
|
||||
if !is_mem {
|
||||
revoke_clean(bcx, val);
|
||||
*cell = val;
|
||||
} else if ty::type_is_unique(bcx_tcx(bcx), ty) {
|
||||
// Do a song and a dance to work around the fact that take_ty
|
||||
// for unique boxes overwrites the pointer.
|
||||
let oldval = Load(bcx, val);
|
||||
bcx = take_ty(bcx, val, ty);
|
||||
*cell = Load(bcx, val);
|
||||
Store(bcx, oldval, val);
|
||||
} else {
|
||||
bcx = take_ty(bcx, val, ty);
|
||||
*cell = Load(bcx, val);
|
||||
}
|
||||
}
|
||||
by_ref(cell) {
|
||||
|
|
@ -4402,28 +4446,24 @@ fn load_if_immediate(cx: @block_ctxt, v: ValueRef, t: ty::t) -> ValueRef {
|
|||
ret v;
|
||||
}
|
||||
|
||||
fn trans_log(lvl: int, cx: @block_ctxt, e: @ast::expr) -> result {
|
||||
fn trans_log(lvl: int, cx: @block_ctxt, e: @ast::expr) -> @block_ctxt {
|
||||
let lcx = cx.fcx.lcx;
|
||||
let modname = str::connect(lcx.module_path, "::");
|
||||
let global;
|
||||
if lcx.ccx.module_data.contains_key(modname) {
|
||||
global = lcx.ccx.module_data.get(modname);
|
||||
let global = if lcx.ccx.module_data.contains_key(modname) {
|
||||
lcx.ccx.module_data.get(modname)
|
||||
} else {
|
||||
let s =
|
||||
link::mangle_internal_name_by_path_and_seq(lcx.ccx,
|
||||
lcx.module_path,
|
||||
"loglevel");
|
||||
global =
|
||||
str::as_buf(s,
|
||||
{|buf|
|
||||
llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), buf)
|
||||
});
|
||||
let s = link::mangle_internal_name_by_path_and_seq(
|
||||
lcx.ccx, lcx.module_path, "loglevel");
|
||||
let global = str::as_buf(s, {|buf|
|
||||
llvm::LLVMAddGlobal(lcx.ccx.llmod, T_int(), buf)
|
||||
});
|
||||
llvm::LLVMSetGlobalConstant(global, False);
|
||||
llvm::LLVMSetInitializer(global, C_null(T_int()));
|
||||
llvm::LLVMSetLinkage(global,
|
||||
lib::llvm::LLVMInternalLinkage as llvm::Linkage);
|
||||
lcx.ccx.module_data.insert(modname, global);
|
||||
}
|
||||
global
|
||||
};
|
||||
let log_cx = new_scope_block_ctxt(cx, "log");
|
||||
let after_cx = new_sub_block_ctxt(cx, "after");
|
||||
let load = Load(cx, global);
|
||||
|
|
@ -4442,7 +4482,6 @@ fn trans_log(lvl: int, cx: @block_ctxt, e: @ast::expr) -> result {
|
|||
r = spill_if_immediate(log_bcx, sub.val, e_ty);
|
||||
log_bcx = r.bcx;
|
||||
let llvalptr = r.val;
|
||||
|
||||
let llval_i8 = PointerCast(log_bcx, llvalptr, T_ptr(T_i8()));
|
||||
|
||||
Call(log_bcx, bcx_ccx(log_bcx).upcalls.log_type,
|
||||
|
|
@ -4450,22 +4489,21 @@ fn trans_log(lvl: int, cx: @block_ctxt, e: @ast::expr) -> result {
|
|||
|
||||
log_bcx = trans_block_cleanups(log_bcx, log_cx);
|
||||
Br(log_bcx, after_cx.llbb);
|
||||
ret rslt(after_cx, C_nil());
|
||||
ret after_cx;
|
||||
}
|
||||
|
||||
fn trans_check_expr(cx: @block_ctxt, e: @ast::expr, s: str) -> result {
|
||||
fn trans_check_expr(cx: @block_ctxt, e: @ast::expr, s: str) -> @block_ctxt {
|
||||
let cond_res = trans_expr(cx, e);
|
||||
let expr_str = s + " " + expr_to_str(e) + " failed";
|
||||
let fail_cx = new_sub_block_ctxt(cx, "fail");
|
||||
trans_fail(fail_cx, some::<span>(e.span), expr_str);
|
||||
let next_cx = new_sub_block_ctxt(cx, "next");
|
||||
CondBr(cond_res.bcx, cond_res.val, next_cx.llbb, fail_cx.llbb);
|
||||
ret rslt(next_cx, C_nil());
|
||||
ret next_cx;
|
||||
}
|
||||
|
||||
fn trans_fail_expr(cx: @block_ctxt, sp_opt: option::t<span>,
|
||||
fail_expr: option::t<@ast::expr>) -> result {
|
||||
let bcx = cx;
|
||||
fn trans_fail_expr(bcx: @block_ctxt, sp_opt: option::t<span>,
|
||||
fail_expr: option::t<@ast::expr>) -> @block_ctxt {
|
||||
alt fail_expr {
|
||||
some(expr) {
|
||||
let tcx = bcx_tcx(bcx);
|
||||
|
|
@ -4474,51 +4512,49 @@ fn trans_fail_expr(cx: @block_ctxt, sp_opt: option::t<span>,
|
|||
bcx = expr_res.bcx;
|
||||
|
||||
if ty::type_is_str(tcx, e_ty) {
|
||||
let data =
|
||||
tvec::get_dataptr(bcx, expr_res.val,
|
||||
type_of_or_i8(bcx,
|
||||
ty::mk_mach(tcx,
|
||||
ast::ty_u8)));
|
||||
let data = tvec::get_dataptr(
|
||||
bcx, expr_res.val, type_of_or_i8(
|
||||
bcx, ty::mk_mach(tcx, ast::ty_u8)));
|
||||
ret trans_fail_value(bcx, sp_opt, data);
|
||||
} else if bcx.unreachable {
|
||||
ret rslt(bcx, C_nil());
|
||||
ret bcx;
|
||||
} else {
|
||||
bcx_ccx(cx).sess.span_bug(expr.span,
|
||||
"fail called with unsupported type " +
|
||||
ty_to_str(tcx, e_ty));
|
||||
bcx_ccx(bcx).sess.span_bug(
|
||||
expr.span, "fail called with unsupported type " +
|
||||
ty_to_str(tcx, e_ty));
|
||||
}
|
||||
}
|
||||
_ { ret trans_fail(bcx, sp_opt, "explicit failure"); }
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_fail(cx: @block_ctxt, sp_opt: option::t<span>, fail_str: str) ->
|
||||
result {
|
||||
let V_fail_str = C_cstr(bcx_ccx(cx), fail_str);
|
||||
ret trans_fail_value(cx, sp_opt, V_fail_str);
|
||||
fn trans_fail(bcx: @block_ctxt, sp_opt: option::t<span>, fail_str: str) ->
|
||||
@block_ctxt {
|
||||
let V_fail_str = C_cstr(bcx_ccx(bcx), fail_str);
|
||||
ret trans_fail_value(bcx, sp_opt, V_fail_str);
|
||||
}
|
||||
|
||||
fn trans_fail_value(cx: @block_ctxt, sp_opt: option::t<span>,
|
||||
V_fail_str: ValueRef) -> result {
|
||||
fn trans_fail_value(bcx: @block_ctxt, sp_opt: option::t<span>,
|
||||
V_fail_str: ValueRef) -> @block_ctxt {
|
||||
let V_filename;
|
||||
let V_line;
|
||||
alt sp_opt {
|
||||
some(sp) {
|
||||
let loc = bcx_ccx(cx).sess.lookup_pos(sp.lo);
|
||||
V_filename = C_cstr(bcx_ccx(cx), loc.filename);
|
||||
let loc = bcx_ccx(bcx).sess.lookup_pos(sp.lo);
|
||||
V_filename = C_cstr(bcx_ccx(bcx), loc.filename);
|
||||
V_line = loc.line as int;
|
||||
}
|
||||
none. { V_filename = C_cstr(bcx_ccx(cx), "<runtime>"); V_line = 0; }
|
||||
none. { V_filename = C_cstr(bcx_ccx(bcx), "<runtime>"); V_line = 0; }
|
||||
}
|
||||
let V_str = PointerCast(cx, V_fail_str, T_ptr(T_i8()));
|
||||
V_filename = PointerCast(cx, V_filename, T_ptr(T_i8()));
|
||||
let args = [cx.fcx.lltaskptr, V_str, V_filename, C_int(V_line)];
|
||||
let cx = invoke(cx, bcx_ccx(cx).upcalls._fail, args);
|
||||
Unreachable(cx);
|
||||
ret rslt(cx, C_nil());
|
||||
let V_str = PointerCast(bcx, V_fail_str, T_ptr(T_i8()));
|
||||
V_filename = PointerCast(bcx, V_filename, T_ptr(T_i8()));
|
||||
let args = [bcx.fcx.lltaskptr, V_str, V_filename, C_int(V_line)];
|
||||
let bcx = invoke(bcx, bcx_ccx(bcx).upcalls._fail, args);
|
||||
Unreachable(bcx);
|
||||
ret bcx;
|
||||
}
|
||||
|
||||
fn trans_put(in_cx: @block_ctxt, e: option::t<@ast::expr>) -> result {
|
||||
fn trans_put(in_cx: @block_ctxt, e: option::t<@ast::expr>) -> @block_ctxt {
|
||||
let cx = new_scope_block_ctxt(in_cx, "put");
|
||||
Br(in_cx, cx.llbb);
|
||||
let llcallee = C_nil();
|
||||
|
|
@ -4556,14 +4592,13 @@ fn trans_put(in_cx: @block_ctxt, e: option::t<@ast::expr>) -> result {
|
|||
let next_cx = new_sub_block_ctxt(in_cx, "next");
|
||||
if bcx.unreachable { Unreachable(next_cx); }
|
||||
Br(bcx, next_cx.llbb);
|
||||
ret rslt(next_cx, C_nil());
|
||||
ret next_cx;
|
||||
}
|
||||
|
||||
fn trans_break_cont(sp: span, cx: @block_ctxt, to_end: bool) -> result {
|
||||
let bcx = cx;
|
||||
fn trans_break_cont(sp: span, bcx: @block_ctxt, to_end: bool)
|
||||
-> @block_ctxt {
|
||||
// Locate closest loop block, outputting cleanup as we go.
|
||||
|
||||
let cleanup_cx = cx;
|
||||
let cleanup_cx = bcx;
|
||||
while true {
|
||||
bcx = trans_block_cleanups(bcx, cleanup_cx);
|
||||
alt copy cleanup_cx.kind {
|
||||
|
|
@ -4577,62 +4612,42 @@ fn trans_break_cont(sp: span, cx: @block_ctxt, to_end: bool) -> result {
|
|||
}
|
||||
}
|
||||
Unreachable(bcx);
|
||||
ret rslt(bcx, C_nil());
|
||||
ret bcx;
|
||||
}
|
||||
_ {
|
||||
alt cleanup_cx.parent {
|
||||
parent_some(cx) { cleanup_cx = cx; }
|
||||
parent_none. {
|
||||
bcx_ccx(cx).sess.span_fatal(sp,
|
||||
if to_end {
|
||||
"Break"
|
||||
} else { "Cont" } +
|
||||
" outside a loop");
|
||||
bcx_ccx(bcx).sess.span_fatal
|
||||
(sp, if to_end { "Break" } else { "Cont" } +
|
||||
" outside a loop");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we get here without returning, it's a bug
|
||||
|
||||
bcx_ccx(cx).sess.bug("in trans::trans_break_cont()");
|
||||
bcx_ccx(bcx).sess.bug("in trans::trans_break_cont()");
|
||||
}
|
||||
|
||||
fn trans_break(sp: span, cx: @block_ctxt) -> result {
|
||||
fn trans_break(sp: span, cx: @block_ctxt) -> @block_ctxt {
|
||||
ret trans_break_cont(sp, cx, true);
|
||||
}
|
||||
|
||||
fn trans_cont(sp: span, cx: @block_ctxt) -> result {
|
||||
fn trans_cont(sp: span, cx: @block_ctxt) -> @block_ctxt {
|
||||
ret trans_break_cont(sp, cx, false);
|
||||
}
|
||||
|
||||
fn trans_ret(cx: @block_ctxt, e: option::t<@ast::expr>) -> result {
|
||||
let bcx = cx;
|
||||
fn trans_ret(bcx: @block_ctxt, e: option::t<@ast::expr>) -> @block_ctxt {
|
||||
let cleanup_cx = bcx;
|
||||
alt e {
|
||||
some(x) {
|
||||
let t = ty::expr_ty(bcx_tcx(cx), x);
|
||||
let lv = trans_lval(cx, x);
|
||||
bcx = lv.bcx;
|
||||
if ty::type_is_nil(bcx_tcx(cx), t) {
|
||||
// Don't write nil
|
||||
} else if ast_util::ret_by_ref(cx.fcx.ret_style) {
|
||||
assert lv.is_mem;
|
||||
Store(bcx, lv.val, cx.fcx.llretptr);
|
||||
if ast_util::ret_by_ref(bcx.fcx.ret_style) {
|
||||
let {bcx: cx, val} = trans_expr_by_ref(bcx, x);
|
||||
Store(cx, val, bcx.fcx.llretptr);
|
||||
bcx = cx;
|
||||
} else {
|
||||
let is_local = alt x.node {
|
||||
ast::expr_path(p) {
|
||||
alt bcx_tcx(bcx).def_map.get(x.id) {
|
||||
ast::def_local(_, _) { true }
|
||||
_ { false }
|
||||
}
|
||||
}
|
||||
_ { false }
|
||||
};
|
||||
if is_local {
|
||||
bcx = move_val(bcx, INIT, cx.fcx.llretptr, lv, t);
|
||||
} else {
|
||||
bcx = move_val_if_temp(bcx, INIT, cx.fcx.llretptr, lv, t);
|
||||
}
|
||||
bcx = trans_expr_save_in(bcx, x, bcx.fcx.llretptr);
|
||||
}
|
||||
}
|
||||
_ {}
|
||||
|
|
@ -4640,7 +4655,6 @@ fn trans_ret(cx: @block_ctxt, e: option::t<@ast::expr>) -> result {
|
|||
// run all cleanups and back out.
|
||||
|
||||
let more_cleanups: bool = true;
|
||||
let cleanup_cx = cx;
|
||||
while more_cleanups {
|
||||
bcx = trans_block_cleanups(bcx, cleanup_cx);
|
||||
alt cleanup_cx.parent {
|
||||
|
|
@ -4650,18 +4664,16 @@ fn trans_ret(cx: @block_ctxt, e: option::t<@ast::expr>) -> result {
|
|||
}
|
||||
build_return(bcx);
|
||||
Unreachable(bcx);
|
||||
ret rslt(bcx, C_nil());
|
||||
ret bcx;
|
||||
}
|
||||
|
||||
fn build_return(bcx: @block_ctxt) { Br(bcx, bcx_fcx(bcx).llreturn); }
|
||||
|
||||
// fn trans_be(cx: &@block_ctxt, e: &@ast::expr) -> result {
|
||||
fn trans_be(cx: @block_ctxt, e: @ast::expr) : ast_util::is_call_expr(e) ->
|
||||
result {
|
||||
|
||||
@block_ctxt {
|
||||
// FIXME: Turn this into a real tail call once
|
||||
// calling convention issues are settled
|
||||
|
||||
ret trans_ret(cx, some(e));
|
||||
}
|
||||
|
||||
|
|
@ -4999,7 +5011,10 @@ fn trans_block_dps(bcx: @block_ctxt, b: ast::blk, dest: dest)
|
|||
bcx = trans_stmt(bcx, *s);
|
||||
}
|
||||
alt b.node.expr {
|
||||
some(e) { bcx = trans_expr_dps(bcx, e, dest); }
|
||||
some(e) {
|
||||
let bt = ty::type_is_bot(bcx_tcx(bcx), ty::expr_ty(bcx_tcx(bcx), e));
|
||||
bcx = trans_expr_dps(bcx, e, bt ? ignore : dest);
|
||||
}
|
||||
_ { assert dest == ignore || bcx.unreachable; }
|
||||
}
|
||||
ret trans_block_cleanups(bcx, find_scope_cx(bcx));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue