Add a pass-by-copy parameter passing convention
This is intended to solve the problem of how to pass arguments to constructor functions -- you want to move in rvalues, but not have to explicitly copy stuff that is not an rvalue. The by-copy passing convention will ensure the callee gets its own copy of the value. For rvalues, it'll just pass off the value. For lvalues, it'll make a copy. Issue #1177
This commit is contained in:
parent
6297fc979e
commit
4e03112141
@ -379,8 +379,9 @@ fn parse_ty_fn(st: @pstate, sd: str_def) ->
|
||||
let mode = alt peek(st) as char {
|
||||
'&' { ast::by_mut_ref }
|
||||
'-' { ast::by_move }
|
||||
'+' { ast::by_copy }
|
||||
'=' { ast::by_ref }
|
||||
'+' { ast::by_val }
|
||||
'#' { ast::by_val }
|
||||
};
|
||||
st.pos += 1u;
|
||||
inputs += [{mode: mode, ty: parse_ty(st, sd)}];
|
||||
|
@ -202,8 +202,9 @@ fn enc_ty_fn(w: io::writer, cx: @ctxt, args: [ty::arg], out: ty::t,
|
||||
alt arg.mode {
|
||||
by_mut_ref. { w.write_char('&'); }
|
||||
by_move. { w.write_char('-'); }
|
||||
by_copy. { w.write_char('+'); }
|
||||
by_ref. { w.write_char('='); }
|
||||
by_val. { w.write_char('+'); }
|
||||
by_val. { w.write_char('#'); }
|
||||
}
|
||||
enc_ty(w, cx, arg.ty);
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ fn check_call(cx: ctx, f: @ast::expr, args: [@ast::expr]) -> [binding] {
|
||||
local_id: 0u,
|
||||
unsafe_tys: unsafe_set(root.mut),
|
||||
mutable copied: alt arg_t.mode {
|
||||
ast::by_move. { copied }
|
||||
ast::by_move. | ast::by_copy. { copied }
|
||||
ast::by_mut_ref. { not_allowed }
|
||||
_ { i + 1u == by_ref ? not_allowed : not_copied }
|
||||
}}];
|
||||
@ -337,6 +337,9 @@ fn check_ret_ref(cx: ctx, sc: scope, mut: bool, arg_node_id: node_id,
|
||||
if arg.mode == ast::by_move {
|
||||
bad = some("a move-mode parameter");
|
||||
}
|
||||
if arg.mode == ast::by_copy {
|
||||
bad = some("a copy-mode parameter");
|
||||
}
|
||||
if cur_node != arg_node_id {
|
||||
bad = some("the wrong parameter");
|
||||
}
|
||||
|
@ -67,8 +67,7 @@ fn type_of_explicit_args(cx: @crate_ctxt, sp: span, inputs: [ty::arg]) ->
|
||||
// that would obviate the need for this check
|
||||
check non_ty_var(cx, arg_ty);
|
||||
let llty = type_of_inner(cx, sp, arg_ty);
|
||||
if arg.mode == ast::by_val { atys += [llty]; }
|
||||
else { atys += [T_ptr(llty)]; }
|
||||
atys += [arg.mode == ast::by_val ? llty : T_ptr(llty)];
|
||||
}
|
||||
ret atys;
|
||||
}
|
||||
@ -3636,6 +3635,15 @@ fn trans_arg_expr(cx: @block_ctxt, arg: ty::arg, lldestty0: TypeRef,
|
||||
if arg.mode == ast::by_val && (lv.kind == owned || !imm) {
|
||||
val = Load(bcx, val);
|
||||
}
|
||||
} else if arg.mode == ast::by_copy {
|
||||
let {bcx: cx, val: alloc} = alloc_ty(bcx, e_ty);
|
||||
bcx = cx;
|
||||
if lv.kind == temporary { revoke_clean(bcx, val); }
|
||||
if lv.kind == owned || !ty::type_is_immediate(ccx.tcx, e_ty) {
|
||||
bcx = memmove_ty(bcx, alloc, val, e_ty);
|
||||
} else { Store(bcx, val, alloc); }
|
||||
val = alloc;
|
||||
if lv.kind != temporary { bcx = take_ty(bcx, val, e_ty); }
|
||||
} else if ty::type_is_immediate(ccx.tcx, e_ty) && lv.kind != owned {
|
||||
let r = do_spill(bcx, val, e_ty);
|
||||
val = r.val;
|
||||
@ -4989,7 +4997,7 @@ fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg],
|
||||
let argval = alt fcx.llargs.get(id) { local_mem(v) { v } };
|
||||
alt arg.mode {
|
||||
ast::by_mut_ref. { }
|
||||
ast::by_move. { add_clean(bcx, argval, arg.ty); }
|
||||
ast::by_move. | ast::by_copy. { add_clean(bcx, argval, arg.ty); }
|
||||
ast::by_val. {
|
||||
if !ty::type_is_immediate(bcx_tcx(bcx), arg.ty) {
|
||||
let {bcx: cx, val: alloc} = alloc_ty(bcx, arg.ty);
|
||||
|
@ -144,7 +144,7 @@ tag unop {
|
||||
deref; not; neg;
|
||||
}
|
||||
|
||||
tag mode { by_ref; by_val; by_mut_ref; by_move; mode_infer; }
|
||||
tag mode { by_ref; by_val; by_mut_ref; by_move; by_copy; mode_infer; }
|
||||
|
||||
type stmt = spanned<stmt_>;
|
||||
|
||||
|
@ -573,7 +573,10 @@ fn parse_arg_mode(p: parser) -> ast::mode {
|
||||
if eat(p, token::BINOP(token::AND)) { ast::by_mut_ref }
|
||||
else if eat(p, token::BINOP(token::MINUS)) { ast::by_move }
|
||||
else if eat(p, token::ANDAND) { ast::by_ref }
|
||||
else if eat(p, token::BINOP(token::PLUS)) { ast::by_val }
|
||||
else if eat(p, token::BINOP(token::PLUS)) {
|
||||
if eat(p, token::BINOP(token::PLUS)) { ast::by_val }
|
||||
else { ast::by_copy }
|
||||
}
|
||||
else { ast::mode_infer }
|
||||
}
|
||||
|
||||
|
@ -1161,7 +1161,8 @@ fn print_arg_mode(s: ps, m: ast::mode) {
|
||||
ast::by_mut_ref. { word(s.s, "&"); }
|
||||
ast::by_move. { word(s.s, "-"); }
|
||||
ast::by_ref. { word(s.s, "&&"); }
|
||||
ast::by_val. { word(s.s, "+"); }
|
||||
ast::by_val. { word(s.s, "++"); }
|
||||
ast::by_copy. { word(s.s, "+"); }
|
||||
ast::mode_infer. {}
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,10 @@ import middle::ast_map;
|
||||
fn mode_str(m: ty::mode) -> str {
|
||||
alt m {
|
||||
ast::by_ref. { "&&" }
|
||||
ast::by_val. { "+" }
|
||||
ast::by_val. { "++" }
|
||||
ast::by_mut_ref. { "&" }
|
||||
ast::by_move. { "-" }
|
||||
ast::by_copy. { "+" }
|
||||
_ { "" }
|
||||
}
|
||||
}
|
||||
|
8
src/test/run-pass/pass-by-copy.rs
Normal file
8
src/test/run-pass/pass-by-copy.rs
Normal file
@ -0,0 +1,8 @@
|
||||
fn magic(+x: {a: @int}) { log x; }
|
||||
fn magic2(+x: @int) { log x; }
|
||||
|
||||
fn main() {
|
||||
let a = {a: @10}, b = @10;
|
||||
magic(a); magic({a: @20});
|
||||
magic2(b); magic2(@20);
|
||||
}
|
Loading…
Reference in New Issue
Block a user