Skip to content

Commit 0d30171

Browse files
committed
---
yaml --- r: 152600 b: refs/heads/try2 c: 7b42e38 h: refs/heads/master v: v3
1 parent cd18c0c commit 0d30171

File tree

10 files changed

+337
-158
lines changed

10 files changed

+337
-158
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ refs/heads/snap-stage3: 78a7676898d9f80ab540c6df5d4c9ce35bb50463
55
refs/heads/try: 519addf6277dbafccbb4159db4b710c37eaa2ec5
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
8-
refs/heads/try2: acc944a35c315c97e9c666cee7f55f7a795ecf04
8+
refs/heads/try2: 7b42e3851c320d5a5f0f27c2b5649efafd8e5057
99
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/try2/src/doc/tutorial.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3247,7 +3247,7 @@ fn main() { println!("hello {}", world::explore()); }
32473247
Now compile and run like this (adjust to your platform if necessary):
32483248

32493249
~~~~console
3250-
$ rustc --crate-type=lib world.rs # compiles libworld-<HASH>-0.42.rlib
3250+
$ rustc --crate-type=lib world.rs # compiles libworld-<HASH>-0.42.so
32513251
$ rustc main.rs -L . # compiles main
32523252
$ ./main
32533253
"hello world"

branches/try2/src/etc/emacs/rust-mode.el

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,9 @@
212212
;; Special types
213213
(,(regexp-opt rust-special-types 'words) . font-lock-type-face)
214214

215-
;; Attributes like `#[bar(baz)]` or `#![bar(baz)]` or `#[bar = "baz"]`
216-
(,(rust-re-grab (concat "#\\!?\\[" rust-re-ident "[^]]*\\]"))
217-
1 font-lock-preprocessor-face t)
215+
;; Attributes like `#[bar(baz)]` or `#![bar(baz)]`
216+
(,(rust-re-grab (concat "#\\!?[" rust-re-ident "[^]]*\\]"))
217+
1 font-lock-preprocessor-face)
218218

219219
;; Syntax extension invocations like `foo!`, highlight including the !
220220
(,(concat (rust-re-grab (concat rust-re-ident "!")) "[({[:space:][]")

branches/try2/src/librustc/middle/borrowck/check_loans.rs

Lines changed: 207 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,6 @@ enum UseError {
155155
UseWhileBorrowed(/*loan*/Rc<LoanPath>, /*loan*/Span)
156156
}
157157

158-
fn compatible_borrow_kinds(borrow_kind1: ty::BorrowKind,
159-
borrow_kind2: ty::BorrowKind)
160-
-> bool {
161-
borrow_kind1 == ty::ImmBorrow && borrow_kind2 == ty::ImmBorrow
162-
}
163-
164158
impl<'a> CheckLoanCtxt<'a> {
165159
pub fn tcx(&self) -> &'a ty::ctxt { self.bccx.tcx }
166160

@@ -195,75 +189,29 @@ impl<'a> CheckLoanCtxt<'a> {
195189
})
196190
}
197191

198-
fn each_in_scope_loan_affecting_path(&self,
199-
scope_id: ast::NodeId,
200-
loan_path: &LoanPath,
201-
op: |&Loan| -> bool)
202-
-> bool {
203-
//! Iterates through all of the in-scope loans affecting `loan_path`,
204-
//! calling `op`, and ceasing iteration if `false` is returned.
192+
pub fn each_in_scope_restriction(&self,
193+
scope_id: ast::NodeId,
194+
loan_path: &LoanPath,
195+
op: |&Loan, &Restriction| -> bool)
196+
-> bool {
197+
//! Iterates through all the in-scope restrictions for the
198+
//! given `loan_path`
205199
206-
// First, we check for a loan restricting the path P being used. This
207-
// accounts for borrows of P but also borrows of subpaths, like P.a.b.
208-
// Consider the following example:
209-
//
210-
// let x = &mut a.b.c; // Restricts a, a.b, and a.b.c
211-
// let y = a; // Conflicts with restriction
200+
self.each_in_scope_loan(scope_id, |loan| {
201+
debug!("each_in_scope_restriction found loan: {:?}",
202+
loan.repr(self.tcx()));
212203

213-
let cont = self.each_in_scope_loan(scope_id, |loan| {
214204
let mut ret = true;
215-
for restr_path in loan.restricted_paths.iter() {
216-
if **restr_path == *loan_path {
217-
if !op(loan) {
205+
for restr in loan.restrictions.iter() {
206+
if *restr.loan_path == *loan_path {
207+
if !op(loan, restr) {
218208
ret = false;
219209
break;
220210
}
221211
}
222212
}
223213
ret
224-
});
225-
226-
if !cont {
227-
return false;
228-
}
229-
230-
// Next, we must check for *loans* (not restrictions) on the path P or
231-
// any base path. This rejects examples like the following:
232-
//
233-
// let x = &mut a.b;
234-
// let y = a.b.c;
235-
//
236-
// Limiting this search to *loans* and not *restrictions* means that
237-
// examples like the following continue to work:
238-
//
239-
// let x = &mut a.b;
240-
// let y = a.c;
241-
242-
let mut loan_path = loan_path;
243-
loop {
244-
match *loan_path {
245-
LpVar(_) => {
246-
break;
247-
}
248-
LpExtend(ref lp_base, _, _) => {
249-
loan_path = &**lp_base;
250-
}
251-
}
252-
253-
let cont = self.each_in_scope_loan(scope_id, |loan| {
254-
if *loan.loan_path == *loan_path {
255-
op(loan)
256-
} else {
257-
true
258-
}
259-
});
260-
261-
if !cont {
262-
return false;
263-
}
264-
}
265-
266-
return true;
214+
})
267215
}
268216

269217
pub fn loans_generated_by(&self, scope_id: ast::NodeId) -> Vec<uint> {
@@ -340,12 +288,26 @@ impl<'a> CheckLoanCtxt<'a> {
340288
loan1.repr(self.tcx()),
341289
loan2.repr(self.tcx()));
342290

343-
if compatible_borrow_kinds(loan1.kind, loan2.kind) {
344-
return true;
345-
}
291+
// Restrictions that would cause the new loan to be illegal:
292+
let illegal_if = match loan2.kind {
293+
// Look for restrictions against mutation. These are
294+
// generated by all other borrows.
295+
ty::MutBorrow => RESTR_MUTATE,
296+
297+
// Look for restrictions against freezing (immutable borrows).
298+
// These are generated by `&mut` borrows.
299+
ty::ImmBorrow => RESTR_FREEZE,
346300

347-
for restr_path in loan1.restricted_paths.iter() {
348-
if *restr_path != loan2.loan_path { continue; }
301+
// No matter how the data is borrowed (as `&`, as `&mut`,
302+
// or as `&unique imm`) it will always generate a
303+
// restriction against mutating the data. So look for those.
304+
ty::UniqueImmBorrow => RESTR_MUTATE,
305+
};
306+
debug!("illegal_if={:?}", illegal_if);
307+
308+
for restr in loan1.restrictions.iter() {
309+
if !restr.set.intersects(illegal_if) { continue; }
310+
if restr.loan_path != loan2.loan_path { continue; }
349311

350312
let old_pronoun = if new_loan.loan_path == old_loan.loan_path {
351313
"it".to_string()
@@ -572,16 +534,63 @@ impl<'a> CheckLoanCtxt<'a> {
572534

573535
let mut ret = UseOk;
574536

575-
self.each_in_scope_loan_affecting_path(expr_id, use_path, |loan| {
576-
if !compatible_borrow_kinds(loan.kind, borrow_kind) {
537+
// First, we check for a restriction on the path P being used. This
538+
// accounts for borrows of P but also borrows of subpaths, like P.a.b.
539+
// Consider the following example:
540+
//
541+
// let x = &mut a.b.c; // Restricts a, a.b, and a.b.c
542+
// let y = a; // Conflicts with restriction
543+
544+
self.each_in_scope_restriction(expr_id, use_path, |loan, _restr| {
545+
if incompatible(loan.kind, borrow_kind) {
577546
ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
578547
false
579548
} else {
580549
true
581550
}
582551
});
583552

553+
// Next, we must check for *loans* (not restrictions) on the path P or
554+
// any base path. This rejects examples like the following:
555+
//
556+
// let x = &mut a.b;
557+
// let y = a.b.c;
558+
//
559+
// Limiting this search to *loans* and not *restrictions* means that
560+
// examples like the following continue to work:
561+
//
562+
// let x = &mut a.b;
563+
// let y = a.c;
564+
565+
let mut loan_path = use_path;
566+
loop {
567+
self.each_in_scope_loan(expr_id, |loan| {
568+
if *loan.loan_path == *loan_path &&
569+
incompatible(loan.kind, borrow_kind) {
570+
ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
571+
false
572+
} else {
573+
true
574+
}
575+
});
576+
577+
match *loan_path {
578+
LpVar(_) => {
579+
break;
580+
}
581+
LpExtend(ref lp_base, _, _) => {
582+
loan_path = &**lp_base;
583+
}
584+
}
585+
}
586+
584587
return ret;
588+
589+
fn incompatible(borrow_kind1: ty::BorrowKind,
590+
borrow_kind2: ty::BorrowKind)
591+
-> bool {
592+
borrow_kind1 != ty::ImmBorrow || borrow_kind2 != ty::ImmBorrow
593+
}
585594
}
586595

587596
fn check_if_path_is_moved(&self,
@@ -659,9 +668,11 @@ impl<'a> CheckLoanCtxt<'a> {
659668
// and aliasing restrictions:
660669
if assignee_cmt.mutbl.is_mutable() {
661670
if check_for_aliasable_mutable_writes(self, assignment_span, assignee_cmt.clone()) {
662-
if mode != euv::Init {
663-
check_for_assignment_to_borrowed_path(
664-
self, assignment_id, assignment_span, assignee_cmt.clone());
671+
if mode != euv::Init &&
672+
check_for_assignment_to_restricted_or_frozen_location(
673+
self, assignment_id, assignment_span, assignee_cmt.clone())
674+
{
675+
// Safe, but record for lint pass later:
665676
mark_variable_as_used_mut(self, assignee_cmt);
666677
}
667678
}
@@ -796,24 +807,138 @@ impl<'a> CheckLoanCtxt<'a> {
796807
}
797808
}
798809

799-
fn check_for_assignment_to_borrowed_path(
810+
fn check_for_assignment_to_restricted_or_frozen_location(
800811
this: &CheckLoanCtxt,
801812
assignment_id: ast::NodeId,
802813
assignment_span: Span,
803-
assignee_cmt: mc::cmt)
814+
assignee_cmt: mc::cmt) -> bool
804815
{
805816
//! Check for assignments that violate the terms of an
806817
//! outstanding loan.
807818
808819
let loan_path = match opt_loan_path(&assignee_cmt) {
809820
Some(lp) => lp,
810-
None => { return; /* no loan path, can't be any loans */ }
821+
None => { return true; /* no loan path, can't be any loans */ }
811822
};
812823

813-
this.each_in_scope_loan_affecting_path(assignment_id, &*loan_path, |loan| {
814-
this.report_illegal_mutation(assignment_span, &*loan_path, loan);
815-
false
824+
// Start by searching for an assignment to a *restricted*
825+
// location. Here is one example of the kind of error caught
826+
// by this check:
827+
//
828+
// let mut v = ~[1, 2, 3];
829+
// let p = &v;
830+
// v = ~[4];
831+
//
832+
// In this case, creating `p` triggers a RESTR_MUTATE
833+
// restriction on the path `v`.
834+
//
835+
// Here is a second, more subtle example:
836+
//
837+
// let mut v = ~[1, 2, 3];
838+
// let p = &const v[0];
839+
// v[0] = 4; // OK
840+
// v[1] = 5; // OK
841+
// v = ~[4, 5, 3]; // Error
842+
//
843+
// In this case, `p` is pointing to `v[0]`, and it is a
844+
// `const` pointer in any case. So the first two
845+
// assignments are legal (and would be permitted by this
846+
// check). However, the final assignment (which is
847+
// logically equivalent) is forbidden, because it would
848+
// cause the existing `v` array to be freed, thus
849+
// invalidating `p`. In the code, this error results
850+
// because `gather_loans::restrictions` adds a
851+
// `RESTR_MUTATE` restriction whenever the contents of an
852+
// owned pointer are borrowed, and hence while `v[*]` is not
853+
// restricted from being written, `v` is.
854+
let cont = this.each_in_scope_restriction(assignment_id,
855+
&*loan_path,
856+
|loan, restr| {
857+
if restr.set.intersects(RESTR_MUTATE) {
858+
this.report_illegal_mutation(assignment_span, &*loan_path, loan);
859+
false
860+
} else {
861+
true
862+
}
816863
});
864+
865+
if !cont { return false }
866+
867+
// The previous code handled assignments to paths that
868+
// have been restricted. This covers paths that have been
869+
// directly lent out and their base paths, but does not
870+
// cover random extensions of those paths. For example,
871+
// the following program is not declared illegal by the
872+
// previous check:
873+
//
874+
// let mut v = ~[1, 2, 3];
875+
// let p = &v;
876+
// v[0] = 4; // declared error by loop below, not code above
877+
//
878+
// The reason that this passes the previous check whereas
879+
// an assignment like `v = ~[4]` fails is because the assignment
880+
// here is to `v[*]`, and the existing restrictions were issued
881+
// for `v`, not `v[*]`.
882+
//
883+
// So in this loop, we walk back up the loan path so long
884+
// as the mutability of the path is dependent on a super
885+
// path, and check that the super path was not lent out as
886+
// mutable or immutable (a const loan is ok).
887+
//
888+
// Mutability of a path can be dependent on the super path
889+
// in two ways. First, it might be inherited mutability.
890+
// Second, the pointee of an `&mut` pointer can only be
891+
// mutated if it is found in an unaliased location, so we
892+
// have to check that the owner location is not borrowed.
893+
//
894+
// Note that we are *not* checking for any and all
895+
// restrictions. We are only interested in the pointers
896+
// that the user created, whereas we add restrictions for
897+
// all kinds of paths that are not directly aliased. If we checked
898+
// for all restrictions, and not just loans, then the following
899+
// valid program would be considered illegal:
900+
//
901+
// let mut v = ~[1, 2, 3];
902+
// let p = &const v[0];
903+
// v[1] = 5; // ok
904+
//
905+
// Here the restriction that `v` not be mutated would be misapplied
906+
// to block the subpath `v[1]`.
907+
let full_loan_path = loan_path.clone();
908+
let mut loan_path = loan_path;
909+
loop {
910+
loan_path = match *loan_path {
911+
// Peel back one layer if, for `loan_path` to be
912+
// mutable, `lp_base` must be mutable. This occurs
913+
// with inherited mutability, owned pointers and
914+
// `&mut` pointers.
915+
LpExtend(ref lp_base, mc::McInherited, _) |
916+
LpExtend(ref lp_base, _, LpDeref(mc::OwnedPtr)) |
917+
LpExtend(ref lp_base, _, LpDeref(mc::GcPtr)) |
918+
LpExtend(ref lp_base, _, LpDeref(mc::BorrowedPtr(ty::MutBorrow, _))) => {
919+
lp_base.clone()
920+
}
921+
922+
// Otherwise stop iterating
923+
LpExtend(_, mc::McDeclared, _) |
924+
LpExtend(_, mc::McImmutable, _) |
925+
LpVar(_) => {
926+
return true;
927+
}
928+
};
929+
930+
// Check for a non-const loan of `loan_path`
931+
let cont = this.each_in_scope_loan(assignment_id, |loan| {
932+
if loan.loan_path == loan_path {
933+
this.report_illegal_mutation(assignment_span, &*full_loan_path, loan);
934+
false
935+
} else {
936+
true
937+
}
938+
});
939+
940+
if !cont { return false }
941+
}
817942
}
818943
}
819944

0 commit comments

Comments
 (0)