Skip to content

Commit ad25e20

Browse files
committed
librustc: Allow &mut to be loaned; allow self to be loaned; make &mut loanable to &. r=nmatsakis
1 parent bbbb805 commit ad25e20

29 files changed

+338
-166
lines changed

src/libcore/vec.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#[forbid(deprecated_pattern)];
1515
#[warn(non_camel_case_types)];
1616

17+
use cast::transmute;
1718
use cast;
1819
use cmp::{Eq, Ord};
1920
use iter::BaseIter;
@@ -477,14 +478,20 @@ pub fn shift<T>(v: &mut ~[T]) -> T {
477478
// Memcopy the head element (the one we want) to the location we just
478479
// popped. For the moment it unsafely exists at both the head and last
479480
// positions
480-
let first_slice = view(*v, 0, 1);
481-
let last_slice = mut_view(*v, next_ln, ln);
482-
raw::copy_memory(last_slice, first_slice, 1);
481+
{
482+
let first_slice = view(*v, 0, 1);
483+
let last_slice = view(*v, next_ln, ln);
484+
raw::copy_memory(::cast::transmute(last_slice), first_slice, 1);
485+
}
483486

484487
// Memcopy everything to the left one element
485-
let init_slice = mut_view(*v, 0, next_ln);
486-
let tail_slice = view(*v, 1, ln);
487-
raw::copy_memory(init_slice, tail_slice, next_ln);
488+
{
489+
let init_slice = view(*v, 0, next_ln);
490+
let tail_slice = view(*v, 1, ln);
491+
raw::copy_memory(::cast::transmute(init_slice),
492+
tail_slice,
493+
next_ln);
494+
}
488495

489496
// Set the new length. Now the vector is back to normal
490497
raw::set_len(&mut *v, next_ln);

src/librustc/middle/borrowck/check_loans.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ use core::prelude::*;
2222
use middle::borrowck::{Loan, bckerr, borrowck_ctxt, cmt, inherent_mutability};
2323
use middle::borrowck::{req_maps, save_and_restore};
2424
use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref};
25-
use middle::mem_categorization::{cat_local, cat_rvalue, cat_special, gc_ptr};
26-
use middle::mem_categorization::{loan_path, lp_arg, lp_comp, lp_deref};
27-
use middle::mem_categorization::{lp_local};
25+
use middle::mem_categorization::{cat_local, cat_rvalue, cat_self};
26+
use middle::mem_categorization::{cat_special, gc_ptr, loan_path, lp_arg};
27+
use middle::mem_categorization::{lp_comp, lp_deref, lp_local};
2828
use middle::ty::{CopyValue, MoveValue, ReadValue};
2929
use middle::ty;
3030
use util::ppaux::ty_to_str;
@@ -444,7 +444,7 @@ impl check_loan_ctxt {
444444
self.check_for_loan_conflicting_with_assignment(
445445
at, ex, cmt, lp_base);
446446
}
447-
lp_comp(*) | lp_local(*) | lp_arg(*) | lp_deref(*) => ()
447+
lp_comp(*) | lp_self | lp_local(*) | lp_arg(*) | lp_deref(*) => ()
448448
}
449449
}
450450

