Demode some code using by-mutbl-ref; warn about by-mutbl-ref

The parser now warns about use of mutbl-ref mode, though it's kind
of a lie since this commit doesn't remove support for the mode.

Changed move_val_init to have stage0 and stage1/2 versions, the latter of
which is demoded.

Changed the type that the typechecker expects the move_val_init
intrinsic to have. After this is pushed, I can make a new snapshot,
which will remove the need for the stage0 versions.
This commit is contained in:
Tim Chevalier 2012-10-05 14:58:42 -07:00
parent e3cb70fa8a
commit e16dbb7888
13 changed files with 204 additions and 23 deletions

View File

@ -21,7 +21,11 @@ extern mod rustrt {
#[abi = "rust-intrinsic"]
extern mod rusti {
#[legacy_exports];
#[cfg(stage0)]
fn move_val_init<T>(&dst: T, -src: T);
#[cfg(stage1)]
#[cfg(stage2)]
fn move_val_init<T>(dst: &mut T, -src: T);
}
/// Returns the number of elements the vector can hold without reallocating
@ -176,7 +180,9 @@ pub mod raw {
push_slow(v, move initval);
}
}
// This doesn't bother to make sure we have space.
#[cfg(stage0)]
#[inline(always)] // really pretty please
pub unsafe fn push_fast<T>(v: &mut @[const T], initval: T) {
let repr: **VecRepr = ::cast::reinterpret_cast(&v);
@ -186,6 +192,18 @@ pub mod raw {
let p = ptr::offset(p, fill) as *mut T;
rusti::move_val_init(*p, move initval);
}
// This doesn't bother to make sure we have space.
#[cfg(stage1)]
#[cfg(stage2)]
#[inline(always)] // really pretty please
pub unsafe fn push_fast<T>(v: &mut @[const T], initval: T) {
let repr: **VecRepr = ::cast::reinterpret_cast(&v);
let fill = (**repr).unboxed.fill;
(**repr).unboxed.fill += sys::size_of::<T>();
let p = addr_of(&((**repr).unboxed.data));
let p = ptr::offset(p, fill) as *mut T;
rusti::move_val_init(&mut(*p), move initval);
}
pub unsafe fn push_slow<T>(v: &mut @[const T], initval: T) {
reserve_at_least(v, v.len() + 1u);

View File

@ -18,9 +18,14 @@ extern mod rustrt {
#[abi = "rust-intrinsic"]
extern mod rusti {
#[cfg(stage0)]
fn move_val_init<T>(&dst: T, -src: T);
#[cfg(stage1)]
#[cfg(stage2)]
fn move_val_init<T>(dst: &mut T, -src: T);
}
/// Returns true if a vector contains no elements
pub pure fn is_empty<T>(v: &[const T]) -> bool {
as_const_buf(v, |_p, len| len == 0u)
@ -98,6 +103,7 @@ pub pure fn len<T>(v: &[const T]) -> uint {
* Creates an immutable vector of size `n_elts` and initializes the elements
* to the value returned by the function `op`.
*/
#[cfg(stage0)]
pub pure fn from_fn<T>(n_elts: uint, op: iter::InitOp<T>) -> ~[T] {
unsafe {
let mut v = with_capacity(n_elts);
@ -112,6 +118,22 @@ pub pure fn from_fn<T>(n_elts: uint, op: iter::InitOp<T>) -> ~[T] {
return move v;
}
}
#[cfg(stage1)]
#[cfg(stage2)]
pub pure fn from_fn<T>(n_elts: uint, op: iter::InitOp<T>) -> ~[T] {
unsafe {
let mut v = with_capacity(n_elts);
do as_mut_buf(v) |p, _len| {
let mut i: uint = 0u;
while i < n_elts {
rusti::move_val_init(&mut(*ptr::mut_offset(p, i)), op(i));
i += 1u;
}
}
raw::set_len(&mut v, n_elts);
return move v;
}
}
/**
* Creates and initializes an immutable vector.
@ -481,6 +503,7 @@ pub fn push<T>(v: &mut ~[T], initval: T) {
}
}
#[cfg(stage0)]
// This doesn't bother to make sure we have space.
#[inline(always)] // really pretty please
unsafe fn push_fast<T>(v: &mut ~[T], initval: T) {
@ -491,6 +514,18 @@ unsafe fn push_fast<T>(v: &mut ~[T], initval: T) {
let p = ptr::offset(p, fill) as *mut T;
rusti::move_val_init(*p, move initval);
}
#[cfg(stage1)]
#[cfg(stage2)]
// This doesn't bother to make sure we have space.
#[inline(always)] // really pretty please
unsafe fn push_fast<T>(v: &mut ~[T], initval: T) {
let repr: **raw::VecRepr = ::cast::transmute(v);
let fill = (**repr).unboxed.fill;
(**repr).unboxed.fill += sys::size_of::<T>();
let p = addr_of(&((**repr).unboxed.data));
let p = ptr::offset(p, fill) as *mut T;
rusti::move_val_init(&mut(*p), move initval);
}
#[inline(never)]
fn push_slow<T>(v: &mut ~[T], initval: T) {
@ -1758,6 +1793,18 @@ pub mod raw {
as_const_buf(v, |p, _len| *ptr::const_offset(p, i))
}
#[cfg(stage0)]
#[inline(always)]
pub unsafe fn init_elem<T>(v: &[mut T], i: uint, val: T) {
let mut box = Some(move val);
do as_mut_buf(v) |p, _len| {
let mut box2 = None;
box2 <-> box;
rusti::move_val_init(*ptr::mut_offset(p, i),
option::unwrap(move box2));
}
}
#[cfg(stage1)]
/**
* Unchecked vector index assignment. Does not drop the
* old value and hence is only suitable when the vector
@ -1769,7 +1816,7 @@ pub mod raw {
do as_mut_buf(v) |p, _len| {
let mut box2 = None;
box2 <-> box;
rusti::move_val_init(*ptr::mut_offset(p, i),
rusti::move_val_init(&mut(*ptr::mut_offset(p, i)),
option::unwrap(move box2));
}
}

View File

@ -31,9 +31,14 @@ use libc::size_t;
#[abi = "rust-intrinsic"]
extern mod rusti {
#[cfg(stage0)]
fn move_val_init<T>(&dst: T, -src: T);
#[cfg(stage1)]
#[cfg(stage2)]
fn move_val_init<T>(dst: &mut T, -src: T);
fn needs_drop<T>() -> bool;
}
extern mod rustrt {
#[rust_stack]
fn rust_call_tydesc_glue(root: *u8, tydesc: *TypeDesc, field: size_t);
@ -127,6 +132,8 @@ unsafe fn un_bitpack_tydesc_ptr(p: uint) -> (*TypeDesc, bool) {
(reinterpret_cast(&(p & !1)), p & 1 == 1)
}
// tjc: Can get rid of the duplication post-snapshot
#[cfg(stage0)]
// The duplication between the POD and non-POD functions is annoying.
impl &Arena {
// Functions for the POD part of the arena
@ -234,6 +241,114 @@ impl &Arena {
} else { self.alloc_nonpod(op) }
}
}
#[cfg(stage1)]
#[cfg(stage2)]
impl &Arena {
// Functions for the POD part of the arena
fn alloc_pod_grow(n_bytes: uint, align: uint) -> *u8 {
// Allocate a new chunk.
let chunk_size = at_vec::capacity(self.pod_head.data);
let new_min_chunk_size = uint::max(n_bytes, chunk_size);
self.chunks = @Cons(copy self.pod_head, self.chunks);
self.pod_head =
chunk(uint::next_power_of_two(new_min_chunk_size + 1u), true);
return self.alloc_pod_inner(n_bytes, align);
}
#[inline(always)]
fn alloc_pod_inner(n_bytes: uint, align: uint) -> *u8 {
let head = &mut self.pod_head;
let start = round_up_to(head.fill, align);
let end = start + n_bytes;
if end > at_vec::capacity(head.data) {
return self.alloc_pod_grow(n_bytes, align);
}
head.fill = end;
//debug!("idx = %u, size = %u, align = %u, fill = %u",
// start, n_bytes, align, head.fill);
unsafe {
ptr::offset(vec::raw::to_ptr(head.data), start)
}
}
#[inline(always)]
fn alloc_pod<T>(op: fn() -> T) -> &self/T {
unsafe {
let tydesc = sys::get_type_desc::<T>();
let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align);
let ptr: *mut T = reinterpret_cast(&ptr);
rusti::move_val_init(&mut (*ptr), op());
return reinterpret_cast(&ptr);
}
}
// Functions for the non-POD part of the arena
fn alloc_nonpod_grow(n_bytes: uint, align: uint) -> (*u8, *u8) {
// Allocate a new chunk.
let chunk_size = at_vec::capacity(self.head.data);
let new_min_chunk_size = uint::max(n_bytes, chunk_size);
self.chunks = @Cons(copy self.head, self.chunks);
self.head =
chunk(uint::next_power_of_two(new_min_chunk_size + 1u), false);
return self.alloc_nonpod_inner(n_bytes, align);
}
#[inline(always)]
fn alloc_nonpod_inner(n_bytes: uint, align: uint) -> (*u8, *u8) {
let head = &mut self.head;
let tydesc_start = head.fill;
let after_tydesc = head.fill + sys::size_of::<*TypeDesc>();
let start = round_up_to(after_tydesc, align);
let end = start + n_bytes;
if end > at_vec::capacity(head.data) {
return self.alloc_nonpod_grow(n_bytes, align);
}
head.fill = round_up_to(end, sys::pref_align_of::<*TypeDesc>());
//debug!("idx = %u, size = %u, align = %u, fill = %u",
// start, n_bytes, align, head.fill);
unsafe {
let buf = vec::raw::to_ptr(head.data);
return (ptr::offset(buf, tydesc_start), ptr::offset(buf, start));
}
}
#[inline(always)]
fn alloc_nonpod<T>(op: fn() -> T) -> &self/T {
unsafe {
let tydesc = sys::get_type_desc::<T>();
let (ty_ptr, ptr) =
self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align);
let ty_ptr: *mut uint = reinterpret_cast(&ty_ptr);
let ptr: *mut T = reinterpret_cast(&ptr);
// Write in our tydesc along with a bit indicating that it
// has *not* been initialized yet.
*ty_ptr = reinterpret_cast(&tydesc);
// Actually initialize it
rusti::move_val_init(&mut(*ptr), op());
// Now that we are done, update the tydesc to indicate that
// the object is there.
*ty_ptr = bitpack_tydesc_ptr(tydesc, true);
return reinterpret_cast(&ptr);
}
}
// The external interface
#[inline(always)]
fn alloc<T>(op: fn() -> T) -> &self/T {
if !rusti::needs_drop::<T>() {
self.alloc_pod(op)
} else { self.alloc_nonpod(op) }
}
}
#[test]
fn test_arena_destructors() {

View File

@ -570,6 +570,7 @@ impl parser {
fn parse_arg_mode() -> mode {
if self.eat(token::BINOP(token::AND)) {
self.warn(~"Obsolete syntax has no effect");
expl(by_mutbl_ref)
} else if self.eat(token::BINOP(token::MINUS)) {
expl(by_move)

View File

@ -2601,7 +2601,9 @@ fn check_intrinsic_type(ccx: @crate_ctxt, it: @ast::foreign_item) {
~"addr_of" => (1u, ~[arg(ast::by_ref, param(ccx, 0u))],
ty::mk_imm_ptr(tcx, param(ccx, 0u))),
~"move_val" | ~"move_val_init" => {
(1u, ~[arg(ast::by_mutbl_ref, param(ccx, 0u)),
(1u, ~[arg(ast::by_copy,
ty::mk_mut_rptr(tcx, ty::re_bound(ty::br_anon(0)),
param(ccx, 0u))),
arg(ast::by_move, param(ccx, 0u))],
ty::mk_nil(tcx))
}

View File

@ -4,8 +4,8 @@ fn borrow_from_arg_imm_ref(&&v: ~int) {
borrow(v);
}
fn borrow_from_arg_mut_ref(&v: ~int) {
borrow(v); //~ ERROR illegal borrow unless pure
fn borrow_from_arg_mut_ref(v: &mut ~int) {
borrow(*v); //~ ERROR illegal borrow unless pure
//~^ NOTE impure due to access to impure function
}

View File

@ -1,9 +1,11 @@
#[forbid(deprecated_mode)];
fn foo(_f: fn(&i: int)) { //~ ERROR explicit mode
//~^ WARNING Obsolete syntax has no effect
}
type Bar = fn(&i: int); //~ ERROR explicit mode
//~^ WARNING Obsolete syntax has no effect
fn main() {
}

View File

@ -1,11 +1,11 @@
extern mod std;
use cmp::Eq;
fn f<T:Eq>(&o: Option<T>) {
assert o == option::None;
fn f<T:Eq>(o: &mut Option<T>) {
assert *o == option::None;
}
fn main() {
f::<int>(option::None);
f::<int>(&mut option::None);
//~^ ERROR illegal borrow: creating mutable alias to static item
}

View File

@ -1,5 +1,5 @@
fn f1(&x: int) {
x = 1; // no error
fn f1(x: &mut int) {
*x = 1; // no error
}
fn f2() {

View File

@ -4,10 +4,6 @@ fn from_by_value_arg(++x: int) {
take(x); //~ ERROR illegal move from argument `x`, which is not copy or move mode
}
fn from_by_mut_ref_arg(&x: int) {
take(x); //~ ERROR illegal move from argument `x`, which is not copy or move mode
}
fn from_by_ref_arg(&&x: int) {
take(x); //~ ERROR illegal move from argument `x`, which is not copy or move mode
}

View File

@ -2,7 +2,7 @@ fn f1(x: int) {
//~^ WARNING unused variable: `x`
}
fn f1b(&x: int) {
fn f1b(x: &mut int) {
//~^ WARNING unused variable: `x`
}

View File

@ -1,28 +1,28 @@
// Note: it would be nice to give fewer warnings in these cases.
fn mutate_by_mut_ref(&x: uint) {
x = 0u;
fn mutate_by_mut_ref(x: &mut uint) {
*x = 0;
}
fn mutate_by_ref(&&x: uint) {
//~^ WARNING unused variable: `x`
x = 0u; //~ ERROR assigning to argument
x = 0; //~ ERROR assigning to argument
}
fn mutate_by_val(++x: uint) {
//~^ WARNING unused variable: `x`
x = 0u; //~ ERROR assigning to argument
x = 0; //~ ERROR assigning to argument
}
fn mutate_by_copy(+x: uint) {
//~^ WARNING unused variable: `x`
x = 0u; //~ ERROR assigning to argument
x = 0; //~ ERROR assigning to argument
//~^ WARNING value assigned to `x` is never read
}
fn mutate_by_move(-x: uint) {
//~^ WARNING unused variable: `x`
x = 0u; //~ ERROR assigning to argument
x = 0; //~ ERROR assigning to argument
//~^ WARNING value assigned to `x` is never read
}

View File

@ -1,13 +1,13 @@
#[abi = "rust-intrinsic"]
extern mod rusti {
#[legacy_exports];
fn move_val_init<T>(&dst: T, -src: T);
fn move_val<T>(&dst: T, -src: T);
fn move_val_init<T>(dst: &mut T, -src: T);
fn move_val<T>(dst: &mut T, -src: T);
}
fn main() {
let mut x = @1;
let mut y = @2;
rusti::move_val(y, x);
rusti::move_val(&mut y, x);
assert *y == 1;
}