diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 1caf569e77d50..df62b1356efaf 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -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,18 @@ pub fn shift(v: &mut ~[T]) -> T unsafe { // 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(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(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); diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 5635d5d18e59b..ff5854322f456 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -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; @@ -296,12 +296,11 @@ impl check_loan_ctxt { } match (old_loan.mutbl, new_loan.mutbl) { - (m_const, _) | (_, m_const) | - (m_mutbl, m_mutbl) | (m_imm, m_imm) => { + (m_const, _) | (_, m_const) | (m_imm, m_imm) => { /*ok*/ } - (m_mutbl, m_imm) | (m_imm, m_mutbl) => { + (m_mutbl, m_mutbl) | (m_mutbl, m_imm) | (m_imm, m_mutbl) => { self.bccx.span_err( new_loan.cmt.span, fmt!("loan of %s as %s \ @@ -418,8 +417,8 @@ impl check_loan_ctxt { for self.walk_loans_of(ex.id, lp) |loan| { match loan.mutbl { - m_mutbl | m_const => { /*ok*/ } - m_imm => { + m_const => { /*ok*/ } + m_mutbl | m_imm => { self.bccx.span_err( ex.span, fmt!("%s prohibited due to outstanding loan", @@ -445,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(*) => () } } @@ -482,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. diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs index 30ed831c53fe0..7f64ef094addf 100644 --- a/src/librustc/middle/borrowck/gather_loans.rs +++ b/src/librustc/middle/borrowck/gather_loans.rs @@ -479,13 +479,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)); } }; diff --git a/src/librustc/middle/borrowck/loan.rs b/src/librustc/middle/borrowck/loan.rs index 80e5dacae41e9..1b274a5241c67 100644 --- a/src/librustc/middle/borrowck/loan.rs +++ b/src/librustc/middle/borrowck/loan.rs @@ -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, @@ -251,7 +260,7 @@ impl LoanContext { // Variant components: the base must be immutable, because // if it is overwritten, the types of the embedded data // could change. - do self.loan(cmt_base, m_imm).chain |_ok| { + do self.loan(cmt_base, m_imm).chain |_| { // can use static, as in loan_stable_comp() self.issue_loan(cmt, ty::re_static, req_mutbl) } diff --git a/src/librustc/middle/borrowck/preserve.rs b/src/librustc/middle/borrowck/preserve.rs index 429df1a6aa52d..40dca3d930c27 100644 --- a/src/librustc/middle/borrowck/preserve.rs +++ b/src/librustc/middle/borrowck/preserve.rs @@ -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). diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3919c6bc8f108..e83dec7a85d8d 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -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 { 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) | @@ -480,15 +453,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} } @@ -625,13 +601,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 } }; @@ -641,7 +620,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 } }; @@ -687,7 +666,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 } }; @@ -865,13 +844,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) @@ -895,7 +874,7 @@ impl &mem_categorization_ctxt { match ptr { uniq_ptr => ~"~", gc_ptr(_) => ~"@", - region_ptr(_) => ~"&", + region_ptr(_, _) => ~"&", unsafe_ptr => ~"*" } } @@ -918,6 +897,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)) @@ -944,13 +924,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)), @@ -1044,7 +1024,8 @@ impl categorization { cat_special(*) | cat_local(*) | cat_binding(*) | - cat_arg(*) => { + cat_arg(*) | + cat_self(*) => { false } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index ae6a6d67c1d4a..723f432b78ac3 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -334,6 +334,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); diff --git a/src/libstd/arc.rs b/src/libstd/arc.rs index 4d1a8af0b1dd7..536f43d648c45 100644 --- a/src/libstd/arc.rs +++ b/src/libstd/arc.rs @@ -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(arc: RWARC) -> T { // field is never overwritten; only 'failed' and 'data'. #[doc(hidden)] fn borrow_rwlock(state: &r/mut RWARCInner) -> &r/RWlock { - unsafe { cast::transmute_immut(&mut state.lock) } + unsafe { cast::transmute(&mut state.lock) } } // FIXME (#3154) ice with struct/& prevents these from being structs. @@ -442,12 +447,14 @@ impl &RWWriteMode { 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) + } } } } diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index 4d341d737f602..34a977f3751fc 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -9,6 +9,7 @@ use core::vec; #[abi = "rust-intrinsic"] extern "C" mod rusti { fn move_val_init(dst: &mut T, -src: T); + fn init() -> T; } pub struct PriorityQueue { @@ -124,8 +125,9 @@ impl PriorityQueue { 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 } @@ -145,8 +147,9 @@ impl PriorityQueue { 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; } diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs index d83568ddd9475..f5fccd40d25a4 100644 --- a/src/libstd/sort.rs +++ b/src/libstd/sort.rs @@ -630,9 +630,15 @@ impl MergeState { dest -= 1; c2 -= 1; len2 -= 1; if len2 == 1 { break_outer = true; break; } - let tmp_view = vec::mut_view(tmp, 0, len2); - let count2 = len2 - gallop_left(&const array[c1], - tmp_view, len2-1); + let count2; + { + let tmp_view = vec::mut_view(tmp, 0, len2); + count2 = len2 - gallop_left(&const array[c1], + tmp_view, + len2-1); + // Make tmp_view go out of scope to appease borrowck. + } + if count2 != 0 { dest -= count2; c2 -= count2; len2 -= count2; copy_vec(array, dest+1, tmp, c2+1, count2); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6fba59d6a84d2..523c156abe77f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2482,6 +2482,10 @@ impl Parser { } else { break; } + + if self.eat(token::BINOP(token::PLUS)) { + // Should be `break;` but that isn't backwards compatible. + } } } return @move bounds; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f7117cc7043e2..9092a18f4389f 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1791,8 +1791,15 @@ fn print_arg_mode(s: ps, m: ast::mode) { fn print_bounds(s: ps, bounds: @~[ast::ty_param_bound]) { if bounds.is_not_empty() { word(s.s, ~":"); + let mut first = true; for vec::each(*bounds) |&bound| { nbsp(s); + if first { + first = false; + } else { + word_space(s, ~"+"); + } + match bound { TraitTyParamBound(ty) => print_type(s, ty), RegionTyParamBound => word(s.s, ~"&static"), diff --git a/src/test/compile-fail/borrowck-autoref-3261.rs b/src/test/compile-fail/borrowck-autoref-3261.rs index 457cdd2344737..0aec458aef43c 100644 --- a/src/test/compile-fail/borrowck-autoref-3261.rs +++ b/src/test/compile-fail/borrowck-autoref-3261.rs @@ -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 diff --git a/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs b/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs index 6bbe7adec3b48..4e0cc76bf7543 100644 --- a/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs +++ b/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs @@ -19,7 +19,7 @@ impl Foo { } fn a(x: &mut Foo) { - x.f(); //~ ERROR illegal borrow unless pure + x.f(); x.g(); x.h(); } diff --git a/src/test/compile-fail/borrowck-imm-field-mut-base.rs b/src/test/compile-fail/borrowck-imm-field-mut-base.rs index 48bd4ef75d64b..5c3fe22960254 100644 --- a/src/test/compile-fail/borrowck-imm-field-mut-base.rs +++ b/src/test/compile-fail/borrowck-imm-field-mut-base.rs @@ -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)); -} \ No newline at end of file +} diff --git a/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs b/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs index 618e094da1615..88db5f5434116 100644 --- a/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs +++ b/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs @@ -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 } } diff --git a/src/test/compile-fail/borrowck-uniq-via-ref.rs b/src/test/compile-fail/borrowck-uniq-via-ref.rs index 046ae7ea6d674..48d39c39e5a47 100644 --- a/src/test/compile-fail/borrowck-uniq-via-ref.rs +++ b/src/test/compile-fail/borrowck-uniq-via-ref.rs @@ -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) { diff --git a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs new file mode 100644 index 0000000000000..e47ad721b0d7b --- /dev/null +++ b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs @@ -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 +} + diff --git a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs new file mode 100644 index 0000000000000..015f368ecb068 --- /dev/null +++ b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs @@ -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; +} + diff --git a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs new file mode 100644 index 0000000000000..36d32fddda150 --- /dev/null +++ b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs @@ -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; +} + diff --git a/src/test/compile-fail/borrowck-wg-move-base-2.rs b/src/test/compile-fail/borrowck-wg-move-base-2.rs new file mode 100644 index 0000000000000..ba85616e63f28 --- /dev/null +++ b/src/test/compile-fail/borrowck-wg-move-base-2.rs @@ -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() { +} + + diff --git a/src/test/compile-fail/regions-escape-loop-via-vec.rs b/src/test/compile-fail/regions-escape-loop-via-vec.rs index 7490448caf004..da5e3c2660ef7 100644 --- a/src/test/compile-fail/regions-escape-loop-via-vec.rs +++ b/src/test/compile-fail/regions-escape-loop-via-vec.rs @@ -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 } } diff --git a/src/test/run-fail/write-guard-fail-2.rs b/src/test/run-fail/borrowck-wg-fail-2.rs similarity index 100% rename from src/test/run-fail/write-guard-fail-2.rs rename to src/test/run-fail/borrowck-wg-fail-2.rs diff --git a/src/test/run-fail/write-guard-fail-3.rs b/src/test/run-fail/borrowck-wg-fail-3.rs similarity index 100% rename from src/test/run-fail/write-guard-fail-3.rs rename to src/test/run-fail/borrowck-wg-fail-3.rs diff --git a/src/test/run-fail/write-guard-fail.rs b/src/test/run-fail/borrowck-wg-fail.rs similarity index 100% rename from src/test/run-fail/write-guard-fail.rs rename to src/test/run-fail/borrowck-wg-fail.rs diff --git a/src/test/run-pass/alt-implicit-copy-unique.rs b/src/test/run-pass/alt-implicit-copy-unique.rs index df9be797ed3f2..f703eed6a21c5 100644 --- a/src/test/run-pass/alt-implicit-copy-unique.rs +++ b/src/test/run-pass/alt-implicit-copy-unique.rs @@ -12,7 +12,7 @@ fn main() { let x = ~{mut a: ~10, b: ~20}; match x { ~{a: ref mut a, b: ref b} => { - assert **a == 10; (*x).a = ~30; assert **a == 30; + assert **a == 10; *a = ~30; assert **a == 30; } } } diff --git a/src/test/compile-fail/borrowck-binding-mutbl.rs b/src/test/run-pass/borrowck-binding-mutbl.rs similarity index 83% rename from src/test/compile-fail/borrowck-binding-mutbl.rs rename to src/test/run-pass/borrowck-binding-mutbl.rs index 5840dd001e872..04e00b5972c59 100644 --- a/src/test/compile-fail/borrowck-binding-mutbl.rs +++ b/src/test/run-pass/borrowck-binding-mutbl.rs @@ -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); } } } diff --git a/src/test/compile-fail/borrowck-lend-args.rs b/src/test/run-pass/borrowck-lend-args.rs similarity index 87% rename from src/test/compile-fail/borrowck-lend-args.rs rename to src/test/run-pass/borrowck-lend-args.rs index a71fca1ec0441..745f8f7f35744 100644 --- a/src/test/compile-fail/borrowck-lend-args.rs +++ b/src/test/run-pass/borrowck-lend-args.rs @@ -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) { diff --git a/src/test/run-pass/borrowck-wg-borrow-mut-to-imm-2.rs b/src/test/run-pass/borrowck-wg-borrow-mut-to-imm-2.rs new file mode 100644 index 0000000000000..12dc0c3a310ad --- /dev/null +++ b/src/test/run-pass/borrowck-wg-borrow-mut-to-imm-2.rs @@ -0,0 +1,13 @@ +struct Cat; + +fn bar(_: &Cat) { +} + +fn foo(cat: &mut Cat) { + bar(&*cat); +} + +fn main() { + let mut mimi = ~Cat; + foo(mimi); +} diff --git a/src/test/run-pass/borrowck-wg-borrow-mut-to-imm-3.rs b/src/test/run-pass/borrowck-wg-borrow-mut-to-imm-3.rs new file mode 100644 index 0000000000000..66e29f3af3d37 --- /dev/null +++ b/src/test/run-pass/borrowck-wg-borrow-mut-to-imm-3.rs @@ -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(); +} diff --git a/src/test/run-pass/borrowck-wg-borrow-mut-to-imm.rs b/src/test/run-pass/borrowck-wg-borrow-mut-to-imm.rs new file mode 100644 index 0000000000000..36155a9d26604 --- /dev/null +++ b/src/test/run-pass/borrowck-wg-borrow-mut-to-imm.rs @@ -0,0 +1,12 @@ +fn g(x: &Option) { + io::println(x.get().to_str()); +} + +fn f(x: &mut Option) { + g(&*x); +} + +fn main() { + let mut x = ~Some(3); + f(x); +} diff --git a/src/test/run-pass/write-guard.rs b/src/test/run-pass/borrowck-wg-simple.rs similarity index 100% rename from src/test/run-pass/write-guard.rs rename to src/test/run-pass/borrowck-wg-simple.rs diff --git a/src/test/run-pass/multiple-trait-bounds.rs b/src/test/run-pass/multiple-trait-bounds.rs new file mode 100644 index 0000000000000..e64b51888ef00 --- /dev/null +++ b/src/test/run-pass/multiple-trait-bounds.rs @@ -0,0 +1,7 @@ +fn f(_: T) { +} + +fn main() { + f(3); +} +