about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBen Blum <bblum@andrew.cmu.edu>2013-06-17 19:06:36 -0400
committerBen Blum <bblum@andrew.cmu.edu>2013-06-19 14:25:51 -0400
commit1496216db6e0ab266df6dcbda31d9fab495afcf9 (patch)
tree526e8308b73cc3db27d84a6e1f1c525648024ec7
parent2c7903d59946e6a091bdcbb5f2ff51021c57a1d2 (diff)
downloadrust-1496216db6e0ab266df6dcbda31d9fab495afcf9.tar.gz
rust-1496216db6e0ab266df6dcbda31d9fab495afcf9.zip
Permit moving out of captured upvars in once fns. Close #2549.
-rw-r--r--src/librustc/middle/borrowck/gather_loans/gather_moves.rs20
-rw-r--r--src/librustc/middle/mem_categorization.rs10
2 files changed, 23 insertions, 7 deletions
diff --git a/src/librustc/middle/borrowck/gather_loans/gather_moves.rs b/src/librustc/middle/borrowck/gather_loans/gather_moves.rs
index 5431a0a2998..d982be684a2 100644
--- a/src/librustc/middle/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc/middle/borrowck/gather_loans/gather_moves.rs
@@ -101,9 +101,7 @@ fn check_is_legal_to_move_from(bccx: @BorrowckCtxt,
                                cmt0: mc::cmt,
                                cmt: mc::cmt) -> bool {
     match cmt.cat {
-        mc::cat_stack_upvar(*) |
         mc::cat_implicit_self(*) |
-        mc::cat_copied_upvar(*) |
         mc::cat_deref(_, _, mc::region_ptr(*)) |
         mc::cat_deref(_, _, mc::gc_ptr(*)) |
         mc::cat_deref(_, _, mc::unsafe_ptr(*)) => {
@@ -114,6 +112,24 @@ fn check_is_legal_to_move_from(bccx: @BorrowckCtxt,
             false
         }
 
+        // These are separate from the above cases for a better error message.
+        mc::cat_stack_upvar(*) |
+        mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, _ }) => {
+            bccx.span_err(
+                cmt0.span,
+                fmt!("cannot move out of %s \
+                      (unless the destination closure type is `once fn')",
+                     bccx.cmt_to_str(cmt)));
+            false
+        }
+
+        // Can move out of captured upvars only if the destination closure
+        // type is 'once'. 1-shot stack closures emit the copied_upvar form
+        // (see mem_categorization.rs).
+        mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Once, _ }) => {
+            true
+        }
+
         // It seems strange to allow a move out of a static item,
         // but what happens in practice is that you have a
         // reference to a constant with a type that should be
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 14764e7bc37..d020cf651a4 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -78,7 +78,7 @@ pub enum categorization {
 }
 
 #[deriving(Eq)]
-struct CopiedUpvar {
+pub struct CopiedUpvar {
     upvar_id: ast::node_id,
     onceness: ast::Onceness,
 }
@@ -497,9 +497,8 @@ impl mem_categorization_ctxt {
               let ty = ty::node_id_to_type(self.tcx, fn_node_id);
               match ty::get(ty).sty {
                   ty::ty_closure(ref closure_ty) => {
-                      let sigil = closure_ty.sigil;
-                      match sigil {
-                          ast::BorrowedSigil => {
+                      match (closure_ty.sigil, closure_ty.onceness) {
+                          (ast::BorrowedSigil, ast::Many) => {
                               let upvar_cmt =
                                   self.cat_def(id, span, expr_ty, *inner);
                               @cmt_ {
@@ -510,7 +509,8 @@ impl mem_categorization_ctxt {
                                   ty:upvar_cmt.ty
                               }
                           }
-                          ast::OwnedSigil | ast::ManagedSigil => {
+                          (ast::BorrowedSigil, ast::Once) |
+                          (ast::OwnedSigil, _) | (ast::ManagedSigil, _) => {
                               // FIXME #2152 allow mutation of moved upvars
                               @cmt_ {
                                   id:id,