Skip to content

Commit 18c451f

Browse files
committed
auto merge of #14739 : zwarich/rust/mut-unique-path, r=nikomatsakis
Implement the stronger guarantees for mutable borrows proposed in #12624.
2 parents 2c6caad + 6fc7889 commit 18c451f

File tree

22 files changed

+503
-199
lines changed

22 files changed

+503
-199
lines changed

src/libarena/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,8 @@ impl<T> TypedArenaChunk<T> {
406406
None => {}
407407
Some(mut next) => {
408408
// We assume that the next chunk is completely filled.
409-
next.destroy(next.capacity)
409+
let capacity = next.capacity;
410+
next.destroy(capacity)
410411
}
411412
}
412413
}

src/libcollections/ringbuf.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ impl<T> Deque<T> for RingBuf<T> {
6666

6767
/// Return a mutable reference to the last element in the RingBuf
6868
fn back_mut<'a>(&'a mut self) -> Option<&'a mut T> {
69-
if self.nelts > 0 { Some(self.get_mut(self.nelts - 1)) } else { None }
69+
let nelts = self.nelts;
70+
if nelts > 0 { Some(self.get_mut(nelts - 1)) } else { None }
7071
}
7172

7273
/// Remove and return the first element in the RingBuf, or None if it is empty

src/libcollections/vec.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ impl<T> Vec<T> {
114114
unsafe {
115115
let mut xs = Vec::with_capacity(length);
116116
while xs.len < length {
117-
ptr::write(xs.as_mut_slice().unsafe_mut_ref(xs.len), op(xs.len));
117+
let len = xs.len;
118+
ptr::write(xs.as_mut_slice().unsafe_mut_ref(len), op(len));
118119
xs.len += 1;
119120
}
120121
xs
@@ -210,7 +211,8 @@ impl<T: Clone> Vec<T> {
210211
unsafe {
211212
let mut xs = Vec::with_capacity(length);
212213
while xs.len < length {
213-
ptr::write(xs.as_mut_slice().unsafe_mut_ref(xs.len),
214+
let len = xs.len;
215+
ptr::write(xs.as_mut_slice().unsafe_mut_ref(len),
214216
value.clone());
215217
xs.len += 1;
216218
}
@@ -321,9 +323,10 @@ impl<T:Clone> Clone for Vec<T> {
321323
let this_slice = self.as_slice();
322324
while vector.len < len {
323325
unsafe {
326+
let len = vector.len;
324327
ptr::write(
325-
vector.as_mut_slice().unsafe_mut_ref(vector.len),
326-
this_slice.unsafe_ref(vector.len).clone());
328+
vector.as_mut_slice().unsafe_mut_ref(len),
329+
this_slice.unsafe_ref(len).clone());
327330
}
328331
vector.len += 1;
329332
}

src/libdebug/repr.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,15 @@ impl<'a> ReprVisitor<'a> {
127127
#[inline]
128128
pub fn get<T>(&mut self, f: |&mut ReprVisitor, &T| -> bool) -> bool {
129129
unsafe {
130-
f(self, mem::transmute::<*u8,&T>(self.ptr))
130+
let ptr = self.ptr;
131+
f(self, mem::transmute::<*u8,&T>(ptr))
131132
}
132133
}
133134

134135
#[inline]
135136
pub fn visit_inner(&mut self, inner: *TyDesc) -> bool {
136-
self.visit_ptr_inner(self.ptr, inner)
137+
let ptr = self.ptr;
138+
self.visit_ptr_inner(ptr, inner)
137139
}
138140

139141
#[inline]

src/libnative/io/net.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -637,16 +637,15 @@ impl rtio::RtioUdpSocket for UdpSocket {
637637
mem::size_of::<libc::sockaddr_storage>() as libc::socklen_t;
638638

639639
let dolock = || self.lock_nonblocking();
640-
let doread = |nb| unsafe {
640+
let n = try!(read(fd, self.read_deadline, dolock, |nb| unsafe {
641641
let flags = if nb {c::MSG_DONTWAIT} else {0};
642642
libc::recvfrom(fd,
643643
buf.as_mut_ptr() as *mut libc::c_void,
644644
buf.len() as msglen_t,
645645
flags,
646646
storagep,
647647
&mut addrlen) as libc::c_int
648-
};
649-
let n = try!(read(fd, self.read_deadline, dolock, doread));
648+
}));
650649
sockaddr_to_addr(&storage, addrlen as uint).and_then(|addr| {
651650
Ok((n as uint, addr))
652651
})

src/libregex/parse/mod.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -345,18 +345,19 @@ impl<'a> Parser<'a> {
345345
}
346346

347347
fn push_literal(&mut self, c: char) -> Result<(), Error> {
348+
let flags = self.flags;
348349
match c {
349350
'.' => {
350-
self.push(Dot(self.flags))
351+
self.push(Dot(flags))
351352
}
352353
'^' => {
353-
self.push(Begin(self.flags))
354+
self.push(Begin(flags))
354355
}
355356
'$' => {
356-
self.push(End(self.flags))
357+
self.push(End(flags))
357358
}
358359
_ => {
359-
self.push(Literal(c, self.flags))
360+
self.push(Literal(c, flags))
360361
}
361362
}
362363
Ok(())

src/librustc/middle/borrowck/check_loans.rs

+128-66
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,9 @@ pub fn check_loans(bccx: &BorrowckCtxt,
150150
}
151151

152152
#[deriving(PartialEq)]
153-
enum MoveError {
154-
MoveOk,
155-
MoveWhileBorrowed(/*loan*/Rc<LoanPath>, /*loan*/Span)
153+
enum UseError {
154+
UseOk,
155+
UseWhileBorrowed(/*loan*/Rc<LoanPath>, /*loan*/Span)
156156
}
157157

158158
impl<'a> CheckLoanCtxt<'a> {
@@ -438,8 +438,7 @@ impl<'a> CheckLoanCtxt<'a> {
438438
Some(lp) => {
439439
let moved_value_use_kind = match mode {
440440
euv::Copy => {
441-
// FIXME(#12624) -- If we are copying the value,
442-
// we don't care if it's borrowed.
441+
self.check_for_copy_of_frozen_path(id, span, &*lp);
443442
MovedInUse
444443
}
445444
euv::Move(_) => {
@@ -454,7 +453,7 @@ impl<'a> CheckLoanCtxt<'a> {
454453
}
455454
Some(move_kind) => {
456455
self.check_for_move_of_borrowed_path(id, span,
457-
&lp, move_kind);
456+
&*lp, move_kind);
458457
if move_kind == move_data::Captured {
459458
MovedInCapture
460459
} else {
@@ -471,23 +470,47 @@ impl<'a> CheckLoanCtxt<'a> {
471470
}
472471
}
473472

473+
fn check_for_copy_of_frozen_path(&self,
474+
id: ast::NodeId,
475+
span: Span,
476+
copy_path: &LoanPath) {
477+
match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) {
478+
UseOk => { }
479+
UseWhileBorrowed(loan_path, loan_span) => {
480+
self.bccx.span_err(
481+
span,
482+
format!("cannot use `{}` because it was mutably borrowed",
483+
self.bccx.loan_path_to_str(copy_path).as_slice())
484+
.as_slice());
485+
self.bccx.span_note(
486+
loan_span,
487+
format!("borrow of `{}` occurs here",
488+
self.bccx.loan_path_to_str(&*loan_path).as_slice())
489+
.as_slice());
490+
}
491+
}
492+
}
493+
474494
fn check_for_move_of_borrowed_path(&self,
475495
id: ast::NodeId,
476496
span: Span,
477-
move_path: &Rc<LoanPath>,
497+
move_path: &LoanPath,
478498
move_kind: move_data::MoveKind) {
479-
match self.analyze_move_out_from(id, &**move_path) {
480-
MoveOk => { }
481-
MoveWhileBorrowed(loan_path, loan_span) => {
499+
// We want to detect if there are any loans at all, so we search for
500+
// any loans incompatible with MutBorrrow, since all other kinds of
501+
// loans are incompatible with that.
502+
match self.analyze_restrictions_on_use(id, move_path, ty::MutBorrow) {
503+
UseOk => { }
504+
UseWhileBorrowed(loan_path, loan_span) => {
482505
let err_message = match move_kind {
483506
move_data::Captured =>
484507
format!("cannot move `{}` into closure because it is borrowed",
485-
self.bccx.loan_path_to_str(&**move_path).as_slice()),
508+
self.bccx.loan_path_to_str(move_path).as_slice()),
486509
move_data::Declared |
487510
move_data::MoveExpr |
488511
move_data::MovePat =>
489512
format!("cannot move out of `{}` because it is borrowed",
490-
self.bccx.loan_path_to_str(&**move_path).as_slice())
513+
self.bccx.loan_path_to_str(move_path).as_slice())
491514
};
492515

493516
self.bccx.span_err(span, err_message.as_slice());
@@ -500,6 +523,99 @@ impl<'a> CheckLoanCtxt<'a> {
500523
}
501524
}
502525

526+
pub fn analyze_restrictions_on_use(&self,
527+
expr_id: ast::NodeId,
528+
use_path: &LoanPath,
529+
borrow_kind: ty::BorrowKind)
530+
-> UseError {
531+
debug!("analyze_restrictions_on_use(expr_id={:?}, use_path={})",
532+
self.tcx().map.node_to_str(expr_id),
533+
use_path.repr(self.tcx()));
534+
535+
let mut ret = UseOk;
536+
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) {
546+
ret = UseWhileBorrowed(loan.loan_path.clone(), loan.span);
547+
false
548+
} else {
549+
true
550+
}
551+
});
552+
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+
587+
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+
}
594+
}
595+
596+
fn check_if_path_is_moved(&self,
597+
id: ast::NodeId,
598+
span: Span,
599+
use_kind: MovedValueUseKind,
600+
lp: &Rc<LoanPath>) {
601+
/*!
602+
* Reports an error if `expr` (which should be a path)
603+
* is using a moved/uninitialized value
604+
*/
605+
606+
debug!("check_if_path_is_moved(id={:?}, use_kind={:?}, lp={})",
607+
id, use_kind, lp.repr(self.bccx.tcx));
608+
self.move_data.each_move_of(id, lp, |move, moved_lp| {
609+
self.bccx.report_use_of_moved_value(
610+
span,
611+
use_kind,
612+
&**lp,
613+
move,
614+
moved_lp);
615+
false
616+
});
617+
}
618+
503619
fn check_if_assigned_path_is_moved(&self,
504620
id: ast::NodeId,
505621
span: Span,
@@ -541,29 +657,6 @@ impl<'a> CheckLoanCtxt<'a> {
541657
}
542658
}
543659

544-
fn check_if_path_is_moved(&self,
545-
id: ast::NodeId,
546-
span: Span,
547-
use_kind: MovedValueUseKind,
548-
lp: &Rc<LoanPath>) {
549-
/*!
550-
* Reports an error if `expr` (which should be a path)
551-
* is using a moved/uninitialized value
552-
*/
553-
554-
debug!("check_if_path_is_moved(id={:?}, use_kind={:?}, lp={})",
555-
id, use_kind, lp.repr(self.bccx.tcx));
556-
self.move_data.each_move_of(id, lp, |move, moved_lp| {
557-
self.bccx.report_use_of_moved_value(
558-
span,
559-
use_kind,
560-
&**lp,
561-
move,
562-
moved_lp);
563-
false
564-
});
565-
}
566-
567660
fn check_assignment(&self,
568661
assignment_id: ast::NodeId,
569662
assignment_span: Span,
@@ -862,35 +955,4 @@ impl<'a> CheckLoanCtxt<'a> {
862955
format!("borrow of `{}` occurs here",
863956
self.bccx.loan_path_to_str(loan_path)).as_slice());
864957
}
865-
866-
pub fn analyze_move_out_from(&self,
867-
expr_id: ast::NodeId,
868-
move_path: &LoanPath)
869-
-> MoveError {
870-
debug!("analyze_move_out_from(expr_id={:?}, move_path={})",
871-
self.tcx().map.node_to_str(expr_id),
872-
move_path.repr(self.tcx()));
873-
874-
// We must check every element of a move path. See
875-
// `borrowck-move-subcomponent.rs` for a test case.
876-
877-
// check for a conflicting loan:
878-
let mut ret = MoveOk;
879-
self.each_in_scope_restriction(expr_id, move_path, |loan, _| {
880-
// Any restriction prevents moves.
881-
ret = MoveWhileBorrowed(loan.loan_path.clone(), loan.span);
882-
false
883-
});
884-
885-
if ret != MoveOk {
886-
return ret
887-
}
888-
889-
match *move_path {
890-
LpVar(_) => MoveOk,
891-
LpExtend(ref subpath, _, _) => {
892-
self.analyze_move_out_from(expr_id, &**subpath)
893-
}
894-
}
895-
}
896958
}

src/librustc/middle/dataflow.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -300,12 +300,13 @@ impl<'a, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, O> {
300300
}
301301

302302
{
303+
let words_per_id = self.words_per_id;
303304
let mut propcx = PropagationContext {
304305
dfcx: &mut *self,
305306
changed: true
306307
};
307308

308-
let mut temp = Vec::from_elem(self.words_per_id, 0u);
309+
let mut temp = Vec::from_elem(words_per_id, 0u);
309310
let mut loop_scopes = Vec::new();
310311

311312
while propcx.changed {

0 commit comments

Comments
 (0)