Skip to content

Commit

Permalink
Borrow checking for overloaded indexing
Browse files Browse the repository at this point in the history
Closes #15525
  • Loading branch information
nrc committed Jul 14, 2014
1 parent 996263a commit 2bc6547
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 23 deletions.
3 changes: 2 additions & 1 deletion src/librustc/middle/borrowck/check_loans.rs
Expand Up @@ -734,7 +734,8 @@ impl<'a> CheckLoanCtxt<'a> {
mc::cat_static_item |
mc::cat_copied_upvar(..) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_deref(_, _, mc::BorrowedPtr(..)) => {
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) => {
assert_eq!(cmt.mutbl, mc::McDeclared);
return;
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/borrowck/gather_loans/gather_moves.rs
Expand Up @@ -131,6 +131,7 @@ fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt,
cmt: &mc::cmt) -> Option<mc::cmt> {
match cmt.cat {
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) |
mc::cat_deref(_, _, mc::GcPtr) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_upvar(..) | mc::cat_static_item |
Expand Down
4 changes: 3 additions & 1 deletion src/librustc/middle/borrowck/gather_loans/lifetime.rs
Expand Up @@ -72,6 +72,7 @@ impl<'a> GuaranteeLifetimeContext<'a> {
mc::cat_arg(..) | // L-Local
mc::cat_upvar(..) |
mc::cat_deref(_, _, mc::BorrowedPtr(..)) | // L-Deref-Borrowed
mc::cat_deref(_, _, mc::Implicit(..)) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
self.check_scope(self.scope(cmt))
}
Expand Down Expand Up @@ -180,7 +181,8 @@ impl<'a> GuaranteeLifetimeContext<'a> {
mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
ty::ReStatic
}
mc::cat_deref(_, _, mc::BorrowedPtr(_, r)) => {
mc::cat_deref(_, _, mc::BorrowedPtr(_, r)) |
mc::cat_deref(_, _, mc::Implicit(_, r)) => {
r
}
mc::cat_downcast(ref cmt) |
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/borrowck/gather_loans/move_error.rs
Expand Up @@ -113,6 +113,7 @@ fn group_errors_with_same_origin(errors: &Vec<MoveError>)
fn report_cannot_move_out_of(bccx: &BorrowckCtxt, move_from: mc::cmt) {
match move_from.cat {
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) |
mc::cat_deref(_, _, mc::GcPtr) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_upvar(..) | mc::cat_static_item |
Expand Down
7 changes: 5 additions & 2 deletions src/librustc/middle/borrowck/gather_loans/restrictions.rs
Expand Up @@ -122,7 +122,9 @@ impl<'a> RestrictionsContext<'a> {
}

mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) |
mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::UniqueImmBorrow, lt)) => {
mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::UniqueImmBorrow, lt)) |
mc::cat_deref(cmt_base, _, mc::Implicit(ty::ImmBorrow, lt)) |
mc::cat_deref(cmt_base, _, mc::Implicit(ty::UniqueImmBorrow, lt)) => {
// R-Deref-Imm-Borrowed
if !self.bccx.is_subregion_of(self.loan_region, lt) {
self.bccx.report(
Expand All @@ -137,7 +139,8 @@ impl<'a> RestrictionsContext<'a> {
Safe
}

mc::cat_deref(cmt_base, _, pk @ mc::BorrowedPtr(ty::MutBorrow, lt)) => {
mc::cat_deref(cmt_base, _, pk @ mc::BorrowedPtr(ty::MutBorrow, lt)) |
mc::cat_deref(cmt_base, _, pk @ mc::Implicit(ty::MutBorrow, lt)) => {
// R-Deref-Mut-Borrowed
if !self.bccx.is_subregion_of(self.loan_region, lt) {
self.bccx.report(
Expand Down
66 changes: 51 additions & 15 deletions src/librustc/middle/mem_categorization.rs
Expand Up @@ -106,7 +106,8 @@ pub enum PointerKind {
OwnedPtr,
GcPtr,
BorrowedPtr(ty::BorrowKind, ty::Region),
UnsafePtr(ast::Mutability),
Implicit(ty::BorrowKind, ty::Region), // Implicit deref of a borrowed ptr.
UnsafePtr(ast::Mutability)
}

// We use the term "interior" to mean "something reachable from the
Expand Down Expand Up @@ -293,7 +294,7 @@ impl MutabilityCategory {
OwnedPtr => {
base_mutbl.inherit()
}
BorrowedPtr(borrow_kind, _) => {
BorrowedPtr(borrow_kind, _) | Implicit(borrow_kind, _) => {
MutabilityCategory::from_borrow_kind(borrow_kind)
}
GcPtr => {
Expand Down Expand Up @@ -422,7 +423,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
-> McResult<cmt> {
let mut cmt = if_ok!(self.cat_expr_unadjusted(expr));
for deref in range(1u, autoderefs + 1) {
cmt = self.cat_deref(expr, cmt, deref);
cmt = self.cat_deref(expr, cmt, deref, false);
}
return Ok(cmt);
}
Expand All @@ -434,7 +435,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
match expr.node {
ast::ExprUnary(ast::UnDeref, ref e_base) => {
let base_cmt = if_ok!(self.cat_expr(&**e_base));
Ok(self.cat_deref(expr, base_cmt, 0))
Ok(self.cat_deref(expr, base_cmt, 0, false))
}

ast::ExprField(ref base, f_name, _) => {
Expand All @@ -443,8 +444,22 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
}

ast::ExprIndex(ref base, _) => {
let base_cmt = if_ok!(self.cat_expr(&**base));
Ok(self.cat_index(expr, base_cmt, 0))
let method_call = typeck::MethodCall::expr(expr.id());
match self.typer.node_method_ty(method_call) {
Some(method_ty) => {
// If this is an index implemented by a method call, then it will
// include an implicit deref of the result.
let ret_ty = ty::ty_fn_ret(method_ty);
Ok(self.cat_deref(expr,
self.cat_rvalue_node(expr.id(),
expr.span(),
ret_ty), 1, true))
}
None => {
let base_cmt = if_ok!(self.cat_expr(&**base));
Ok(self.cat_index(expr, base_cmt, 0))
}
}
}

ast::ExprPath(_) => {
Expand Down Expand Up @@ -687,13 +702,14 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
}

pub fn cat_deref_obj<N:ast_node>(&self, node: &N, base_cmt: cmt) -> cmt {
self.cat_deref_common(node, base_cmt, 0, ty::mk_nil())
self.cat_deref_common(node, base_cmt, 0, ty::mk_nil(), false)
}

fn cat_deref<N:ast_node>(&self,
node: &N,
base_cmt: cmt,
deref_cnt: uint)
deref_cnt: uint,
implicit: bool)
-> cmt {
let adjustment = match self.typer.adjustments().borrow().find(&node.id()) {
Some(&ty::AutoObject(..)) => typeck::AutoObject,
Expand All @@ -717,7 +733,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
None => base_cmt
};
match ty::deref(base_cmt.ty, true) {
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty),
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, implicit),
None => {
self.tcx().sess.span_bug(
node.span(),
Expand All @@ -731,10 +747,20 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
node: &N,
base_cmt: cmt,
deref_cnt: uint,
deref_ty: ty::t)
deref_ty: ty::t,
implicit: bool)
-> cmt {
let (m, cat) = match deref_kind(self.tcx(), base_cmt.ty) {
deref_ptr(ptr) => {
let ptr = if implicit {
match ptr {
BorrowedPtr(bk, r) => Implicit(bk, r),
_ => self.tcx().sess.span_bug(node.span(),
"Implicit deref of non-borrowed pointer")
}
} else {
ptr
};
// for unique ptrs, we inherit mutability from the
// owning reference.
(MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr),
Expand Down Expand Up @@ -1073,7 +1099,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {

ast::PatBox(ref subpat) | ast::PatRegion(ref subpat) => {
// @p1, ~p1
let subcmt = self.cat_deref(pat, cmt, 0);
let subcmt = self.cat_deref(pat, cmt, 0, false);
if_ok!(self.cat_pattern(subcmt, &**subpat, op));
}

Expand Down Expand Up @@ -1129,6 +1155,9 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
}
_ => {
match pk {
Implicit(..) => {
"dereference (dereference is implicit, due to indexing)".to_string()
}
OwnedPtr | GcPtr => format!("dereference of `{}`", ptr_sigil(pk)),
_ => format!("dereference of `{}`-pointer", ptr_sigil(pk))
}
Expand Down Expand Up @@ -1188,6 +1217,7 @@ impl cmt_ {
cat_deref(_, _, UnsafePtr(..)) |
cat_deref(_, _, GcPtr(..)) |
cat_deref(_, _, BorrowedPtr(..)) |
cat_deref(_, _, Implicit(..)) |
cat_upvar(..) => {
Rc::new((*self).clone())
}
Expand All @@ -1212,7 +1242,9 @@ impl cmt_ {

match self.cat {
cat_deref(ref b, _, BorrowedPtr(ty::MutBorrow, _)) |
cat_deref(ref b, _, Implicit(ty::MutBorrow, _)) |
cat_deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
cat_deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
cat_downcast(ref b) |
cat_deref(ref b, _, OwnedPtr) |
cat_interior(ref b, _) |
Expand Down Expand Up @@ -1252,7 +1284,8 @@ impl cmt_ {
Some(AliasableManaged)
}

cat_deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) => {
cat_deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) |
cat_deref(_, _, Implicit(ty::ImmBorrow, _)) => {
Some(AliasableBorrowed)
}
}
Expand Down Expand Up @@ -1300,9 +1333,12 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
match ptr {
OwnedPtr => "Box",
GcPtr => "Gc",
BorrowedPtr(ty::ImmBorrow, _) => "&",
BorrowedPtr(ty::MutBorrow, _) => "&mut",
BorrowedPtr(ty::UniqueImmBorrow, _) => "&unique",
BorrowedPtr(ty::ImmBorrow, _) |
Implicit(ty::ImmBorrow, _) => "&",
BorrowedPtr(ty::MutBorrow, _) |
Implicit(ty::MutBorrow, _) => "&mut",
BorrowedPtr(ty::UniqueImmBorrow, _) |
Implicit(ty::UniqueImmBorrow, _) => "&unique",
UnsafePtr(_) => "*"
}
}
Expand Down
9 changes: 6 additions & 3 deletions src/librustc/middle/typeck/check/regionck.rs
Expand Up @@ -1219,7 +1219,8 @@ fn link_region(rcx: &Rcx,
kind.repr(rcx.tcx()),
cmt_borrowed.repr(rcx.tcx()));
match cmt_borrowed.cat.clone() {
mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) => {
mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) |
mc::cat_deref(base, _, mc::Implicit(_, r_borrowed)) => {
// References to an upvar `x` are translated to
// `*x`, since that is what happens in the
// underlying machine. We detect such references
Expand Down Expand Up @@ -1340,7 +1341,8 @@ fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
continue;
}

mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
mc::cat_deref(base, _, mc::Implicit(..)) => {
match base.cat {
mc::cat_upvar(ref upvar_id, _) => {
// if this is an implicit deref of an
Expand Down Expand Up @@ -1394,7 +1396,8 @@ fn adjust_upvar_borrow_kind_for_unique(rcx: &Rcx, cmt: mc::cmt) {
continue;
}

mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
mc::cat_deref(base, _, mc::Implicit(..)) => {
match base.cat {
mc::cat_upvar(ref upvar_id, _) => {
// if this is an implicit deref of an
Expand Down
26 changes: 26 additions & 0 deletions src/test/compile-fail/borrowck-overloaded-index-2.rs
@@ -0,0 +1,26 @@
// Copyright 2014 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.

struct MyVec<T> {
data: Vec<T>,
}

impl<T> Index<uint, T> for MyVec<T> {
fn index<'a>(&'a self, &i: &uint) -> &'a T {
self.data.get(i)
}
}

fn main() {
let v = MyVec { data: vec!(box 1i, box 2, box 3) };
let good = &v[0]; // Shouldn't fail here
let bad = v[0];
//~^ ERROR cannot move out of dereference (dereference is implicit, due to indexing)
}
2 changes: 1 addition & 1 deletion src/test/compile-fail/borrowck-overloaded-index.rs
Expand Up @@ -58,7 +58,7 @@ fn main() {
x: 1,
};
s[2] = 20;
//~^ ERROR cannot assign to immutable indexed content
//~^ ERROR cannot assign to immutable dereference (dereference is implicit, due to indexing)
}


5 comments on commit 2bc6547

@bors
Copy link
Contributor

@bors bors commented on 2bc6547 Jul 16, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from pnkfelix
at nrc@2bc6547

@bors
Copy link
Contributor

@bors bors commented on 2bc6547 Jul 16, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging nick29581/rust/index-bck = 2bc6547 into auto

@bors
Copy link
Contributor

@bors bors commented on 2bc6547 Jul 16, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nick29581/rust/index-bck = 2bc6547 merged ok, testing candidate = 6c35d51

@bors
Copy link
Contributor

@bors bors commented on 2bc6547 Jul 16, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = 6c35d51

Please sign in to comment.