@@ -481,16 +481,13 @@ impl check_loan_ctxt {
481481

482482
match cmt.cat {
483483
// Rvalues, locals, and arguments can be moved:
484-
cat_rvalue | cat_local(_) | cat_arg(_) => {}
484+
cat_rvalue | cat_local(_) | cat_arg(_) | cat_self(_) => {}
485485

486486
// We allow moving out of static items because the old code
487487
// did. This seems consistent with permitting moves out of
488488
// rvalues, I guess.
489489
cat_special(sk_static_item) => {}
490490

491-
// We allow moving out of explicit self only.
492-
cat_special(sk_self) => {}
493-
494491
cat_deref(_, _, unsafe_ptr) => {}
495492

496493
// Nothing else.

src/librustc/middle/borrowck/gather_loans.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -480,13 +480,44 @@ impl gather_loan_ctxt {
480480
return;
481481
}
482482

483+
// Normally we wouldn't allow `re_free` here. However, in this case
484+
// it should be sound. Below is nmatsakis' reasoning:
485+
//
486+
// Perhaps [this permits] a function kind of like this one here, which
487+
// consumes one mut pointer and returns a narrower one:
488+
//
489+
// struct Foo { f: int }
490+
// fn foo(p: &v/mut Foo) -> &v/mut int { &mut p.f }
491+
//
492+
// I think this should work fine but there is more subtlety to it than
493+
// I at first imagined. Unfortunately it's a very important use case,
494+
// I think, so it really ought to work. The changes you [pcwalton]
495+
// made to permit re_free() do permit this case, I think, but I'm not
496+
// sure what else they permit. I have to think that over a bit.
497+
//
498+
// Ordinarily, a loan with scope re_free wouldn't make sense, because
499+
// you couldn't enforce it. But in this case, your function signature
500+
// informs the caller that you demand exclusive access to p and its
501+
// contents for the lifetime v. Since borrowed pointers are
502+
// non-copyable, they must have (a) made a borrow which will enforce
503+
// those conditions and then (b) given you the resulting pointer.
504+
// Therefore, they should be respecting the loan. So it actually seems
505+
// that it's ok in this case to have a loan with re_free, so long as
506+
// the scope of the loan is no greater than the region pointer on
507+
// which it is based. Neat but not something I had previously
508+
// considered all the way through. (Note that we already rely on
509+
// similar reasoning to permit you to return borrowed pointers into
510+
// immutable structures, this is just the converse I suppose)
511+
483512
let scope_id = match scope_r {
484-
ty::re_scope(scope_id) => scope_id,
513+
ty::re_scope(scope_id) | ty::re_free(scope_id, _) => scope_id,
485514
_ => {
486515
self.bccx.tcx.sess.span_bug(
487516
cmt.span,
488-
fmt!("loans required but scope is scope_region is %s",
489-
region_to_str(self.tcx(), scope_r)));
517+
fmt!("loans required but scope is scope_region is %s \
518+
(%?)",
519+
region_to_str(self.tcx(), scope_r),
520+
scope_r));
490521
}
491522
};
492523

src/librustc/middle/borrowck/loan.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use core::prelude::*;
1717
use middle::borrowck::{Loan, bckres, borrowck_ctxt, cmt, err_mutbl};
1818
use middle::borrowck::{err_out_of_scope};
1919
use middle::mem_categorization::{cat_arg, cat_binding, cat_discr, cat_comp};
20-
use middle::mem_categorization::{cat_deref, cat_discr, cat_local};
20+
use middle::mem_categorization::{cat_deref, cat_discr, cat_local, cat_self};
2121
use middle::mem_categorization::{cat_special, cat_stack_upvar, comp_field};
2222
use middle::mem_categorization::{comp_index, comp_variant, gc_ptr};
2323
use middle::mem_categorization::{region_ptr};
@@ -121,7 +121,7 @@ impl LoanContext {
121121
cmt.span,
122122
~"rvalue with a non-none lp");
123123
}
124-
cat_local(local_id) | cat_arg(local_id) => {
124+
cat_local(local_id) | cat_arg(local_id) | cat_self(local_id) => {
125125
let local_scope_id = self.tcx().region_map.get(local_id);
126126
self.issue_loan(cmt, ty::re_scope(local_scope_id), req_mutbl)
127127
}
@@ -162,9 +162,18 @@ impl LoanContext {
162162
// then the memory is freed.
163163
self.loan_unstable_deref(cmt, cmt_base, req_mutbl)
164164
}
165+
cat_deref(cmt_base, _, region_ptr(ast::m_mutbl, region)) => {
166+
// Mutable data can be loaned out as immutable or const. We must
167+
// loan out the base as well as the main memory. For example,
168+
// if someone borrows `*b`, we want to borrow `b` as immutable
169+
// as well.
170+
do self.loan(cmt_base, m_imm).chain |_| {
171+
self.issue_loan(cmt, region, m_const)
172+
}
173+
}
165174
cat_deref(_, _, unsafe_ptr) |
166175
cat_deref(_, _, gc_ptr(_)) |
167-
cat_deref(_, _, region_ptr(_)) => {
176+
cat_deref(_, _, region_ptr(_, _)) => {
168177
// Aliased data is simply not lendable.
169178
self.bccx.tcx.sess.span_bug(
170179
cmt.span,

src/librustc/middle/borrowck/preserve.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use middle::borrowck::{cmt, err_mut_uniq, err_mut_variant};
2020
use middle::borrowck::{err_out_of_root_scope, err_out_of_scope};
2121
use middle::borrowck::{err_root_not_permitted};
2222
use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref};
23-
use middle::mem_categorization::{cat_discr, cat_local, cat_special};
23+
use middle::mem_categorization::{cat_discr, cat_local, cat_self, cat_special};
2424
use middle::mem_categorization::{cat_stack_upvar, comp_field, comp_index};
2525
use middle::mem_categorization::{comp_variant, gc_ptr, region_ptr};
2626
use middle::ty;
@@ -90,7 +90,6 @@ priv impl &preserve_ctxt {
9090
let _i = indenter();
9191

9292
match cmt.cat {
93-
cat_special(sk_self) |
9493
cat_special(sk_implicit_self) |
9594
cat_special(sk_heap_upvar) => {
9695
self.compare_scope(cmt, ty::re_scope(self.item_ub))
@@ -148,6 +147,10 @@ priv impl &preserve_ctxt {
148147
let local_scope_id = self.tcx().region_map.get(local_id);
149148
self.compare_scope(cmt, ty::re_scope(local_scope_id))
150149
}
150+
cat_self(local_id) => {
151+
let local_scope_id = self.tcx().region_map.get(local_id);
152+
self.compare_scope(cmt, ty::re_scope(local_scope_id))
153+
}
151154
cat_comp(cmt_base, comp_field(*)) |
152155
cat_comp(cmt_base, comp_index(*)) |
153156
cat_comp(cmt_base, comp_tuple) |
@@ -171,7 +174,7 @@ priv impl &preserve_ctxt {
171174
// freed, so require imm.
172175
self.require_imm(cmt, cmt_base, err_mut_uniq)
173176
}
174-
cat_deref(_, _, region_ptr(region)) => {
177+
cat_deref(_, _, region_ptr(_, region)) => {
175178
// References are always "stable" for lifetime `region` by
176179
// induction (when the reference of type &MT was created,
177180
// the memory must have been stable).

0 commit comments

Comments
 (0)