]> git.lizzy.rs Git - rust.git/commitdiff
rustc: Implement the #[global_allocator] attribute
authorAlex Crichton <alex@alexcrichton.com>
Sat, 3 Jun 2017 21:54:08 +0000 (14:54 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 5 Jul 2017 21:37:01 +0000 (14:37 -0700)
This PR is an implementation of [RFC 1974] which specifies a new method of
defining a global allocator for a program. This obsoletes the old
`#![allocator]` attribute and also removes support for it.

[RFC 1974]: https://github.com/rust-lang/rfcs/pull/197

The new `#[global_allocator]` attribute solves many issues encountered with the
`#![allocator]` attribute such as composition and restrictions on the crate
graph itself. The compiler now has much more control over the ABI of the
allocator and how it's implemented, allowing much more freedom in terms of how
this feature is implemented.

cc #27389

124 files changed:
src/Cargo.lock
src/doc/unstable-book/src/language-features/allocator-internals.md [new file with mode: 0644]
src/doc/unstable-book/src/language-features/allocator.md [deleted file]
src/doc/unstable-book/src/language-features/global-allocator.md [new file with mode: 0644]
src/liballoc/allocator.rs
src/liballoc/arc.rs
src/liballoc/boxed.rs
src/liballoc/btree/node.rs
src/liballoc/heap.rs
src/liballoc/lib.rs
src/liballoc/oom.rs [deleted file]
src/liballoc/raw_vec.rs
src/liballoc/rc.rs
src/liballoc_jemalloc/Cargo.toml
src/liballoc_jemalloc/lib.rs
src/liballoc_system/Cargo.toml
src/liballoc_system/lib.rs
src/liballoc_system/old.rs [new file with mode: 0644]
src/libcollections/lib.rs
src/librustc/lib.rs
src/librustc/middle/allocator.rs [new file with mode: 0644]
src/librustc/middle/dead.rs
src/librustc/middle/dependency_format.rs
src/librustc/session/mod.rs
src/librustc_allocator/Cargo.toml [new file with mode: 0644]
src/librustc_allocator/expand.rs [new file with mode: 0644]
src/librustc_allocator/lib.rs [new file with mode: 0644]
src/librustc_asan/Cargo.toml
src/librustc_asan/lib.rs
src/librustc_back/target/aarch64_unknown_freebsd.rs
src/librustc_back/target/aarch64_unknown_linux_gnu.rs
src/librustc_back/target/bitrig_base.rs
src/librustc_back/target/fuchsia_base.rs
src/librustc_back/target/mips64_unknown_linux_gnuabi64.rs
src/librustc_back/target/mips64el_unknown_linux_gnuabi64.rs
src/librustc_back/target/mips_unknown_linux_gnu.rs
src/librustc_back/target/mips_unknown_linux_musl.rs
src/librustc_back/target/mips_unknown_linux_uclibc.rs
src/librustc_back/target/mipsel_unknown_linux_gnu.rs
src/librustc_back/target/mipsel_unknown_linux_musl.rs
src/librustc_back/target/mipsel_unknown_linux_uclibc.rs
src/librustc_back/target/mod.rs
src/librustc_back/target/openbsd_base.rs
src/librustc_back/target/powerpc64_unknown_linux_gnu.rs
src/librustc_back/target/powerpc64le_unknown_linux_gnu.rs
src/librustc_back/target/powerpc_unknown_linux_gnu.rs
src/librustc_back/target/redox_base.rs
src/librustc_back/target/s390x_unknown_linux_gnu.rs
src/librustc_back/target/sparc64_unknown_linux_gnu.rs
src/librustc_back/target/windows_msvc_base.rs
src/librustc_back/target/x86_64_rumprun_netbsd.rs
src/librustc_driver/Cargo.toml
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_lint/builtin.rs
src/librustc_llvm/ffi.rs
src/librustc_lsan/Cargo.toml
src/librustc_lsan/lib.rs
src/librustc_metadata/creader.rs
src/librustc_metadata/cstore.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_metadata/encoder.rs
src/librustc_metadata/schema.rs
src/librustc_msan/Cargo.toml
src/librustc_msan/lib.rs
src/librustc_trans/Cargo.toml
src/librustc_trans/allocator.rs [new file with mode: 0644]
src/librustc_trans/back/link.rs
src/librustc_trans/back/symbol_export.rs
src/librustc_trans/back/write.rs
src/librustc_trans/base.rs
src/librustc_trans/lib.rs
src/libstd/collections/hash/table.rs
src/libstd/error.rs
src/libstd/heap.rs [new file with mode: 0644]
src/libstd/lib.rs
src/libstd/sys/unix/mod.rs
src/libstd/sys/windows/mod.rs
src/libsyntax/ext/build.rs
src/libsyntax/feature_gate.rs
src/rustllvm/llvm-rebuild-trigger
src/test/codegen/function-arguments.rs
src/test/compile-fail/allocator-depends-on-needs-allocators.rs [deleted file]
src/test/compile-fail/allocator-dylib-is-system.rs [deleted file]
src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs [deleted file]
src/test/compile-fail/allocator/auxiliary/system-allocator.rs [new file with mode: 0644]
src/test/compile-fail/allocator/auxiliary/system-allocator2.rs [new file with mode: 0644]
src/test/compile-fail/allocator/function-allocator.rs [new file with mode: 0644]
src/test/compile-fail/allocator/not-an-allocator.rs [new file with mode: 0644]
src/test/compile-fail/allocator/two-allocators.rs [new file with mode: 0644]
src/test/compile-fail/allocator/two-allocators2.rs [new file with mode: 0644]
src/test/compile-fail/allocator/two-allocators3.rs [new file with mode: 0644]
src/test/compile-fail/auxiliary/allocator-dylib.rs [deleted file]
src/test/compile-fail/auxiliary/allocator-dylib2.rs [deleted file]
src/test/compile-fail/auxiliary/allocator1.rs [deleted file]
src/test/compile-fail/auxiliary/allocator2.rs [deleted file]
src/test/compile-fail/auxiliary/allocator3.rs [deleted file]
src/test/compile-fail/auxiliary/needs_allocator.rs [deleted file]
src/test/compile-fail/feature-gate-allocator.rs [deleted file]
src/test/compile-fail/feature-gate-allocator_internals.rs [new file with mode: 0644]
src/test/compile-fail/feature-gate-global_allocator.rs [new file with mode: 0644]
src/test/compile-fail/two-allocators-2.rs [deleted file]
src/test/compile-fail/two-allocators-3.rs [deleted file]
src/test/compile-fail/two-allocators.rs [deleted file]
src/test/run-make/no-duplicate-libs/Makefile
src/test/run-make/no-duplicate-libs/bar.c [new file with mode: 0644]
src/test/run-make/no-duplicate-libs/bar.rs [deleted file]
src/test/run-make/no-duplicate-libs/foo.c [new file with mode: 0644]
src/test/run-make/no-duplicate-libs/foo.rs [deleted file]
src/test/run-make/no-duplicate-libs/main.rs
src/test/run-pass/allocator-alloc-one.rs
src/test/run-pass/allocator-default.rs [deleted file]
src/test/run-pass/allocator-override.rs [deleted file]
src/test/run-pass/allocator-system.rs [deleted file]
src/test/run-pass/allocator/auxiliary/custom-as-global.rs [new file with mode: 0644]
src/test/run-pass/allocator/auxiliary/custom.rs [new file with mode: 0644]
src/test/run-pass/allocator/auxiliary/helper.rs [new file with mode: 0644]
src/test/run-pass/allocator/custom.rs [new file with mode: 0644]
src/test/run-pass/allocator/xcrate-use.rs [new file with mode: 0644]
src/test/run-pass/allocator/xcrate-use2.rs [new file with mode: 0644]
src/test/run-pass/lib-defaults.rs
src/test/run-pass/realloc-16687.rs
src/test/run-pass/rfc1717/library-override.rs
src/test/run-pass/smallest-hello-world.rs

index 2d42903ad0a7d48b4bf342d50e492137d8e1e853..cb3efea0d9f016e479491f0f4e7c31d86676e40e 100644 (file)
@@ -43,6 +43,8 @@ dependencies = [
 name = "alloc_jemalloc"
 version = "0.0.0"
 dependencies = [
+ "alloc 0.0.0",
+ "alloc_system 0.0.0",
  "build_helper 0.1.0",
  "core 0.0.0",
  "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -53,6 +55,7 @@ dependencies = [
 name = "alloc_system"
 version = "0.0.0"
 dependencies = [
+ "alloc 0.0.0",
  "core 0.0.0",
  "libc 0.0.0",
 ]
@@ -1127,10 +1130,21 @@ name = "rustc-serialize"
 version = "0.3.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "rustc_allocator"
+version = "0.0.0"
+dependencies = [
+ "rustc 0.0.0",
+ "rustc_errors 0.0.0",
+ "syntax 0.0.0",
+ "syntax_pos 0.0.0",
+]
+
 [[package]]
 name = "rustc_asan"
 version = "0.0.0"
 dependencies = [
+ "alloc 0.0.0",
  "alloc_system 0.0.0",
  "build_helper 0.1.0",
  "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1205,6 +1219,7 @@ dependencies = [
  "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "proc_macro_plugin 0.0.0",
  "rustc 0.0.0",
+ "rustc_allocator 0.0.0",
  "rustc_back 0.0.0",
  "rustc_borrowck 0.0.0",
  "rustc_const_eval 0.0.0",
@@ -1273,6 +1288,7 @@ dependencies = [
 name = "rustc_lsan"
 version = "0.0.0"
 dependencies = [
+ "alloc 0.0.0",
  "alloc_system 0.0.0",
  "build_helper 0.1.0",
  "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1317,6 +1333,7 @@ dependencies = [
 name = "rustc_msan"
 version = "0.0.0"
 dependencies = [
+ "alloc 0.0.0",
  "alloc_system 0.0.0",
  "build_helper 0.1.0",
  "cmake 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1399,6 +1416,7 @@ dependencies = [
  "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
  "rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_allocator 0.0.0",
  "rustc_back 0.0.0",
  "rustc_bitflags 0.0.0",
  "rustc_const_math 0.0.0",
diff --git a/src/doc/unstable-book/src/language-features/allocator-internals.md b/src/doc/unstable-book/src/language-features/allocator-internals.md
new file mode 100644 (file)
index 0000000..2023d75
--- /dev/null
@@ -0,0 +1,7 @@
+# `allocator_internals`
+
+This feature does not have a tracking issue, it is an unstable implementation
+detail of the `global_allocator` feature not intended for use outside the
+compiler.
+
+------------------------
diff --git a/src/doc/unstable-book/src/language-features/allocator.md b/src/doc/unstable-book/src/language-features/allocator.md
deleted file mode 100644 (file)
index cfcf8e2..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-# `allocator`
-
-The tracking issue for this feature is: [#27389]
-
-[#27389]: https://github.com/rust-lang/rust/issues/27389
-
-------------------------
-
-Sometimes even the choices of jemalloc vs the system allocator aren't enough and
-an entirely new custom allocator is required. In this you'll write your own
-crate which implements the allocator API (e.g. the same as `alloc_system` or
-`alloc_jemalloc`). As an example, let's take a look at a simplified and
-annotated version of `alloc_system`
-
-```rust,no_run
-# // Only needed for rustdoc --test down below.
-# #![feature(lang_items)]
-// The compiler needs to be instructed that this crate is an allocator in order
-// to realize that when this is linked in another allocator like jemalloc should
-// not be linked in.
-#![feature(allocator)]
-#![allocator]
-
-// Allocators are not allowed to depend on the standard library which in turn
-// requires an allocator in order to avoid circular dependencies. This crate,
-// however, can use all of libcore.
-#![no_std]
-
-// Let's give a unique name to our custom allocator:
-#![crate_name = "my_allocator"]
-#![crate_type = "rlib"]
-
-// Our system allocator will use the in-tree libc crate for FFI bindings. Note
-// that currently the external (crates.io) libc cannot be used because it links
-// to the standard library (e.g. `#![no_std]` isn't stable yet), so that's why
-// this specifically requires the in-tree version.
-#![feature(libc)]
-extern crate libc;
-
-// Listed below are the five allocation functions currently required by custom
-// allocators. Their signatures and symbol names are not currently typechecked
-// by the compiler, but this is a future extension and are required to match
-// what is found below.
-//
-// Note that the standard `malloc` and `realloc` functions do not provide a way
-// to communicate alignment so this implementation would need to be improved
-// with respect to alignment in that aspect.
-
-#[no_mangle]
-pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 {
-    unsafe { libc::malloc(size as libc::size_t) as *mut u8 }
-}
-
-#[no_mangle]
-pub extern fn __rust_allocate_zeroed(size: usize, _align: usize) -> *mut u8 {
-    unsafe { libc::calloc(size as libc::size_t, 1) as *mut u8 }
-}
-
-#[no_mangle]
-pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
-    unsafe { libc::free(ptr as *mut libc::c_void) }
-}
-
-#[no_mangle]
-pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize,
-                                _align: usize) -> *mut u8 {
-    unsafe {
-        libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
-    }
-}
-
-#[no_mangle]
-pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize,
-                                        _size: usize, _align: usize) -> usize {
-    old_size // This api is not supported by libc.
-}
-
-#[no_mangle]
-pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
-    size
-}
-
-# // Only needed to get rustdoc to test this:
-# fn main() {}
-# #[lang = "panic_fmt"] fn panic_fmt() {}
-# #[lang = "eh_personality"] fn eh_personality() {}
-# #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {}
-# #[no_mangle] pub extern fn rust_eh_register_frames () {}
-# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
-```
-
-After we compile this crate, it can be used as follows:
-
-```rust,ignore
-extern crate my_allocator;
-
-fn main() {
-    let a = Box::new(8); // Allocates memory via our custom allocator crate.
-    println!("{}", a);
-}
-```
-
-## Custom allocator limitations
-
-There are a few restrictions when working with custom allocators which may cause
-compiler errors:
-
-* Any one artifact may only be linked to at most one allocator. Binaries,
-  dylibs, and staticlibs must link to exactly one allocator, and if none have
-  been explicitly chosen the compiler will choose one. On the other hand rlibs
-  do not need to link to an allocator (but still can).
-
-* A consumer of an allocator is tagged with `#![needs_allocator]` (e.g. the
-  `liballoc` crate currently) and an `#[allocator]` crate cannot transitively
-  depend on a crate which needs an allocator (e.g. circular dependencies are not
-  allowed). This basically means that allocators must restrict themselves to
-  libcore currently.
-
-
diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md
new file mode 100644 (file)
index 0000000..2eae40a
--- /dev/null
@@ -0,0 +1,71 @@
+# `global_allocator`
+
+The tracking issue for this feature is: [#27389]
+
+[#27389]: https://github.com/rust-lang/rust/issues/27389
+
+------------------------
+
+Rust programs may need to change the allocator that they're running with from
+time to time. This use case is distinct from an allocator-per-collection (e.g. a
+`Vec` with a custom allocator) and instead is more related to changing the
+global default allocator, e.g. what `Vec<T>` uses by default.
+
+Currently Rust programs don't have a specified global allocator. The compiler
+may link to a version of [jemalloc] on some platforms, but this is not
+guaranteed. Libraries, however, like cdylibs and staticlibs are guaranteed
+to use the "system allocator" which means something like `malloc` on Unixes and
+`HeapAlloc` on Windows.
+
+[jemalloc]: https://github.com/jemalloc/jemalloc
+
+The `#[global_allocator]` attribute, however, allows configuring this choice.
+You can use this to implement a completely custom global allocator to route all
+default allocation requests to a custom object. Defined in [RFC 1974] usage
+looks like:
+
+[RFC 1974]: https://github.com/rust-lang/rfcs/pull/1974
+
+```rust
+#![feature(global_allocator, heap_api)]
+
+use std::heap::{Alloc, System, Layout, AllocErr};
+
+struct MyAllocator;
+
+unsafe impl<'a> Alloc for &'a MyAllocator {
+    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+        System.alloc(layout)
+    }
+
+    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
+        System.dealloc(ptr, layout)
+    }
+}
+
+#[global_allocator]
+static GLOBAL: MyAllocator = MyAllocator;
+
+fn main() {
+    // This `Vec` will allocate memory through `GLOBAL` above
+    let mut v = Vec::new();
+    v.push(1);
+}
+```
+
+And that's it! The `#[global_allocator]` attribute is applied to a `static`
+which implements the `Alloc` trait in the `std::heap` module. Note, though,
+that the implementation is defined for `&MyAllocator`, not just `MyAllocator`.
+You may wish, however, to also provide `Alloc for MyAllocator` for other use
+cases.
+
+A crate can only have one instance of `#[global_allocator]` and this instance
+may be loaded through a dependency. For example `#[global_allocator]` above
+could have been placed in one of the dependencies loaded through `extern crate`.
+
+Note that `Alloc` itself is an `unsafe` trait, with much documentation on the
+trait itself about usage and for implementors. Extra care should be taken when
+implementing a global allocator as well as the allocator may be called from many
+portions of the standard library, such as the panicking routine. As a result it
+is highly recommended to not panic during allocation and work in as many
+situations with as few dependencies as possible as well.
index bf38629ed38a7a344eb5214842a49c340428fab1..ca5388b47014781dc3b2c25fd1213a0c2339890b 100644 (file)
@@ -13,7 +13,7 @@
                       slightly, especially to possibly take into account the \
                       types being stored to make room for a future \
                       tracing garbage collector",
-            issue = "27700")]
+            issue = "32838")]
 
 use core::cmp;
 use core::fmt;
@@ -73,6 +73,7 @@ impl Layout {
     /// * `size`, when rounded up to the nearest multiple of `align`,
     ///    must not overflow (i.e. the rounded value must be less than
     ///    `usize::MAX`).
+    #[inline]
     pub fn from_size_align(size: usize, align: usize) -> Option<Layout> {
         if !align.is_power_of_two() {
             return None;
@@ -96,13 +97,28 @@ pub fn from_size_align(size: usize, align: usize) -> Option<Layout> {
             return None;
         }
 
-        Some(Layout { size: size, align: align })
+        unsafe {
+            Some(Layout::from_size_align_unchecked(size, align))
+        }
+    }
+
+    /// Creates a layout, bypassing all checks.
+    ///
+    /// # Unsafety
+    ///
+    /// This function is unsafe as it does not verify that `align` is a power of
+    /// two nor that `size` aligned to `align` fits within the address space.
+    #[inline]
+    pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Layout {
+        Layout { size: size, align: align }
     }
 
     /// The minimum size in bytes for a memory block of this layout.
+    #[inline]
     pub fn size(&self) -> usize { self.size }
 
     /// The minimum byte alignment for a memory block of this layout.
+    #[inline]
     pub fn align(&self) -> usize { self.align }
 
     /// Constructs a `Layout` suitable for holding a value of type `T`.
@@ -135,6 +151,7 @@ pub fn for_value<T: ?Sized>(t: &T) -> Self {
     ///
     /// Panics if the combination of `self.size` and the given `align`
     /// violates the conditions listed in `from_size_align`.
+    #[inline]
     pub fn align_to(&self, align: usize) -> Self {
         Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap()
     }
@@ -155,6 +172,7 @@ pub fn align_to(&self, align: usize) -> Self {
     /// to be less than or equal to the alignment of the starting
     /// address for the whole allocated block of memory. One way to
     /// satisfy this constraint is to ensure `align <= self.align`.
+    #[inline]
     pub fn padding_needed_for(&self, align: usize) -> usize {
         let len = self.size();
 
@@ -556,6 +574,7 @@ fn oom(&mut self, _: AllocErr) -> ! {
     /// However, for clients that do not wish to track the capacity
     /// returned by `alloc_excess` locally, this method is likely to
     /// produce useful results.
+    #[inline]
     fn usable_size(&self, layout: &Layout) -> (usize, usize) {
         (layout.size(), layout.size())
     }
index 7c51c4b161ca861693e07cfed920fe8b5b0b1935..d9edf50b9c8ec28b18a4afd04abf40b7934d391a 100644 (file)
@@ -23,7 +23,6 @@
 use core::borrow;
 use core::fmt;
 use core::cmp::Ordering;
-use core::mem::{align_of_val, size_of_val};
 use core::intrinsics::abort;
 use core::mem;
 use core::mem::uninitialized;
@@ -34,7 +33,8 @@
 use core::hash::{Hash, Hasher};
 use core::{isize, usize};
 use core::convert::From;
-use heap::deallocate;
+
+use heap::{Heap, Alloc, Layout};
 
 /// A soft limit on the amount of references that may be made to an `Arc`.
 ///
@@ -503,7 +503,7 @@ unsafe fn drop_slow(&mut self) {
 
         if self.inner().weak.fetch_sub(1, Release) == 1 {
             atomic::fence(Acquire);
-            deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
+            Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr))
         }
     }
 
@@ -1007,7 +1007,9 @@ fn drop(&mut self) {
         // ref, which can only happen after the lock is released.
         if self.inner().weak.fetch_sub(1, Release) == 1 {
             atomic::fence(Acquire);
-            unsafe { deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) }
+            unsafe {
+                Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr))
+            }
         }
     }
 }
index 4a43018e973b176b72c36e75125d4926b4b648d8..76cf10f0d55ea9ecded8f6184986edd40b05fb95 100644 (file)
@@ -55,7 +55,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use heap;
+use heap::{Heap, Layout, Alloc};
 use raw_vec::RawVec;
 
 use core::any::Any;
@@ -135,8 +135,7 @@ pub struct ExchangeHeapSingleton {
 #[allow(missing_debug_implementations)]
 pub struct IntermediateBox<T: ?Sized> {
     ptr: *mut u8,
-    size: usize,
-    align: usize,
+    layout: Layout,
     marker: marker::PhantomData<*mut T>,
 }
 
@@ -156,23 +155,21 @@ unsafe fn finalize<T>(b: IntermediateBox<T>) -> Box<T> {
 }
 
 fn make_place<T>() -> IntermediateBox<T> {
-    let size = mem::size_of::<T>();
-    let align = mem::align_of::<T>();
+    let layout = Layout::new::<T>();
 
-    let p = if size == 0 {
+    let p = if layout.size() == 0 {
         mem::align_of::<T>() as *mut u8
     } else {
-        let p = unsafe { heap::allocate(size, align) };
-        if p.is_null() {
-            panic!("Box make_place allocation failure.");
+        unsafe {
+            Heap.alloc(layout.clone()).unwrap_or_else(|err| {
+                Heap.oom(err)
+            })
         }
-        p
     };
 
     IntermediateBox {
         ptr: p,
-        size: size,
-        align: align,
+        layout: layout,
         marker: marker::PhantomData,
     }
 }
@@ -221,8 +218,10 @@ fn make_place(self) -> IntermediateBox<T> {
            issue = "27779")]
 impl<T: ?Sized> Drop for IntermediateBox<T> {
     fn drop(&mut self) {
-        if self.size > 0 {
-            unsafe { heap::deallocate(self.ptr, self.size, self.align) }
+        if self.layout.size() > 0 {
+            unsafe {
+                Heap.dealloc(self.ptr, self.layout.clone())
+            }
         }
     }
 }
index 811174b331e2b3669fa4bd9477fc6ecfbc23047f..0eaff6f2192c8a22281b7db3da8498e8963af22c 100644 (file)
@@ -48,7 +48,7 @@
 use core::slice;
 
 use boxed::Box;
-use heap;
+use heap::{Heap, Alloc, Layout};
 
 const B: usize = 6;
 pub const MIN_LEN: usize = B - 1;
@@ -254,11 +254,7 @@ pub fn pop_level(&mut self) {
         self.as_mut().as_leaf_mut().parent = ptr::null();
 
         unsafe {
-            heap::deallocate(
-                top,
-                mem::size_of::<InternalNode<K, V>>(),
-                mem::align_of::<InternalNode<K, V>>()
-            );
+            Heap.dealloc(top, Layout::new::<InternalNode<K, V>>());
         }
     }
 }
@@ -445,7 +441,7 @@ pub unsafe fn deallocate_and_ascend(self) -> Option<
     > {
         let ptr = self.as_leaf() as *const LeafNode<K, V> as *const u8 as *mut u8;
         let ret = self.ascend().ok();
-        heap::deallocate(ptr, mem::size_of::<LeafNode<K, V>>(), mem::align_of::<LeafNode<K, V>>());
+        Heap.dealloc(ptr, Layout::new::<LeafNode<K, V>>());
         ret
     }
 }
@@ -466,11 +462,7 @@ pub unsafe fn deallocate_and_ascend(self) -> Option<
     > {
         let ptr = self.as_internal() as *const InternalNode<K, V> as *const u8 as *mut u8;
         let ret = self.ascend().ok();
-        heap::deallocate(
-            ptr,
-            mem::size_of::<InternalNode<K, V>>(),
-            mem::align_of::<InternalNode<K, V>>()
-        );
+        Heap.dealloc(ptr, Layout::new::<InternalNode<K, V>>());
         ret
     }
 }
@@ -1252,16 +1244,14 @@ pub fn merge(mut self)
                     ).correct_parent_link();
                 }
 
-                heap::deallocate(
+                Heap.dealloc(
                     right_node.node.get() as *mut u8,
-                    mem::size_of::<InternalNode<K, V>>(),
-                    mem::align_of::<InternalNode<K, V>>()
+                    Layout::new::<InternalNode<K, V>>(),
                 );
             } else {
-                heap::deallocate(
+                Heap.dealloc(
                     right_node.node.get() as *mut u8,
-                    mem::size_of::<LeafNode<K, V>>(),
-                    mem::align_of::<LeafNode<K, V>>()
+                    Layout::new::<LeafNode<K, V>>(),
                 );
             }
 
index d46c6a83ff32c64069c50f985838e1885199909b..1d959ac5bf6dcaf06a2a4dea32bb69ee38b1067e 100644 (file)
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![unstable(feature = "heap_api",
+#![unstable(feature = "allocator_api",
             reason = "the precise API and guarantees it provides may be tweaked \
                       slightly, especially to possibly take into account the \
                       types being stored to make room for a future \
                       tracing garbage collector",
-            issue = "27700")]
+            issue = "32838")]
 
