From 4e0311214160ea0dc7d1ff7347db6c6550c79de2 Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Wed, 16 Nov 2011 12:32:38 +0100 Subject: [PATCH] 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 --- src/comp/metadata/tydecode.rs | 3 ++- src/comp/metadata/tyencode.rs | 3 ++- src/comp/middle/alias.rs | 5 ++++- src/comp/middle/trans.rs | 14 +++++++++++--- src/comp/syntax/ast.rs | 2 +- src/comp/syntax/parse/parser.rs | 5 ++++- src/comp/syntax/print/pprust.rs | 3 ++- src/comp/util/ppaux.rs | 3 ++- src/test/run-pass/pass-by-copy.rs | 8 ++++++++ 9 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 src/test/run-pass/pass-by-copy.rs diff --git a/src/comp/metadata/tydecode.rs b/src/comp/metadata/tydecode.rs index 5239e70a5a8..8e71ff86f56 100644 --- a/src/comp/metadata/tydecode.rs +++ b/src/comp/metadata/tydecode.rs @@ -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)}]; diff --git a/src/comp/metadata/tyencode.rs b/src/comp/metadata/tyencode.rs index 89a1f3e05ff..b5bba9d723c 100644 --- a/src/comp/metadata/tyencode.rs +++ b/src/comp/metadata/tyencode.rs @@ -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); } diff --git a/src/comp/middle/alias.rs b/src/comp/middle/alias.rs index 88d4f3b56a5..b4cd16d1ee9 100644 --- a/src/comp/middle/alias.rs +++ b/src/comp/middle/alias.rs @@ -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"); } diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index d5d2620fa6f..b57953d20a6 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -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); diff --git a/src/comp/syntax/ast.rs b/src/comp/syntax/ast.rs index b77c58709ae..b5164b54c6c 100644 --- a/src/comp/syntax/ast.rs +++ b/src/comp/syntax/ast.rs @@ -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; diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 3731a6af7d0..d33bd89d5d8 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -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 } } diff --git a/src/comp/syntax/print/pprust.rs b/src/comp/syntax/print/pprust.rs index b5c466bd308..dc09187e062 100644 --- a/src/comp/syntax/print/pprust.rs +++ b/src/comp/syntax/print/pprust.rs @@ -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. {} } } diff --git a/src/comp/util/ppaux.rs b/src/comp/util/ppaux.rs index a6248087ab1..efc259c979f 100644 --- a/src/comp/util/ppaux.rs +++ b/src/comp/util/ppaux.rs @@ -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. { "+" } _ { "" } } } diff --git a/src/test/run-pass/pass-by-copy.rs b/src/test/run-pass/pass-by-copy.rs new file mode 100644 index 00000000000..61cdd01ba21 --- /dev/null +++ b/src/test/run-pass/pass-by-copy.rs @@ -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); +}