about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBen Blum <bblum@andrew.cmu.edu>2013-06-17 18:02:17 -0400
committerBen Blum <bblum@andrew.cmu.edu>2013-06-19 14:25:51 -0400
commit2c7903d59946e6a091bdcbb5f2ff51021c57a1d2 (patch)
treeac168a4b371fc48b07084df054f6ec588c5c2dbe
parent1120f8c1e57b7b30134d670dd1dfc18c6444c15f (diff)
downloadrust-2c7903d59946e6a091bdcbb5f2ff51021c57a1d2.tar.gz
rust-2c7903d59946e6a091bdcbb5f2ff51021c57a1d2.zip
Consume once fns when calling them (#2549).
-rw-r--r--src/librustc/middle/moves.rs23
1 files changed, 22 insertions, 1 deletions
diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs
index 2217e632d14..4f31107620f 100644
--- a/src/librustc/middle/moves.rs
+++ b/src/librustc/middle/moves.rs
@@ -183,6 +183,7 @@ struct VisitContext {
     move_maps: MoveMaps
 }
 
+#[deriving(Eq)]
 enum UseMode {
     Move,        // This value or something owned by it is moved.
     Read         // Read no matter what the type.
@@ -335,7 +336,27 @@ impl VisitContext {
             }
 
             expr_call(callee, ref args, _) => {    // callee(args)
-                self.use_expr(callee, Read, visitor);
+                // Figure out whether the called function is consumed.
+                let mode = match ty::get(ty::expr_ty(self.tcx, callee)).sty {
+                    ty::ty_closure(ref cty) => {
+                        match cty.onceness {
+                        Once => Move,
+                        Many => Read,
+                        }
+                    },
+                    ty::ty_bare_fn(*) => Read,
+                    ref x =>
+                        self.tcx.sess.span_bug(callee.span,
+                            fmt!("non-function type in moves for expr_call: %?", x)),
+                };
+                // Note we're not using consume_expr, which uses type_moves_by_default
+                // to determine the mode, for this. The reason is that while stack
+                // closures should be noncopyable, they shouldn't move by default;
+                // calling a closure should only consume it if it's once.
+                if mode == Move {
+                    self.move_maps.moves_map.insert(callee.id);
+                }
+                self.use_expr(callee, mode, visitor);
                 self.use_fn_args(callee.id, *args, visitor);
             }