-use allocator::{Alloc, AllocErr, CannotReallocInPlace, Layout};
-use core::{isize, usize, cmp, ptr};
 use core::intrinsics::{min_align_of_val, size_of_val};
+use core::mem::{self, ManuallyDrop};
+use core::usize;
 
-#[allow(improper_ctypes)]
-extern "C" {
-    #[allocator]
-    fn __rust_allocate(size: usize, align: usize) -> *mut u8;
-    fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8;
-    fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize);
-    fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8;
-    fn __rust_reallocate_inplace(ptr: *mut u8,
-                                 old_size: usize,
-                                 size: usize,
-                                 align: usize)
-                                 -> usize;
-    fn __rust_usable_size(size: usize, align: usize) -> usize;
+pub use allocator::*;
+#[doc(hidden)]
+pub mod __core {
+    pub use core::*;
 }
 
-#[inline(always)]
-fn check_size_and_alignment(size: usize, align: usize) {
-    debug_assert!(size != 0);
-    debug_assert!(size <= isize::MAX as usize,
-                  "Tried to allocate too much: {} bytes",
-                  size);
-    debug_assert!(usize::is_power_of_two(align),
-                  "Invalid alignment of allocation: {}",
-                  align);
+extern "Rust" {
+    #[allocator]
+    fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8;
+    fn __rust_oom(err: *const u8) -> !;
+    fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
+    fn __rust_usable_size(layout: *const u8,
+                          min: *mut usize,
+                          max: *mut usize);
+    fn __rust_realloc(ptr: *mut u8,
+                      old_size: usize,
+                      old_align: usize,
+                      new_size: usize,
+                      new_align: usize,
+                      err: *mut u8) -> *mut u8;
+    fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8;
+    fn __rust_alloc_excess(size: usize,
+                           align: usize,
+                           excess: *mut usize,
+                           err: *mut u8) -> *mut u8;
+    fn __rust_realloc_excess(ptr: *mut u8,
+                             old_size: usize,
+                             old_align: usize,
+                             new_size: usize,
+                             new_align: usize,
+                             excess: *mut usize,
+                             err: *mut u8) -> *mut u8;
+    fn __rust_grow_in_place(ptr: *mut u8,
+                            old_size: usize,
+                            old_align: usize,
+                            new_size: usize,
+                            new_align: usize) -> u8;
+    fn __rust_shrink_in_place(ptr: *mut u8,
+                              old_size: usize,
+                              old_align: usize,
+                              new_size: usize,
+                              new_align: usize) -> u8;
 }
 
 #[derive(Copy, Clone, Default, Debug)]
-pub struct HeapAlloc;
+pub struct Heap;
 
-unsafe impl Alloc for HeapAlloc {
+unsafe impl Alloc for Heap {
+    #[inline]
     unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
-        let addr = allocate(layout.size(), layout.align());
-        if addr.is_null() {
-            Err(AllocErr::Exhausted { request: layout })
+        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
+        let ptr = __rust_alloc(layout.size(),
+                               layout.align(),
+                               &mut *err as *mut AllocErr as *mut u8);
+        if ptr.is_null() {
+            Err(ManuallyDrop::into_inner(err))
         } else {
-            Ok(addr)
+            Ok(ptr)
         }
     }
 
-    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
-        let addr = allocate_zeroed(layout.size(), layout.align());
-        if addr.is_null() {
-            Err(AllocErr::Exhausted { request: layout })
-        } else {
-            Ok(addr)
+    #[inline]
+    fn oom(&mut self, err: AllocErr) -> ! {
+        unsafe {
+            __rust_oom(&err as *const AllocErr as *const u8)
         }
     }
 
+    #[inline]
     unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
-        deallocate(ptr, layout.size(), layout.align());
+        __rust_dealloc(ptr, layout.size(), layout.align())
     }
 
+    #[inline]
     fn usable_size(&self, layout: &Layout) -> (usize, usize) {
-        (layout.size(), usable_size(layout.size(), layout.align()))
+        let mut min = 0;
+        let mut max = 0;
+        unsafe {
+            __rust_usable_size(layout as *const Layout as *const u8,
+                               &mut min,
+                               &mut max);
+        }
+        (min, max)
     }
 
+    #[inline]
     unsafe fn realloc(&mut self,
                       ptr: *mut u8,
                       layout: Layout,
                       new_layout: Layout)
                       -> Result<*mut u8, AllocErr>
     {
-        let old_size = layout.size();
-        let new_size = new_layout.size();
-        if layout.align() == new_layout.align() {
-            let new_ptr = reallocate(ptr, old_size, new_size, layout.align());
-            if new_ptr.is_null() {
-                // We assume `reallocate` already tried alloc + copy +
-                // dealloc fallback; thus pointless to repeat effort
-                Err(AllocErr::Exhausted { request: new_layout })
-            } else {
-                Ok(new_ptr)
-            }
+        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
+        let ptr = __rust_realloc(ptr,
+                                 layout.size(),
+                                 layout.align(),
+                                 new_layout.size(),
+                                 new_layout.align(),
+                                 &mut *err as *mut AllocErr as *mut u8);
+        if ptr.is_null() {
+            Err(ManuallyDrop::into_inner(err))
         } else {
-            // if alignments don't match, fall back on alloc + copy + dealloc
-            let result = self.alloc(new_layout);
-            if let Ok(new_ptr) = result {
-                ptr::copy_nonoverlapping(ptr as *const u8, new_ptr, cmp::min(old_size, new_size));
-                self.dealloc(ptr, layout);
-            }
-            result
+            mem::forget(err);
+            Ok(ptr)
         }
     }
 
+    #[inline]
+    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
+        let ptr = __rust_alloc_zeroed(layout.size(),
+                                      layout.align(),
+                                      &mut *err as *mut AllocErr as *mut u8);
+        if ptr.is_null() {
+            Err(ManuallyDrop::into_inner(err))
+        } else {
+            Ok(ptr)
+        }
+    }
+
+    #[inline]
+    unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
+        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
+        let mut size = 0;
+        let ptr = __rust_alloc_excess(layout.size(),
+                                      layout.align(),
+                                      &mut size,
+                                      &mut *err as *mut AllocErr as *mut u8);
+        if ptr.is_null() {
+            Err(ManuallyDrop::into_inner(err))
+        } else {
+            Ok(Excess(ptr, size))
+        }
+    }
+
+    #[inline]
+    unsafe fn realloc_excess(&mut self,
+                             ptr: *mut u8,
+                             layout: Layout,
+                             new_layout: Layout) -> Result<Excess, AllocErr> {
+        let mut err = ManuallyDrop::new(mem::uninitialized::<AllocErr>());
+        let mut size = 0;
+        let ptr = __rust_realloc_excess(ptr,
+                                        layout.size(),
+                                        layout.align(),
+                                        new_layout.size(),
+                                        new_layout.align(),
+                                        &mut size,
+                                        &mut *err as *mut AllocErr as *mut u8);
+        if ptr.is_null() {
+            Err(ManuallyDrop::into_inner(err))
+        } else {
+            Ok(Excess(ptr, size))
+        }
+    }
+
+    #[inline]
     unsafe fn grow_in_place(&mut self,
                             ptr: *mut u8,
                             layout: Layout,
                             new_layout: Layout)
                             -> Result<(), CannotReallocInPlace>
     {
-        // grow_in_place spec requires this, and the spec for reallocate_inplace
-        // makes it hard to detect failure if it does not hold.
         debug_assert!(new_layout.size() >= layout.size());
-
-        if layout.align() != new_layout.align() { // reallocate_inplace requires this.
-            return Err(CannotReallocInPlace);
+        debug_assert!(new_layout.align() == layout.align());
+        let ret = __rust_grow_in_place(ptr,
+                                       layout.size(),
+                                       layout.align(),
+                                       new_layout.size(),
+                                       new_layout.align());
+        if ret != 0 {
+            Ok(())
+        } else {
+            Err(CannotReallocInPlace)
         }
-        let usable = reallocate_inplace(ptr, layout.size(), new_layout.size(), layout.align());
-        if usable >= new_layout.size() { Ok(()) } else { Err(CannotReallocInPlace) }
     }
-}
-
-// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
 
-/// Return a pointer to `size` bytes of memory aligned to `align`.
-///
-/// On failure, return a null pointer.
-///
-/// Behavior is undefined if the requested size is 0 or the alignment is not a
-/// power of 2. The alignment must be no larger than the largest supported page
-/// size on the platform.
-#[inline]
-pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
-    check_size_and_alignment(size, align);
-    __rust_allocate(size, align)
-}
-
-/// Return a pointer to `size` bytes of memory aligned to `align` and
-/// initialized to zeroes.
-///
-/// On failure, return a null pointer.
-///
-/// Behavior is undefined if the requested size is 0 or the alignment is not a
-/// power of 2. The alignment must be no larger than the largest supported page
-/// size on the platform.
-#[inline]
-pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
-    check_size_and_alignment(size, align);
-    __rust_allocate_zeroed(size, align)
-}
-
-/// Resize the allocation referenced by `ptr` to `size` bytes.
-///
-/// On failure, return a null pointer and leave the original allocation intact.
-///
-/// If the allocation was relocated, the memory at the passed-in pointer is
-/// undefined after the call.
-///
-/// Behavior is undefined if the requested size is 0 or the alignment is not a
-/// power of 2. The alignment must be no larger than the largest supported page
-/// size on the platform.
-///
-/// The `old_size` and `align` parameters are the parameters that were used to
-/// create the allocation referenced by `ptr`. The `old_size` parameter may be
-/// any value in range_inclusive(requested_size, usable_size).
-#[inline]
-pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
-    check_size_and_alignment(size, align);
-    __rust_reallocate(ptr, old_size, size, align)
-}
-
-/// Resize the allocation referenced by `ptr` to `size` bytes.
-///
-/// If the operation succeeds, it returns `usable_size(size, align)` and if it
-/// fails (or is a no-op) it returns `usable_size(old_size, align)`.
-///
-/// Behavior is undefined if the requested size is 0 or the alignment is not a
-/// power of 2. The alignment must be no larger than the largest supported page
-/// size on the platform.
-///
-/// The `old_size` and `align` parameters are the parameters that were used to
-/// create the allocation referenced by `ptr`. The `old_size` parameter may be
-/// any value in range_inclusive(requested_size, usable_size).
-#[inline]
-pub unsafe fn reallocate_inplace(ptr: *mut u8,
-                                 old_size: usize,
-                                 size: usize,
-                                 align: usize)
-                                 -> usize {
-    check_size_and_alignment(size, align);
-    __rust_reallocate_inplace(ptr, old_size, size, align)
-}
-
-/// Deallocates the memory referenced by `ptr`.
-///
-/// The `ptr` parameter must not be null.
-///
-/// The `old_size` and `align` parameters are the parameters that were used to
-/// create the allocation referenced by `ptr`. The `old_size` parameter may be
-/// any value in range_inclusive(requested_size, usable_size).
-#[inline]
-pub unsafe fn deallocate(ptr: *mut u8, old_size: usize, align: usize) {
-    __rust_deallocate(ptr, old_size, align)
-}
-
-/// Returns the usable size of an allocation created with the specified the
-/// `size` and `align`.
-#[inline]
-pub fn usable_size(size: usize, align: usize) -> usize {
-    unsafe { __rust_usable_size(size, align) }
+    #[inline]
+    unsafe fn shrink_in_place(&mut self,
+                              ptr: *mut u8,
+                              layout: Layout,
+                              new_layout: Layout) -> Result<(), CannotReallocInPlace> {
+        debug_assert!(new_layout.size() <= layout.size());
+        debug_assert!(new_layout.align() == layout.align());
+        let ret = __rust_shrink_in_place(ptr,
+                                         layout.size(),
+                                         layout.align(),
+                                         new_layout.size(),
+                                         new_layout.align());
+        if ret != 0 {
+            Ok(())
+        } else {
+            Err(CannotReallocInPlace)
+        }
+    }
 }
 
 /// An arbitrary non-null address to represent zero-size allocations.
@@ -228,11 +233,10 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
     if size == 0 {
         align as *mut u8
     } else {
-        let ptr = allocate(size, align);
-        if ptr.is_null() {
-            ::oom()
-        }
-        ptr
+        let layout = Layout::from_size_align_unchecked(size, align);
+        Heap.alloc(layout).unwrap_or_else(|err| {
+            Heap.oom(err)
+        })
     }
 }
 
@@ -243,7 +247,8 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
     let align = min_align_of_val(&*ptr);
     // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
     if size != 0 {
-        deallocate(ptr as *mut u8, size, align);
+        let layout = Layout::from_size_align_unchecked(size, align);
+        Heap.dealloc(ptr as *mut u8, layout);
     }
 }
 
@@ -252,38 +257,22 @@ mod tests {
     extern crate test;
     use self::test::Bencher;
     use boxed::Box;
-    use heap;
+    use heap::{Heap, Alloc, Layout};
 
     #[test]
     fn allocate_zeroed() {
         unsafe {
-            let size = 1024;
-            let ptr = heap::allocate_zeroed(size, 1);
-            if ptr.is_null() {
-                ::oom()
-            }
+            let layout = Layout::from_size_align(1024, 1).unwrap();
+            let ptr = Heap.alloc_zeroed(layout.clone())
+                .unwrap_or_else(|e| Heap.oom(e));
 
-            let end = ptr.offset(size as isize);
+            let end = ptr.offset(layout.size() as isize);
             let mut i = ptr;
             while i < end {
                 assert_eq!(*i, 0);
                 i = i.offset(1);
             }
-            heap::deallocate(ptr, size, 1);
-        }
-    }
-
-    #[test]
-    fn basic_reallocate_inplace_noop() {
-        unsafe {
-            let size = 4000;
-            let ptr = heap::allocate(size, 8);
-            if ptr.is_null() {
-                ::oom()
-            }
-            let ret = heap::reallocate_inplace(ptr, size, size, 8);
-            heap::deallocate(ptr, size, 8);
-            assert_eq!(ret, heap::usable_size(size, 8));
+            Heap.dealloc(ptr, layout);
         }
     }
 
index 23da29131362e6c3e0773668df58d5f30929200a..b419aeb5ab5931e56eac4c565dfaeb670d9426b3 100644 (file)
@@ -85,7 +85,7 @@
 #![cfg_attr(not(test), feature(slice_rotate))]
 #![cfg_attr(not(test), feature(str_checked_slicing))]
 #![cfg_attr(test, feature(rand, test))]
-#![feature(allocator)]
+#![cfg_attr(stage0, feature(allocator))]
 #![feature(allow_internal_unstable)]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(unicode)]
 #![feature(unique)]
 #![feature(unsize)]
+#![cfg_attr(not(stage0), feature(allocator_internals))]
 
 #![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol))]
 #![cfg_attr(test, feature(test, box_heap))]
@@ -168,7 +169,6 @@ mod boxed {
 pub mod arc;
 pub mod rc;
 pub mod raw_vec;
-pub mod oom;
 
 // collections modules
 pub mod binary_heap;
@@ -260,8 +260,6 @@ trait SpecExtend<I: IntoIterator> {
     fn spec_extend(&mut self, iter: I);
 }
 
-pub use oom::oom;
-
 #[doc(no_inline)]
 pub use binary_heap::BinaryHeap;
 #[doc(no_inline)]
diff --git a/src/liballoc/oom.rs b/src/liballoc/oom.rs
deleted file mode 100644 (file)
index 3640156..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2014-2015 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.
-
-#[cfg(target_has_atomic = "ptr")]
-pub use self::imp::set_oom_handler;
-use core::intrinsics;
-
-fn default_oom_handler() -> ! {
-    // The default handler can't do much more since we can't assume the presence
-    // of libc or any way of printing an error message.
-    unsafe { intrinsics::abort() }
-}
-
-/// Common out-of-memory routine
-#[cold]
-#[inline(never)]
-#[unstable(feature = "oom", reason = "not a scrutinized interface",
-           issue = "27700")]
-pub fn oom() -> ! {
-    self::imp::oom()
-}
-
-#[cfg(target_has_atomic = "ptr")]
-mod imp {
-    use core::mem;
-    use core::sync::atomic::{AtomicPtr, Ordering};
-
-    static OOM_HANDLER: AtomicPtr<()> = AtomicPtr::new(super::default_oom_handler as *mut ());
-
-    #[inline(always)]
-    pub fn oom() -> ! {
-        let value = OOM_HANDLER.load(Ordering::SeqCst);
-        let handler: fn() -> ! = unsafe { mem::transmute(value) };
-        handler();
-    }
-
-    /// Set a custom handler for out-of-memory conditions
-    ///
-    /// To avoid recursive OOM failures, it is critical that the OOM handler does
-    /// not allocate any memory itself.
-    #[unstable(feature = "oom", reason = "not a scrutinized interface",
-               issue = "27700")]
-    pub fn set_oom_handler(handler: fn() -> !) {
-        OOM_HANDLER.store(handler as *mut (), Ordering::SeqCst);
-    }
-}
-
-#[cfg(not(target_has_atomic = "ptr"))]
-mod imp {
-    #[inline(always)]
-    pub fn oom() -> ! {
-        super::default_oom_handler()
-    }
-}
index c56a93c046041082a0a000e4e3d0a5208b8b1888..d1aab4c70be4a9aa59a9142921febcb50c851adc 100644 (file)
@@ -12,7 +12,7 @@
 use core::ptr::{self, Unique};
 use core::mem;
 use core::slice;
-use heap::{HeapAlloc};
+use heap::Heap;
 use super::boxed::Box;
 use core::ops::Drop;
 use core::cmp;
@@ -45,7 +45,7 @@
 /// field. This allows zero-sized types to not be special-cased by consumers of
 /// this type.
 #[allow(missing_debug_implementations)]
-pub struct RawVec<T, A: Alloc = HeapAlloc> {
+pub struct RawVec<T, A: Alloc = Heap> {
     ptr: Unique<T>,
     cap: usize,
     a: A,
@@ -112,14 +112,14 @@ fn allocate_in(cap: usize, zeroed: bool, mut a: A) -> Self {
     }
 }
 
-impl<T> RawVec<T, HeapAlloc> {
+impl<T> RawVec<T, Heap> {
     /// Creates the biggest possible RawVec (on the system heap)
     /// without allocating. If T has positive size, then this makes a
     /// RawVec with capacity 0. If T has 0 size, then it it makes a
     /// RawVec with capacity `usize::MAX`. Useful for implementing
     /// delayed allocation.
     pub fn new() -> Self {
-        Self::new_in(HeapAlloc)
+        Self::new_in(Heap)
     }
 
     /// Creates a RawVec (on the system heap) with exactly the
@@ -139,13 +139,13 @@ pub fn new() -> Self {
     /// Aborts on OOM
     #[inline]
     pub fn with_capacity(cap: usize) -> Self {
-        RawVec::allocate_in(cap, false, HeapAlloc)
+        RawVec::allocate_in(cap, false, Heap)
     }
 
     /// Like `with_capacity` but guarantees the buffer is zeroed.
     #[inline]
     pub fn with_capacity_zeroed(cap: usize) -> Self {
-        RawVec::allocate_in(cap, true, HeapAlloc)
+        RawVec::allocate_in(cap, true, Heap)
     }
 }
 
@@ -166,7 +166,7 @@ pub unsafe fn from_raw_parts_in(ptr: *mut T, cap: usize, a: A) -> Self {
     }
 }
 
-impl<T> RawVec<T, HeapAlloc> {
+impl<T> RawVec<T, Heap> {
     /// Reconstitutes a RawVec from a pointer, capacity.
     ///
     /// # Undefined Behavior
@@ -178,7 +178,7 @@ pub unsafe fn from_raw_parts(ptr: *mut T, cap: usize) -> Self {
         RawVec {
             ptr: Unique::new(ptr),
             cap: cap,
-            a: HeapAlloc,
+            a: Heap,
         }
     }
 
@@ -609,7 +609,7 @@ pub fn shrink_to_fit(&mut self, amount: usize) {
     }
 }
 
-impl<T> RawVec<T, HeapAlloc> {
+impl<T> RawVec<T, Heap> {
     /// Converts the entire buffer into `Box<[T]>`.
     ///
     /// While it is not *strictly* Undefined Behavior to call
@@ -693,13 +693,13 @@ unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
                 if size > self.fuel {
                     return Err(AllocErr::Unsupported { details: "fuel exhausted" });
                 }
-                match HeapAlloc.alloc(layout) {
+                match Heap.alloc(layout) {
                     ok @ Ok(_) => { self.fuel -= size; ok }
                     err @ Err(_) => err,
                 }
             }
             unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
-                HeapAlloc.dealloc(ptr, layout)
+                Heap.dealloc(ptr, layout)
             }
         }
 
index 94fe36d01a5a529dd9aa0a18f2a06ca23cbff682..306136b21c84b2cb6013be9e4ccbe044c4923fb3 100644 (file)
 use core::intrinsics::abort;
 use core::marker;
 use core::marker::Unsize;
-use core::mem::{self, align_of_val, forget, size_of, size_of_val, uninitialized};
+use core::mem::{self, forget, size_of, size_of_val, uninitialized};
 use core::ops::Deref;
 use core::ops::CoerceUnsized;
 use core::ptr::{self, Shared};
 use core::convert::From;
 
-use heap::{allocate, deallocate, box_free};
+use heap::{Heap, Alloc, Layout, box_free};
 use raw_vec::RawVec;
 
 struct RcBox<T: ?Sized> {
@@ -461,7 +461,8 @@ pub fn __from_array(value: Box<[T]>) -> Rc<[T]> {
             // FIXME(custom-DST): creating this invalid &[T] is dubiously defined,
             // we should have a better way of getting the size/align
             // of a DST from its unsized part.
-            let ptr = allocate(size_of_val(&*ptr), align_of_val(&*ptr));
+            let ptr = Heap.alloc(Layout::for_value(&*ptr))
+                .unwrap_or_else(|e| Heap.oom(e));
             let ptr: *mut RcBox<[T]> = mem::transmute([ptr as usize, value.len()]);
 
             // Initialize the new RcBox.
@@ -719,7 +720,7 @@ fn drop(&mut self) {
                 self.dec_weak();
 
                 if self.weak() == 0 {
-                    deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
+                    Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr));
                 }
             }
         }
@@ -1097,7 +1098,7 @@ fn drop(&mut self) {
             // the weak count starts at 1, and will only go to zero if all
             // the strong pointers have disappeared.
             if self.weak() == 0 {
-                deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
+                Heap.dealloc(ptr as *mut u8, Layout::for_value(&*ptr));
             }
         }
     }
index 49e5baad74dda4322d93ee395ba63a3999fa3f00..99c0bf2aaab4847865d398b07bda98e70bf77759 100644 (file)
@@ -15,6 +15,10 @@ doc = false
 core = { path = "../libcore" }
 libc = { path = "../rustc/libc_shim" }
 
+[target.'cfg(not(stage0))'.dependencies]
+alloc = { path = "../liballoc" }
+alloc_system = { path = "../liballoc_system" }
+
 [build-dependencies]
 build_helper = { path = "../build_helper" }
 gcc = "0.3.50"
index 288531cb5b21f3b438edb8f3fb1d0bca76b4f520..72686ddcc09efda99db2c166730b71fe1eac759f 100644 (file)
 #![crate_name = "alloc_jemalloc"]
 #![crate_type = "rlib"]
 #![no_std]
-#![allocator]
 #![unstable(feature = "alloc_jemalloc",
             reason = "this library is unlikely to be stabilized in its current \
                       form or name",
             issue = "27783")]
 #![deny(warnings)]
-#![feature(allocator)]
 #![feature(libc)]
 #![feature(staged_api)]
-
+#![feature(linkage)]
+#![cfg_attr(stage0, allocator)]
+#![cfg_attr(stage0, feature(allocator))]
+#![cfg_attr(not(stage0), feature(global_allocator))]
+#![cfg_attr(all(not(stage0), not(dummy_jemalloc)), feature(allocator_api))]
+#![cfg_attr(not(stage0), feature(alloc))]
+#![cfg_attr(not(stage0), feature(alloc_system))]
+#![cfg_attr(dummy_jemalloc, allow(dead_code))]
+
+#[cfg(not(stage0))]
+extern crate alloc;
+#[cfg(not(stage0))]
+extern crate alloc_system;
 extern crate libc;
 
-pub use imp::*;
+#[cfg(all(not(stage0), not(dummy_jemalloc)))]
+pub use contents::*;
+#[cfg(all(not(stage0), not(dummy_jemalloc)))]
+mod contents {
+    use core::ptr;
 
-// See comments in build.rs for why we sometimes build a crate that does nothing
-#[cfg(not(dummy_jemalloc))]
-mod imp {
+    use alloc::heap::{Alloc, AllocErr, Layout};
+    use alloc_system::System;
     use libc::{c_int, c_void, size_t};
 
     // Note that the symbols here are prefixed by default on macOS and Windows (we
@@ -91,96 +104,152 @@ fn align_to_flags(align: usize) -> c_int {
         }
     }
 
-    #[no_mangle]
-    pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
-        let flags = align_to_flags(align);
-        unsafe { mallocx(size as size_t, flags) as *mut u8 }
-    }
+    // for symbol names src/librustc/middle/allocator.rs
+    // for signatures src/librustc_allocator/lib.rs
 
