about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2014-01-10 18:30:06 -0800
committerPatrick Walton <pcwalton@mimiga.net>2014-01-10 19:01:51 -0800
commitc2e6673a6bb7688f411c4465c3d25fcd2876f808 (patch)
tree542b59d7dc7b7bbf8cb658cc8227cfac6a2bc3c9
parent33e866339126df3806f9cae95f2b91d38abaab32 (diff)
downloadrust-c2e6673a6bb7688f411c4465c3d25fcd2876f808.tar.gz
rust-c2e6673a6bb7688f411c4465c3d25fcd2876f808.zip
librustc: Check restrictions on all subcomponents of a path when moving
it. r=nikomatsakis
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs44
-rw-r--r--src/librustc/middle/borrowck/mod.rs5
-rw-r--r--src/test/compile-fail/borrowck-move-subcomponent.rs27
3 files changed, 62 insertions, 14 deletions
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index ea7979b855e..fe9371af1fe 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -24,8 +24,10 @@ use middle::moves;
 use middle::ty;
 use syntax::ast::{MutImmutable, MutMutable};
 use syntax::ast;
+use syntax::ast_map;
 use syntax::ast_util;
 use syntax::codemap::Span;
+use syntax::parse::token;
 use syntax::visit::Visitor;
 use syntax::visit;
 use util::ppaux::Repr;
@@ -77,6 +79,7 @@ pub fn check_loans(bccx: &BorrowckCtxt,
     clcx.visit_block(body, ());
 }
 
+#[deriving(Eq)]
 enum MoveError {
     MoveOk,
     MoveWhileBorrowed(/*loan*/@LoanPath, /*loan*/Span)
@@ -125,6 +128,9 @@ impl<'a> CheckLoanCtxt<'a> {
         //! given `loan_path`
 
         self.each_in_scope_loan(scope_id, |loan| {
+            debug!("each_in_scope_restriction found loan: {:?}",
+                   loan.repr(self.tcx()));
+
             let mut ret = true;
             for restr in loan.restrictions.iter() {
                 if restr.loan_path == loan_path {
@@ -647,22 +653,34 @@ impl<'a> CheckLoanCtxt<'a> {
 
     pub fn analyze_move_out_from(&self,
                                  expr_id: ast::NodeId,
-                                 move_path: @LoanPath) -> MoveError {
+                                 mut move_path: @LoanPath)
+                                 -> MoveError {
         debug!("analyze_move_out_from(expr_id={:?}, move_path={})",
-               expr_id, move_path.repr(self.tcx()));
-
-        // FIXME(#4384) inadequare if/when we permit `move a.b`
-
-        let mut ret = MoveOk;
+               ast_map::node_id_to_str(self.tcx().items,
+                                       expr_id,
+                                       token::get_ident_interner()),
+               move_path.repr(self.tcx()));
+
+        // We must check every element of a move path. See
+        // `borrowck-move-subcomponent.rs` for a test case.
+        loop {
+            // check for a conflicting loan:
+            let mut ret = MoveOk;
+            self.each_in_scope_restriction(expr_id, move_path, |loan, _| {
+                // Any restriction prevents moves.
+                ret = MoveWhileBorrowed(loan.loan_path, loan.span);
+                false
+            });
 
-        // check for a conflicting loan:
-        self.each_in_scope_restriction(expr_id, move_path, |loan, _| {
-            // Any restriction prevents moves.
-            ret = MoveWhileBorrowed(loan.loan_path, loan.span);
-            false
-        });
+            if ret != MoveOk {
+                return ret
+            }
 
-        ret
+            match *move_path {
+                LpVar(_) => return MoveOk,
+                LpExtend(subpath, _, _) => move_path = subpath,
+            }
+        }
     }
 
     pub fn check_call(&self,
diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs
index 5160233ecbf..cb2f985f8cb 100644
--- a/src/librustc/middle/borrowck/mod.rs
+++ b/src/librustc/middle/borrowck/mod.rs
@@ -872,7 +872,10 @@ impl Repr for LoanPath {
     fn repr(&self, tcx: ty::ctxt) -> ~str {
         match self {
             &LpVar(id) => {
-                format!("$({:?})", id)
+                format!("$({})",
+                        ast_map::node_id_to_str(tcx.items,
+                                                id,
+                                                token::get_ident_interner()))
             }
 
             &LpExtend(lp, _, LpDeref(_)) => {
diff --git a/src/test/compile-fail/borrowck-move-subcomponent.rs b/src/test/compile-fail/borrowck-move-subcomponent.rs
new file mode 100644
index 00000000000..368ceb5adab
--- /dev/null
+++ b/src/test/compile-fail/borrowck-move-subcomponent.rs
@@ -0,0 +1,27 @@
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests that the borrow checker checks all components of a path when moving
+// out.
+
+#[no_std];
+
+struct S {
+  x : ~int
+}
+
+fn f<T>(_: T) {}
+
+fn main() {
+  let a : S = S { x : ~1 };
+  let pb = &a;
+  let S { x: ax } = a;  //~ ERROR cannot move out
+  f(pb);
+}