auto merge of #17725 : alexcrichton/rust/rollup, r=alexcrichton

This commit is contained in:
bors 2014-10-03 05:02:37 +00:00
commit aa034cd3ba
320 changed files with 1055 additions and 5371 deletions

View File

@ -1,60 +1,26 @@
# Use something that's not 'ruby' so we don't set up things like # Use something that's not 'ruby' so we don't set up things like
# RVM/bundler/ruby and whatnot. Right now 'rust' isn't a language on travis and # RVM/bundler/ruby and whatnot. Right now 'rust' as a language actually
# it treats unknown languages as ruby-like I believe. # downloads a rust/cargo snapshot, which we don't really want for building rust.
language: c language: c
# Before we start doing anything, install a stock LLVM # Make sure we've got an up-to-date g++ compiler to get past the LLVM configure
# script.
install: install:
- sudo sh -c "echo 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.4 main' >> /etc/apt/sources.list" - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo sh -c "echo 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise main' >> /etc/apt/sources.list"
- sudo sh -c "echo 'deb http://ppa.launchpad.net/ubuntu-toolchain-r/test/ubuntu precise main' >> /etc/apt/sources.list"
- wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add -
- sudo apt-get update -qq - sudo apt-get update -qq
- sudo apt-get install -qq --force-yes -y llvm-$LLVM_VERSION - sudo apt-get install g++-4.7
llvm-${LLVM_VERSION}-dev clang-$LLVM_VERSION lldb-$LLVM_VERSION
# The test suite is in general way too stressful for travis, especially in
# All of the llvm tools are suffixed with "-$VERS" which we don't want, so # terms of time limit and reliability. In the past we've tried to scale things
# symlink them all into a local directory and just use that # back to only build the stage1 compiler and run a subset of tests, but this
# didn't end up panning out very well.
# #
# FIXME: this shouldn't update the src/llvm sub-repo, that takes about a minute # As a result, we're just using travis to run `make tidy` now. It'll help
# it's gotta download so much stuff. # everyone find out about their trailing spaces early on!
before_script: before_script:
- mkdir -p local-llvm/bin - ./configure
- ln -nsf /usr/bin/llvm-config-$LLVM_VERSION local-llvm/bin/llvm-config script:
- ln -nsf /usr/bin/llvm-mc-$LLVM_VERSION local-llvm/bin/llvm-mc - make tidy
- ln -nsf /usr/bin/llvm-as-$LLVM_VERSION local-llvm/bin/llvm-as
- ln -nsf /usr/bin/llvm-dis-$LLVM_VERSION local-llvm/bin/llvm-dis
- ln -nsf /usr/bin/llc-$LLVM_VERSION local-llvm/bin/llc
- ln -nsf /usr/include/llvm-$LLVM_VERSION local-llvm/include
- ./configure --disable-optimize-tests --llvm-root=`pwd`/local-llvm
--enable-fast-make --enable-clang
# Tidy everything up first, then build a few things, and then run a few tests.
# Note that this is meant to run in a "fairly small" amount of time, so this
# isn't exhaustive at all.
#
# As a result of https://github.com/travis-ci/travis-ci/issues/1066, we run
# everything in one large command instead of multiple commands.
script: |
if [[ $TRAVIS_PULL_REQUEST != 'false' ]]; then
if [[ $LLVM_VERSION != '3.4' ]]; then exit 0; fi
fi &&
make tidy &&
make -j4 rustc-stage1 RUSTFLAGS='-Z time-passes' &&
make check-stage1-std check-stage1-rpass check-stage1-cfail check-stage1-rfail check-stage1-doc
env:
global:
- NO_BENCH=1
matrix:
- LLVM_VERSION=3.3
- LLVM_VERSION=3.4
# We track this ourselves, and in theory we don't have to update the LLVM repo
# (but sadly we do right now anyway).
git:
submodules: false
notifications: notifications:
email: false email: false

View File