-    #[no_mangle]
-    pub extern "C" fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8 {
-        if align <= MIN_ALIGN {
-            unsafe { calloc(size as size_t, 1) as *mut u8 }
-        } else {
-            let flags = align_to_flags(align) | MALLOCX_ZERO;
-            unsafe { mallocx(size as size_t, flags) as *mut u8 }
-        }
-    }
+    // linkage directives are provided as part of the current compiler allocator
+    // ABI
 
     #[no_mangle]
-    pub extern "C" fn __rust_reallocate(ptr: *mut u8,
-                                        _old_size: usize,
-                                        size: usize,
-                                        align: usize)
-                                        -> *mut u8 {
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_alloc(size: usize,
+                                     align: usize,
+                                     err: *mut u8) -> *mut u8 {
         let flags = align_to_flags(align);
-        unsafe { rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
+        let ptr = mallocx(size as size_t, flags) as *mut u8;
+        if ptr.is_null() {
+            let layout = Layout::from_size_align_unchecked(size, align);
+            ptr::write(err as *mut AllocErr,
+                       AllocErr::Exhausted { request: layout });
+        }
+        ptr
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
-                                                _old_size: usize,
-                                                size: usize,
-                                                align: usize)
-                                                -> usize {
-        let flags = align_to_flags(align);
-        unsafe { xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_oom(err: *const u8) -> ! {
+        System.oom((*(err as *const AllocErr)).clone())
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_dealloc(ptr: *mut u8,
+                                       size: usize,
+                                       align: usize) {
         let flags = align_to_flags(align);
-        unsafe { sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
+        sdallocx(ptr as *mut c_void, size, flags);
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
-        let flags = align_to_flags(align);
-        unsafe { nallocx(size as size_t, flags) as usize }
-    }
-}
-
-#[cfg(dummy_jemalloc)]
-mod imp {
-    fn bogus() -> ! {
-        panic!("jemalloc is not implemented for this platform");
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_usable_size(layout: *const u8,
+                                           min: *mut usize,
+                                           max: *mut usize) {
+        let layout = &*(layout as *const Layout);
+        let flags = align_to_flags(layout.align());
+        let size = nallocx(layout.size(), flags) as usize;
+        *min = layout.size();
+        if size > 0 {
+            *max = size;
+        } else {
+            *max = layout.size();
+        }
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_allocate(_size: usize, _align: usize) -> *mut u8 {
-        bogus()
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_realloc(ptr: *mut u8,
+                                       _old_size: usize,
+                                       old_align: usize,
+                                       new_size: usize,
+                                       new_align: usize,
+                                       err: *mut u8) -> *mut u8 {
+        if new_align != old_align {
+            ptr::write(err as *mut AllocErr,
+                       AllocErr::Unsupported { details: "can't change alignments" });
+            return 0 as *mut u8
+        }
+
+        let flags = align_to_flags(new_align);
+        let ptr = rallocx(ptr as *mut c_void, new_size, flags) as *mut u8;
+        if ptr.is_null() {
+            let layout = Layout::from_size_align_unchecked(new_size, new_align);
+            ptr::write(err as *mut AllocErr,
+                       AllocErr::Exhausted { request: layout });
+        }
+        ptr
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_allocate_zeroed(_size: usize, _align: usize) -> *mut u8 {
-        bogus()
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_alloc_zeroed(size: usize,
+                                            align: usize,
+                                            err: *mut u8) -> *mut u8 {
+        let ptr = if align <= MIN_ALIGN {
+            calloc(size as size_t, 1) as *mut u8
+        } else {
+            let flags = align_to_flags(align) | MALLOCX_ZERO;
+            mallocx(size as size_t, flags) as *mut u8
+        };
+        if ptr.is_null() {
+            let layout = Layout::from_size_align_unchecked(size, align);
+            ptr::write(err as *mut AllocErr,
+                       AllocErr::Exhausted { request: layout });
+        }
+        ptr
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_reallocate(_ptr: *mut u8,
-                                        _old_size: usize,
-                                        _size: usize,
-                                        _align: usize)
-                                        -> *mut u8 {
-        bogus()
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_alloc_excess(size: usize,
+                                            align: usize,
+                                            excess: *mut usize,
+                                            err: *mut u8) -> *mut u8 {
+        let p = __rde_alloc(size, align, err);
+        if !p.is_null() {
+            *excess = size;
+        }
+        return p
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_reallocate_inplace(_ptr: *mut u8,
-                                                _old_size: usize,
-                                                _size: usize,
-                                                _align: usize)
-                                                -> usize {
-        bogus()
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_realloc_excess(ptr: *mut u8,
+                                              old_size: usize,
+                                              old_align: usize,
+                                              new_size: usize,
+                                              new_align: usize,
+                                              excess: *mut usize,
+                                              err: *mut u8) -> *mut u8 {
+        let p = __rde_realloc(ptr, old_size, old_align, new_size, new_align, err);
+        if !p.is_null() {
+            *excess = new_size;
+        }
+        return p
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_deallocate(_ptr: *mut u8, _old_size: usize, _align: usize) {
-        bogus()
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_grow_in_place(ptr: *mut u8,
+                                             old_size: usize,
+                                             old_align: usize,
+                                             new_size: usize,
+                                             new_align: usize) -> u8 {
+        __rde_shrink_in_place(ptr, old_size, old_align, new_size, new_align)
     }
 
     #[no_mangle]
-    pub extern "C" fn __rust_usable_size(_size: usize, _align: usize) -> usize {
-        bogus()
+    #[linkage = "external"]
+    pub unsafe extern fn __rde_shrink_in_place(ptr: *mut u8,
+                                               _old_size: usize,
+                                               old_align: usize,
+                                               new_size: usize,
+                                               new_align: usize) -> u8 {
+        if old_align == new_align {
+            let flags = align_to_flags(new_align);
+            (xallocx(ptr as *mut c_void, new_size, 0, flags) == new_size) as u8
+        } else {
+            0
+        }
     }
 }
index 8e3c2c0b9cc66695c58a3a31fca886d42a22e9b4..f20be5fdf5f2b207e318abbd386b84feaacea821 100644 (file)
@@ -12,3 +12,6 @@ doc = false
 [dependencies]
 core = { path = "../libcore" }
 libc = { path = "../rustc/libc_shim" }
+
+[target.'cfg(not(stage0))'.dependencies]
+alloc = { path = "../liballoc" }
index 1f36bc4fbcea73043049bdfb013378c22b3041b6..afecfc16f2c90c19d8580b0afd7c1c51c6d2260d 100644 (file)
 #![crate_name = "alloc_system"]
 #![crate_type = "rlib"]
 #![no_std]
-#![allocator]
 #![deny(warnings)]
 #![unstable(feature = "alloc_system",
             reason = "this library is unlikely to be stabilized in its current \
                       form or name",
             issue = "27783")]
-#![feature(allocator)]
+#![cfg_attr(stage0, allocator)]
+#![cfg_attr(stage0, feature(allocator))]
+#![cfg_attr(stage0, feature(core_intrinsics))]
+#![cfg_attr(not(stage0), feature(global_allocator))]
+#![cfg_attr(not(stage0), feature(allocator_api))]
+#![cfg_attr(not(stage0), feature(alloc))]
+#![cfg_attr(not(stage0), feature(core_intrinsics))]
 #![feature(staged_api)]
 #![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
 
               target_arch = "sparc64")))]
 const MIN_ALIGN: usize = 16;
 
-#[no_mangle]
-pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
-    unsafe { imp::allocate(size, align) }
-}
+#[cfg(stage0)]
+pub use old::*;
+#[cfg(stage0)]
+mod old;
 
-#[no_mangle]
-pub extern "C" fn __rust_allocate_zeroed(size: usize, align: usize) -> *mut u8 {
-    unsafe { imp::allocate_zeroed(size, align) }
-}
+#[cfg(not(stage0))]
+pub use new::System;
+#[cfg(not(stage0))]
+mod new {
+    pub extern crate alloc;
 
-#[no_mangle]
-pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
-    unsafe { imp::deallocate(ptr, old_size, align) }
-}
+    use self::alloc::heap::{Alloc, AllocErr, Layout, Excess, CannotReallocInPlace};
 
-#[no_mangle]
-pub extern "C" fn __rust_reallocate(ptr: *mut u8,
-                                    old_size: usize,
-                                    size: usize,
-                                    align: usize)
-                                    -> *mut u8 {
-    unsafe { imp::reallocate(ptr, old_size, size, align) }
-}
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub struct System;
 
-#[no_mangle]
-pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
-                                            old_size: usize,
-                                            size: usize,
-                                            align: usize)
-                                            -> usize {
-    unsafe { imp::reallocate_inplace(ptr, old_size, size, align) }
-}
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    unsafe impl Alloc for System {
+        #[inline]
+        unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+            (&*self).alloc(layout)
+        }
+
+        #[inline]
+        unsafe fn alloc_zeroed(&mut self, layout: Layout)
+            -> Result<*mut u8, AllocErr>
+        {
+            (&*self).alloc_zeroed(layout)
+        }
+
+        #[inline]
+        unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
+            (&*self).dealloc(ptr, layout)
+        }
+
+        #[inline]
+        unsafe fn realloc(&mut self,
+                          ptr: *mut u8,
+                          old_layout: Layout,
+                          new_layout: Layout) -> Result<*mut u8, AllocErr> {
+            (&*self).realloc(ptr, old_layout, new_layout)
+        }
 
-#[no_mangle]
-pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
-    imp::usable_size(size, align)
+        fn oom(&mut self, err: AllocErr) -> ! {
+            (&*self).oom(err)
+        }
+
+        #[inline]
+        fn usable_size(&self, layout: &Layout) -> (usize, usize) {
+            (&self).usable_size(layout)
+        }
+
+        #[inline]
+        unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
+            (&*self).alloc_excess(layout)
+        }
+
+        #[inline]
+        unsafe fn realloc_excess(&mut self,
+                                 ptr: *mut u8,
+                                 layout: Layout,
+                                 new_layout: Layout) -> Result<Excess, AllocErr> {
+            (&*self).realloc_excess(ptr, layout, new_layout)
+        }
+
+        #[inline]
+        unsafe fn grow_in_place(&mut self,
+                                ptr: *mut u8,
+                                layout: Layout,
+                                new_layout: Layout) -> Result<(), CannotReallocInPlace> {
+            (&*self).grow_in_place(ptr, layout, new_layout)
+        }
+
+        #[inline]
+        unsafe fn shrink_in_place(&mut self,
+                                  ptr: *mut u8,
+                                  layout: Layout,
+                                  new_layout: Layout) -> Result<(), CannotReallocInPlace> {
+            (&*self).shrink_in_place(ptr, layout, new_layout)
+        }
+    }
 }
 
-#[cfg(any(unix, target_os = "redox"))]
-mod imp {
+#[cfg(all(not(stage0), any(unix, target_os = "redox")))]
+mod platform {
     extern crate libc;
 
     use core::cmp;
     use core::ptr;
+
     use MIN_ALIGN;
+    use new::System;
+    use new::alloc::heap::{Alloc, AllocErr, Layout};
+
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    unsafe impl<'a> Alloc for &'a System {
+        #[inline]
+        unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+            let ptr = if layout.align() <= MIN_ALIGN {
+                libc::malloc(layout.size()) as *mut u8
+            } else {
+                aligned_malloc(&layout)
+            };
+            if !ptr.is_null() {
+                Ok(ptr)
+            } else {
+                Err(AllocErr::Exhausted { request: layout })
+            }
+        }
 
-    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
-        if align <= MIN_ALIGN {
-            libc::malloc(size as libc::size_t) as *mut u8
-        } else {
-            aligned_malloc(size, align)
+        #[inline]
+        unsafe fn alloc_zeroed(&mut self, layout: Layout)
+            -> Result<*mut u8, AllocErr>
+        {
+            if layout.align() <= MIN_ALIGN {
+                let ptr = libc::calloc(layout.size(), 1) as *mut u8;
+                if !ptr.is_null() {
+                    Ok(ptr)
+                } else {
+                    Err(AllocErr::Exhausted { request: layout })
+                }
+            } else {
+                let ret = self.alloc(layout.clone());
+                if let Ok(ptr) = ret {
+                    ptr::write_bytes(ptr, 0, layout.size());
+                }
+                ret
+            }
+        }
+
+        #[inline]
+        unsafe fn dealloc(&mut self, ptr: *mut u8, _layout: Layout) {
+            libc::free(ptr as *mut libc::c_void)
+        }
+
+        #[inline]
+        unsafe fn realloc(&mut self,
+                          ptr: *mut u8,
+                          old_layout: Layout,
+                          new_layout: Layout) -> Result<*mut u8, AllocErr> {
+            if old_layout.align() != new_layout.align() {
+                return Err(AllocErr::Unsupported {
+                    details: "cannot change alignment on `realloc`",
+                })
+            }
+
+            if new_layout.align() <= MIN_ALIGN {
+                let ptr = libc::realloc(ptr as *mut libc::c_void, new_layout.size());
+                if !ptr.is_null() {
+                    Ok(ptr as *mut u8)
+                } else {
+                    Err(AllocErr::Exhausted { request: new_layout })
+                }
+            } else {
+                let res = self.alloc(new_layout.clone());
+                if let Ok(new_ptr) = res {
+                    let size = cmp::min(old_layout.size(), new_layout.size());
+                    ptr::copy_nonoverlapping(ptr, new_ptr, size);
+                    self.dealloc(ptr, old_layout);
+                }
+                res
+            }
+        }
+
+        fn oom(&mut self, err: AllocErr) -> ! {
+            use core::fmt::{self, Write};
+
+            // Print a message to stderr before aborting to assist with
+            // debugging. It is critical that this code does not allocate any
+            // memory since we are in an OOM situation. Any errors are ignored
+            // while printing since there's nothing we can do about them and we
+            // are about to exit anyways.
+            drop(writeln!(Stderr, "fatal runtime error: {}", err));
+            unsafe {
+                ::core::intrinsics::abort();
+            }
+
+            struct Stderr;
+
+            impl Write for Stderr {
+                fn write_str(&mut self, s: &str) -> fmt::Result {
+                    unsafe {
+                        libc::write(libc::STDERR_FILENO,
+                                    s.as_ptr() as *const libc::c_void,
+                                    s.len());
+                    }
+                    Ok(())
+                }
+            }
         }
     }
 
     #[cfg(any(target_os = "android", target_os = "redox"))]
-    unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
+    #[inline]
+    unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
         // On android we currently target API level 9 which unfortunately
         // doesn't have the `posix_memalign` API used below. Instead we use
         // `memalign`, but this unfortunately has the property on some systems
@@ -112,74 +256,41 @@ unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
         // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
         // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
         //                                       /memory/aligned_memory.cc
-        libc::memalign(align as libc::size_t, size as libc::size_t) as *mut u8
+        libc::memalign(layout.align(), layout.size()) as *mut u8
     }
 
     #[cfg(not(any(target_os = "android", target_os = "redox")))]
-    unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
+    #[inline]
+    unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
         let mut out = ptr::null_mut();
-        let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
+        let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
         if ret != 0 {
             ptr::null_mut()
         } else {
             out as *mut u8
         }
     }
-
-    pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
-        if align <= MIN_ALIGN {
-            libc::calloc(size as libc::size_t, 1) as *mut u8
-        } else {
-            let ptr = aligned_malloc(size, align);
-            if !ptr.is_null() {
-                ptr::write_bytes(ptr, 0, size);
-            }
-            ptr
-        }
-    }
-
-    pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
-        if align <= MIN_ALIGN {
-            libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
-        } else {
-            let new_ptr = allocate(size, align);
-            if !new_ptr.is_null() {
-                ptr::copy(ptr, new_ptr, cmp::min(size, old_size));
-                deallocate(ptr, old_size, align);
-            }
-            new_ptr
-        }
-    }
-
-    pub unsafe fn reallocate_inplace(_ptr: *mut u8,
-                                     old_size: usize,
-                                     _size: usize,
-                                     _align: usize)
-                                     -> usize {
-        old_size
-    }
-
-    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
-        libc::free(ptr as *mut libc::c_void)
-    }
-
-    pub fn usable_size(size: usize, _align: usize) -> usize {
-        size
-    }
 }
 
-#[cfg(windows)]
+#[cfg(all(windows, not(stage0)))]
 #[allow(bad_style)]
-mod imp {
-    use core::cmp::min;
-    use core::ptr::copy_nonoverlapping;
+mod platform {
+    use core::cmp;
+    use core::ptr;
+
     use MIN_ALIGN;
+    use new::System;
+    use new::alloc::heap::{Alloc, AllocErr, Layout, CannotReallocInPlace};
 
     type LPVOID = *mut u8;
     type HANDLE = LPVOID;
     type SIZE_T = usize;
     type DWORD = u32;
     type BOOL = i32;
+    type LPDWORD = *mut DWORD;
+    type LPOVERLAPPED = *mut u8;
+
+    const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD;
 
     extern "system" {
         fn GetProcessHeap() -> HANDLE;
@@ -187,12 +298,18 @@ mod imp {
         fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
         fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
         fn GetLastError() -> DWORD;
+        fn WriteFile(hFile: HANDLE,
+                     lpBuffer: LPVOID,
+                     nNumberOfBytesToWrite: DWORD,
+                     lpNumberOfBytesWritten: LPDWORD,
+                     lpOverlapped: LPOVERLAPPED)
+                     -> BOOL;
+        fn GetStdHandle(which: DWORD) -> HANDLE;
     }
 
     #[repr(C)]
     struct Header(*mut u8);
 
-
     const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
     const HEAP_REALLOC_IN_PLACE_ONLY: DWORD = 0x00000010;
 
@@ -207,71 +324,149 @@ unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
     }
 
     #[inline]
-    unsafe fn allocate_with_flags(size: usize, align: usize, flags: DWORD) -> *mut u8 {
-        if align <= MIN_ALIGN {
-            HeapAlloc(GetProcessHeap(), flags, size as SIZE_T) as *mut u8
+    unsafe fn allocate_with_flags(layout: Layout, flags: DWORD)
+        -> Result<*mut u8, AllocErr>
+    {
+        let ptr = if layout.align() <= MIN_ALIGN {
+            HeapAlloc(GetProcessHeap(), flags, layout.size())
         } else {
-            let ptr = HeapAlloc(GetProcessHeap(), flags, (size + align) as SIZE_T) as *mut u8;
+            let size = layout.size() + layout.align();
+            let ptr = HeapAlloc(GetProcessHeap(), flags, size);
             if ptr.is_null() {
-                return ptr;
+                ptr
+            } else {
+                align_ptr(ptr, layout.align())
             }
-            align_ptr(ptr, align)
+        };
+        if ptr.is_null() {
+            Err(AllocErr::Exhausted { request: layout })
+        } else {
+            Ok(ptr as *mut u8)
         }
     }
 
-    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
-        allocate_with_flags(size, align, 0)
-    }
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    unsafe impl<'a> Alloc for &'a System {
+        #[inline]
+        unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+            allocate_with_flags(layout, 0)
+        }
 
-    pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
-        allocate_with_flags(size, align, HEAP_ZERO_MEMORY)
-    }
+        #[inline]
+        unsafe fn alloc_zeroed(&mut self, layout: Layout)
+            -> Result<*mut u8, AllocErr>
+        {
+            allocate_with_flags(layout, HEAP_ZERO_MEMORY)
+        }
 
-    pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
-        if align <= MIN_ALIGN {
-            HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
-        } else {
-            let new = allocate(size, align);
-            if !new.is_null() {
-                copy_nonoverlapping(ptr, new, min(size, old_size));
-                deallocate(ptr, old_size, align);
+        #[inline]
+        unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
+            if layout.align() <= MIN_ALIGN {
+                let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
+                debug_assert!(err != 0, "Failed to free heap memory: {}",
+                              GetLastError());
+            } else {
+                let header = get_header(ptr);
+                let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
+                debug_assert!(err != 0, "Failed to free heap memory: {}",
+                              GetLastError());
             }
-            new
         }
-    }
 
-    pub unsafe fn reallocate_inplace(ptr: *mut u8,
-                                     old_size: usize,
-                                     size: usize,
-                                     align: usize)
-                                     -> usize {
-        let new = if align <= MIN_ALIGN {
-            HeapReAlloc(GetProcessHeap(),
-                        HEAP_REALLOC_IN_PLACE_ONLY,
-                        ptr as LPVOID,
-                        size as SIZE_T) as *mut u8
-        } else {
-            let header = get_header(ptr);
-            HeapReAlloc(GetProcessHeap(),
-                        HEAP_REALLOC_IN_PLACE_ONLY,
-                        header.0 as LPVOID,
-                        size + align as SIZE_T) as *mut u8
-        };
-        if new.is_null() { old_size } else { size }
-    }
+        #[inline]
+        unsafe fn realloc(&mut self,
+                          ptr: *mut u8,
+                          old_layout: Layout,
+                          new_layout: Layout) -> Result<*mut u8, AllocErr> {
+            if old_layout.align() != new_layout.align() {
+                return Err(AllocErr::Unsupported {
+                    details: "cannot change alignment on `realloc`",
+                })
+            }
 
-    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
-        if align <= MIN_ALIGN {
-            let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
-            debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
-        } else {
-            let header = get_header(ptr);
-            let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
-            debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
+            if new_layout.align() <= MIN_ALIGN {
+                let ptr = HeapReAlloc(GetProcessHeap(),
+                                      0,
+                                      ptr as LPVOID,
+                                      new_layout.size());
+                if !ptr.is_null() {
+                    Ok(ptr as *mut u8)
+                } else {
+                    Err(AllocErr::Exhausted { request: new_layout })
+                }
+            } else {
+                let res = self.alloc(new_layout.clone());
+                if let Ok(new_ptr) = res {
+                    let size = cmp::min(old_layout.size(), new_layout.size());
+                    ptr::copy_nonoverlapping(ptr, new_ptr, size);
+                    self.dealloc(ptr, old_layout);
+                }
+                res
+            }
         }
-    }
 
-    pub fn usable_size(size: usize, _align: usize) -> usize {
-        size
+        #[inline]
+        unsafe fn grow_in_place(&mut self,
+                                ptr: *mut u8,
+                                layout: Layout,
+                                new_layout: Layout) -> Result<(), CannotReallocInPlace> {
+            self.shrink_in_place(ptr, layout, new_layout)
+        }
+
+        #[inline]
+        unsafe fn shrink_in_place(&mut self,
+                                  ptr: *mut u8,
+                                  old_layout: Layout,
+                                  new_layout: Layout) -> Result<(), CannotReallocInPlace> {
+            if old_layout.align() != new_layout.align() {
+                return Err(CannotReallocInPlace)
+            }
+
+            let new = if new_layout.align() <= MIN_ALIGN {
+                HeapReAlloc(GetProcessHeap(),
+                            HEAP_REALLOC_IN_PLACE_ONLY,
+                            ptr as LPVOID,
+                            new_layout.size())
+            } else {
+                let header = get_header(ptr);
+                HeapReAlloc(GetProcessHeap(),
+                            HEAP_REALLOC_IN_PLACE_ONLY,
+                            header.0 as LPVOID,
+                            new_layout.size() + new_layout.align())
+            };
+            if new.is_null() {
+                Err(CannotReallocInPlace)
+            } else {
+                Ok(())
+            }
+        }
+
+        fn oom(&mut self, err: AllocErr) -> ! {
+            use core::fmt::{self, Write};
+
+            // Same as with unix we ignore all errors here
+            drop(writeln!(Stderr, "fatal runtime error: {}", err));
+            unsafe {
+                ::core::intrinsics::abort();
+            }
+
+            struct Stderr;
+
+            impl Write for Stderr {
+                fn write_str(&mut self, s: &str) -> fmt::Result {
+                    unsafe {
+                        // WriteFile silently fails if it is passed an invalid
+                        // handle, so there is no need to check the result of
+                        // GetStdHandle.
+                        WriteFile(GetStdHandle(STD_ERROR_HANDLE),
+                                  s.as_ptr() as LPVOID,
+                                  s.len() as DWORD,
+                                  ptr::null_mut(),
+                                  ptr::null_mut());
+                    }
+                    Ok(())
+                }
+            }
+        }
     }
 }
diff --git a/src/liballoc_system/old.rs b/src/liballoc_system/old.rs
new file mode 100644 (file)
index 0000000..80aa460
--- /dev/null
@@ -0,0 +1,268 @@
+// Copyright 2017 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.
+
+#[no_mangle]
+pub unsafe extern fn __rust_alloc(size: usize,
+                                  align: usize,
+                                  err: *mut u8) -> *mut u8 {
+    let p = imp::allocate(size, align);
+    if p.is_null() {
+        __rust_oom(err);
+    }
+    p
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_oom(_err: *const u8) -> ! {
+    ::core::intrinsics::abort()
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_dealloc(ptr: *mut u8,
+                                    size: usize,
+                                    align: usize) {
+    imp::deallocate(ptr, size, align)
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_usable_size(size: usize,
+                                        _align: usize,
+                                        min: *mut usize,
+                                        max: *mut usize) {
+    *min = size;
+    *max = size;
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_realloc(ptr: *mut u8,
+                                    old_size: usize,
+                                    old_align: usize,
+                                    new_size: usize,
+                                    new_align: usize,
+                                    err: *mut u8) -> *mut u8 {
+    if new_align != old_align {
+        __rust_oom(err);
+    }
+    let p = imp::reallocate(ptr, old_size, new_size, new_align);
+    if p.is_null() {
+        __rust_oom(err);
+    }
+    p
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_alloc_zeroed(size: usize,
+                                         align: usize,
+                                         err: *mut u8) -> *mut u8 {
+    let p = imp::allocate_zeroed(size, align);
+    if p.is_null() {
+        __rust_oom(err);
+    }
+    p
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_alloc_excess(_size: usize,
+                                         _align: usize,
+                                         _excess: *mut usize,
+                                         err: *mut u8) -> *mut u8 {
+    __rust_oom(err);
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_realloc_excess(_ptr: *mut u8,
+                                           _old_size: usize,
+                                           _old_align: usize,
+                                           _new_size: usize,
+                                           _new_align: usize,
+                                           _excess: *mut usize,
+                                           err: *mut u8) -> *mut u8 {
+    __rust_oom(err);
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_grow_in_place(_ptr: *mut u8,
+                                          _old_size: usize,
+                                          _old_align: usize,
+                                          _new_size: usize,
+                                          _new_align: usize) -> u8 {
+    0
+}
+
+#[no_mangle]
+pub unsafe extern fn __rust_shrink_in_place(_ptr: *mut u8,
+                                            _old_size: usize,
+                                            _old_align: usize,
+                                            _new_size: usize,
+                                            _new_align: usize) -> u8 {
+    0
+}
+
+#[cfg(any(unix, target_os = "redox"))]
+mod imp {
+    extern crate libc;
+
+    use core::cmp;
+    use core::ptr;
+    use MIN_ALIGN;
+
+    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
+        if align <= MIN_ALIGN {
+            libc::malloc(size as libc::size_t) as *mut u8
+        } else {
+            aligned_malloc(size, align)
+        }
+    }
+
+    #[cfg(any(target_os = "android", target_os = "redox"))]
+    unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
+        // On android we currently target API level 9 which unfortunately
+        // doesn't have the `posix_memalign` API used below. Instead we use
+        // `memalign`, but this unfortunately has the property on some systems
+        // where the memory returned cannot be deallocated by `free`!
+        //
+        // Upon closer inspection, however, this appears to work just fine with
+        // Android, so for this platform we should be fine to call `memalign`
+        // (which is present in API level 9). Some helpful references could
+        // possibly be chromium using memalign [1], attempts at documenting that
+        // memalign + free is ok [2] [3], or the current source of chromium
+        // which still uses memalign on android [4].
+        //
+        // [1]: https://codereview.chromium.org/10796020/
+        // [2]: https://code.google.com/p/android/issues/detail?id=35391
+        // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
+        // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
+        //                                       /memory/aligned_memory.cc
+        libc::memalign(align as libc::size_t, size as libc::size_t) as *mut u8
+    }
+
+    #[cfg(not(any(target_os = "android", target_os = "redox")))]
+    unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
+        let mut out = ptr::null_mut();
+        let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
+        if ret != 0 {
+            ptr::null_mut()
+        } else {
+            out as *mut u8
+        }
+    }
+
+    pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
+        if align <= MIN_ALIGN {
+            libc::calloc(size as libc::size_t, 1) as *mut u8
+        } else {
+            let ptr = aligned_malloc(size, align);
+            if !ptr.is_null() {
+                ptr::write_bytes(ptr, 0, size);
+            }
+            ptr
+        }
+    }
+
+    pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
+        if align <= MIN_ALIGN {
+            libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
+        } else {
+            let new_ptr = allocate(size, align);
+            if !new_ptr.is_null() {
+                ptr::copy(ptr, new_ptr, cmp::min(size, old_size));
+                deallocate(ptr, old_size, align);
+            }
+            new_ptr
+        }
+    }
+
+    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
+        libc::free(ptr as *mut libc::c_void)
+    }
+}
+
+#[cfg(windows)]
+#[allow(bad_style)]
+mod imp {
+    use core::cmp::min;
+    use core::ptr::copy_nonoverlapping;
+    use MIN_ALIGN;
+
+    type LPVOID = *mut u8;
+    type HANDLE = LPVOID;
+    type SIZE_T = usize;
+    type DWORD = u32;
+    type BOOL = i32;
+
+    extern "system" {
+        fn GetProcessHeap() -> HANDLE;
+        fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
+        fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
+        fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
+        fn GetLastError() -> DWORD;
+    }
+
+    #[repr(C)]
+    struct Header(*mut u8);
+
+
+    const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
+
+    unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
+        &mut *(ptr as *mut Header).offset(-1)
+    }
+
+    unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
+        let aligned = ptr.offset((align - (ptr as usize & (align - 1))) as isize);
+        *get_header(aligned) = Header(ptr);
+        aligned
+    }
+
+    #[inline]
+    unsafe fn allocate_with_flags(size: usize, align: usize, flags: DWORD) -> *mut u8 {
+        if align <= MIN_ALIGN {
+            HeapAlloc(GetProcessHeap(), flags, size as SIZE_T) as *mut u8
+        } else {
+            let ptr = HeapAlloc(GetProcessHeap(), flags, (size + align) as SIZE_T) as *mut u8;
+            if ptr.is_null() {
+                return ptr;
+            }
+            align_ptr(ptr, align)
+        }
+    }
+
+    pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
+        allocate_with_flags(size, align, 0)
+    }
+
+    pub unsafe fn allocate_zeroed(size: usize, align: usize) -> *mut u8 {
+        allocate_with_flags(size, align, HEAP_ZERO_MEMORY)
+    }
+
+    pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
+        if align <= MIN_ALIGN {
+            HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
+        } else {
+            let new = allocate(size, align);
+            if !new.is_null() {
+                copy_nonoverlapping(ptr, new, min(size, old_size));
+                deallocate(ptr, old_size, align);
+            }
+            new
+        }
+    }
+
+    pub unsafe fn deallocate(ptr: *mut u8, _old_size: usize, align: usize) {
+        if align <= MIN_ALIGN {
+            let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID);
+            debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
+        } else {
+            let header = get_header(ptr);
+            let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
+            debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError());
+        }
+    }
+}
index de5d6df328cbd4fd7ca975e115c925b21c8b7fbe..38143593eb12bd3d3147e23b23abfa3420de3475 100644 (file)
        issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
        test(no_crate_inject, attr(allow(unused_variables), deny(warnings))))]
 #![no_std]
