mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-26 22:53:28 +00:00
librustc: Allow &mut
to be loaned; allow self
to be loaned; make &mut
loanable to &
. r=nmatsakis
This commit is contained in:
parent
bbbb80559c
commit
ad25e208ee
@ -14,6 +14,7 @@
|
||||
#[forbid(deprecated_pattern)];
|
||||
#[warn(non_camel_case_types)];
|
||||
|
||||
use cast::transmute;
|
||||
use cast;
|
||||
use cmp::{Eq, Ord};
|
||||
use iter::BaseIter;
|
||||
@ -477,14 +478,20 @@ pub fn shift<T>(v: &mut ~[T]) -> T {
|
||||
// Memcopy the head element (the one we want) to the location we just
|
||||
// popped. For the moment it unsafely exists at both the head and last
|
||||
// positions
|
||||
let first_slice = view(*v, 0, 1);
|
||||
let last_slice = mut_view(*v, next_ln, ln);
|
||||
raw::copy_memory(last_slice, first_slice, 1);
|
||||
{
|
||||
let first_slice = view(*v, 0, 1);
|
||||
let last_slice = view(*v, next_ln, ln);
|
||||
raw::copy_memory(::cast::transmute(last_slice), first_slice, 1);
|
||||
}
|
||||
|
||||
// Memcopy everything to the left one element
|
||||
let init_slice = mut_view(*v, 0, next_ln);
|
||||
let tail_slice = view(*v, 1, ln);
|
||||
raw::copy_memory(init_slice, tail_slice, next_ln);
|
||||
{
|
||||
let init_slice = view(*v, 0, next_ln);
|
||||
let tail_slice = view(*v, 1, ln);
|
||||
raw::copy_memory(::cast::transmute(init_slice),
|
||||
tail_slice,
|
||||
next_ln);
|
||||
}
|
||||
|
||||
// Set the new length. Now the vector is back to normal
|
||||
raw::set_len(&mut *v, next_ln);
|
||||
|
@ -22,9 +22,9 @@ use core::prelude::*;
|
||||
use middle::borrowck::{Loan, bckerr, borrowck_ctxt, cmt, inherent_mutability};
|
||||
use middle::borrowck::{req_maps, save_and_restore};
|
||||
use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref};
|
||||
use middle::mem_categorization::{cat_local, cat_rvalue, cat_special, gc_ptr};
|
||||
use middle::mem_categorization::{loan_path, lp_arg, lp_comp, lp_deref};
|
||||
use middle::mem_categorization::{lp_local};
|
||||
use middle::mem_categorization::{cat_local, cat_rvalue, cat_self};
|
||||
use middle::mem_categorization::{cat_special, gc_ptr, loan_path, lp_arg};
|
||||
use middle::mem_categorization::{lp_comp, lp_deref, lp_local};
|
||||
use middle::ty::{CopyValue, MoveValue, ReadValue};
|
||||
use middle::ty;
|
||||
use util::ppaux::ty_to_str;
|
||||
@ -444,7 +444,7 @@ impl check_loan_ctxt {
|
||||
self.check_for_loan_conflicting_with_assignment(
|
||||
at, ex, cmt, lp_base);
|
||||
}
|
||||
lp_comp(*) | lp_local(*) | lp_arg(*) | lp_deref(*) => ()
|
||||
lp_comp(*) | lp_self | lp_local(*) | lp_arg(*) | lp_deref(*) => ()
|
||||
}
|
||||
}
|
||||
|
||||
@ -481,16 +481,13 @@ impl check_loan_ctxt {
|
||||
|
||||
match cmt.cat {
|
||||
// Rvalues, locals, and arguments can be moved:
|
||||
cat_rvalue | cat_local(_) | cat_arg(_) => {}
|
||||
cat_rvalue | cat_local(_) | cat_arg(_) | cat_self(_) => {}
|
||||
|
||||
// We allow moving out of static items because the old code
|
||||
// did. This seems consistent with permitting moves out of
|
||||
// rvalues, I guess.
|
||||
cat_special(sk_static_item) => {}
|
||||
|
||||
// We allow moving out of explicit self only.
|
||||
cat_special(sk_self) => {}
|
||||
|
||||
cat_deref(_, _, unsafe_ptr) => {}
|
||||
|
||||
// Nothing else.
|
||||
|
@ -480,13 +480,44 @@ impl gather_loan_ctxt {
|
||||
return;
|
||||
}
|
||||
|
||||
// Normally we wouldn't allow `re_free` here. However, in this case
|
||||
// it should be sound. Below is nmatsakis' reasoning:
|
||||
//
|
||||
// Perhaps [this permits] a function kind of like this one here, which
|
||||
// consumes one mut pointer and returns a narrower one:
|
||||
//
|
||||
// struct Foo { f: int }
|
||||
// fn foo(p: &v/mut Foo) -> &v/mut int { &mut p.f }
|
||||
//
|
||||
// I think this should work fine but there is more subtlety to it than
|
||||
// I at first imagined. Unfortunately it's a very important use case,
|
||||
// I think, so it really ought to work. The changes you [pcwalton]
|
||||
// made to permit re_free() do permit this case, I think, but I'm not
|
||||
// sure what else they permit. I have to think that over a bit.
|
||||
//
|
||||
// Ordinarily, a loan with scope re_free wouldn't make sense, because
|
||||
// you couldn't enforce it. But in this case, your function signature
|
||||
// informs the caller that you demand exclusive access to p and its
|
||||
// contents for the lifetime v. Since borrowed pointers are
|
||||
// non-copyable, they must have (a) made a borrow which will enforce
|
||||
// those conditions and then (b) given you the resulting pointer.
|
||||
// Therefore, they should be respecting the loan. So it actually seems
|
||||
// that it's ok in this case to have a loan with re_free, so long as
|
||||
// the scope of the loan is no greater than the region pointer on
|
||||
// which it is based. Neat but not something I had previously
|
||||
// considered all the way through. (Note that we already rely on
|
||||
// similar reasoning to permit you to return borrowed pointers into
|
||||
// immutable structures, this is just the converse I suppose)
|
||||
|
||||
let scope_id = match scope_r {
|
||||
ty::re_scope(scope_id) => scope_id,
|
||||
ty::re_scope(scope_id) | ty::re_free(scope_id, _) => scope_id,
|
||||
_ => {
|
||||
self.bccx.tcx.sess.span_bug(
|
||||
cmt.span,
|
||||
fmt!("loans required but scope is scope_region is %s",
|
||||
region_to_str(self.tcx(), scope_r)));
|
||||
fmt!("loans required but scope is scope_region is %s \
|
||||
(%?)",
|
||||
region_to_str(self.tcx(), scope_r),
|
||||
scope_r));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -17,7 +17,7 @@ use core::prelude::*;
|
||||
use middle::borrowck::{Loan, bckres, borrowck_ctxt, cmt, err_mutbl};
|
||||
use middle::borrowck::{err_out_of_scope};
|
||||
use middle::mem_categorization::{cat_arg, cat_binding, cat_discr, cat_comp};
|
||||
use middle::mem_categorization::{cat_deref, cat_discr, cat_local};
|
||||
use middle::mem_categorization::{cat_deref, cat_discr, cat_local, cat_self};
|
||||
use middle::mem_categorization::{cat_special, cat_stack_upvar, comp_field};
|
||||
use middle::mem_categorization::{comp_index, comp_variant, gc_ptr};
|
||||
use middle::mem_categorization::{region_ptr};
|
||||
@ -121,7 +121,7 @@ impl LoanContext {
|
||||
cmt.span,
|
||||
~"rvalue with a non-none lp");
|
||||
}
|
||||
cat_local(local_id) | cat_arg(local_id) => {
|
||||
cat_local(local_id) | cat_arg(local_id) | cat_self(local_id) => {
|
||||
let local_scope_id = self.tcx().region_map.get(local_id);
|
||||
self.issue_loan(cmt, ty::re_scope(local_scope_id), req_mutbl)
|
||||
}
|
||||
@ -162,9 +162,18 @@ impl LoanContext {
|
||||
// then the memory is freed.
|
||||
self.loan_unstable_deref(cmt, cmt_base, req_mutbl)
|
||||
}
|
||||
cat_deref(cmt_base, _, region_ptr(ast::m_mutbl, region)) => {
|
||||
// Mutable data can be loaned out as immutable or const. We must
|
||||
// loan out the base as well as the main memory. For example,
|
||||
// if someone borrows `*b`, we want to borrow `b` as immutable
|
||||
// as well.
|
||||
do self.loan(cmt_base, m_imm).chain |_| {
|
||||
self.issue_loan(cmt, region, m_const)
|
||||
}
|
||||
}
|
||||
cat_deref(_, _, unsafe_ptr) |
|
||||
cat_deref(_, _, gc_ptr(_)) |
|
||||
cat_deref(_, _, region_ptr(_)) => {
|
||||
cat_deref(_, _, region_ptr(_, _)) => {
|
||||
// Aliased data is simply not lendable.
|
||||
self.bccx.tcx.sess.span_bug(
|
||||
cmt.span,
|
||||
|
@ -20,7 +20,7 @@ use middle::borrowck::{cmt, err_mut_uniq, err_mut_variant};
|
||||
use middle::borrowck::{err_out_of_root_scope, err_out_of_scope};
|
||||
use middle::borrowck::{err_root_not_permitted};
|
||||
use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref};
|
||||
use middle::mem_categorization::{cat_discr, cat_local, cat_special};
|
||||
use middle::mem_categorization::{cat_discr, cat_local, cat_self, cat_special};
|
||||
use middle::mem_categorization::{cat_stack_upvar, comp_field, comp_index};
|
||||
use middle::mem_categorization::{comp_variant, gc_ptr, region_ptr};
|
||||
use middle::ty;
|
||||
@ -90,7 +90,6 @@ priv impl &preserve_ctxt {
|
||||
let _i = indenter();
|
||||
|
||||
match cmt.cat {
|
||||
cat_special(sk_self) |
|
||||
cat_special(sk_implicit_self) |
|
||||
cat_special(sk_heap_upvar) => {
|
||||
self.compare_scope(cmt, ty::re_scope(self.item_ub))
|
||||
@ -148,6 +147,10 @@ priv impl &preserve_ctxt {
|
||||
let local_scope_id = self.tcx().region_map.get(local_id);
|
||||
self.compare_scope(cmt, ty::re_scope(local_scope_id))
|
||||
}
|
||||
cat_self(local_id) => {
|
||||
let local_scope_id = self.tcx().region_map.get(local_id);
|
||||
self.compare_scope(cmt, ty::re_scope(local_scope_id))
|
||||
}
|
||||
cat_comp(cmt_base, comp_field(*)) |
|
||||
cat_comp(cmt_base, comp_index(*)) |
|
||||
cat_comp(cmt_base, comp_tuple) |
|
||||
@ -171,7 +174,7 @@ priv impl &preserve_ctxt {
|
||||
// freed, so require imm.
|
||||
self.require_imm(cmt, cmt_base, err_mut_uniq)
|
||||
}
|
||||
cat_deref(_, _, region_ptr(region)) => {
|
||||
cat_deref(_, _, region_ptr(_, region)) => {
|
||||
// References are always "stable" for lifetime `region` by
|
||||
// induction (when the reference of type &MT was created,
|
||||
// the memory must have been stable).
|
||||
|
@ -73,6 +73,7 @@ enum categorization {
|
||||
cat_deref(cmt, uint, ptr_kind), // deref of a ptr
|
||||
cat_comp(cmt, comp_kind), // adjust to locate an internal component
|
||||
cat_discr(cmt, ast::node_id), // match discriminant (see preserve())
|
||||
cat_self(ast::node_id), // explicit `self`
|
||||
}
|
||||
|
||||
// different kinds of pointers:
|
||||
@ -80,7 +81,7 @@ enum categorization {
|
||||
pub enum ptr_kind {
|
||||
uniq_ptr,
|
||||
gc_ptr(ast::mutability),
|
||||
region_ptr(ty::Region),
|
||||
region_ptr(ast::mutability, ty::Region),
|
||||
unsafe_ptr
|
||||
}
|
||||
|
||||
@ -103,7 +104,6 @@ pub enum comp_kind {
|
||||
enum special_kind {
|
||||
sk_method,
|
||||
sk_static_item,
|
||||
sk_self,
|
||||
sk_implicit_self, // old by-reference `self`
|
||||
sk_heap_upvar
|
||||
}
|
||||
@ -135,45 +135,15 @@ impl cmt_ : cmp::Eq {
|
||||
// a loan path is like a category, but it exists only when the data is
|
||||
// interior to the stack frame. loan paths are used as the key to a
|
||||
// map indicating what is borrowed at any point in time.
|
||||
#[deriving_eq]
|
||||
pub enum loan_path {
|
||||
lp_local(ast::node_id),
|
||||
lp_arg(ast::node_id),
|
||||
lp_self,
|
||||
lp_deref(@loan_path, ptr_kind),
|
||||
lp_comp(@loan_path, comp_kind)
|
||||
}
|
||||
|
||||
impl loan_path : cmp::Eq {
|
||||
pure fn eq(&self, other: &loan_path) -> bool {
|
||||
match (*self) {
|
||||
lp_local(e0a) => {
|
||||
match (*other) {
|
||||
lp_local(e0b) => e0a == e0b,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
lp_arg(e0a) => {
|
||||
match (*other) {
|
||||
lp_arg(e0b) => e0a == e0b,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
lp_deref(e0a, e1a) => {
|
||||
match (*other) {
|
||||
lp_deref(e0b, e1b) => e0a == e0b && e1a == e1b,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
lp_comp(e0a, e1a) => {
|
||||
match (*other) {
|
||||
lp_comp(e0b, e1b) => e0a == e0b && e1a == e1b,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pure fn ne(&self, other: &loan_path) -> bool { !(*self).eq(other) }
|
||||
}
|
||||
|
||||
// We pun on *T to mean both actual deref of a ptr as well
|
||||
// as accessing of components:
|
||||
enum deref_kind {deref_ptr(ptr_kind), deref_comp(comp_kind)}
|
||||
@ -193,14 +163,17 @@ fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
|
||||
Some(deref_ptr(uniq_ptr))
|
||||
}
|
||||
|
||||
ty::ty_rptr(r, _) |
|
||||
ty::ty_evec(_, ty::vstore_slice(r)) |
|
||||
ty::ty_rptr(r, mt) |
|
||||
ty::ty_evec(mt, ty::vstore_slice(r)) => {
|
||||
Some(deref_ptr(region_ptr(mt.mutbl, r)))
|
||||
}
|
||||
|
||||
ty::ty_estr(ty::vstore_slice(r)) => {
|
||||
Some(deref_ptr(region_ptr(r)))
|
||||
Some(deref_ptr(region_ptr(ast::m_imm, r)))
|
||||
}
|
||||
|
||||
ty::ty_fn(ref f) if (*f).meta.proto == ast::ProtoBorrowed => {
|
||||
Some(deref_ptr(region_ptr((*f).meta.region)))
|
||||
Some(deref_ptr(region_ptr(ast::m_imm, (*f).meta.region)))
|
||||
}
|
||||
|
||||
ty::ty_box(mt) |
|
||||
@ -481,15 +454,18 @@ impl &mem_categorization_ctxt {
|
||||
mutbl:m, ty:expr_ty}
|
||||
}
|
||||
|
||||
ast::def_self(_, is_implicit) => {
|
||||
let special_kind = if is_implicit {
|
||||
sk_implicit_self
|
||||
ast::def_self(self_id, is_implicit) => {
|
||||
let cat, loan_path;
|
||||
if is_implicit {
|
||||
cat = cat_special(sk_implicit_self);
|
||||
loan_path = None;
|
||||
} else {
|
||||
sk_self
|
||||
cat = cat_self(self_id);
|
||||
loan_path = Some(@lp_self);
|
||||
};
|
||||
|
||||
@{id:id, span:span,
|
||||
cat:cat_special(special_kind), lp:None,
|
||||
cat:cat, lp:loan_path,
|
||||
mutbl:m_imm, ty:expr_ty}
|
||||
}
|
||||
|
||||
@ -626,13 +602,16 @@ impl &mem_categorization_ctxt {
|
||||
deref_ptr(ptr) => {
|
||||
let lp = do base_cmt.lp.chain_ref |l| {
|
||||
// Given that the ptr itself is loanable, we can
|
||||
// loan out deref'd uniq ptrs as the data they are
|
||||
// the only way to reach the data they point at.
|
||||
// Other ptr types admit aliases and are therefore
|
||||
// not loanable.
|
||||
// loan out deref'd uniq ptrs or mut ptrs as the data
|
||||
// they are the only way to mutably reach the data they
|
||||
// point at. Other ptr types admit mutable aliases and
|
||||
// are therefore not loanable.
|
||||
match ptr {
|
||||
uniq_ptr => {Some(@lp_deref(*l, ptr))}
|
||||
gc_ptr(*) | region_ptr(_) | unsafe_ptr => {None}
|
||||
uniq_ptr => Some(@lp_deref(*l, ptr)),
|
||||
region_ptr(ast::m_mutbl, _) => {
|
||||
Some(@lp_deref(*l, ptr))
|
||||
}
|
||||
gc_ptr(*) | region_ptr(_, _) | unsafe_ptr => None
|
||||
}
|
||||
};
|
||||
|
||||
@ -642,7 +621,7 @@ impl &mem_categorization_ctxt {
|
||||
uniq_ptr => {
|
||||
self.inherited_mutability(base_cmt.mutbl, mt.mutbl)
|
||||
}
|
||||
gc_ptr(*) | region_ptr(_) | unsafe_ptr => {
|
||||
gc_ptr(*) | region_ptr(_, _) | unsafe_ptr => {
|
||||
mt.mutbl
|
||||
}
|
||||
};
|
||||
@ -688,7 +667,7 @@ impl &mem_categorization_ctxt {
|
||||
uniq_ptr => {
|
||||
self.inherited_mutability(base_cmt.mutbl, mt.mutbl)
|
||||
}
|
||||
gc_ptr(_) | region_ptr(_) | unsafe_ptr => {
|
||||
gc_ptr(_) | region_ptr(_, _) | unsafe_ptr => {
|
||||
mt.mutbl
|
||||
}
|
||||
};
|
||||
@ -866,13 +845,13 @@ impl &mem_categorization_ctxt {
|
||||
cat_special(sk_method) => ~"method",
|
||||
cat_special(sk_static_item) => ~"static_item",
|
||||
cat_special(sk_implicit_self) => ~"implicit-self",
|
||||
cat_special(sk_self) => ~"self",
|
||||
cat_special(sk_heap_upvar) => ~"heap-upvar",
|
||||
cat_stack_upvar(_) => ~"stack-upvar",
|
||||
cat_rvalue => ~"rvalue",
|
||||
cat_local(node_id) => fmt!("local(%d)", node_id),
|
||||
cat_binding(node_id) => fmt!("binding(%d)", node_id),
|
||||
cat_arg(node_id) => fmt!("arg(%d)", node_id),
|
||||
cat_self(node_id) => fmt!("self(%d)", node_id),
|
||||
cat_deref(cmt, derefs, ptr) => {
|
||||
fmt!("%s->(%s, %u)", self.cat_to_repr(cmt.cat),
|
||||
self.ptr_sigil(ptr), derefs)
|
||||
@ -896,7 +875,7 @@ impl &mem_categorization_ctxt {
|
||||
match ptr {
|
||||
uniq_ptr => ~"~",
|
||||
gc_ptr(_) => ~"@",
|
||||
region_ptr(_) => ~"&",
|
||||
region_ptr(_, _) => ~"&",
|
||||
unsafe_ptr => ~"*"
|
||||
}
|
||||
}
|
||||
@ -919,6 +898,7 @@ impl &mem_categorization_ctxt {
|
||||
lp_arg(node_id) => {
|
||||
fmt!("arg(%d)", node_id)
|
||||
}
|
||||
lp_self => ~"self",
|
||||
lp_deref(lp, ptr) => {
|
||||
fmt!("%s->(%s)", self.lp_to_str(lp),
|
||||
self.ptr_sigil(ptr))
|
||||
@ -945,13 +925,13 @@ impl &mem_categorization_ctxt {
|
||||
cat_special(sk_method) => ~"method",
|
||||
cat_special(sk_static_item) => ~"static item",
|
||||
cat_special(sk_implicit_self) => ~"self reference",
|
||||
cat_special(sk_self) => ~"self value",
|
||||
cat_special(sk_heap_upvar) => {
|
||||
~"captured outer variable in a heap closure"
|
||||
}
|
||||
cat_rvalue => ~"non-lvalue",
|
||||
cat_local(_) => mut_str + ~" local variable",
|
||||
cat_binding(_) => ~"pattern binding",
|
||||
cat_self(_) => ~"self value",
|
||||
cat_arg(_) => ~"argument",
|
||||
cat_deref(_, _, pk) => fmt!("dereference of %s %s pointer",
|
||||
mut_str, self.ptr_sigil(pk)),
|
||||
@ -1045,7 +1025,8 @@ impl categorization {
|
||||
cat_special(*) |
|
||||
cat_local(*) |
|
||||
cat_binding(*) |
|
||||
cat_arg(*) => {
|
||||
cat_arg(*) |
|
||||
cat_self(*) => {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -336,6 +336,14 @@ fn resolve_fn(fk: visit::fn_kind, decl: ast::fn_decl, body: ast::blk,
|
||||
}
|
||||
};
|
||||
|
||||
// Record the ID of `self`.
|
||||
match fk {
|
||||
visit::fk_method(_, _, method) => {
|
||||
cx.region_map.insert(method.self_id, body.node.id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
debug!("visiting fn with body %d. cx.parent: %? \
|
||||
fn_cx.parent: %?",
|
||||
body.node.id, cx.parent, fn_cx.parent);
|
||||
|
@ -241,19 +241,24 @@ fn check_poison(is_mutex: bool, failed: bool) {
|
||||
|
||||
#[doc(hidden)]
|
||||
struct PoisonOnFail {
|
||||
failed: &mut bool,
|
||||
failed: *mut bool,
|
||||
}
|
||||
|
||||
impl PoisonOnFail : Drop {
|
||||
fn finalize(&self) {
|
||||
/* assert !*self.failed; -- might be false in case of cond.wait() */
|
||||
if task::failing() { *self.failed = true; }
|
||||
unsafe {
|
||||
/* assert !*self.failed;
|
||||
-- might be false in case of cond.wait() */
|
||||
if task::failing() {
|
||||
*self.failed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn PoisonOnFail(failed: &r/mut bool) -> PoisonOnFail/&r {
|
||||
fn PoisonOnFail(failed: &r/mut bool) -> PoisonOnFail {
|
||||
PoisonOnFail {
|
||||
failed: failed
|
||||
failed: ptr::to_mut_unsafe_ptr(failed)
|
||||
}
|
||||
}
|
||||
|
||||
@ -415,7 +420,7 @@ pub fn unwrap_rw_arc<T: Const Owned>(arc: RWARC<T>) -> T {
|
||||
// field is never overwritten; only 'failed' and 'data'.
|
||||
#[doc(hidden)]
|
||||
fn borrow_rwlock<T: Const Owned>(state: &r/mut RWARCInner<T>) -> &r/RWlock {
|
||||
unsafe { cast::transmute_immut(&mut state.lock) }
|
||||
unsafe { cast::transmute(&mut state.lock) }
|
||||
}
|
||||
|
||||
// FIXME (#3154) ice with struct/&<T> prevents these from being structs.
|
||||
@ -442,12 +447,14 @@ impl<T: Const Owned> &RWWriteMode<T> {
|
||||
match *self {
|
||||
RWWriteMode((ref data, ref token, ref poison)) => {
|
||||
do token.write_cond |cond| {
|
||||
let cvar = Condvar {
|
||||
is_mutex: false,
|
||||
failed: &mut *poison.failed,
|
||||
cond: cond
|
||||
};
|
||||
blk(&mut **data, &cvar)
|
||||
unsafe {
|
||||
let cvar = Condvar {
|
||||
is_mutex: false,
|
||||
failed: &mut *poison.failed,
|
||||
cond: cond
|
||||
};
|
||||
blk(&mut **data, &cvar)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ use core::vec;
|
||||
#[abi = "rust-intrinsic"]
|
||||
extern "C" mod rusti {
|
||||
fn move_val_init<T>(dst: &mut T, -src: T);
|
||||
fn init<T>() -> T;
|
||||
}
|
||||
|
||||
pub struct PriorityQueue <T: Ord>{
|
||||
@ -136,8 +137,9 @@ impl <T: Ord> PriorityQueue<T> {
|
||||
while pos > start {
|
||||
let parent = (pos - 1) >> 1;
|
||||
if new > self.data[parent] {
|
||||
rusti::move_val_init(&mut self.data[pos],
|
||||
move *addr_of(&self.data[parent]));
|
||||
let mut x = rusti::init();
|
||||
x <-> self.data[parent];
|
||||
rusti::move_val_init(&mut self.data[pos], move x);
|
||||
pos = parent;
|
||||
loop
|
||||
}
|
||||
@ -159,8 +161,9 @@ impl <T: Ord> PriorityQueue<T> {
|
||||
if right < end && !(self.data[child] > self.data[right]) {
|
||||
child = right;
|
||||
}
|
||||
rusti::move_val_init(&mut self.data[pos],
|
||||
move *addr_of(&self.data[child]));
|
||||
let mut x = rusti::init();
|
||||
x <-> self.data[child];
|
||||
rusti::move_val_init(&mut self.data[pos], move x);
|
||||
pos = child;
|
||||
child = 2 * pos + 1;
|
||||
}
|
||||
|
@ -55,8 +55,10 @@ impl <K: Eq Ord, V: Eq> TreeMap<K, V>: Eq {
|
||||
unsafe { // unsafe as a purity workaround
|
||||
// ICE: x.next() != y.next()
|
||||
|
||||
let (x1, x2) = x.next().unwrap();
|
||||
let (y1, y2) = y.next().unwrap();
|
||||
x = x.next();
|
||||
y = y.next();
|
||||
let (x1, x2) = x.get().unwrap();
|
||||
let (y1, y2) = y.get().unwrap();
|
||||
|
||||
if x1 != y1 || x2 != y2 {
|
||||
return false
|
||||
@ -160,35 +162,46 @@ impl <K: Ord, V> TreeMap<K, V> {
|
||||
/// Get a lazy iterator over the key-value pairs in the map.
|
||||
/// Requires that it be frozen (immutable).
|
||||
pure fn iter(&self) -> TreeMapIterator/&self<K, V> {
|
||||
TreeMapIterator{stack: ~[], node: &self.root}
|
||||
TreeMapIterator{stack: ~[], node: &self.root, current: None}
|
||||
}
|
||||
}
|
||||
|
||||
/// Lazy forward iterator over a map
|
||||
pub struct TreeMapIterator<K: Ord, V> {
|
||||
priv stack: ~[&~TreeNode<K, V>],
|
||||
priv node: &Option<~TreeNode<K, V>>
|
||||
priv node: &Option<~TreeNode<K, V>>,
|
||||
priv current: Option<&~TreeNode<K, V>>
|
||||
}
|
||||
|
||||
impl <K: Ord, V> TreeMapIterator<K, V> {
|
||||
/// Advance the iterator to the next node (in order) and return a
|
||||
/// tuple with a reference to the key and value. If there are no
|
||||
/// more nodes, return `None`.
|
||||
fn next(&mut self) -> Option<(&self/K, &self/V)> {
|
||||
while !self.stack.is_empty() || self.node.is_some() {
|
||||
match *self.node {
|
||||
// Returns the current node, or None if this iterator is at the end.
|
||||
fn get(&const self) -> Option<(&self/K, &self/V)> {
|
||||
match self.current {
|
||||
Some(res) => Some((&res.key, &res.value)),
|
||||
None => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Advance the iterator to the next node (in order). If this iterator
|
||||
/// is finished, does nothing.
|
||||
fn next(self) -> TreeMapIterator/&self<K, V> {
|
||||
let mut this = self;
|
||||
while !this.stack.is_empty() || this.node.is_some() {
|
||||
match *this.node {
|
||||
Some(ref x) => {
|
||||
self.stack.push(x);
|
||||
self.node = &x.left;
|
||||
this.stack.push(x);
|
||||
this.node = &x.left;
|
||||
}
|
||||
None => {
|
||||
let res = self.stack.pop();
|
||||
self.node = &res.right;
|
||||
return Some((&res.key, &res.value));
|
||||
let res = this.stack.pop();
|
||||
this.node = &res.right;
|
||||
this.current = Some(res);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
this.current = None;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@ -256,15 +269,19 @@ impl <T: Ord> TreeSet<T> {
|
||||
let mut x = self.iter();
|
||||
let mut y = other.iter();
|
||||
unsafe { // purity workaround
|
||||
let mut a = x.next();
|
||||
let mut b = y.next();
|
||||
x = x.next();
|
||||
y = y.next();
|
||||
let mut a = x.get();
|
||||
let mut b = y.get();
|
||||
while a.is_some() && b.is_some() {
|
||||
let a1 = a.unwrap();
|
||||
let b1 = b.unwrap();
|
||||
if a1 < b1 {
|
||||
a = x.next();
|
||||
x = x.next();
|
||||
a = x.get();
|
||||
} else if b1 < a1 {
|
||||
b = y.next();
|
||||
y = y.next();
|
||||
b = y.get();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@ -283,8 +300,10 @@ impl <T: Ord> TreeSet<T> {
|
||||
let mut x = self.iter();
|
||||
let mut y = other.iter();
|
||||
unsafe { // purity workaround
|
||||
let mut a = x.next();
|
||||
let mut b = y.next();
|
||||
x = x.next();
|
||||
y = y.next();
|
||||
let mut a = x.get();
|
||||
let mut b = y.get();
|
||||
while b.is_some() {
|
||||
if a.is_none() {
|
||||
return false
|
||||
@ -298,9 +317,11 @@ impl <T: Ord> TreeSet<T> {
|
||||
}
|
||||
|
||||
if !(a1 < b1) {
|
||||
b = y.next();
|
||||
y = y.next();
|
||||
b = y.get();
|
||||
}
|
||||
a = x.next();
|
||||
x = x.next();
|
||||
a = x.get();
|
||||
}
|
||||
}
|
||||
true
|
||||
@ -312,13 +333,15 @@ impl <T: Ord> TreeSet<T> {
|
||||
let mut y = other.iter();
|
||||
|
||||
unsafe { // purity workaround
|
||||
let mut a = x.next();
|
||||
let mut b = y.next();
|
||||
x = x.next();
|
||||
y = y.next();
|
||||
let mut a = x.get();
|
||||
let mut b = y.get();
|
||||
|
||||
while a.is_some() {
|
||||
if b.is_none() {
|
||||
return do a.while_some() |a1| {
|
||||
if f(a1) { x.next() } else { None }
|
||||
if f(a1) { x = x.next(); x.get() } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,10 +350,12 @@ impl <T: Ord> TreeSet<T> {
|
||||
|
||||
if a1 < b1 {
|
||||
if !f(a1) { return }
|
||||
a = x.next();
|
||||
x = x.next();
|
||||
a = x.get();
|
||||
} else {
|
||||
if !(b1 < a1) { a = x.next() }
|
||||
b = y.next();
|
||||
if !(b1 < a1) { x = x.next(); a = x.get() }
|
||||
y = y.next();
|
||||
b = y.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -343,13 +368,15 @@ impl <T: Ord> TreeSet<T> {
|
||||
let mut y = other.iter();
|
||||
|
||||
unsafe { // purity workaround
|
||||
let mut a = x.next();
|
||||
let mut b = y.next();
|
||||
x = x.next();
|
||||
y = y.next();
|
||||
let mut a = x.get();
|
||||
let mut b = y.get();
|
||||
|
||||
while a.is_some() {
|
||||
if b.is_none() {
|
||||
return do a.while_some() |a1| {
|
||||
if f(a1) { x.next() } else { None }
|
||||
if f(a1) { x.next(); x.get() } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
@ -358,18 +385,21 @@ impl <T: Ord> TreeSet<T> {
|
||||
|
||||
if a1 < b1 {
|
||||
if !f(a1) { return }
|
||||
a = x.next();
|
||||
x = x.next();
|
||||
a = x.get();
|
||||
} else {
|
||||
if b1 < a1 {
|
||||
if !f(b1) { return }
|
||||
} else {
|
||||
a = x.next();
|
||||
x = x.next();
|
||||
a = x.get();
|
||||
}
|
||||
b = y.next();
|
||||
y = y.next();
|
||||
b = y.get();
|
||||
}
|
||||
}
|
||||
do b.while_some |b1| {
|
||||
if f(b1) { y.next() } else { None }
|
||||
if f(b1) { y = y.next(); y.get() } else { None }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -380,19 +410,23 @@ impl <T: Ord> TreeSet<T> {
|
||||
let mut y = other.iter();
|
||||
|
||||
unsafe { // purity workaround
|
||||
let mut a = x.next();
|
||||
let mut b = y.next();
|
||||
x = x.next();
|
||||
y = y.next();
|
||||
let mut a = x.get();
|
||||
let mut b = y.get();
|
||||
|
||||
while a.is_some() && b.is_some() {
|
||||
let a1 = a.unwrap();
|
||||
let b1 = b.unwrap();
|
||||
if a1 < b1 {
|
||||
a = x.next();
|
||||
x = x.next();
|
||||
a = x.get();
|
||||
} else {
|
||||
if !(b1 < a1) {
|
||||
if !f(a1) { return }
|
||||
}
|
||||
b = y.next();
|
||||
y = y.next();
|
||||
b = y.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -404,13 +438,15 @@ impl <T: Ord> TreeSet<T> {
|
||||
let mut y = other.iter();
|
||||
|
||||
unsafe { // purity workaround
|
||||
let mut a = x.next();
|
||||
let mut b = y.next();
|
||||
x = x.next();
|
||||
y = y.next();
|
||||
let mut a = x.get();
|
||||
let mut b = y.get();
|
||||
|
||||
while a.is_some() {
|
||||
if b.is_none() {
|
||||
return do a.while_some() |a1| {
|
||||
if f(a1) { x.next() } else { None }
|
||||
if f(a1) { x = x.next(); x.get() } else { None }
|
||||
}
|
||||
}
|
||||
|
||||
@ -419,13 +455,16 @@ impl <T: Ord> TreeSet<T> {
|
||||
|
||||
if b1 < a1 {
|
||||
if !f(b1) { return }
|
||||
b = y.next();
|
||||
y = y.next();
|
||||
b = y.get();
|
||||
} else {
|
||||
if !f(a1) { return }
|
||||
if !(a1 < b1) {
|
||||
b = y.next()
|
||||
y = y.next();
|
||||
b = y.get()
|
||||
}
|
||||
a = x.next();
|
||||
x = x.next();
|
||||
a = x.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -438,11 +477,18 @@ pub struct TreeSetIterator<T: Ord> {
|
||||
}
|
||||
|
||||
impl <T: Ord> TreeSetIterator<T> {
|
||||
/// Advance the iterator to the next node (in order) and return a
|
||||
/// tuple with a reference to the value. If there are no more nodes,
|
||||
/// return `None`.
|
||||
fn next(&mut self) -> Option<&self/T> {
|
||||
self.iter.next().map_consume(|(x, _)| x)
|
||||
/// Returns the current node, or None if this iterator is at the end.
|
||||
fn get(&const self) -> Option<&self/T> {
|
||||
match self.iter.get() {
|
||||
None => None,
|
||||
Some((k, _)) => Some(k)
|
||||
}
|
||||
}
|
||||
|
||||
/// Advance the iterator to the next node (in order). If this iterator is
|
||||
/// finished, does nothing.
|
||||
fn next(self) -> TreeSetIterator/&self<T> {
|
||||
TreeSetIterator { iter: self.iter.next() }
|
||||
}
|
||||
}
|
||||
|
||||
@ -854,17 +900,23 @@ mod test_treemap {
|
||||
//assert iter.next() == Some((&x1, &y1));
|
||||
//assert iter.next().eq(&Some((&x1, &y1)));
|
||||
|
||||
assert iter.next().unwrap() == (&x1, &y1);
|
||||
assert iter.next().unwrap() == (&x2, &y2);
|
||||
assert iter.next().unwrap() == (&x3, &y3);
|
||||
assert iter.next().unwrap() == (&x4, &y4);
|
||||
assert iter.next().unwrap() == (&x5, &y5);
|
||||
iter = iter.next();
|
||||
assert iter.get().unwrap() == (&x1, &y1);
|
||||
iter = iter.next();
|
||||
assert iter.get().unwrap() == (&x2, &y2);
|
||||
iter = iter.next();
|
||||
assert iter.get().unwrap() == (&x3, &y3);
|
||||
iter = iter.next();
|
||||
assert iter.get().unwrap() == (&x4, &y4);
|
||||
iter = iter.next();
|
||||
assert iter.get().unwrap() == (&x5, &y5);
|
||||
|
||||
// ICE:
|
||||
//assert iter.next() == None;
|
||||
//assert iter.next().eq(&None);
|
||||
|
||||
assert iter.next().is_none();
|
||||
iter = iter.next();
|
||||
assert iter.get().is_none();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ fn main() {
|
||||
do (&mut x).with |opt| { //~ ERROR illegal borrow
|
||||
match opt {
|
||||
&Right(ref f) => {
|
||||
x = X(Left((0,0)));
|
||||
x = X(Left((0,0))); //~ ERROR assigning to captured outer mutable variable
|
||||
(*f)()
|
||||
},
|
||||
_ => fail
|
||||
|
@ -19,7 +19,7 @@ impl Foo {
|
||||
}
|
||||
|
||||
fn a(x: &mut Foo) {
|
||||
x.f(); //~ ERROR illegal borrow unless pure
|
||||
x.f();
|
||||
x.g();
|
||||
x.h();
|
||||
}
|
||||
|
@ -22,8 +22,9 @@ fn main() {
|
||||
let q = &mut b.foo; //~ ERROR loan of mutable field as mutable conflicts with prior loan
|
||||
//~^ ERROR loan of mutable local variable as mutable conflicts with prior loan
|
||||
let r = &mut b; //~ ERROR loan of mutable local variable as mutable conflicts with prior loan
|
||||
//~^ ERROR loan of mutable local variable as mutable conflicts with prior loan
|
||||
io::println(fmt!("*p = %u", *p));
|
||||
q.x += 1;
|
||||
r.foo.x += 1;
|
||||
io::println(fmt!("*p = %u", *p));
|
||||
}
|
||||
}
|
||||
|
@ -10,9 +10,9 @@
|
||||
|
||||
fn main() {
|
||||
let mut _a = 3;
|
||||
let _b = &mut _a;
|
||||
let _b = &mut _a; //~ NOTE loan of mutable local variable granted here
|
||||
{
|
||||
let _c = &*_b; //~ ERROR illegal borrow unless pure
|
||||
_a = 4; //~ NOTE impure due to assigning to mutable local variable
|
||||
let _c = &*_b;
|
||||
_a = 4; //~ ERROR assigning to mutable local variable prohibited
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
fn borrow(_v: &int) {}
|
||||
|
||||
fn box_mut(v: &mut ~int) {
|
||||
borrow(*v); //~ ERROR illegal borrow unless pure
|
||||
borrow(*v); // OK: &mut -> &imm
|
||||
}
|
||||
|
||||
fn box_rec_mut(v: &{mut f: ~int}) {
|
||||
@ -19,11 +19,11 @@ fn box_rec_mut(v: &{mut f: ~int}) {
|
||||
}
|
||||
|
||||
fn box_mut_rec(v: &mut {f: ~int}) {
|
||||
borrow(v.f); //~ ERROR illegal borrow unless pure
|
||||
borrow(v.f); // OK: &mut -> &imm
|
||||
}
|
||||
|
||||
fn box_mut_recs(v: &mut {f: {g: {h: ~int}}}) {
|
||||
borrow(v.f.g.h); //~ ERROR illegal borrow unless pure
|
||||
borrow(v.f.g.h); // OK: &mut -> &imm
|
||||
}
|
||||
|
||||
fn box_imm(v: &~int) {
|
||||
|
@ -0,0 +1,6 @@
|
||||
fn main() {
|
||||
let mut b = ~3;
|
||||
let _x = &mut *b; //~ NOTE prior loan as mutable granted here
|
||||
let _y = &mut *b; //~ ERROR loan of dereference of mutable ~ pointer as mutable conflicts with prior loan
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
fn main() {
|
||||
let mut a = ~3;
|
||||
let mut b = &mut a; //~ NOTE loan of mutable local variable granted here
|
||||
let _c = &mut *b;
|
||||
let mut d = /*move*/ a; //~ ERROR moving out of mutable local variable prohibited due to outstanding loan
|
||||
*d += 1;
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
fn main() {
|
||||
let mut b = ~3;
|
||||
let _x = &mut *b; //~ NOTE loan of mutable local variable granted here
|
||||
let mut y = /*move*/ b; //~ ERROR moving out of mutable local variable prohibited
|
||||
*y += 1;
|
||||
}
|
||||
|
11
src/test/compile-fail/borrowck-wg-move-base-2.rs
Normal file
11
src/test/compile-fail/borrowck-wg-move-base-2.rs
Normal file
@ -0,0 +1,11 @@
|
||||
fn foo(x: &mut int) {
|
||||
let mut a = 3;
|
||||
let mut _y = &mut *x;
|
||||
let _z = &mut *_y;
|
||||
_y = &mut a; //~ ERROR assigning to mutable local variable prohibited
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@ fn broken() {
|
||||
while x < 10 {
|
||||
let mut z = x;
|
||||
_y.push(&mut z); //~ ERROR illegal borrow
|
||||
x += 1;
|
||||
x += 1; //~ ERROR assigning to mutable local variable prohibited due to outstanding loan
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,8 +16,7 @@ fn main() {
|
||||
|
||||
match x {
|
||||
{f: ref mut v} => {
|
||||
impure(*v); //~ ERROR illegal borrow unless pure
|
||||
//~^ NOTE impure due to access to impure function
|
||||
impure(*v);
|
||||
}
|
||||
}
|
||||
}
|
@ -15,8 +15,7 @@ fn borrow_from_arg_imm_ref(&&v: ~int) {
|
||||
}
|
||||
|
||||
fn borrow_from_arg_mut_ref(v: &mut ~int) {
|
||||
borrow(*v); //~ ERROR illegal borrow unless pure
|
||||
//~^ NOTE impure due to access to impure function
|
||||
borrow(*v);
|
||||
}
|
||||
|
||||
fn borrow_from_arg_move(-v: ~int) {
|
13
src/test/run-pass/borrowck-wg-borrow-mut-to-imm-2.rs
Normal file
13
src/test/run-pass/borrowck-wg-borrow-mut-to-imm-2.rs
Normal file
@ -0,0 +1,13 @@
|
||||
struct Cat;
|
||||
|
||||
fn bar(_: &Cat) {
|
||||
}
|
||||
|
||||
fn foo(cat: &mut Cat) {
|
||||
bar(&*cat);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut mimi = ~Cat;
|
||||
foo(mimi);
|
||||
}
|
18
src/test/run-pass/borrowck-wg-borrow-mut-to-imm-3.rs
Normal file
18
src/test/run-pass/borrowck-wg-borrow-mut-to-imm-3.rs
Normal file
@ -0,0 +1,18 @@
|
||||
struct Wizard {
|
||||
spells: ~[&static/str]
|
||||
}
|
||||
|
||||
impl Wizard {
|
||||
fn cast(&mut self) {
|
||||
for self.spells.each |&spell| {
|
||||
io::println(spell);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut harry = Wizard {
|
||||
spells: ~[ "expelliarmus", "expecto patronum", "incendio" ]
|
||||
};
|
||||
harry.cast();
|
||||
}
|
12
src/test/run-pass/borrowck-wg-borrow-mut-to-imm.rs
Normal file
12
src/test/run-pass/borrowck-wg-borrow-mut-to-imm.rs
Normal file
@ -0,0 +1,12 @@
|
||||
fn g(x: &Option<int>) {
|
||||
io::println(x.get().to_str());
|
||||
}
|
||||
|
||||
fn f(x: &mut Option<int>) {
|
||||
g(&*x);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut x = ~Some(3);
|
||||
f(x);
|
||||
}
|
Loading…
Reference in New Issue
Block a user