From c2e6673a6bb7688f411c4465c3d25fcd2876f808 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Fri, 10 Jan 2014 18:30:06 -0800 Subject: [PATCH] librustc: Check restrictions on all subcomponents of a path when moving it. r=nikomatsakis --- src/librustc/middle/borrowck/check_loans.rs | 42 +++++++++++++------ src/librustc/middle/borrowck/mod.rs | 5 ++- .../borrowck-move-subcomponent.rs | 27 ++++++++++++ 3 files changed, 61 insertions(+), 13 deletions(-) create mode 100644 src/test/compile-fail/borrowck-move-subcomponent.rs 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())); + ast_map::node_id_to_str(self.tcx().items, + expr_id, + token::get_ident_interner()), + move_path.repr(self.tcx())); - // FIXME(#4384) inadequare if/when we permit `move a.b` + // 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 + }); - let mut ret = MoveOk; + if ret != MoveOk { + return ret + } - // 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 - }); - - 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 or the MIT license +// , 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) {} + +fn main() { + let a : S = S { x : ~1 }; + let pb = &a; + let S { x: ax } = a; //~ ERROR cannot move out + f(pb); +}