-#![needs_allocator]
 #![deny(warnings)]
 
 #![feature(alloc)]
 #![feature(collections_range)]
 #![feature(macro_reexport)]
-#![feature(needs_allocator)]
 #![feature(staged_api)]
 
 //! Collection types
index e4cf893375c757e68d4695da606c7ca498c56314..efa6a6cccc2b6850583560a5ea2113f27a315b07 100644 (file)
@@ -84,6 +84,7 @@
 pub mod lint;
 
 pub mod middle {
+    pub mod allocator;
     pub mod expr_use_visitor;
     pub mod const_val;
     pub mod cstore;
diff --git a/src/librustc/middle/allocator.rs b/src/librustc/middle/allocator.rs
new file mode 100644 (file)
index 0000000..79a9ef0
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2017 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.
+
+#[derive(Clone, Copy)]
+pub enum AllocatorKind {
+    Global,
+    DefaultLib,
+    DefaultExe,
+}
+
+impl AllocatorKind {
+    pub fn fn_name(&self, base: &str) -> String {
+        match *self {
+            AllocatorKind::Global => format!("__rg_{}", base),
+            AllocatorKind::DefaultLib => format!("__rdl_{}", base),
+            AllocatorKind::DefaultExe => format!("__rde_{}", base),
+        }
+    }
+}
index 6077b7863e2c3d034a59f8548df12fb21e9d8208..77b4c977d289ecd2b62758e4ecccbcc3556735ee 100644 (file)
@@ -287,6 +287,11 @@ fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool {
         return true;
     }
 
+    // Don't lint about global allocators
+    if attr::contains_name(attrs, "global_allocator") {
+        return true;
+    }
+
     let dead_code = lint::builtin::DEAD_CODE.name_lower();
     for attr in lint::gather_attrs(attrs) {
         match attr {
index 4e1f06cca06cc087b4b869db74ab7645c4d02c29..9af93d0d494244591cac86d942c6e59327e35537 100644 (file)
@@ -214,10 +214,9 @@ fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     //
     // Things like allocators and panic runtimes may not have been activated
     // quite yet, so do so here.
-    activate_injected_dep(sess.injected_allocator.get(), &mut ret,
-                          &|cnum| tcx.is_allocator(cnum.as_def_id()));
     activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret,
                           &|cnum| tcx.is_panic_runtime(cnum.as_def_id()));
+    activate_injected_allocator(sess, &mut ret);
 
     // When dylib B links to dylib A, then when using B we must also link to A.
     // It could be the case, however, that the rlib for A is present (hence we
@@ -295,10 +294,9 @@ fn attempt_static<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<DependencyLis
     // Our allocator/panic runtime may not have been linked above if it wasn't
     // explicitly linked, which is the case for any injected dependency. Handle
     // that here and activate them.
-    activate_injected_dep(sess.injected_allocator.get(), &mut ret,
-                          &|cnum| tcx.is_allocator(cnum.as_def_id()));
     activate_injected_dep(sess.injected_panic_runtime.get(), &mut ret,
                           &|cnum| tcx.is_panic_runtime(cnum.as_def_id()));
+    activate_injected_allocator(sess, &mut ret);
 
     Some(ret)
 }
@@ -331,6 +329,18 @@ fn activate_injected_dep(injected: Option<CrateNum>,
     }
 }
 
+fn activate_injected_allocator(sess: &session::Session,
+                               list: &mut DependencyList) {
+    let cnum = match sess.injected_allocator.get() {
+        Some(cnum) => cnum,
+        None => return,
+    };
+    let idx = cnum.as_usize() - 1;
+    if list[idx] == Linkage::NotLinked {
+        list[idx] = Linkage::Static;
+    }
+}
+
 // After the linkage for a crate has been determined we need to verify that
 // there's only going to be one allocator in the output.
 fn verify_ok<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, list: &[Linkage]) {
@@ -338,23 +348,12 @@ fn verify_ok<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, list: &[Linkage]) {
     if list.len() == 0 {
         return
     }
-    let mut allocator = None;
     let mut panic_runtime = None;
     for (i, linkage) in list.iter().enumerate() {
         if let Linkage::NotLinked = *linkage {
             continue
         }
         let cnum = CrateNum::new(i + 1);
-        if tcx.is_allocator(cnum.as_def_id()) {
-            if let Some(prev) = allocator {
-                let prev_name = sess.cstore.crate_name(prev);
-                let cur_name = sess.cstore.crate_name(cnum);
-                sess.err(&format!("cannot link together two \
-                                   allocators: {} and {}",
-                                  prev_name, cur_name));
-            }
-            allocator = Some(cnum);
-        }
 
         if tcx.is_panic_runtime(cnum.as_def_id()) {
             if let Some((prev, _)) = panic_runtime {
index 8bafdda234a09b1589a30b7314f8d156a9e8b961..39a719faa123ecd46af046f7b7a13484c9b521e4 100644 (file)
@@ -16,6 +16,7 @@
 
 use lint;
 use middle::cstore::CrateStore;
+use middle::allocator::AllocatorKind;
 use middle::dependency_format;
 use session::search_paths::PathKind;
 use session::config::DebugInfoLevel;
@@ -106,6 +107,7 @@ pub struct Session {
     /// dependency if it didn't already find one, and this tracks what was
     /// injected.
     pub injected_allocator: Cell<Option<CrateNum>>,
+    pub allocator_kind: Cell<Option<AllocatorKind>>,
     pub injected_panic_runtime: Cell<Option<CrateNum>>,
 
     /// Map from imported macro spans (which consist of
@@ -140,6 +142,9 @@ pub struct Session {
     /// Loaded up early on in the initialization of this `Session` to avoid
     /// false positives about a job server in our environment.
     pub jobserver_from_env: Option<Client>,
+
+    /// Metadata about the allocators for the current crate being compiled
+    pub has_global_allocator: Cell<bool>,
 }
 
 pub struct PerfStats {
@@ -715,6 +720,7 @@ pub fn build_session_(sopts: config::Options,
         type_length_limit: Cell::new(1048576),
         next_node_id: Cell::new(NodeId::new(1)),
         injected_allocator: Cell::new(None),
+        allocator_kind: Cell::new(None),
         injected_panic_runtime: Cell::new(None),
         imported_macro_spans: RefCell::new(HashMap::new()),
         incr_comp_session: RefCell::new(IncrCompSession::NotInitialized),
@@ -732,7 +738,6 @@ pub fn build_session_(sopts: config::Options,
         print_fuel_crate: print_fuel_crate,
         print_fuel: print_fuel,
         out_of_fuel: Cell::new(false),
-
         // Note that this is unsafe because it may misinterpret file descriptors
         // on Unix as jobserver file descriptors. We hopefully execute this near
         // the beginning of the process though to ensure we don't get false
@@ -750,6 +755,7 @@ pub fn build_session_(sopts: config::Options,
             });
             (*GLOBAL_JOBSERVER).clone()
         },
+        has_global_allocator: Cell::new(false),
     };
 
     sess
diff --git a/src/librustc_allocator/Cargo.toml b/src/librustc_allocator/Cargo.toml
new file mode 100644 (file)
index 0000000..e3d1d8e
--- /dev/null
@@ -0,0 +1,15 @@
+[package]
+authors = ["The Rust Project Developers"]
+name = "rustc_allocator"
+version = "0.0.0"
+
+[lib]
+path = "lib.rs"
+crate-type = ["dylib"]
+test = false
+
+[dependencies]
+rustc = { path = "../librustc" }
+rustc_errors = { path = "../librustc_errors" }
+syntax = { path = "../libsyntax" }
+syntax_pos = { path = "../libsyntax_pos" }
diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs
new file mode 100644 (file)
index 0000000..e942b72
--- /dev/null
@@ -0,0 +1,498 @@
+// Copyright 2016 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.
+
+use rustc::middle::allocator::AllocatorKind;
+use rustc_errors;
+use syntax::abi::Abi;
+use syntax::ast::{Crate, Attribute, LitKind, StrStyle, ExprKind};
+use syntax::ast::{Unsafety, Constness, Generics, Mutability, Ty, Mac, Arg};
+use syntax::ast::{self, Ident, Item, ItemKind, TyKind, Visibility, Expr};
+use syntax::attr;
+use syntax::codemap::dummy_spanned;
+use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute};
+use syntax::ext::base::ExtCtxt;
+use syntax::ext::base::Resolver;
+use syntax::ext::build::AstBuilder;
+use syntax::ext::expand::ExpansionConfig;
+use syntax::ext::hygiene::{Mark, SyntaxContext};
+use syntax::fold::{self, Folder};
+use syntax::parse::ParseSess;
+use syntax::ptr::P;
+use syntax::symbol::Symbol;
+use syntax::util::small_vector::SmallVector;
+use syntax_pos::{Span, DUMMY_SP};
+
+use {AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS};
+
+pub fn modify(sess: &ParseSess,
+              resolver: &mut Resolver,
+              krate: Crate,
+              handler: &rustc_errors::Handler) -> ast::Crate {
+    ExpandAllocatorDirectives {
+        handler: handler,
+        sess: sess,
+        resolver: resolver,
+        found: false,
+    }.fold_crate(krate)
+}
+
+struct ExpandAllocatorDirectives<'a> {
+    found: bool,
+    handler: &'a rustc_errors::Handler,
+    sess: &'a ParseSess,
+    resolver: &'a mut Resolver,
+}
+
+impl<'a> Folder for ExpandAllocatorDirectives<'a> {
+    fn fold_item(&mut self, item: P<Item>) -> SmallVector<P<Item>> {
+        let name = if attr::contains_name(&item.attrs, "global_allocator") {
+            "global_allocator"
+        } else {
+            return fold::noop_fold_item(item, self)
+        };
+        match item.node {
+            ItemKind::Static(..) => {}
+            _ => {
+                self.handler.span_err(item.span, "allocators must be statics");
+                return SmallVector::one(item)
+            }
+        }
+
+        if self.found {
+            self.handler.span_err(item.span, "cannot define more than one \
+                                              #[global_allocator]");
+            return SmallVector::one(item)
+        }
+        self.found = true;
+
+        let mark = Mark::fresh(Mark::root());
+        mark.set_expn_info(ExpnInfo {
+            call_site: DUMMY_SP,
+            callee: NameAndSpan {
+                format: MacroAttribute(Symbol::intern(name)),
+                span: None,
+                allow_internal_unstable: true,
+            }
+        });
+        let span = Span {
+            ctxt: SyntaxContext::empty().apply_mark(mark),
+            ..item.span
+        };
+        let ecfg = ExpansionConfig::default(name.to_string());
+        let mut f = AllocFnFactory {
+            span: span,
+            kind: AllocatorKind::Global,
+            global: item.ident,
+            alloc: Ident::from_str("alloc"),
+            cx: ExtCtxt::new(self.sess, ecfg, self.resolver),
+        };
+        let super_path = f.cx.path(f.span, vec![
+            Ident::from_str("super"),
+            f.global,
+        ]);
+        let mut items = vec![
+            f.cx.item_extern_crate(f.span, f.alloc),
+            f.cx.item_use_simple(f.span, Visibility::Inherited, super_path),
+        ];
+        for method in ALLOCATOR_METHODS {
+            items.push(f.allocator_fn(method));
+        }
+        let name = f.kind.fn_name("allocator_abi");
+        let allocator_abi = Ident::with_empty_ctxt(Symbol::gensym(&name));
+        let module = f.cx.item_mod(span, span, allocator_abi, Vec::new(), items);
+        let module = f.cx.monotonic_expander().fold_item(module).pop().unwrap();
+
+        let mut ret = SmallVector::new();
+        ret.push(item);
+        ret.push(module);
+        return ret
+    }
+
+    fn fold_mac(&mut self, mac: Mac) -> Mac {
+        fold::noop_fold_mac(mac, self)
+    }
+}
+
+struct AllocFnFactory<'a> {
+    span: Span,
+    kind: AllocatorKind,
+    global: Ident,
+    alloc: Ident,
+    cx: ExtCtxt<'a>,
+}
+
+impl<'a> AllocFnFactory<'a> {
+    fn allocator_fn(&self, method: &AllocatorMethod) -> P<Item> {
+        let mut abi_args = Vec::new();
+        let mut i = 0;
+        let ref mut mk = || {
+            let name = Ident::from_str(&format!("arg{}", i));
+            i += 1;
+            name
+        };
+        let args = method.inputs.iter().map(|ty| {
+            self.arg_ty(ty, &mut abi_args, mk)
+        }).collect();
+        let result = self.call_allocator(method.name, args);
+        let (output_ty, output_expr) =
+            self.ret_ty(&method.output, &mut abi_args, mk, result);
+        let kind = ItemKind::Fn(self.cx.fn_decl(abi_args, output_ty),
+                                Unsafety::Unsafe,
+                                dummy_spanned(Constness::NotConst),
+                                Abi::Rust,
+                                Generics::default(),
+                                self.cx.block_expr(output_expr));
+        self.cx.item(self.span,
+                     Ident::from_str(&self.kind.fn_name(method.name)),
+                     self.attrs(),
+                     kind)
+    }
+
+    fn call_allocator(&self, method: &str, mut args: Vec<P<Expr>>) -> P<Expr> {
+        let method = self.cx.path(self.span, vec![
+            self.alloc,
+            Ident::from_str("heap"),
+            Ident::from_str("Alloc"),
+            Ident::from_str(method),
+        ]);
+        let method = self.cx.expr_path(method);
+        let allocator = self.cx.path_ident(self.span, self.global);
+        let allocator = self.cx.expr_path(allocator);
+        let allocator = self.cx.expr_addr_of(self.span, allocator);
+        let allocator = self.cx.expr_mut_addr_of(self.span, allocator);
+        args.insert(0, allocator);
+
+        self.cx.expr_call(self.span, method, args)
+    }
+
+    fn attrs(&self) -> Vec<Attribute> {
+        let key = Symbol::intern("linkage");
+        let value = LitKind::Str(Symbol::intern("external"), StrStyle::Cooked);
+        let linkage = self.cx.meta_name_value(self.span, key, value);
+
+        let no_mangle = Symbol::intern("no_mangle");
+        let no_mangle = self.cx.meta_word(self.span, no_mangle);
+        vec![
+            self.cx.attribute(self.span, linkage),
+            self.cx.attribute(self.span, no_mangle),
+        ]
+    }
+
+    fn arg_ty(&self,
+              ty: &AllocatorTy,
+              args: &mut Vec<Arg>,
+              mut ident: &mut FnMut() -> Ident) -> P<Expr> {
+        match *ty {
+            AllocatorTy::Layout => {
+                let usize = self.cx.path_ident(self.span, Ident::from_str("usize"));
+                let ty_usize = self.cx.ty_path(usize);
+                let size = ident();
+                let align = ident();
+                args.push(self.cx.arg(self.span, size, ty_usize.clone()));
+                args.push(self.cx.arg(self.span, align, ty_usize));
+
+                let layout_new = self.cx.path(self.span, vec![
+                    self.alloc,
+                    Ident::from_str("heap"),
+                    Ident::from_str("Layout"),
+                    Ident::from_str("from_size_align_unchecked"),
+                ]);
+                let layout_new = self.cx.expr_path(layout_new);
+                let size = self.cx.expr_ident(self.span, size);
+                let align = self.cx.expr_ident(self.span, align);
+                let layout = self.cx.expr_call(self.span,
+                                               layout_new,
+                                               vec![size, align]);
+                layout
+            }
+
+            AllocatorTy::LayoutRef => {
+                let ident = ident();
+                args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
+
+                // Convert our `arg: *const u8` via:
+                //
+                //      &*(arg as *const Layout)
+                let expr = self.cx.expr_ident(self.span, ident);
+                let expr = self.cx.expr_cast(self.span, expr, self.layout_ptr());
+                let expr = self.cx.expr_deref(self.span, expr);
+                self.cx.expr_addr_of(self.span, expr)
+            }
+
+            AllocatorTy::AllocErr => {
+                // We're creating:
+                //
+                //      (*(arg as *const AllocErr)).clone()
+                let ident = ident();
+                args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
+                let expr = self.cx.expr_ident(self.span, ident);
+                let expr = self.cx.expr_cast(self.span, expr, self.alloc_err_ptr());
+                let expr = self.cx.expr_deref(self.span, expr);
+                self.cx.expr_method_call(
+                    self.span,
+                    expr,
+                    Ident::from_str("clone"),
+                    Vec::new()
+                )
+            }
+
+            AllocatorTy::Ptr => {
+                let ident = ident();
+                args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
+                self.cx.expr_ident(self.span, ident)
+            }
+
+            AllocatorTy::ResultPtr |
+            AllocatorTy::ResultExcess |
+            AllocatorTy::ResultUnit |
+            AllocatorTy::Bang |
+            AllocatorTy::UsizePair |
+            AllocatorTy::Unit => {
+                panic!("can't convert AllocatorTy to an argument")
+            }
+        }
+    }
+
+    fn ret_ty(&self,
+              ty: &AllocatorTy,
+              args: &mut Vec<Arg>,
+              mut ident: &mut FnMut() -> Ident,
+              expr: P<Expr>) -> (P<Ty>, P<Expr>)
+    {
+        match *ty {
+            AllocatorTy::UsizePair => {
+                // We're creating:
+                //
+                //      let arg = #expr;
+                //      *min = arg.0;
+                //      *max = arg.1;
+
+                let min = ident();
+                let max = ident();
+
+                args.push(self.cx.arg(self.span, min, self.ptr_usize()));
+                args.push(self.cx.arg(self.span, max, self.ptr_usize()));
+
+                let ident = ident();
+                let stmt = self.cx.stmt_let(self.span, false, ident, expr);
+                let min = self.cx.expr_ident(self.span, min);
+                let max = self.cx.expr_ident(self.span, max);
+                let layout = self.cx.expr_ident(self.span, ident);
+                let assign_min = self.cx.expr(self.span, ExprKind::Assign(
+                    self.cx.expr_deref(self.span, min),
+                    self.cx.expr_tup_field_access(self.span, layout.clone(), 0),
+                ));
+                let assign_min = self.cx.stmt_semi(assign_min);
+                let assign_max = self.cx.expr(self.span, ExprKind::Assign(
+                    self.cx.expr_deref(self.span, max),
+                    self.cx.expr_tup_field_access(self.span, layout.clone(), 1),
+                ));
+                let assign_max = self.cx.stmt_semi(assign_max);
+
+                let stmts = vec![stmt, assign_min, assign_max];
+                let block = self.cx.block(self.span, stmts);
+                let ty_unit = self.cx.ty(self.span, TyKind::Tup(Vec::new()));
+                (ty_unit, self.cx.expr_block(block))
+            }
+
+            AllocatorTy::ResultExcess => {
+                // We're creating:
+                //
+                //      match #expr {
+                //          Ok(ptr) => {
+                //              *excess = ptr.1;
+                //              ptr.0
+                //          }
+                //          Err(e) => {
+                //              ptr::write(err_ptr, e);
+                //              0 as *mut u8
+                //          }
+                //      }
+
+                let excess_ptr = ident();
+                args.push(self.cx.arg(self.span, excess_ptr, self.ptr_usize()));
+                let excess_ptr = self.cx.expr_ident(self.span, excess_ptr);
+
+                let err_ptr = ident();
+                args.push(self.cx.arg(self.span, err_ptr, self.ptr_u8()));
+                let err_ptr = self.cx.expr_ident(self.span, err_ptr);
+                let err_ptr = self.cx.expr_cast(self.span,
+                                                err_ptr,
+                                                self.alloc_err_ptr());
+
+                let name = ident();
+                let ok_expr = {
+                    let ptr = self.cx.expr_ident(self.span, name);
+                    let write = self.cx.expr(self.span, ExprKind::Assign(
+                        self.cx.expr_deref(self.span, excess_ptr),
+                        self.cx.expr_tup_field_access(self.span, ptr.clone(), 1),
+                    ));
+                    let write = self.cx.stmt_semi(write);
+                    let ret = self.cx.expr_tup_field_access(self.span,
+                                                            ptr.clone(),
+                                                            0);
+                    let ret = self.cx.stmt_expr(ret);
+                    let block = self.cx.block(self.span, vec![write, ret]);
+                    self.cx.expr_block(block)
+                };
+                let pat = self.cx.pat_ident(self.span, name);
+                let ok = self.cx.path_ident(self.span, Ident::from_str("Ok"));
+                let ok = self.cx.pat_tuple_struct(self.span, ok, vec![pat]);
+                let ok = self.cx.arm(self.span, vec![ok], ok_expr);
+
+                let name = ident();
+                let err_expr = {
+                    let err = self.cx.expr_ident(self.span, name);
+                    let write = self.cx.path(self.span, vec![
+                        self.alloc,
+                        Ident::from_str("heap"),
+                        Ident::from_str("__core"),
+                        Ident::from_str("ptr"),
+                        Ident::from_str("write"),
+                    ]);
+                    let write = self.cx.expr_path(write);
+                    let write = self.cx.expr_call(self.span, write,
+                                                  vec![err_ptr, err]);
+                    let write = self.cx.stmt_semi(write);
+                    let null = self.cx.expr_usize(self.span, 0);
+                    let null = self.cx.expr_cast(self.span, null, self.ptr_u8());
+                    let null = self.cx.stmt_expr(null);
+                    let block = self.cx.block(self.span, vec![write, null]);
+                    self.cx.expr_block(block)
+                };
+                let pat = self.cx.pat_ident(self.span, name);
+                let err = self.cx.path_ident(self.span, Ident::from_str("Err"));
+                let err = self.cx.pat_tuple_struct(self.span, err, vec![pat]);
+                let err = self.cx.arm(self.span, vec![err], err_expr);
+
+                let expr = self.cx.expr_match(self.span, expr, vec![ok, err]);
+                (self.ptr_u8(), expr)
+            }
+
+            AllocatorTy::ResultPtr => {
+                // We're creating:
+                //
+                //      match #expr {
+                //          Ok(ptr) => ptr,
+                //          Err(e) => {
+                //              ptr::write(err_ptr, e);
+                //              0 as *mut u8
+                //          }
+                //      }
+
+                let err_ptr = ident();
+                args.push(self.cx.arg(self.span, err_ptr, self.ptr_u8()));
+                let err_ptr = self.cx.expr_ident(self.span, err_ptr);
+                let err_ptr = self.cx.expr_cast(self.span,
+                                                err_ptr,
+                                                self.alloc_err_ptr());
+
+                let name = ident();
+                let ok_expr = self.cx.expr_ident(self.span, name);
+                let pat = self.cx.pat_ident(self.span, name);
+                let ok = self.cx.path_ident(self.span, Ident::from_str("Ok"));
+                let ok = self.cx.pat_tuple_struct(self.span, ok, vec![pat]);
+                let ok = self.cx.arm(self.span, vec![ok], ok_expr);
+
+                let name = ident();
+                let err_expr = {
+                    let err = self.cx.expr_ident(self.span, name);
+                    let write = self.cx.path(self.span, vec![
+                        self.alloc,
+                        Ident::from_str("heap"),
+                        Ident::from_str("__core"),
+                        Ident::from_str("ptr"),
+                        Ident::from_str("write"),
+                    ]);
+                    let write = self.cx.expr_path(write);
+                    let write = self.cx.expr_call(self.span, write,
+                                                  vec![err_ptr, err]);
+                    let write = self.cx.stmt_semi(write);
+                    let null = self.cx.expr_usize(self.span, 0);
+                    let null = self.cx.expr_cast(self.span, null, self.ptr_u8());
+                    let null = self.cx.stmt_expr(null);
+                    let block = self.cx.block(self.span, vec![write, null]);
+                    self.cx.expr_block(block)
+                };
+                let pat = self.cx.pat_ident(self.span, name);
+                let err = self.cx.path_ident(self.span, Ident::from_str("Err"));
+                let err = self.cx.pat_tuple_struct(self.span, err, vec![pat]);
+                let err = self.cx.arm(self.span, vec![err], err_expr);
+
+                let expr = self.cx.expr_match(self.span, expr, vec![ok, err]);
+                (self.ptr_u8(), expr)
+            }
+
+            AllocatorTy::ResultUnit => {
+                // We're creating:
+                //
+                //      #expr.is_ok() as u8
+
+                let cast = self.cx.expr_method_call(
+                    self.span,
+                    expr,
+                    Ident::from_str("is_ok"),
+                    Vec::new()
+                );
+                let u8 = self.cx.path_ident(self.span, Ident::from_str("u8"));
+                let u8 = self.cx.ty_path(u8);
+                let cast = self.cx.expr_cast(self.span, cast, u8.clone());
+                (u8, cast)
+            }
+
+            AllocatorTy::Bang => {
+                (self.cx.ty(self.span, TyKind::Never), expr)
+            }
+
+            AllocatorTy::Unit => {
+                (self.cx.ty(self.span, TyKind::Tup(Vec::new())), expr)
+            }
+
+            AllocatorTy::AllocErr |
+            AllocatorTy::Layout |
+            AllocatorTy::LayoutRef |
+            AllocatorTy::Ptr => {
+                panic!("can't convert AllocatorTy to an output")
+            }
+        }
+    }
+
+    fn ptr_u8(&self) -> P<Ty> {
+        let u8 = self.cx.path_ident(self.span, Ident::from_str("u8"));
+        let ty_u8 = self.cx.ty_path(u8);
+        self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable)
+    }
+
+    fn ptr_usize(&self) -> P<Ty> {
+        let usize = self.cx.path_ident(self.span, Ident::from_str("usize"));
+        let ty_usize = self.cx.ty_path(usize);
+        self.cx.ty_ptr(self.span, ty_usize, Mutability::Mutable)
+    }
+
+    fn layout_ptr(&self) -> P<Ty> {
+        let layout = self.cx.path(self.span, vec![
+            self.alloc,
+            Ident::from_str("heap"),
+            Ident::from_str("Layout"),
+        ]);
+        let layout = self.cx.ty_path(layout);
+        self.cx.ty_ptr(self.span, layout, Mutability::Mutable)
+    }
+
+    fn alloc_err_ptr(&self) -> P<Ty> {
+        let err = self.cx.path(self.span, vec![
+            self.alloc,
+            Ident::from_str("heap"),
+            Ident::from_str("AllocErr"),
+        ]);
+        let err = self.cx.ty_path(err);
+        self.cx.ty_ptr(self.span, err, Mutability::Mutable)
+    }
+}
diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs
new file mode 100644 (file)
index 0000000..d0ea40d
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright 2016 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.
+
+#![feature(rustc_private)]
+
+extern crate rustc;
+extern crate rustc_errors;
+extern crate syntax;
+extern crate syntax_pos;
+
+pub mod expand;
+
+pub static ALLOCATOR_METHODS: &[AllocatorMethod] = &[
+    AllocatorMethod {
+        name: "alloc",
+        inputs: &[AllocatorTy::Layout],
+        output: AllocatorTy::ResultPtr,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "oom",
+        inputs: &[AllocatorTy::AllocErr],
+        output: AllocatorTy::Bang,
+        is_unsafe: false,
+    },
+    AllocatorMethod {
+        name: "dealloc",
+        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout],
+        output: AllocatorTy::Unit,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "usable_size",
+        inputs: &[AllocatorTy::LayoutRef],
+        output: AllocatorTy::UsizePair,
+        is_unsafe: false,
+    },
+    AllocatorMethod {
+        name: "realloc",
+        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout],
+        output: AllocatorTy::ResultPtr,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "alloc_zeroed",
+        inputs: &[AllocatorTy::Layout],
+        output: AllocatorTy::ResultPtr,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "alloc_excess",
+        inputs: &[AllocatorTy::Layout],
+        output: AllocatorTy::ResultExcess,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "realloc_excess",
+        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout],
+        output: AllocatorTy::ResultExcess,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "grow_in_place",
+        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout],
+        output: AllocatorTy::ResultUnit,
+        is_unsafe: true,
+    },
+    AllocatorMethod {
+        name: "shrink_in_place",
+        inputs: &[AllocatorTy::Ptr, AllocatorTy::Layout, AllocatorTy::Layout],
+        output: AllocatorTy::ResultUnit,
+        is_unsafe: true,
+    },
+];
+
+pub struct AllocatorMethod {
+    pub name: &'static str,
+    pub inputs: &'static [AllocatorTy],
+    pub output: AllocatorTy,
+    pub is_unsafe: bool,
+}
+
+pub enum AllocatorTy {
+    AllocErr,
+    Bang,
+    Layout,
+    LayoutRef,
+    Ptr,
+    ResultExcess,
+    ResultPtr,
+    ResultUnit,
+    Unit,
+    UsizePair,
+}
index 0fda2805feac89a6ce18ea6319903186db4ae927..8f8ef1cc4a0111165ced04bddc19f49a1078fe43 100644 (file)
@@ -14,5 +14,6 @@ build_helper = { path = "../build_helper" }
 cmake = "0.1.18"
 
 [dependencies]
