mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
auto merge of #17725 : alexcrichton/rust/rollup, r=alexcrichton
This commit is contained in:
commit
aa034cd3ba
64
.travis.yml
64
.travis.yml
@ -1,60 +1,26 @@
|
||||
# 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
|
||||
# it treats unknown languages as ruby-like I believe.
|
||||
# RVM/bundler/ruby and whatnot. Right now 'rust' as a language actually
|
||||
# downloads a rust/cargo snapshot, which we don't really want for building rust.
|
||||
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:
|
||||
- sudo sh -c "echo 'deb http://llvm.org/apt/precise/ llvm-toolchain-precise-3.4 main' >> /etc/apt/sources.list"
|
||||
- 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 add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq --force-yes -y llvm-$LLVM_VERSION
|
||||
llvm-${LLVM_VERSION}-dev clang-$LLVM_VERSION lldb-$LLVM_VERSION
|
||||
- sudo apt-get install g++-4.7
|
||||
|
||||
|
||||
# All of the llvm tools are suffixed with "-$VERS" which we don't want, so
|
||||
# symlink them all into a local directory and just use that
|
||||
# The test suite is in general way too stressful for travis, especially in
|
||||
# terms of time limit and reliability. In the past we've tried to scale things
|
||||
# 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
|
||||
# it's gotta download so much stuff.
|
||||
# As a result, we're just using travis to run `make tidy` now. It'll help
|
||||
# everyone find out about their trailing spaces early on!
|
||||
before_script:
|
||||
- mkdir -p local-llvm/bin
|
||||
- ln -nsf /usr/bin/llvm-config-$LLVM_VERSION local-llvm/bin/llvm-config
|
||||
- ln -nsf /usr/bin/llvm-mc-$LLVM_VERSION local-llvm/bin/llvm-mc
|
||||
- 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
|
||||
- ./configure
|
||||
script:
|
||||
- make tidy
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
@ -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/vg,, \
|
||||
$(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}
|
||||
# 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
|
||||
|
3
mk/rt.mk
3
mk/rt.mk
@ -35,7 +35,7 @@
|
||||
# that's per-target so you're allowed to conditionally add files based on the
|
||||
# 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
|
||||
|
||||
# $(1) is the target triple
|
||||
@ -50,7 +50,6 @@ NATIVE_DEPS_hoedown_$(1) := hoedown/src/autolink.c \
|
||||
hoedown/src/html_smartypants.c \
|
||||
hoedown/src/stack.c \
|
||||
hoedown/src/version.c
|
||||
NATIVE_DEPS_uv_support_$(1) := rust_uv.c
|
||||
NATIVE_DEPS_miniz_$(1) = miniz.c
|
||||
NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
|
||||
rust_android_dummy.c
|
||||
|
@ -305,10 +305,9 @@ copying.
|
||||
# Circle(Point, f64), // origin, radius
|
||||
# Rectangle(Point, Size) // upper-left, dimensions
|
||||
# }
|
||||
# static tau: f64 = 6.28;
|
||||
fn compute_area(shape: &Shape) -> f64 {
|
||||
match *shape {
|
||||
Circle(_, radius) => 0.5 * tau * radius * radius,
|
||||
Circle(_, radius) => std::f64::consts::PI * radius * radius,
|
||||
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
|
||||
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
|
||||
circle constant][tau] and not that dreadfully outdated notion of pi).
|
||||
|
||||
[tau]: http://www.math.utah.edu/~palais/pi.html
|
||||
area of the circle.
|
||||
|
||||
The second match is more interesting. Here we match against a
|
||||
rectangle and extract its size: but rather than copy the `size`
|
||||
|
@ -632,19 +632,6 @@ 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
|
||||
|
||||
This part is coming soon.
|
||||
|
@ -31,7 +31,6 @@ list):
|
||||
* Task synchronization
|
||||
* Task-local storage
|
||||
* Logging
|
||||
* Local heaps (GC heaps)
|
||||
* Task unwinding
|
||||
|
||||
## What is the runtime accomplishing?
|
||||
|
@ -208,9 +208,7 @@ pub struct Unique<T> {
|
||||
// Implement methods for creating and using the values in the box.
|
||||
|
||||
// NB: For simplicity and correctness, we require that T has kind Send
|
||||
// (owned boxes relax this restriction, and can contain managed (GC) boxes).
|
||||
// This is because, as implemented, the garbage collector would not know
|
||||
// about any shared boxes stored in the malloc'd region of memory.
|
||||
// (owned boxes relax this restriction).
|
||||
impl<T: Send> Unique<T> {
|
||||
pub fn new(value: T) -> Unique<T> {
|
||||
unsafe {
|
||||
|
@ -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
|
||||
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
|
||||
means that you're calling a macro instead of a normal function. 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
|
||||
means that you're calling a macro instead of a normal function. Rust implements
|
||||
`println!` as a macro rather than a function for good reasons, but that's a
|
||||
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.
|
||||
|
||||
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
|
||||
special type in Rust's type system. `()` is different than `null` in other
|
||||
languages, because `()` is distinct from other types. For example, in C, `null`
|
||||
is a valid value for a variable of type `int`. In Rust, `()` is _not_ a valid
|
||||
value for a variable of type `int`. It's only a valid value for variables of
|
||||
the type `()`, which aren't very useful. Remember how we said statements don't
|
||||
return a value? Well, that's the purpose of unit in this case. The semicolon
|
||||
turns any expression into a statement by throwing away its value and returning
|
||||
unit instead.
|
||||
special type in Rust's type system. In Rust, `()` is _not_ a valid value for a
|
||||
variable of type `int`. It's only a valid value for variables of the type `()`,
|
||||
which aren't very useful. Remember how we said statements don't return a value?
|
||||
Well, that's the purpose of unit in this case. The semicolon 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
|
||||
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
|
||||
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
|
||||
input, our program doesn't work, so we're okay with that. In most cases, we
|
||||
would want to handle the error case explicitly. The result of `ok()` has a
|
||||
method, `expect()`, which allows us to give an error message if this crash
|
||||
happens.
|
||||
We then call `expect()` on the result, which will terminate our program if we
|
||||
don't have a valid value. In this case, if we can't get input, our program
|
||||
doesn't work, so we're okay with that. In most cases, we would want to handle
|
||||
the error case explicitly. `expect()` allows us to give an error message if
|
||||
this crash happens.
|
||||
|
||||
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.
|
||||
@ -2030,7 +2030,7 @@ fn main() {
|
||||
match cmp(input, secret_number) {
|
||||
Less => println!("Too small!"),
|
||||
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}
|
||||
$ cargo run
|
||||
@ -3291,8 +3292,7 @@ use super::times_four;
|
||||
|
||||
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
|
||||
the parent. We sometimes call this usage of `use` a 're-export,' because we're
|
||||
exporting the name again, somewhere else.
|
||||
the parent.
|
||||
|
||||
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
|
||||
|
@ -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:
|
||||
|
||||
```
|
||||
|
@ -373,14 +373,6 @@
|
||||
fun:_ZN4llvm4UsernwEjj
|
||||
}
|
||||
|
||||
{
|
||||
libuv-0-byte-realloc
|
||||
Memcheck:Leak
|
||||
fun:malloc
|
||||
...
|
||||
fun:*uv_loop_delete*
|
||||
}
|
||||
|
||||
{
|
||||
race-or-something-ask-pcwalton-0
|
||||
Memcheck:Value4
|
||||
@ -502,15 +494,3 @@
|
||||
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
|
||||
...
|
||||
}
|
||||
|
@ -182,9 +182,15 @@ mod imp {
|
||||
|
||||
#[inline]
|
||||
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);
|
||||
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]
|
||||
@ -250,9 +256,9 @@ mod imp {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn reallocate_inplace(_ptr: *mut u8, _size: uint, _align: uint,
|
||||
_old_size: uint) -> bool {
|
||||
false
|
||||
pub unsafe fn reallocate_inplace(_ptr: *mut u8, size: uint, _align: uint,
|
||||
old_size: uint) -> bool {
|
||||
size == old_size
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -312,9 +318,9 @@ mod imp {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn reallocate_inplace(_ptr: *mut u8, _size: uint, _align: uint,
|
||||
_old_size: uint) -> bool {
|
||||
false
|
||||
pub unsafe fn reallocate_inplace(_ptr: *mut u8, size: uint, _align: uint,
|
||||
old_size: uint) -> bool {
|
||||
size == old_size
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -335,9 +341,21 @@ mod imp {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod bench {
|
||||
mod test {
|
||||
extern crate test;
|
||||
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]
|
||||
fn alloc_owned_small(b: &mut Bencher) {
|
||||
|
@ -92,7 +92,6 @@ pub use boxed as owned;
|
||||
|
||||
pub mod heap;
|
||||
pub mod libc_heap;
|
||||
pub mod util;
|
||||
|
||||
// Primitive types using the heaps above
|
||||
|
||||
|
@ -541,14 +541,6 @@ mod tests {
|
||||
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]
|
||||
fn weak_self_cyclic() {
|
||||
struct Cycle {
|
||||
|
@ -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)
|
||||
}
|
@ -46,12 +46,12 @@ struct AbsEntries<T> {
|
||||
}
|
||||
|
||||
/// 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>>
|
||||
}
|
||||
|
||||
/// 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>>
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
html_root_url = "http://doc.rust-lang.org/master/",
|
||||
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)]
|
||||
#![no_std]
|
||||
|
||||
|
@ -532,7 +532,6 @@ impl<T: fmt::Show> fmt::Show for RingBuf<T> {
|
||||
mod tests {
|
||||
use std::fmt::Show;
|
||||
use std::prelude::*;
|
||||
use std::gc::{GC, Gc};
|
||||
use std::hash;
|
||||
use test::Bencher;
|
||||
use test;
|
||||
@ -587,43 +586,6 @@ mod tests {
|
||||
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)]
|
||||
fn test_parameterized<T:Clone + PartialEq + Show>(a: T, b: T, c: T, d: T) {
|
||||
let mut deq = RingBuf::new();
|
||||
@ -755,12 +717,6 @@ mod tests {
|
||||
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]
|
||||
fn test_param_taggy() {
|
||||
test_parameterized::<Taggy>(One(1), Two(1, 2), Three(1, 2, 3), Two(17, 42));
|
||||
|
@ -791,11 +791,16 @@ impl<T> Vec<T> {
|
||||
#[inline]
|
||||
pub fn into_iter(self) -> MoveItems<T> {
|
||||
unsafe {
|
||||
let iter = mem::transmute(self.as_slice().iter());
|
||||
let ptr = self.ptr;
|
||||
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);
|
||||
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> {
|
||||
allocation: *mut T, // the block of memory allocated for the vector
|
||||
cap: uint, // the capacity of the vector
|
||||
iter: Items<'static, T>
|
||||
ptr: *const T,
|
||||
end: *const T
|
||||
}
|
||||
|
||||
impl<T> MoveItems<T> {
|
||||
@ -1728,7 +1734,7 @@ impl<T> MoveItems<T> {
|
||||
pub fn unwrap(mut self) -> Vec<T> {
|
||||
unsafe {
|
||||
for _x in self { }
|
||||
let MoveItems { allocation, cap, iter: _iter } = self;
|
||||
let MoveItems { allocation, cap, ptr: _ptr, end: _end } = self;
|
||||
mem::forget(self);
|
||||
Vec { ptr: allocation, cap: cap, len: 0 }
|
||||
}
|
||||
@ -1739,17 +1745,33 @@ impl<T> Iterator<T> for MoveItems<T> {
|
||||
#[inline]
|
||||
fn next<'a>(&'a mut self) -> Option<T> {
|
||||
unsafe {
|
||||
// Unsafely transmute from Items<'static, T> to Items<'a,
|
||||
// T> because otherwise the type checker requires that T
|
||||
// be bounded by 'static.
|
||||
let iter: &mut Items<'a, T> = mem::transmute(&mut self.iter);
|
||||
iter.next().map(|x| ptr::read(x))
|
||||
if self.ptr == self.end {
|
||||
None
|
||||
} else {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
// 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]
|
||||
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]
|
||||
fn next_back<'a>(&'a mut self) -> Option<T> {
|
||||
unsafe {
|
||||
// Unsafely transmute from Items<'static, T> to Items<'a,
|
||||
// T> because otherwise the type checker requires that T
|
||||
// be bounded by 'static.
|
||||
let iter: &mut Items<'a, T> = mem::transmute(&mut self.iter);
|
||||
iter.next_back().map(|x| ptr::read(x))
|
||||
if self.end == self.ptr {
|
||||
None
|
||||
} else {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
// 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());
|
||||
}
|
||||
|
||||
#[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]
|
||||
fn bench_new(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
|
@ -57,7 +57,7 @@
|
||||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
|
||||
#![no_std]
|
||||
#![feature(globs, intrinsics, lang_items, macro_rules, managed_boxes, phase)]
|
||||
#![feature(globs, intrinsics, lang_items, macro_rules, phase)]
|
||||
#![feature(simd, unsafe_destructor)]
|
||||
#![deny(missing_doc)]
|
||||
|
||||
|
@ -20,15 +20,6 @@
|
||||
|
||||
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
|
||||
pub struct Slice<T> {
|
||||
pub data: *const T,
|
||||
|
@ -1218,7 +1218,7 @@ macro_rules! iterator {
|
||||
|
||||
/// Immutable slice iterator
|
||||
#[experimental = "needs review"]
|
||||
pub struct Items<'a, T> {
|
||||
pub struct Items<'a, T: 'a> {
|
||||
ptr: *const T,
|
||||
end: *const T,
|
||||
marker: marker::ContravariantLifetime<'a>
|
||||
@ -1261,7 +1261,7 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> {
|
||||
|
||||
/// Mutable slice iterator.
|
||||
#[experimental = "needs review"]
|
||||
pub struct MutItems<'a, T> {
|
||||
pub struct MutItems<'a, T: 'a> {
|
||||
ptr: *mut T,
|
||||
end: *mut T,
|
||||
marker: marker::ContravariantLifetime<'a>,
|
||||
|
@ -528,9 +528,8 @@ fn test_rposition() {
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_rposition_fail() {
|
||||
use std::gc::GC;
|
||||
let v = [(box 0i, box(GC) 0i), (box 0i, box(GC) 0i),
|
||||
(box 0i, box(GC) 0i), (box 0i, box(GC) 0i)];
|
||||
let v = [(box 0i, box 0i), (box 0i, box 0i),
|
||||
(box 0i, box 0i), (box 0i, box 0i)];
|
||||
let mut i = 0i;
|
||||
v.iter().rposition(|_elt| {
|
||||
if i == 2 {
|
||||
|
@ -25,7 +25,7 @@
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/master/")]
|
||||
#![experimental]
|
||||
#![feature(managed_boxes, macro_rules)]
|
||||
#![feature(macro_rules)]
|
||||
#![allow(experimental)]
|
||||
|
||||
pub mod fmt;
|
||||
|
@ -18,7 +18,6 @@ Runtime type reflection
|
||||
|
||||
use std::intrinsics::{Disr, Opaque, TyDesc, TyVisitor};
|
||||
use std::mem;
|
||||
use std::gc::Gc;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
self.align_to::<Gc<u8>>();
|
||||
self.align_to::<Box<u8>>();
|
||||
if ! self.inner.visit_box(mtbl, inner) { return false; }
|
||||
self.bump_past::<Gc<u8>>();
|
||||
self.bump_past::<Box<u8>>();
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -274,13 +274,9 @@ impl<'a> TyVisitor for ReprVisitor<'a> {
|
||||
self.get::<&str>(|this, s| this.write_escaped_slice(*s))
|
||||
}
|
||||
|
||||
fn visit_box(&mut self, mtbl: uint, inner: *const TyDesc) -> bool {
|
||||
try!(self, self.writer.write("box(GC) ".as_bytes()));
|
||||
self.write_mut_qualifier(mtbl);
|
||||
self.get::<&raw::GcBox<()>>(|this, b| {
|
||||
let p = &b.data as *const () as *const u8;
|
||||
this.visit_ptr_inner(p, inner)
|
||||
})
|
||||
fn visit_box(&mut self, _mtbl: uint, _inner: *const TyDesc) -> bool {
|
||||
try!(self, self.writer.write("box(GC) ???".as_bytes()));
|
||||
true
|
||||
}
|
||||
|
||||
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::char::is_alphabetic;
|
||||
use std::mem::swap;
|
||||
use std::gc::GC;
|
||||
|
||||
fn exact_test<T>(t: &T, e:&str) {
|
||||
let mut m = io::MemWriter::new();
|
||||
@ -591,7 +586,6 @@ fn test_repr() {
|
||||
exact_test(&1.234f64, "1.234f64");
|
||||
exact_test(&("hello"), "\"hello\"");
|
||||
|
||||
exact_test(&(box(GC) 10i), "box(GC) 10");
|
||||
exact_test(&(box 10i), "box 10");
|
||||
exact_test(&(&10i), "&10");
|
||||
let mut x = 10i;
|
||||
@ -605,8 +599,6 @@ fn test_repr() {
|
||||
"&[\"hi\", \"there\"]");
|
||||
exact_test(&(P{a:10, b:1.234}),
|
||||
"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}),
|
||||
"box repr::P{a: 10, b: 1.234f64}");
|
||||
|
||||
|
@ -50,7 +50,7 @@ fn main() {
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/master/")]
|
||||
|
||||
#![feature(plugin_registrar, managed_boxes)]
|
||||
#![feature(plugin_registrar)]
|
||||
|
||||
extern crate syntax;
|
||||
extern crate rustc;
|
||||
|
@ -73,13 +73,13 @@ impl BasicLoop {
|
||||
RunRemote(i) => {
|
||||
match self.remotes.iter_mut().find(|& &(id, _)| id == i) {
|
||||
Some(&(_, ref mut f)) => f.call(),
|
||||
None => unreachable!()
|
||||
None => fail!("bad remote: {}", i),
|
||||
}
|
||||
}
|
||||
RemoveRemote(i) => {
|
||||
match self.remotes.iter().position(|&(id, _)| id == i) {
|
||||
Some(i) => { self.remotes.remove(i).unwrap(); }
|
||||
None => unreachable!()
|
||||
None => fail!("bad remote: {}", i),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ fn main() {
|
||||
#![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_root_url = "http://doc.rust-lang.org/master/")]
|
||||
#![feature(plugin_registrar, managed_boxes)]
|
||||
#![feature(plugin_registrar)]
|
||||
|
||||
extern crate syntax;
|
||||
extern crate rustc;
|
||||
|
@ -583,10 +583,11 @@ fn spawn_process_os(cfg: ProcessConfig,
|
||||
let mut bytes = [0, ..4];
|
||||
return match input.inner_read(bytes) {
|
||||
Ok(4) => {
|
||||
let errno = (bytes[0] << 24) as i32 |
|
||||
(bytes[1] << 16) as i32 |
|
||||
(bytes[2] << 8) as i32 |
|
||||
(bytes[3] << 0) as i32;
|
||||
let errno = (bytes[0] as i32 << 24) |
|
||||
(bytes[1] as i32 << 16) |
|
||||
(bytes[2] as i32 << 8) |
|
||||
(bytes[3] as i32 << 0);
|
||||
|
||||
Err(IoError {
|
||||
code: errno as uint,
|
||||
detail: None,
|
||||
@ -637,10 +638,10 @@ fn spawn_process_os(cfg: ProcessConfig,
|
||||
fn fail(output: &mut file::FileDesc) -> ! {
|
||||
let errno = os::errno();
|
||||
let bytes = [
|
||||
(errno << 24) as u8,
|
||||
(errno << 16) as u8,
|
||||
(errno << 8) as u8,
|
||||
(errno << 0) as u8,
|
||||
(errno >> 24) as u8,
|
||||
(errno >> 16) as u8,
|
||||
(errno >> 8) as u8,
|
||||
(errno >> 0) as u8,
|
||||
];
|
||||
assert!(output.inner_write(bytes).is_ok());
|
||||
unsafe { libc::_exit(1) }
|
||||
|
@ -19,7 +19,7 @@
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/master/")]
|
||||
|
||||
#![feature(plugin_registrar, managed_boxes, quote)]
|
||||
#![feature(plugin_registrar, quote)]
|
||||
|
||||
extern crate regex;
|
||||
extern crate syntax;
|
||||
|
@ -125,6 +125,21 @@ fn run_compiler(args: &[String]) {
|
||||
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
|
||||
/// message on failure.
|
||||
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))
|
||||
};
|
||||
|
||||
println!("{} {}", binary, env!("CFG_VERSION"));
|
||||
println!("{} {}", binary, option_env!("CFG_VERSION").unwrap_or("unknown version"));
|
||||
if verbose {
|
||||
fn unw(x: Option<&str>) -> &str { x.unwrap_or("unknown") }
|
||||
println!("binary: {}", binary);
|
||||
println!("commit-hash: {}", option_env!("CFG_VER_HASH").unwrap_or("unknown"));
|
||||
println!("commit-date: {}", option_env!("CFG_VER_DATE").unwrap_or("unknown"));
|
||||
println!("commit-hash: {}", unw(commit_hash_str()));
|
||||
println!("commit-date: {}", unw(commit_date_str()));
|
||||
println!("host: {}", driver::host_triple());
|
||||
println!("release: {}", env!("CFG_RELEASE"));
|
||||
println!("release: {}", unw(release_str()));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
@ -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,
|
||||
"use of owned (Box type) heap memory")
|
||||
|
||||
declare_lint!(HEAP_MEMORY, Allow,
|
||||
"use of any (Box type or @ type) heap memory")
|
||||
|
||||
pub struct HeapMemory;
|
||||
|
||||
impl HeapMemory {
|
||||
fn check_heap_type(&self, cx: &Context, span: Span, ty: ty::t) {
|
||||
let mut n_box = 0i;
|
||||
let mut n_uniq = 0i;
|
||||
ty::fold_ty(cx.tcx, ty, |t| {
|
||||
match ty::get(t).sty {
|
||||
ty::ty_box(_) => {
|
||||
n_box += 1;
|
||||
}
|
||||
ty::ty_uniq(_) |
|
||||
ty::ty_closure(box ty::ClosureTy {
|
||||
store: ty::UniqTraitStore,
|
||||
@ -449,21 +439,13 @@ impl HeapMemory {
|
||||
let s = ty_to_string(cx.tcx, ty);
|
||||
let m = format!("type uses owned (Box type) pointers: {}", s);
|
||||
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 {
|
||||
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) {
|
||||
@ -1289,7 +1271,7 @@ impl LintPass for UnnecessaryAllocation {
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||
match e.node {
|
||||
ast::ExprUnary(ast::UnUniq, _) | ast::ExprUnary(ast::UnBox, _) => (),
|
||||
ast::ExprUnary(ast::UnUniq, _) => (),
|
||||
_ => return
|
||||
}
|
||||
|
||||
|
@ -397,7 +397,6 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
|
||||
assert_eq!(next(st), '|');
|
||||
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_ptr(st.tcx, parse_mt(st, |x,y| conv(x,y))),
|
||||
'&' => {
|
||||
|
@ -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); }
|
||||
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_ptr(mt) => { mywrite!(w, "*"); enc_mt(w, cx, mt); }
|
||||
ty::ty_rptr(r, mt) => {
|
||||
|
@ -815,11 +815,6 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
mc::cat_deref(_, _, mc::GcPtr) => {
|
||||
assert_eq!(cmt.mutbl, mc::McImmutable);
|
||||
return;
|
||||
}
|
||||
|
||||
mc::cat_rvalue(..) |
|
||||
mc::cat_static_item |
|
||||
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
|
||||
|
@ -74,7 +74,7 @@ to an `LV` of `(*a).f`.
|
||||
Here is the formal grammar for the types we'll consider:
|
||||
|
||||
```text
|
||||
TY = () | S<'LT...> | Box<TY> | & 'LT MQ TY | @ MQ TY
|
||||
TY = () | S<'LT...> | Box<TY> | & 'LT MQ TY
|
||||
MQ = mut | imm | const
|
||||
```
|
||||
|
||||
@ -263,9 +263,7 @@ compatible with the aliasability of `LV`. The goal is to prevent
|
||||
`&mut` borrows of aliasability data.
|
||||
|
||||
3. `LIFETIME(LV, LT, MQ)`: The lifetime of the borrow does not exceed
|
||||
the lifetime of the value being borrowed. This pass is also
|
||||
responsible for inserting root annotations to keep managed values
|
||||
alive.
|
||||
the lifetime of the value being borrowed.
|
||||
|
||||
4. `RESTRICTIONS(LV, LT, ACTIONS) = RS`: This pass checks and computes the
|
||||
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
|
||||
|
||||
Immutable pointer types like `&T` and `@T` can only
|
||||
Immutable pointer types like `&T` can only
|
||||
be borrowed if MQ is immutable or const:
|
||||
|
||||
```text
|
||||
MUTABILITY(*LV, MQ) // M-Deref-Borrowed-Imm
|
||||
TYPE(LV) = &Ty
|
||||
MQ == imm | const
|
||||
|
||||
MUTABILITY(*LV, MQ) // M-Deref-Managed-Imm
|
||||
TYPE(LV) = @Ty
|
||||
MQ == imm | const
|
||||
```
|
||||
|
||||
### Checking mutability of mutable pointer types
|
||||
@ -390,11 +384,10 @@ ALIASABLE(*LV, MQ) // M-Deref-Borrowed-Mut
|
||||
## Checking lifetime
|
||||
|
||||
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.
|
||||
These two computations wind up being intimately related. Formally, we define
|
||||
a predicate `LIFETIME(LV, LT, MQ)`, which states that "the lvalue `LV` can be
|
||||
safely borrowed for the lifetime `LT` with mutability `MQ`". The Rust
|
||||
code corresponding to this predicate is the module
|
||||
its lifetime. These two computations wind up being intimately related.
|
||||
Formally, we define a predicate `LIFETIME(LV, LT, MQ)`, which states that
|
||||
"the lvalue `LV` can be safely borrowed for the lifetime `LT` with mutability
|
||||
`MQ`". The Rust code corresponding to this predicate is the module
|
||||
`middle::borrowck::gather_loans::lifetime`.
|
||||
|
||||
### 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>
|
||||
```
|
||||
|
||||
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
|
||||
pointer. This is a conservative approximation, since the data that
|
||||
the pointer points at may actually live longer:
|
||||
@ -477,59 +462,6 @@ LIFETIME(*LV, LT, MQ) // L-Deref-Borrowed
|
||||
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
|
||||
|
||||
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 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
|
||||
implies that issuing restrictions is useless. We might prevent the
|
||||
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
|
||||
restricting that path. Therefore, the rule for `&Ty` and `@Ty`
|
||||
pointers always returns an empty set of restrictions, and it only
|
||||
permits restricting `MUTATE` and `CLAIM` actions:
|
||||
restricting that path. Therefore, the rule for `&Ty` pointers
|
||||
always returns an empty set of restrictions, and it only permits
|
||||
restricting `MUTATE` and `CLAIM` actions:
|
||||
|
||||
```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
|
||||
TYPE(LV) = <' Ty
|
||||
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
|
||||
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
|
||||
words, those restrictions are already inherent in the type.
|
||||
borrow mutably the contents of a `&Ty` pointer. In other words,
|
||||
those restrictions are already inherent in the type.
|
||||
|
||||
Clause (1) in the rule for `&Ty` deserves mention. Here I
|
||||
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
|
||||
we can not prevent *anything* but moves in that case. So the
|
||||
`RESTRICTIONS` function is only defined if `ACTIONS` is the empty set.
|
||||
Because moves from a `&const` or `@const` lvalue are never legal, it
|
||||
is not necessary to add any restrictions at all to the final
|
||||
result.
|
||||
Because moves from a `&const` lvalue are never legal, it is not
|
||||
necessary to add any restrictions at all to the final result.
|
||||
|
||||
```text
|
||||
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
|
||||
@ -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
|
||||
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`).
|
||||
The bits are also killed when the root variables (`x`, `a`) go out of
|
||||
scope. Bits are unioned when two control-flow paths join. Thus, the
|
||||
Bits are unioned when two control-flow paths join. Thus, the
|
||||
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,
|
||||
we examine the bits in scope, and check that none of them are
|
||||
|
@ -132,7 +132,6 @@ fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt,
|
||||
match cmt.cat {
|
||||
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
|
||||
mc::cat_deref(_, _, mc::Implicit(..)) |
|
||||
mc::cat_deref(_, _, mc::GcPtr) |
|
||||
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
|
||||
mc::cat_upvar(..) | mc::cat_static_item |
|
||||
mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {
|
||||
|
@ -82,8 +82,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
|
||||
|
||||
mc::cat_downcast(ref base) |
|
||||
mc::cat_deref(ref base, _, mc::OwnedPtr) | // L-Deref-Send
|
||||
mc::cat_interior(ref base, _) | // L-Field
|
||||
mc::cat_deref(ref base, _, mc::GcPtr) => {
|
||||
mc::cat_interior(ref base, _) => { // L-Field
|
||||
self.check(base, discr_scope)
|
||||
}
|
||||
|
||||
@ -185,7 +184,6 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
|
||||
}
|
||||
mc::cat_downcast(ref cmt) |
|
||||
mc::cat_deref(ref cmt, _, mc::OwnedPtr) |
|
||||
mc::cat_deref(ref cmt, _, mc::GcPtr) |
|
||||
mc::cat_interior(ref cmt, _) |
|
||||
mc::cat_discr(ref cmt, _) => {
|
||||
self.scope(cmt)
|
||||
|
@ -114,7 +114,6 @@ fn report_cannot_move_out_of(bccx: &BorrowckCtxt, move_from: mc::cmt) {
|
||||
match move_from.cat {
|
||||
mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
|
||||
mc::cat_deref(_, _, mc::Implicit(..)) |
|
||||
mc::cat_deref(_, _, mc::GcPtr) |
|
||||
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
|
||||
mc::cat_upvar(..) | mc::cat_static_item |
|
||||
mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {
|
||||
|
@ -101,16 +101,13 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> {
|
||||
self.extend(result, cmt.mutbl, LpInterior(i))
|
||||
}
|
||||
|
||||
mc::cat_deref(cmt_base, _, pk @ mc::OwnedPtr) |
|
||||
mc::cat_deref(cmt_base, _, pk @ mc::GcPtr) => {
|
||||
mc::cat_deref(cmt_base, _, pk @ mc::OwnedPtr) => {
|
||||
// R-Deref-Send-Pointer
|
||||
//
|
||||
// When we borrow the interior of an owned pointer, we
|
||||
// cannot permit the base to be mutated, because that
|
||||
// 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
|
||||
// just rely on Deref<T> implementation.
|
||||
let result = self.restrict(cmt_base);
|
||||
|
@ -730,11 +730,6 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
|
||||
span,
|
||||
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 => {
|
||||
self.tcx.sess.span_err(
|
||||
span,
|
||||
|
@ -100,7 +100,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) {
|
||||
if v.in_const {
|
||||
match e.node {
|
||||
ExprUnary(UnDeref, _) => { }
|
||||
ExprUnary(UnBox, _) | ExprUnary(UnUniq, _) => {
|
||||
ExprUnary(UnUniq, _) => {
|
||||
span_err!(v.tcx.sess, e.span, E0010, "cannot do allocations in constant expressions");
|
||||
return;
|
||||
}
|
||||
@ -149,7 +149,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr) {
|
||||
}
|
||||
ExprCall(ref callee, _) => {
|
||||
match v.tcx.def_map.borrow().find(&callee.id) {
|
||||
Some(&DefStruct(..)) => {} // OK.
|
||||
Some(&DefStruct(..)) |
|
||||
Some(&DefVariant(..)) => {} // OK.
|
||||
_ => {
|
||||
span_err!(v.tcx.sess, e.span, E0015,
|
||||
|
@ -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)) => {
|
||||
assert_eq!(pats_len, len);
|
||||
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 {
|
||||
match ty::get(ty).sty {
|
||||
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_vec(_, None) => match *ctor {
|
||||
Slice(length) => length,
|
||||
@ -757,7 +752,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
||||
DefStatic(..) =>
|
||||
cx.tcx.sess.span_bug(pat_span, "static pattern should've been rewritten"),
|
||||
DefVariant(_, id, _) if *constructor != Variant(id) => None,
|
||||
DefVariant(..) | DefFn(..) | DefStruct(..) => {
|
||||
DefVariant(..) | DefStruct(..) => {
|
||||
Some(match args {
|
||||
&Some(ref args) => args.iter().map(|p| &**p).collect(),
|
||||
&None => Vec::from_elem(arity, &DUMMY_WILD_PAT)
|
||||
|
@ -115,10 +115,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckStaticVisitor<'a, 'tcx> {
|
||||
span_err!(self.tcx.sess, e.span, E0020,
|
||||
"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::ExprUnary(ast::UnUniq, _) => {
|
||||
span_err!(self.tcx.sess, e.span, E0022,
|
||||
|
@ -28,8 +28,8 @@ fn type_size_is_affected_by_type_parameters(tcx: &ty::ctxt, typ: ty::t)
|
||||
let mut result = false;
|
||||
ty::maybe_walk_ty(typ, |typ| {
|
||||
match ty::get(typ).sty {
|
||||
ty::ty_box(_) | ty::ty_uniq(_) | ty::ty_ptr(_) |
|
||||
ty::ty_rptr(..) | ty::ty_bare_fn(..) | ty::ty_closure(..) => {
|
||||
ty::ty_uniq(_) | ty::ty_ptr(_) | ty::ty_rptr(..) |
|
||||
ty::ty_bare_fn(..) | ty::ty_closure(..) => {
|
||||
false
|
||||
}
|
||||
ty::ty_param(_) => {
|
||||
|
@ -279,8 +279,6 @@ lets_do_this! {
|
||||
|
||||
ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
|
||||
ExchangeFreeFnLangItem, "exchange_free", exchange_free_fn;
|
||||
MallocFnLangItem, "malloc", malloc_fn;
|
||||
FreeFnLangItem, "free", free_fn;
|
||||
StrDupUniqFnLangItem, "strdup_uniq", strdup_uniq_fn;
|
||||
|
||||
StartFnLangItem, "start", start_fn;
|
||||
@ -293,9 +291,7 @@ lets_do_this! {
|
||||
|
||||
EhPersonalityLangItem, "eh_personality", eh_personality;
|
||||
|
||||
ManagedHeapLangItem, "managed_heap", managed_heap;
|
||||
ExchangeHeapLangItem, "exchange_heap", exchange_heap;
|
||||
GcLangItem, "gc", gc;
|
||||
OwnedBoxLangItem, "owned_box", owned_box;
|
||||
|
||||
CovariantTypeItem, "covariant_type", covariant_type;
|
||||
|
@ -104,7 +104,6 @@ pub struct CopiedUpvar {
|
||||
#[deriving(Clone, PartialEq, Eq, Hash)]
|
||||
pub enum PointerKind {
|
||||
OwnedPtr,
|
||||
GcPtr,
|
||||
BorrowedPtr(ty::BorrowKind, ty::Region),
|
||||
Implicit(ty::BorrowKind, ty::Region), // Implicit deref of a borrowed ptr.
|
||||
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)))
|
||||
}
|
||||
|
||||
ty::ty_box(..) => {
|
||||
Some(deref_ptr(GcPtr))
|
||||
}
|
||||
|
||||
ty::ty_ptr(ref mt) => {
|
||||
Some(deref_ptr(UnsafePtr(mt.mutbl)))
|
||||
}
|
||||
@ -302,9 +297,6 @@ impl MutabilityCategory {
|
||||
BorrowedPtr(borrow_kind, _) | Implicit(borrow_kind, _) => {
|
||||
MutabilityCategory::from_borrow_kind(borrow_kind)
|
||||
}
|
||||
GcPtr => {
|
||||
McImmutable
|
||||
}
|
||||
UnsafePtr(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)));
|
||||
}
|
||||
}
|
||||
Some(&def::DefFn(..)) |
|
||||
Some(&def::DefStruct(..)) => {
|
||||
for (i, subpat) in subpats.iter().enumerate() {
|
||||
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(..) => {
|
||||
"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))
|
||||
}
|
||||
}
|
||||
@ -1237,7 +1228,6 @@ pub enum InteriorSafety {
|
||||
}
|
||||
|
||||
pub enum AliasableReason {
|
||||
AliasableManaged,
|
||||
AliasableBorrowed,
|
||||
AliasableOther,
|
||||
AliasableStatic(InteriorSafety),
|
||||
@ -1256,7 +1246,6 @@ impl cmt_ {
|
||||
cat_copied_upvar(..) |
|
||||
cat_local(..) |
|
||||
cat_deref(_, _, UnsafePtr(..)) |
|
||||
cat_deref(_, _, GcPtr(..)) |
|
||||
cat_deref(_, _, BorrowedPtr(..)) |
|
||||
cat_deref(_, _, Implicit(..)) |
|
||||
cat_upvar(..) => {
|
||||
@ -1320,10 +1309,6 @@ impl cmt_ {
|
||||
}
|
||||
}
|
||||
|
||||
cat_deref(_, _, GcPtr) => {
|
||||
Some(AliasableManaged)
|
||||
}
|
||||
|
||||
cat_deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) |
|
||||
cat_deref(_, _, Implicit(ty::ImmBorrow, _)) => {
|
||||
Some(AliasableBorrowed)
|
||||
@ -1371,7 +1356,6 @@ impl Repr for categorization {
|
||||
pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
|
||||
match ptr {
|
||||
OwnedPtr => "Box",
|
||||
GcPtr => "Gc",
|
||||
BorrowedPtr(ty::ImmBorrow, _) |
|
||||
Implicit(ty::ImmBorrow, _) => "&",
|
||||
BorrowedPtr(ty::MutBorrow, _) |
|
||||
|
@ -931,15 +931,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
|
||||
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 => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -1824,6 +1824,11 @@ impl<'a> Resolver<'a> {
|
||||
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(..) => {
|
||||
debug!("(building reduced graph for external \
|
||||
crate) building value (fn/static) {}", final_ident);
|
||||
|
@ -104,11 +104,6 @@ pub fn ty_is_local(tcx: &ty::ctxt,
|
||||
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_ptr(ty::mt { ty: t, .. }) |
|
||||
ty::ty_rptr(_, ty::mt { ty: t, .. }) => {
|
||||
|
@ -713,23 +713,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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>
|
||||
match bound {
|
||||
ty::BoundCopy => {
|
||||
|
@ -698,7 +698,6 @@ fn any_irrefutable_adt_pat(tcx: &ty::ctxt, m: &[Match], col: uint) -> bool {
|
||||
}
|
||||
ast::PatEnum(..) | ast::PatIdent(_, _, None) => {
|
||||
match tcx.def_map.borrow().find(&pat.id) {
|
||||
Some(&def::DefFn(..)) |
|
||||
Some(&def::DefStruct(..)) => true,
|
||||
_ => false
|
||||
}
|
||||
@ -1646,7 +1645,6 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(def::DefFn(..)) |
|
||||
Some(def::DefStruct(..)) => {
|
||||
match *sub_pats {
|
||||
None => {
|
||||
|
@ -321,9 +321,6 @@ impl Case {
|
||||
_ => return Some(ThinPointer(i))
|
||||
},
|
||||
|
||||
// Gc<T> is just a pointer
|
||||
ty::ty_box(..) => return Some(ThinPointer(i)),
|
||||
|
||||
// Functions are just pointers
|
||||
ty::ty_bare_fn(..) => return Some(ThinPointer(i)),
|
||||
|
||||
|
@ -397,36 +397,6 @@ pub fn malloc_raw_dyn_proc<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: ty::t) -> Resu
|
||||
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
|
||||
|
||||
pub fn get_tydesc(ccx: &CrateContext, t: ty::t) -> Rc<tydesc_info> {
|
||||
|
@ -960,7 +960,6 @@ impl Cleanup for DropValue {
|
||||
}
|
||||
|
||||
pub enum Heap {
|
||||
HeapManaged,
|
||||
HeapExchange
|
||||
}
|
||||
|
||||
@ -986,9 +985,6 @@ impl Cleanup for FreeValue {
|
||||
apply_debug_loc(bcx.fcx, debug_loc);
|
||||
|
||||
match self.heap {
|
||||
HeapManaged => {
|
||||
glue::trans_free(bcx, self.ptr)
|
||||
}
|
||||
HeapExchange => {
|
||||
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);
|
||||
|
||||
match self.heap {
|
||||
HeapManaged => {
|
||||
glue::trans_free(bcx, self.ptr)
|
||||
}
|
||||
HeapExchange => {
|
||||
glue::trans_exchange_free_dyn(bcx, self.ptr, self.size, self.align)
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool {
|
||||
use middle::trans::type_of::sizing_type_of;
|
||||
|
||||
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) ||
|
||||
type_is_newtype_immediate(ccx, ty) || ty::type_is_bot(ty) ||
|
||||
ty::type_is_simd(tcx, ty);
|
||||
|
@ -421,7 +421,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
let ty = ty::expr_ty(cx.tcx(), &**e);
|
||||
let is_float = ty::type_is_fp(ty);
|
||||
return (match u {
|
||||
ast::UnBox | ast::UnUniq | ast::UnDeref => {
|
||||
ast::UnUniq | ast::UnDeref => {
|
||||
let (dv, _dt) = const_deref(cx, te, ty, true);
|
||||
dv
|
||||
}
|
||||
@ -547,6 +547,9 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
(expr::cast_integral, expr::cast_pointer) => {
|
||||
llvm::LLVMConstIntToPtr(v, llty.to_ref())
|
||||
}
|
||||
(expr::cast_pointer, expr::cast_integral) => {
|
||||
llvm::LLVMConstPtrToInt(v, llty.to_ref())
|
||||
}
|
||||
_ => {
|
||||
cx.sess().impossible_case(e.span,
|
||||
"bad combination of types for cast")
|
||||
|
@ -20,7 +20,6 @@ use middle::trans::common::*;
|
||||
use middle::trans::cleanup;
|
||||
use middle::trans::cleanup::CleanupMethods;
|
||||
use middle::trans::expr;
|
||||
use middle::trans::glue;
|
||||
use middle::trans::tvec;
|
||||
use middle::trans::type_of;
|
||||
use middle::ty;
|
||||
@ -240,14 +239,9 @@ impl KindOps for Lvalue {
|
||||
*/
|
||||
|
||||
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
|
||||
let () = zero_mem(bcx, val, ty);
|
||||
bcx
|
||||
} else {
|
||||
// incr. refcount for @T or newtype'd @T
|
||||
glue::take_ty(bcx, val, ty)
|
||||
}
|
||||
// cancel cleanup of affine values by zeroing out
|
||||
let () = zero_mem(bcx, val, ty);
|
||||
bcx
|
||||
} else {
|
||||
bcx
|
||||
}
|
||||
@ -567,15 +561,15 @@ impl<K:KindOps> Datum<K> {
|
||||
* is moved).
|
||||
*/
|
||||
|
||||
self.shallow_copy(bcx, dst);
|
||||
self.shallow_copy_raw(bcx, dst);
|
||||
|
||||
self.kind.post_store(bcx, self.val, self.ty)
|
||||
}
|
||||
|
||||
fn shallow_copy<'blk, 'tcx>(&self,
|
||||
bcx: Block<'blk, 'tcx>,
|
||||
dst: ValueRef)
|
||||
-> Block<'blk, 'tcx> {
|
||||
fn shallow_copy_raw<'blk, 'tcx>(&self,
|
||||
bcx: Block<'blk, 'tcx>,
|
||||
dst: ValueRef)
|
||||
-> Block<'blk, 'tcx> {
|
||||
/*!
|
||||
* Helper function that performs a shallow copy of this value
|
||||
* 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
|
||||
* in an unstable state, where the source value has been
|
||||
* copied but not zeroed. Public methods are `store_to` (if
|
||||
* you no longer need the source value) or
|
||||
* `shallow_copy_and_take` (if you wish the source value to
|
||||
* remain valid).
|
||||
* copied but not zeroed. Public methods are `store_to`
|
||||
* (if you no longer need the source value) or `shallow_copy`
|
||||
* (if you wish the source value to remain valid).
|
||||
*/
|
||||
|
||||
let _icx = push_ctxt("copy_to_no_check");
|
||||
@ -605,22 +598,19 @@ impl<K:KindOps> Datum<K> {
|
||||
return bcx;
|
||||
}
|
||||
|
||||
pub fn shallow_copy_and_take<'blk, 'tcx>(&self,
|
||||
bcx: Block<'blk, 'tcx>,
|
||||
dst: ValueRef)
|
||||
-> Block<'blk, 'tcx> {
|
||||
pub fn shallow_copy<'blk, 'tcx>(&self,
|
||||
bcx: Block<'blk, 'tcx>,
|
||||
dst: ValueRef)
|
||||
-> Block<'blk, 'tcx> {
|
||||
/*!
|
||||
* Copies the value into a new location and runs any necessary
|
||||
* take glue on the new location. This function always
|
||||
* Copies the value into a new location. This function always
|
||||
* preserves the existing datum as a valid value. Therefore,
|
||||
* it does not consume `self` and, also, cannot be applied to
|
||||
* affine values (since they must never be duplicated).
|
||||
*/
|
||||
|
||||
assert!(!ty::type_moves_by_default(bcx.tcx(), self.ty));
|
||||
let mut bcx = bcx;
|
||||
bcx = self.shallow_copy(bcx, dst);
|
||||
glue::take_ty(bcx, dst, self.ty)
|
||||
self.shallow_copy_raw(bcx, dst)
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // useful for debugging
|
||||
|
@ -373,12 +373,6 @@ impl TypeMap {
|
||||
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) => {
|
||||
unique_type_id.push_char('~');
|
||||
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));
|
||||
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
|
||||
@ -2646,105 +2628,6 @@ fn create_struct_stub(cx: &CrateContext,
|
||||
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,
|
||||
unique_type_id: UniqueTypeId,
|
||||
element_type: ty::t,
|
||||
@ -2968,9 +2851,6 @@ fn type_metadata(cx: &CrateContext,
|
||||
ty::ty_enum(def_id, _) => {
|
||||
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)) => {
|
||||
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,
|
||||
outputs: ref outputs,
|
||||
.. }) => {
|
||||
// inputs, outputs: ~[(String, Gc<expr>)]
|
||||
// inputs, outputs: Vec<(String, P<Expr>)>
|
||||
for &(_, ref exp) in inputs.iter() {
|
||||
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);
|
||||
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 } ) => {
|
||||
output.push_char('*');
|
||||
match mutbl {
|
||||
|
@ -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
|
||||
datum (`&self`) rather than consume it, but they always include
|
||||
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.
|
||||
|
||||
Translating an expression always yields a `Datum<Expr>` result, but
|
||||
|
@ -38,7 +38,6 @@ use llvm;
|
||||
use llvm::{ValueRef};
|
||||
use metadata::csearch;
|
||||
use middle::def;
|
||||
use middle::lang_items::MallocFnLangItem;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::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())
|
||||
}
|
||||
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 contents_ty = expr_ty(bcx, &**contents);
|
||||
match ty::get(box_ty).sty {
|
||||
ty::ty_uniq(..) => {
|
||||
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,
|
||||
"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()
|
||||
}
|
||||
ast::UnBox => {
|
||||
trans_managed_expr(bcx, un_ty, sub_expr, expr_ty(bcx, sub_expr))
|
||||
}
|
||||
ast::UnUniq => {
|
||||
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()
|
||||
}
|
||||
|
||||
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>,
|
||||
expr: &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 {
|
||||
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)) {
|
||||
(Some(ty::mt{ ty: t_in, .. }), Some(ty::mt{ ty: 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_rptr(_, ty::mt { ty: content_ty, .. }) => {
|
||||
if ty::type_is_sized(bcx.tcx(), content_ty) {
|
||||
|
@ -17,7 +17,7 @@ use back::abi;
|
||||
use back::link::*;
|
||||
use llvm::{ValueRef, True, get_param};
|
||||
use llvm;
|
||||
use middle::lang_items::{FreeFnLangItem, ExchangeFreeFnLangItem};
|
||||
use middle::lang_items::ExchangeFreeFnLangItem;
|
||||
use middle::subst;
|
||||
use middle::subst::Subst;
|
||||
use middle::trans::adt;
|
||||
@ -46,15 +46,6 @@ use libc::c_uint;
|
||||
use syntax::ast;
|
||||
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,
|
||||
size: ValueRef, align: ValueRef)
|
||||
-> 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 {
|
||||
let tcx = ccx.tcx();
|
||||
// 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.
|
||||
let _icx = push_ctxt("make_drop_glue");
|
||||
match ty::get(t).sty {
|
||||
ty::ty_box(body_ty) => {
|
||||
decr_refcnt_maybe_free(bcx, v0, body_ty)
|
||||
}
|
||||
ty::ty_uniq(content_ty) => {
|
||||
match ty::get(content_ty).sty {
|
||||
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.
|
||||
pub fn declare_tydesc(ccx: &CrateContext, t: ty::t) -> tydesc_info {
|
||||
// If emit_tydescs already ran, then we shouldn't be creating any new
|
||||
|
@ -169,14 +169,6 @@ impl<'a, 'blk, 'tcx> Reflector<'a, 'blk, 'tcx> {
|
||||
extra.push(self.c_tydesc(ty));
|
||||
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) => {
|
||||
match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(ty, None) => {
|
||||
|
@ -325,7 +325,7 @@ pub fn write_content<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
|
||||
let bcx = iter_vec_loop(bcx, lldest, vt,
|
||||
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);
|
||||
|
@ -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_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, ..}) => {
|
||||
if ty::type_is_sized(cx.tcx(), ty) {
|
||||
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, []);
|
||||
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, ..}) => {
|
||||
match ty::get(ty).sty {
|
||||
|
@ -940,7 +940,6 @@ pub enum sty {
|
||||
/// the `ast_ty_to_ty_cache`. This is probably true for `ty_struct` as
|
||||
/// well.`
|
||||
ty_enum(DefId, Substs),
|
||||
ty_box(t),
|
||||
ty_uniq(t),
|
||||
ty_str,
|
||||
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 |= 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
|
||||
}
|
||||
&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))
|
||||
}
|
||||
|
||||
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_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 {
|
||||
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_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) => {
|
||||
maybe_walk_ty(tm.ty, f);
|
||||
}
|
||||
@ -2014,7 +2011,7 @@ pub fn type_is_vec(ty: t) -> bool {
|
||||
match get(ty).sty {
|
||||
ty_vec(..) => true,
|
||||
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,
|
||||
_ => 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 {
|
||||
match get(ty).sty {
|
||||
ty_rptr(..) => true,
|
||||
@ -2144,29 +2134,22 @@ pub fn type_needs_unwind_cleanup(cx: &ctxt, ty: t) -> bool {
|
||||
|
||||
let mut tycache = HashSet::new();
|
||||
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);
|
||||
return needs_unwind_cleanup;
|
||||
needs_unwind_cleanup
|
||||
}
|
||||
|
||||
fn type_needs_unwind_cleanup_(cx: &ctxt, ty: t,
|
||||
tycache: &mut HashSet<t>,
|
||||
encountered_box: bool) -> bool {
|
||||
tycache: &mut HashSet<t>) -> bool {
|
||||
|
||||
// Prevent infinite recursion
|
||||
if !tycache.insert(ty) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut encountered_box = encountered_box;
|
||||
let mut needs_unwind_cleanup = false;
|
||||
maybe_walk_ty(ty, |ty| {
|
||||
let old_encountered_box = encountered_box;
|
||||
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_tup(_) | ty_ptr(_) => {
|
||||
true
|
||||
@ -2176,33 +2159,21 @@ fn type_needs_unwind_cleanup_(cx: &ctxt, ty: t,
|
||||
for aty in v.args.iter() {
|
||||
let t = aty.subst(cx, substs);
|
||||
needs_unwind_cleanup |=
|
||||
type_needs_unwind_cleanup_(cx, t, tycache,
|
||||
encountered_box);
|
||||
type_needs_unwind_cleanup_(cx, t, tycache);
|
||||
}
|
||||
}
|
||||
!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;
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
encountered_box = old_encountered_box;
|
||||
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
|
||||
}
|
||||
|
||||
ty_box(typ) => {
|
||||
tc_ty(cx, typ, cache).managed_pointer() | TC::ReachesFfiUnsafe
|
||||
}
|
||||
|
||||
ty_uniq(typ) => {
|
||||
TC::ReachesFfiUnsafe | match get(typ).sty {
|
||||
ty_str => TC::OwnsOwned,
|
||||
@ -2782,7 +2749,7 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
|
||||
ty_vec(_, None) => {
|
||||
false
|
||||
}
|
||||
ty_box(typ) | ty_uniq(typ) | ty_open(typ) => {
|
||||
ty_uniq(typ) | ty_open(typ) => {
|
||||
type_requires(cx, seen, r_ty, typ)
|
||||
}
|
||||
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.
|
||||
pub fn deref(t: t, explicit: bool) -> Option<mt> {
|
||||
match get(t).sty {
|
||||
ty_box(ty) | ty_uniq(ty) => {
|
||||
ty_uniq(ty) => {
|
||||
Some(mt {
|
||||
ty: ty,
|
||||
mutbl: ast::MutImmutable,
|
||||
@ -3106,9 +3073,7 @@ pub fn deref(t: t, explicit: bool) -> Option<mt> {
|
||||
|
||||
pub fn deref_or_dont(t: t) -> t {
|
||||
match get(t).sty {
|
||||
ty_box(ty) | ty_uniq(ty) => {
|
||||
ty
|
||||
},
|
||||
ty_uniq(ty) => ty,
|
||||
ty_rptr(_, mt) | ty_ptr(mt) => mt.ty,
|
||||
_ => t
|
||||
}
|
||||
@ -3124,7 +3089,7 @@ pub fn close_type(cx: &ctxt, t: t) -> t {
|
||||
|
||||
pub fn type_content(t: t) -> t {
|
||||
match get(t).sty {
|
||||
ty_box(ty) | ty_uniq(ty) => ty,
|
||||
ty_uniq(ty) => ty,
|
||||
ty_rptr(_, mt) |ty_ptr(mt) => mt.ty,
|
||||
_ => t
|
||||
}
|
||||
@ -3695,14 +3660,13 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
|
||||
}
|
||||
|
||||
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) {
|
||||
Some(&def) => def,
|
||||
None => fail!("no def for place"),
|
||||
};
|
||||
let def_id = definition.def_id();
|
||||
if tcx.lang_items.exchange_heap() == Some(def_id) ||
|
||||
tcx.lang_items.managed_heap() == Some(def_id) {
|
||||
if tcx.lang_items.exchange_heap() == Some(def_id) {
|
||||
RvalueDatumExpr
|
||||
} else {
|
||||
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_box(_) => "Gc-ptr".to_string(),
|
||||
ty_uniq(_) => "box".to_string(),
|
||||
ty_vec(_, Some(_)) => "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);
|
||||
did(&mut state, d);
|
||||
}
|
||||
ty_box(_) => {
|
||||
ty_uniq(_) => {
|
||||
byte!(9);
|
||||
}
|
||||
ty_uniq(_) => {
|
||||
byte!(10);
|
||||
}
|
||||
ty_vec(_, Some(n)) => {
|
||||
byte!(11);
|
||||
byte!(10);
|
||||
n.hash(&mut state);
|
||||
}
|
||||
ty_vec(_, None) => {
|
||||
byte!(11);
|
||||
0u8.hash(&mut state);
|
||||
}
|
||||
ty_ptr(m) => {
|
||||
byte!(12);
|
||||
@ -5586,7 +5545,6 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
|
||||
ty_int(_) |
|
||||
ty_uint(_) |
|
||||
ty_float(_) |
|
||||
ty_box(_) |
|
||||
ty_uniq(_) |
|
||||
ty_str |
|
||||
ty_vec(_, _) |
|
||||
|
@ -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,
|
||||
sty: &ty::sty) -> ty::sty {
|
||||
match *sty {
|
||||
ty::ty_box(typ) => {
|
||||
ty::ty_box(typ.fold_with(this))
|
||||
}
|
||||
ty::ty_uniq(typ) => {
|
||||
ty::ty_uniq(typ.fold_with(this))
|
||||
}
|
||||
|
@ -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>`");
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -606,7 +568,6 @@ pub fn ast_ty_to_builtin_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
|
||||
#[deriving(Show)]
|
||||
enum PointerTy {
|
||||
Box,
|
||||
RPtr(ty::Region),
|
||||
Uniq
|
||||
}
|
||||
@ -614,7 +575,6 @@ enum PointerTy {
|
||||
impl PointerTy {
|
||||
fn default_region(&self) -> ty::Region {
|
||||
match *self {
|
||||
Box => ty::ReStatic,
|
||||
Uniq => ty::ReStatic,
|
||||
RPtr(r) => r,
|
||||
}
|
||||
@ -702,14 +662,6 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
r,
|
||||
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) => {
|
||||
@ -726,11 +678,6 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
RPtr(r) => {
|
||||
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)) => {
|
||||
@ -767,13 +714,6 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>(
|
||||
RPtr(r) => {
|
||||
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 {
|
||||
ast::TyNil => ty::mk_nil(),
|
||||
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) => {
|
||||
mk_pointer(this, rscope, ast::MutImmutable, &**ty, Uniq,
|
||||
|ty| ty::mk_uniq(tcx, ty))
|
||||
|
@ -1094,7 +1094,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> {
|
||||
|
||||
let tcx = self.tcx();
|
||||
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(FloatVar(_)) |
|
||||
ty_param(..) | ty_nil | ty_bot | ty_bool |
|
||||
|
@ -1468,7 +1468,7 @@ fn check_cast(fcx: &FnCtxt,
|
||||
// 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;
|
||||
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| {
|
||||
format!("illegal cast; cast through an \
|
||||
integer first: `{}` as `{}`",
|
||||
@ -3820,12 +3820,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
if tcx.lang_items.exchange_heap() == Some(def_id) {
|
||||
fcx.write_ty(id, ty::mk_uniq(tcx, referent_ty));
|
||||
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) => {
|
||||
let expected_inner = expected.map(fcx, |sty| {
|
||||
match unop {
|
||||
ast::UnBox | ast::UnUniq => match *sty {
|
||||
ty::ty_box(ty) | ty::ty_uniq(ty) => {
|
||||
ast::UnUniq => match *sty {
|
||||
ty::ty_uniq(ty) => {
|
||||
ExpectHasType(ty)
|
||||
}
|
||||
_ => {
|
||||
@ -3907,11 +3901,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
|
||||
if !ty::type_is_error(oprnd_t) {
|
||||
match unop {
|
||||
ast::UnBox => {
|
||||
if !ty::type_is_bot(oprnd_t) {
|
||||
oprnd_t = ty::mk_box(tcx, oprnd_t)
|
||||
}
|
||||
}
|
||||
ast::UnUniq => {
|
||||
if !ty::type_is_bot(oprnd_t) {
|
||||
oprnd_t = ty::mk_uniq(tcx, oprnd_t);
|
||||
|
@ -663,14 +663,6 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::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) => {
|
||||
// For *a, the lifetime of a must enclose the deref
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
@ -1474,7 +1466,6 @@ fn link_region(rcx: &Rcx,
|
||||
|
||||
mc::cat_discr(cmt_base, _) |
|
||||
mc::cat_downcast(cmt_base) |
|
||||
mc::cat_deref(cmt_base, _, mc::GcPtr(..)) |
|
||||
mc::cat_deref(cmt_base, _, mc::OwnedPtr) |
|
||||
mc::cat_interior(cmt_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::GcPtr) |
|
||||
mc::cat_static_item |
|
||||
mc::cat_rvalue(_) |
|
||||
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::GcPtr) |
|
||||
mc::cat_static_item |
|
||||
mc::cat_rvalue(_) |
|
||||
mc::cat_copied_upvar(_) |
|
||||
|
@ -129,7 +129,6 @@ impl<'a, 'tcx> Wf<'a, 'tcx> {
|
||||
|
||||
ty::ty_vec(t, _) |
|
||||
ty::ty_ptr(ty::mt { ty: t, .. }) |
|
||||
ty::ty_box(t) |
|
||||
ty::ty_uniq(t) => {
|
||||
self.accumulate_from_ty(t)
|
||||
}
|
||||
|
@ -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
|
||||
// gratuitously unsafe.
|
||||
fn object_trait<'a>(t: &'a ty::t) -> &'a ty::TyTrait {
|
||||
|
@ -23,7 +23,7 @@ use middle::subst::{Substs};
|
||||
use middle::ty::get;
|
||||
use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId};
|
||||
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_param, Polytype, ty_ptr};
|
||||
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_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
|
||||
ty_infer(..) | ty_param(..) | ty_err | ty_open(..) |
|
||||
ty_box(_) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => {
|
||||
ty_infer(..) | ty_param(..) | ty_err | ty_open(..) | ty_uniq(_) |
|
||||
ty_ptr(_) | ty_rptr(_, _) => {
|
||||
debug!("(getting base type) no base type; found {:?}",
|
||||
get(original_type).sty);
|
||||
None
|
||||
|
@ -258,7 +258,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
let r_borrow = self.get_ref().infcx.next_region_var(coercion);
|
||||
|
||||
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,
|
||||
_ => {
|
||||
return self.subtype(a, b);
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
(&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)) => {
|
||||
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))
|
||||
|
@ -776,11 +776,6 @@ impl<'a, 'tcx> ErrorReporting for InferCtxt<'a, 'tcx> {
|
||||
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) => {
|
||||
ty_queue.push(&*mut_ty.ty);
|
||||
}
|
||||
ast::TyBox(ref ty) |
|
||||
ast::TyVec(ref ty) |
|
||||
ast::TyUniq(ref ty) |
|
||||
ast::TyFixedLengthVec(ref ty, _) => {
|
||||
@ -1323,7 +1317,6 @@ impl<'a, 'tcx> Rebuilder<'a, 'tcx> {
|
||||
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::TyUniq(ty) => ast::TyUniq(build_to(ty, to)),
|
||||
ast::TyFixedLengthVec(ty, e) => {
|
||||
@ -1614,11 +1607,6 @@ impl<'a, 'tcx> ErrorReportingHelpers for InferCtxt<'a, 'tcx> {
|
||||
does not outlive the data it points at",
|
||||
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) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
|
@ -216,9 +216,6 @@ pub enum SubregionOrigin {
|
||||
|
||||
// An auto-borrow that does not enclose the expr where it occurs
|
||||
AutoBorrow(Span),
|
||||
|
||||
// Managed data cannot contain borrowed pointers.
|
||||
Managed(Span),
|
||||
}
|
||||
|
||||
/// Reasons to create a region inference variable
|
||||
@ -1029,7 +1026,6 @@ impl SubregionOrigin {
|
||||
CallReturn(a) => a,
|
||||
AddrOf(a) => a,
|
||||
AutoBorrow(a) => a,
|
||||
Managed(a) => a,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1102,7 +1098,6 @@ impl Repr for SubregionOrigin {
|
||||
CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
|
||||
AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
|
||||
AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)),
|
||||
Managed(a) => format!("Managed({})", a.repr(tcx)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeSkolemizer<'a, 'tcx> {
|
||||
ty::ty_uint(..) |
|
||||
ty::ty_float(..) |
|
||||
ty::ty_enum(..) |
|
||||
ty::ty_box(..) |
|
||||
ty::ty_uniq(..) |
|
||||
ty::ty_str |
|
||||
ty::ty_err |
|
||||
|
@ -742,7 +742,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ use middle::ty::{ReEarlyBound, BrFresh, ctxt};
|
||||
use middle::ty::{ReFree, ReScope, ReInfer, ReStatic, Region, ReEmpty};
|
||||
use middle::ty::{ReSkolemized, ReVar};
|
||||
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_nil, ty_param, ty_ptr, ty_rptr, ty_tup, ty_open};
|
||||
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_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_box(typ) => format!("Gc<{}>", ty_to_string(cx, typ)),
|
||||
ty_uniq(typ) => format!("Box<{}>", ty_to_string(cx, typ)),
|
||||
ty_ptr(ref tm) => {
|
||||
format!("*{} {}", match tm.mutbl {
|
||||
|
@ -1087,7 +1087,6 @@ pub enum Type {
|
||||
/// aka TyBot
|
||||
Bottom,
|
||||
Unique(Box<Type>),
|
||||
Managed(Box<Type>),
|
||||
RawPointer(Mutability, Box<Type>),
|
||||
BorrowedRef {
|
||||
pub lifetime: Option<Lifetime>,
|
||||
@ -1215,7 +1214,6 @@ impl Clean<Type> for ast::Ty {
|
||||
TyRptr(ref l, ref m) =>
|
||||
BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
|
||||
type_: box m.ty.clean(cx)},
|
||||
TyBox(ref ty) => Managed(box ty.clean(cx)),
|
||||
TyUniq(ref ty) => Unique(box ty.clean(cx)),
|
||||
TyVec(ref ty) => Vector(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::TyF64) => Primitive(F64),
|
||||
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) => {
|
||||
let box_did = cx.tcx_opt().and_then(|tcx| {
|
||||
tcx.lang_items.owned_box()
|
||||
|
@ -476,7 +476,7 @@ impl fmt::Show for clean::Type {
|
||||
};
|
||||
write!(f, "&{}{}{}", lt, MutableSpace(mutability), **ty)
|
||||
}
|
||||
clean::Unique(..) | clean::Managed(..) => {
|
||||
clean::Unique(..) => {
|
||||
fail!("should have been cleaned")
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
#![crate_type = "dylib"]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
#![feature(globs, struct_variant, managed_boxes, macro_rules, phase)]
|
||||
#![feature(globs, struct_variant, macro_rules, phase)]
|
||||
|
||||
extern crate arena;
|
||||
extern crate debug;
|
||||
|
@ -16,7 +16,7 @@
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
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(import_shadowing)]
|
||||
#![no_std]
|
||||
@ -57,7 +57,6 @@ pub mod c_str;
|
||||
pub mod exclusive;
|
||||
pub mod local;
|
||||
pub mod local_data;
|
||||
pub mod local_heap;
|
||||
pub mod mutex;
|
||||
pub mod rtio;
|
||||
pub mod stack;
|
||||
@ -104,9 +103,8 @@ pub static DEFAULT_ERROR_CODE: int = 101;
|
||||
|
||||
/// One-time runtime initialization.
|
||||
///
|
||||
/// Initializes global state, including frobbing
|
||||
/// the crate's logging flags, registering GC
|
||||
/// metadata, and storing the process arguments.
|
||||
/// Initializes global state, including frobbing the crate's logging flags,
|
||||
/// and storing the process arguments.
|
||||
pub fn init(argc: int, argv: *const *const u8) {
|
||||
// FIXME: Derefing these pointers is not safe.
|
||||
// Need to propagate the unsafety to `start`.
|
||||
|
@ -411,7 +411,6 @@ mod tests {
|
||||
extern crate test;
|
||||
|
||||
use std::prelude::*;
|
||||
use std::gc::{Gc, GC};
|
||||
use super::*;
|
||||
use std::task;
|
||||
|
||||
@ -467,11 +466,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_tls_multiple_types() {
|
||||
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;
|
||||
task::spawn(proc() {
|
||||
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));
|
||||
});
|
||||
}
|
||||
@ -479,13 +478,13 @@ mod tests {
|
||||
#[test]
|
||||
fn test_tls_overwrite_multiple_types() {
|
||||
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;
|
||||
task::spawn(proc() {
|
||||
str_key.replace(Some("string data".to_string()));
|
||||
str_key.replace(Some("string data 2".to_string()));
|
||||
box_key.replace(Some(box(GC) ()));
|
||||
box_key.replace(Some(box(GC) ()));
|
||||
box_key.replace(Some(box 0));
|
||||
box_key.replace(Some(box 1));
|
||||
int_key.replace(Some(42));
|
||||
// This could cause a segfault if overwriting-destruction is done
|
||||
// with the crazy polymorphic transmute rather than the provided
|
||||
@ -498,13 +497,13 @@ mod tests {
|
||||
#[should_fail]
|
||||
fn test_tls_cleanup_on_failure() {
|
||||
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;
|
||||
str_key.replace(Some("parent data".to_string()));
|
||||
box_key.replace(Some(box(GC) ()));
|
||||
box_key.replace(Some(box 0));
|
||||
task::spawn(proc() {
|
||||
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));
|
||||
fail!();
|
||||
});
|
||||
|
@ -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]) });
|
||||
}
|
||||
}
|
@ -9,9 +9,8 @@
|
||||
// except according to those terms.
|
||||
|
||||
//! Language-level runtime services that should reasonably expected
|
||||
//! to be available 'everywhere'. Local heaps, GC, unwinding,
|
||||
//! local storage, and logging. Even a 'freestanding' Rust would likely want
|
||||
//! to implement this.
|
||||
//! to be available 'everywhere'. Unwinding, local storage, and logging.
|
||||
//! Even a 'freestanding' Rust would likely want to implement this.
|
||||
|
||||
use alloc::arc::Arc;
|
||||
use alloc::boxed::{BoxAny, Box};
|
||||
@ -27,7 +26,6 @@ use core::raw;
|
||||
use local_data;
|
||||
use Runtime;
|
||||
use local::Local;
|
||||
use local_heap::LocalHeap;
|
||||
use rtio::LocalIo;
|
||||
use unwind;
|
||||
use unwind::Unwinder;
|
||||
@ -95,8 +93,6 @@ use collections::str::SendStr;
|
||||
/// # }
|
||||
/// ```
|
||||
pub struct Task {
|
||||
pub heap: LocalHeap,
|
||||
pub gc: GarbageCollector,
|
||||
pub storage: LocalStorage,
|
||||
pub unwinder: Unwinder,
|
||||
pub death: Death,
|
||||
@ -132,7 +128,6 @@ pub struct TaskOpts {
|
||||
/// children tasks complete, recommend using a result future.
|
||||
pub type Result = ::core::result::Result<(), Box<Any + Send>>;
|
||||
|
||||
pub struct GarbageCollector;
|
||||
pub struct LocalStorage(pub Option<local_data::Map>);
|
||||
|
||||
/// 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.
|
||||
pub fn new() -> Task {
|
||||
Task {
|
||||
heap: LocalHeap::new(),
|
||||
gc: GarbageCollector,
|
||||
storage: LocalStorage(None),
|
||||
unwinder: Unwinder::new(),
|
||||
death: Death::new(),
|
||||
@ -264,32 +257,22 @@ impl Task {
|
||||
/// already been destroyed and/or annihilated.
|
||||
fn cleanup(self: Box<Task>, result: Result) -> Box<Task> {
|
||||
// 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
|
||||
//
|
||||
// 1. If any TLD object fails destruction, then all of TLD will leak.
|
||||
// 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
|
||||
// abort the runtime #14807.
|
||||
//
|
||||
// 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.
|
||||
// 3. The order of destruction of TLD matters, but either way is
|
||||
// susceptible to leaks (see 2) #8302.
|
||||
//
|
||||
// That being said, there are a few upshots to this code
|
||||
//
|
||||
// 1. If TLD destruction fails, heap destruction will be attempted.
|
||||
// There is a test for this at fail-during-tld-destroy.rs. Sadly the
|
||||
// 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).
|
||||
// There is a test for this at fail-during-tld-destroy.rs.
|
||||
//
|
||||
// 2. One failure in destruction is tolerable, so long as the task
|
||||
// didn't originally fail while it was running.
|
||||
@ -301,15 +284,10 @@ impl Task {
|
||||
let &LocalStorage(ref mut optmap) = &mut task.storage;
|
||||
optmap.take()
|
||||
};
|
||||
let mut heap = mem::replace(&mut task.heap, LocalHeap::new());
|
||||
unsafe { heap.immortalize() }
|
||||
drop(task);
|
||||
|
||||
// First, destroy task-local storage. This may run user dtors.
|
||||
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
|
||||
@ -327,9 +305,8 @@ impl Task {
|
||||
Local::put(task);
|
||||
|
||||
// FIXME: this is running in a seriously constrained context. If this
|
||||
// allocates GC or allocates TLD then it will likely abort the
|
||||
// runtime. Similarly, if this fails, this will also likely abort
|
||||
// the runtime.
|
||||
// allocates TLD then it will likely abort the runtime. Similarly,
|
||||
// if this fails, this will also likely abort the runtime.
|
||||
//
|
||||
// This closure is currently limited to a channel send via the
|
||||
// standard library's task interface, but this needs
|
||||
@ -577,23 +554,14 @@ mod test {
|
||||
use super::*;
|
||||
use std::prelude::*;
|
||||
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]
|
||||
fn tls() {
|
||||
local_data_key!(key: Gc<String>)
|
||||
key.replace(Some(box(GC) "data".to_string()));
|
||||
local_data_key!(key: String)
|
||||
key.replace(Some("data".to_string()));
|
||||
assert_eq!(key.get().unwrap().as_slice(), "data");
|
||||
local_data_key!(key2: Gc<String>)
|
||||
key2.replace(Some(box(GC) "data".to_string()));
|
||||
local_data_key!(key2: String)
|
||||
key2.replace(Some("data".to_string()));
|
||||
assert_eq!(key2.get().unwrap().as_slice(), "data");
|
||||
}
|
||||
|
||||
@ -628,23 +596,6 @@ mod test {
|
||||
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]
|
||||
#[should_fail]
|
||||
fn test_begin_unwind() {
|
||||
|
@ -23,7 +23,7 @@ Core encoding and decoding interfaces.
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/master/",
|
||||
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
|
||||
#[cfg(test)]
|
||||
|
@ -16,7 +16,6 @@ Core encoding and decoding interfaces.
|
||||
|
||||
use std::path;
|
||||
use std::rc::Rc;
|
||||
use std::gc::{Gc, GC};
|
||||
use std::cell::{Cell, RefCell};
|
||||
|
||||
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> {
|
||||
#[inline]
|
||||
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] {
|
||||
fn encode(&self, s: &mut S) -> Result<(), E> {
|
||||
s.emit_seq(self.len(), |s| {
|
||||
|
156
src/libstd/gc.rs
156
src/libstd/gc.rs
@ -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);
|
||||
}
|
||||
}
|
@ -958,7 +958,9 @@ mod tests {
|
||||
// don't check windows magical empty-named variables
|
||||
assert!(k.is_empty() ||
|
||||
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")]
|
||||
|
@ -105,7 +105,7 @@
|
||||
html_root_url = "http://doc.rust-lang.org/master/",
|
||||
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(import_shadowing)]
|
||||
|
||||
@ -136,7 +136,6 @@ extern crate rustrt;
|
||||
#[cfg(test)] pub use realstd::cmp;
|
||||
#[cfg(test)] pub use realstd::ty;
|
||||
#[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
|
||||
@ -219,9 +218,6 @@ pub mod rand;
|
||||
|
||||
pub mod ascii;
|
||||
|
||||
#[cfg(not(test))]
|
||||
pub mod gc;
|
||||
|
||||
pub mod time;
|
||||
|
||||
/* Common traits */
|
||||
|
@ -201,12 +201,13 @@ mod test {
|
||||
#[test]
|
||||
fn test_sendable_future() {
|
||||
let expected = "schlorf";
|
||||
let (tx, rx) = channel();
|
||||
let f = Future::spawn(proc() { expected });
|
||||
task::spawn(proc() {
|
||||
let mut f = f;
|
||||
let actual = f.get();
|
||||
assert_eq!(actual, expected);
|
||||
tx.send(f.get());
|
||||
});
|
||||
assert_eq!(rx.recv(), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -416,7 +416,6 @@ pub enum BinOp {
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
|
||||
pub enum UnOp {
|
||||
UnBox,
|
||||
UnUniq,
|
||||
UnDeref,
|
||||
UnNot,
|
||||
@ -953,7 +952,6 @@ pub struct UnboxedFnTy {
|
||||
pub enum Ty_ {
|
||||
TyNil,
|
||||
TyBot, /* bottom type */
|
||||
TyBox(P<Ty>),
|
||||
TyUniq(P<Ty>),
|
||||
TyVec(P<Ty>),
|
||||
TyFixedLengthVec(P<Ty>, P<Expr>),
|
||||
|
@ -90,7 +90,6 @@ pub fn is_shift_binop(b: BinOp) -> bool {
|
||||
|
||||
pub fn unop_to_string(op: UnOp) -> &'static str {
|
||||
match op {
|
||||
UnBox => "box(GC) ",
|
||||
UnUniq => "box() ",
|
||||
UnDeref => "*",
|
||||
UnNot => "!",
|
||||
|
@ -112,7 +112,6 @@ pub trait AstBuilder {
|
||||
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_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_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>;
|
||||
@ -565,10 +564,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||
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> {
|
||||
let field_name = token::get_ident(ident);
|
||||
let field_span = Span {
|
||||
|
@ -40,7 +40,7 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
|
||||
("struct_variant", Active),
|
||||
("once_fns", Active),
|
||||
("asm", Active),
|
||||
("managed_boxes", Active),
|
||||
("managed_boxes", Removed),
|
||||
("non_ascii_idents", Active),
|
||||
("thread_local", 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 {
|
||||
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");
|
||||
|
||||
},
|
||||
ast::TyBox(_) => { self.gate_box(t.span); }
|
||||
ast::TyUnboxedFn(..) => {
|
||||
self.gate_feature("unboxed_closure_sugar",
|
||||
t.span,
|
||||
@ -344,9 +335,6 @@ impl<'a, 'v> Visitor<'v> for Context<'a> {
|
||||
|
||||
fn visit_expr(&mut self, e: &ast::Expr) {
|
||||
match e.node {
|
||||
ast::ExprUnary(ast::UnBox, _) => {
|
||||
self.gate_box(e.span);
|
||||
}
|
||||
ast::ExprUnboxedFn(..) => {
|
||||
self.gate_feature("unboxed_closures",
|
||||
e.span,
|
||||
|
@ -372,7 +372,6 @@ pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
|
||||
id: fld.new_id(id),
|
||||
node: match node {
|
||||
TyNil | TyBot | TyInfer => node,
|
||||
TyBox(ty) => TyBox(fld.fold_ty(ty)),
|
||||
TyUniq(ty) => TyUniq(fld.fold_ty(ty)),
|
||||
TyVec(ty) => TyVec(fld.fold_ty(ty)),
|
||||
TyPtr(mt) => TyPtr(fld.fold_mt(mt)),
|
||||
|
@ -31,8 +31,6 @@ pub enum ObsoleteSyntax {
|
||||
ObsoleteOwnedPattern,
|
||||
ObsoleteOwnedVector,
|
||||
ObsoleteOwnedSelf,
|
||||
ObsoleteManagedType,
|
||||
ObsoleteManagedExpr,
|
||||
ObsoleteImportRenaming,
|
||||
ObsoleteSubsliceMatch,
|
||||
ObsoleteExternCrateRenaming,
|
||||
@ -77,14 +75,6 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
|
||||
"`~self` is no longer supported",
|
||||
"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 => (
|
||||
"`use foo = bar` syntax",
|
||||
"write `use bar as foo` instead"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user