@ -28,7 +28,7 @@ CTAGS_LOCATIONS=$(patsubst ${CFG_SRC_DIR}src/llvm,, \
$(patsubst ${CFG_SRC_DIR}src/rt/sundown,, \ $(patsubst ${CFG_SRC_DIR}src/rt/sundown,, \
$(patsubst ${CFG_SRC_DIR}src/rt/vg,, \ $(patsubst ${CFG_SRC_DIR}src/rt/vg,, \
$(wildcard ${CFG_SRC_DIR}src/*) $(wildcard ${CFG_SRC_DIR}src/rt/*) \ $(wildcard ${CFG_SRC_DIR}src/*) $(wildcard ${CFG_SRC_DIR}src/rt/*) \
))))))))))) )))))))))
CTAGS_OPTS=--options="${CFG_SRC_DIR}src/etc/ctags.rust" --languages=-javascript --recurse ${CTAGS_LOCATIONS} CTAGS_OPTS=--options="${CFG_SRC_DIR}src/etc/ctags.rust" --languages=-javascript --recurse ${CTAGS_LOCATIONS}
# We could use `--languages=Rust`, but there is value in producing tags for the # We could use `--languages=Rust`, but there is value in producing tags for the
# C++ parts of the code base too (at the time of writing, those are .h and .cpp # C++ parts of the code base too (at the time of writing, those are .h and .cpp

View File

@ -35,7 +35,7 @@
# that's per-target so you're allowed to conditionally add files based on the # that's per-target so you're allowed to conditionally add files based on the
# target. # target.
################################################################################ ################################################################################
NATIVE_LIBS := rust_builtin hoedown uv_support morestack miniz context_switch \ NATIVE_LIBS := rust_builtin hoedown morestack miniz context_switch \
rustrt_native rust_test_helpers rustrt_native rust_test_helpers
# $(1) is the target triple # $(1) is the target triple
@ -50,7 +50,6 @@ NATIVE_DEPS_hoedown_$(1) := hoedown/src/autolink.c \
hoedown/src/html_smartypants.c \ hoedown/src/html_smartypants.c \
hoedown/src/stack.c \ hoedown/src/stack.c \
hoedown/src/version.c hoedown/src/version.c
NATIVE_DEPS_uv_support_$(1) := rust_uv.c
NATIVE_DEPS_miniz_$(1) = miniz.c NATIVE_DEPS_miniz_$(1) = miniz.c
NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \ NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
rust_android_dummy.c rust_android_dummy.c

View File

@ -305,10 +305,9 @@ copying.
# Circle(Point, f64), // origin, radius # Circle(Point, f64), // origin, radius
# Rectangle(Point, Size) // upper-left, dimensions # Rectangle(Point, Size) // upper-left, dimensions
# } # }
# static tau: f64 = 6.28;
fn compute_area(shape: &Shape) -> f64 { fn compute_area(shape: &Shape) -> f64 {
match *shape { match *shape {
Circle(_, radius) => 0.5 * tau * radius * radius, Circle(_, radius) => std::f64::consts::PI * radius * radius,
Rectangle(_, ref size) => size.w * size.h Rectangle(_, ref size) => size.w * size.h
} }
} }
@ -316,10 +315,7 @@ fn compute_area(shape: &Shape) -> f64 {
The first case matches against circles. Here, the pattern extracts the The first case matches against circles. Here, the pattern extracts the
radius from the shape variant and the action uses it to compute the radius from the shape variant and the action uses it to compute the
area of the circle. (Like any up-to-date engineer, we use the [tau area of the circle.
circle constant][tau] and not that dreadfully outdated notion of pi).
[tau]: http://www.math.utah.edu/~palais/pi.html
The second match is more interesting. Here we match against a The second match is more interesting. Here we match against a
rectangle and extract its size: but rather than copy the `size` rectangle and extract its size: but rather than copy the `size`

View File

@ -632,19 +632,6 @@ This part is coming soon.
This part is coming soon. This part is coming soon.
# Gc
The `Gc<T>` type exists for historical reasons, and is [still used
internally](https://github.com/rust-lang/rust/issues/7929) by the compiler.
It is not even a 'real' garbage collected type at the moment.
In the future, Rust may have a real garbage collected type, and so it
has not yet been removed for that reason.
## Best practices
There is currently no legitimate use case for the `Gc<T>` type.
# Raw Pointers # Raw Pointers
This part is coming soon. This part is coming soon.

View File

@ -31,7 +31,6 @@ list):
* Task synchronization * Task synchronization
* Task-local storage * Task-local storage
* Logging * Logging
* Local heaps (GC heaps)
* Task unwinding * Task unwinding
## What is the runtime accomplishing? ## What is the runtime accomplishing?

View File

@ -208,9 +208,7 @@ pub struct Unique<T> {
// Implement methods for creating and using the values in the box. // Implement methods for creating and using the values in the box.
// NB: For simplicity and correctness, we require that T has kind Send // NB: For simplicity and correctness, we require that T has kind Send
// (owned boxes relax this restriction, and can contain managed (GC) boxes). // (owned boxes relax this restriction).
// This is because, as implemented, the garbage collector would not know
// about any shared boxes stored in the malloc'd region of memory.
impl<T: Send> Unique<T> { impl<T: Send> Unique<T> {
pub fn new(value: T) -> Unique<T> { pub fn new(value: T) -> Unique<T> {
unsafe { unsafe {

View File

@ -195,9 +195,11 @@ The second point is the `println!()` part. This is calling a Rust **macro**,
which is how metaprogramming is done in Rust. If it were a function instead, it which is how metaprogramming is done in Rust. If it were a function instead, it
would look like this: `println()`. For our purposes, we don't need to worry would look like this: `println()`. For our purposes, we don't need to worry
about this difference. Just know that sometimes, you'll see a `!`, and that about this difference. Just know that sometimes, you'll see a `!`, and that
means that you're calling a macro instead of a normal function. One last thing means that you're calling a macro instead of a normal function. Rust implements
to mention: Rust's macros are significantly different than C macros, if you've `println!` as a macro rather than a function for good reasons, but that's a
used those. Don't be scared of using macros. We'll get to the details very advanced topic. You'll learn more when we talk about macros later. One
last thing to mention: Rust's macros are significantly different than C macros,
if you've used those. Don't be scared of using macros. We'll get to the details
eventually, you'll just have to trust us for now. eventually, you'll just have to trust us for now.
Next, `"Hello, world!"` is a **string**. Strings are a surprisingly complicated Next, `"Hello, world!"` is a **string**. Strings are a surprisingly complicated
@ -659,14 +661,12 @@ error: mismatched types: expected `int` but found `()` (expected int but found (
``` ```
We expected an integer, but we got `()`. `()` is pronounced 'unit', and is a We expected an integer, but we got `()`. `()` is pronounced 'unit', and is a
special type in Rust's type system. `()` is different than `null` in other special type in Rust's type system. In Rust, `()` is _not_ a valid value for a
languages, because `()` is distinct from other types. For example, in C, `null` variable of type `int`. It's only a valid value for variables of the type `()`,
is a valid value for a variable of type `int`. In Rust, `()` is _not_ a valid which aren't very useful. Remember how we said statements don't return a value?
value for a variable of type `int`. It's only a valid value for variables of Well, that's the purpose of unit in this case. The semicolon turns any
the type `()`, which aren't very useful. Remember how we said statements don't expression into a statement by throwing away its value and returning unit
return a value? Well, that's the purpose of unit in this case. The semicolon instead.
turns any expression into a statement by throwing away its value and returning
unit instead.
There's one more time in which you won't see a semicolon at the end of a line There's one more time in which you won't see a semicolon at the end of a line
of Rust code. For that, we'll need our next concept: functions. of Rust code. For that, we'll need our next concept: functions.
@ -1680,11 +1680,11 @@ just `int`s.
Rust provides a method on these `IoResult<T>`s called `ok()`, which does the Rust provides a method on these `IoResult<T>`s called `ok()`, which does the
same thing as our `match` statement, but assuming that we have a valid value. same thing as our `match` statement, but assuming that we have a valid value.
If we don't, it will terminate our program. In this case, if we can't get We then call `expect()` on the result, which will terminate our program if we
input, our program doesn't work, so we're okay with that. In most cases, we don't have a valid value. In this case, if we can't get input, our program
would want to handle the error case explicitly. The result of `ok()` has a doesn't work, so we're okay with that. In most cases, we would want to handle
method, `expect()`, which allows us to give an error message if this crash the error case explicitly. `expect()` allows us to give an error message if
happens. this crash happens.
We will cover the exact details of how all of this works later in the Guide. We will cover the exact details of how all of this works later in the Guide.
For now, this gives you enough of a basic understanding to work with. For now, this gives you enough of a basic understanding to work with.
@ -2030,7 +2030,7 @@ fn main() {
match cmp(input, secret_number) { match cmp(input, secret_number) {
Less => println!("Too small!"), Less => println!("Too small!"),
Greater => println!("Too big!"), Greater => println!("Too big!"),
Equal => { println!("You win!"); }, Equal => println!("You win!"),
} }
} }
@ -2727,7 +2727,8 @@ mod hello {
} }
``` ```
This will work: Usage of the `pub` keyword is sometimes called 'exporting', because
we're making the function available for other modules. This will work:
```{notrust,ignore} ```{notrust,ignore}
$ cargo run $ cargo run
@ -3291,8 +3292,7 @@ use super::times_four;
Because we've made a nested module, we can import functions from the parent Because we've made a nested module, we can import functions from the parent
module by using `super`. Sub-modules are allowed to 'see' private functions in module by using `super`. Sub-modules are allowed to 'see' private functions in
the parent. We sometimes call this usage of `use` a 're-export,' because we're the parent.
exporting the name again, somewhere else.
We've now covered the basics of testing. Rust's tools are primitive, but they We've now covered the basics of testing. Rust's tools are primitive, but they
work well in the simple cases. There are some Rustaceans working on building work well in the simple cases. There are some Rustaceans working on building

View File

@ -3381,7 +3381,7 @@ fn main() {
``` ```
Patterns can also dereference pointers by using the `&`, `box` or `@` symbols, Patterns can also dereference pointers by using the `&`, `box` symbols,
as appropriate. For example, these two matches on `x: &int` are equivalent: as appropriate. For example, these two matches on `x: &int` are equivalent:
``` ```

View File

@ -373,14 +373,6 @@
fun:_ZN4llvm4UsernwEjj fun:_ZN4llvm4UsernwEjj
} }
{
libuv-0-byte-realloc
Memcheck:Leak
fun:malloc
...
fun:*uv_loop_delete*
}
{ {
race-or-something-ask-pcwalton-0 race-or-something-ask-pcwalton-0
Memcheck:Value4 Memcheck:Value4
@ -502,15 +494,3 @@
fun:* fun:*
... ...
} }
{
libuv-mac-no-thread-join
Memcheck:Leak
fun:malloc_zone_malloc
fun:_CFRuntimeCreateInstance
fun:CFRunLoopSourceCreate
fun:uv__platform_loop_init
fun:uv__loop_init
fun:uv_loop_new
...
}

View File

@ -182,9 +182,15 @@ mod imp {
#[inline] #[inline]
pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint, pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint,
_old_size: uint) -> bool { old_size: uint) -> bool {
let flags = align_to_flags(align); let flags = align_to_flags(align);
je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) == size as size_t let new_size = je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) as uint;
// checking for failure to shrink is tricky
if size < old_size {
usable_size(size, align) == new_size as uint
} else {
new_size >= size
}
} }
#[inline] #[inline]
@ -250,9 +256,9 @@ mod imp {
} }
#[inline] #[inline]
pub unsafe fn reallocate_inplace(_ptr: *mut u8, _size: uint, _align: uint, pub unsafe fn reallocate_inplace(_ptr: *mut u8, size: uint, _align: uint,
_old_size: uint) -> bool { old_size: uint) -> bool {
false size == old_size
} }
#[inline] #[inline]
@ -312,9 +318,9 @@ mod imp {
} }
#[inline] #[inline]
pub unsafe fn reallocate_inplace(_ptr: *mut u8, _size: uint, _align: uint, pub unsafe fn reallocate_inplace(_ptr: *mut u8, size: uint, _align: uint,
_old_size: uint) -> bool { old_size: uint) -> bool {
false size == old_size
} }
#[inline] #[inline]
@ -335,9 +341,21 @@ mod imp {
} }
#[cfg(test)] #[cfg(test)]
mod bench { mod test {
extern crate test; extern crate test;
use self::test::Bencher; use self::test::Bencher;
use heap;
#[test]
fn basic_reallocate_inplace_noop() {
unsafe {
let size = 4000;
let ptr = heap::allocate(size, 8);
let ret = heap::reallocate_inplace(ptr, size, 8, size);
heap::deallocate(ptr, size, 8);
assert!(ret);
}
}
#[bench] #[bench]
fn alloc_owned_small(b: &mut Bencher) { fn alloc_owned_small(b: &mut Bencher) {

View File

@ -92,7 +92,6 @@ pub use boxed as owned;
pub mod heap; pub mod heap;
pub mod libc_heap; pub mod libc_heap;
pub mod util;
// Primitive types using the heaps above // Primitive types using the heaps above

View File

@ -541,14 +541,6 @@ mod tests {
assert!(y.upgrade().is_none()); assert!(y.upgrade().is_none());
} }
#[test]
fn gc_inside() {
// see issue #11532
use std::gc::GC;
let a = Rc::new(RefCell::new(box(GC) 1i));
assert!(a.try_borrow_mut().is_some());
}
#[test] #[test]
fn weak_self_cyclic() { fn weak_self_cyclic() {
struct Cycle { struct Cycle {

View File

@ -1,30 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![doc(hidden)]
use core::mem;
use core::raw;
#[inline]
#[deprecated]
pub fn get_box_size(body_size: uint, body_align: uint) -> uint {
let header_size = mem::size_of::<raw::GcBox<()>>();
let total_size = align_to(header_size, body_align) + body_size;
total_size
}
// Rounds size to the next alignment. Alignment is required to be a power of
// two.
#[inline]
fn align_to(size: uint, align: uint) -> uint {
assert!(align != 0);
(size + align - 1) & !(align - 1)
}

View File

@ -46,12 +46,12 @@ struct AbsEntries<T> {
} }
/// An iterator over a BTreeMap's entries. /// An iterator over a BTreeMap's entries.
pub struct Entries<'a, K, V> { pub struct Entries<'a, K: 'a, V: 'a> {
inner: AbsEntries<Traversal<'a, K, V>> inner: AbsEntries<Traversal<'a, K, V>>
} }
/// A mutable iterator over a BTreeMap's entries. /// A mutable iterator over a BTreeMap's entries.
pub struct MutEntries<'a, K, V> { pub struct MutEntries<'a, K: 'a, V: 'a> {
inner: AbsEntries<MutTraversal<'a, K, V>> inner: AbsEntries<MutTraversal<'a, K, V>>
} }

View File

@ -19,7 +19,7 @@
html_root_url = "http://doc.rust-lang.org/master/", html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")] html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, managed_boxes, default_type_params, phase, globs)] #![feature(macro_rules, default_type_params, phase, globs)]
#![feature(unsafe_destructor, import_shadowing)] #![feature(unsafe_destructor, import_shadowing)]
#![no_std] #![no_std]

View File

@ -532,7 +532,6 @@ impl<T: fmt::Show> fmt::Show for RingBuf<T> {
mod tests { mod tests {
use std::fmt::Show; use std::fmt::Show;
use std::prelude::*; use std::prelude::*;
use std::gc::{GC, Gc};
use std::hash; use std::hash;
use test::Bencher; use test::Bencher;
use test; use test;
@ -587,43 +586,6 @@ mod tests {
assert_eq!(*d.get(3), 4); assert_eq!(*d.get(3), 4);
} }
#[test]
#[allow(deprecated)]
fn test_boxes() {
let a: Gc<int> = box(GC) 5;
let b: Gc<int> = box(GC) 72;
let c: Gc<int> = box(GC) 64;
let d: Gc<int> = box(GC) 175;
let mut deq = RingBuf::new();
assert_eq!(deq.len(), 0);
deq.push_front(a);
deq.push_front(b);
deq.push(c);
assert_eq!(deq.len(), 3);
deq.push(d);
assert_eq!(deq.len(), 4);
assert_eq!(deq.front(), Some(&b));
assert_eq!(deq.back(), Some(&d));
assert_eq!(deq.pop_front(), Some(b));
assert_eq!(deq.pop(), Some(d));
assert_eq!(deq.pop(), Some(c));
assert_eq!(deq.pop(), Some(a));
assert_eq!(deq.len(), 0);
deq.push(c);
assert_eq!(deq.len(), 1);
deq.push_front(b);
assert_eq!(deq.len(), 2);
deq.push(d);
assert_eq!(deq.len(), 3);
deq.push_front(a);
assert_eq!(deq.len(), 4);
assert_eq!(*deq.get(0), a);
assert_eq!(*deq.get(1), b);
assert_eq!(*deq.get(2), c);
assert_eq!(*deq.get(3), d);
}
#[cfg(test)] #[cfg(test)]
fn test_parameterized<T:Clone + PartialEq + Show>(a: T, b: T, c: T, d: T) { fn test_parameterized<T:Clone + PartialEq + Show>(a: T, b: T, c: T, d: T) {
let mut deq = RingBuf::new(); let mut deq = RingBuf::new();
@ -755,12 +717,6 @@ mod tests {
test_parameterized::<int>(5, 72, 64, 175); test_parameterized::<int>(5, 72, 64, 175);
} }
#[test]
fn test_param_at_int() {
test_parameterized::<Gc<int>>(box(GC) 5, box(GC) 72,
box(GC) 64, box(GC) 175);
}
#[test] #[test]
fn test_param_taggy() { fn test_param_taggy() {
test_parameterized::<Taggy>(One(1), Two(1, 2), Three(1, 2, 3), Two(17, 42)); test_parameterized::<Taggy>(One(1), Two(1, 2), Three(1, 2, 3), Two(17, 42));

View File

@ -791,11 +791,16 @@ impl<T> Vec<T> {
#[inline] #[inline]
pub fn into_iter(self) -> MoveItems<T> { pub fn into_iter(self) -> MoveItems<T> {
unsafe { unsafe {
let iter = mem::transmute(self.as_slice().iter());
let ptr = self.ptr; let ptr = self.ptr;
let cap = self.cap; let cap = self.cap;
let begin = self.ptr as *const T;
let end = if mem::size_of::<T>() == 0 {
(ptr as uint + self.len()) as *const T
} else {
ptr.offset(self.len() as int) as *const T
};
mem::forget(self); mem::forget(self);
MoveItems { allocation: ptr, cap: cap, iter: iter } MoveItems { allocation: ptr, cap: cap, ptr: begin, end: end }
} }
} }
@ -1719,7 +1724,8 @@ impl<T> MutableSeq<T> for Vec<T> {
pub struct MoveItems<T> { pub struct MoveItems<T> {
allocation: *mut T, // the block of memory allocated for the vector allocation: *mut T, // the block of memory allocated for the vector
cap: uint, // the capacity of the vector cap: uint, // the capacity of the vector
iter: Items<'static, T> ptr: *const T,
end: *const T
} }
impl<T> MoveItems<T> { impl<T> MoveItems<T> {
@ -1728,7 +1734,7 @@ impl<T> MoveItems<T> {
pub fn unwrap(mut self) -> Vec<T> { pub fn unwrap(mut self) -> Vec<T> {
unsafe { unsafe {
for _x in self { } for _x in self { }
let MoveItems { allocation, cap, iter: _iter } = self; let MoveItems { allocation, cap, ptr: _ptr, end: _end } = self;
mem::forget(self); mem::forget(self);
Vec { ptr: allocation, cap: cap, len: 0 } Vec { ptr: allocation, cap: cap, len: 0 }
} }
@ -1739,17 +1745,33 @@ impl<T> Iterator<T> for MoveItems<T> {
#[inline] #[inline]
fn next<'a>(&'a mut self) -> Option<T> { fn next<'a>(&'a mut self) -> Option<T> {
unsafe { unsafe {
// Unsafely transmute from Items<'static, T> to Items<'a, if self.ptr == self.end {
// T> because otherwise the type checker requires that T None
// be bounded by 'static. } else {
let iter: &mut Items<'a, T> = mem::transmute(&mut self.iter); if mem::size_of::<T>() == 0 {
iter.next().map(|x| ptr::read(x)) // purposefully don't use 'ptr.offset' because for
// vectors with 0-size elements this would return the
// same pointer.
self.ptr = mem::transmute(self.ptr as uint + 1);
// Use a non-null pointer value
Some(ptr::read(mem::transmute(1u)))
} else {
let old = self.ptr;
self.ptr = self.ptr.offset(1);
Some(ptr::read(old))
}
}
} }
} }
#[inline] #[inline]
fn size_hint(&self) -> (uint, Option<uint>) { fn size_hint(&self) -> (uint, Option<uint>) {
self.iter.size_hint() let diff = (self.end as uint) - (self.ptr as uint);
let size = mem::size_of::<T>();
let exact = diff / (if size == 0 {1} else {size});
(exact, Some(exact))
} }
} }
@ -1757,11 +1779,21 @@ impl<T> DoubleEndedIterator<T> for MoveItems<T> {
#[inline] #[inline]
fn next_back<'a>(&'a mut self) -> Option<T> { fn next_back<'a>(&'a mut self) -> Option<T> {
unsafe { unsafe {
// Unsafely transmute from Items<'static, T> to Items<'a, if self.end == self.ptr {
// T> because otherwise the type checker requires that T None
// be bounded by 'static. } else {
let iter: &mut Items<'a, T> = mem::transmute(&mut self.iter); if mem::size_of::<T>() == 0 {
iter.next_back().map(|x| ptr::read(x)) // See above for why 'ptr.offset' isn't used
self.end = mem::transmute(self.end as uint - 1);
// Use a non-null pointer value
Some(ptr::read(mem::transmute(1u)))
} else {
self.end = self.end.offset(-1);
Some(ptr::read(mem::transmute(self.end)))
}
}
} }
} }
} }
@ -2473,6 +2505,36 @@ mod tests {
assert_eq!(v.map_in_place(|_| ZeroSized).as_slice(), [ZeroSized, ZeroSized].as_slice()); assert_eq!(v.map_in_place(|_| ZeroSized).as_slice(), [ZeroSized, ZeroSized].as_slice());
} }
#[test]
fn test_move_items() {
let mut vec = vec!(1i, 2, 3);
let mut vec2 : Vec<int> = vec!();
for i in vec.into_iter() {
vec2.push(i);
}
assert!(vec2 == vec!(1i, 2, 3));
}
#[test]
fn test_move_items_reverse() {
let mut vec = vec!(1i, 2, 3);
let mut vec2 : Vec<int> = vec!();
for i in vec.into_iter().rev() {
vec2.push(i);
}
assert!(vec2 == vec!(3i, 2, 1));
}
#[test]
fn test_move_items_zero_sized() {
let mut vec = vec!((), (), ());
let mut vec2 : Vec<()> = vec!();
for i in vec.into_iter() {
vec2.push(i);
}
assert!(vec2 == vec!((), (), ()));
}
#[bench] #[bench]
fn bench_new(b: &mut Bencher) { fn bench_new(b: &mut Bencher) {
b.iter(|| { b.iter(|| {

View File

@ -57,7 +57,7 @@
html_playground_url = "http://play.rust-lang.org/")] html_playground_url = "http://play.rust-lang.org/")]
#![no_std] #![no_std]
#![feature(globs, intrinsics, lang_items, macro_rules, managed_boxes, phase)] #![feature(globs, intrinsics, lang_items, macro_rules, phase)]
#![feature(simd, unsafe_destructor)] #![feature(simd, unsafe_destructor)]
#![deny(missing_doc)] #![deny(missing_doc)]

View File

@ -20,15 +20,6 @@
use mem; use mem;
/// The representation of `std::gc::Gc`.
pub struct GcBox<T> {
pub ref_count: uint,
pub drop_glue: fn(ptr: *mut u8),
pub prev: *mut GcBox<T>,
pub next: *mut GcBox<T>,
pub data: T,
}
/// The representation of a Rust slice /// The representation of a Rust slice
pub struct Slice<T> { pub struct Slice<T> {
pub data: *const T, pub data: *const T,

View File

@ -1218,7 +1218,7 @@ macro_rules! iterator {
/// Immutable slice iterator /// Immutable slice iterator
#[experimental = "needs review"] #[experimental = "needs review"]
pub struct Items<'a, T> { pub struct Items<'a, T: 'a> {
ptr: *const T, ptr: *const T,
end: *const T, end: *const T,
marker: marker::ContravariantLifetime<'a> marker: marker::ContravariantLifetime<'a>
@ -1261,7 +1261,7 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> {
/// Mutable slice iterator. /// Mutable slice iterator.
#[experimental = "needs review"] #[experimental = "needs review"]
pub struct MutItems<'a, T> { pub struct MutItems<'a, T: 'a> {
ptr: *mut T, ptr: *mut T,
end: *mut T, end: *mut T,
marker: marker::ContravariantLifetime<'a>, marker: marker::ContravariantLifetime<'a>,

View File

@ -528,9 +528,8 @@ fn test_rposition() {
#[test] #[test]
#[should_fail] #[should_fail]
fn test_rposition_fail() { fn test_rposition_fail() {
use std::gc::GC; let v = [(box 0i, box 0i), (box 0i, box 0i),
let v = [(box 0i, box(GC) 0i), (box 0i, box(GC) 0i), (box 0i, box 0i), (box 0i, box 0i)];
(box 0i, box(GC) 0i), (box 0i, box(GC) 0i)];
let mut i = 0i; let mut i = 0i;
v.iter().rposition(|_elt| { v.iter().rposition(|_elt| {
if i == 2 { if i == 2 {

View File

@ -25,7 +25,7 @@
html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/master/")] html_root_url = "http://doc.rust-lang.org/master/")]
#![experimental] #![experimental]
#![feature(managed_boxes, macro_rules)] #![feature(macro_rules)]
#![allow(experimental)] #![allow(experimental)]
pub mod fmt; pub mod fmt;

View File

@ -18,7 +18,6 @@ Runtime type reflection
use std::intrinsics::{Disr, Opaque, TyDesc, TyVisitor}; use std::intrinsics::{Disr, Opaque, TyDesc, TyVisitor};
use std::mem; use std::mem;
use std::gc::Gc;
/** /**
* Trait for visitor that wishes to reflect on data. * Trait for visitor that wishes to reflect on data.
@ -194,9 +193,9 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
} }
fn visit_box(&mut self, mtbl: uint, inner: *const TyDesc) -> bool { fn visit_box(&mut self, mtbl: uint, inner: *const TyDesc) -> bool {
self.align_to::<Gc<u8>>(); self.align_to::<Box<u8>>();
if ! self.inner.visit_box(mtbl, inner) { return false; } if ! self.inner.visit_box(mtbl, inner) { return false; }
self.bump_past::<Gc<u8>>(); self.bump_past::<Box<u8>>();
true true
} }

View File

@ -274,13 +274,9 @@ impl<'a> TyVisitor for ReprVisitor<'a> {
self.get::<&str>(|this, s| this.write_escaped_slice(*s)) self.get::<&str>(|this, s| this.write_escaped_slice(*s))
} }
fn visit_box(&mut self, mtbl: uint, inner: *const TyDesc) -> bool { fn visit_box(&mut self, _mtbl: uint, _inner: *const TyDesc) -> bool {
try!(self, self.writer.write("box(GC) ".as_bytes())); try!(self, self.writer.write("box(GC) ???".as_bytes()));
self.write_mut_qualifier(mtbl); true
self.get::<&raw::GcBox<()>>(|this, b| {
let p = &b.data as *const () as *const u8;
this.visit_ptr_inner(p, inner)
})
} }
fn visit_uniq(&mut self, _mtbl: uint, inner: *const TyDesc) -> bool { fn visit_uniq(&mut self, _mtbl: uint, inner: *const TyDesc) -> bool {
@ -576,7 +572,6 @@ fn test_repr() {
use std::io::stdio::println; use std::io::stdio::println;
use std::char::is_alphabetic; use std::char::is_alphabetic;
use std::mem::swap; use std::mem::swap;
use std::gc::GC;
fn exact_test<T>(t: &T, e:&str) { fn exact_test<T>(t: &T, e:&str) {
let mut m = io::MemWriter::new(); let mut m = io::MemWriter::new();
@ -591,7 +586,6 @@ fn test_repr() {
exact_test(&1.234f64, "1.234f64"); exact_test(&1.234f64, "1.234f64");
exact_test(&("hello"), "\"hello\""); exact_test(&("hello"), "\"hello\"");
exact_test(&(box(GC) 10i), "box(GC) 10");
exact_test(&(box 10i), "box 10"); exact_test(&(box 10i), "box 10");
exact_test(&(&10i), "&10"); exact_test(&(&10i), "&10");
let mut x = 10i; let mut x = 10i;
@ -605,8 +599,6 @@ fn test_repr() {
"&[\"hi\", \"there\"]"); "&[\"hi\", \"there\"]");
exact_test(&(P{a:10, b:1.234}), exact_test(&(P{a:10, b:1.234}),
"repr::P{a: 10, b: 1.234f64}"); "repr::P{a: 10, b: 1.234f64}");
exact_test(&(box(GC) P{a:10, b:1.234}),
"box(GC) repr::P{a: 10, b: 1.234f64}");
exact_test(&(box P{a:10, b:1.234}), exact_test(&(box P{a:10, b:1.234}),
"box repr::P{a: 10, b: 1.234f64}"); "box repr::P{a: 10, b: 1.234f64}");

View File

@ -50,7 +50,7 @@ fn main() {
html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/master/")] html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(plugin_registrar, managed_boxes)] #![feature(plugin_registrar)]
extern crate syntax; extern crate syntax;
extern crate rustc; extern crate rustc;

View File

@ -73,13 +73,13 @@ impl BasicLoop {
RunRemote(i) => { RunRemote(i) => {
match self.remotes.iter_mut().find(|& &(id, _)| id == i) { match self.remotes.iter_mut().find(|& &(id, _)| id == i) {
Some(&(_, ref mut f)) => f.call(), Some(&(_, ref mut f)) => f.call(),
None => unreachable!() None => fail!("bad remote: {}", i),
} }
} }
RemoveRemote(i) => { RemoveRemote(i) => {
match self.remotes.iter().position(|&(id, _)| id == i) { match self.remotes.iter().position(|&(id, _)| id == i) {
Some(i) => { self.remotes.remove(i).unwrap(); } Some(i) => { self.remotes.remove(i).unwrap(); }
None => unreachable!() None => fail!("bad remote: {}", i),
} }
} }
} }

View File

@ -46,7 +46,7 @@ fn main() {
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", #![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/master/")] html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(plugin_registrar, managed_boxes)] #![feature(plugin_registrar)]
extern crate syntax; extern crate syntax;
extern crate rustc; extern crate rustc;

View File

@ -583,10 +583,11 @@ fn spawn_process_os(cfg: ProcessConfig,
let mut bytes = [0, ..4]; let mut bytes = [0, ..4];
return match input.inner_read(bytes) { return match input.inner_read(bytes) {
Ok(4) => { Ok(4) => {
let errno = (bytes[0] << 24) as i32 | let errno = (bytes[0] as i32 << 24) |
(bytes[1] << 16) as i32 | (bytes[1] as i32 << 16) |
(bytes[2] << 8) as i32 | (bytes[2] as i32 << 8) |
(bytes[3] << 0) as i32; (bytes[3] as i32 << 0);
Err(IoError { Err(IoError {
code: errno as uint, code: errno as uint,
detail: None, detail: None,
@ -637,10 +638,10 @@ fn spawn_process_os(cfg: ProcessConfig,
fn fail(output: &mut file::FileDesc) -> ! { fn fail(output: &mut file::FileDesc) -> ! {
let errno = os::errno(); let errno = os::errno();
let bytes = [ let bytes = [
(errno << 24) as u8, (errno >> 24) as u8,
(errno << 16) as u8, (errno >> 16) as u8,
(errno << 8) as u8, (errno >> 8) as u8,
(errno << 0) as u8, (errno >> 0) as u8,
]; ];
assert!(output.inner_write(bytes).is_ok()); assert!(output.inner_write(bytes).is_ok());
unsafe { libc::_exit(1) } unsafe { libc::_exit(1) }

View File

@ -19,7 +19,7 @@
html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/master/")] html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(plugin_registrar, managed_boxes, quote)] #![feature(plugin_registrar, quote)]
extern crate regex; extern crate regex;
extern crate syntax; extern crate syntax;

View File

@ -125,6 +125,21 @@ fn run_compiler(args: &[String]) {
driver::compile_input(sess, cfg, &input, &odir, &ofile, None); driver::compile_input(sess, cfg, &input, &odir, &ofile, None);
} }
/// Returns a version string such as "0.12.0-dev".
pub fn release_str() -> Option<&'static str> {
option_env!("CFG_RELEASE")
}
/// Returns the full SHA1 hash of HEAD of the Git repo from which rustc was built.
pub fn commit_hash_str() -> Option<&'static str> {
option_env!("CFG_VER_HASH")
}
/// Returns the "commit date" of HEAD of the Git repo from which rustc was built as a static string.
pub fn commit_date_str() -> Option<&'static str> {
option_env!("CFG_VER_DATE")
}
/// Prints version information and returns None on success or an error /// Prints version information and returns None on success or an error
/// message on failure. /// message on failure.
pub fn version(binary: &str, matches: &getopts::Matches) -> Option<String> { pub fn version(binary: &str, matches: &getopts::Matches) -> Option<String> {
@ -134,13 +149,14 @@ pub fn version(binary: &str, matches: &getopts::Matches) -> Option<String> {
Some(s) => return Some(format!("Unrecognized argument: {}", s)) Some(s) => return Some(format!("Unrecognized argument: {}", s))
}; };
println!("{} {}", binary, env!("CFG_VERSION")); println!("{} {}", binary, option_env!("CFG_VERSION").unwrap_or("unknown version"));
if verbose { if verbose {
fn unw(x: Option<&str>) -> &str { x.unwrap_or("unknown") }
println!("binary: {}", binary); println!("binary: {}", binary);
println!("commit-hash: {}", option_env!("CFG_VER_HASH").unwrap_or("unknown")); println!("commit-hash: {}", unw(commit_hash_str()));
println!("commit-date: {}", option_env!("CFG_VER_DATE").unwrap_or("unknown")); println!("commit-date: {}", unw(commit_date_str()));
println!("host: {}", driver::host_triple()); println!("host: {}", driver::host_triple());
println!("release: {}", env!("CFG_RELEASE")); println!("release: {}", unw(release_str()));
} }
None None
} }

View File

@ -412,26 +412,16 @@ impl LintPass for CTypes {
} }
} }
declare_lint!(MANAGED_HEAP_MEMORY, Allow,
"use of managed (@ type) heap memory")
declare_lint!(OWNED_HEAP_MEMORY, Allow, declare_lint!(OWNED_HEAP_MEMORY, Allow,
"use of owned (Box type) heap memory") "use of owned (Box type) heap memory")
declare_lint!(HEAP_MEMORY, Allow,
"use of any (Box type or @ type) heap memory")
pub struct HeapMemory; pub struct HeapMemory;
impl HeapMemory { impl HeapMemory {
fn check_heap_type(&self, cx: &Context, span: Span, ty: ty::t) { fn check_heap_type(&self, cx: &Context, span: Span, ty: ty::t) {
let mut n_box = 0i;
let mut n_uniq = 0i; let mut n_uniq = 0i;
ty::fold_ty(cx.tcx, ty, |t| { ty::fold_ty(cx.tcx, ty, |t| {
match ty::get(t).sty { match ty::get(t).sty {
ty::ty_box(_) => {
n_box += 1;
}
ty::ty_uniq(_) | ty::ty_uniq(_) |
ty::ty_closure(box ty::ClosureTy { ty::ty_closure(box ty::ClosureTy {
store: ty::UniqTraitStore, store: ty::UniqTraitStore,
@ -449,21 +439,13 @@ impl HeapMemory {
let s = ty_to_string(cx.tcx, ty); let s = ty_to_string(cx.tcx, ty);
let m = format!("type uses owned (Box type) pointers: {}", s); let m = format!("type uses owned (Box type) pointers: {}", s);
cx.span_lint(OWNED_HEAP_MEMORY, span, m.as_slice()); cx.span_lint(OWNED_HEAP_MEMORY, span, m.as_slice());
cx.span_lint(HEAP_MEMORY, span, m.as_slice());
}
if n_box > 0 {
let s = ty_to_string(cx.tcx, ty);
let m = format!("type uses managed (@ type) pointers: {}", s);
cx.span_lint(MANAGED_HEAP_MEMORY, span, m.as_slice());
cx.span_lint(HEAP_MEMORY, span, m.as_slice());
} }
} }
} }
impl LintPass for HeapMemory { impl LintPass for HeapMemory {
fn get_lints(&self) -> LintArray { fn get_lints(&self) -> LintArray {
lint_array!(MANAGED_HEAP_MEMORY, OWNED_HEAP_MEMORY, HEAP_MEMORY) lint_array!(OWNED_HEAP_MEMORY)
} }
fn check_item(&mut self, cx: &Context, it: &ast::Item) { fn check_item(&mut self, cx: &Context, it: &ast::Item) {
@ -1289,7 +1271,7 @@ impl LintPass for UnnecessaryAllocation {
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) { fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
match e.node { match e.node {
ast::ExprUnary(ast::UnUniq, _) | ast::ExprUnary(ast::UnBox, _) => (), ast::ExprUnary(ast::UnUniq, _) => (),
_ => return _ => return
} }

View File

@ -397,7 +397,6 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
assert_eq!(next(st), '|'); assert_eq!(next(st), '|');
return ty::mk_param(st.tcx, space, index, did); return ty::mk_param(st.tcx, space, index, did);
} }
'@' => return ty::mk_box(st.tcx, parse_ty(st, |x,y| conv(x,y))),
'~' => return ty::mk_uniq(st.tcx, parse_ty(st, |x,y| conv(x,y))), '~' => return ty::mk_uniq(st.tcx, parse_ty(st, |x,y| conv(x,y))),
'*' => return ty::mk_ptr(st.tcx, parse_mt(st, |x,y| conv(x,y))), '*' => return ty::mk_ptr(st.tcx, parse_mt(st, |x,y| conv(x,y))),
'&' => { '&' => {

View File

@ -244,7 +244,6 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) {
for t in ts.iter() { enc_ty(w, cx, *t); } for t in ts.iter() { enc_ty(w, cx, *t); }
mywrite!(w, "]"); mywrite!(w, "]");
} }
ty::ty_box(typ) => { mywrite!(w, "@"); enc_ty(w, cx, typ); }
ty::ty_uniq(typ) => { mywrite!(w, "~"); enc_ty(w, cx, typ); } ty::ty_uniq(typ) => { mywrite!(w, "~"); enc_ty(w, cx, typ); }
ty::ty_ptr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); } ty::ty_ptr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); }
ty::ty_rptr(r, mt) => { ty::ty_rptr(r, mt) => {

View File

@ -815,11 +815,6 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
return; return;
} }
mc::cat_deref(_, _, mc::GcPtr) => {
assert_eq!(cmt.mutbl, mc::McImmutable);
return;
}
mc::cat_rvalue(..) | mc::cat_rvalue(..) |
mc::cat_static_item | mc::cat_static_item |
mc::cat_deref(_, _, mc::UnsafePtr(..)) | mc::cat_deref(_, _, mc::UnsafePtr(..)) |

View File

@ -74,7 +74,7 @@ to an `LV` of `(*a).f`.
Here is the formal grammar for the types we'll consider: Here is the formal grammar for the types we'll consider:
```text ```text
TY = () | S<'LT...> | Box<TY> | & 'LT MQ TY | @ MQ TY TY = () | S<'LT...> | Box<TY> | & 'LT MQ TY
MQ = mut | imm | const MQ = mut | imm | const
``` ```
@ -263,9 +263,7 @@ compatible with the aliasability of `LV`. The goal is to prevent
`&mut` borrows of aliasability data. `&mut` borrows of aliasability data.
3. `LIFETIME(LV, LT, MQ)`: The lifetime of the borrow does not exceed 3. `LIFETIME(LV, LT, MQ)`: The lifetime of the borrow does not exceed
the lifetime of the value being borrowed. This pass is also the lifetime of the value being borrowed.
responsible for inserting root annotations to keep managed values
alive.
4. `RESTRICTIONS(LV, LT, ACTIONS) = RS`: This pass checks and computes the 4. `RESTRICTIONS(LV, LT, ACTIONS) = RS`: This pass checks and computes the
restrictions to maintain memory safety. These are the restrictions restrictions to maintain memory safety. These are the restrictions
@ -316,17 +314,13 @@ MUTABILITY(*LV, MQ) // M-Deref-Unique
### Checking mutability of immutable pointer types ### Checking mutability of immutable pointer types
Immutable pointer types like `&T` and `@T` can only Immutable pointer types like `&T` can only
be borrowed if MQ is immutable or const: be borrowed if MQ is immutable or const:
```text ```text
MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Imm MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Imm
TYPE(LV) = &Ty TYPE(LV) = &Ty
MQ == imm | const MQ == imm | const
MUTABILITY(*LV, MQ) // M-Deref-Managed-Imm
TYPE(LV) = @Ty
MQ == imm | const
``` ```
### Checking mutability of mutable pointer types ### Checking mutability of mutable pointer types
@ -390,11 +384,10 @@ ALIASABLE(*LV, MQ) // M-Deref-Borrowed-Mut
## Checking lifetime ## Checking lifetime
These rules aim to ensure that no data is borrowed for a scope that exceeds These rules aim to ensure that no data is borrowed for a scope that exceeds
its lifetime. In addition, these rules manage the rooting of `@` values. its lifetime. These two computations wind up being intimately related.
These two computations wind up being intimately related. Formally, we define Formally, we define a predicate `LIFETIME(LV, LT, MQ)`, which states that
a predicate `LIFETIME(LV, LT, MQ)`, which states that "the lvalue `LV` can be "the lvalue `LV` can be safely borrowed for the lifetime `LT` with mutability
safely borrowed for the lifetime `LT` with mutability `MQ`". The Rust `MQ`". The Rust code corresponding to this predicate is the module
code corresponding to this predicate is the module
`middle::borrowck::gather_loans::lifetime`. `middle::borrowck::gather_loans::lifetime`.
### The Scope function ### The Scope function
@ -423,14 +416,6 @@ the pointer itself `LV` goes out of scope:
SCOPE(*LV) = SCOPE(LV) if LV has type Box<T> SCOPE(*LV) = SCOPE(LV) if LV has type Box<T>
``` ```
The scope of a managed referent is also the scope of the pointer. This
is a conservative approximation, since there may be other aliases for
that same managed box that would cause it to live longer:
```text
SCOPE(*LV) = SCOPE(LV) if LV has type @T
```
The scope of a borrowed referent is the scope associated with the The scope of a borrowed referent is the scope associated with the
pointer. This is a conservative approximation, since the data that pointer. This is a conservative approximation, since the data that
the pointer points at may actually live longer: the pointer points at may actually live longer:
@ -477,59 +462,6 @@ LIFETIME(*LV, LT, MQ) // L-Deref-Borrowed
LT <= LT' LT <= LT'
``` ```
### Checking lifetime for derefs of managed, immutable pointers
Managed pointers are valid so long as the data within them is
*rooted*. There are two ways that this can be achieved. The first is
when the user guarantees such a root will exist. For this to be true,
three conditions must be met:
```text
LIFETIME(*LV, LT, MQ) // L-Deref-Managed-Imm-User-Root
TYPE(LV) = @Ty
LT <= SCOPE(LV) // (1)
LV is immutable // (2)
LV is not moved or not movable // (3)
```
Condition (1) guarantees that the managed box will be rooted for at
least the lifetime `LT` of the borrow, presuming that no mutation or
moves occur. Conditions (2) and (3) then serve to guarantee that the
value is not mutated or moved. Note that lvalues are either
(ultimately) owned by a local variable, in which case we can check
whether that local variable is ever moved in its scope, or they are
owned by the referent of an (immutable, due to condition 2) managed or
references, in which case moves are not permitted because the
location is aliasable.
If the conditions of `L-Deref-Managed-Imm-User-Root` are not met, then
there is a second alternative. The compiler can attempt to root the
managed pointer itself. This permits great flexibility, because the
location `LV` where the managed pointer is found does not matter, but
there are some limitations. The lifetime of the borrow can only extend
to the innermost enclosing loop or function body. This guarantees that
the compiler never requires an unbounded amount of stack space to
perform the rooting; if this condition were violated, the compiler
might have to accumulate a list of rooted objects, for example if the
borrow occurred inside the body of a loop but the scope of the borrow
extended outside the loop. More formally, the requirement is that
there is no path starting from the borrow that leads back to the
borrow without crossing the exit from the scope `LT`.
The rule for compiler rooting is as follows:
```text
LIFETIME(*LV, LT, MQ) // L-Deref-Managed-Imm-Compiler-Root
TYPE(LV) = @Ty
LT <= innermost enclosing loop/func
ROOT LV at *LV for LT
```
Here I have written `ROOT LV at *LV FOR LT` to indicate that the code
makes a note in a side-table that the box `LV` must be rooted into the
stack when `*LV` is evaluated, and that this root can be released when
the scope `LT` exits.
## Computing the restrictions ## Computing the restrictions
The final rules govern the computation of *restrictions*, meaning that The final rules govern the computation of *restrictions*, meaning that
@ -599,22 +531,18 @@ RESTRICTIONS(*LV, LT, ACTIONS) = RS, (*LV, ACTIONS) // R-Deref-Send-Pointer
RESTRICTIONS(LV, LT, ACTIONS|MUTATE|CLAIM) = RS RESTRICTIONS(LV, LT, ACTIONS|MUTATE|CLAIM) = RS
``` ```
### Restrictions for loans of immutable managed/borrowed referents ### Restrictions for loans of immutable borrowed referents
Immutable managed/borrowed referents are freely aliasable, meaning that Immutable borrowed referents are freely aliasable, meaning that
the compiler does not prevent you from copying the pointer. This the compiler does not prevent you from copying the pointer. This
implies that issuing restrictions is useless. We might prevent the implies that issuing restrictions is useless. We might prevent the
user from acting on `*LV` itself, but there could be another path user from acting on `*LV` itself, but there could be another path
`*LV1` that refers to the exact same memory, and we would not be `*LV1` that refers to the exact same memory, and we would not be
restricting that path. Therefore, the rule for `&Ty` and `@Ty` restricting that path. Therefore, the rule for `&Ty` pointers
pointers always returns an empty set of restrictions, and it only always returns an empty set of restrictions, and it only permits
permits restricting `MUTATE` and `CLAIM` actions: restricting `MUTATE` and `CLAIM` actions:
```text ```text
RESTRICTIONS(*LV, LT, ACTIONS) = [] // R-Deref-Imm-Managed
TYPE(LV) = @Ty
ACTIONS subset of [MUTATE, CLAIM]
RESTRICTIONS(*LV, LT, ACTIONS) = [] // R-Deref-Imm-Borrowed RESTRICTIONS(*LV, LT, ACTIONS) = [] // R-Deref-Imm-Borrowed
TYPE(LV) = &LT' Ty TYPE(LV) = &LT' Ty
LT <= LT' // (1) LT <= LT' // (1)
@ -623,8 +551,8 @@ RESTRICTIONS(*LV, LT, ACTIONS) = [] // R-Deref-Imm-Borrowed
The reason that we can restrict `MUTATE` and `CLAIM` actions even The reason that we can restrict `MUTATE` and `CLAIM` actions even
without a restrictions list is that it is never legal to mutate nor to without a restrictions list is that it is never legal to mutate nor to
borrow mutably the contents of a `&Ty` or `@Ty` pointer. In other borrow mutably the contents of a `&Ty` pointer. In other words,
words, those restrictions are already inherent in the type. those restrictions are already inherent in the type.
Clause (1) in the rule for `&Ty` deserves mention. Here I Clause (1) in the rule for `&Ty` deserves mention. Here I
specify that the lifetime of the loan must be less than the lifetime specify that the lifetime of the loan must be less than the lifetime
@ -729,13 +657,12 @@ are affine.)
Freeze pointers are read-only. There may be `&mut` or `&` aliases, and Freeze pointers are read-only. There may be `&mut` or `&` aliases, and
we can not prevent *anything* but moves in that case. So the we can not prevent *anything* but moves in that case. So the
`RESTRICTIONS` function is only defined if `ACTIONS` is the empty set. `RESTRICTIONS` function is only defined if `ACTIONS` is the empty set.
Because moves from a `&const` or `@const` lvalue are never legal, it Because moves from a `&const` lvalue are never legal, it is not
is not necessary to add any restrictions at all to the final necessary to add any restrictions at all to the final result.
result.
```text ```text
RESTRICTIONS(*LV, LT, []) = [] // R-Deref-Freeze-Borrowed RESTRICTIONS(*LV, LT, []) = [] // R-Deref-Freeze-Borrowed
TYPE(LV) = &const Ty or @const Ty TYPE(LV) = &const Ty
``` ```
### Restrictions for loans of mutable borrowed referents ### Restrictions for loans of mutable borrowed referents
@ -957,8 +884,7 @@ moves and the declaration of uninitialized variables. For each of
these points, we create a bit in the dataflow set. Assignments to a these points, we create a bit in the dataflow set. Assignments to a
variable `x` or path `a.b.c` kill the move/uninitialization bits for variable `x` or path `a.b.c` kill the move/uninitialization bits for
those paths and any subpaths (e.g., `x`, `x.y`, `a.b.c`, `*a.b.c`). those paths and any subpaths (e.g., `x`, `x.y`, `a.b.c`, `*a.b.c`).
The bits are also killed when the root variables (`x`, `a`) go out of Bits are unioned when two control-flow paths join. Thus, the
scope. Bits are unioned when two control-flow paths join. Thus, the
presence of a bit indicates that the move may have occurred without an presence of a bit indicates that the move may have occurred without an
intervening assignment to the same memory. At each use of a variable, intervening assignment to the same memory. At each use of a variable,
we examine the bits in scope, and check that none of them are we examine the bits in scope, and check that none of them are

View File

@ -132,7 +132,6 @@ fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt,
match cmt.cat { match cmt.cat {
mc::cat_deref(_, _, mc::BorrowedPtr(..)) | mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) | mc::cat_deref(_, _, mc::Implicit(..)) |
mc::cat_deref(_, _, mc::GcPtr) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) | mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_upvar(..) | mc::cat_static_item | mc::cat_upvar(..) | mc::cat_static_item |
mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => { mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {

View File

@ -82,8 +82,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
mc::cat_downcast(ref base) | mc::cat_downcast(ref base) |
mc::cat_deref(ref base, _, mc::OwnedPtr) | // L-Deref-Send mc::cat_deref(ref base, _, mc::OwnedPtr) | // L-Deref-Send
mc::cat_interior(ref base, _) | // L-Field mc::cat_interior(ref base, _) => { // L-Field
mc::cat_deref(ref base, _, mc::GcPtr) => {
self.check(base, discr_scope) self.check(base, discr_scope)
} }
@ -185,7 +184,6 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
} }
mc::cat_downcast(ref cmt) | mc::cat_downcast(ref cmt) |
mc::cat_deref(ref cmt, _, mc::OwnedPtr) | mc::cat_deref(ref cmt, _, mc::OwnedPtr) |
mc::cat_deref(ref cmt, _, mc::GcPtr) |
mc::cat_interior(ref cmt, _) | mc::cat_interior(ref cmt, _) |
mc::cat_discr(ref cmt, _) => { mc::cat_discr(ref cmt, _) => {
self.scope(cmt) self.scope(cmt)

View File

@ -114,7 +114,6 @@ fn report_cannot_move_out_of(bccx: &BorrowckCtxt, move_from: mc::cmt) {
match move_from.cat { match move_from.cat {
mc::cat_deref(_, _, mc::BorrowedPtr(..)) | mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
mc::cat_deref(_, _, mc::Implicit(..)) | mc::cat_deref(_, _, mc::Implicit(..)) |
mc::cat_deref(_, _, mc::GcPtr) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) | mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_upvar(..) | mc::cat_static_item | mc::cat_upvar(..) | mc::cat_static_item |
mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => { mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {

View File

@ -101,16 +101,13 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
self.extend(result, cmt.mutbl, LpInterior(i)) self.extend(result, cmt.mutbl, LpInterior(i))
} }
mc::cat_deref(cmt_base, _, pk @ mc::OwnedPtr) | mc::cat_deref(cmt_base, _, pk @ mc::OwnedPtr) => {
mc::cat_deref(cmt_base, _, pk @ mc::GcPtr) => {
// R-Deref-Send-Pointer // R-Deref-Send-Pointer
// //
// When we borrow the interior of an owned pointer, we // When we borrow the interior of an owned pointer, we
// cannot permit the base to be mutated, because that // cannot permit the base to be mutated, because that
// would cause the unique pointer to be freed. // would cause the unique pointer to be freed.
// //
// For a managed pointer, the rules are basically the
// same, because this could be the last ref.
// Eventually we should make these non-special and // Eventually we should make these non-special and
// just rely on Deref<T> implementation. // just rely on Deref<T> implementation.
let result = self.restrict(cmt_base); let result = self.restrict(cmt_base);

View File

@ -730,11 +730,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
span, span,
format!("{} in a static location", prefix).as_slice()); format!("{} in a static location", prefix).as_slice());
} }
mc::AliasableManaged => {
self.tcx.sess.span_err(
span,
format!("{} in a `Gc` pointer", prefix).as_slice());
}
mc::AliasableBorrowed => { mc::AliasableBorrowed => {
self.tcx.sess.span_err( self.tcx.sess.span_err(
span, span,

View File

@ -100,7 +100,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) {
if v.in_const { if v.in_const {
match e.node { match e.node {
ExprUnary(UnDeref, _) => { } ExprUnary(UnDeref, _) => { }
ExprUnary(UnBox, _) | ExprUnary(UnUniq, _) => { ExprUnary(UnUniq, _) => {
span_err!(v.tcx.sess, e.span, E0010, "cannot do allocations in constant expressions"); span_err!(v.tcx.sess, e.span, E0010, "cannot do allocations in constant expressions");
return; return;
} }
@ -149,7 +149,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) {
} }
ExprCall(ref callee, _) => { ExprCall(ref callee, _) => {
match v.tcx.def_map.borrow().find(&callee.id) { match v.tcx.def_map.borrow().find(&callee.id) {
Some(&DefStruct(..)) => {} // OK. Some(&DefStruct(..)) |
Some(&DefVariant(..)) => {} // OK. Some(&DefVariant(..)) => {} // OK.
_ => { _ => {
span_err!(v.tcx.sess, e.span, E0015, span_err!(v.tcx.sess, e.span, E0015,

View File

@ -440,11 +440,6 @@ fn construct_witness(cx: &MatchCheckCtxt, ctor: &Constructor,
} }
} }
ty::ty_box(_) => {
assert_eq!(pats_len, 1);
PatBox(pats.nth(0).unwrap())
}
ty::ty_vec(_, Some(len)) => { ty::ty_vec(_, Some(len)) => {
assert_eq!(pats_len, len); assert_eq!(pats_len, len);
PatVec(pats.collect(), None, vec![]) PatVec(pats.collect(), None, vec![])
@ -681,7 +676,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: ty::t) -> uint { pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: ty::t) -> uint {
match ty::get(ty).sty { match ty::get(ty).sty {
ty::ty_tup(ref fs) => fs.len(), ty::ty_tup(ref fs) => fs.len(),
ty::ty_box(_) | ty::ty_uniq(_) => 1u, ty::ty_uniq(_) => 1u,
ty::ty_rptr(_, ty::mt { ty: ty, .. }) => match ty::get(ty).sty { ty::ty_rptr(_, ty::mt { ty: ty, .. }) => match ty::get(ty).sty {
ty::ty_vec(_, None) => match *ctor { ty::ty_vec(_, None) => match *ctor {
Slice(length) => length, Slice(length) => length,
@ -757,7 +752,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
DefStatic(..) => DefStatic(..) =>
cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"), cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
DefVariant(_, id, _) if *constructor != Variant(id) => None, DefVariant(_, id, _) if *constructor != Variant(id) => None,
DefVariant(..) | DefFn(..) | DefStruct(..) => { DefVariant(..) | DefStruct(..) => {
Some(match args { Some(match args {
&Some(ref args) => args.iter().map(|p| &**p).collect(), &Some(ref args) => args.iter().map(|p| &**p).collect(),
&None => Vec::from_elem(arity, &DUMMY_WILD_PAT) &None => Vec::from_elem(arity, &DUMMY_WILD_PAT)

View File

@ -115,10 +115,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckStaticVisitor<'a, 'tcx> {
span_err!(self.tcx.sess, e.span, E0020, span_err!(self.tcx.sess, e.span, E0020,
"static items are not allowed to have mutable slices"); "static items are not allowed to have mutable slices");
}, },
ast::ExprUnary(ast::UnBox, _) => {
span_err!(self.tcx.sess, e.span, E0021,
"static items are not allowed to have managed pointers");
}
ast::ExprBox(..) | ast::ExprBox(..) |
ast::ExprUnary(ast::UnUniq, _) => { ast::ExprUnary(ast::UnUniq, _) => {
span_err!(self.tcx.sess, e.span, E0022, span_err!(self.tcx.sess, e.span, E0022,

View File

@ -28,8 +28,8 @@ fn type_size_is_affected_by_type_parameters(tcx: &ty::ctxt, typ: ty::t)
let mut result = false; let mut result = false;
ty::maybe_walk_ty(typ, |typ| { ty::maybe_walk_ty(typ, |typ| {
match ty::get(typ).sty { match ty::get(typ).sty {
ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_ptr(_) | ty::ty_uniq(_) | ty::ty_ptr(_) | ty::ty_rptr(..) |
ty::ty_rptr(..) | ty::ty_bare_fn(..) | ty::ty_closure(..) => { ty::ty_bare_fn(..) | ty::ty_closure(..) => {
false false
} }
ty::ty_param(_) => { ty::ty_param(_) => {

View File

@ -279,8 +279,6 @@ lets_do_this! {
ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn; ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
ExchangeFreeFnLangItem, "exchange_free", exchange_free_fn; ExchangeFreeFnLangItem, "exchange_free", exchange_free_fn;
MallocFnLangItem, "malloc", malloc_fn;
FreeFnLangItem, "free", free_fn;
StrDupUniqFnLangItem, "strdup_uniq", strdup_uniq_fn; StrDupUniqFnLangItem, "strdup_uniq", strdup_uniq_fn;
StartFnLangItem, "start", start_fn; StartFnLangItem, "start", start_fn;
@ -293,9 +291,7 @@ lets_do_this! {
EhPersonalityLangItem, "eh_personality", eh_personality; EhPersonalityLangItem, "eh_personality", eh_personality;
ManagedHeapLangItem, "managed_heap", managed_heap;
ExchangeHeapLangItem, "exchange_heap", exchange_heap; ExchangeHeapLangItem, "exchange_heap", exchange_heap;
GcLangItem, "gc", gc;
OwnedBoxLangItem, "owned_box", owned_box; OwnedBoxLangItem, "owned_box", owned_box;
CovariantTypeItem, "covariant_type", covariant_type; CovariantTypeItem, "covariant_type", covariant_type;

View File

@ -104,7 +104,6 @@ pub struct CopiedUpvar {
#[deriving(Clone, PartialEq, Eq, Hash)] #[deriving(Clone, PartialEq, Eq, Hash)]
pub enum PointerKind { pub enum PointerKind {
OwnedPtr, OwnedPtr,
GcPtr,
BorrowedPtr(ty::BorrowKind, ty::Region), BorrowedPtr(ty::BorrowKind, ty::Region),
Implicit(ty::BorrowKind, ty::Region), // Implicit deref of a borrowed ptr. Implicit(ty::BorrowKind, ty::Region), // Implicit deref of a borrowed ptr.
UnsafePtr(ast::Mutability) UnsafePtr(ast::Mutability)
@ -191,10 +190,6 @@ pub fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
Some(deref_ptr(BorrowedPtr(ty::ImmBorrow, r))) Some(deref_ptr(BorrowedPtr(ty::ImmBorrow, r)))
} }
ty::ty_box(..) => {
Some(deref_ptr(GcPtr))
}
ty::ty_ptr(ref mt) => { ty::ty_ptr(ref mt) => {
Some(deref_ptr(UnsafePtr(mt.mutbl))) Some(deref_ptr(UnsafePtr(mt.mutbl)))
} }
@ -302,9 +297,6 @@ impl MutabilityCategory {
BorrowedPtr(borrow_kind, _) | Implicit(borrow_kind, _) => { BorrowedPtr(borrow_kind, _) | Implicit(borrow_kind, _) => {
MutabilityCategory::from_borrow_kind(borrow_kind) MutabilityCategory::from_borrow_kind(borrow_kind)
} }
GcPtr => {
McImmutable
}
UnsafePtr(m) => { UnsafePtr(m) => {
MutabilityCategory::from_mutbl(m) MutabilityCategory::from_mutbl(m)
} }
@ -1083,7 +1075,6 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
if_ok!(self.cat_pattern(subcmt, &**subpat, |x,y,z| op(x,y,z))); if_ok!(self.cat_pattern(subcmt, &**subpat, |x,y,z| op(x,y,z)));
} }
} }
Some(&def::DefFn(..)) |
Some(&def::DefStruct(..)) => { Some(&def::DefStruct(..)) => {
for (i, subpat) in subpats.iter().enumerate() { for (i, subpat) in subpats.iter().enumerate() {
let subpat_ty = if_ok!(self.pat_ty(&**subpat)); // see (*2) let subpat_ty = if_ok!(self.pat_ty(&**subpat)); // see (*2)
@ -1200,7 +1191,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
Implicit(..) => { Implicit(..) => {
"dereference (dereference is implicit, due to indexing)".to_string() "dereference (dereference is implicit, due to indexing)".to_string()
} }
OwnedPtr | GcPtr => format!("dereference of `{}`", ptr_sigil(pk)), OwnedPtr => format!("dereference of `{}`", ptr_sigil(pk)),
_ => format!("dereference of `{}`-pointer", ptr_sigil(pk)) _ => format!("dereference of `{}`-pointer", ptr_sigil(pk))
} }
} }
@ -1237,7 +1228,6 @@ pub enum InteriorSafety {
} }
pub enum AliasableReason { pub enum AliasableReason {
AliasableManaged,
AliasableBorrowed, AliasableBorrowed,
AliasableOther, AliasableOther,
AliasableStatic(InteriorSafety), AliasableStatic(InteriorSafety),
@ -1256,7 +1246,6 @@ impl cmt_ {
cat_copied_upvar(..) | cat_copied_upvar(..) |
cat_local(..) | cat_local(..) |
cat_deref(_, _, UnsafePtr(..)) | cat_deref(_, _, UnsafePtr(..)) |
cat_deref(_, _, GcPtr(..)) |
cat_deref(_, _, BorrowedPtr(..)) | cat_deref(_, _, BorrowedPtr(..)) |
cat_deref(_, _, Implicit(..)) | cat_deref(_, _, Implicit(..)) |
cat_upvar(..) => { cat_upvar(..) => {
@ -1320,10 +1309,6 @@ impl cmt_ {
} }
} }
cat_deref(_, _, GcPtr) => {
Some(AliasableManaged)
}
cat_deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) | cat_deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) |
cat_deref(_, _, Implicit(ty::ImmBorrow, _)) => { cat_deref(_, _, Implicit(ty::ImmBorrow, _)) => {
Some(AliasableBorrowed) Some(AliasableBorrowed)
@ -1371,7 +1356,6 @@ impl Repr for categorization {
pub fn ptr_sigil(ptr: PointerKind) -> &'static str { pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
match ptr { match ptr {
OwnedPtr => "Box", OwnedPtr => "Box",
GcPtr => "Gc",
BorrowedPtr(ty::ImmBorrow, _) | BorrowedPtr(ty::ImmBorrow, _) |
Implicit(ty::ImmBorrow, _) => "&", Implicit(ty::ImmBorrow, _) => "&",
BorrowedPtr(ty::MutBorrow, _) | BorrowedPtr(ty::MutBorrow, _) |

View File

@ -931,15 +931,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
maybe_did.unwrap_or(did) maybe_did.unwrap_or(did)
}) })
} }
// Tuple struct constructors across crates are identified as
// DefFn types, so we explicitly handle that case here.
Some(&def::DefFn(did, _, _)) if !is_local(did) => {
match csearch::get_tuple_struct_definition_if_ctor(
&self.tcx.sess.cstore, did) {
Some(did) => guard(did),
None => {}
}
}
_ => {} _ => {}
} }
} }

View File

@ -1824,6 +1824,11 @@ impl<'a> Resolver<'a> {
child_name_bindings.define_value(def, DUMMY_SP, is_exported); child_name_bindings.define_value(def, DUMMY_SP, is_exported);
} }
} }
DefFn(ctor_id, _, true) => {
child_name_bindings.define_value(
csearch::get_tuple_struct_definition_if_ctor(&self.session.cstore, ctor_id)
.map_or(def, |_| DefStruct(ctor_id)), DUMMY_SP, is_public);
}
DefFn(..) | DefStaticMethod(..) | DefStatic(..) => { DefFn(..) | DefStaticMethod(..) | DefStatic(..) => {
debug!("(building reduced graph for external \ debug!("(building reduced graph for external \
crate) building value (fn/static) {}", final_ident); crate) building value (fn/static) {}", final_ident);

View File

@ -104,11 +104,6 @@ pub fn ty_is_local(tcx: &ty::ctxt,
krate == Some(ast::LOCAL_CRATE) || ty_is_local(tcx, t) krate == Some(ast::LOCAL_CRATE) || ty_is_local(tcx, t)
} }
ty::ty_box(t) => {
let krate = tcx.lang_items.gc().map(|d| d.krate);
krate == Some(ast::LOCAL_CRATE) || ty_is_local(tcx, t)
}
ty::ty_vec(t, _) | ty::ty_vec(t, _) |
ty::ty_ptr(ty::mt { ty: t, .. }) | ty::ty_ptr(ty::mt { ty: t, .. }) |
ty::ty_rptr(_, ty::mt { ty: t, .. }) => { ty::ty_rptr(_, ty::mt { ty: t, .. }) => {

View File

@ -713,23 +713,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ok(self, Always) ok(self, Always)
} }
ty::ty_box(_) => {
match bound {
ty::BoundSync |
ty::BoundSend |
ty::BoundCopy => {
// Managed data is not copyable, sendable, nor
// synchronized, regardless of referent.
ok(self, Never)
}
ty::BoundSized => {
// But it is sized, regardless of referent.
ok(self, Always)
}
}
}
ty::ty_uniq(referent_ty) => { // Box<T> ty::ty_uniq(referent_ty) => { // Box<T>
match bound { match bound {
ty::BoundCopy => { ty::BoundCopy => {

View File

@ -698,7 +698,6 @@ fn any_irrefutable_adt_pat(tcx: &ty::ctxt, m: &[Match], col: uint) -> bool {
} }
ast::PatEnum(..) | ast::PatIdent(_, _, None) => { ast::PatEnum(..) | ast::PatIdent(_, _, None) => {
match tcx.def_map.borrow().find(&pat.id) { match tcx.def_map.borrow().find(&pat.id) {
Some(&def::DefFn(..)) |
Some(&def::DefStruct(..)) => true, Some(&def::DefStruct(..)) => true,
_ => false _ => false
} }
@ -1646,7 +1645,6 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
} }
} }
} }
Some(def::DefFn(..)) |
Some(def::DefStruct(..)) => { Some(def::DefStruct(..)) => {
match *sub_pats { match *sub_pats {
None => { None => {

View File

@ -321,9 +321,6 @@ impl Case {
_ => return Some(ThinPointer(i)) _ => return Some(ThinPointer(i))
}, },
// Gc<T> is just a pointer
ty::ty_box(..) => return Some(ThinPointer(i)),
// Functions are just pointers // Functions are just pointers
ty::ty_bare_fn(..) => return Some(ThinPointer(i)), ty::ty_bare_fn(..) => return Some(ThinPointer(i)),

View File

@ -397,36 +397,6 @@ pub fn malloc_raw_dyn_proc<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: ty::t) -> Resu
Result::new(bcx, llbox) Result::new(bcx, llbox)
} }
pub fn malloc_raw_dyn_managed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
t: ty::t,
alloc_fn: LangItem,
size: ValueRef)
-> Result<'blk, 'tcx> {
let _icx = push_ctxt("malloc_raw_dyn_managed");
let ccx = bcx.ccx();
let langcall = require_alloc_fn(bcx, t, alloc_fn);
// Grab the TypeRef type of box_ptr_ty.
let box_ptr_ty = ty::mk_box(bcx.tcx(), t);
let llty = type_of(ccx, box_ptr_ty);
let llalign = C_uint(ccx, type_of::align_of(ccx, box_ptr_ty) as uint);
// Allocate space:
let drop_glue = glue::get_drop_glue(ccx, t);
let r = callee::trans_lang_call(
bcx,
langcall,
[
PointerCast(bcx, drop_glue, Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to()),
size,
llalign
],
None);
Result::new(r.bcx, PointerCast(r.bcx, r.val, llty))
}
// Type descriptor and type glue stuff // Type descriptor and type glue stuff
pub fn get_tydesc(ccx: &CrateContext, t: ty::t) -> Rc<tydesc_info> { pub fn get_tydesc(ccx: &CrateContext, t: ty::t) -> Rc<tydesc_info> {

View File

@ -960,7 +960,6 @@ impl Cleanup for DropValue {
} }
pub enum Heap { pub enum Heap {
HeapManaged,
HeapExchange HeapExchange
} }
@ -986,9 +985,6 @@ impl Cleanup for FreeValue {
apply_debug_loc(bcx.fcx, debug_loc); apply_debug_loc(bcx.fcx, debug_loc);
match self.heap { match self.heap {
HeapManaged => {
glue::trans_free(bcx, self.ptr)
}
HeapExchange => { HeapExchange => {
glue::trans_exchange_free_ty(bcx, self.ptr, self.content_ty) glue::trans_exchange_free_ty(bcx, self.ptr, self.content_ty)
} }
@ -1019,9 +1015,6 @@ impl Cleanup for FreeSlice {
apply_debug_loc(bcx.fcx, debug_loc); apply_debug_loc(bcx.fcx, debug_loc);
match self.heap { match self.heap {
HeapManaged => {
glue::trans_free(bcx, self.ptr)
}
HeapExchange => { HeapExchange => {
glue::trans_exchange_free_dyn(bcx, self.ptr, self.size, self.align) glue::trans_exchange_free_dyn(bcx, self.ptr, self.size, self.align)
} }

View File

@ -71,7 +71,7 @@ pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool {
use middle::trans::type_of::sizing_type_of; use middle::trans::type_of::sizing_type_of;
let tcx = ccx.tcx(); let tcx = ccx.tcx();
let simple = ty::type_is_scalar(ty) || ty::type_is_boxed(ty) || let simple = ty::type_is_scalar(ty) ||
ty::type_is_unique(ty) || ty::type_is_region_ptr(ty) || ty::type_is_unique(ty) || ty::type_is_region_ptr(ty) ||
type_is_newtype_immediate(ccx, ty) || ty::type_is_bot(ty) || type_is_newtype_immediate(ccx, ty) || ty::type_is_bot(ty) ||
ty::type_is_simd(tcx, ty); ty::type_is_simd(tcx, ty);

View File

@ -421,7 +421,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
let ty = ty::expr_ty(cx.tcx(), &**e); let ty = ty::expr_ty(cx.tcx(), &**e);
let is_float = ty::type_is_fp(ty); let is_float = ty::type_is_fp(ty);
return (match u { return (match u {
ast::UnBox | ast::UnUniq | ast::UnDeref => { ast::UnUniq | ast::UnDeref => {
let (dv, _dt) = const_deref(cx, te, ty, true); let (dv, _dt) = const_deref(cx, te, ty, true);
dv dv
} }
@ -547,6 +547,9 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
(expr::cast_integral, expr::cast_pointer) => { (expr::cast_integral, expr::cast_pointer) => {
llvm::LLVMConstIntToPtr(v, llty.to_ref()) llvm::LLVMConstIntToPtr(v, llty.to_ref())
} }
(expr::cast_pointer, expr::cast_integral) => {
llvm::LLVMConstPtrToInt(v, llty.to_ref())
}
_ => { _ => {
cx.sess().impossible_case(e.span, cx.sess().impossible_case(e.span,
"bad combination of types for cast") "bad combination of types for cast")

View File

@ -20,7 +20,6 @@ use middle::trans::common::*;
use middle::trans::cleanup; use middle::trans::cleanup;
use middle::trans::cleanup::CleanupMethods; use middle::trans::cleanup::CleanupMethods;
use middle::trans::expr; use middle::trans::expr;
use middle::trans::glue;
use middle::trans::tvec; use middle::trans::tvec;
use middle::trans::type_of; use middle::trans::type_of;
use middle::ty; use middle::ty;
@ -240,14 +239,9 @@ impl KindOps for Lvalue {
*/ */
if ty::type_needs_drop(bcx.tcx(), ty) { if ty::type_needs_drop(bcx.tcx(), ty) {
if ty::type_moves_by_default(bcx.tcx(), ty) { // cancel cleanup of affine values by zeroing out
// cancel cleanup of affine values by zeroing out let () = zero_mem(bcx, val, ty);
let () = zero_mem(bcx, val, ty); bcx
bcx
} else {
// incr. refcount for @T or newtype'd @T
glue::take_ty(bcx, val, ty)
}
} else { } else {
bcx bcx
} }
@ -567,15 +561,15 @@ impl<K:KindOps> Datum<K> {
* is moved). * is moved).
*/ */
self.shallow_copy(bcx, dst); self.shallow_copy_raw(bcx, dst);
self.kind.post_store(bcx, self.val, self.ty) self.kind.post_store(bcx, self.val, self.ty)
} }
fn shallow_copy<'blk, 'tcx>(&self, fn shallow_copy_raw<'blk, 'tcx>(&self,
bcx: Block<'blk, 'tcx>, bcx: Block<'blk, 'tcx>,
dst: ValueRef) dst: ValueRef)
-> Block<'blk, 'tcx> { -> Block<'blk, 'tcx> {
/*! /*!
* Helper function that performs a shallow copy of this value * Helper function that performs a shallow copy of this value
* into `dst`, which should be a pointer to a memory location * into `dst`, which should be a pointer to a memory location
@ -584,10 +578,9 @@ impl<K:KindOps> Datum<K> {
* *
* This function is private to datums because it leaves memory * This function is private to datums because it leaves memory
* in an unstable state, where the source value has been * in an unstable state, where the source value has been
* copied but not zeroed. Public methods are `store_to` (if * copied but not zeroed. Public methods are `store_to`
* you no longer need the source value) or * (if you no longer need the source value) or `shallow_copy`
* `shallow_copy_and_take` (if you wish the source value to * (if you wish the source value to remain valid).
* remain valid).
*/ */
let _icx = push_ctxt("copy_to_no_check"); let _icx = push_ctxt("copy_to_no_check");
@ -605,22 +598,19 @@ impl<K:KindOps> Datum<K> {
return bcx; return bcx;
} }
pub fn shallow_copy_and_take<'blk, 'tcx>(&self, pub fn shallow_copy<'blk, 'tcx>(&self,
bcx: Block<'blk, 'tcx>, bcx: Block<'blk, 'tcx>,
dst: ValueRef) dst: ValueRef)
-> Block<'blk, 'tcx> { -> Block<'blk, 'tcx> {
/*! /*!
* Copies the value into a new location and runs any necessary * Copies the value into a new location. This function always
* take glue on the new location. This function always
* preserves the existing datum as a valid value. Therefore, * preserves the existing datum as a valid value. Therefore,
* it does not consume `self` and, also, cannot be applied to * it does not consume `self` and, also, cannot be applied to
* affine values (since they must never be duplicated). * affine values (since they must never be duplicated).
*/ */
assert!(!ty::type_moves_by_default(bcx.tcx(), self.ty)); assert!(!ty::type_moves_by_default(bcx.tcx(), self.ty));
let mut bcx = bcx; self.shallow_copy_raw(bcx, dst)
bcx = self.shallow_copy(bcx, dst);
glue::take_ty(bcx, dst, self.ty)
} }
#[allow(dead_code)] // useful for debugging #[allow(dead_code)] // useful for debugging

View File

@ -373,12 +373,6 @@ impl TypeMap {
unique_type_id.push_str(component_type_id.as_slice()); unique_type_id.push_str(component_type_id.as_slice());
} }
}, },
ty::ty_box(inner_type) => {
unique_type_id.push_char('@');
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
unique_type_id.push_str(inner_type_id.as_slice());
},
ty::ty_uniq(inner_type) => { ty::ty_uniq(inner_type) => {
unique_type_id.push_char('~'); unique_type_id.push_char('~');
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type); let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
@ -596,18 +590,6 @@ impl TypeMap {
let interner_key = self.unique_id_interner.intern(Rc::new(enum_variant_type_id)); let interner_key = self.unique_id_interner.intern(Rc::new(enum_variant_type_id));
UniqueTypeId(interner_key) UniqueTypeId(interner_key)
} }
fn get_unique_type_id_of_gc_box(&mut self,
cx: &CrateContext,
element_type: ty::t)
-> UniqueTypeId {
let element_type_id = self.get_unique_type_id_of_type(cx, element_type);
let gc_box_type_id = format!("{{GC_BOX<{}>}}",
self.get_unique_type_id_as_string(element_type_id)
.as_slice());
let interner_key = self.unique_id_interner.intern(Rc::new(gc_box_type_id));
UniqueTypeId(interner_key)
}
} }
// Returns from the enclosing function if the type metadata with the given // Returns from the enclosing function if the type metadata with the given
@ -2646,105 +2628,6 @@ fn create_struct_stub(cx: &CrateContext,
return metadata_stub; return metadata_stub;
} }
fn at_box_metadata(cx: &CrateContext,
at_pointer_type: ty::t,
content_type: ty::t,
unique_type_id: UniqueTypeId)
-> MetadataCreationResult {
let content_type_metadata = type_metadata(cx, content_type, codemap::DUMMY_SP);
return_if_metadata_created_in_meantime!(cx, unique_type_id);
let content_type_name = compute_debuginfo_type_name(cx, content_type, true);
let content_type_name = content_type_name.as_slice();
let content_llvm_type = type_of::type_of(cx, content_type);
let box_type_name = format!("GcBox<{}>", content_type_name);
let box_llvm_type = Type::at_box(cx, content_llvm_type);
let member_llvm_types = box_llvm_type.field_types();
assert!(box_layout_is_correct(cx,
member_llvm_types.as_slice(),
content_llvm_type));
let int_type = ty::mk_int();
let nil_pointer_type = ty::mk_nil_ptr(cx.tcx());
let nil_pointer_type_metadata = type_metadata(cx,
nil_pointer_type,
codemap::DUMMY_SP);
let member_descriptions = [
MemberDescription {
name: "refcnt".to_string(),
llvm_type: *member_llvm_types.get(0),
type_metadata: type_metadata(cx, int_type, codemap::DUMMY_SP),
offset: ComputedMemberOffset,
flags: FLAGS_ARTIFICAL,
},
MemberDescription {
name: "drop_glue".to_string(),
llvm_type: *member_llvm_types.get(1),
type_metadata: nil_pointer_type_metadata,
offset: ComputedMemberOffset,
flags: FLAGS_ARTIFICAL,
},
MemberDescription {
name: "prev".to_string(),
llvm_type: *member_llvm_types.get(2),
type_metadata: nil_pointer_type_metadata,
offset: ComputedMemberOffset,
flags: FLAGS_ARTIFICAL,
},
MemberDescription {
name: "next".to_string(),
llvm_type: *member_llvm_types.get(3),
type_metadata: nil_pointer_type_metadata,
offset: ComputedMemberOffset,
flags: FLAGS_ARTIFICAL,
},
MemberDescription {
name: "val".to_string(),
llvm_type: *member_llvm_types.get(4),
type_metadata: content_type_metadata,
offset: ComputedMemberOffset,
flags: FLAGS_ARTIFICAL,
}
];
let gc_box_unique_id = debug_context(cx).type_map
.borrow_mut()
.get_unique_type_id_of_gc_box(cx, content_type);
let gc_box_metadata = composite_type_metadata(
cx,
box_llvm_type,
box_type_name.as_slice(),
gc_box_unique_id,
member_descriptions,
UNKNOWN_SCOPE_METADATA,
UNKNOWN_FILE_METADATA,
codemap::DUMMY_SP);
let gc_pointer_metadata = pointer_type_metadata(cx,
at_pointer_type,
gc_box_metadata);
return MetadataCreationResult::new(gc_pointer_metadata, false);
// Unfortunately, we cannot assert anything but the correct types here---and
// not whether the 'next' and 'prev' pointers are in the correct order.
fn box_layout_is_correct(cx: &CrateContext,
member_llvm_types: &[Type],
content_llvm_type: Type)
-> bool {
member_llvm_types.len() == 5 &&
member_llvm_types[0] == cx.int_type() &&
member_llvm_types[1] == Type::generic_glue_fn(cx).ptr_to() &&
member_llvm_types[2] == Type::i8(cx).ptr_to() &&
member_llvm_types[3] == Type::i8(cx).ptr_to() &&
member_llvm_types[4] == content_llvm_type
}
}
fn fixed_vec_metadata(cx: &CrateContext, fn fixed_vec_metadata(cx: &CrateContext,
unique_type_id: UniqueTypeId, unique_type_id: UniqueTypeId,
element_type: ty::t, element_type: ty::t,
@ -2968,9 +2851,6 @@ fn type_metadata(cx: &CrateContext,
ty::ty_enum(def_id, _) => { ty::ty_enum(def_id, _) => {
prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span).finalize(cx) prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span).finalize(cx)
} }
ty::ty_box(pointee_type) => {
at_box_metadata(cx, t, pointee_type, unique_type_id)
}
ty::ty_vec(typ, Some(len)) => { ty::ty_vec(typ, Some(len)) => {
fixed_vec_metadata(cx, unique_type_id, typ, len, usage_site_span) fixed_vec_metadata(cx, unique_type_id, typ, len, usage_site_span)
} }
@ -3702,7 +3582,7 @@ fn populate_scope_map(cx: &CrateContext,
ast::ExprInlineAsm(ast::InlineAsm { inputs: ref inputs, ast::ExprInlineAsm(ast::InlineAsm { inputs: ref inputs,
outputs: ref outputs, outputs: ref outputs,
.. }) => { .. }) => {
// inputs, outputs: ~[(String, Gc<expr>)] // inputs, outputs: Vec<(String, P<Expr>)>
for &(_, ref exp) in inputs.iter() { for &(_, ref exp) in inputs.iter() {
walk_expr(cx, &**exp, scope_stack, scope_map); walk_expr(cx, &**exp, scope_stack, scope_map);
} }
@ -3777,10 +3657,6 @@ fn push_debuginfo_type_name(cx: &CrateContext,
push_debuginfo_type_name(cx, inner_type, true, output); push_debuginfo_type_name(cx, inner_type, true, output);
output.push_char('>'); output.push_char('>');
}, },
ty::ty_box(inner_type) => {
output.push_char('@');
push_debuginfo_type_name(cx, inner_type, true, output);
},
ty::ty_ptr(ty::mt { ty: inner_type, mutbl } ) => { ty::ty_ptr(ty::mt { ty: inner_type, mutbl } ) => {
output.push_char('*'); output.push_char('*');
match mutbl { match mutbl {

View File

@ -65,7 +65,7 @@ Some of the datum methods, however, are designed to work only on
copyable values such as ints or pointers. Those methods may borrow the copyable values such as ints or pointers. Those methods may borrow the
datum (`&self`) rather than consume it, but they always include datum (`&self`) rather than consume it, but they always include
assertions on the type of the value represented to check that this assertions on the type of the value represented to check that this
makes sense. An example is `shallow_copy_and_take()`, which duplicates makes sense. An example is `shallow_copy()`, which duplicates
a datum value. a datum value.
Translating an expression always yields a `Datum<Expr>` result, but Translating an expression always yields a `Datum<Expr>` result, but

View File

@ -38,7 +38,6 @@ use llvm;
use llvm::{ValueRef}; use llvm::{ValueRef};
use metadata::csearch; use metadata::csearch;
use middle::def; use middle::def;
use middle::lang_items::MallocFnLangItem;
use middle::mem_categorization::Typer; use middle::mem_categorization::Typer;
use middle::subst; use middle::subst;
use middle::subst::Subst; use middle::subst::Subst;
@ -624,18 +623,15 @@ fn trans_datum_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
DatumBlock::new(bcx, scratch.to_expr_datum()) DatumBlock::new(bcx, scratch.to_expr_datum())
} }
ast::ExprBox(_, ref contents) => { ast::ExprBox(_, ref contents) => {
// Special case for `Box<T>` and `Gc<T>` // Special case for `Box<T>`
let box_ty = expr_ty(bcx, expr); let box_ty = expr_ty(bcx, expr);
let contents_ty = expr_ty(bcx, &**contents); let contents_ty = expr_ty(bcx, &**contents);
match ty::get(box_ty).sty { match ty::get(box_ty).sty {
ty::ty_uniq(..) => { ty::ty_uniq(..) => {
trans_uniq_expr(bcx, box_ty, &**contents, contents_ty) trans_uniq_expr(bcx, box_ty, &**contents, contents_ty)
} }
ty::ty_box(..) => {
trans_managed_expr(bcx, box_ty, &**contents, contents_ty)
}
_ => bcx.sess().span_bug(expr.span, _ => bcx.sess().span_bug(expr.span,
"expected unique or managed box") "expected unique box")
} }
} }
@ -1533,9 +1529,6 @@ fn trans_unary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}; };
immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock() immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
} }
ast::UnBox => {
trans_managed_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
}
ast::UnUniq => { ast::UnUniq => {
trans_uniq_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr)) trans_uniq_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
} }
@ -1575,26 +1568,6 @@ fn trans_uniq_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock() immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
} }
fn trans_managed_expr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
box_ty: ty::t,
contents: &ast::Expr,
contents_ty: ty::t)
-> DatumBlock<'blk, 'tcx, Expr> {
let _icx = push_ctxt("trans_managed_expr");
let fcx = bcx.fcx;
let ty = type_of::type_of(bcx.ccx(), contents_ty);
let Result {bcx, val: bx} = malloc_raw_dyn_managed(bcx, contents_ty, MallocFnLangItem,
llsize_of(bcx.ccx(), ty));
let body = GEPi(bcx, bx, [0u, abi::box_field_body]);
let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
bx, cleanup::HeapManaged, contents_ty);
let bcx = trans_into(bcx, contents, SaveIn(body));
fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
immediate_rvalue_bcx(bcx, bx, box_ty).to_expr_datumblock()
}
fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &ast::Expr, expr: &ast::Expr,
subexpr: &ast::Expr) subexpr: &ast::Expr)
@ -1927,10 +1900,6 @@ pub fn cast_type_kind(tcx: &ty::ctxt, t: ty::t) -> cast_kind {
} }
fn cast_is_noop(t_in: ty::t, t_out: ty::t) -> bool { fn cast_is_noop(t_in: ty::t, t_out: ty::t) -> bool {
if ty::type_is_boxed(t_in) || ty::type_is_boxed(t_out) {
return false;
}
match (ty::deref(t_in, true), ty::deref(t_out, true)) { match (ty::deref(t_in, true), ty::deref(t_out, true)) {
(Some(ty::mt{ ty: t_in, .. }), Some(ty::mt{ ty: t_out, .. })) => { (Some(ty::mt{ ty: t_in, .. }), Some(ty::mt{ ty: t_out, .. })) => {
t_in == t_out t_in == t_out
@ -2163,15 +2132,6 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
} }
} }
ty::ty_box(content_ty) => {
let datum = unpack_datum!(
bcx, datum.to_lvalue_datum(bcx, "deref", expr.id));
let llptrref = datum.to_llref();
let llptr = Load(bcx, llptrref);
let llbody = GEPi(bcx, llptr, [0u, abi::box_field_body]);
DatumBlock::new(bcx, Datum::new(llbody, content_ty, LvalueExpr))
}
ty::ty_ptr(ty::mt { ty: content_ty, .. }) | ty::ty_ptr(ty::mt { ty: content_ty, .. }) |
ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => { ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => {
if ty::type_is_sized(bcx.tcx(), content_ty) { if ty::type_is_sized(bcx.tcx(), content_ty) {

View File

@ -17,7 +17,7 @@ use back::abi;
use back::link::*; use back::link::*;
use llvm::{ValueRef, True, get_param}; use llvm::{ValueRef, True, get_param};
use llvm; use llvm;
use middle::lang_items::{FreeFnLangItem, ExchangeFreeFnLangItem}; use middle::lang_items::ExchangeFreeFnLangItem;
use middle::subst; use middle::subst;
use middle::subst::Subst; use middle::subst::Subst;
use middle::trans::adt; use middle::trans::adt;
@ -46,15 +46,6 @@ use libc::c_uint;
use syntax::ast; use syntax::ast;
use syntax::parse::token; use syntax::parse::token;
pub fn trans_free<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_free");
callee::trans_lang_call(cx,
langcall(cx, None, "", FreeFnLangItem),
[PointerCast(cx, v, Type::i8p(cx.ccx()))],
Some(expr::Ignore)).bcx
}
pub fn trans_exchange_free_dyn<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, pub fn trans_exchange_free_dyn<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef,
size: ValueRef, align: ValueRef) size: ValueRef, align: ValueRef)
-> Block<'blk, 'tcx> { -> Block<'blk, 'tcx> {
@ -87,20 +78,6 @@ pub fn trans_exchange_free_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ptr: ValueRef,
} }
} }
pub fn take_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v: ValueRef, t: ty::t)
-> Block<'blk, 'tcx> {
// NB: v is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("take_ty");
match ty::get(t).sty {
ty::ty_box(_) => incr_refcnt_of_boxed(bcx, v),
_ if ty::type_is_structural(t)
&& ty::type_needs_drop(bcx.tcx(), t) => {
iter_structural_ty(bcx, v, t, take_ty)
}
_ => bcx
}
}
pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t { pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
let tcx = ccx.tcx(); let tcx = ccx.tcx();
// Even if there is no dtor for t, there might be one deeper down and we // Even if there is no dtor for t, there might be one deeper down and we
@ -446,9 +423,6 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: ty::t)
// NB: v0 is an *alias* of type t here, not a direct value. // NB: v0 is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("make_drop_glue"); let _icx = push_ctxt("make_drop_glue");
match ty::get(t).sty { match ty::get(t).sty {
ty::ty_box(body_ty) => {
decr_refcnt_maybe_free(bcx, v0, body_ty)
}
ty::ty_uniq(content_ty) => { ty::ty_uniq(content_ty) => {
match ty::get(content_ty).sty { match ty::get(content_ty).sty {
ty::ty_vec(ty, None) => { ty::ty_vec(ty, None) => {
@ -568,48 +542,6 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: ty::t)
} }
} }
fn decr_refcnt_maybe_free<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
box_ptr_ptr: ValueRef,
t: ty::t) -> Block<'blk, 'tcx> {
let _icx = push_ctxt("decr_refcnt_maybe_free");
let fcx = bcx.fcx;
let ccx = bcx.ccx();
let decr_bcx = fcx.new_temp_block("decr");
let free_bcx = fcx.new_temp_block("free");
let next_bcx = fcx.new_temp_block("next");
let box_ptr = Load(bcx, box_ptr_ptr);
let llnotnull = IsNotNull(bcx, box_ptr);
CondBr(bcx, llnotnull, decr_bcx.llbb, next_bcx.llbb);
let rc_ptr = GEPi(decr_bcx, box_ptr, [0u, abi::box_field_refcnt]);
let rc = Sub(decr_bcx, Load(decr_bcx, rc_ptr), C_int(ccx, 1));
Store(decr_bcx, rc, rc_ptr);
CondBr(decr_bcx, IsNull(decr_bcx, rc), free_bcx.llbb, next_bcx.llbb);
let v = Load(free_bcx, box_ptr_ptr);
let body = GEPi(free_bcx, v, [0u, abi::box_field_body]);
let free_bcx = drop_ty(free_bcx, body, t, None);
let free_bcx = trans_free(free_bcx, v);
Br(free_bcx, next_bcx.llbb);
next_bcx
}
fn incr_refcnt_of_boxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
box_ptr_ptr: ValueRef) -> Block<'blk, 'tcx> {
let _icx = push_ctxt("incr_refcnt_of_boxed");
let ccx = bcx.ccx();
let box_ptr = Load(bcx, box_ptr_ptr);
let rc_ptr = GEPi(bcx, box_ptr, [0u, abi::box_field_refcnt]);
let rc = Load(bcx, rc_ptr);
let rc = Add(bcx, rc, C_int(ccx, 1));
Store(bcx, rc, rc_ptr);
bcx
}
// Generates the declaration for (but doesn't emit) a type descriptor. // Generates the declaration for (but doesn't emit) a type descriptor.
pub fn declare_tydesc(ccx: &CrateContext, t: ty::t) -> tydesc_info { pub fn declare_tydesc(ccx: &CrateContext, t: ty::t) -> tydesc_info {
// If emit_tydescs already ran, then we shouldn't be creating any new // If emit_tydescs already ran, then we shouldn't be creating any new

View File

@ -169,14 +169,6 @@ impl<'a, 'blk, 'tcx> Reflector<'a, 'blk, 'tcx> {
extra.push(self.c_tydesc(ty)); extra.push(self.c_tydesc(ty));
self.visit("evec_fixed", extra.as_slice()) self.visit("evec_fixed", extra.as_slice())
} }
// Should remove mt from box and uniq.
ty::ty_box(typ) => {
let extra = self.c_mt(&ty::mt {
ty: typ,
mutbl: ast::MutImmutable,
});
self.visit("box", extra.as_slice())
}
ty::ty_ptr(ref mt) => { ty::ty_ptr(ref mt) => {
match ty::get(mt.ty).sty { match ty::get(mt.ty).sty {
ty::ty_vec(ty, None) => { ty::ty_vec(ty, None) => {

View File

@ -325,7 +325,7 @@ pub fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let bcx = iter_vec_loop(bcx, lldest, vt, let bcx = iter_vec_loop(bcx, lldest, vt,
C_uint(bcx.ccx(), count), |set_bcx, lleltptr, _| { C_uint(bcx.ccx(), count), |set_bcx, lleltptr, _| {
elem.shallow_copy_and_take(set_bcx, lleltptr) elem.shallow_copy(set_bcx, lleltptr)
}); });
elem.add_clean_if_rvalue(bcx, element.id); elem.add_clean_if_rvalue(bcx, element.id);

View File

@ -174,7 +174,6 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
ty::ty_uint(t) => Type::uint_from_ty(cx, t), ty::ty_uint(t) => Type::uint_from_ty(cx, t),
ty::ty_float(t) => Type::float_from_ty(cx, t), ty::ty_float(t) => Type::float_from_ty(cx, t),
ty::ty_box(..) => Type::i8p(cx),
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => { ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => {
if ty::type_is_sized(cx.tcx(), ty) { if ty::type_is_sized(cx.tcx(), ty) {
Type::i8p(cx) Type::i8p(cx)
@ -299,9 +298,6 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
let name = llvm_type_name(cx, an_unboxed_closure, did, []); let name = llvm_type_name(cx, an_unboxed_closure, did, []);
adt::incomplete_type_of(cx, &*repr, name.as_slice()) adt::incomplete_type_of(cx, &*repr, name.as_slice())
} }
ty::ty_box(typ) => {
Type::at_box(cx, type_of(cx, typ)).ptr_to()
}
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => { ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => {
match ty::get(ty).sty { match ty::get(ty).sty {

View File

@ -940,7 +940,6 @@ pub enum sty {
/// the `ast_ty_to_ty_cache`. This is probably true for `ty_struct` as /// the `ast_ty_to_ty_cache`. This is probably true for `ty_struct` as
/// well.` /// well.`
ty_enum(DefId, Substs), ty_enum(DefId, Substs),
ty_box(t),
ty_uniq(t), ty_uniq(t),
ty_str, ty_str,
ty_vec(t, Option<uint>), // Second field is length. ty_vec(t, Option<uint>), // Second field is length.
@ -1621,7 +1620,7 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
flags |= sflags(substs); flags |= sflags(substs);
flags |= flags_for_bounds(bounds); flags |= flags_for_bounds(bounds);
} }
&ty_box(tt) | &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => { &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => {
flags |= get(tt).flags flags |= get(tt).flags
} }
&ty_ptr(ref m) => { &ty_ptr(ref m) => {
@ -1776,8 +1775,6 @@ pub fn mk_enum(cx: &ctxt, did: ast::DefId, substs: Substs) -> t {
mk_t(cx, ty_enum(did, substs)) mk_t(cx, ty_enum(did, substs))
} }
pub fn mk_box(cx: &ctxt, ty: t) -> t { mk_t(cx, ty_box(ty)) }
pub fn mk_uniq(cx: &ctxt, ty: t) -> t { mk_t(cx, ty_uniq(ty)) } pub fn mk_uniq(cx: &ctxt, ty: t) -> t { mk_t(cx, ty_uniq(ty)) }
pub fn mk_ptr(cx: &ctxt, tm: mt) -> t { mk_t(cx, ty_ptr(tm)) } pub fn mk_ptr(cx: &ctxt, tm: mt) -> t { mk_t(cx, ty_ptr(tm)) }
@ -1901,7 +1898,7 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) {
match get(ty).sty { match get(ty).sty {
ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) | ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(_, _) | ty_err => {} ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(_, _) | ty_err => {}
ty_box(ty) | ty_uniq(ty) | ty_vec(ty, _) | ty_open(ty) => maybe_walk_ty(ty, f), ty_uniq(ty) | ty_vec(ty, _) | ty_open(ty) => maybe_walk_ty(ty, f),
ty_ptr(ref tm) | ty_rptr(_, ref tm) => { ty_ptr(ref tm) | ty_rptr(_, ref tm) => {
maybe_walk_ty(tm.ty, f); maybe_walk_ty(tm.ty, f);
} }
@ -2014,7 +2011,7 @@ pub fn type_is_vec(ty: t) -> bool {
match get(ty).sty { match get(ty).sty {
ty_vec(..) => true, ty_vec(..) => true,
ty_ptr(mt{ty: t, ..}) | ty_rptr(_, mt{ty: t, ..}) | ty_ptr(mt{ty: t, ..}) | ty_rptr(_, mt{ty: t, ..}) |
ty_box(t) | ty_uniq(t) => match get(t).sty { ty_uniq(t) => match get(t).sty {
ty_vec(_, None) => true, ty_vec(_, None) => true,
_ => false _ => false
}, },
@ -2067,13 +2064,6 @@ pub fn simd_size(cx: &ctxt, ty: t) -> uint {
} }
} }
pub fn type_is_boxed(ty: t) -> bool {
match get(ty).sty {
ty_box(_) => true,
_ => false
}
}
pub fn type_is_region_ptr(ty: t) -> bool { pub fn type_is_region_ptr(ty: t) -> bool {
match get(ty).sty { match get(ty).sty {
ty_rptr(..) => true, ty_rptr(..) => true,
@ -2144,29 +2134,22 @@ pub fn type_needs_unwind_cleanup(cx: &ctxt, ty: t) -> bool {
let mut tycache = HashSet::new(); let mut tycache = HashSet::new();
let needs_unwind_cleanup = let needs_unwind_cleanup =
type_needs_unwind_cleanup_(cx, ty, &mut tycache, false); type_needs_unwind_cleanup_(cx, ty, &mut tycache);
cx.needs_unwind_cleanup_cache.borrow_mut().insert(ty, needs_unwind_cleanup); cx.needs_unwind_cleanup_cache.borrow_mut().insert(ty, needs_unwind_cleanup);
return needs_unwind_cleanup; needs_unwind_cleanup
} }
fn type_needs_unwind_cleanup_(cx: &ctxt, ty: t, fn type_needs_unwind_cleanup_(cx: &ctxt, ty: t,
tycache: &mut HashSet<t>, tycache: &mut HashSet<t>) -> bool {
encountered_box: bool) -> bool {
// Prevent infinite recursion // Prevent infinite recursion
if !tycache.insert(ty) { if !tycache.insert(ty) {
return false; return false;
} }
let mut encountered_box = encountered_box;
let mut needs_unwind_cleanup = false; let mut needs_unwind_cleanup = false;
maybe_walk_ty(ty, |ty| { maybe_walk_ty(ty, |ty| {
let old_encountered_box = encountered_box;
let result = match get(ty).sty { let result = match get(ty).sty {
ty_box(_) => {
encountered_box = true;
true
}
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
ty_tup(_) | ty_ptr(_) => { ty_tup(_) | ty_ptr(_) => {
true true
@ -2176,33 +2159,21 @@ fn type_needs_unwind_cleanup_(cx: &ctxt, ty: t,
for aty in v.args.iter() { for aty in v.args.iter() {
let t = aty.subst(cx, substs); let t = aty.subst(cx, substs);
needs_unwind_cleanup |= needs_unwind_cleanup |=
type_needs_unwind_cleanup_(cx, t, tycache, type_needs_unwind_cleanup_(cx, t, tycache);
encountered_box);
} }
} }
!needs_unwind_cleanup !needs_unwind_cleanup
} }
ty_uniq(_) => {
// Once we're inside a box, the annihilator will find
// it and destroy it.
if !encountered_box {
needs_unwind_cleanup = true;
false
} else {
true
}
}
_ => { _ => {
needs_unwind_cleanup = true; needs_unwind_cleanup = true;
false false
} }
}; };
encountered_box = old_encountered_box;
result result
}); });
return needs_unwind_cleanup; needs_unwind_cleanup
} }
/** /**
@ -2460,10 +2431,6 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
closure_contents(cx, &**c) | TC::ReachesFfiUnsafe closure_contents(cx, &**c) | TC::ReachesFfiUnsafe
} }
ty_box(typ) => {
tc_ty(cx, typ, cache).managed_pointer() | TC::ReachesFfiUnsafe
}
ty_uniq(typ) => { ty_uniq(typ) => {
TC::ReachesFfiUnsafe | match get(typ).sty { TC::ReachesFfiUnsafe | match get(typ).sty {
ty_str => TC::OwnsOwned, ty_str => TC::OwnsOwned,
@ -2782,7 +2749,7 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
ty_vec(_, None) => { ty_vec(_, None) => {
false false
} }
ty_box(typ) | ty_uniq(typ) | ty_open(typ) => { ty_uniq(typ) | ty_open(typ) => {
type_requires(cx, seen, r_ty, typ) type_requires(cx, seen, r_ty, typ)
} }
ty_rptr(_, ref mt) => { ty_rptr(_, ref mt) => {
@ -3092,7 +3059,7 @@ pub fn type_is_c_like_enum(cx: &ctxt, ty: t) -> bool {
// Some types---notably unsafe ptrs---can only be dereferenced explicitly. // Some types---notably unsafe ptrs---can only be dereferenced explicitly.
pub fn deref(t: t, explicit: bool) -> Option<mt> { pub fn deref(t: t, explicit: bool) -> Option<mt> {
match get(t).sty { match get(t).sty {
ty_box(ty) | ty_uniq(ty) => { ty_uniq(ty) => {
Some(mt { Some(mt {
ty: ty, ty: ty,
mutbl: ast::MutImmutable, mutbl: ast::MutImmutable,
@ -3106,9 +3073,7 @@ pub fn deref(t: t, explicit: bool) -> Option<mt> {
pub fn deref_or_dont(t: t) -> t { pub fn deref_or_dont(t: t) -> t {
match get(t).sty { match get(t).sty {
ty_box(ty) | ty_uniq(ty) => { ty_uniq(ty) => ty,
ty
},
ty_rptr(_, mt) | ty_ptr(mt) => mt.ty, ty_rptr(_, mt) | ty_ptr(mt) => mt.ty,
_ => t _ => t
} }
@ -3124,7 +3089,7 @@ pub fn close_type(cx: &ctxt, t: t) -> t {
pub fn type_content(t: t) -> t { pub fn type_content(t: t) -> t {
match get(t).sty { match get(t).sty {
ty_box(ty) | ty_uniq(ty) => ty, ty_uniq(ty) => ty,
ty_rptr(_, mt) |ty_ptr(mt) => mt.ty, ty_rptr(_, mt) |ty_ptr(mt) => mt.ty,
_ => t _ => t
} }
@ -3695,14 +3660,13 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
} }
ast::ExprBox(ref place, _) => { ast::ExprBox(ref place, _) => {
// Special case `Box<T>`/`Gc<T>` for now: // Special case `Box<T>` for now:
let definition = match tcx.def_map.borrow().find(&place.id) { let definition = match tcx.def_map.borrow().find(&place.id) {
Some(&def) => def, Some(&def) => def,
None => fail!("no def for place"), None => fail!("no def for place"),
}; };
let def_id = definition.def_id(); let def_id = definition.def_id();
if tcx.lang_items.exchange_heap() == Some(def_id) || if tcx.lang_items.exchange_heap() == Some(def_id) {
tcx.lang_items.managed_heap() == Some(def_id) {
RvalueDatumExpr RvalueDatumExpr
} else { } else {
RvalueDpsExpr RvalueDpsExpr
@ -3753,7 +3717,6 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String {
} }
ty_enum(id, _) => format!("enum {}", item_path_str(cx, id)), ty_enum(id, _) => format!("enum {}", item_path_str(cx, id)),
ty_box(_) => "Gc-ptr".to_string(),
ty_uniq(_) => "box".to_string(), ty_uniq(_) => "box".to_string(),
ty_vec(_, Some(_)) => "array".to_string(), ty_vec(_, Some(_)) => "array".to_string(),
ty_vec(_, None) => "unsized array".to_string(), ty_vec(_, None) => "unsized array".to_string(),
@ -5223,19 +5186,15 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 {
byte!(8); byte!(8);
did(&mut state, d); did(&mut state, d);
} }
ty_box(_) => { ty_uniq(_) => {
byte!(9); byte!(9);
} }
ty_uniq(_) => {
byte!(10);
}
ty_vec(_, Some(n)) => { ty_vec(_, Some(n)) => {
byte!(11); byte!(10);
n.hash(&mut state); n.hash(&mut state);
} }
ty_vec(_, None) => { ty_vec(_, None) => {
byte!(11); byte!(11);
0u8.hash(&mut state);
} }
ty_ptr(m) => { ty_ptr(m) => {
byte!(12); byte!(12);
@ -5586,7 +5545,6 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
ty_int(_) | ty_int(_) |
ty_uint(_) | ty_uint(_) |
ty_float(_) | ty_float(_) |
ty_box(_) |
ty_uniq(_) | ty_uniq(_) |
ty_str | ty_str |
ty_vec(_, _) | ty_vec(_, _) |

View File

@ -485,9 +485,6 @@ pub fn super_fold_mt<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
pub fn super_fold_sty<'tcx, T: TypeFolder<'tcx>>(this: &mut T, pub fn super_fold_sty<'tcx, T: TypeFolder<'tcx>>(this: &mut T,
sty: &ty::sty) -> ty::sty { sty: &ty::sty) -> ty::sty {
match *sty { match *sty {
ty::ty_box(typ) => {
ty::ty_box(typ.fold_with(this))
}
ty::ty_uniq(typ) => { ty::ty_uniq(typ) => {
ty::ty_uniq(typ.fold_with(this)) ty::ty_uniq(typ.fold_with(this))
} }

View File

@ -559,44 +559,6 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
"not enough type parameters supplied to `Box<T>`"); "not enough type parameters supplied to `Box<T>`");
Some(ty::mk_err()) Some(ty::mk_err())
} }
def::DefTy(did, _) | def::DefStruct(did)
if Some(did) == this.tcx().lang_items.gc() => {
if path.segments
.iter()
.flat_map(|s| s.types.iter())
.count() > 1 {
span_err!(this.tcx().sess, path.span, E0048,
"`Gc` has only one type parameter");
}
for inner_ast_type in path.segments
.iter()
.flat_map(|s| s.types.iter()) {
return Some(mk_pointer(this,
rscope,
ast::MutImmutable,
&**inner_ast_type,
Box,
|typ| {
match ty::get(typ).sty {
ty::ty_str => {
span_err!(this.tcx().sess, path.span, E0114,
"`Gc<str>` is not a type");
ty::mk_err()
}
ty::ty_vec(_, None) => {
span_err!(this.tcx().sess, path.span, E0115,
"`Gc<[T]>` is not a type");
ty::mk_err()
}
_ => ty::mk_box(this.tcx(), typ),
}
}))
}
this.tcx().sess.span_bug(path.span,
"not enough type parameters \
supplied to `Gc<T>`")
}
_ => None _ => None
} }
} }
@ -606,7 +568,6 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
#[deriving(Show)] #[deriving(Show)]
enum PointerTy { enum PointerTy {
Box,
RPtr(ty::Region), RPtr(ty::Region),
Uniq Uniq
} }
@ -614,7 +575,6 @@ enum PointerTy {
impl PointerTy { impl PointerTy {
fn default_region(&self) -> ty::Region { fn default_region(&self) -> ty::Region {
match *self { match *self {
Box => ty::ReStatic,
Uniq => ty::ReStatic, Uniq => ty::ReStatic,
RPtr(r) => r, RPtr(r) => r,
} }
@ -702,14 +662,6 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
r, r,
ty::mt {mutbl: a_seq_mutbl, ty: tr}); ty::mt {mutbl: a_seq_mutbl, ty: tr});
} }
_ => {
tcx.sess.span_err(
a_seq_ty.span,
"~trait or &trait are the only supported \
forms of casting-to-trait");
return ty::mk_err();
}
} }
} }
ast::TyPath(ref path, ref opt_bounds, id) => { ast::TyPath(ref path, ref opt_bounds, id) => {
@ -726,11 +678,6 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
RPtr(r) => { RPtr(r) => {
return ty::mk_str_slice(tcx, r, ast::MutImmutable); return ty::mk_str_slice(tcx, r, ast::MutImmutable);
} }
_ => {
tcx.sess
.span_err(path.span,
"managed strings are not supported")
}
} }
} }
Some(&def::DefTrait(trait_def_id)) => { Some(&def::DefTrait(trait_def_id)) => {
@ -767,13 +714,6 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
RPtr(r) => { RPtr(r) => {
return ty::mk_rptr(tcx, r, ty::mt{mutbl: a_seq_mutbl, ty: tr}); return ty::mk_rptr(tcx, r, ty::mt{mutbl: a_seq_mutbl, ty: tr});
} }
_ => {
tcx.sess.span_err(
path.span,
"~trait or &trait are the only supported \
forms of casting-to-trait");
return ty::mk_err();
}
}; };
} }
_ => {} _ => {}
@ -856,10 +796,6 @@ pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
match ast_ty.node { match ast_ty.node {
ast::TyNil => ty::mk_nil(), ast::TyNil => ty::mk_nil(),
ast::TyBot => ty::mk_bot(), ast::TyBot => ty::mk_bot(),
ast::TyBox(ref ty) => {
mk_pointer(this, rscope, ast::MutImmutable, &**ty, Box,
|ty| ty::mk_box(tcx, ty))
}
ast::TyUniq(ref ty) => { ast::TyUniq(ref ty) => {
mk_pointer(this, rscope, ast::MutImmutable, &**ty, Uniq, mk_pointer(this, rscope, ast::MutImmutable, &**ty, Uniq,
|ty| ty::mk_uniq(tcx, ty)) |ty| ty::mk_uniq(tcx, ty))

View File

@ -1094,7 +1094,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
let tcx = self.tcx(); let tcx = self.tcx();
match ty::get(self_ty).sty { match ty::get(self_ty).sty {
ty_bare_fn(..) | ty_box(..) | ty_uniq(..) | ty_rptr(..) | ty_bare_fn(..) | ty_uniq(..) | ty_rptr(..) |
ty_infer(IntVar(_)) | ty_infer(IntVar(_)) |
ty_infer(FloatVar(_)) | ty_infer(FloatVar(_)) |
ty_param(..) | ty_nil | ty_bot | ty_bool | ty_param(..) | ty_nil | ty_bot | ty_bool |

View File

@ -1468,7 +1468,7 @@ fn check_cast(fcx: &FnCtxt,
// casts to scalars other than `char` and `bare fn` are trivial // casts to scalars other than `char` and `bare fn` are trivial
let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn; let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
if ty::type_is_c_like_enum(fcx.tcx(), t_e) && t_1_is_trivial { if ty::type_is_c_like_enum(fcx.tcx(), t_e) && t_1_is_trivial {
if t_1_is_float { if t_1_is_float || ty::type_is_unsafe_ptr(t_1) {
fcx.type_error_message(span, |actual| { fcx.type_error_message(span, |actual| {
format!("illegal cast; cast through an \ format!("illegal cast; cast through an \
integer first: `{}` as `{}`", integer first: `{}` as `{}`",
@ -3820,12 +3820,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
if tcx.lang_items.exchange_heap() == Some(def_id) { if tcx.lang_items.exchange_heap() == Some(def_id) {
fcx.write_ty(id, ty::mk_uniq(tcx, referent_ty)); fcx.write_ty(id, ty::mk_uniq(tcx, referent_ty));
checked = true checked = true
} else if tcx.lang_items.managed_heap() == Some(def_id) {
fcx.register_region_obligation(infer::Managed(expr.span),
referent_ty,
ty::ReStatic);
fcx.write_ty(id, ty::mk_box(tcx, referent_ty));
checked = true
} }
} }
_ => {} _ => {}
@ -3881,8 +3875,8 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
ast::ExprUnary(unop, ref oprnd) => { ast::ExprUnary(unop, ref oprnd) => {
let expected_inner = expected.map(fcx, |sty| { let expected_inner = expected.map(fcx, |sty| {
match unop { match unop {
ast::UnBox | ast::UnUniq => match *sty { ast::UnUniq => match *sty {
ty::ty_box(ty) | ty::ty_uniq(ty) => { ty::ty_uniq(ty) => {
ExpectHasType(ty) ExpectHasType(ty)
} }
_ => { _ => {
@ -3907,11 +3901,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
if !ty::type_is_error(oprnd_t) { if !ty::type_is_error(oprnd_t) {
match unop { match unop {
ast::UnBox => {
if !ty::type_is_bot(oprnd_t) {
oprnd_t = ty::mk_box(tcx, oprnd_t)
}
}
ast::UnUniq => { ast::UnUniq => {
if !ty::type_is_bot(oprnd_t) { if !ty::type_is_bot(oprnd_t) {
oprnd_t = ty::mk_uniq(tcx, oprnd_t); oprnd_t = ty::mk_uniq(tcx, oprnd_t);

View File

@ -663,14 +663,6 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
visit::walk_expr(rcx, expr); visit::walk_expr(rcx, expr);
} }
ast::ExprUnary(ast::UnBox, ref base) => {
// Managed data must not have borrowed pointers within it:
let base_ty = rcx.resolve_node_type(base.id);
type_must_outlive(rcx, infer::Managed(expr.span),
base_ty, ty::ReStatic);
visit::walk_expr(rcx, expr);
}
ast::ExprUnary(ast::UnDeref, ref base) => { ast::ExprUnary(ast::UnDeref, ref base) => {
// For *a, the lifetime of a must enclose the deref // For *a, the lifetime of a must enclose the deref
let method_call = MethodCall::expr(expr.id); let method_call = MethodCall::expr(expr.id);
@ -1474,7 +1466,6 @@ fn link_region(rcx: &Rcx,
mc::cat_discr(cmt_base, _) | mc::cat_discr(cmt_base, _) |
mc::cat_downcast(cmt_base) | mc::cat_downcast(cmt_base) |
mc::cat_deref(cmt_base, _, mc::GcPtr(..)) |
mc::cat_deref(cmt_base, _, mc::OwnedPtr) | mc::cat_deref(cmt_base, _, mc::OwnedPtr) |
mc::cat_interior(cmt_base, _) => { mc::cat_interior(cmt_base, _) => {
// Borrowing interior or owned data requires the base // Borrowing interior or owned data requires the base
@ -1707,7 +1698,6 @@ fn adjust_upvar_borrow_kind_for_mut(rcx: &Rcx,
} }
mc::cat_deref(_, _, mc::UnsafePtr(..)) | mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_deref(_, _, mc::GcPtr) |
mc::cat_static_item | mc::cat_static_item |
mc::cat_rvalue(_) | mc::cat_rvalue(_) |
mc::cat_copied_upvar(_) | mc::cat_copied_upvar(_) |
@ -1758,7 +1748,6 @@ fn adjust_upvar_borrow_kind_for_unique(rcx: &Rcx, cmt: mc::cmt) {
} }
mc::cat_deref(_, _, mc::UnsafePtr(..)) | mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_deref(_, _, mc::GcPtr) |
mc::cat_static_item | mc::cat_static_item |
mc::cat_rvalue(_) | mc::cat_rvalue(_) |
mc::cat_copied_upvar(_) | mc::cat_copied_upvar(_) |

View File

@ -129,7 +129,6 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
ty::ty_vec(t, _) | ty::ty_vec(t, _) |
ty::ty_ptr(ty::mt { ty: t, .. }) | ty::ty_ptr(ty::mt { ty: t, .. }) |
ty::ty_box(t) |
ty::ty_uniq(t) => { ty::ty_uniq(t) => {
self.accumulate_from_ty(t) self.accumulate_from_ty(t)
} }

View File

@ -95,7 +95,7 @@ pub fn check_object_cast(fcx: &FnCtxt,
} }
} }
// Because we currently give unsound lifetimes to the "ty_box", I // Because we currently give unsound lifetimes to the "t_box", I
// could have written &'static ty::TyTrait here, but it seems // could have written &'static ty::TyTrait here, but it seems
// gratuitously unsafe. // gratuitously unsafe.
fn object_trait<'a>(t: &'a ty::t) -> &'a ty::TyTrait { fn object_trait<'a>(t: &'a ty::t) -> &'a ty::TyTrait {

View File

@ -23,7 +23,7 @@ use middle::subst::{Substs};
use middle::ty::get; use middle::ty::get;
use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId}; use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId};
use middle::ty::{TypeTraitItemId, lookup_item_type}; use middle::ty::{TypeTraitItemId, lookup_item_type};
use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err}; use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_enum, ty_err};
use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil, ty_open}; use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil, ty_open};
use middle::ty::{ty_param, Polytype, ty_ptr}; use middle::ty::{ty_param, Polytype, ty_ptr};
use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
@ -84,8 +84,8 @@ fn get_base_type(inference_context: &InferCtxt,
ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) | ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) | ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
ty_infer(..) | ty_param(..) | ty_err | ty_open(..) | ty_infer(..) | ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) |
ty_box(_) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => { ty_ptr(_) | ty_rptr(_, _) => {
debug!("(getting base type) no base type; found {:?}", debug!("(getting base type) no base type; found {:?}",
get(original_type).sty); get(original_type).sty);
None None

View File

@ -258,7 +258,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
let r_borrow = self.get_ref().infcx.next_region_var(coercion); let r_borrow = self.get_ref().infcx.next_region_var(coercion);
let inner_ty = match *sty_a { let inner_ty = match *sty_a {
ty::ty_box(_) | ty::ty_uniq(_) => return Err(ty::terr_mismatch), ty::ty_uniq(_) => return Err(ty::terr_mismatch),
ty::ty_rptr(_, mt_a) => mt_a.ty, ty::ty_rptr(_, mt_a) => mt_a.ty,
_ => { _ => {
return self.subtype(a, b); return self.subtype(a, b);

View File

@ -495,10 +495,6 @@ pub fn super_tys<'tcx, C: Combine<'tcx>>(this: &C, a: ty::t, b: ty::t) -> cres<t
Ok(ty::mk_unboxed_closure(tcx, a_id, region)) Ok(ty::mk_unboxed_closure(tcx, a_id, region))
} }
(&ty::ty_box(a_inner), &ty::ty_box(b_inner)) => {
this.tys(a_inner, b_inner).and_then(|typ| Ok(ty::mk_box(tcx, typ)))
}
(&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => { (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => {
let typ = try!(this.tys(a_inner, b_inner)); let typ = try!(this.tys(a_inner, b_inner));
check_ptr_to_unsized(this, a, b, a_inner, b_inner, ty::mk_uniq(tcx, typ)) check_ptr_to_unsized(this, a, b, a_inner, b_inner, ty::mk_uniq(tcx, typ))

View File

@ -776,11 +776,6 @@ impl<'a, 'tcx> ErrorReporting for InferCtxt<'a, 'tcx> {
sup, sup,
""); "");
} }
infer::Managed(span) => {
self.tcx.sess.span_err(
span,
format!("cannot put borrowed references into managed memory").as_slice());
}
} }
} }
@ -1285,7 +1280,6 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
ast::TyPtr(ref mut_ty) => { ast::TyPtr(ref mut_ty) => {
ty_queue.push(&*mut_ty.ty); ty_queue.push(&*mut_ty.ty);
} }
ast::TyBox(ref ty) |
ast::TyVec(ref ty) | ast::TyVec(ref ty) |
ast::TyUniq(ref ty) | ast::TyUniq(ref ty) |
ast::TyFixedLengthVec(ref ty, _) => { ast::TyFixedLengthVec(ref ty, _) => {
@ -1323,7 +1317,6 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
ty: build_to(mut_ty.ty, to), ty: build_to(mut_ty.ty, to),
}) })
} }
ast::TyBox(ty) => ast::TyBox(build_to(ty, to)),
ast::TyVec(ty) => ast::TyVec(build_to(ty, to)), ast::TyVec(ty) => ast::TyVec(build_to(ty, to)),
ast::TyUniq(ty) => ast::TyUniq(build_to(ty, to)), ast::TyUniq(ty) => ast::TyUniq(build_to(ty, to)),
ast::TyFixedLengthVec(ty, e) => { ast::TyFixedLengthVec(ty, e) => {
@ -1614,11 +1607,6 @@ impl<'a, 'tcx> ErrorReportingHelpers for InferCtxt<'a, 'tcx> {
does not outlive the data it points at", does not outlive the data it points at",
self.ty_to_string(ty)).as_slice()); self.ty_to_string(ty)).as_slice());
} }
infer::Managed(span) => {
self.tcx.sess.span_note(
span,
"...so that the value can be stored in managed memory.");
}
infer::RelateParamBound(span, param_ty, t) => { infer::RelateParamBound(span, param_ty, t) => {
self.tcx.sess.span_note( self.tcx.sess.span_note(
span, span,

View File

@ -216,9 +216,6 @@ pub enum SubregionOrigin {
// An auto-borrow that does not enclose the expr where it occurs // An auto-borrow that does not enclose the expr where it occurs
AutoBorrow(Span), AutoBorrow(Span),
// Managed data cannot contain borrowed pointers.
Managed(Span),
} }
/// Reasons to create a region inference variable /// Reasons to create a region inference variable
@ -1029,7 +1026,6 @@ impl SubregionOrigin {
CallReturn(a) => a, CallReturn(a) => a,
AddrOf(a) => a, AddrOf(a) => a,
AutoBorrow(a) => a, AutoBorrow(a) => a,
Managed(a) => a,
} }
} }
} }
@ -1102,7 +1098,6 @@ impl Repr for SubregionOrigin {
CallReturn(a) => format!("CallReturn({})", a.repr(tcx)), CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
AddrOf(a) => format!("AddrOf({})", a.repr(tcx)), AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)), AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)),
Managed(a) => format!("Managed({})", a.repr(tcx)),
} }
} }
} }

View File

@ -143,7 +143,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> {
ty::ty_uint(..) | ty::ty_uint(..) |
ty::ty_float(..) | ty::ty_float(..) |
ty::ty_enum(..) | ty::ty_enum(..) |
ty::ty_box(..) |
ty::ty_uniq(..) | ty::ty_uniq(..) |
ty::ty_str | ty::ty_str |
ty::ty_err | ty::ty_err |

View File

@ -742,7 +742,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
self.add_constraints_from_mt(mt, variance); self.add_constraints_from_mt(mt, variance);
} }
ty::ty_uniq(typ) | ty::ty_box(typ) | ty::ty_vec(typ, _) | ty::ty_open(typ) => { ty::ty_uniq(typ) | ty::ty_vec(typ, _) | ty::ty_open(typ) => {
self.add_constraints_from_ty(typ, variance); self.add_constraints_from_ty(typ, variance);
} }

View File

@ -17,7 +17,7 @@ use middle::ty::{ReEarlyBound, BrFresh, ctxt};
use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty}; use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty};
use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{ReSkolemized, ReVar};
use middle::ty::{mt, t, ParamTy}; use middle::ty::{mt, t, ParamTy};
use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum}; use middle::ty::{ty_bool, ty_char, ty_bot, ty_struct, ty_enum};
use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure}; use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure};
use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup, ty_open}; use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup, ty_open};
use middle::ty::{ty_unboxed_closure}; use middle::ty::{ty_unboxed_closure};
@ -375,7 +375,6 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
ty_int(t) => ast_util::int_ty_to_string(t, None).to_string(), ty_int(t) => ast_util::int_ty_to_string(t, None).to_string(),
ty_uint(t) => ast_util::uint_ty_to_string(t, None).to_string(), ty_uint(t) => ast_util::uint_ty_to_string(t, None).to_string(),
ty_float(t) => ast_util::float_ty_to_string(t).to_string(), ty_float(t) => ast_util::float_ty_to_string(t).to_string(),
ty_box(typ) => format!("Gc<{}>", ty_to_string(cx, typ)),
ty_uniq(typ) => format!("Box<{}>", ty_to_string(cx, typ)), ty_uniq(typ) => format!("Box<{}>", ty_to_string(cx, typ)),
ty_ptr(ref tm) => { ty_ptr(ref tm) => {
format!("*{} {}", match tm.mutbl { format!("*{} {}", match tm.mutbl {

View File

@ -1087,7 +1087,6 @@ pub enum Type {
/// aka TyBot /// aka TyBot
Bottom, Bottom,
Unique(Box<Type>), Unique(Box<Type>),
Managed(Box<Type>),
RawPointer(Mutability, Box<Type>), RawPointer(Mutability, Box<Type>),
BorrowedRef { BorrowedRef {
pub lifetime: Option<Lifetime>, pub lifetime: Option<Lifetime>,
@ -1215,7 +1214,6 @@ impl Clean<Type> for ast::Ty {
TyRptr(ref l, ref m) => TyRptr(ref l, ref m) =>
BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx), BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
type_: box m.ty.clean(cx)}, type_: box m.ty.clean(cx)},
TyBox(ref ty) => Managed(box ty.clean(cx)),
TyUniq(ref ty) => Unique(box ty.clean(cx)), TyUniq(ref ty) => Unique(box ty.clean(cx)),
TyVec(ref ty) => Vector(box ty.clean(cx)), TyVec(ref ty) => Vector(box ty.clean(cx)),
TyFixedLengthVec(ref ty, ref e) => FixedVector(box ty.clean(cx), TyFixedLengthVec(ref ty, ref e) => FixedVector(box ty.clean(cx),
@ -1254,12 +1252,6 @@ impl Clean<Type> for ty::t {
ty::ty_float(ast::TyF32) => Primitive(F32), ty::ty_float(ast::TyF32) => Primitive(F32),
ty::ty_float(ast::TyF64) => Primitive(F64), ty::ty_float(ast::TyF64) => Primitive(F64),
ty::ty_str => Primitive(Str), ty::ty_str => Primitive(Str),
ty::ty_box(t) => {
let gc_did = cx.tcx_opt().and_then(|tcx| {
tcx.lang_items.gc()
});
lang_struct(cx, gc_did, t, "Gc", Managed)
}
ty::ty_uniq(t) => { ty::ty_uniq(t) => {
let box_did = cx.tcx_opt().and_then(|tcx| { let box_did = cx.tcx_opt().and_then(|tcx| {
tcx.lang_items.owned_box() tcx.lang_items.owned_box()

View File

@ -476,7 +476,7 @@ impl fmt::Show for clean::Type {
}; };
write!(f, "&amp;{}{}{}", lt, MutableSpace(mutability), **ty) write!(f, "&amp;{}{}{}", lt, MutableSpace(mutability), **ty)
} }
clean::Unique(..) | clean::Managed(..) => { clean::Unique(..) => {
fail!("should have been cleaned") fail!("should have been cleaned")
} }
} }

View File

@ -15,7 +15,7 @@
#![crate_type = "dylib"] #![crate_type = "dylib"]
#![crate_type = "rlib"] #![crate_type = "rlib"]
#![feature(globs, struct_variant, managed_boxes, macro_rules, phase)] #![feature(globs, struct_variant, macro_rules, phase)]
extern crate arena; extern crate arena;
extern crate debug; extern crate debug;

View File

@ -16,7 +16,7 @@
html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/master/")] html_root_url = "http://doc.rust-lang.org/master/")]
#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)] #![feature(macro_rules, phase, globs, thread_local, asm)]
#![feature(linkage, lang_items, unsafe_destructor, default_type_params)] #![feature(linkage, lang_items, unsafe_destructor, default_type_params)]
#![feature(import_shadowing)] #![feature(import_shadowing)]
#![no_std] #![no_std]
@ -57,7 +57,6 @@ pub mod c_str;
pub mod exclusive; pub mod exclusive;
pub mod local; pub mod local;
pub mod local_data; pub mod local_data;
pub mod local_heap;
pub mod mutex; pub mod mutex;
pub mod rtio; pub mod rtio;
pub mod stack; pub mod stack;
@ -104,9 +103,8 @@ pub static DEFAULT_ERROR_CODE: int = 101;
/// One-time runtime initialization. /// One-time runtime initialization.
/// ///
/// Initializes global state, including frobbing /// Initializes global state, including frobbing the crate's logging flags,
/// the crate's logging flags, registering GC /// and storing the process arguments.
/// metadata, and storing the process arguments.
pub fn init(argc: int, argv: *const *const u8) { pub fn init(argc: int, argv: *const *const u8) {
// FIXME: Derefing these pointers is not safe. // FIXME: Derefing these pointers is not safe.
// Need to propagate the unsafety to `start`. // Need to propagate the unsafety to `start`.

View File

@ -411,7 +411,6 @@ mod tests {
extern crate test; extern crate test;
use std::prelude::*; use std::prelude::*;
use std::gc::{Gc, GC};
use super::*; use super::*;
use std::task; use std::task;
@ -467,11 +466,11 @@ mod tests {
#[test] #[test]
fn test_tls_multiple_types() { fn test_tls_multiple_types() {
static str_key: Key<String> = &KeyValueKey; static str_key: Key<String> = &KeyValueKey;
static box_key: Key<Gc<()>> = &KeyValueKey; static box_key: Key<Box<int>> = &KeyValueKey;
static int_key: Key<int> = &KeyValueKey; static int_key: Key<int> = &KeyValueKey;
task::spawn(proc() { task::spawn(proc() {
str_key.replace(Some("string data".to_string())); str_key.replace(Some("string data".to_string()));
box_key.replace(Some(box(GC) ())); box_key.replace(Some(box 0));
int_key.replace(Some(42)); int_key.replace(Some(42));
}); });
} }
@ -479,13 +478,13 @@ mod tests {
#[test] #[test]
fn test_tls_overwrite_multiple_types() { fn test_tls_overwrite_multiple_types() {
static str_key: Key<String> = &KeyValueKey; static str_key: Key<String> = &KeyValueKey;
static box_key: Key<Gc<()>> = &KeyValueKey; static box_key: Key<Box<int>> = &KeyValueKey;
static int_key: Key<int> = &KeyValueKey; static int_key: Key<int> = &KeyValueKey;
task::spawn(proc() { task::spawn(proc() {
str_key.replace(Some("string data".to_string())); str_key.replace(Some("string data".to_string()));
str_key.replace(Some("string data 2".to_string())); str_key.replace(Some("string data 2".to_string()));
box_key.replace(Some(box(GC) ())); box_key.replace(Some(box 0));
box_key.replace(Some(box(GC) ())); box_key.replace(Some(box 1));
int_key.replace(Some(42)); int_key.replace(Some(42));
// This could cause a segfault if overwriting-destruction is done // This could cause a segfault if overwriting-destruction is done
// with the crazy polymorphic transmute rather than the provided // with the crazy polymorphic transmute rather than the provided
@ -498,13 +497,13 @@ mod tests {
#[should_fail] #[should_fail]
fn test_tls_cleanup_on_failure() { fn test_tls_cleanup_on_failure() {
static str_key: Key<String> = &KeyValueKey; static str_key: Key<String> = &KeyValueKey;
static box_key: Key<Gc<()>> = &KeyValueKey; static box_key: Key<Box<int>> = &KeyValueKey;
static int_key: Key<int> = &KeyValueKey; static int_key: Key<int> = &KeyValueKey;
str_key.replace(Some("parent data".to_string())); str_key.replace(Some("parent data".to_string()));
box_key.replace(Some(box(GC) ())); box_key.replace(Some(box 0));
task::spawn(proc() { task::spawn(proc() {
str_key.replace(Some("string data".to_string())); str_key.replace(Some("string data".to_string()));
box_key.replace(Some(box(GC) ())); box_key.replace(Some(box 2));
int_key.replace(Some(42)); int_key.replace(Some(42));
fail!(); fail!();
}); });

View File

@ -1,345 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! The local, garbage collected heap
use core::prelude::*;
use alloc::libc_heap;
use alloc::util;
use libc::{c_void, free};
use core::mem;
use core::ptr;
use core::raw;
use local::Local;
use task::Task;
static RC_IMMORTAL : uint = 0x77777777;
pub type Box = raw::GcBox<()>;
pub struct MemoryRegion {
live_allocations: uint,
}
pub struct LocalHeap {
memory_region: MemoryRegion,
live_allocs: *mut raw::GcBox<()>,
}
impl LocalHeap {
pub fn new() -> LocalHeap {
LocalHeap {
memory_region: MemoryRegion { live_allocations: 0 },
live_allocs: ptr::null_mut(),
}
}
#[inline]
#[allow(deprecated)]
pub fn alloc(&mut self,
drop_glue: fn(*mut u8),
size: uint,
align: uint) -> *mut Box {
let total_size = util::get_box_size(size, align);
let alloc = self.memory_region.malloc(total_size);
{
// Make sure that we can't use `mybox` outside of this scope
let mybox: &mut Box = unsafe { mem::transmute(alloc) };
// Clear out this box, and move it to the front of the live
// allocations list
mybox.drop_glue = drop_glue;
mybox.ref_count = 1;
mybox.prev = ptr::null_mut();
mybox.next = self.live_allocs;
if !self.live_allocs.is_null() {
unsafe { (*self.live_allocs).prev = alloc; }
}
self.live_allocs = alloc;
}
return alloc;
}
#[inline]
pub fn realloc(&mut self, ptr: *mut Box, size: uint) -> *mut Box {
// Make sure that we can't use `mybox` outside of this scope
let total_size = size + mem::size_of::<Box>();
let new_box = self.memory_region.realloc(ptr, total_size);
{
// Fix links because we could have moved around
let mybox: &mut Box = unsafe { mem::transmute(new_box) };
if !mybox.prev.is_null() {
unsafe { (*mybox.prev).next = new_box; }
}
if !mybox.next.is_null() {
unsafe { (*mybox.next).prev = new_box; }
}
}
if self.live_allocs == ptr {
self.live_allocs = new_box;
}
return new_box;
}
#[inline]
pub fn free(&mut self, alloc: *mut Box) {
{
// Make sure that we can't use `mybox` outside of this scope
let mybox: &mut Box = unsafe { mem::transmute(alloc) };
// Unlink it from the linked list
if !mybox.prev.is_null() {
unsafe { (*mybox.prev).next = mybox.next; }
}
if !mybox.next.is_null() {
unsafe { (*mybox.next).prev = mybox.prev; }
}
if self.live_allocs == alloc {
self.live_allocs = mybox.next;
}
}
self.memory_region.free(alloc);
}
/// Immortalize all pending allocations, forcing them to live forever.
///
/// This function will freeze all allocations to prevent all pending
/// allocations from being deallocated. This is used in preparation for when
/// a task is about to destroy TLD.
pub unsafe fn immortalize(&mut self) {
let mut n_total_boxes = 0u;
// Pass 1: Make all boxes immortal.
//
// In this pass, nothing gets freed, so it does not matter whether
// we read the next field before or after the callback.
self.each_live_alloc(true, |_, alloc| {
n_total_boxes += 1;
(*alloc).ref_count = RC_IMMORTAL;
});
if debug_mem() {
// We do logging here w/o allocation.
rterrln!("total boxes annihilated: {}", n_total_boxes);
}
}
/// Continues deallocation of the all pending allocations in this arena.
///
/// This is invoked from the destructor, and requires that `immortalize` has
/// been called previously.
unsafe fn annihilate(&mut self) {
// Pass 2: Drop all boxes.
//
// In this pass, unique-managed boxes may get freed, but not
// managed boxes, so we must read the `next` field *after* the
// callback, as the original value may have been freed.
self.each_live_alloc(false, |_, alloc| {
let drop_glue = (*alloc).drop_glue;
let data = &mut (*alloc).data as *mut ();
drop_glue(data as *mut u8);
});
// Pass 3: Free all boxes.
//
// In this pass, managed boxes may get freed (but not
// unique-managed boxes, though I think that none of those are
// left), so we must read the `next` field before, since it will
// not be valid after.
self.each_live_alloc(true, |me, alloc| {
me.free(alloc);
});
}
unsafe fn each_live_alloc(&mut self, read_next_before: bool,
f: |&mut LocalHeap, alloc: *mut raw::GcBox<()>|) {
//! Walks the internal list of allocations
let mut alloc = self.live_allocs;
while alloc != ptr::null_mut() {
let next_before = (*alloc).next;
f(self, alloc);
if read_next_before {
alloc = next_before;
} else {
alloc = (*alloc).next;
}
}
}
}
impl Drop for LocalHeap {
fn drop(&mut self) {
unsafe { self.annihilate() }
assert!(self.live_allocs.is_null());
}
}
struct AllocHeader;
impl AllocHeader {
fn init(&mut self, _size: u32) {}
fn assert_sane(&self) {}
fn update_size(&mut self, _size: u32) {}
fn as_box(&mut self) -> *mut Box {
let myaddr: uint = unsafe { mem::transmute(self) };
(myaddr + AllocHeader::size()) as *mut Box
}
fn size() -> uint {
// For some platforms, 16 byte alignment is required.
let ptr_size = 16;
let header_size = mem::size_of::<AllocHeader>();
return (header_size + ptr_size - 1) / ptr_size * ptr_size;
}
fn from(a_box: *mut Box) -> *mut AllocHeader {
(a_box as uint - AllocHeader::size()) as *mut AllocHeader
}
}
#[cfg(unix)]
fn debug_mem() -> bool {
// FIXME: Need to port the environment struct to newsched
false
}
#[cfg(windows)]
fn debug_mem() -> bool {
false
}
impl MemoryRegion {
#[inline]
fn malloc(&mut self, size: uint) -> *mut Box {
let total_size = size + AllocHeader::size();
let alloc: *mut AllocHeader = unsafe {
libc_heap::malloc_raw(total_size) as *mut AllocHeader
};
let alloc: &mut AllocHeader = unsafe { mem::transmute(alloc) };
alloc.init(size as u32);
self.claim(alloc);
self.live_allocations += 1;
return alloc.as_box();
}
#[inline]
fn realloc(&mut self, alloc: *mut Box, size: uint) -> *mut Box {
rtassert!(!alloc.is_null());
let orig_alloc = AllocHeader::from(alloc);
unsafe { (*orig_alloc).assert_sane(); }
let total_size = size + AllocHeader::size();
let alloc: *mut AllocHeader = unsafe {
libc_heap::realloc_raw(orig_alloc as *mut u8, total_size) as *mut AllocHeader
};
let alloc: &mut AllocHeader = unsafe { mem::transmute(alloc) };
alloc.assert_sane();
alloc.update_size(size as u32);
self.update(alloc, orig_alloc as *mut AllocHeader);
return alloc.as_box();
}
#[inline]
fn free(&mut self, alloc: *mut Box) {
rtassert!(!alloc.is_null());
let alloc = AllocHeader::from(alloc);
unsafe {
(*alloc).assert_sane();
self.release(mem::transmute(alloc));
rtassert!(self.live_allocations > 0);
self.live_allocations -= 1;
free(alloc as *mut c_void)
}
}
#[inline]
fn claim(&mut self, _alloc: &mut AllocHeader) {}
#[inline]
fn release(&mut self, _alloc: &AllocHeader) {}
#[inline]
fn update(&mut self, _alloc: &mut AllocHeader, _orig: *mut AllocHeader) {}
}
impl Drop for MemoryRegion {
fn drop(&mut self) {
if self.live_allocations != 0 {
rtabort!("leaked managed memory ({} objects)", self.live_allocations);
}
}
}
#[cfg(not(test))]
#[lang="malloc"]
#[inline]
pub unsafe fn local_malloc_(drop_glue: fn(*mut u8), size: uint,
align: uint) -> *mut u8 {
local_malloc(drop_glue, size, align)
}
#[inline]
pub unsafe fn local_malloc(drop_glue: fn(*mut u8), size: uint,
align: uint) -> *mut u8 {
// FIXME: Unsafe borrow for speed. Lame.
let task: Option<*mut Task> = Local::try_unsafe_borrow();
match task {
Some(task) => {
(*task).heap.alloc(drop_glue, size, align) as *mut u8
}
None => rtabort!("local malloc outside of task")
}
}
#[cfg(not(test))]
#[lang="free"]
#[inline]
pub unsafe fn local_free_(ptr: *mut u8) {
local_free(ptr)
}
// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
// inside a landing pad may corrupt the state of the exception handler. If a
// problem occurs, call exit instead.
#[inline]
pub unsafe fn local_free(ptr: *mut u8) {
// FIXME: Unsafe borrow for speed. Lame.
let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
match task_ptr {
Some(task) => {
(*task).heap.free(ptr as *mut Box)
}
None => rtabort!("local free outside of task")
}
}
#[cfg(test)]
mod bench {
extern crate test;
use self::test::Bencher;
use std::gc::GC;
#[bench]
fn alloc_managed_small(b: &mut Bencher) {
b.iter(|| { box(GC) 10i });
}
#[bench]
fn alloc_managed_big(b: &mut Bencher) {
b.iter(|| { box(GC) ([10i, ..1000]) });
}
}

View File

@ -9,9 +9,8 @@
// except according to those terms. // except according to those terms.
//! Language-level runtime services that should reasonably expected //! Language-level runtime services that should reasonably expected
//! to be available 'everywhere'. Local heaps, GC, unwinding, //! to be available 'everywhere'. Unwinding, local storage, and logging.
//! local storage, and logging. Even a 'freestanding' Rust would likely want //! Even a 'freestanding' Rust would likely want to implement this.
//! to implement this.
use alloc::arc::Arc; use alloc::arc::Arc;
use alloc::boxed::{BoxAny, Box}; use alloc::boxed::{BoxAny, Box};
@ -27,7 +26,6 @@ use core::raw;
use local_data; use local_data;
use Runtime; use Runtime;
use local::Local; use local::Local;
use local_heap::LocalHeap;
use rtio::LocalIo; use rtio::LocalIo;
use unwind; use unwind;
use unwind::Unwinder; use unwind::Unwinder;
@ -95,8 +93,6 @@ use collections::str::SendStr;
/// # } /// # }
/// ``` /// ```
pub struct Task { pub struct Task {
pub heap: LocalHeap,
pub gc: GarbageCollector,
pub storage: LocalStorage, pub storage: LocalStorage,
pub unwinder: Unwinder, pub unwinder: Unwinder,
pub death: Death, pub death: Death,
@ -132,7 +128,6 @@ pub struct TaskOpts {
/// children tasks complete, recommend using a result future. /// children tasks complete, recommend using a result future.
pub type Result = ::core::result::Result<(), Box<Any + Send>>; pub type Result = ::core::result::Result<(), Box<Any + Send>>;
pub struct GarbageCollector;
pub struct LocalStorage(pub Option<local_data::Map>); pub struct LocalStorage(pub Option<local_data::Map>);
/// A handle to a blocked task. Usually this means having the Box<Task> /// A handle to a blocked task. Usually this means having the Box<Task>
@ -163,8 +158,6 @@ impl Task {
/// task creation functions through libnative or libgreen. /// task creation functions through libnative or libgreen.
pub fn new() -> Task { pub fn new() -> Task {
Task { Task {
heap: LocalHeap::new(),
gc: GarbageCollector,
storage: LocalStorage(None), storage: LocalStorage(None),
unwinder: Unwinder::new(), unwinder: Unwinder::new(),
death: Death::new(), death: Death::new(),
@ -264,32 +257,22 @@ impl Task {
/// already been destroyed and/or annihilated. /// already been destroyed and/or annihilated.
fn cleanup(self: Box<Task>, result: Result) -> Box<Task> { fn cleanup(self: Box<Task>, result: Result) -> Box<Task> {
// The first thing to do when cleaning up is to deallocate our local // The first thing to do when cleaning up is to deallocate our local
// resources, such as TLD and GC data. // resources, such as TLD.
// //
// FIXME: there are a number of problems with this code // FIXME: there are a number of problems with this code
// //
// 1. If any TLD object fails destruction, then all of TLD will leak. // 1. If any TLD object fails destruction, then all of TLD will leak.
// This appears to be a consequence of #14875. // This appears to be a consequence of #14875.
// //
// 2. Failing during GC annihilation aborts the runtime #14876. // 2. Setting a TLD key while destroying TLD will abort the runtime #14807.
// //
// 3. Setting a TLD key while destroying TLD or while destroying GC will // 3. The order of destruction of TLD matters, but either way is
// abort the runtime #14807. // susceptible to leaks (see 2) #8302.
//
// 4. Invoking GC in GC destructors will abort the runtime #6996.
//
// 5. The order of destruction of TLD and GC matters, but either way is
// susceptible to leaks (see 3/4) #8302.
// //
// That being said, there are a few upshots to this code // That being said, there are a few upshots to this code
// //
// 1. If TLD destruction fails, heap destruction will be attempted. // 1. If TLD destruction fails, heap destruction will be attempted.
// There is a test for this at fail-during-tld-destroy.rs. Sadly the // There is a test for this at fail-during-tld-destroy.rs.
// other way can't be tested due to point 2 above. Note that we must
// immortalize the heap first because if any deallocations are
// attempted while TLD is being dropped it will attempt to free the
// allocation from the wrong heap (because the current one has been
// replaced).
// //
// 2. One failure in destruction is tolerable, so long as the task // 2. One failure in destruction is tolerable, so long as the task
// didn't originally fail while it was running. // didn't originally fail while it was running.
@ -301,15 +284,10 @@ impl Task {
let &LocalStorage(ref mut optmap) = &mut task.storage; let &LocalStorage(ref mut optmap) = &mut task.storage;
optmap.take() optmap.take()
}; };
let mut heap = mem::replace(&mut task.heap, LocalHeap::new());
unsafe { heap.immortalize() }
drop(task); drop(task);
// First, destroy task-local storage. This may run user dtors. // First, destroy task-local storage. This may run user dtors.
drop(tld); drop(tld);
// Destroy remaining boxes. Also may run user dtors.
drop(heap);
}); });
// If the above `run` block failed, then it must be the case that the // If the above `run` block failed, then it must be the case that the
@ -327,9 +305,8 @@ impl Task {
Local::put(task); Local::put(task);
// FIXME: this is running in a seriously constrained context. If this // FIXME: this is running in a seriously constrained context. If this
// allocates GC or allocates TLD then it will likely abort the // allocates TLD then it will likely abort the runtime. Similarly,
// runtime. Similarly, if this fails, this will also likely abort // if this fails, this will also likely abort the runtime.
// the runtime.
// //
// This closure is currently limited to a channel send via the // This closure is currently limited to a channel send via the
// standard library's task interface, but this needs // standard library's task interface, but this needs
@ -577,23 +554,14 @@ mod test {
use super::*; use super::*;
use std::prelude::*; use std::prelude::*;
use std::task; use std::task;
use std::gc::{Gc, GC};
#[test]
fn local_heap() {
let a = box(GC) 5i;
let b = a;
assert!(*a == 5);
assert!(*b == 5);
}
#[test] #[test]
fn tls() { fn tls() {
local_data_key!(key: Gc<String>) local_data_key!(key: String)
key.replace(Some(box(GC) "data".to_string())); key.replace(Some("data".to_string()));
assert_eq!(key.get().unwrap().as_slice(), "data"); assert_eq!(key.get().unwrap().as_slice(), "data");
local_data_key!(key2: Gc<String>) local_data_key!(key2: String)
key2.replace(Some(box(GC) "data".to_string())); key2.replace(Some("data".to_string()));
assert_eq!(key2.get().unwrap().as_slice(), "data"); assert_eq!(key2.get().unwrap().as_slice(), "data");
} }
@ -628,23 +596,6 @@ mod test {
assert!(rx.recv() == 10); assert!(rx.recv() == 10);
} }
#[test]
fn heap_cycles() {
use std::cell::RefCell;
struct List {
next: Option<Gc<RefCell<List>>>,
}
let a = box(GC) RefCell::new(List { next: None });
let b = box(GC) RefCell::new(List { next: Some(a) });
{
let mut a = a.borrow_mut();
a.next = Some(b);
}
}
#[test] #[test]
#[should_fail] #[should_fail]
fn test_begin_unwind() { fn test_begin_unwind() {

View File

@ -23,7 +23,7 @@ Core encoding and decoding interfaces.
html_favicon_url = "http://www.rust-lang.org/favicon.ico", html_favicon_url = "http://www.rust-lang.org/favicon.ico",
html_root_url = "http://doc.rust-lang.org/master/", html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")] html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, managed_boxes, default_type_params, phase)] #![feature(macro_rules, default_type_params, phase)]
// test harness access // test harness access
#[cfg(test)] #[cfg(test)]

View File

@ -16,7 +16,6 @@ Core encoding and decoding interfaces.
use std::path; use std::path;
use std::rc::Rc; use std::rc::Rc;
use std::gc::{Gc, GC};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
pub trait Encoder<E> { pub trait Encoder<E> {
@ -392,12 +391,6 @@ impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for Box<T> {
} }
} }
impl<E, S:Encoder<E>,T:'static + Encodable<S, E>> Encodable<S, E> for Gc<T> {
fn encode(&self, s: &mut S) -> Result<(), E> {
(**self).encode(s)
}
}
impl<E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for Rc<T> { impl<E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for Rc<T> {
#[inline] #[inline]
fn encode(&self, s: &mut S) -> Result<(), E> { fn encode(&self, s: &mut S) -> Result<(), E> {
@ -412,12 +405,6 @@ impl<E, D:Decoder<E>,T:Decodable<D, E>> Decodable<D, E> for Rc<T> {
} }
} }
impl<E, D:Decoder<E>,T:Decodable<D, E> + 'static> Decodable<D, E> for Gc<T> {
fn decode(d: &mut D) -> Result<Gc<T>, E> {
Ok(box(GC) try!(Decodable::decode(d)))
}
}
impl<'a, E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for &'a [T] { impl<'a, E, S:Encoder<E>,T:Encodable<S, E>> Encodable<S, E> for &'a [T] {
fn encode(&self, s: &mut S) -> Result<(), E> { fn encode(&self, s: &mut S) -> Result<(), E> {
s.emit_seq(self.len(), |s| { s.emit_seq(self.len(), |s| {

View File

@ -1,156 +0,0 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
/*! Task-local garbage-collected boxes
The `Gc` type provides shared ownership of an immutable value. Destruction is not deterministic, and
will occur some time between every `Gc` handle being gone and the end of the task. The garbage
collector is task-local so `Gc<T>` is not sendable.
*/
#![experimental]
#![allow(experimental)]
use clone::Clone;
use cmp::{Ord, PartialOrd, Ordering, Eq, PartialEq};
use default::Default;
use fmt;
use hash;
use kinds::marker;
use option::Option;
use ops::Deref;
use raw;
/// Immutable garbage-collected pointer type
#[lang="gc"]
#[experimental = "Gc is currently based on reference-counting and will not collect cycles until \
task annihilation. For now, cycles need to be broken manually by using `Rc<T>` \
with a non-owning `Weak<T>` pointer. A tracing garbage collector is planned."]
pub struct Gc<T> {
_ptr: *mut T,
marker: marker::NoSend,
}
#[unstable]
impl<T> Clone for Gc<T> {
/// Clone the pointer only
#[inline]
fn clone(&self) -> Gc<T> { *self }
}
/// An value that represents the task-local managed heap.
///
/// Use this like `let foo = box(GC) Bar::new(...);`
#[lang="managed_heap"]
#[cfg(not(test))]
pub static GC: () = ();
impl<T: PartialEq + 'static> PartialEq for Gc<T> {
#[inline]
fn eq(&self, other: &Gc<T>) -> bool { *(*self) == *(*other) }
#[inline]
fn ne(&self, other: &Gc<T>) -> bool { *(*self) != *(*other) }
}
impl<T: PartialOrd + 'static> PartialOrd for Gc<T> {
#[inline]
fn partial_cmp(&self, other: &Gc<T>) -> Option<Ordering> {
(**self).partial_cmp(&**other)
}
#[inline]
fn lt(&self, other: &Gc<T>) -> bool { *(*self) < *(*other) }
#[inline]
fn le(&self, other: &Gc<T>) -> bool { *(*self) <= *(*other) }
#[inline]
fn ge(&self, other: &Gc<T>) -> bool { *(*self) >= *(*other) }
#[inline]
fn gt(&self, other: &Gc<T>) -> bool { *(*self) > *(*other) }
}
impl<T: Ord + 'static> Ord for Gc<T> {
#[inline]
fn cmp(&self, other: &Gc<T>) -> Ordering { (**self).cmp(&**other) }
}
impl<T: Eq + 'static> Eq for Gc<T> {}
impl<T: 'static> Deref<T> for Gc<T> {
fn deref<'a>(&'a self) -> &'a T { &**self }
}
impl<T: Default + 'static> Default for Gc<T> {
fn default() -> Gc<T> {
box(GC) Default::default()
}
}
impl<T: 'static> raw::Repr<*const raw::GcBox<T>> for Gc<T> {}
impl<S: hash::Writer, T: hash::Hash<S> + 'static> hash::Hash<S> for Gc<T> {
fn hash(&self, s: &mut S) {
(**self).hash(s)
}
}
impl<T: 'static + fmt::Show> fmt::Show for Gc<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(**self).fmt(f)
}
}
#[cfg(test)]
mod tests {
use prelude::*;
use super::*;
use cell::RefCell;
#[test]
fn test_managed_clone() {
let a = box(GC) 5i;
let b: Gc<int> = a.clone();
assert!(a == b);
}
#[test]
fn test_clone() {
let x = Gc::new(RefCell::new(5));
let y = x.clone();
*x.borrow().borrow_mut() = 20;
assert_eq!(*y.borrow().borrow(), 20);
}
#[test]
fn test_simple() {
let x = Gc::new(5);
assert_eq!(*x.borrow(), 5);
}
#[test]
fn test_simple_clone() {
let x = Gc::new(5);
let y = x.clone();
assert_eq!(*x.borrow(), 5);
assert_eq!(*y.borrow(), 5);
}
#[test]
fn test_ptr_eq() {
let x = Gc::new(5);
let y = x.clone();
let z = Gc::new(7);
assert!(x.ptr_eq(&x));
assert!(x.ptr_eq(&y));
assert!(!x.ptr_eq(&z));
}
#[test]
fn test_destructor() {
let x = Gc::new(box 5);
assert_eq!(**x.borrow(), 5);
}
}

View File

@ -958,7 +958,9 @@ mod tests {
// don't check windows magical empty-named variables // don't check windows magical empty-named variables
assert!(k.is_empty() || assert!(k.is_empty() ||
output.as_slice() output.as_slice()
.contains(format!("{}={}", *k, *v).as_slice())); .contains(format!("{}={}", *k, *v).as_slice()),
"output doesn't contain `{}={}`\n{}",
k, v, output);
} }
} }
#[cfg(target_os="android")] #[cfg(target_os="android")]

View File

@ -105,7 +105,7 @@
html_root_url = "http://doc.rust-lang.org/master/", html_root_url = "http://doc.rust-lang.org/master/",
html_playground_url = "http://play.rust-lang.org/")] html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, globs, managed_boxes, linkage)] #![feature(macro_rules, globs, linkage)]
#![feature(default_type_params, phase, lang_items, unsafe_destructor)] #![feature(default_type_params, phase, lang_items, unsafe_destructor)]
#![feature(import_shadowing)] #![feature(import_shadowing)]
@ -136,7 +136,6 @@ extern crate rustrt;
#[cfg(test)] pub use realstd::cmp; #[cfg(test)] pub use realstd::cmp;
#[cfg(test)] pub use realstd::ty; #[cfg(test)] pub use realstd::ty;
#[cfg(test)] pub use realstd::boxed; #[cfg(test)] pub use realstd::boxed;
#[cfg(test)] pub use realstd::gc;
// NB: These reexports are in the order they should be listed in rustdoc // NB: These reexports are in the order they should be listed in rustdoc
@ -219,9 +218,6 @@ pub mod rand;
pub mod ascii; pub mod ascii;
#[cfg(not(test))]
pub mod gc;
pub mod time; pub mod time;
/* Common traits */ /* Common traits */

View File

@ -201,12 +201,13 @@ mod test {
#[test] #[test]
fn test_sendable_future() { fn test_sendable_future() {
let expected = "schlorf"; let expected = "schlorf";
let (tx, rx) = channel();
let f = Future::spawn(proc() { expected }); let f = Future::spawn(proc() { expected });
task::spawn(proc() { task::spawn(proc() {
let mut f = f; let mut f = f;
let actual = f.get(); tx.send(f.get());
assert_eq!(actual, expected);
}); });
assert_eq!(rx.recv(), expected);
} }
#[test] #[test]

View File

@ -416,7 +416,6 @@ pub enum BinOp {
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
pub enum UnOp { pub enum UnOp {
UnBox,
UnUniq, UnUniq,
UnDeref, UnDeref,
UnNot, UnNot,
@ -953,7 +952,6 @@ pub struct UnboxedFnTy {
pub enum Ty_ { pub enum Ty_ {
TyNil, TyNil,
TyBot, /* bottom type */ TyBot, /* bottom type */
TyBox(P<Ty>),
TyUniq(P<Ty>), TyUniq(P<Ty>),
TyVec(P<Ty>), TyVec(P<Ty>),
TyFixedLengthVec(P<Ty>, P<Expr>), TyFixedLengthVec(P<Ty>, P<Expr>),

View File

@ -90,7 +90,6 @@ pub fn is_shift_binop(b: BinOp) -> bool {
pub fn unop_to_string(op: UnOp) -> &'static str { pub fn unop_to_string(op: UnOp) -> &'static str {
match op { match op {
UnBox => "box(GC) ",
UnUniq => "box() ", UnUniq => "box() ",
UnDeref => "*", UnDeref => "*",
UnNot => "!", UnNot => "!",

View File

@ -112,7 +112,6 @@ pub trait AstBuilder {
fn expr_deref(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr>; fn expr_deref(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr>;
fn expr_unary(&self, sp: Span, op: ast::UnOp, e: P<ast::Expr>) -> P<ast::Expr>; fn expr_unary(&self, sp: Span, op: ast::UnOp, e: P<ast::Expr>) -> P<ast::Expr>;
fn expr_managed(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr>;
fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr>; fn expr_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr>;
fn expr_mut_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr>; fn expr_mut_addr_of(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr>;
fn expr_field_access(&self, span: Span, expr: P<ast::Expr>, ident: ast::Ident) -> P<ast::Expr>; fn expr_field_access(&self, span: Span, expr: P<ast::Expr>, ident: ast::Ident) -> P<ast::Expr>;
@ -565,10 +564,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
self.expr(sp, ast::ExprUnary(op, e)) self.expr(sp, ast::ExprUnary(op, e))
} }
fn expr_managed(&self, sp: Span, e: P<ast::Expr>) -> P<ast::Expr> {
self.expr_unary(sp, ast::UnBox, e)
}
fn expr_field_access(&self, sp: Span, expr: P<ast::Expr>, ident: ast::Ident) -> P<ast::Expr> { fn expr_field_access(&self, sp: Span, expr: P<ast::Expr>, ident: ast::Ident) -> P<ast::Expr> {
let field_name = token::get_ident(ident); let field_name = token::get_ident(ident);
let field_span = Span { let field_span = Span {

View File

@ -40,7 +40,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
("struct_variant", Active), ("struct_variant", Active),
("once_fns", Active), ("once_fns", Active),
("asm", Active), ("asm", Active),
("managed_boxes", Active), ("managed_boxes", Removed),
("non_ascii_idents", Active), ("non_ascii_idents", Active),
("thread_local", Active), ("thread_local", Active),
("link_args", Active), ("link_args", Active),
@ -135,14 +135,6 @@ impl<'a> Context<'a> {
} }
} }
fn gate_box(&self, span: Span) {
self.gate_feature("managed_boxes", span,
"The managed box syntax is being replaced by the \
`std::gc::Gc` and `std::rc::Rc` types. Equivalent \
functionality to managed trait objects will be \
implemented but is currently missing.");
}
fn has_feature(&self, feature: &str) -> bool { fn has_feature(&self, feature: &str) -> bool {
self.features.iter().any(|n| n.as_slice() == feature) self.features.iter().any(|n| n.as_slice() == feature)
} }
@ -330,7 +322,6 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
experimental and likely to be removed"); experimental and likely to be removed");
}, },
ast::TyBox(_) => { self.gate_box(t.span); }
ast::TyUnboxedFn(..) => { ast::TyUnboxedFn(..) => {
self.gate_feature("unboxed_closure_sugar", self.gate_feature("unboxed_closure_sugar",
t.span, t.span,
@ -344,9 +335,6 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
fn visit_expr(&mut self, e: &ast::Expr) { fn visit_expr(&mut self, e: &ast::Expr) {
match e.node { match e.node {
ast::ExprUnary(ast::UnBox, _) => {
self.gate_box(e.span);
}
ast::ExprUnboxedFn(..) => { ast::ExprUnboxedFn(..) => {
self.gate_feature("unboxed_closures", self.gate_feature("unboxed_closures",
e.span, e.span,

View File

@ -372,7 +372,6 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
id: fld.new_id(id), id: fld.new_id(id),
node: match node { node: match node {
TyNil | TyBot | TyInfer => node, TyNil | TyBot | TyInfer => node,
TyBox(ty) => TyBox(fld.fold_ty(ty)),
TyUniq(ty) => TyUniq(fld.fold_ty(ty)), TyUniq(ty) => TyUniq(fld.fold_ty(ty)),
TyVec(ty) => TyVec(fld.fold_ty(ty)), TyVec(ty) => TyVec(fld.fold_ty(ty)),
TyPtr(mt) => TyPtr(fld.fold_mt(mt)), TyPtr(mt) => TyPtr(fld.fold_mt(mt)),

View File

@ -31,8 +31,6 @@ pub enum ObsoleteSyntax {
ObsoleteOwnedPattern, ObsoleteOwnedPattern,
ObsoleteOwnedVector, ObsoleteOwnedVector,
ObsoleteOwnedSelf, ObsoleteOwnedSelf,
ObsoleteManagedType,
ObsoleteManagedExpr,
ObsoleteImportRenaming, ObsoleteImportRenaming,
ObsoleteSubsliceMatch, ObsoleteSubsliceMatch,
ObsoleteExternCrateRenaming, ObsoleteExternCrateRenaming,
@ -77,14 +75,6 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
"`~self` is no longer supported", "`~self` is no longer supported",
"write `self: Box<Self>` instead" "write `self: Box<Self>` instead"
), ),
ObsoleteManagedType => (
"`@` notation for managed pointers",
"use `Gc<T>` in `std::gc` instead"
),
ObsoleteManagedExpr => (
"`@` notation for a managed pointer allocation",
"use the `box(GC)` operator instead of `@`"
),
ObsoleteImportRenaming => ( ObsoleteImportRenaming => (
"`use foo = bar` syntax", "`use foo = bar` syntax",
"write `use bar as foo` instead" "write `use bar as foo` instead"

Some files were not shown because too many files have changed in this diff Show More