+alloc = { path = "../liballoc" }
 alloc_system = { path = "../liballoc_system" }
 core = { path = "../libcore" }
index 54941362e845091861e06dba9cabea1e9310cdc2..e987b1f335e19c3b711a943e0f1f8e2205f8b9d6 100644 (file)
@@ -11,6 +11,8 @@
 #![sanitizer_runtime]
 #![feature(sanitizer_runtime)]
 #![feature(alloc_system)]
+#![cfg_attr(not(stage0), feature(allocator_api))]
+#![cfg_attr(not(stage0), feature(global_allocator))]
 #![feature(staged_api)]
 #![no_std]
 #![unstable(feature = "sanitizer_runtime_lib",
             issue = "0")]
 
 extern crate alloc_system;
+
+#[cfg(not(stage0))]
+use alloc_system::System;
+
+#[cfg(not(stage0))]
+#[global_allocator]
+static ALLOC: System = System;
index c5cfff0be03ad05851fb1461454492a264dc0b7b..c5427a13e4c7df44510a32ec669eb8d0d7945699 100644 (file)
@@ -16,7 +16,7 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(128);
 
     // see #36994
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "aarch64-unknown-freebsd".to_string(),
index 043bd881c7290c6062cde4331f495641e9b10b45..7c2c45a2843a7ccf8e9da14c8aef7a470ddaed12 100644 (file)
@@ -16,7 +16,7 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(128);
 
     // see #36994
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "aarch64-unknown-linux-gnu".to_string(),
index 62418e68d43415fe020671e30759bcf075d076ac..5c4e01886a434366f9de5eb085b584aa26f9aec3 100644 (file)
@@ -19,7 +19,6 @@ pub fn opts() -> TargetOptions {
         linker_is_gnu: true,
         has_rpath: true,
         position_independent_executables: true,
-        exe_allocation_crate: "alloc_system".to_string(),
 
         .. Default::default()
     }
index c6207cdc4d9c18efa6a76a1102af11b7bb897024..63ccd21c220f32aa290583a2f3f8dbde66bb75ce 100644 (file)
@@ -37,7 +37,6 @@ pub fn opts() -> TargetOptions {
         has_rpath: true,
         pre_link_args: args,
         position_independent_executables: true,
-        exe_allocation_crate: "alloc_system".to_string(),
         has_elf_tls: true,
         .. Default::default()
     }
index 038a70ed6b17ee3e700405f71d6a988e8f9b094a..2d77902046109223ed6db1c777c6581fa0e8a71c 100644 (file)
@@ -29,7 +29,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(64),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         },
index aed4c4fbb08deb90479fac1533c2d6e848b90847..c26780b9e65ce604e4df480a576980a4db114ce0 100644 (file)
@@ -29,7 +29,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(64),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         },
index 9ef61f9caddcdbaf6bd59001ca142f3e340f8d2b..24649851d76fd1b336fdd03ff37f27af224b9580 100644 (file)
@@ -28,7 +28,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         },
index f54790bab970b85b0c67d39b22386db08fca0e80..6303722945c9f3a4814157a903b4c74b507d45d7 100644 (file)
@@ -28,7 +28,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         }
index 59c07efe0fdc1818fe7125413d9dceecf0a89c3d..1a7a56a9779218c52823912fa0ac720db4f40b86 100644 (file)
@@ -28,7 +28,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         },
index ec19cc1a536ad7f45a5b9efffdd6a8ec8630c291..cbf8339993c86f503ca60d0b3cd3e8885fdb6999 100644 (file)
@@ -29,7 +29,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         },
index 00085d18e6d09eb7f8953993d866fc25e5b41a0d..b367bce75a1d944076f81d8716b7f47eaead6dbb 100644 (file)
@@ -28,7 +28,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         }
index b3ca2edec1eda57d60122665c2b3d6654d8e3fe7..686dfbe987d10e3d90f6f9fc4009a98aae2b33c0 100644 (file)
@@ -29,7 +29,7 @@ pub fn target() -> TargetResult {
             max_atomic_width: Some(32),
 
             // see #36994
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
 
             ..super::linux_base::opts()
         },
