about summary refs log tree commit diff
path: root/src/comp
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-11-16 12:32:38 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2011-11-18 12:49:00 +0100
commit4e0311214160ea0dc7d1ff7347db6c6550c79de2 (patch)
treec4024b2ab58c93b1441e887e0f3e93936d2dc530 /src/comp
parent6297fc979ee715c276b5303decf2220e70629917 (diff)
downloadrust-4e0311214160ea0dc7d1ff7347db6c6550c79de2.tar.gz
rust-4e0311214160ea0dc7d1ff7347db6c6550c79de2.zip
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
Diffstat (limited to 'src/comp')
-rw-r--r--src/comp/metadata/tydecode.rs3
-rw-r--r--src/comp/metadata/tyencode.rs3
-rw-r--r--src/comp/middle/alias.rs5
-rw-r--r--src/comp/middle/trans.rs14
-rw-r--r--src/comp/syntax/ast.rs2
-rw-r--r--src/comp/syntax/parse/parser.rs5
-rw-r--r--src/comp/syntax/print/pprust.rs3
-rw-r--r--src/comp/util/ppaux.rs3
8 files changed, 28 insertions, 10 deletions
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<stmt_>;
 
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. { "+" }
       _ { "" }
     }
 }