Skip to content

Commit 2bc6547

Browse files
committed
Borrow checking for overloaded indexing
Closes #15525
1 parent 996263a commit 2bc6547

File tree

9 files changed

+96
-23
lines changed

9 files changed

+96
-23
lines changed

src/librustc/middle/borrowck/check_loans.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,8 @@ impl<'a> CheckLoanCtxt<'a> {
734734
mc::cat_static_item |
735735
mc::cat_copied_upvar(..) |
736736
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
737-
mc::cat_deref(_, _, mc::BorrowedPtr(..)) => {
737+
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
738+
mc::cat_deref(_, _, mc::Implicit(..)) => {
738739
assert_eq!(cmt.mutbl, mc::McDeclared);
739740
return;
740741
}

src/librustc/middle/borrowck/gather_loans/gather_moves.rs

+1
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt,
131131
cmt: &mc::cmt) -> Option<mc::cmt> {
132132
match cmt.cat {
133133
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
134+
mc::cat_deref(_, _, mc::Implicit(..)) |
134135
mc::cat_deref(_, _, mc::GcPtr) |
135136
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
136137
mc::cat_upvar(..) | mc::cat_static_item |

src/librustc/middle/borrowck/gather_loans/lifetime.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ impl<'a> GuaranteeLifetimeContext<'a> {
7272
mc::cat_arg(..) | // L-Local
7373
mc::cat_upvar(..) |
7474
mc::cat_deref(_, _, mc::BorrowedPtr(..)) | // L-Deref-Borrowed
75+
mc::cat_deref(_, _, mc::Implicit(..)) |
7576
mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
7677
self.check_scope(self.scope(cmt))
7778
}
@@ -180,7 +181,8 @@ impl<'a> GuaranteeLifetimeContext<'a> {
180181
mc::cat_deref(_, _, mc::UnsafePtr(..)) => {
181182
ty::ReStatic
182183
}
183-
mc::cat_deref(_, _, mc::BorrowedPtr(_, r)) => {
184+
mc::cat_deref(_, _, mc::BorrowedPtr(_, r)) |
185+
mc::cat_deref(_, _, mc::Implicit(_, r)) => {
184186
r
185187
}
186188
mc::cat_downcast(ref cmt) |

src/librustc/middle/borrowck/gather_loans/move_error.rs

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ fn group_errors_with_same_origin(errors: &Vec<MoveError>)
113113
fn report_cannot_move_out_of(bccx: &BorrowckCtxt, move_from: mc::cmt) {
114114
match move_from.cat {
115115
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
116+
mc::cat_deref(_, _, mc::Implicit(..)) |
116117
mc::cat_deref(_, _, mc::GcPtr) |
117118
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
118119
mc::cat_upvar(..) | mc::cat_static_item |

src/librustc/middle/borrowck/gather_loans/restrictions.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ impl<'a> RestrictionsContext<'a> {
122122
}
123123

124124
mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) |
125-
mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::UniqueImmBorrow, lt)) => {
125+
mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::UniqueImmBorrow, lt)) |
126+
mc::cat_deref(cmt_base, _, mc::Implicit(ty::ImmBorrow, lt)) |
127+
mc::cat_deref(cmt_base, _, mc::Implicit(ty::UniqueImmBorrow, lt)) => {
126128
// R-Deref-Imm-Borrowed
127129
if !self.bccx.is_subregion_of(self.loan_region, lt) {
128130
self.bccx.report(
@@ -137,7 +139,8 @@ impl<'a> RestrictionsContext<'a> {
137139
Safe
138140
}
139141

140-
mc::cat_deref(cmt_base, _, pk @ mc::BorrowedPtr(ty::MutBorrow, lt)) => {
142+
mc::cat_deref(cmt_base, _, pk @ mc::BorrowedPtr(ty::MutBorrow, lt)) |
143+
mc::cat_deref(cmt_base, _, pk @ mc::Implicit(ty::MutBorrow, lt)) => {
141144
// R-Deref-Mut-Borrowed
142145
if !self.bccx.is_subregion_of(self.loan_region, lt) {
143146
self.bccx.report(

src/librustc/middle/mem_categorization.rs

+51-15
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ pub enum PointerKind {
106106
OwnedPtr,
107107
GcPtr,
108108
BorrowedPtr(ty::BorrowKind, ty::Region),
109-
UnsafePtr(ast::Mutability),
109+
Implicit(ty::BorrowKind, ty::Region), // Implicit deref of a borrowed ptr.
110+
UnsafePtr(ast::Mutability)
110111
}
111112

112113
// We use the term "interior" to mean "something reachable from the
@@ -293,7 +294,7 @@ impl MutabilityCategory {
293294
OwnedPtr => {
294295
base_mutbl.inherit()
295296
}
296-
BorrowedPtr(borrow_kind, _) => {
297+
BorrowedPtr(borrow_kind, _) | Implicit(borrow_kind, _) => {
297298
MutabilityCategory::from_borrow_kind(borrow_kind)
298299
}
299300
GcPtr => {
@@ -422,7 +423,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
422423
-> McResult<cmt> {
423424
let mut cmt = if_ok!(self.cat_expr_unadjusted(expr));
424425
for deref in range(1u, autoderefs + 1) {
425-
cmt = self.cat_deref(expr, cmt, deref);
426+
cmt = self.cat_deref(expr, cmt, deref, false);
426427
}
427428
return Ok(cmt);
428429
}
@@ -434,7 +435,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
434435
match expr.node {
435436
ast::ExprUnary(ast::UnDeref, ref e_base) => {
436437
let base_cmt = if_ok!(self.cat_expr(&**e_base));
437-
Ok(self.cat_deref(expr, base_cmt, 0))
438+
Ok(self.cat_deref(expr, base_cmt, 0, false))
438439
}
439440

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

445446
ast::ExprIndex(ref base, _) => {
446-
let base_cmt = if_ok!(self.cat_expr(&**base));
447-
Ok(self.cat_index(expr, base_cmt, 0))
447+
let method_call = typeck::MethodCall::expr(expr.id());
448+
match self.typer.node_method_ty(method_call) {
449+
Some(method_ty) => {
450+
// If this is an index implemented by a method call, then it will
451+
// include an implicit deref of the result.
452+
let ret_ty = ty::ty_fn_ret(method_ty);
453+
Ok(self.cat_deref(expr,
454+
self.cat_rvalue_node(expr.id(),
455+
expr.span(),
456+
ret_ty), 1, true))
457+
}
458+
None => {
459+
let base_cmt = if_ok!(self.cat_expr(&**base));
460+
Ok(self.cat_index(expr, base_cmt, 0))
461+
}
462+
}
448463
}
449464

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

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

693708
fn cat_deref<N:ast_node>(&self,
694709
node: &N,
695710
base_cmt: cmt,
696-
deref_cnt: uint)
711+
deref_cnt: uint,
712+
implicit: bool)
697713
-> cmt {
698714
let adjustment = match self.typer.adjustments().borrow().find(&node.id()) {
699715
Some(&ty::AutoObject(..)) => typeck::AutoObject,
@@ -717,7 +733,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
717733
None => base_cmt
718734
};
719735
match ty::deref(base_cmt.ty, true) {
720-
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty),
736+
Some(mt) => self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, implicit),
721737
None => {
722738
self.tcx().sess.span_bug(
723739
node.span(),
@@ -731,10 +747,20 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
731747
node: &N,
732748
base_cmt: cmt,
733749
deref_cnt: uint,
734-
deref_ty: ty::t)
750+
deref_ty: ty::t,
751+
implicit: bool)
735752
-> cmt {
736753
let (m, cat) = match deref_kind(self.tcx(), base_cmt.ty) {
737754
deref_ptr(ptr) => {
755+
let ptr = if implicit {
756+
match ptr {
757+
BorrowedPtr(bk, r) => Implicit(bk, r),
758+
_ => self.tcx().sess.span_bug(node.span(),
759+
"Implicit deref of non-borrowed pointer")
760+
}
761+
} else {
762+
ptr
763+
};
738764
// for unique ptrs, we inherit mutability from the
739765
// owning reference.
740766
(MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr),
@@ -1073,7 +1099,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
10731099

10741100
ast::PatBox(ref subpat) | ast::PatRegion(ref subpat) => {
10751101
// @p1, ~p1
1076-
let subcmt = self.cat_deref(pat, cmt, 0);
1102+
let subcmt = self.cat_deref(pat, cmt, 0, false);
10771103
if_ok!(self.cat_pattern(subcmt, &**subpat, op));
10781104
}
10791105

@@ -1129,6 +1155,9 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
11291155
}
11301156
_ => {
11311157
match pk {
1158+
Implicit(..) => {
1159+
"dereference (dereference is implicit, due to indexing)".to_string()
1160+
}
11321161
OwnedPtr | GcPtr => format!("dereference of `{}`", ptr_sigil(pk)),
11331162
_ => format!("dereference of `{}`-pointer", ptr_sigil(pk))
11341163
}
@@ -1188,6 +1217,7 @@ impl cmt_ {
11881217
cat_deref(_, _, UnsafePtr(..)) |
11891218
cat_deref(_, _, GcPtr(..)) |
11901219
cat_deref(_, _, BorrowedPtr(..)) |
1220+
cat_deref(_, _, Implicit(..)) |
11911221
cat_upvar(..) => {
11921222
Rc::new((*self).clone())
11931223
}
@@ -1212,7 +1242,9 @@ impl cmt_ {
12121242

12131243
match self.cat {
12141244
cat_deref(ref b, _, BorrowedPtr(ty::MutBorrow, _)) |
1245+
cat_deref(ref b, _, Implicit(ty::MutBorrow, _)) |
12151246
cat_deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
1247+
cat_deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
12161248
cat_downcast(ref b) |
12171249
cat_deref(ref b, _, OwnedPtr) |
12181250
cat_interior(ref b, _) |
@@ -1252,7 +1284,8 @@ impl cmt_ {
12521284
Some(AliasableManaged)
12531285
}
12541286

1255-
cat_deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) => {
1287+
cat_deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) |
1288+
cat_deref(_, _, Implicit(ty::ImmBorrow, _)) => {
12561289
Some(AliasableBorrowed)
12571290
}
12581291
}
@@ -1300,9 +1333,12 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
13001333
match ptr {
13011334
OwnedPtr => "Box",
13021335
GcPtr => "Gc",
1303-
BorrowedPtr(ty::ImmBorrow, _) => "&",
1304-
BorrowedPtr(ty::MutBorrow, _) => "&mut",
1305-
BorrowedPtr(ty::UniqueImmBorrow, _) => "&unique",
1336+
BorrowedPtr(ty::ImmBorrow, _) |
1337+
Implicit(ty::ImmBorrow, _) => "&",
1338+
BorrowedPtr(ty::MutBorrow, _) |
1339+
Implicit(ty::MutBorrow, _) => "&mut",
1340+
BorrowedPtr(ty::UniqueImmBorrow, _) |
1341+
Implicit(ty::UniqueImmBorrow, _) => "&unique",
13061342
UnsafePtr(_) => "*"
13071343
}
13081344
}

src/librustc/middle/typeck/check/regionck.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -1219,7 +1219,8 @@ fn link_region(rcx: &Rcx,
12191219
kind.repr(rcx.tcx()),
12201220
cmt_borrowed.repr(rcx.tcx()));
12211221
match cmt_borrowed.cat.clone() {
1222-
mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) => {
1222+
mc::cat_deref(base, _, mc::BorrowedPtr(_, r_borrowed)) |
1223+
mc::cat_deref(base, _, mc::Implicit(_, r_borrowed)) => {
12231224
// References to an upvar `x` are translated to
12241225
// `*x`, since that is what happens in the
12251226
// underlying machine. We detect such references
@@ -1340,7 +1341,8 @@ fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
13401341
continue;
13411342
}
13421343

1343-
mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
1344+
mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
1345+
mc::cat_deref(base, _, mc::Implicit(..)) => {
13441346
match base.cat {
13451347
mc::cat_upvar(ref upvar_id, _) => {
13461348
// if this is an implicit deref of an
@@ -1394,7 +1396,8 @@ fn adjust_upvar_borrow_kind_for_unique(rcx: &Rcx, cmt: mc::cmt) {
13941396
continue;
13951397
}
13961398

1397-
mc::cat_deref(base, _, mc::BorrowedPtr(..)) => {
1399+
mc::cat_deref(base, _, mc::BorrowedPtr(..)) |
1400+
mc::cat_deref(base, _, mc::Implicit(..)) => {
13981401
match base.cat {
13991402
mc::cat_upvar(ref upvar_id, _) => {
14001403
// if this is an implicit deref of an
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct MyVec<T> {
12+
data: Vec<T>,
13+
}
14+
15+
impl<T> Index<uint, T> for MyVec<T> {
16+
fn index<'a>(&'a self, &i: &uint) -> &'a T {
17+
self.data.get(i)
18+
}
19+
}
20+
21+
fn main() {
22+
let v = MyVec { data: vec!(box 1i, box 2, box 3) };
23+
let good = &v[0]; // Shouldn't fail here
24+
let bad = v[0];
25+
//~^ ERROR cannot move out of dereference (dereference is implicit, due to indexing)
26+
}

src/test/compile-fail/borrowck-overloaded-index.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ fn main() {
5858
x: 1,
5959
};
6060
s[2] = 20;
61-
//~^ ERROR cannot assign to immutable indexed content
61+
//~^ ERROR cannot assign to immutable dereference (dereference is implicit, due to indexing)
6262
}
6363

6464

0 commit comments

Comments
 (0)