index 5df227e39acbdaf0c9eb70d9c2434994f64f311c..983a98e350c6aaedf3344ac83e2c11b7eecd7fd0 100644 (file)
@@ -378,9 +378,8 @@ pub struct TargetOptions {
     /// `eh_unwind_resume` lang item.
     pub custom_unwind_resume: bool,
 
-    /// Default crate for allocation symbols to link against
-    pub lib_allocation_crate: String,
-    pub exe_allocation_crate: String,
+    /// If necessary, a different crate to link exe allocators by default
+    pub exe_allocation_crate: Option<String>,
 
     /// Flag indicating whether ELF TLS (e.g. #[thread_local]) is available for
     /// this target.
@@ -457,8 +456,7 @@ fn default() -> TargetOptions {
             link_env: Vec::new(),
             archive_format: "gnu".to_string(),
             custom_unwind_resume: false,
-            lib_allocation_crate: "alloc_system".to_string(),
-            exe_allocation_crate: "alloc_system".to_string(),
+            exe_allocation_crate: None,
             allow_asm: true,
             has_elf_tls: false,
             obj_is_bitcode: false,
@@ -682,8 +680,7 @@ macro_rules! key {
         key!(archive_format);
         key!(allow_asm, bool);
         key!(custom_unwind_resume, bool);
-        key!(lib_allocation_crate);
-        key!(exe_allocation_crate);
+        key!(exe_allocation_crate, optional);
         key!(has_elf_tls, bool);
         key!(obj_is_bitcode, bool);
         key!(no_integrated_as, bool);
@@ -869,7 +866,6 @@ macro_rules! target_option_val {
         target_option_val!(archive_format);
         target_option_val!(allow_asm);
         target_option_val!(custom_unwind_resume);
-        target_option_val!(lib_allocation_crate);
         target_option_val!(exe_allocation_crate);
         target_option_val!(has_elf_tls);
         target_option_val!(obj_is_bitcode);
@@ -889,10 +885,10 @@ macro_rules! target_option_val {
     }
 }
 
-fn maybe_jemalloc() -> String {
+fn maybe_jemalloc() -> Option<String> {
     if cfg!(feature = "jemalloc") {
-        "alloc_jemalloc".to_string()
+        Some("alloc_jemalloc".to_string())
     } else {
-        "alloc_system".to_string()
+        None
     }
 }
index 2df9b8e03ff535866f8428d5ac9aa88f23693ba4..051028d5c4a7752840887313af6e8fc6762c300e 100644 (file)
@@ -34,7 +34,6 @@ pub fn opts() -> TargetOptions {
         is_like_openbsd: true,
         pre_link_args: args,
         position_independent_executables: true,
-        exe_allocation_crate: "alloc_system".to_string(),
         .. Default::default()
     }
 }
index 55a5bfd1e674621bf02d294439bba4c10a1485a3..718a79a685e066b066b645b33464678c1f54e4e6 100644 (file)
@@ -18,7 +18,7 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(64);
 
     // see #36994
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "powerpc64-unknown-linux-gnu".to_string(),
index c22bc3b041a4ee2d41dd0903347015dbab12546b..5b50b96837fbe27a7ece78477d084a0005e2f098 100644 (file)
@@ -18,7 +18,7 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(64);
 
     // see #36994
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "powerpc64le-unknown-linux-gnu".to_string(),
index 677d198b1a379a315158c8d13428fe5401ca4665..8d4ad5f0b447f87d163eb1fdddaed1cbc1a7a101 100644 (file)
@@ -17,7 +17,7 @@ pub fn target() -> TargetResult {
     base.max_atomic_width = Some(32);
 
     // see #36994
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "powerpc-unknown-linux-gnu".to_string(),
index f26a86d4bdc0f13c4bc60de2626eaf442e3e882b..2eae0a1240823c0553cf64f4dd97a02f5dacda17 100644 (file)
@@ -36,8 +36,6 @@ pub fn opts() -> TargetOptions {
         eliminate_frame_pointer: false,
         target_family: None,
         linker_is_gnu: true,
-        lib_allocation_crate: "alloc_system".to_string(),
-        exe_allocation_crate: "alloc_system".to_string(),
         has_elf_tls: true,
         panic_strategy: PanicStrategy::Abort,
         .. Default::default()
index cc8eb7c4e84243e281e54086220474d7f22c0366..78a6bb7933d9539c6637b21a1fce2c8f828b2032 100644 (file)
@@ -21,7 +21,7 @@ pub fn target() -> TargetResult {
     base.features = "-vector".to_string();
     base.max_atomic_width = Some(64);
     // see #36994
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "s390x-unknown-linux-gnu".to_string(),
index 1bd51ac62581f06ee4e5104607376285694473e5..7f710ad402053cef9b9befe426461125a7819e93 100644 (file)
@@ -15,7 +15,7 @@ pub fn target() -> TargetResult {
     let mut base = super::linux_base::opts();
     base.cpu = "v9".to_string();
     base.max_atomic_width = Some(64);
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "sparc64-unknown-linux-gnu".to_string(),
index 421f59aea93bf4acba458dd5622be1641f832746..c07321e418e64eb5ebf3a4b07f556533591357f8 100644 (file)
@@ -63,7 +63,6 @@ pub fn opts() -> TargetOptions {
         is_like_windows: true,
         is_like_msvc: true,
         pre_link_args: args,
-        exe_allocation_crate: "alloc_system".to_string(),
 
         .. Default::default()
     }
index eea4389cfd64eaee7e5f8bfd79166ca552e470f6..ec5cc197dfc1a642582759e123d61d213180a573 100644 (file)
@@ -24,7 +24,7 @@ pub fn target() -> TargetResult {
     base.position_independent_executables = false;
     base.disable_redzone = true;
     base.no_default_libraries = false;
-    base.exe_allocation_crate = "alloc_system".to_string();
+    base.exe_allocation_crate = None;
 
     Ok(Target {
         llvm_target: "x86_64-rumprun-netbsd".to_string(),
index 2e949f48c175ee7e44c9126d771043367b352e30..def72752389e9cd7f1d1904b3be30745d606eaba 100644 (file)
@@ -15,6 +15,7 @@ log = { version = "0.3", features = ["release_max_level_info"] }
 env_logger = { version = "0.4", default-features = false }
 proc_macro_plugin = { path = "../libproc_macro_plugin" }
 rustc = { path = "../librustc" }
+rustc_allocator = { path = "../librustc_allocator" }
 rustc_back = { path = "../librustc_back" }
 rustc_borrowck = { path = "../librustc_borrowck" }
 rustc_const_eval = { path = "../librustc_const_eval" }
index a3e1cf7c1a8f81427179929d7bc6fb618d9008f0..daa5917cf324db580989f03881579d386a0e3899 100644 (file)
@@ -27,6 +27,7 @@
 use rustc::util::common::{ErrorReported, time};
 use rustc::util::nodemap::NodeSet;
 use rustc::util::fs::rename_or_copy_remove;
+use rustc_allocator as allocator;
 use rustc_borrowck as borrowck;
 use rustc_incremental::{self, IncrementalHashesMap};
 use rustc_resolve::{MakeGlobMap, Resolver};
@@ -750,6 +751,13 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
         });
     }
 
+    krate = time(time_passes, "creating allocators", || {
+        allocator::expand::modify(&sess.parse_sess,
+                                  &mut resolver,
+                                  krate,
+                                  sess.diagnostic())
+    });
+
     after_expand(&krate)?;
 
     if sess.opts.debugging_opts.input_stats {
index f2aacbc629fad9351705af9cffebadab1e9fe514..add827536c8771d06661e424aedbc6f03739b885 100644 (file)
@@ -34,6 +34,7 @@
 extern crate env_logger;
 extern crate libc;
 extern crate rustc;
+extern crate rustc_allocator;
 extern crate rustc_back;
 extern crate rustc_borrowck;
 extern crate rustc_const_eval;
index 2b33150902532536d219720d89c2034c2efd8e4e..02d68a41b4cc4dbfb3a524522905999a4c1e5ae3 100644 (file)
@@ -1071,7 +1071,8 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for InvalidNoMangleItems {
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         match it.node {
             hir::ItemFn(.., ref generics, _) => {
-                if attr::contains_name(&it.attrs, "no_mangle") {
+                if attr::contains_name(&it.attrs, "no_mangle") &&
+                   !attr::contains_name(&it.attrs, "linkage") {
                     if !cx.access_levels.is_reachable(it.id) {
                         let msg = format!("function {} is marked #[no_mangle], but not exported",
                                           it.name);
index 770d16e5c029a6e6c21f1b1919bfaee93e83877d..9f0ee95b5a60e93de74a22bfe9521e14e170b5f2 100644 (file)
@@ -698,6 +698,7 @@ pub fn LLVMConstInlineAsm(Ty: TypeRef,
     pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool;
     pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool);
     pub fn LLVMRustGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef;
+    pub fn LLVMSetTailCall(CallInst: ValueRef, IsTailCall: Bool);
 
     // Operations on functions
     pub fn LLVMAddFunction(M: ModuleRef, Name: *const c_char, FunctionTy: TypeRef) -> ValueRef;
index 786883d21350b4d152fabc13f9bb0096553b948a..087c3162119432a60af7000c58fd7c654dd11c09 100644 (file)
@@ -14,5 +14,6 @@ build_helper = { path = "../build_helper" }
 cmake = "0.1.18"
 
 [dependencies]
+alloc = { path = "../liballoc" }
 alloc_system = { path = "../liballoc_system" }
 core = { path = "../libcore" }
index 54941362e845091861e06dba9cabea1e9310cdc2..e987b1f335e19c3b711a943e0f1f8e2205f8b9d6 100644 (file)
@@ -11,6 +11,8 @@
 #![sanitizer_runtime]
 #![feature(sanitizer_runtime)]
 #![feature(alloc_system)]
+#![cfg_attr(not(stage0), feature(allocator_api))]
+#![cfg_attr(not(stage0), feature(global_allocator))]
 #![feature(staged_api)]
 #![no_std]
 #![unstable(feature = "sanitizer_runtime_lib",
             issue = "0")]
 
 extern crate alloc_system;
+
+#[cfg(not(stage0))]
+use alloc_system::System;
+
+#[cfg(not(stage0))]
+#[global_allocator]
+static ALLOC: System = System;
index 27c2d22168c8b84aa4f3c639302c4b18ac2579fc..ac39da48ac1fc3ce8798359eae3947b2933953cf 100644 (file)
@@ -16,6 +16,7 @@
 
 use rustc::hir::def_id::{CrateNum, DefIndex};
 use rustc::hir::svh::Svh;
+use rustc::middle::allocator::AllocatorKind;
 use rustc::middle::cstore::DepKind;
 use rustc::session::Session;
 use rustc::session::config::{Sanitizer, self};
@@ -40,6 +41,7 @@
 use syntax::ext::base::SyntaxExtension;
 use syntax::feature_gate::{self, GateIssue};
 use syntax::symbol::Symbol;
+use syntax::visit;
 use syntax_pos::{Span, DUMMY_SP};
 use log;
 
@@ -920,34 +922,28 @@ fn inject_profiler_runtime(&mut self) {
         }
     }
 
-    fn inject_allocator_crate(&mut self) {
-        // Make sure that we actually need an allocator, if none of our
-        // dependencies need one then we definitely don't!
-        //
-        // Also, if one of our dependencies has an explicit allocator, then we
-        // also bail out as we don't need to implicitly inject one.
-        let mut needs_allocator = false;
-        let mut found_required_allocator = false;
+    fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
+        let has_global_allocator = has_global_allocator(krate);
+        if has_global_allocator {
+            self.sess.has_global_allocator.set(true);
+        }
+
+        // Check to see if we actually need an allocator. This desire comes
+        // about through the `#![needs_allocator]` attribute and is typically
+        // written down in liballoc.
+        let mut needs_allocator = attr::contains_name(&krate.attrs,
+                                                      "needs_allocator");
         let dep_graph = &self.sess.dep_graph;
-        self.cstore.iter_crate_data(|cnum, data| {
+        self.cstore.iter_crate_data(|_, data| {
             needs_allocator = needs_allocator || data.needs_allocator(dep_graph);
-            if data.is_allocator(dep_graph) {
-                info!("{} required by rlib and is an allocator", data.name());
-                self.inject_dependency_if(cnum, "an allocator",
-                                          &|data| data.needs_allocator(dep_graph));
-                found_required_allocator = found_required_allocator ||
-                    data.dep_kind.get() == DepKind::Explicit;
-            }
         });
-        if !needs_allocator || found_required_allocator { return }
+        if !needs_allocator {
+            return
+        }
 
-        // At this point we've determined that we need an allocator and no
-        // previous allocator has been activated. We look through our outputs of
-        // crate types to see what kind of allocator types we may need.
-        //
-        // The main special output type here is that rlibs do **not** need an
-        // allocator linked in (they're just object files), only final products
-        // (exes, dylibs, staticlibs) need allocators.
+        // At this point we've determined that we need an allocator. Let's see
+        // if our compilation session actually needs an allocator based on what
+        // we're emitting.
         let mut need_lib_alloc = false;
         let mut need_exe_alloc = false;
         for ct in self.sess.crate_types.borrow().iter() {
@@ -960,44 +956,132 @@ fn inject_allocator_crate(&mut self) {
                 config::CrateTypeRlib => {}
             }
         }
-        if !need_lib_alloc && !need_exe_alloc { return }
+        if !need_lib_alloc && !need_exe_alloc {
+            return
+        }
 
-        // The default allocator crate comes from the custom target spec, and we
-        // choose between the standard library allocator or exe allocator. This
-        // distinction exists because the default allocator for binaries (where
-        // the world is Rust) is different than library (where the world is
-        // likely *not* Rust).
-        //
-        // If a library is being produced, but we're also flagged with `-C
-        // prefer-dynamic`, then we interpret this as a *Rust* dynamic library
-        // is being produced so we use the exe allocator instead.
+        // Ok, we need an allocator. Not only that but we're actually going to
+        // create an artifact that needs one linked in. Let's go find the one
+        // that we're going to link in.
         //
-        // What this boils down to is:
-        //
-        // * Binaries use jemalloc
-        // * Staticlibs and Rust dylibs use system malloc
-        // * Rust dylibs used as dependencies to rust use jemalloc
-        let name = if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic {
-            Symbol::intern(&self.sess.target.target.options.lib_allocation_crate)
+        // First up we check for global allocators. Look at the crate graph here
+        // and see what's a global allocator, including if we ourselves are a
+        // global allocator.
+        let dep_graph = &self.sess.dep_graph;
+        let mut global_allocator = if has_global_allocator {
+            Some(None)
         } else {
-            Symbol::intern(&self.sess.target.target.options.exe_allocation_crate)
+            None
         };
-        let dep_kind = DepKind::Implicit;
-        let (cnum, data) =
-            self.resolve_crate(&None, name, name, None, DUMMY_SP, PathKind::Crate, dep_kind);
+        self.cstore.iter_crate_data(|_, data| {
+            if !data.has_global_allocator(dep_graph) {
+                return
+            }
+            match global_allocator {
+                Some(Some(other_crate)) => {
+                    self.sess.err(&format!("the #[global_allocator] in {} \
+                                            conflicts with this global \
+                                            allocator in: {}",
+                                           other_crate,
+                                           data.name()));
+                }
+                Some(None) => {
+                    self.sess.err(&format!("the #[global_allocator] in this \
+                                            crate conflicts with global \
+                                            allocator in: {}", data.name()));
+                }
+                None => global_allocator = Some(Some(data.name())),
+            }
+        });
+        if global_allocator.is_some() {
+            self.sess.allocator_kind.set(Some(AllocatorKind::Global));
+            return
+        }
+
+        // Ok we haven't found a global allocator but we still need an
+        // allocator. At this point we'll either fall back to the "library
+        // allocator" or the "exe allocator" depending on a few variables. Let's
+        // figure out which one.
+        //
+        // Note that here we favor linking to the "library allocator" as much as
+        // possible. If we're not creating rustc's version of libstd
+        // (need_lib_alloc and prefer_dynamic) then we select `None`, and if the
+        // exe allocation crate doesn't exist for this target then we also
+        // select `None`.
+        let exe_allocation_crate =
+            if need_lib_alloc && !self.sess.opts.cg.prefer_dynamic {
+                None
+            } else {
+                self.sess.target.target.options.exe_allocation_crate.as_ref()
+            };
+
+        match exe_allocation_crate {
+            // We've determined that we're injecting an "exe allocator" which
+            // means that we're going to load up a whole new crate. An example
+            // of this is that we're producing a normal binary on Linux which
+            // means we need to load the `alloc_jemalloc` crate to link as an
+            // allocator.
+            Some(krate) => {
+                self.sess.allocator_kind.set(Some(AllocatorKind::DefaultExe));
+                let name = Symbol::intern(krate);
+                let dep_kind = DepKind::Implicit;
+                let (cnum, _data) =
+                    self.resolve_crate(&None,
+                                       name,
+                                       name,
+                                       None,
+                                       DUMMY_SP,
+                                       PathKind::Crate, dep_kind);
+                self.sess.injected_allocator.set(Some(cnum));
+            //     self.cstore.iter_crate_data(|_, data| {
+            //         if !data.needs_allocator(dep_graph) {
+            //             return
+            //         }
+            //         data.cnum_map.borrow_mut().push(cnum);
+            //     });
+            }
 
-        // Sanity check the crate we loaded to ensure that it is indeed an
-        // allocator.
-        if !data.is_allocator(dep_graph) {
-            self.sess.err(&format!("the allocator crate `{}` is not tagged \
-                                    with #![allocator]", data.name()));
+            // We're not actually going to inject an allocator, we're going to
+            // require that something in our crate graph is the default lib
+            // allocator. This is typically libstd, so this'll rarely be an
+            // error.
+            None => {
+                self.sess.allocator_kind.set(Some(AllocatorKind::DefaultLib));
+                let mut found_lib_allocator =
+                    attr::contains_name(&krate.attrs, "default_lib_allocator");
+                self.cstore.iter_crate_data(|_, data| {
+                    if !found_lib_allocator {
+                        if data.has_default_lib_allocator(dep_graph) {
+                            found_lib_allocator = true;
+                        }
+                    }
+                });
+                if found_lib_allocator {
+                    return
+                }
+                self.sess.err("no #[default_lib_allocator] found but one is \
+                               required; is libstd not linked?");
+            }
         }
 
-        self.sess.injected_allocator.set(Some(cnum));
-        self.inject_dependency_if(cnum, "an allocator",
-                                  &|data| data.needs_allocator(dep_graph));
+        fn has_global_allocator(krate: &ast::Crate) -> bool {
+            struct Finder(bool);
+            let mut f = Finder(false);
+            visit::walk_crate(&mut f, krate);
+            return f.0;
+
+            impl<'ast> visit::Visitor<'ast> for Finder {
+                fn visit_item(&mut self, i: &'ast ast::Item) {
+                    if attr::contains_name(&i.attrs, "global_allocator") {
+                        self.0 = true;
+                    }
+                    visit::walk_item(self, i)
+                }
+            }
+        }
     }
 
+
     fn inject_dependency_if(&self,
                             krate: CrateNum,
                             what: &str,
@@ -1123,7 +1207,7 @@ fn postprocess(&mut self, krate: &ast::Crate) {
         // sanitizers force the use of the `alloc_system` allocator
         self.inject_sanitizer_runtime();
         self.inject_profiler_runtime();
-        self.inject_allocator_crate();
+        self.inject_allocator_crate(krate);
         self.inject_panic_runtime(krate);
 
         if log_enabled!(log::LogLevel::Info) {
index 86146fe3947bcb06db134d6a5b747dd97012163a..fb43f91c46d7f02ff3f43af49bb1a00514aaad73 100644 (file)
@@ -275,16 +275,27 @@ pub fn disambiguator(&self) -> Symbol {
         self.root.disambiguator
     }
 
-    pub fn is_allocator(&self, dep_graph: &DepGraph) -> bool {
-        let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph);
-        attr::contains_name(&attrs, "allocator")
-    }
-
     pub fn needs_allocator(&self, dep_graph: &DepGraph) -> bool {
         let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph);
         attr::contains_name(&attrs, "needs_allocator")
     }
 
+    pub fn has_global_allocator(&self, dep_graph: &DepGraph) -> bool {
+        let dep_node = self.metadata_dep_node(GlobalMetaDataKind::Krate);
+        self.root
+            .has_global_allocator
+            .get(dep_graph, dep_node)
+            .clone()
+    }
+
+    pub fn has_default_lib_allocator(&self, dep_graph: &DepGraph) -> bool {
+        let dep_node = self.metadata_dep_node(GlobalMetaDataKind::Krate);
+        self.root
+            .has_default_lib_allocator
+            .get(dep_graph, dep_node)
+            .clone()
+    }
+
     pub fn is_panic_runtime(&self, dep_graph: &DepGraph) -> bool {
         let attrs = self.get_item_attrs(CRATE_DEF_INDEX, dep_graph);
         attr::contains_name(&attrs, "panic_runtime")
index 502eab44dac52d7c116aa6103b77fae04bc15079..35ce993d33557614cbf3682e39ea79b504234253 100644 (file)
@@ -134,7 +134,6 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) {
     is_mir_available => { cdata.is_item_mir_available(def_id.index) }
 
     dylib_dependency_formats => { Rc::new(cdata.get_dylib_dependency_formats(&tcx.dep_graph)) }
-    is_allocator => { cdata.is_allocator(&tcx.dep_graph) }
     is_panic_runtime => { cdata.is_panic_runtime(&tcx.dep_graph) }
     extern_crate => { Rc::new(cdata.extern_crate.get()) }
 }
index e9701b95002d4dc5d4706ffe6e1c94c29a7051cb..47f586ac895290126577448126a9871a407b4164 100644 (file)
@@ -400,12 +400,17 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot> {
         let tcx = self.tcx;
         let link_meta = self.link_meta;
         let is_proc_macro = tcx.sess.crate_types.borrow().contains(&CrateTypeProcMacro);
+        let has_default_lib_allocator =
+            attr::contains_name(tcx.hir.krate_attrs(), "default_lib_allocator");
+        let has_global_allocator = tcx.sess.has_global_allocator.get();
         let root = self.lazy(&CrateRoot {
             name: tcx.crate_name(LOCAL_CRATE),
             triple: tcx.sess.opts.target_triple.clone(),
             hash: link_meta.crate_hash,
             disambiguator: tcx.sess.local_crate_disambiguator(),
             panic_strategy: Tracked::new(tcx.sess.panic_strategy()),
+            has_global_allocator: Tracked::new(has_global_allocator),
+            has_default_lib_allocator: Tracked::new(has_default_lib_allocator),
             plugin_registrar_fn: tcx.sess
                 .plugin_registrar_fn
                 .get()
index 9ef5b9408303d7f886ad74a3a145e2a872d6665b..0b670121ba23b38f2a7318d7286ff9db8943762f 100644 (file)
@@ -243,6 +243,8 @@ pub struct CrateRoot {
     pub hash: hir::svh::Svh,
     pub disambiguator: Symbol,
     pub panic_strategy: Tracked<PanicStrategy>,
+    pub has_global_allocator: Tracked<bool>,
+    pub has_default_lib_allocator: Tracked<bool>,
     pub plugin_registrar_fn: Option<DefIndex>,
     pub macro_derive_registrar: Option<DefIndex>,
 
index b3b70bc0a25efc779759c6934780a05930a724a2..8d7279b29eb552db3ac95907a5926334d7044e97 100644 (file)
@@ -14,5 +14,6 @@ build_helper = { path = "../build_helper" }
 cmake = "0.1.18"
 
 [dependencies]
+alloc = { path = "../liballoc" }
 alloc_system = { path = "../liballoc_system" }
 core = { path = "../libcore" }
index 54941362e845091861e06dba9cabea1e9310cdc2..e987b1f335e19c3b711a943e0f1f8e2205f8b9d6 100644 (file)
@@ -11,6 +11,8 @@
 #![sanitizer_runtime]
 #![feature(sanitizer_runtime)]
 #![feature(alloc_system)]
+#![cfg_attr(not(stage0), feature(allocator_api))]
+#![cfg_attr(not(stage0), feature(global_allocator))]
 #![feature(staged_api)]
 #![no_std]
 #![unstable(feature = "sanitizer_runtime_lib",
             issue = "0")]
 
 extern crate alloc_system;
+
+#[cfg(not(stage0))]
+use alloc_system::System;
+
+#[cfg(not(stage0))]
+#[global_allocator]
+static ALLOC: System = System;
index a512cf2f02a5c0807f33995332a29918df55e8ae..c7db2a9a8ae7ddaa86f5364a3257dd88895cd790 100644 (file)
@@ -17,6 +17,7 @@ log = "0.3"
 owning_ref = "0.3.3"
 rustc-demangle = "0.1.4"
 rustc = { path = "../librustc" }
+rustc_allocator = { path = "../librustc_allocator" }
 rustc_back = { path = "../librustc_back" }
 rustc_bitflags = { path = "../librustc_bitflags" }
 rustc_const_math = { path = "../librustc_const_math" }
diff --git a/src/librustc_trans/allocator.rs b/src/librustc_trans/allocator.rs
new file mode 100644 (file)
index 0000000..9abb6d6
--- /dev/null
@@ -0,0 +1,117 @@
+// Copyright 2017 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.
+
+use std::ffi::CString;
+use std::ptr;
+
+use libc::c_uint;
+use rustc::middle::allocator::AllocatorKind;
+use rustc::ty::TyCtxt;
+use rustc_allocator::{ALLOCATOR_METHODS, AllocatorTy};
+
+use ModuleLlvm;
+use llvm::{self, False, True};
+
+pub unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) {
+    let llcx = mods.llcx;
+    let llmod = mods.llmod;
+    let usize = match &tcx.sess.target.target.target_pointer_width[..] {
+        "16" => llvm::LLVMInt16TypeInContext(llcx),
+        "32" => llvm::LLVMInt32TypeInContext(llcx),
+        "64" => llvm::LLVMInt64TypeInContext(llcx),
+        tws => bug!("Unsupported target word size for int: {}", tws),
+    };
+    let i8 = llvm::LLVMInt8TypeInContext(llcx);
+    let i8p = llvm::LLVMPointerType(i8, 0);
+    let usizep = llvm::LLVMPointerType(usize, 0);
+    let void = llvm::LLVMVoidTypeInContext(llcx);
+
+    for method in ALLOCATOR_METHODS {
+        let mut args = Vec::new();
+        for ty in method.inputs.iter() {
+            match *ty {
+                AllocatorTy::Layout => {
+                    args.push(usize); // size
+                    args.push(usize); // align
+                }
+                AllocatorTy::LayoutRef => args.push(i8p),
+                AllocatorTy::Ptr => args.push(i8p),
+                AllocatorTy::AllocErr => args.push(i8p),
+
+                AllocatorTy::Bang |
+                AllocatorTy::ResultExcess |
+                AllocatorTy::ResultPtr |
+                AllocatorTy::ResultUnit |
+                AllocatorTy::UsizePair |
+                AllocatorTy::Unit => panic!("invalid allocator arg"),
+            }
+        }
+        let output = match method.output {
+            AllocatorTy::UsizePair => {
+                args.push(usizep); // min
+                args.push(usizep); // max
+                None
+            }
+            AllocatorTy::Bang => None,
+            AllocatorTy::ResultExcess => {
+                args.push(i8p); // excess_ptr
+                args.push(i8p); // err_ptr
+                Some(i8p)
+            }
+            AllocatorTy::ResultPtr => {
+                args.push(i8p); // err_ptr
+                Some(i8p)
+            }
+            AllocatorTy::ResultUnit => Some(i8),
+            AllocatorTy::Unit => None,
+
+            AllocatorTy::AllocErr |
+            AllocatorTy::Layout |
+            AllocatorTy::LayoutRef |
+            AllocatorTy::Ptr => panic!("invalid allocator output"),
+        };
+        let ty = llvm::LLVMFunctionType(output.unwrap_or(void),
+                                        args.as_ptr(),
+                                        args.len() as c_uint,
+                                        False);
+        let name = CString::new(format!("__rust_{}", method.name)).unwrap();
+        let llfn = llvm::LLVMRustGetOrInsertFunction(llmod,
+                                                     name.as_ptr(),
+                                                     ty);
+
+        let callee = CString::new(kind.fn_name(method.name)).unwrap();
+        let callee = llvm::LLVMRustGetOrInsertFunction(llmod,
+                                                       callee.as_ptr(),
+                                                       ty);
+
+        let llbb = llvm::LLVMAppendBasicBlockInContext(llcx,
+                                                       llfn,
+                                                       "entry\0".as_ptr() as *const _);
+
+        let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
+        llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
+        let args = args.iter().enumerate().map(|(i, _)| {
+            llvm::LLVMGetParam(llfn, i as c_uint)
+        }).collect::<Vec<_>>();
+        let ret = llvm::LLVMRustBuildCall(llbuilder,
+                                          callee,
+                                          args.as_ptr(),
+                                          args.len() as c_uint,
+                                          ptr::null_mut(),
+                                          "\0".as_ptr() as *const _);
+        llvm::LLVMSetTailCall(ret, True);
+        if output.is_some() {
+            llvm::LLVMBuildRet(llbuilder, ret);
+        } else {
+            llvm::LLVMBuildRetVoid(llbuilder);
+        }
+        llvm::LLVMDisposeBuilder(llbuilder);
+    }
+}
index a7f205a18a46c8bb2868acc4444d291aafa9df09..6f235ae5ee049897d9cb5aa451c3759e93591605 100644 (file)
 /// match up with `METADATA_MODULE_NAME`.
 pub const METADATA_OBJ_NAME: &'static str = "crate.metadata.o";
 
+// same as for metadata above, but for allocator shim
+pub const ALLOCATOR_MODULE_NAME: &'static str = "crate.allocator";
+pub const ALLOCATOR_OBJ_NAME: &'static str = "crate.allocator.o";
+
 // RLIB LLVM-BYTECODE OBJECT LAYOUT
 // Version 1
 // Bytes    Data
@@ -240,6 +244,9 @@ pub fn link_binary(sess: &Session,
             }
         }
         remove(sess, &outputs.with_extension(METADATA_OBJ_NAME));
+        if trans.allocator_module.is_some() {
+            remove(sess, &outputs.with_extension(ALLOCATOR_OBJ_NAME));
+        }
     }
 
     out_filenames
@@ -417,11 +424,21 @@ fn link_binary_output(sess: &Session,
         let out_filename = out_filename(sess, crate_type, outputs, crate_name);
         match crate_type {
             config::CrateTypeRlib => {
-                link_rlib(sess, Some(trans), &objects, &out_filename,
+                link_rlib(sess,
+                          trans,
+                          RlibFlavor::Normal,
+                          &objects,
+                          outputs,
+                          &out_filename,
                           tmpdir.path()).build();
             }
             config::CrateTypeStaticlib => {
-                link_staticlib(sess, &objects, &out_filename, tmpdir.path());
+                link_staticlib(sess,
+                               trans,
+                               outputs,
+                               &objects,
+                               &out_filename,
+                               tmpdir.path());
             }
             _ => {
                 link_natively(sess, crate_type, &objects, &out_filename, trans,
@@ -477,6 +494,11 @@ fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, out_filename:
     }
 }
 
+enum RlibFlavor {
+    Normal,
+    StaticlibBase,
+}
+
 // Create an 'rlib'
 //
 // An rlib in its current incarnation is essentially a renamed .a file. The
@@ -484,8 +506,10 @@ fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, out_filename:
 // all of the object files from native libraries. This is done by unzipping
 // native libraries and inserting all of the contents into this archive.
 fn link_rlib<'a>(sess: &'a Session,
-                 trans: Option<&CrateTranslation>, // None == no metadata/bytecode
+                 trans: &CrateTranslation,
+                 flavor: RlibFlavor,
                  objects: &[PathBuf],
+                 outputs: &OutputFilenames,
                  out_filename: &Path,
                  tmpdir: &Path) -> ArchiveBuilder<'a> {
     info!("preparing rlib from {:?} to {:?}", objects, out_filename);
@@ -546,8 +570,8 @@ fn link_rlib<'a>(sess: &'a Session,
     //
     // Basically, all this means is that this code should not move above the
     // code above.
-    match trans {
-        Some(trans) => {
+    match flavor {
+        RlibFlavor::Normal => {
             // Instead of putting the metadata in an object file section, rlibs
             // contain the metadata in a separate file. We use a temp directory
             // here so concurrent builds in the same directory don't try to use
@@ -620,7 +644,11 @@ fn link_rlib<'a>(sess: &'a Session,
             }
         }
 
-        None => {}
+        RlibFlavor::StaticlibBase => {
+            if trans.allocator_module.is_some() {
+                ab.add_file(&outputs.with_extension(ALLOCATOR_OBJ_NAME));
+            }
+        }
     }
 
     ab
@@ -672,9 +700,19 @@ fn write_rlib_bytecode_object_v1(writer: &mut Write,
 // There's no need to include metadata in a static archive, so ensure to not
 // link in the metadata object file (and also don't prepare the archive with a
 // metadata file).
-fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
+fn link_staticlib(sess: &Session,
+                  trans: &CrateTranslation,
+                  outputs: &OutputFilenames,
+                  objects: &[PathBuf],
+                  out_filename: &Path,
                   tempdir: &Path) {
-    let mut ab = link_rlib(sess, None, objects, out_filename, tempdir);
+    let mut ab = link_rlib(sess,
+                           trans,
+                           RlibFlavor::StaticlibBase,
+                           objects,
+                           outputs,
+                           out_filename,
+                           tempdir);
     let mut all_native_libs = vec![];
 
     let res = each_linked_rlib(sess, &mut |cnum, path| {
@@ -944,6 +982,10 @@ fn link_args(cmd: &mut Linker,
         cmd.add_object(&outputs.with_extension(METADATA_OBJ_NAME));
     }
 
+    if trans.allocator_module.is_some() {
+        cmd.add_object(&outputs.with_extension(ALLOCATOR_OBJ_NAME));
+    }
+
     // Try to strip as much out of the generated object by removing unused
     // sections if possible. See more comments in linker.rs
     if !sess.opts.cg.link_dead_code {
index b38dc18838923196d527ee64900398c7a4f6c8bb..52fe747858cc4ba26af551cdbafd13c03ee33b34 100644 (file)
@@ -92,7 +92,6 @@ pub fn compute<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) -> ExportedSymbols
             // Down below we'll hardwire all of the symbols to the `Rust` export
             // level instead.
             let special_runtime_crate =
-                scx.tcx().is_allocator(cnum.as_def_id()) ||
                 scx.tcx().is_panic_runtime(cnum.as_def_id()) ||
                 scx.sess().cstore.is_compiler_builtins(cnum);
 
index 562d7171156fe0dbe66b1b250a0d624ae2b5705c..0c233dfe109bc3b86a654eb3ffe0a650da41ba1a 100644 (file)
@@ -644,6 +644,7 @@ pub fn run_passes(sess: &Session,
 
     let mut modules_config = ModuleConfig::new(tm, sess.opts.cg.passes.clone());
     let mut metadata_config = ModuleConfig::new(tm, vec![]);
+    let mut allocator_config = ModuleConfig::new(tm, vec![]);
 
     if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
         match *sanitizer {
@@ -674,6 +675,7 @@ pub fn run_passes(sess: &Session,
         modules_config.emit_bc = true;
         modules_config.emit_lto_bc = true;
         metadata_config.emit_bc = true;
+        allocator_config.emit_bc = true;
     }
 
     // Emit bitcode files for the crate if we're emitting an rlib.
@@ -699,6 +701,7 @@ pub fn run_passes(sess: &Session,
                 // in this case we still want the metadata object file.
                 if !sess.opts.output_types.contains_key(&OutputType::Assembly) {
                     metadata_config.emit_obj = true;
+                    allocator_config.emit_obj = true;
                 }
             }
             OutputType::Object => { modules_config.emit_obj = true; }
@@ -706,6 +709,7 @@ pub fn run_passes(sess: &Session,
             OutputType::Exe => {
                 modules_config.emit_obj = true;
                 metadata_config.emit_obj = true;
+                allocator_config.emit_obj = true;
             },
             OutputType::Mir => {}
             OutputType::DepInfo => {}
@@ -714,6 +718,7 @@ pub fn run_passes(sess: &Session,
 
     modules_config.set_flags(sess, trans);
     metadata_config.set_flags(sess, trans);
+    allocator_config.set_flags(sess, trans);
 
 
     // Populate a buffer with a list of codegen threads.  Items are processed in
@@ -729,6 +734,14 @@ pub fn run_passes(sess: &Session,
         work_items.push(work);
     }
 
+    if let Some(allocator) = trans.allocator_module.clone() {
+        let work = build_work_item(sess,
+                                   allocator,
+                                   allocator_config.clone(),
+                                   crate_output.clone());
+        work_items.push(work);
+    }
+
     for mtrans in trans.modules.iter() {
         let work = build_work_item(sess,
                                    mtrans.clone(),
@@ -905,6 +918,13 @@ pub fn run_passes(sess: &Session,
                                               Some(&trans.metadata_module.name));
             remove(sess, &path);
         }
+        if allocator_config.emit_bc && !user_wants_bitcode {
+            if let Some(ref module) = trans.allocator_module {
+                let path = crate_output.temp_path(OutputType::Bitcode,
+                                                  Some(&module.name));
+                remove(sess, &path);
+            }
+        }
     }
 
     // We leave the following files around by default:
index 2589a3538a940729bece46979422cbb6184fdee1..8298324e9968089749c5d802161b9613090656b2 100644 (file)
@@ -47,6 +47,7 @@
 use rustc::session::Session;
 use rustc_incremental::IncrementalHashesMap;
 use abi;
+use allocator;
 use mir::lvalue::LvalueRef;
 use attributes;
 use builder::Builder;
@@ -1086,8 +1087,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             llmod: metadata_llmod,
         }),
     };
+
     let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
 
+
     // Skip crate items and just output metadata in -Z no-trans mode.
     if tcx.sess.opts.debugging_opts.no_trans ||
        !tcx.sess.opts.output_types.should_trans() {
@@ -1097,6 +1100,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             crate_name: tcx.crate_name(LOCAL_CRATE),
             modules: vec![],
             metadata_module: metadata_module,
+            allocator_module: None,
             link: link_meta,
             metadata: metadata,
             exported_symbols: empty_exported_symbols,
@@ -1296,6 +1300,41 @@ fn module_translation<'a, 'tcx>(
         create_imps(sess, &llvm_modules);
     }
 
+    // Translate an allocator shim, if any
+    //
+    // If LTO is enabled and we've got some previous LLVM module we translated
+    // above, then we can just translate directly into that LLVM module. If not,
+    // however, we need to create a separate module and trans into that. Note
+    // that the separate translation is critical for the standard library where
+    // the rlib's object file doesn't have allocator functions but the dylib
+    // links in an object file that has allocator functions. When we're
+    // compiling a final LTO artifact, though, there's no need to worry about
+    // this as we're not working with this dual "rlib/dylib" functionality.
+    let allocator_module = tcx.sess.allocator_kind.get().and_then(|kind| unsafe {
+        if sess.lto() && llvm_modules.len() > 0 {
+            time(tcx.sess.time_passes(), "write allocator module", || {
+                allocator::trans(tcx, &llvm_modules[0], kind)
+            });
+            None
+        } else {
+            let (llcx, llmod) =
+                context::create_context_and_module(tcx.sess, "allocator");
+            let modules = ModuleLlvm {
+                llmod: llmod,
+                llcx: llcx,
+            };
+            time(tcx.sess.time_passes(), "write allocator module", || {
+                allocator::trans(tcx, &modules, kind)
+            });
+
+            Some(ModuleTranslation {
+                name: link::ALLOCATOR_MODULE_NAME.to_string(),
+                symbol_name_hash: 0, // we always rebuild allocator shims
+                source: ModuleSource::Translated(modules),
+            })
+        }
+    });
+
     let linker_info = LinkerInfo::new(&shared_ccx, &exported_symbols);
 
     let subsystem = attr::first_attr_value_str_by_name(&krate.attrs,
@@ -1313,6 +1352,7 @@ fn module_translation<'a, 'tcx>(
         crate_name: tcx.crate_name(LOCAL_CRATE),
         modules: modules,
         metadata_module: metadata_module,
+        allocator_module: allocator_module,
         link: link_meta,
         metadata: metadata,
         exported_symbols: exported_symbols,
index 6acd10cb887f8e615a63b76d3a383bc737b1daf4..5c76f778f8d63610553bd35a36eadc57e2d684e8 100644 (file)
@@ -43,6 +43,7 @@
 extern crate libc;
 extern crate owning_ref;
 #[macro_use] extern crate rustc;
+extern crate rustc_allocator;
 extern crate rustc_back;
 extern crate rustc_data_structures;
 extern crate rustc_incremental;
@@ -84,6 +85,7 @@ pub mod back {
 
 mod abi;
 mod adt;
+mod allocator;
 mod asm;
 mod assert_module_sources;
 mod attributes;
@@ -163,6 +165,7 @@ pub struct CrateTranslation {
     pub crate_name: Symbol,
     pub modules: Vec<ModuleTranslation>,
     pub metadata_module: ModuleTranslation,
+    pub allocator_module: Option<ModuleTranslation>,
     pub link: rustc::middle::cstore::LinkMeta,
     pub metadata: rustc::middle::cstore::EncodedMetadata,
     pub exported_symbols: back::symbol_export::ExportedSymbols,
index 50c721db849aa7307eeb18430e1eca93e4570fa5..06f4f7643ec830a57e9536a26fbb5fa97eb4aecf 100644 (file)
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use alloc::heap::{allocate, deallocate};
+use alloc::heap::{Heap, Alloc, Layout};
 
 use cmp;
 use hash::{BuildHasher, Hash, Hasher};
@@ -781,10 +781,8 @@ unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> {
                     .expect("capacity overflow"),
                 "capacity overflow");
 
-        let buffer = allocate(size, alignment);
-        if buffer.is_null() {
-            ::alloc::oom()
-        }
+        let buffer = Heap.alloc(Layout::from_size_align(size, alignment).unwrap())
+            .unwrap_or_else(|e| Heap.oom(e));
 
         let hashes = buffer.offset(hash_offset as isize) as *mut HashUint;
 
@@ -1193,7 +1191,8 @@ fn drop(&mut self) {
         debug_assert!(!oflo, "should be impossible");
 
         unsafe {
-            deallocate(self.hashes.ptr() as *mut u8, size, align);
+            Heap.dealloc(self.hashes.ptr() as *mut u8,
+                         Layout::from_size_align(size, align).unwrap());
             // Remember how everything was allocated out of one buffer
             // during initialization? We only need one call to free here.
         }
index 4b340f70fbc745089b811af196960db05ab274d1..d77f817659c566917f8e5548e1528fa8c02358fc 100644 (file)
@@ -224,7 +224,7 @@ fn description(&self) -> &str { *self }
 
 #[unstable(feature = "allocator_api",
            reason = "the precise API and guarantees it provides may be tweaked.",
-           issue = "27700")]
+           issue = "32838")]
 impl Error for allocator::AllocErr {
     fn description(&self) -> &str {
         allocator::AllocErr::description(self)
@@ -233,7 +233,7 @@ fn description(&self) -> &str {
 
 #[unstable(feature = "allocator_api",
            reason = "the precise API and guarantees it provides may be tweaked.",
-           issue = "27700")]
+           issue = "32838")]
 impl Error for allocator::CannotReallocInPlace {
     fn description(&self) -> &str {
         allocator::CannotReallocInPlace::description(self)
diff --git a/src/libstd/heap.rs b/src/libstd/heap.rs
new file mode 100644 (file)
index 0000000..83bd3b0
--- /dev/null
@@ -0,0 +1,165 @@
+// Copyright 2017 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.
+
+//! dox
+
+#![unstable(issue = "32838", feature = "allocator_api")]
+
+pub use alloc::heap::{Heap, Alloc, Layout, Excess, CannotReallocInPlace, AllocErr};
+#[cfg(not(stage0))]
+pub use alloc_system::System;
+
+#[cfg(all(not(stage0), not(test)))]
+#[doc(hidden)]
+pub mod __default_lib_allocator {
+    use super::{System, Layout, Alloc, AllocErr};
+    use ptr;
+
+    // for symbol names src/librustc/middle/allocator.rs
+    // for signatures src/librustc_allocator/lib.rs
+
+    // linkage directives are provided as part of the current compiler allocator
+    // ABI
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_alloc(size: usize,
+                                     align: usize,
+                                     err: *mut u8) -> *mut u8 {
+        let layout = Layout::from_size_align_unchecked(size, align);
+        match System.alloc(layout) {
+            Ok(p) => p,
+            Err(e) => {
+                ptr::write(err as *mut AllocErr, e);
+                0 as *mut u8
+            }
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_oom(err: *const u8) -> ! {
+        System.oom((*(err as *const AllocErr)).clone())
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
+                                       size: usize,
+                                       align: usize) {
+        System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_usable_size(layout: *const u8,
+                                           min: *mut usize,
+                                           max: *mut usize) {
+        let pair = System.usable_size(&*(layout as *const Layout));
+        *min = pair.0;
+        *max = pair.1;
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_realloc(ptr: *mut u8,
+                                       old_size: usize,
+                                       old_align: usize,
+                                       new_size: usize,
+                                       new_align: usize,
+                                       err: *mut u8) -> *mut u8 {
+        let old_layout = Layout::from_size_align_unchecked(old_size, old_align);
+        let new_layout = Layout::from_size_align_unchecked(new_size, new_align);
+        match System.realloc(ptr, old_layout, new_layout) {
+            Ok(p) => p,
+            Err(e) => {
+                ptr::write(err as *mut AllocErr, e);
+                0 as *mut u8
+            }
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_alloc_zeroed(size: usize,
+                                            align: usize,
+                                            err: *mut u8) -> *mut u8 {
+        let layout = Layout::from_size_align_unchecked(size, align);
+        match System.alloc_zeroed(layout) {
+            Ok(p) => p,
+            Err(e) => {
+                ptr::write(err as *mut AllocErr, e);
+                0 as *mut u8
+            }
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_alloc_excess(size: usize,
+                                            align: usize,
+                                            excess: *mut usize,
+                                            err: *mut u8) -> *mut u8 {
+        let layout = Layout::from_size_align_unchecked(size, align);
+        match System.alloc_excess(layout) {
+            Ok(p) => {
+                *excess = p.1;
+                p.0
+            }
+            Err(e) => {
+                ptr::write(err as *mut AllocErr, e);
+                0 as *mut u8
+            }
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_realloc_excess(ptr: *mut u8,
+                                              old_size: usize,
+                                              old_align: usize,
+                                              new_size: usize,
+                                              new_align: usize,
+                                              excess: *mut usize,
+                                              err: *mut u8) -> *mut u8 {
+        let old_layout = Layout::from_size_align_unchecked(old_size, old_align);
+        let new_layout = Layout::from_size_align_unchecked(new_size, new_align);
+        match System.realloc_excess(ptr, old_layout, new_layout) {
+            Ok(p) => {
+                *excess = p.1;
+                p.0
+            }
+            Err(e) => {
+                ptr::write(err as *mut AllocErr, e);
+                0 as *mut u8
+            }
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_grow_in_place(ptr: *mut u8,
+                                             old_size: usize,
+                                             old_align: usize,
+                                             new_size: usize,
+                                             new_align: usize) -> u8 {
+        let old_layout = Layout::from_size_align_unchecked(old_size, old_align);
+        let new_layout = Layout::from_size_align_unchecked(new_size, new_align);
+        match System.grow_in_place(ptr, old_layout, new_layout) {
+            Ok(()) => 1,
+            Err(_) => 0,
+        }
+    }
+
+    #[no_mangle]
+    pub unsafe extern fn __rdl_shrink_in_place(ptr: *mut u8,
+                                               old_size: usize,
+                                               old_align: usize,
+                                               new_size: usize,
+                                               new_align: usize) -> u8 {
+        let old_layout = Layout::from_size_align_unchecked(old_size, old_align);
+        let new_layout = Layout::from_size_align_unchecked(new_size, new_align);
+        match System.shrink_in_place(ptr, old_layout, new_layout) {
+            Ok(()) => 1,
+            Err(_) => 0,
+        }
+    }
+}
index bafe23e80a030cfb3758eb43ad213b6473f31a97..c4bdf7c5b822b3ae15f8c0b50a4f393a4951ebc4 100644 (file)
 // Tell the compiler to link to either panic_abort or panic_unwind
 #![needs_panic_runtime]
 
-// Always use alloc_system during stage0 since we don't know if the alloc_*
-// crate the stage0 compiler will pick by default is available (most
-// obviously, if the user has disabled jemalloc in `./configure`).
-#![cfg_attr(any(stage0, feature = "force_alloc_system"), feature(alloc_system))]
-
 // Turn warnings into errors, but only after stage0, where it can be useful for
 // code to emit warnings during language transitions
 #![deny(warnings)]
 // compiler details that will never be stable
 #![feature(alloc)]
 #![feature(allocator_api)]
+#![feature(alloc_system)]
+#![feature(allocator_internals)]
 #![feature(allow_internal_unstable)]
 #![feature(asm)]
 #![feature(associated_consts)]
 #![cfg_attr(test, feature(update_panic_count))]
 #![cfg_attr(test, feature(float_bits_conv))]
 
+#![cfg_attr(not(stage0), default_lib_allocator)]
+
 // Explicitly import the prelude. The compiler uses this same unstable attribute
 // to import the prelude implicitly when building crates that depend on std.
 #[prelude_import]
 #[macro_use]
 #[macro_reexport(vec, format)]
 extern crate alloc;
+extern crate alloc_system;
 extern crate std_unicode;
 extern crate libc;
 
 // We always need an unwinder currently for backtraces
 extern crate unwind;
 
-#[cfg(any(stage0, feature = "force_alloc_system"))]
-extern crate alloc_system;
-
 // compiler-rt intrinsics
 extern crate compiler_builtins;
 
 pub mod process;
 pub mod sync;
 pub mod time;
+pub mod heap;
 
 // Platform-abstraction modules
 #[macro_use]
index 854d380d128c9d18d500297b7ecaa07badce30a3..46e5acdf3d22bdfd8d6216dbeb962b01849d23ec 100644 (file)
@@ -59,8 +59,6 @@
 
 #[cfg(not(test))]
 pub fn init() {
-    use alloc::oom;
-
     // By default, some platforms will send a *signal* when an EPIPE error
     // would otherwise be delivered. This runtime doesn't install a SIGPIPE
     // handler, causing it to kill the program, which isn't exactly what we
@@ -72,24 +70,6 @@ pub fn init() {
         reset_sigpipe();
     }
 
-    oom::set_oom_handler(oom_handler);
-
-    // A nicer handler for out-of-memory situations than the default one. This
-    // one prints a message to stderr before aborting. It is critical that this
-    // code does not allocate any memory since we are in an OOM situation. Any
-    // errors are ignored while printing since there's nothing we can do about
-    // them and we are about to exit anyways.
-    fn oom_handler() -> ! {
-        use intrinsics;
-        let msg = "fatal runtime error: out of memory\n";
-        unsafe {
-            libc::write(libc::STDERR_FILENO,
-                        msg.as_ptr() as *const libc::c_void,
-                        msg.len());
-            intrinsics::abort();
-        }
-    }
-
     #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))]
     unsafe fn reset_sigpipe() {
         assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
index 840e7fdfc9b26942c56e4e5d11d8c038707072ad..ee58efc5144a822e77f4afde5ac57c744ef286b9 100644 (file)
 
 #[cfg(not(test))]
 pub fn init() {
-    ::alloc::oom::set_oom_handler(oom_handler);
-
-    // See comment in sys/unix/mod.rs
-    fn oom_handler() -> ! {
-        use intrinsics;
-        use ptr;
-        let msg = "fatal runtime error: out of memory\n";
-        unsafe {
-            // WriteFile silently fails if it is passed an invalid handle, so
-            // there is no need to check the result of GetStdHandle.
-            c::WriteFile(c::GetStdHandle(c::STD_ERROR_HANDLE),
-                         msg.as_ptr() as c::LPVOID,
-                         msg.len() as c::DWORD,
-                         ptr::null_mut(),
-                         ptr::null_mut());
-            intrinsics::abort();
-        }
-    }
 }
 
 pub fn decode_error_kind(errno: i32) -> ErrorKind {
index 412a34932087d52a9bbbabb4794baaeb9590b2c4..2cfb16169273f1da541037f0dfb2864f924c174e 100644 (file)
@@ -249,6 +249,8 @@ fn item_mod(&self, span: Span, inner_span: Span,
                 name: Ident, attrs: Vec<ast::Attribute>,
                 items: Vec<P<ast::Item>>) -> P<ast::Item>;
 
+    fn item_extern_crate(&self, span: Span, name: Ident) -> P<ast::Item>;
+
     fn item_static(&self,
                    span: Span,
                    name: Ident,
@@ -1095,6 +1097,10 @@ fn item_mod(&self, span: Span, inner_span: Span, name: Ident,
         )
     }
 
+    fn item_extern_crate(&self, span: Span, name: Ident) -> P<ast::Item> {
+        self.item(span, name, Vec::new(), ast::ItemKind::ExternCrate(None))
+    }
+
     fn item_static(&self,
                    span: Span,
                    name: Ident,
index df8ee189d21b3d23a7040896e26b4d91396db97e..0163bb3b1d05adb7a1659b7acb5b3eb5aae9c1ce 100644 (file)
@@ -137,7 +137,6 @@ pub fn new() -> Features {
     (active, placement_in_syntax, "1.0.0", Some(27779)),
     (active, unboxed_closures, "1.0.0", Some(29625)),
 
-    (active, allocator, "1.0.0", Some(27389)),
     (active, fundamental, "1.0.0", Some(29635)),
     (active, main, "1.0.0", Some(29634)),
     (active, needs_allocator, "1.4.0", Some(27389)),
@@ -360,6 +359,10 @@ pub fn new() -> Features {
 
     // Allows unsized tuple coercion.
     (active, unsized_tuple_coercion, "1.20.0", Some(42877)),
+
+    // global allocators and their internals
+    (active, global_allocator, "1.20.0", None),
+    (active, allocator_internals, "1.20.0", None),
 );
 
 declare_features! (
@@ -379,6 +382,7 @@ pub fn new() -> Features {
     // rustc internal
     (removed, unmarked_api, "1.0.0", None),
     (removed, pushpop_unsafe, "1.2.0", None),
+    (removed, allocator, "1.0.0", None),
 );
 
 declare_features! (
@@ -585,16 +589,22 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
                                              "the `#[rustc_on_unimplemented]` attribute \
                                               is an experimental feature",
                                              cfg_fn!(on_unimplemented))),
-    ("allocator", Whitelisted, Gated(Stability::Unstable,
-                                     "allocator",
-                                     "the `#[allocator]` attribute is an experimental feature",
-                                     cfg_fn!(allocator))),
+    ("global_allocator", Normal, Gated(Stability::Unstable,
+                                       "global_allocator",
+                                       "the `#[global_allocator]` attribute is \
+                                        an experimental feature",
+                                       cfg_fn!(global_allocator))),
+    ("default_lib_allocator", Whitelisted, Gated(Stability::Unstable,
+                                            "allocator_internals",
+                                            "the `#[default_lib_allocator]` \
+                                             attribute is an experimental feature",
+                                            cfg_fn!(allocator_internals))),
     ("needs_allocator", Normal, Gated(Stability::Unstable,
-                                      "needs_allocator",
+                                      "allocator_internals",
                                       "the `#[needs_allocator]` \
                                        attribute is an experimental \
                                        feature",
-                                      cfg_fn!(needs_allocator))),
+                                      cfg_fn!(allocator_internals))),
     ("panic_runtime", Whitelisted, Gated(Stability::Unstable,
                                          "panic_runtime",
                                          "the `#[panic_runtime]` attribute is \
index 37ba3264452650a19f6d47b819c2ac8a2e6adcde..b2d4c1132951247e6a116aa5c8f6de8d96c9164e 100644 (file)
@@ -1,4 +1,8 @@
 # If this file is modified, then llvm will be (optionally) cleaned and then rebuilt.
 # The actual contents of this file do not matter, but to trigger a change on the
 # build bots then the contents should be changed so git updates the mtime.
+<<<<<<< 37849a002ed91ac2b80aeb2172364b4e19250e05
 2017-06-27
+=======
+2017-06-26
+>>>>>>> rustc: Implement the #[global_allocator] attribute
index bc84ac49da985a11166ccc4e2c80793f45291e63..d8bbcd9b7328ee841d33e4c8eec79993a999ba4e 100644 (file)
@@ -11,7 +11,7 @@
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type = "lib"]
-#![feature(allocator)]
+#![feature(custom_attribute)]
 
 pub struct S {
   _field: [i64; 4],
diff --git a/src/test/compile-fail/allocator-depends-on-needs-allocators.rs b/src/test/compile-fail/allocator-depends-on-needs-allocators.rs
deleted file mode 100644 (file)
index 7f420ff..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2015 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.
-
-// error-pattern: `allocator3` cannot depend on a crate that needs an allocator
-// aux-build:needs_allocator.rs
-// aux-build:allocator3.rs
-
-// The needs_allocator crate is a dependency of the allocator crate allocator3,
-// which is not allowed
-
-extern crate allocator3;
-
-fn main() {
-}
diff --git a/src/test/compile-fail/allocator-dylib-is-system.rs b/src/test/compile-fail/allocator-dylib-is-system.rs
deleted file mode 100644 (file)
index 3100955..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 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.
-
-// ignore-musl no dylibs
-// aux-build:allocator-dylib.rs
-// aux-build:allocator1.rs
-// no-prefer-dynamic
-// error-pattern: cannot link together two allocators
-
-// Verify that the allocator for statically linked dynamic libraries is the
-// system allocator. Do this by linking in jemalloc and making sure that we get
-// an error.
-
-// ignore-emscripten FIXME: What "other allocator" should we use for emcc?
-
-#![feature(alloc_jemalloc)]
-
-extern crate allocator_dylib;
-
-// The main purpose of this test is to ensure that `alloc_jemalloc` **fails**
-// here (specifically the jemalloc allocator), but currently jemalloc is
-// disabled on quite a few platforms (bsds, emscripten, msvc, etc). To ensure
-// that this just passes on those platforms we link in some other allocator to
-// ensure we get the same error.
-//
-// So long as we CI linux/macOS we should be good.
-#[cfg(any(target_os = "linux", target_os = "macos"))]
-extern crate alloc_jemalloc;
-#[cfg(not(any(target_os = "linux", target_os = "macos")))]
-extern crate allocator1;
-
-fn main() {
-    allocator_dylib::foo();
-}
diff --git a/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs b/src/test/compile-fail/allocator-rust-dylib-is-jemalloc.rs
deleted file mode 100644 (file)
index 68e01ba..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 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.
-
-// ignore-musl no dylibs
-// aux-build:allocator-dylib2.rs
-// aux-build:allocator1.rs
-// error-pattern: cannot link together two allocators
-
-// Ensure that rust dynamic libraries use jemalloc as their allocator, verifying
-// by linking in the system allocator here and ensuring that we get a complaint.
-
-// ignore-emscripten FIXME: What "other allocator" is correct for emscripten?
-
-#![feature(alloc_system)]
-
-extern crate allocator_dylib2;
-
-// The main purpose of this test is to ensure that `alloc_system` **fails**
-// here (specifically the system allocator), but currently system is
-// disabled on quite a few platforms (bsds, emscripten, msvc, etc). To ensure
-// that this just passes on those platforms we link in some other allocator to
-// ensure we get the same error.
-//
-// So long as we CI linux/macOS we should be good.
-#[cfg(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")),
-          target_os = "macos"))]
-extern crate alloc_system;
-#[cfg(not(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")),
-              target_os = "macos")))]
-extern crate allocator1;
-
-fn main() {
-    allocator_dylib2::foo();
-}
diff --git a/src/test/compile-fail/allocator/auxiliary/system-allocator.rs b/src/test/compile-fail/allocator/auxiliary/system-allocator.rs
new file mode 100644 (file)
index 0000000..4761dc4
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![feature(global_allocator, allocator_api)]
+#![crate_type = "rlib"]
+
+use std::heap::System;
+
+#[global_allocator]
+static A: System = System;
diff --git a/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs b/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs
new file mode 100644 (file)
index 0000000..4761dc4
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2016 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.
+
+// no-prefer-dynamic
+
+#![feature(global_allocator, allocator_api)]
+#![crate_type = "rlib"]
+
+use std::heap::System;
+
+#[global_allocator]
+static A: System = System;
diff --git a/src/test/compile-fail/allocator/function-allocator.rs b/src/test/compile-fail/allocator/function-allocator.rs
new file mode 100644 (file)
index 0000000..50f8260
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2016 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.
+
+#![feature(global_allocator)]
+
+#[global_allocator]
+fn foo() {} //~ ERROR: allocators must be statics
+
+fn main() {}
diff --git a/src/test/compile-fail/allocator/not-an-allocator.rs b/src/test/compile-fail/allocator/not-an-allocator.rs
new file mode 100644 (file)
index 0000000..e430143
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright 2016 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.
+
+#![feature(global_allocator, heap_api)]
+
+#[global_allocator]
+static A: usize = 0;
+//~^ the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+//~| the trait bound `&usize:
+
+fn main() {}
diff --git a/src/test/compile-fail/allocator/two-allocators.rs b/src/test/compile-fail/allocator/two-allocators.rs
new file mode 100644 (file)
index 0000000..b46ba63
--- /dev/null
@@ -0,0 +1,22 @@
+// Copyright 2016 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.
+
+#![feature(global_allocator, allocator_api)]
+
+use std::heap::System;
+
+#[global_allocator]
+static A: System = System;
+#[global_allocator]
+static B: System = System;
+//~^ ERROR: cannot define more than one #[global_allocator]
+
+fn main() {}
+
diff --git a/src/test/compile-fail/allocator/two-allocators2.rs b/src/test/compile-fail/allocator/two-allocators2.rs
new file mode 100644 (file)
index 0000000..e342c1f
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright 2016 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.
+
+// aux-build:system-allocator.rs
+// no-prefer-dynamic
+// error-pattern: the #[global_allocator] in
+
+#![feature(global_allocator, allocator_api)]
+
+extern crate system_allocator;
+
+use std::heap::System;
+
+#[global_allocator]
+static A: System = System;
+
+fn main() {}
+
diff --git a/src/test/compile-fail/allocator/two-allocators3.rs b/src/test/compile-fail/allocator/two-allocators3.rs
new file mode 100644 (file)
index 0000000..c310d94
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2016 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.
+
+// aux-build:system-allocator.rs
+// aux-build:system-allocator2.rs
+// no-prefer-dynamic
+// error-pattern: the #[global_allocator] in
+
+#![feature(global_allocator)]
+
+extern crate system_allocator;
+extern crate system_allocator2;
+
+fn main() {}
diff --git a/src/test/compile-fail/auxiliary/allocator-dylib.rs b/src/test/compile-fail/auxiliary/allocator-dylib.rs
deleted file mode 100644 (file)
index 568b247..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2015 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.
-
-// no-prefer-dynamic
-
-#![crate_type = "dylib"]
-
-pub fn foo() {}
diff --git a/src/test/compile-fail/auxiliary/allocator-dylib2.rs b/src/test/compile-fail/auxiliary/allocator-dylib2.rs
deleted file mode 100644 (file)
index 0d76c0e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2015 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.
-
-pub fn foo() {}
-
diff --git a/src/test/compile-fail/auxiliary/allocator1.rs b/src/test/compile-fail/auxiliary/allocator1.rs
deleted file mode 100644 (file)
index b247848..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2015 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.
-
-// no-prefer-dynamic
-
-#![feature(allocator)]
-#![allocator]
-#![crate_type = "rlib"]
-#![no_std]
diff --git a/src/test/compile-fail/auxiliary/allocator2.rs b/src/test/compile-fail/auxiliary/allocator2.rs
deleted file mode 100644 (file)
index b247848..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2015 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.
-
-// no-prefer-dynamic
-
-#![feature(allocator)]
-#![allocator]
-#![crate_type = "rlib"]
-#![no_std]
diff --git a/src/test/compile-fail/auxiliary/allocator3.rs b/src/test/compile-fail/auxiliary/allocator3.rs
deleted file mode 100644 (file)
index d3eb1f6..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2015 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.
-
-// no-prefer-dynamic
-
-#![feature(allocator)]
-#![no_std]
-#![allocator]
-#![crate_type = "rlib"]
-
-extern crate needs_allocator;
-
diff --git a/src/test/compile-fail/auxiliary/needs_allocator.rs b/src/test/compile-fail/auxiliary/needs_allocator.rs
deleted file mode 100644 (file)
index 5100316..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2015 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.
-
-// no-prefer-dynamic
-
-#![feature(needs_allocator)]
-#![no_std]
-#![needs_allocator]
-#![crate_type = "rlib"]
diff --git a/src/test/compile-fail/feature-gate-allocator.rs b/src/test/compile-fail/feature-gate-allocator.rs
deleted file mode 100644 (file)
index 6490216..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright 2015 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.
-
-#![allocator] //~ ERROR: experimental feature
-
-fn main() {}
diff --git a/src/test/compile-fail/feature-gate-allocator_internals.rs b/src/test/compile-fail/feature-gate-allocator_internals.rs
new file mode 100644 (file)
index 0000000..b519a98
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2016 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.
+
+#![default_lib_allocator] //~ ERROR: attribute is an experimental feature
+
+fn main() {}
+
diff --git a/src/test/compile-fail/feature-gate-global_allocator.rs b/src/test/compile-fail/feature-gate-global_allocator.rs
new file mode 100644 (file)
index 0000000..ff3c342
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2016 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.
+
+#[global_allocator] //~ ERROR: attribute is an experimental feature
+static A: usize = 0;
+
+fn main() {}
diff --git a/src/test/compile-fail/two-allocators-2.rs b/src/test/compile-fail/two-allocators-2.rs
deleted file mode 100644 (file)
index d6fcbcb..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2015 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.
-
-// error-pattern: cannot link together two allocators: allocator1 and allocator2
-// aux-build:allocator1.rs
-// aux-build:allocator2.rs
-
-// Make sure we can't link together two explicit allocators.
-
-extern crate allocator1;
-extern crate allocator2;
-
-fn main() {}
-
diff --git a/src/test/compile-fail/two-allocators-3.rs b/src/test/compile-fail/two-allocators-3.rs
deleted file mode 100644 (file)
index 965e4e0..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2015 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.
-
-// aux-build:allocator1.rs
-// error-pattern: cannot link together two allocators
-// ignore-musl no dylibs on musl yet
-// ignore-emscripten
-
-// We're linking std dynamically (via -C prefer-dynamic for this test) which
-// has an allocator and then we're also linking in a new allocator (allocator1)
-// and this should be an error
-
-extern crate allocator1;
-
-fn main() {
-}
diff --git a/src/test/compile-fail/two-allocators.rs b/src/test/compile-fail/two-allocators.rs
deleted file mode 100644 (file)
index a34f77d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2015 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.
-
-// error-pattern: cannot link together two allocators
-
-// aux-build:allocator1.rs
-// aux-build:allocator2.rs
-
-extern crate allocator1;
-extern crate allocator2;
-
-fn main() {}
index 3f6a28c251a2fad4e3cd7a72bba83d89b94d54cb..13d8366c60ab943edc1aaaae89dedbf36a26478c 100644 (file)
@@ -4,9 +4,7 @@ ifdef IS_MSVC
 # FIXME(#27979)
 all:
 else
-all:
-       $(RUSTC) foo.rs
-       $(RUSTC) bar.rs
+all: $(call STATICLIB,foo) $(call STATICLIB,bar)
        $(RUSTC) main.rs
        $(call RUN,main)
 endif
diff --git a/src/test/run-make/no-duplicate-libs/bar.c b/src/test/run-make/no-duplicate-libs/bar.c
new file mode 100644 (file)
index 0000000..b9dcd0f
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2017 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.
+
+extern void foo();
+
+void bar() {
+  foo();
+}
diff --git a/src/test/run-make/no-duplicate-libs/bar.rs b/src/test/run-make/no-duplicate-libs/bar.rs
deleted file mode 100644 (file)
index cb1c886..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 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.
-
-#![feature(lang_items, alloc_system, compiler_builtins_lib)]
-#![crate_type = "dylib"]
-#![no_std]
-
-extern crate alloc_system;
-extern crate compiler_builtins;
-
-#[no_mangle]
-pub extern fn bar() {}
-
-#[lang = "eh_personality"] fn eh_personality() {}
-#[lang = "eh_unwind_resume"] fn eh_unwind_resume() {}
-#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
-#[no_mangle] pub extern fn rust_eh_register_frames () {}
-#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
diff --git a/src/test/run-make/no-duplicate-libs/foo.c b/src/test/run-make/no-duplicate-libs/foo.c
new file mode 100644 (file)
index 0000000..906cd56
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2017 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.
+
+void foo() {}
diff --git a/src/test/run-make/no-duplicate-libs/foo.rs b/src/test/run-make/no-duplicate-libs/foo.rs
deleted file mode 100644 (file)
index 214fb15..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014 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.
-
-#![feature(lang_items, alloc_system, compiler_builtins_lib)]
-#![no_std]
-#![crate_type = "dylib"]
-
-extern crate alloc_system;
-extern crate compiler_builtins;
-
-#[no_mangle]
-pub extern fn foo() {}
-
-#[lang = "eh_personality"] fn eh_personality() {}
-#[lang = "eh_unwind_resume"] fn eh_unwind_resume() {}
-#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
-#[no_mangle] pub extern fn rust_eh_register_frames () {}
-#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
index 12ddce345820bba9f647d423421604a6f9c4752d..824946fe9c2bdcd45179a43f06dd84e311551b27 100644 (file)
@@ -8,9 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#[link(name = "foo")]
-#[link(name = "bar")]
-#[link(name = "foo")]
+#[link(name = "foo")] // linker should drop this library, no symbols used
+#[link(name = "bar")] // symbol comes from this library
+#[link(name = "foo")] // now linker picks up `foo` b/c `bar` library needs it
 extern {
     fn bar();
 }
index 7cc547dcc04e25860c3e495fb88b64a50aa3d469..712fa2d6001774b23ddb64226629f413f4682443 100644 (file)
@@ -8,20 +8,17 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(alloc, allocator_api, heap_api, unique)]
+#![feature(allocator_api, unique)]
 
-extern crate alloc;
-
-use alloc::heap::HeapAlloc;
-use alloc::allocator::Alloc;
+use std::heap::{Heap, Alloc};
 
 fn main() {
     unsafe {
-        let ptr = HeapAlloc.alloc_one::<i32>().unwrap_or_else(|e| {
-            HeapAlloc.oom(e)
+        let ptr = Heap.alloc_one::<i32>().unwrap_or_else(|e| {
+            Heap.oom(e)
         });
         *ptr.as_ptr() = 4;
         assert_eq!(*ptr.as_ptr(), 4);
-        HeapAlloc.dealloc_one(ptr);
+        Heap.dealloc_one(ptr);
     }
 }
diff --git a/src/test/run-pass/allocator-default.rs b/src/test/run-pass/allocator-default.rs
deleted file mode 100644 (file)
index 0a02e80..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2015 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.
-
-#![feature(alloc_jemalloc)]
-
-#[cfg(any(all(target_os = "linux", any(target_arch = "x86", target_arch = "x86_64")),
-          target_os = "macos"))]
-extern crate alloc_jemalloc;
-
-fn main() {
-    println!("{:?}", Box::new(3));
-}
diff --git a/src/test/run-pass/allocator-override.rs b/src/test/run-pass/allocator-override.rs
deleted file mode 100644 (file)
index ca2dbdf..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2015 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.
-
-// no-prefer-dynamic
-// aux-build:allocator-dummy.rs
-// ignore-emscripten
-
-#![feature(test)]
-
-extern crate allocator_dummy;
-extern crate test;
-
-fn main() {
-    unsafe {
-        let before = allocator_dummy::HITS;
-        let mut b = Box::new(3);
-        test::black_box(&mut b); // Make sure the allocation is not optimized away
-        assert_eq!(allocator_dummy::HITS - before, 1);
-        drop(b);
-        assert_eq!(allocator_dummy::HITS - before, 2);
-    }
-}
diff --git a/src/test/run-pass/allocator-system.rs b/src/test/run-pass/allocator-system.rs
deleted file mode 100644 (file)
index 4585003..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2015 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.
-
-// no-prefer-dynamic
-
-#![feature(alloc_system)]
-
-extern crate alloc_system;
-
-fn main() {
-    println!("{:?}", Box::new(3));
-}
diff --git a/src/test/run-pass/allocator/auxiliary/custom-as-global.rs b/src/test/run-pass/allocator/auxiliary/custom-as-global.rs
new file mode 100644 (file)
index 0000000..538f36f
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2017 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.
+
+// no-prefer-dynamic
+
+#![feature(global_allocator)]
+#![crate_type = "rlib"]
+
+extern crate custom;
+
+use std::sync::atomic::{ATOMIC_USIZE_INIT, Ordering};
+
+use custom::A;
+
+#[global_allocator]
+static ALLOCATOR: A = A(ATOMIC_USIZE_INIT);
+
+pub fn get() -> usize {
+    ALLOCATOR.0.load(Ordering::SeqCst)
+}
diff --git a/src/test/run-pass/allocator/auxiliary/custom.rs b/src/test/run-pass/allocator/auxiliary/custom.rs
new file mode 100644 (file)
index 0000000..8f4fbcd
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2017 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.
+
+// no-prefer-dynamic
+
+#![feature(heap_api, allocator_api)]
+#![crate_type = "rlib"]
+
+use std::heap::{Alloc, System, AllocErr, Layout};
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+pub struct A(pub AtomicUsize);
+
+unsafe impl<'a> Alloc for &'a A {
+    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+        self.0.fetch_add(1, Ordering::SeqCst);
+        System.alloc(layout)
+    }
+
+    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
+        self.0.fetch_add(1, Ordering::SeqCst);
+        System.dealloc(ptr, layout)
+    }
+}
diff --git a/src/test/run-pass/allocator/auxiliary/helper.rs b/src/test/run-pass/allocator/auxiliary/helper.rs
new file mode 100644 (file)
index 0000000..e75a432
--- /dev/null
@@ -0,0 +1,19 @@
+// Copyright 2017 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.
+
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+use std::fmt;
+
+pub fn work_with(p: &fmt::Debug) {
+    drop(p);
+}
diff --git a/src/test/run-pass/allocator/custom.rs b/src/test/run-pass/allocator/custom.rs
new file mode 100644 (file)
index 0000000..b46f024
--- /dev/null
@@ -0,0 +1,68 @@
+// Copyright 2017 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.
+
+// aux-build:helper.rs
+// no-prefer-dynamic
+
+#![feature(global_allocator, heap_api, allocator_api)]
+
+extern crate helper;
+
+use std::env;
+use std::heap::{Heap, Alloc, System, Layout, AllocErr};
+use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
+
+static HITS: AtomicUsize = ATOMIC_USIZE_INIT;
+
+struct A;
+
+unsafe impl<'a> Alloc for &'a A {
+    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
+        HITS.fetch_add(1, Ordering::SeqCst);
+        System.alloc(layout)
+    }
+
+    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
+        HITS.fetch_add(1, Ordering::SeqCst);
+        System.dealloc(ptr, layout)
+    }
+}
+
+#[global_allocator]
+static GLOBAL: A = A;
+
+fn main() {
+    env::set_var("FOO", "bar");
+    drop(env::var("FOO"));
+
+    let n = HITS.load(Ordering::SeqCst);
+    assert!(n > 0);
+    unsafe {
+        let layout = Layout::from_size_align(4, 2).unwrap();
+
+        let ptr = Heap.alloc(layout.clone()).unwrap();
+        helper::work_with(&ptr);
+        assert_eq!(HITS.load(Ordering::SeqCst), n + 1);
+        Heap.dealloc(ptr, layout.clone());
+        assert_eq!(HITS.load(Ordering::SeqCst), n + 2);
+
+        let s = String::with_capacity(10);
+        helper::work_with(&s);
+        assert_eq!(HITS.load(Ordering::SeqCst), n + 3);
+        drop(s);
+        assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
+
+        let ptr = System.alloc(layout.clone()).unwrap();
+        assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
+        helper::work_with(&ptr);
+        System.dealloc(ptr, layout);
+        assert_eq!(HITS.load(Ordering::SeqCst), n + 4);
+    }
+}
diff --git a/src/test/run-pass/allocator/xcrate-use.rs b/src/test/run-pass/allocator/xcrate-use.rs
new file mode 100644 (file)
index 0000000..4b987b9
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2017 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.
+
+// aux-build:custom.rs
+// aux-build:helper.rs
+// no-prefer-dynamic
+
+#![feature(global_allocator, heap_api, allocator_api)]
+
+extern crate custom;
+extern crate helper;
+
+use std::env;
+use std::heap::{Heap, Alloc, System, Layout};
+use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT};
+
+#[global_allocator]
+static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT);
+
+fn main() {
+    unsafe {
+        let n = GLOBAL.0.load(Ordering::SeqCst);
+        let layout = Layout::from_size_align(4, 2).unwrap();
+
+        let ptr = Heap.alloc(layout.clone()).unwrap();
+        helper::work_with(&ptr);
+        assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1);
+        Heap.dealloc(ptr, layout.clone());
+        assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
+
+        let ptr = System.alloc(layout.clone()).unwrap();
+        assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
+        helper::work_with(&ptr);
+        System.dealloc(ptr, layout);
+        assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2);
+    }
+}
diff --git a/src/test/run-pass/allocator/xcrate-use2.rs b/src/test/run-pass/allocator/xcrate-use2.rs
new file mode 100644 (file)
index 0000000..7e6cd9f
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2017 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.
+
+// aux-build:custom.rs
+// aux-build:custom-as-global.rs
+// aux-build:helper.rs
+// no-prefer-dynamic
+
+#![feature(heap_api, allocator_api)]
+
+extern crate custom;
+extern crate custom_as_global;
+extern crate helper;
+
+use std::env;
+use std::heap::{Heap, Alloc, System, Layout};
+use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT};
+
+static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT);
+
+fn main() {
+    unsafe {
+        let n = custom_as_global::get();
+        let layout = Layout::from_size_align(4, 2).unwrap();
+
+        // Global allocator routes to the `custom_as_global` global
+        let ptr = Heap.alloc(layout.clone()).unwrap();
+        helper::work_with(&ptr);
+        assert_eq!(custom_as_global::get(), n + 1);
+        Heap.dealloc(ptr, layout.clone());
+        assert_eq!(custom_as_global::get(), n + 2);
+
+        // Usage of the system allocator avoids all globals
+        let ptr = System.alloc(layout.clone()).unwrap();
+        helper::work_with(&ptr);
+        assert_eq!(custom_as_global::get(), n + 2);
+        System.dealloc(ptr, layout.clone());
+        assert_eq!(custom_as_global::get(), n + 2);
+
+        // Usage of our personal allocator doesn't affect other instances
+        let ptr = (&GLOBAL).alloc(layout.clone()).unwrap();
+        helper::work_with(&ptr);
+        assert_eq!(custom_as_global::get(), n + 2);
+        assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 1);
+        (&GLOBAL).dealloc(ptr, layout);
+        assert_eq!(custom_as_global::get(), n + 2);
+        assert_eq!(GLOBAL.0.load(Ordering::SeqCst), 2);
+    }
+}
+
index a38080f8cfe75f6de210ae8ffadc0c1c9f793c35..6e5dccae0a07deb1dcd4614aa817628d7ec05eaf 100644 (file)
@@ -8,16 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// aux-build:clibrary.rs
-// compile-flags: -lclibrary
+// compile-flags: -lrust_test_helpers
 
-#[link(name = "clibrary", kind = "static")]
+#[link(name = "rust_test_helpers", kind = "static")]
 extern "C" {
-    pub fn foo(x:i32) -> i32;
+    pub fn rust_dbg_extern_identity_u32(x: u32) -> u32;
 }
 
 fn main() {
     unsafe {
-        foo(42);
+        rust_dbg_extern_identity_u32(42);
     }
 }
index b32d42df6b1297ed4f556b6121f619b3cc6d6b35..eddcd5a584a5d3d7cdb805d3afd1a24d7cc6b155 100644 (file)
 // Ideally this would be revised to use no_std, but for now it serves
 // well enough to reproduce (and illustrate) the bug from #16687.
 
-#![feature(heap_api, alloc, oom)]
+#![feature(heap_api, allocator_api)]
 
-extern crate alloc;
-
-use alloc::heap;
+use std::heap::{Heap, Alloc, Layout};
 use std::ptr;
 
 fn main() {
@@ -47,38 +45,39 @@ unsafe fn sanity_check(ascend: &[*mut u8]) {
 
     static PRINT : bool = false;
 
-    unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
-        if PRINT { println!("allocate(size={} align={})", size, align); }
+    unsafe fn allocate(layout: Layout) -> *mut u8 {
+        if PRINT {
+            println!("allocate({:?})", layout);
+        }
 
-        let ret = heap::allocate(size, align);
-        if ret.is_null() { alloc::oom() }
+        let ret = Heap.alloc(layout.clone()).unwrap_or_else(|e| Heap.oom(e));
 
-        if PRINT { println!("allocate(size={} align={}) ret: 0x{:010x}",
-                            size, align, ret as usize);
+        if PRINT {
+            println!("allocate({:?}) = {:?}", layout, ret);
         }
 
         ret
     }
-    unsafe fn deallocate(ptr: *mut u8, size: usize, align: usize) {
-        if PRINT { println!("deallocate(ptr=0x{:010x} size={} align={})",
-                            ptr as usize, size, align);
+
+    unsafe fn deallocate(ptr: *mut u8, layout: Layout) {
+        if PRINT {
+            println!("deallocate({:?}, {:?}", ptr, layout);
         }
 
-        heap::deallocate(ptr, size, align);
+        Heap.dealloc(ptr, layout);
     }
-    unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
+
+    unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 {
         if PRINT {
-            println!("reallocate(ptr=0x{:010x} old_size={} size={} align={})",
-                     ptr as usize, old_size, size, align);
+            println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new);
         }
 
-        let ret = heap::reallocate(ptr, old_size, size, align);
-        if ret.is_null() { alloc::oom() }
+        let ret = Heap.realloc(ptr, old.clone(), new.clone())
+            .unwrap_or_else(|e| Heap.oom(e));
 
         if PRINT {
-            println!("reallocate(ptr=0x{:010x} old_size={} size={} align={}) \
-                      ret: 0x{:010x}",
-                     ptr as usize, old_size, size, align, ret as usize);
+            println!("reallocate({:?}, old={:?}, new={:?}) = {:?}",
+                     ptr, old, new, ret);
         }
         ret
     }
@@ -91,8 +90,8 @@ fn idx_to_size(i: usize) -> usize { (i+1) * 10 }
     // way.)
     for i in 0..COUNT / 2 {
         let size = idx_to_size(i);
-        ascend[2*i]   = allocate(size, ALIGN);
-        ascend[2*i+1] = allocate(size, ALIGN);
+        ascend[2*i]   = allocate(Layout::from_size_align(size, ALIGN).unwrap());
+        ascend[2*i+1] = allocate(Layout::from_size_align(size, ALIGN).unwrap());
     }
 
     // Initialize each pair of rows to distinct value.
@@ -112,8 +111,8 @@ fn idx_to_size(i: usize) -> usize { (i+1) * 10 }
 
     for i in 0..COUNT / 2 {
         let size = idx_to_size(i);
-        deallocate(ascend[2*i], size, ALIGN);
-        deallocate(ascend[2*i+1], size, ALIGN);
+        deallocate(ascend[2*i], Layout::from_size_align(size, ALIGN).unwrap());
+        deallocate(ascend[2*i+1], Layout::from_size_align(size, ALIGN).unwrap());
     }
 
     return true;
@@ -124,14 +123,16 @@ fn idx_to_size(i: usize) -> usize { (i+1) * 10 }
     // rows as we go.
     unsafe fn test_1(ascend: &mut [*mut u8]) {
         let new_size = idx_to_size(COUNT-1);
+        let new = Layout::from_size_align(new_size, ALIGN).unwrap();
         for i in 0..COUNT / 2 {
             let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
             assert!(old_size < new_size);
+            let old = Layout::from_size_align(old_size, ALIGN).unwrap();
 
-            ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN);
+            ascend[2*i] = reallocate(p0, old.clone(), new.clone());
             sanity_check(&*ascend);
 
-            ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN);
+            ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
             sanity_check(&*ascend);
         }
     }
@@ -139,14 +140,16 @@ unsafe fn test_1(ascend: &mut [*mut u8]) {
     // Test 2: turn the square back into a triangle, top to bottom.
     unsafe fn test_2(ascend: &mut [*mut u8]) {
         let old_size = idx_to_size(COUNT-1);
+        let old = Layout::from_size_align(old_size, ALIGN).unwrap();
         for i in 0..COUNT / 2 {
             let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
             assert!(new_size < old_size);
+            let new = Layout::from_size_align(new_size, ALIGN).unwrap();
 
-            ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN);
+            ascend[2*i] = reallocate(p0, old.clone(), new.clone());
             sanity_check(&*ascend);
 
-            ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN);
+            ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
             sanity_check(&*ascend);
         }
     }
@@ -154,14 +157,16 @@ unsafe fn test_2(ascend: &mut [*mut u8]) {
     // Test 3: turn triangle into a square, bottom to top.
     unsafe fn test_3(ascend: &mut [*mut u8]) {
         let new_size = idx_to_size(COUNT-1);
+        let new = Layout::from_size_align(new_size, ALIGN).unwrap();
         for i in (0..COUNT / 2).rev() {
             let (p0, p1, old_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
             assert!(old_size < new_size);
+            let old = Layout::from_size_align(old_size, ALIGN).unwrap();
 
-            ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN);
+            ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
             sanity_check(&*ascend);
 
-            ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN);
+            ascend[2*i] = reallocate(p0, old.clone(), new.clone());
             sanity_check(&*ascend);
         }
     }
@@ -169,14 +174,16 @@ unsafe fn test_3(ascend: &mut [*mut u8]) {
     // Test 4: turn the square back into a triangle, bottom to top.
     unsafe fn test_4(ascend: &mut [*mut u8]) {
         let old_size = idx_to_size(COUNT-1);
+        let old = Layout::from_size_align(old_size, ALIGN).unwrap();
         for i in (0..COUNT / 2).rev() {
             let (p0, p1, new_size) = (ascend[2*i], ascend[2*i+1], idx_to_size(i));
             assert!(new_size < old_size);
+            let new = Layout::from_size_align(new_size, ALIGN).unwrap();
 
-            ascend[2*i+1] = reallocate(p1, old_size, new_size, ALIGN);
+            ascend[2*i+1] = reallocate(p1, old.clone(), new.clone());
             sanity_check(&*ascend);
 
-            ascend[2*i] = reallocate(p0, old_size, new_size, ALIGN);
+            ascend[2*i] = reallocate(p0, old.clone(), new.clone());
             sanity_check(&*ascend);
         }
     }
index d6ef96c5add0134939bfe01ab2ce1f5e7c7020c8..26713a25543772034b15262a2cd83fe5538f2772 100644 (file)
@@ -8,16 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// aux-build:clibrary.rs
-// compile-flags: -lstatic=wronglibrary:clibrary
+// compile-flags: -lstatic=wronglibrary:rust_test_helpers
 
 #[link(name = "wronglibrary", kind = "dylib")]
 extern "C" {
-    pub fn foo(x:i32) -> i32;
+    pub fn rust_dbg_extern_identity_u32(x: u32) -> u32;
 }
 
 fn main() {
     unsafe {
-        foo(42);
+        rust_dbg_extern_identity_u32(42);
     }
 }
index 053ee8ee42ed60a57c434d812ac1396b3b40a033..bcbd3fd3786ab4555da1b24961e880db5728d7b6 100644 (file)
 
 // Smallest "hello world" with a libc runtime
 
-// pretty-expanded FIXME #23616
 // ignore-windows
+// ignore-android
 
 #![feature(intrinsics, lang_items, start, no_core, alloc_system)]
-#![no_core]
+#![feature(global_allocator, allocator_api)]
+#![no_std]
 
 extern crate alloc_system;
 
-extern { fn puts(s: *const u8); }
-extern "rust-intrinsic" { fn transmute<T, U>(t: T) -> U; }
+use alloc_system::System;
 
-#[lang = "eh_personality"] extern fn eh_personality() {}
-#[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {}
+#[global_allocator]
+static A: System = System;
+
+extern {
+    fn puts(s: *const u8);
+}
+
+#[no_mangle]
+#[lang = "eh_personality"] pub extern fn rust_eh_personality() {}
 #[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
-#[no_mangle] pub extern fn rust_eh_register_frames () {}
-#[no_mangle] pub extern fn rust_eh_unregister_frames () {}
 
 #[start]
 fn main(_: isize, _: *const *const u8) -> isize {
     unsafe {
-        let (ptr, _): (*const u8, usize) = transmute("Hello!\0");
-        puts(ptr);
+        puts("Hello!\0".as_ptr() as *const u8);
     }
-    return 0;
+    return 0
 }
-
-#[cfg(target_os = "android")]
-#[link(name="gcc")]
-extern { }