about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-12-07 15:28:57 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2011-12-07 15:28:57 +0100
commit03a6e542126b755a9cd2f4f56144107ba0f4d1cd (patch)
tree3e939cd30c0c905760fc1827f8519bbc8acd976e
parentd28e0c0c0ae329705a063a025b853b292ff033a7 (diff)
downloadrust-03a6e542126b755a9cd2f4f56144107ba0f4d1cd.tar.gz
rust-03a6e542126b755a9cd2f4f56144107ba0f4d1cd.zip
Disallow binding by-mut-ref and by-move arguments
Fix bug in bound by-copy arguments.

Closes #1261
-rw-r--r--src/comp/middle/mut.rs25
-rw-r--r--src/comp/middle/trans.rs6
-rw-r--r--src/libstd/task.rs2
-rw-r--r--src/test/bench/task-perf-word-count.rs18
-rw-r--r--src/test/stdtest/treemap.rs4
5 files changed, 43 insertions, 12 deletions
diff --git a/src/comp/middle/mut.rs b/src/comp/middle/mut.rs
index 12598f3729b..63dadd347e1 100644
--- a/src/comp/middle/mut.rs
+++ b/src/comp/middle/mut.rs
@@ -150,6 +150,7 @@ fn visit_decl(cx: @ctx, d: @decl, &&e: (), v: visit::vt<()>) {
 fn visit_expr(cx: @ctx, ex: @expr, &&e: (), v: visit::vt<()>) {
     alt ex.node {
       expr_call(f, args, _) { check_call(cx, f, args); }
+      expr_bind(f, args) { check_bind(cx, f, args); }
       expr_swap(lhs, rhs) {
         check_lval(cx, lhs, msg_assign);
         check_lval(cx, rhs, msg_assign);
@@ -230,6 +231,30 @@ fn check_call(cx: @ctx, f: @expr, args: [@expr]) {
     }
 }
 
+fn check_bind(cx: @ctx, f: @expr, args: [option::t<@expr>]) {
+    let arg_ts = ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f));
+    let i = 0u;
+    for arg in args {
+        alt arg {
+          some(expr) {
+            alt (alt arg_ts[i].mode {
+              by_mut_ref. { some("by mutable reference") }
+              by_move. { some("by move") }
+              _ { none }
+            }) {
+              some(name) {
+                cx.tcx.sess.span_err(
+                    expr.span, "can not bind an argument passed " + name);
+              }
+              none. {}
+            }
+          }
+          _ {}
+        }
+        i += 1u;
+    }
+}
+
 fn is_immutable_def(def: def) -> option::t<str> {
     alt def {
       def_fn(_, _) | def_mod(_) | def_native_mod(_) | def_const(_) |
diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs
index 693c8ae79e8..107c53cfac3 100644
--- a/src/comp/middle/trans.rs
+++ b/src/comp/middle/trans.rs
@@ -3462,6 +3462,12 @@ fn trans_bind_thunk(cx: @local_ctxt, sp: span, incoming_fty: ty::t,
             bcx = bound_arg.bcx;
             let val = bound_arg.val;
             if out_arg.mode == ast::by_val { val = Load(bcx, val); }
+            if out_arg.mode == ast::by_copy {
+                let {bcx: cx, val: alloc} = alloc_ty(bcx, out_arg.ty);
+                bcx = memmove_ty(cx, alloc, val, out_arg.ty);
+                bcx = take_ty(bcx, alloc, out_arg.ty);
+                val = alloc;
+            }
             // If the type is parameterized, then we need to cast the
             // type we actually have to the parameterized out type.
             if ty::type_contains_params(cx.ccx.tcx, out_arg.ty) {
diff --git a/src/libstd/task.rs b/src/libstd/task.rs
index a8765407f3a..3e396d3ac63 100644
--- a/src/libstd/task.rs
+++ b/src/libstd/task.rs
@@ -288,7 +288,7 @@ fn spawn_inner<send T>(-data: T, f: fn(T),
                           notify: option<comm::chan<task_notification>>)
     -> task unsafe {
 
-    fn wrapper<send T>(-data: *u8, f: fn(T)) unsafe {
+    fn wrapper<send T>(data: *u8, f: fn(T)) unsafe {
         let data: ~T = unsafe::reinterpret_cast(data);
         f(*data);
     }
diff --git a/src/test/bench/task-perf-word-count.rs b/src/test/bench/task-perf-word-count.rs
index 2d4e14af058..d0309713633 100644
--- a/src/test/bench/task-perf-word-count.rs
+++ b/src/test/bench/task-perf-word-count.rs
@@ -112,12 +112,12 @@ mod map_reduce {
 
         send(out, chan(p));
 
-        let ref_count = 0;
-        let is_done = false;
+        let state = @{mutable ref_count: 0, mutable is_done: false};
 
-        fn get(p: port<reduce_proto>, &ref_count: int, &is_done: bool) ->
-           option<int> {
-            while !is_done || ref_count > 0 {
+        fn get(p: port<reduce_proto>, state: @{mutable ref_count: int,
+                                               mutable is_done: bool})
+            -> option<int> {
+            while !state.is_done || state.ref_count > 0 {
                 alt recv(p) {
                   emit_val(v) {
                     // log_err #fmt("received %d", v);
@@ -125,16 +125,16 @@ mod map_reduce {
                   }
                   done. {
                     // log_err "all done";
-                    is_done = true;
+                    state.is_done = true;
                   }
-                  ref. { ref_count += 1; }
-                  release. { ref_count -= 1; }
+                  ref. { state.ref_count += 1; }
+                  release. { state.ref_count -= 1; }
                 }
             }
             ret none;
         }
 
-        reduce(key, bind get(p, ref_count, is_done));
+        reduce(key, bind get(p, state));
     }
 
     fn map_reduce(-inputs: [str]) {
diff --git a/src/test/stdtest/treemap.rs b/src/test/stdtest/treemap.rs
index 1701be37901..2fba1ebb196 100644
--- a/src/test/stdtest/treemap.rs
+++ b/src/test/stdtest/treemap.rs
@@ -39,8 +39,8 @@ fn traverse_in_order() {
     insert(m, 2, ());
     insert(m, 1, ());
 
-    let n = 0;
-    fn t(&n: int, &&k: int, &&_v: ()) { assert (n == k); n += 1; }
+    let n = @mutable 0;
+    fn t(n: @mutable int, &&k: int, &&_v: ()) { assert (*n == k); *n += 1; }
     traverse(m, bind t(n, _, _));
 }