about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-06-12 00:36:21 +0000
committerbors <bors@rust-lang.org>2018-06-12 00:36:21 +0000
commit4367e41ea2a105c373de27c2f080fc2527cc6927 (patch)
tree9ca30ec2dbf3311f0a0d0d6275d5abca8f23fc1f /src
parentf9944fde377b8b2575f96fff60f784eddce54002 (diff)
parent7f0d54d98842c786ab7a140c17c3ea32aea6aead (diff)
downloadrust-4367e41ea2a105c373de27c2f080fc2527cc6927.tar.gz
rust-4367e41ea2a105c373de27c2f080fc2527cc6927.zip
Auto merge of #51241 - glandium:globalalloc, r=sfackler,SimonSapin
Stabilize GlobalAlloc and #[global_allocator]

This PR implements the changes discussed in https://github.com/rust-lang/rust/issues/49668#issuecomment-393263510

Fixes #49668
Fixes #27389

This does not change the default global allocator: #36963
Diffstat (limited to 'src')
-rw-r--r--src/doc/unstable-book/src/language-features/global-allocator.md72
-rw-r--r--src/doc/unstable-book/src/library-features/alloc-jemalloc.md13
-rw-r--r--src/doc/unstable-book/src/library-features/alloc-system.md77
-rw-r--r--src/liballoc/alloc.rs150
-rw-r--r--src/liballoc/arc.rs6
-rw-r--r--src/liballoc/btree/node.rs10
-rw-r--r--src/liballoc/heap.rs110
-rw-r--r--src/liballoc/lib.rs8
-rw-r--r--src/liballoc/raw_vec.rs23
-rw-r--r--src/liballoc/rc.rs10
-rw-r--r--src/liballoc_jemalloc/lib.rs5
-rw-r--r--src/liballoc_system/lib.rs122
-rw-r--r--src/libcore/alloc.rs345
-rw-r--r--src/libcore/lib.rs7
-rw-r--r--src/libcore/ptr.rs8
-rw-r--r--src/librustc_allocator/expand.rs15
-rw-r--r--src/librustc_asan/lib.rs3
-rw-r--r--src/librustc_lsan/lib.rs5
-rw-r--r--src/librustc_msan/lib.rs5
-rw-r--r--src/librustc_tsan/lib.rs3
-rw-r--r--src/libstd/alloc.rs93
-rw-r--r--src/libstd/collections/hash/table.rs2
-rw-r--r--src/libstd/collections/mod.rs2
-rw-r--r--src/libstd/error.rs2
-rw-r--r--src/libstd/lib.rs8
-rw-r--r--src/libsyntax/feature_gate.rs10
-rw-r--r--src/test/compile-fail/allocator/auxiliary/system-allocator.rs1
-rw-r--r--src/test/compile-fail/allocator/auxiliary/system-allocator2.rs1
-rw-r--r--src/test/compile-fail/allocator/function-allocator.rs1
-rw-r--r--src/test/compile-fail/allocator/not-an-allocator.rs2
-rw-r--r--src/test/compile-fail/allocator/two-allocators.rs2
-rw-r--r--src/test/compile-fail/allocator/two-allocators2.rs2
-rw-r--r--src/test/compile-fail/allocator/two-allocators3.rs1
-rw-r--r--src/test/compile-fail/lint-stability-fields.rs7
-rw-r--r--src/test/run-make-fulldeps/std-core-cycle/bar.rs4
-rw-r--r--src/test/run-make-fulldeps/std-core-cycle/foo.rs1
-rw-r--r--src/test/run-pass-valgrind/issue-44800.rs5
-rw-r--r--src/test/run-pass/allocator/auxiliary/custom-as-global.rs1
-rw-r--r--src/test/run-pass/allocator/auxiliary/custom.rs6
-rw-r--r--src/test/run-pass/allocator/custom.rs8
-rw-r--r--src/test/run-pass/allocator/xcrate-use.rs2
-rw-r--r--src/test/run-pass/allocator/xcrate-use2.rs6
-rw-r--r--src/test/run-pass/realloc-16687.rs4
-rw-r--r--src/test/run-pass/thin-lto-global-allocator.rs2
-rw-r--r--src/test/ui/feature-gate-global_allocator.rs14
-rw-r--r--src/test/ui/feature-gate-global_allocator.stderr11
46 files changed, 566 insertions, 629 deletions
diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md
deleted file mode 100644
index 8f1ba22de8c..00000000000
--- a/src/doc/unstable-book/src/language-features/global-allocator.md
+++ /dev/null
@@ -1,72 +0,0 @@
-# `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, allocator_api, heap_api)]
-
-use std::alloc::{GlobalAlloc, System, Layout, Opaque};
-use std::ptr::NonNull;
-
-struct MyAllocator;
-
-unsafe impl GlobalAlloc for MyAllocator {
-    unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
-        System.alloc(layout)
-    }
-
-    unsafe fn dealloc(&self, ptr: *mut Opaque, 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::alloc` 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.
diff --git a/src/doc/unstable-book/src/library-features/alloc-jemalloc.md b/src/doc/unstable-book/src/library-features/alloc-jemalloc.md
deleted file mode 100644
index 425d4cb79b2..00000000000
--- a/src/doc/unstable-book/src/library-features/alloc-jemalloc.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# `alloc_jemalloc`
-
-The tracking issue for this feature is: [#33082]
-
-[#33082]: https://github.com/rust-lang/rust/issues/33082
-
-See also [`alloc_system`](library-features/alloc-system.html).
-
-------------------------
-
-This feature has been replaced by [the `jemallocator` crate on crates.io.][jemallocator].
-
-[jemallocator]: https://crates.io/crates/jemallocator
diff --git a/src/doc/unstable-book/src/library-features/alloc-system.md b/src/doc/unstable-book/src/library-features/alloc-system.md
deleted file mode 100644
index 9effab202ca..00000000000
--- a/src/doc/unstable-book/src/library-features/alloc-system.md
+++ /dev/null
@@ -1,77 +0,0 @@
-# `alloc_system`
-
-The tracking issue for this feature is: [#32838]
-
-[#32838]: https://github.com/rust-lang/rust/issues/32838
-
-See also [`global_allocator`](language-features/global-allocator.html).
-
-------------------------
-
-The compiler currently ships two default allocators: `alloc_system` and
-`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators
-are normal Rust crates and contain an implementation of the routines to
-allocate and deallocate memory. The standard library is not compiled assuming
-either one, and the compiler will decide which allocator is in use at
-compile-time depending on the type of output artifact being produced.
-
-Binaries generated by the compiler will use `alloc_jemalloc` by default (where
-available). In this situation the compiler "controls the world" in the sense of
-it has power over the final link. Primarily this means that the allocator
-decision can be left up the compiler.
-
-Dynamic and static libraries, however, will use `alloc_system` by default. Here
-Rust is typically a 'guest' in another application or another world where it
-cannot authoritatively decide what allocator is in use. As a result it resorts
-back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing
-memory.
-
-# Switching Allocators
-
-Although the compiler's default choices may work most of the time, it's often
-necessary to tweak certain aspects. Overriding the compiler's decision about
-which allocator is in use is done through the `#[global_allocator]` attribute:
-
-```rust,no_run
-#![feature(alloc_system, global_allocator, allocator_api)]
-
-extern crate alloc_system;
-
-use alloc_system::System;
-
-#[global_allocator]
-static A: System = System;
-
-fn main() {
-    let a = Box::new(4); // Allocates from the system allocator.
-    println!("{}", a);
-}
-```
-
-In this example the binary generated will not link to jemalloc by default but
-instead use the system allocator. Conversely to generate a dynamic library which
-uses jemalloc by default one would write:
-
-(The `alloc_jemalloc` crate cannot be used to control the global allocator,
-crate.io’s `jemallocator` crate provides equivalent functionality.)
-
-```toml
-# Cargo.toml
-[dependencies]
-jemallocator = "0.1"
-```
-```rust,ignore
-#![feature(global_allocator)]
-#![crate_type = "dylib"]
-
-extern crate jemallocator;
-
-#[global_allocator]
-static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
-
-pub fn foo() {
-    let a = Box::new(4); // Allocates from jemalloc.
-    println!("{}", a);
-}
-# fn main() {}
-```
diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs
index 8753c495737..04c8063ffeb 100644
--- a/src/liballoc/alloc.rs
+++ b/src/liballoc/alloc.rs
@@ -8,17 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![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 = "32838")]
+//! Memory allocation APIs
+
+#![stable(feature = "alloc_module", since = "1.28.0")]
 
 use core::intrinsics::{min_align_of_val, size_of_val};
 use core::ptr::{NonNull, Unique};
 use core::usize;
 
+#[stable(feature = "alloc_module", since = "1.28.0")]
 #[doc(inline)]
 pub use core::alloc::*;
 
@@ -37,67 +35,112 @@ extern "Rust" {
     fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
 }
 
+/// The global memory allocator.
+///
+/// This type implements the [`Alloc`] trait by forwarding calls
+/// to the allocator registered with the `#[global_allocator]` attribute
+/// if there is one, or the `std` crate’s default.
+#[unstable(feature = "allocator_api", issue = "32838")]
 #[derive(Copy, Clone, Default, Debug)]
 pub struct Global;
 
-#[unstable(feature = "allocator_api", issue = "32838")]
-#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")]
-pub type Heap = Global;
-
-#[unstable(feature = "allocator_api", issue = "32838")]
-#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")]
-#[allow(non_upper_case_globals)]
-pub const Heap: Global = Global;
-
-unsafe impl GlobalAlloc for Global {
-    #[inline]
-    unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
-        let ptr = __rust_alloc(layout.size(), layout.align());
-        ptr as *mut Opaque
-    }
+/// Allocate memory with the global allocator.
+///
+/// This function forwards calls to the [`GlobalAlloc::alloc`] method
+/// of the allocator registered with the `#[global_allocator]` attribute
+/// if there is one, or the `std` crate’s default.
+///
+/// This function is expected to be deprecated in favor of the `alloc` method
+/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
+///
+/// # Safety
+///
+/// See [`GlobalAlloc::alloc`].
+#[stable(feature = "global_alloc", since = "1.28.0")]
+#[inline]
+pub unsafe fn alloc(layout: Layout) -> *mut u8 {
+    __rust_alloc(layout.size(), layout.align())
+}
 
-    #[inline]
-    unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
-        __rust_dealloc(ptr as *mut u8, layout.size(), layout.align())
-    }
+/// Deallocate memory with the global allocator.
+///
+/// This function forwards calls to the [`GlobalAlloc::dealloc`] method
+/// of the allocator registered with the `#[global_allocator]` attribute
+/// if there is one, or the `std` crate’s default.
+///
+/// This function is expected to be deprecated in favor of the `dealloc` method
+/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
+///
+/// # Safety
+///
+/// See [`GlobalAlloc::dealloc`].
+#[stable(feature = "global_alloc", since = "1.28.0")]
+#[inline]
+pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
+    __rust_dealloc(ptr, layout.size(), layout.align())
+}
 
-    #[inline]
-    unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
-        let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size);
-        ptr as *mut Opaque
-    }
+/// Reallocate memory with the global allocator.
+///
+/// This function forwards calls to the [`GlobalAlloc::realloc`] method
+/// of the allocator registered with the `#[global_allocator]` attribute
+/// if there is one, or the `std` crate’s default.
+///
+/// This function is expected to be deprecated in favor of the `realloc` method
+/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
+///
+/// # Safety
+///
+/// See [`GlobalAlloc::realloc`].
+#[stable(feature = "global_alloc", since = "1.28.0")]
+#[inline]
+pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+    __rust_realloc(ptr, layout.size(), layout.align(), new_size)
+}
 
-    #[inline]
-    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
-        let ptr = __rust_alloc_zeroed(layout.size(), layout.align());
-        ptr as *mut Opaque
-    }
+/// Allocate zero-initialized memory with the global allocator.
+///
+/// This function forwards calls to the [`GlobalAlloc::alloc_zeroed`] method
+/// of the allocator registered with the `#[global_allocator]` attribute
+/// if there is one, or the `std` crate’s default.
+///
+/// This function is expected to be deprecated in favor of the `alloc_zeroed` method
+/// of the [`Global`] type when it and the [`Alloc`] trait become stable.
+///
+/// # Safety
+///
+/// See [`GlobalAlloc::alloc_zeroed`].
+#[stable(feature = "global_alloc", since = "1.28.0")]
+#[inline]
+pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
+    __rust_alloc_zeroed(layout.size(), layout.align())
 }
 
+#[unstable(feature = "allocator_api", issue = "32838")]
 unsafe impl Alloc for Global {
     #[inline]
-    unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
-        NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
+    unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
+        NonNull::new(alloc(layout)).ok_or(AllocErr)
     }
 
     #[inline]
-    unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) {
-        GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
+    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
+        dealloc(ptr.as_ptr(), layout)
     }
 
     #[inline]
     unsafe fn realloc(&mut self,
-                      ptr: NonNull<Opaque>,
+                      ptr: NonNull<u8>,
                       layout: Layout,
                       new_size: usize)
-                      -> Result<NonNull<Opaque>, AllocErr>
+                      -> Result<NonNull<u8>, AllocErr>
     {
-        NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
+        NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
     }
 
     #[inline]
-    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
-        NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
+    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
+        NonNull::new(alloc_zeroed(layout)).ok_or(AllocErr)
     }
 }
 
@@ -111,9 +154,9 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
         align as *mut u8
     } else {
         let layout = Layout::from_size_align_unchecked(size, align);
-        let ptr = Global.alloc(layout);
+        let ptr = alloc(layout);
         if !ptr.is_null() {
-            ptr as *mut u8
+            ptr
         } else {
             oom(layout)
         }
@@ -129,10 +172,23 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
     // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
     if size != 0 {
         let layout = Layout::from_size_align_unchecked(size, align);
-        Global.dealloc(ptr as *mut Opaque, layout);
+        dealloc(ptr as *mut u8, layout);
     }
 }
 
+/// Abort on memory allocation error or failure.
+///
+/// Callers of memory allocation APIs wishing to abort computation
+/// in response to an allocation error are encouraged to call this function,
+/// rather than directly invoking `panic!` or similar.
+///
+/// The default behavior of this function is to print a message to standard error
+/// and abort the process.
+/// It can be replaced with [`set_oom_hook`] and [`take_oom_hook`].
+///
+/// [`set_oom_hook`]: ../../std/alloc/fn.set_oom_hook.html
+/// [`take_oom_hook`]: ../../std/alloc/fn.take_oom_hook.html
+#[stable(feature = "global_alloc", since = "1.28.0")]
 #[rustc_allocator_nounwind]
 pub fn oom(layout: Layout) -> ! {
     #[allow(improper_ctypes)]
diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs
index 4026b3ababa..e3369f0a5b5 100644
--- a/src/liballoc/arc.rs
+++ b/src/liballoc/arc.rs
@@ -519,7 +519,7 @@ impl<T: ?Sized> Arc<T> {
 
         if self.inner().weak.fetch_sub(1, Release) == 1 {
             atomic::fence(Acquire);
-            Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref()))
+            Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()))
         }
     }
 
@@ -639,7 +639,7 @@ impl<T: Clone> ArcFromSlice<T> for Arc<[T]> {
                     let slice = from_raw_parts_mut(self.elems, self.n_elems);
                     ptr::drop_in_place(slice);
 
-                    Global.dealloc(self.mem.as_opaque(), self.layout.clone());
+                    Global.dealloc(self.mem.cast(), self.layout.clone());
                 }
             }
         }
@@ -1196,7 +1196,7 @@ impl<T: ?Sized> Drop for Weak<T> {
         if self.inner().weak.fetch_sub(1, Release) == 1 {
             atomic::fence(Acquire);
             unsafe {
-                Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref()))
+                Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()))
             }
         }
     }
diff --git a/src/liballoc/btree/node.rs b/src/liballoc/btree/node.rs
index 431695c32ab..19bdcbc6ad6 100644
--- a/src/liballoc/btree/node.rs
+++ b/src/liballoc/btree/node.rs
@@ -287,7 +287,7 @@ impl<K, V> Root<K, V> {
         self.as_mut().as_leaf_mut().parent = ptr::null();
 
         unsafe {
-            Global.dealloc(NonNull::from(top).as_opaque(), Layout::new::<InternalNode<K, V>>());
+            Global.dealloc(NonNull::from(top).cast(), Layout::new::<InternalNode<K, V>>());
         }
     }
 }
@@ -478,7 +478,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Leaf> {
         debug_assert!(!self.is_shared_root());
         let node = self.node;
         let ret = self.ascend().ok();
-        Global.dealloc(node.as_opaque(), Layout::new::<LeafNode<K, V>>());
+        Global.dealloc(node.cast(), Layout::new::<LeafNode<K, V>>());
         ret
     }
 }
@@ -499,7 +499,7 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::Internal> {
     > {
         let node = self.node;
         let ret = self.ascend().ok();
-        Global.dealloc(node.as_opaque(), Layout::new::<InternalNode<K, V>>());
+        Global.dealloc(node.cast(), Layout::new::<InternalNode<K, V>>());
         ret
     }
 }
@@ -1321,12 +1321,12 @@ impl<'a, K, V> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::
                 }
 
                 Global.dealloc(
-                    right_node.node.as_opaque(),
+                    right_node.node.cast(),
                     Layout::new::<InternalNode<K, V>>(),
                 );
             } else {
                 Global.dealloc(
-                    right_node.node.as_opaque(),
+                    right_node.node.cast(),
                     Layout::new::<LeafNode<K, V>>(),
                 );
             }
diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs
deleted file mode 100644
index 16f0630b911..00000000000
--- a/src/liballoc/heap.rs
+++ /dev/null
@@ -1,110 +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.
-
-#![allow(deprecated)]
-
-pub use alloc::{Layout, AllocErr, CannotReallocInPlace, Opaque};
-use core::alloc::Alloc as CoreAlloc;
-use core::ptr::NonNull;
-
-#[doc(hidden)]
-pub mod __core {
-    pub use core::*;
-}
-
-#[derive(Debug)]
-pub struct Excess(pub *mut u8, pub usize);
-
-/// Compatibility with older versions of #[global_allocator] during bootstrap
-pub unsafe trait Alloc {
-    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>;
-    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout);
-    fn oom(&mut self, err: AllocErr) -> !;
-    fn usable_size(&self, layout: &Layout) -> (usize, usize);
-    unsafe fn realloc(&mut self,
-                      ptr: *mut u8,
-                      layout: Layout,
-                      new_layout: Layout) -> Result<*mut u8, AllocErr>;
-    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>;
-    unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr>;
-    unsafe fn realloc_excess(&mut self,
-                             ptr: *mut u8,
-                             layout: Layout,
-                             new_layout: Layout) -> Result<Excess, AllocErr>;
-    unsafe fn grow_in_place(&mut self,
-                            ptr: *mut u8,
-                            layout: Layout,
-                            new_layout: Layout) -> Result<(), CannotReallocInPlace>;
-    unsafe fn shrink_in_place(&mut self,
-                              ptr: *mut u8,
-                              layout: Layout,
-                              new_layout: Layout) -> Result<(), CannotReallocInPlace>;
-}
-
-unsafe impl<T> Alloc for T where T: CoreAlloc {
-    unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
-        CoreAlloc::alloc(self, layout).map(|ptr| ptr.cast().as_ptr())
-    }
-
-    unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) {
-        let ptr = NonNull::new_unchecked(ptr as *mut Opaque);
-        CoreAlloc::dealloc(self, ptr, layout)
-    }
-
-    fn oom(&mut self, _: AllocErr) -> ! {
-        unsafe { ::core::intrinsics::abort() }
-    }
-
-    fn usable_size(&self, layout: &Layout) -> (usize, usize) {
-        CoreAlloc::usable_size(self, layout)
-    }
-
-    unsafe fn realloc(&mut self,
-                      ptr: *mut u8,
-                      layout: Layout,
-                      new_layout: Layout) -> Result<*mut u8, AllocErr> {
-        let ptr = NonNull::new_unchecked(ptr as *mut Opaque);
-        CoreAlloc::realloc(self, ptr, layout, new_layout.size()).map(|ptr| ptr.cast().as_ptr())
-    }
-
-    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> {
-        CoreAlloc::alloc_zeroed(self, layout).map(|ptr| ptr.cast().as_ptr())
-    }
-
-    unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
-        CoreAlloc::alloc_excess(self, layout)
-            .map(|e| Excess(e.0 .cast().as_ptr(), e.1))
-    }
-
-    unsafe fn realloc_excess(&mut self,
-                             ptr: *mut u8,
-                             layout: Layout,
-                             new_layout: Layout) -> Result<Excess, AllocErr> {
-        let ptr = NonNull::new_unchecked(ptr as *mut Opaque);
-        CoreAlloc::realloc_excess(self, ptr, layout, new_layout.size())
-            .map(|e| Excess(e.0 .cast().as_ptr(), e.1))
-    }
-
-    unsafe fn grow_in_place(&mut self,
-                            ptr: *mut u8,
-                            layout: Layout,
-                            new_layout: Layout) -> Result<(), CannotReallocInPlace> {
-        let ptr = NonNull::new_unchecked(ptr as *mut Opaque);
-        CoreAlloc::grow_in_place(self, ptr, layout, new_layout.size())
-    }
-
-    unsafe fn shrink_in_place(&mut self,
-                              ptr: *mut u8,
-                              layout: Layout,
-                              new_layout: Layout) -> Result<(), CannotReallocInPlace> {
-        let ptr = NonNull::new_unchecked(ptr as *mut Opaque);
-        CoreAlloc::shrink_in_place(self, ptr, layout, new_layout.size())
-    }
-}
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index a1139189c9a..74bbd659246 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -151,18 +151,10 @@ pub mod allocator {
 
 pub mod alloc;
 
-#[unstable(feature = "allocator_api", issue = "32838")]
-#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
-/// Use the `alloc` module instead.
-pub mod heap {
-    pub use alloc::*;
-}
-
 #[unstable(feature = "futures_api",
            reason = "futures in libcore are unstable",
            issue = "50547")]
 pub mod task;
-
 // Primitive types using the heaps above
 
 // Need to conditionally define the mod from `boxed.rs` to avoid
diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs
index 07bb7f1a3eb..d1f140e96a3 100644
--- a/src/liballoc/raw_vec.rs
+++ b/src/liballoc/raw_vec.rs
@@ -93,7 +93,7 @@ impl<T, A: Alloc> RawVec<T, A> {
 
             // handles ZSTs and `cap = 0` alike
             let ptr = if alloc_size == 0 {
-                NonNull::<T>::dangling().as_opaque()
+                NonNull::<T>::dangling()
             } else {
                 let align = mem::align_of::<T>();
                 let layout = Layout::from_size_align(alloc_size, align).unwrap();
@@ -103,13 +103,13 @@ impl<T, A: Alloc> RawVec<T, A> {
                     a.alloc(layout)
                 };
                 match result {
-                    Ok(ptr) => ptr,
+                    Ok(ptr) => ptr.cast(),
                     Err(_) => oom(layout),
                 }
             };
 
             RawVec {
-                ptr: ptr.cast().into(),
+                ptr: ptr.into(),
                 cap,
                 a,
             }
@@ -314,7 +314,7 @@ impl<T, A: Alloc> RawVec<T, A> {
                     let new_cap = 2 * self.cap;
                     let new_size = new_cap * elem_size;
                     alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow());
-                    let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_opaque(),
+                    let ptr_res = self.a.realloc(NonNull::from(self.ptr).cast(),
                                                  cur,
                                                  new_size);
                     match ptr_res {
@@ -373,7 +373,7 @@ impl<T, A: Alloc> RawVec<T, A> {
             let new_cap = 2 * self.cap;
             let new_size = new_cap * elem_size;
             alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow());
-            match self.a.grow_in_place(NonNull::from(self.ptr).as_opaque(), old_layout, new_size) {
+            match self.a.grow_in_place(NonNull::from(self.ptr).cast(), old_layout, new_size) {
                 Ok(_) => {
                     // We can't directly divide `size`.
                     self.cap = new_cap;
@@ -546,7 +546,7 @@ impl<T, A: Alloc> RawVec<T, A> {
             // FIXME: may crash and burn on over-reserve
             alloc_guard(new_layout.size()).unwrap_or_else(|_| capacity_overflow());
             match self.a.grow_in_place(
-                NonNull::from(self.ptr).as_opaque(), old_layout, new_layout.size(),
+                NonNull::from(self.ptr).cast(), old_layout, new_layout.size(),
             ) {
                 Ok(_) => {
                     self.cap = new_cap;
@@ -607,7 +607,7 @@ impl<T, A: Alloc> RawVec<T, A> {
                 let new_size = elem_size * amount;
                 let align = mem::align_of::<T>();
                 let old_layout = Layout::from_size_align_unchecked(old_size, align);
-                match self.a.realloc(NonNull::from(self.ptr).as_opaque(),
+                match self.a.realloc(NonNull::from(self.ptr).cast(),
                                      old_layout,
                                      new_size) {
                     Ok(p) => self.ptr = p.cast().into(),
@@ -667,7 +667,7 @@ impl<T, A: Alloc> RawVec<T, A> {
             let res = match self.current_layout() {
                 Some(layout) => {
                     debug_assert!(new_layout.align() == layout.align());
-                    self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size())
+                    self.a.realloc(NonNull::from(self.ptr).cast(), layout, new_layout.size())
                 }
                 None => self.a.alloc(new_layout),
             };
@@ -710,7 +710,7 @@ impl<T, A: Alloc> RawVec<T, A> {
         let elem_size = mem::size_of::<T>();
         if elem_size != 0 {
             if let Some(layout) = self.current_layout() {
-                self.a.dealloc(NonNull::from(self.ptr).as_opaque(), layout);
+                self.a.dealloc(NonNull::from(self.ptr).cast(), layout);
             }
         }
     }
@@ -753,7 +753,6 @@ fn capacity_overflow() -> ! {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use alloc::Opaque;
 
     #[test]
     fn allocator_param() {
@@ -773,7 +772,7 @@ mod tests {
         // before allocation attempts start failing.
         struct BoundedAlloc { fuel: usize }
         unsafe impl Alloc for BoundedAlloc {
-            unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
+            unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
                 let size = layout.size();
                 if size > self.fuel {
                     return Err(AllocErr);
@@ -783,7 +782,7 @@ mod tests {
                     err @ Err(_) => err,
                 }
             }
-            unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) {
+            unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
                 Global.dealloc(ptr, layout)
             }
         }
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 553c8b5ca32..84a6ecf7103 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -259,7 +259,7 @@ use core::ops::CoerceUnsized;
 use core::ptr::{self, NonNull};
 use core::convert::From;
 
-use alloc::{Global, Alloc, Layout, Opaque, box_free, oom};
+use alloc::{Global, Alloc, Layout, box_free, oom};
 use string::String;
 use vec::Vec;
 
@@ -732,7 +732,7 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
         // In the event of a panic, elements that have been written
         // into the new RcBox will be dropped, then the memory freed.
         struct Guard<T> {
-            mem: NonNull<Opaque>,
+            mem: NonNull<u8>,
             elems: *mut T,
             layout: Layout,
             n_elems: usize,
@@ -755,7 +755,7 @@ impl<T: Clone> RcFromSlice<T> for Rc<[T]> {
             let v_ptr = v as *const [T];
             let ptr = Self::allocate_for_ptr(v_ptr);
 
-            let mem = ptr as *mut _ as *mut Opaque;
+            let mem = ptr as *mut _ as *mut u8;
             let layout = Layout::for_value(&*ptr);
 
             // Pointer to first element
@@ -839,7 +839,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
                 self.dec_weak();
 
                 if self.weak() == 0 {
-                    Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref()));
+                    Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
                 }
             }
         }
@@ -1263,7 +1263,7 @@ impl<T: ?Sized> Drop for Weak<T> {
             // the weak count starts at 1, and will only go to zero if all
             // the strong pointers have disappeared.
             if self.weak() == 0 {
-                Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref()));
+                Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
             }
         }
     }
diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs
index ce856eccd83..b3b20715511 100644
--- a/src/liballoc_jemalloc/lib.rs
+++ b/src/liballoc_jemalloc/lib.rs
@@ -11,9 +11,8 @@
 #![no_std]
 #![allow(unused_attributes)]
 #![unstable(feature = "alloc_jemalloc",
-            reason = "this library is unlikely to be stabilized in its current \
-                      form or name",
-            issue = "27783")]
+            reason = "implementation detail of std, does not provide any public API",
+            issue = "0")]
 #![feature(core_intrinsics)]
 #![feature(libc)]
 #![feature(linkage)]
diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs
index 9490b54e675..64348e05de7 100644
--- a/src/liballoc_system/lib.rs
+++ b/src/liballoc_system/lib.rs
@@ -14,7 +14,6 @@
             reason = "this library is unlikely to be stabilized in its current \
                       form or name",
             issue = "32838")]
-#![feature(global_allocator)]
 #![feature(allocator_api)]
 #![feature(core_intrinsics)]
 #![feature(staged_api)]
@@ -41,54 +40,78 @@ const MIN_ALIGN: usize = 8;
 #[allow(dead_code)]
 const MIN_ALIGN: usize = 16;
 
-use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Opaque};
+use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout};
 use core::ptr::NonNull;
 
-#[unstable(feature = "allocator_api", issue = "32838")]
+/// The default memory allocator provided by the operating system.
+///
+/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows,
+/// plus related functions.
+///
+/// This type can be used in a `static` item
+/// with the `#[global_allocator]` attribute
+/// to force the global allocator to be the system’s one.
+/// (The default is jemalloc for executables, on some platforms.)
+///
+/// ```rust
+/// use std::alloc::System;
+///
+/// #[global_allocator]
+/// static A: System = System;
+///
+/// fn main() {
+///     let a = Box::new(4); // Allocates from the system allocator.
+///     println!("{}", a);
+/// }
+/// ```
+///
+/// It can also be used directly to allocate memory
+/// independently of the standard library’s global allocator.
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
 pub struct System;
 
 #[unstable(feature = "allocator_api", issue = "32838")]
 unsafe impl Alloc for System {
     #[inline]
-    unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
+    unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
         NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr)
     }
 
     #[inline]
-    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
+    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
         NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr)
     }
 
     #[inline]
-    unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout) {
+    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
         GlobalAlloc::dealloc(self, ptr.as_ptr(), layout)
     }
 
     #[inline]
     unsafe fn realloc(&mut self,
-                      ptr: NonNull<Opaque>,
+                      ptr: NonNull<u8>,
                       layout: Layout,
-                      new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
+                      new_size: usize) -> Result<NonNull<u8>, AllocErr> {
         NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
     }
 }
 
 #[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))]
 mod realloc_fallback {
-    use core::alloc::{GlobalAlloc, Opaque, Layout};
+    use core::alloc::{GlobalAlloc, Layout};
     use core::cmp;
     use core::ptr;
 
     impl super::System {
-        pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut Opaque, old_layout: Layout,
-                                              new_size: usize) -> *mut Opaque {
+        pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout,
+                                              new_size: usize) -> *mut u8 {
             // Docs for GlobalAlloc::realloc require this to be valid:
             let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
 
             let new_ptr = GlobalAlloc::alloc(self, new_layout);
             if !new_ptr.is_null() {
                 let size = cmp::min(old_layout.size(), new_size);
-                ptr::copy_nonoverlapping(ptr as *mut u8, new_ptr as *mut u8, size);
+                ptr::copy_nonoverlapping(ptr, new_ptr, size);
                 GlobalAlloc::dealloc(self, ptr, old_layout);
             }
             new_ptr
@@ -104,21 +127,19 @@ mod platform {
 
     use MIN_ALIGN;
     use System;
-    use core::alloc::{GlobalAlloc, Layout, Opaque};
+    use core::alloc::{GlobalAlloc, Layout};
 
-    #[unstable(feature = "allocator_api", issue = "32838")]
+    #[stable(feature = "alloc_system_type", since = "1.28.0")]
     unsafe impl GlobalAlloc for System {
         #[inline]
-        unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
+        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
             if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
-                libc::malloc(layout.size()) as *mut Opaque
+                libc::malloc(layout.size()) as *mut u8
             } else {
                 #[cfg(target_os = "macos")]
                 {
                     if layout.align() > (1 << 31) {
-                        // FIXME: use Opaque::null_mut
-                        // https://github.com/rust-lang/rust/issues/49659
-                        return 0 as *mut Opaque
+                        return ptr::null_mut()
                     }
                 }
                 aligned_malloc(&layout)
@@ -126,27 +147,27 @@ mod platform {
         }
 
         #[inline]
-        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
+        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
             if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
-                libc::calloc(layout.size(), 1) as *mut Opaque
+                libc::calloc(layout.size(), 1) as *mut u8
             } else {
                 let ptr = self.alloc(layout.clone());
                 if !ptr.is_null() {
-                    ptr::write_bytes(ptr as *mut u8, 0, layout.size());
+                    ptr::write_bytes(ptr, 0, layout.size());
                 }
                 ptr
             }
         }
 
         #[inline]
-        unsafe fn dealloc(&self, ptr: *mut Opaque, _layout: Layout) {
+        unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
             libc::free(ptr as *mut libc::c_void)
         }
 
         #[inline]
-        unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
+        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
             if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
-                libc::realloc(ptr as *mut libc::c_void, new_size) as *mut Opaque
+                libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
             } else {
                 self.realloc_fallback(ptr, layout, new_size)
             }
@@ -155,7 +176,7 @@ mod platform {
 
     #[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))]
     #[inline]
-    unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque {
+    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
@@ -173,19 +194,18 @@ mod platform {
         // [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(layout.align(), layout.size()) as *mut Opaque
+        libc::memalign(layout.align(), layout.size()) as *mut u8
     }
 
     #[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))]
     #[inline]
-    unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque {
+    unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
         let mut out = ptr::null_mut();
         let ret = libc::posix_memalign(&mut out, layout.align(), layout.size());
         if ret != 0 {
-            // FIXME: use Opaque::null_mut https://github.com/rust-lang/rust/issues/49659
-            0 as *mut Opaque
+            ptr::null_mut()
         } else {
-            out as *mut Opaque
+            out as *mut u8
         }
     }
 }
@@ -195,7 +215,7 @@ mod platform {
 mod platform {
     use MIN_ALIGN;
     use System;
-    use core::alloc::{GlobalAlloc, Opaque, Layout};
+    use core::alloc::{GlobalAlloc, Layout};
 
     type LPVOID = *mut u8;
     type HANDLE = LPVOID;
@@ -227,7 +247,7 @@ mod platform {
     }
 
     #[inline]
-    unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut Opaque {
+    unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
         let ptr = if layout.align() <= MIN_ALIGN {
             HeapAlloc(GetProcessHeap(), flags, layout.size())
         } else {
@@ -239,29 +259,29 @@ mod platform {
                 align_ptr(ptr, layout.align())
             }
         };
-        ptr as *mut Opaque
+        ptr as *mut u8
     }
 
-    #[unstable(feature = "allocator_api", issue = "32838")]
+    #[stable(feature = "alloc_system_type", since = "1.28.0")]
     unsafe impl GlobalAlloc for System {
         #[inline]
-        unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
+        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
             allocate_with_flags(layout, 0)
         }
 
         #[inline]
-        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
+        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
             allocate_with_flags(layout, HEAP_ZERO_MEMORY)
         }
 
         #[inline]
-        unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
+        unsafe fn dealloc(&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 as *mut u8);
+                let header = get_header(ptr);
                 let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
                 debug_assert!(err != 0, "Failed to free heap memory: {}",
                               GetLastError());
@@ -269,9 +289,9 @@ mod platform {
         }
 
         #[inline]
-        unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
+        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
             if layout.align() <= MIN_ALIGN {
-                HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut Opaque
+                HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8
             } else {
                 self.realloc_fallback(ptr, layout, new_size)
             }
@@ -300,32 +320,32 @@ mod platform {
 mod platform {
     extern crate dlmalloc;
 
-    use core::alloc::{GlobalAlloc, Layout, Opaque};
+    use core::alloc::{GlobalAlloc, Layout};
     use System;
 
     // No need for synchronization here as wasm is currently single-threaded
     static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
 
-    #[unstable(feature = "allocator_api", issue = "32838")]
+    #[stable(feature = "alloc_system_type", since = "1.28.0")]
     unsafe impl GlobalAlloc for System {
         #[inline]
-        unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
-            DLMALLOC.malloc(layout.size(), layout.align()) as *mut Opaque
+        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+            DLMALLOC.malloc(layout.size(), layout.align())
         }
 
         #[inline]
-        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
-            DLMALLOC.calloc(layout.size(), layout.align()) as *mut Opaque
+        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+            DLMALLOC.calloc(layout.size(), layout.align())
         }
 
         #[inline]
-        unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
-            DLMALLOC.free(ptr as *mut u8, layout.size(), layout.align())
+        unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+            DLMALLOC.free(ptr, layout.size(), layout.align())
         }
 
         #[inline]
-        unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
-            DLMALLOC.realloc(ptr as *mut u8, layout.size(), layout.align(), new_size) as *mut Opaque
+        unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+            DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
         }
     }
 }
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs
index 229758803c8..353688d1b85 100644
--- a/src/libcore/alloc.rs
+++ b/src/libcore/alloc.rs
@@ -8,12 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![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 = "32838")]
+//! Memory allocation APIs
+
+#![stable(feature = "alloc_module", since = "1.28.0")]
 
 use cmp;
 use fmt;
@@ -22,30 +19,15 @@ use usize;
 use ptr::{self, NonNull};
 use num::NonZeroUsize;
 
-extern {
-    /// An opaque, unsized type. Used for pointers to allocated memory.
-    ///
-    /// This type can only be used behind a pointer like `*mut Opaque` or `ptr::NonNull<Opaque>`.
-    /// Such pointers are similar to C’s `void*` type.
-    pub type Opaque;
-}
-
-impl Opaque {
-    /// Similar to `std::ptr::null`, which requires `T: Sized`.
-    pub fn null() -> *const Self {
-        0 as _
-    }
-
-    /// Similar to `std::ptr::null_mut`, which requires `T: Sized`.
-    pub fn null_mut() -> *mut Self {
-        0 as _
-    }
-}
+#[unstable(feature = "alloc_internals", issue = "0")]
+#[cfg(stage0)]
+pub type Opaque = u8;
 
 /// Represents the combination of a starting address and
 /// a total capacity of the returned block.
+#[unstable(feature = "allocator_api", issue = "32838")]
 #[derive(Debug)]
-pub struct Excess(pub NonNull<Opaque>, pub usize);
+pub struct Excess(pub NonNull<u8>, pub usize);
 
 fn size_align<T>() -> (usize, usize) {
     (mem::size_of::<T>(), mem::align_of::<T>())
@@ -64,6 +46,7 @@ fn size_align<T>() -> (usize, usize) {
 /// requests have positive size. A caller to the `Alloc::alloc`
 /// method must either ensure that conditions like this are met, or
 /// use specific allocators with looser requirements.)
+#[stable(feature = "alloc_layout", since = "1.28.0")]
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub struct Layout {
     // size of the requested block of memory, measured in bytes.
@@ -89,6 +72,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`).
+    #[stable(feature = "alloc_layout", since = "1.28.0")]
     #[inline]
     pub fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
         if !align.is_power_of_two() {
@@ -124,20 +108,24 @@ impl Layout {
     ///
     /// This function is unsafe as it does not verify the preconditions from
     /// [`Layout::from_size_align`](#method.from_size_align).
+    #[stable(feature = "alloc_layout", since = "1.28.0")]
     #[inline]
     pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
         Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) }
     }
 
     /// The minimum size in bytes for a memory block of this layout.
+    #[stable(feature = "alloc_layout", since = "1.28.0")]
     #[inline]
     pub fn size(&self) -> usize { self.size_ }
 
     /// The minimum byte alignment for a memory block of this layout.
+    #[stable(feature = "alloc_layout", since = "1.28.0")]
     #[inline]
     pub fn align(&self) -> usize { self.align_.get() }
 
     /// Constructs a `Layout` suitable for holding a value of type `T`.
+    #[stable(feature = "alloc_layout", since = "1.28.0")]
     #[inline]
     pub fn new<T>() -> Self {
         let (size, align) = size_align::<T>();
@@ -154,6 +142,7 @@ impl Layout {
     /// Produces layout describing a record that could be used to
     /// allocate backing structure for `T` (which could be a trait
     /// or other unsized type like a slice).
+    #[stable(feature = "alloc_layout", since = "1.28.0")]
     #[inline]
     pub fn for_value<T: ?Sized>(t: &T) -> Self {
         let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
@@ -181,6 +170,7 @@ impl Layout {
     /// Panics if the combination of `self.size()` and the given `align`
     /// violates the conditions listed in
     /// [`Layout::from_size_align`](#method.from_size_align).
+    #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn align_to(&self, align: usize) -> Self {
         Layout::from_size_align(self.size(), cmp::max(self.align(), align)).unwrap()
@@ -202,6 +192,7 @@ impl Layout {
     /// 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()`.
+    #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn padding_needed_for(&self, align: usize) -> usize {
         let len = self.size();
@@ -238,6 +229,7 @@ impl Layout {
     /// of each element in the array.
     ///
     /// On arithmetic overflow, returns `LayoutErr`.
+    #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
         let padded_size = self.size().checked_add(self.padding_needed_for(self.align()))
@@ -263,6 +255,7 @@ impl Layout {
     /// (assuming that the record itself starts at offset 0).
     ///
     /// On arithmetic overflow, returns `LayoutErr`.
+    #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
         let new_align = cmp::max(self.align(), next.align());
@@ -289,6 +282,7 @@ impl Layout {
     /// aligned.
     ///
     /// On arithmetic overflow, returns `LayoutErr`.
+    #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutErr> {
         let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?;
@@ -310,6 +304,7 @@ impl Layout {
     ///  `extend`.)
     ///
     /// On arithmetic overflow, returns `LayoutErr`.
+    #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
         let new_size = self.size().checked_add(next.size())
@@ -321,6 +316,7 @@ impl Layout {
     /// Creates a layout describing the record for a `[T; n]`.
     ///
     /// On arithmetic overflow, returns `LayoutErr`.
+    #[unstable(feature = "allocator_api", issue = "32838")]
     #[inline]
     pub fn array<T>(n: usize) -> Result<Self, LayoutErr> {
         Layout::new::<T>()
@@ -332,28 +328,33 @@ impl Layout {
     }
 }
 
-/// The parameters given to `Layout::from_size_align` do not satisfy
-/// its documented constraints.
+/// The parameters given to `Layout::from_size_align`
+/// or some other `Layout` constructor
+/// do not satisfy its documented constraints.
+#[stable(feature = "alloc_layout", since = "1.28.0")]
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct LayoutErr {
     private: ()
 }
 
 // (we need this for downstream impl of trait Error)
+#[stable(feature = "alloc_layout", since = "1.28.0")]
 impl fmt::Display for LayoutErr {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str("invalid parameters to Layout::from_size_align")
     }
 }
 
-/// The `AllocErr` error specifies whether an allocation failure is
-/// specifically due to resource exhaustion or if it is due to
+/// The `AllocErr` error indicates an allocation failure
+/// that may be due to resource exhaustion or to
 /// something wrong when combining the given input arguments with this
 /// allocator.
+#[unstable(feature = "allocator_api", issue = "32838")]
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct AllocErr;
 
 // (we need this for downstream impl of trait Error)
+#[unstable(feature = "allocator_api", issue = "32838")]
 impl fmt::Display for AllocErr {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         f.write_str("memory allocation failed")
@@ -363,9 +364,11 @@ impl fmt::Display for AllocErr {
 /// The `CannotReallocInPlace` error is used when `grow_in_place` or
 /// `shrink_in_place` were unable to reuse the given memory block for
 /// a requested layout.
+#[unstable(feature = "allocator_api", issue = "32838")]
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct CannotReallocInPlace;
 
+#[unstable(feature = "allocator_api", issue = "32838")]
 impl CannotReallocInPlace {
     pub fn description(&self) -> &str {
         "cannot reallocate allocator's memory in place"
@@ -373,6 +376,7 @@ impl CannotReallocInPlace {
 }
 
 // (we need this for downstream impl of trait Error)
+#[unstable(feature = "allocator_api", issue = "32838")]
 impl fmt::Display for CannotReallocInPlace {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "{}", self.description())
@@ -380,6 +384,7 @@ impl fmt::Display for CannotReallocInPlace {
 }
 
 /// Augments `AllocErr` with a CapacityOverflow variant.
+// FIXME: should this be in libcore or liballoc?
 #[derive(Clone, PartialEq, Eq, Debug)]
 #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
 pub enum CollectionAllocErr {
@@ -406,32 +411,134 @@ impl From<LayoutErr> for CollectionAllocErr {
     }
 }
 
-/// A memory allocator that can be registered to be the one backing `std::alloc::Global`
+/// A memory allocator that can be registered as the standard library’s default
 /// though the `#[global_allocator]` attributes.
+///
+/// Some of the methods require that a memory block be *currently
+/// allocated* via an allocator. This means that:
+///
+/// * the starting address for that memory block was previously
+///   returned by a previous call to an allocation method
+///   such as `alloc`, and
+///
+/// * the memory block has not been subsequently deallocated, where
+///   blocks are deallocated either by being passed to a deallocation
+///   method such as `dealloc` or by being
+///   passed to a reallocation method that returns a non-null pointer.
+///
+///
+/// # Example
+///
+/// ```no_run
+/// use std::alloc::{GlobalAlloc, Layout, alloc};
+/// use std::ptr::null_mut;
+///
+/// struct MyAllocator;
+///
+/// unsafe impl GlobalAlloc for MyAllocator {
+///     unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() }
+///     unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
+/// }
+///
+/// #[global_allocator]
+/// static A: MyAllocator = MyAllocator;
+///
+/// fn main() {
+///     unsafe {
+///         assert!(alloc(Layout::new::<u32>()).is_null())
+///     }
+/// }
+/// ```
+///
+/// # Unsafety
+///
+/// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and
+/// implementors must ensure that they adhere to these contracts:
+///
+/// * It's undefined behavior if global allocators unwind.  This restriction may
+///   be lifted in the future, but currently a panic from any of these
+///   functions may lead to memory unsafety.
+///
+/// * `Layout` queries and calculations in general must be correct. Callers of
+///   this trait are allowed to rely on the contracts defined on each method,
+///   and implementors must ensure such contracts remain true.
+#[stable(feature = "global_alloc", since = "1.28.0")]
 pub unsafe trait GlobalAlloc {
     /// Allocate memory as described by the given `layout`.
     ///
     /// Returns a pointer to newly-allocated memory,
-    /// or NULL to indicate allocation failure.
+    /// or null to indicate allocation failure.
     ///
     /// # Safety
     ///
-    /// **FIXME:** what are the exact requirements?
-    unsafe fn alloc(&self, layout: Layout) -> *mut Opaque;
+    /// This function is unsafe because undefined behavior can result
+    /// if the caller does not ensure that `layout` has non-zero size.
+    ///
+    /// (Extension subtraits might provide more specific bounds on
+    /// behavior, e.g. guarantee a sentinel address or a null pointer
+    /// in response to a zero-size allocation request.)
+    ///
+    /// The allocated block of memory may or may not be initialized.
+    ///
+    /// # Errors
+    ///
+    /// Returning a null pointer indicates that either memory is exhausted
+    /// or `layout` does not meet allocator's size or alignment constraints.
+    ///
+    /// Implementations are encouraged to return null on memory
+    /// exhaustion rather than aborting, but this is not
+    /// a strict requirement. (Specifically: it is *legal* to
+    /// implement this trait atop an underlying native allocation
+    /// library that aborts on memory exhaustion.)
+    ///
+    /// Clients wishing to abort computation in response to an
+    /// allocation error are encouraged to call the [`oom`] function,
+    /// rather than directly invoking `panic!` or similar.
+    ///
+    /// [`oom`]: ../../alloc/alloc/fn.oom.html
+    #[stable(feature = "global_alloc", since = "1.28.0")]
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8;
 
     /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`.
     ///
     /// # Safety
     ///
-    /// **FIXME:** what are the exact requirements?
-    /// In particular around layout *fit*. (See docs for the `Alloc` trait.)
-    unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout);
+    /// This function is unsafe because undefined behavior can result
+    /// if the caller does not ensure all of the following:
+    ///
+    /// * `ptr` must denote a block of memory currently allocated via
+    ///   this allocator,
+    ///
+    /// * `layout` must be the same layout that was used
+    ///   to allocated that block of memory,
+    #[stable(feature = "global_alloc", since = "1.28.0")]
+    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
 
-    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque {
+    /// Behaves like `alloc`, but also ensures that the contents
+    /// are set to zero before being returned.
+    ///
+    /// # Safety
+    ///
+    /// This function is unsafe for the same reasons that `alloc` is.
+    /// However the allocated block of memory is guaranteed to be initialized.
+    ///
+    /// # Errors
+    ///
+    /// Returning a null pointer indicates that either memory is exhausted
+    /// or `layout` does not meet allocator's size or alignment constraints,
+    /// just as in `alloc`.
+    ///
+    /// Clients wishing to abort computation in response to an
+    /// allocation error are encouraged to call the [`oom`] function,
+    /// rather than directly invoking `panic!` or similar.
+    ///
+    /// [`oom`]: ../../alloc/alloc/fn.oom.html
+    #[stable(feature = "global_alloc", since = "1.28.0")]
+    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
         let size = layout.size();
         let ptr = self.alloc(layout);
         if !ptr.is_null() {
-            ptr::write_bytes(ptr as *mut u8, 0, size);
+            ptr::write_bytes(ptr, 0, size);
         }
         ptr
     }
@@ -439,26 +546,61 @@ pub unsafe trait GlobalAlloc {
     /// Shink or grow a block of memory to the given `new_size`.
     /// The block is described by the given `ptr` pointer and `layout`.
     ///
-    /// Return a new pointer (which may or may not be the same as `ptr`),
-    /// or NULL to indicate reallocation failure.
+    /// If this returns a non-null pointer, then ownership of the memory block
+    /// referenced by `ptr` has been transferred to this alloctor.
+    /// The memory may or may not have been deallocated,
+    /// and should be considered unusable (unless of course it was
+    /// transferred back to the caller again via the return value of
+    /// this method).
     ///
-    /// If reallocation is successful, the old `ptr` pointer is considered
-    /// to have been deallocated.
+    /// If this method returns null, then ownership of the memory
+    /// block has not been transferred to this allocator, and the
+    /// contents of the memory block are unaltered.
     ///
     /// # Safety
     ///
-    /// `new_size`, when rounded up to the nearest multiple of `old_layout.align()`,
-    /// must not overflow (i.e. the rounded value must be less than `usize::MAX`).
+    /// This function is unsafe because undefined behavior can result
+    /// if the caller does not ensure all of the following:
+    ///
+    /// * `ptr` must be currently allocated via this allocator,
+    ///
+    /// * `layout` must be the same layout that was used
+    ///   to allocated that block of memory,
+    ///
+    /// * `new_size` must be greater than zero.
+    ///
+    /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
+    ///   must not overflow (i.e. the rounded value must be less than `usize::MAX`).
+    ///
+    /// (Extension subtraits might provide more specific bounds on
+    /// behavior, e.g. guarantee a sentinel address or a null pointer
+    /// in response to a zero-size allocation request.)
+    ///
+    /// # Errors
+    ///
+    /// Returns null if the new layout does not meet the size
+    /// and alignment constraints of the allocator, or if reallocation
+    /// otherwise fails.
+    ///
+    /// Implementations are encouraged to return null on memory
+    /// exhaustion rather than panicking or aborting, but this is not
+    /// a strict requirement. (Specifically: it is *legal* to
+    /// implement this trait atop an underlying native allocation
+    /// library that aborts on memory exhaustion.)
+    ///
+    /// Clients wishing to abort computation in response to a
+    /// reallocation error are encouraged to call the [`oom`] function,
+    /// rather than directly invoking `panic!` or similar.
     ///
-    /// **FIXME:** what are the exact requirements?
-    /// In particular around layout *fit*. (See docs for the `Alloc` trait.)
-    unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque {
+    /// [`oom`]: ../../alloc/alloc/fn.oom.html
+    #[stable(feature = "global_alloc", since = "1.28.0")]
+    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
         let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
         let new_ptr = self.alloc(new_layout);
         if !new_ptr.is_null() {
             ptr::copy_nonoverlapping(
-                ptr as *const u8,
-                new_ptr as *mut u8,
+                ptr,
+                new_ptr,
                 cmp::min(layout.size(), new_size),
             );
             self.dealloc(ptr, layout);
@@ -540,27 +682,22 @@ pub unsafe trait GlobalAlloc {
 ///   retain their validity until at least the instance of `Alloc` is dropped
 ///   itself.
 ///
-/// * It's undefined behavior if global allocators unwind.  This restriction may
-///   be lifted in the future, but currently a panic from any of these
-///   functions may lead to memory unsafety. Note that as of the time of this
-///   writing allocators *not* intending to be global allocators can still panic
-///   in their implementation without violating memory safety.
-///
 /// * `Layout` queries and calculations in general must be correct. Callers of
 ///   this trait are allowed to rely on the contracts defined on each method,
 ///   and implementors must ensure such contracts remain true.
 ///
 /// Note that this list may get tweaked over time as clarifications are made in
-/// the future. Additionally global allocators may gain unique requirements for
-/// how to safely implement one in the future as well.
+/// the future.
+#[unstable(feature = "allocator_api", issue = "32838")]
 pub unsafe trait Alloc {
 
-    // (Note: existing allocators have unspecified but well-defined
+    // (Note: some existing allocators have unspecified but well-defined
     // behavior in response to a zero size allocation request ;
     // e.g. in C, `malloc` of 0 will either return a null pointer or a
     // unique pointer, but will not have arbitrary undefined
-    // behavior. Rust should consider revising the alloc::heap crate
-    // to reflect this reality.)
+    // behavior.
+    // However in jemalloc for example,
+    // `mallocx(0)` is documented as undefined behavior.)
 
     /// Returns a pointer meeting the size and alignment guarantees of
     /// `layout`.
@@ -596,9 +733,11 @@ pub unsafe trait Alloc {
     /// library that aborts on memory exhaustion.)
     ///
     /// Clients wishing to abort computation in response to an
-    /// allocation error are encouraged to call the allocator's `oom`
-    /// method, rather than directly invoking `panic!` or similar.
-    unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr>;
+    /// allocation error are encouraged to call the [`oom`] function,
+    /// rather than directly invoking `panic!` or similar.
+    ///
+    /// [`oom`]: ../../alloc/alloc/fn.oom.html
+    unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr>;
 
     /// Deallocate the memory referenced by `ptr`.
     ///
@@ -615,7 +754,7 @@ pub unsafe trait Alloc {
     /// * In addition to fitting the block of memory `layout`, the
     ///   alignment of the `layout` must match the alignment used
     ///   to allocate that block of memory.
-    unsafe fn dealloc(&mut self, ptr: NonNull<Opaque>, layout: Layout);
+    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);
 
     // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS ==
     // usable_size
@@ -703,13 +842,15 @@ pub unsafe trait Alloc {
     /// implement this trait atop an underlying native allocation
     /// library that aborts on memory exhaustion.)
     ///
-    /// Clients wishing to abort computation in response to an
-    /// reallocation error are encouraged to call the allocator's `oom`
-    /// method, rather than directly invoking `panic!` or similar.
+    /// Clients wishing to abort computation in response to a
+    /// reallocation error are encouraged to call the [`oom`] function,
+    /// rather than directly invoking `panic!` or similar.
+    ///
+    /// [`oom`]: ../../alloc/alloc/fn.oom.html
     unsafe fn realloc(&mut self,
-                      ptr: NonNull<Opaque>,
+                      ptr: NonNull<u8>,
                       layout: Layout,
-                      new_size: usize) -> Result<NonNull<Opaque>, AllocErr> {
+                      new_size: usize) -> Result<NonNull<u8>, AllocErr> {
         let old_size = layout.size();
 
         if new_size >= old_size {
@@ -726,8 +867,8 @@ pub unsafe trait Alloc {
         let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
         let result = self.alloc(new_layout);
         if let Ok(new_ptr) = result {
-            ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8,
-                                     new_ptr.as_ptr() as *mut u8,
+            ptr::copy_nonoverlapping(ptr.as_ptr(),
+                                     new_ptr.as_ptr(),
                                      cmp::min(old_size, new_size));
             self.dealloc(ptr, layout);
         }
@@ -748,13 +889,15 @@ pub unsafe trait Alloc {
     /// constraints, just as in `alloc`.
     ///
     /// Clients wishing to abort computation in response to an
-    /// allocation error are encouraged to call the allocator's `oom`
-    /// method, rather than directly invoking `panic!` or similar.
-    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<Opaque>, AllocErr> {
+    /// allocation error are encouraged to call the [`oom`] function,
+    /// rather than directly invoking `panic!` or similar.
+    ///
+    /// [`oom`]: ../../alloc/alloc/fn.oom.html
+    unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
         let size = layout.size();
         let p = self.alloc(layout);
         if let Ok(p) = p {
-            ptr::write_bytes(p.as_ptr() as *mut u8, 0, size);
+            ptr::write_bytes(p.as_ptr(), 0, size);
         }
         p
     }
@@ -774,8 +917,10 @@ pub unsafe trait Alloc {
     /// constraints, just as in `alloc`.
     ///
     /// Clients wishing to abort computation in response to an
-    /// allocation error are encouraged to call the allocator's `oom`
-    /// method, rather than directly invoking `panic!` or similar.
+    /// allocation error are encouraged to call the [`oom`] function,
+    /// rather than directly invoking `panic!` or similar.
+    ///
+    /// [`oom`]: ../../alloc/alloc/fn.oom.html
     unsafe fn alloc_excess(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
         let usable_size = self.usable_size(&layout);
         self.alloc(layout).map(|p| Excess(p, usable_size.1))
@@ -795,11 +940,13 @@ pub unsafe trait Alloc {
     /// `layout` does not meet allocator's size or alignment
     /// constraints, just as in `realloc`.
     ///
-    /// Clients wishing to abort computation in response to an
-    /// reallocation error are encouraged to call the allocator's `oom`
-    /// method, rather than directly invoking `panic!` or similar.
+    /// Clients wishing to abort computation in response to a
+    /// reallocation error are encouraged to call the [`oom`] function,
+    /// rather than directly invoking `panic!` or similar.
+    ///
+    /// [`oom`]: ../../alloc/alloc/fn.oom.html
     unsafe fn realloc_excess(&mut self,
-                             ptr: NonNull<Opaque>,
+                             ptr: NonNull<u8>,
                              layout: Layout,
                              new_size: usize) -> Result<Excess, AllocErr> {
         let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
@@ -840,11 +987,11 @@ pub unsafe trait Alloc {
     /// could fit `layout`.
     ///
     /// Note that one cannot pass `CannotReallocInPlace` to the `oom`
-    /// method; clients are expected either to be able to recover from
+    /// function; clients are expected either to be able to recover from
     /// `grow_in_place` failures without aborting, or to fall back on
     /// another reallocation method before resorting to an abort.
     unsafe fn grow_in_place(&mut self,
-                            ptr: NonNull<Opaque>,
+                            ptr: NonNull<u8>,
                             layout: Layout,
                             new_size: usize) -> Result<(), CannotReallocInPlace> {
         let _ = ptr; // this default implementation doesn't care about the actual address.
@@ -895,11 +1042,11 @@ pub unsafe trait Alloc {
     /// could fit `layout`.
     ///
     /// Note that one cannot pass `CannotReallocInPlace` to the `oom`
-    /// method; clients are expected either to be able to recover from
+    /// function; clients are expected either to be able to recover from
     /// `shrink_in_place` failures without aborting, or to fall back
     /// on another reallocation method before resorting to an abort.
     unsafe fn shrink_in_place(&mut self,
-                              ptr: NonNull<Opaque>,
+                              ptr: NonNull<u8>,
                               layout: Layout,
                               new_size: usize) -> Result<(), CannotReallocInPlace> {
         let _ = ptr; // this default implementation doesn't care about the actual address.
@@ -943,8 +1090,10 @@ pub unsafe trait Alloc {
     /// will *not* yield undefined behavior.
     ///
     /// Clients wishing to abort computation in response to an
-    /// allocation error are encouraged to call the allocator's `oom`
-    /// method, rather than directly invoking `panic!` or similar.
+    /// allocation error are encouraged to call the [`oom`] function,
+    /// rather than directly invoking `panic!` or similar.
+    ///
+    /// [`oom`]: ../../alloc/alloc/fn.oom.html
     fn alloc_one<T>(&mut self) -> Result<NonNull<T>, AllocErr>
         where Self: Sized
     {
@@ -978,7 +1127,7 @@ pub unsafe trait Alloc {
     {
         let k = Layout::new::<T>();
         if k.size() > 0 {
-            self.dealloc(ptr.as_opaque(), k);
+            self.dealloc(ptr.cast(), k);
         }
     }
 
@@ -1010,8 +1159,10 @@ pub unsafe trait Alloc {
     /// Always returns `Err` on arithmetic overflow.
     ///
     /// Clients wishing to abort computation in response to an
-    /// allocation error are encouraged to call the allocator's `oom`
-    /// method, rather than directly invoking `panic!` or similar.
+    /// allocation error are encouraged to call the [`oom`] function,
+    /// rather than directly invoking `panic!` or similar.
+    ///
+    /// [`oom`]: ../../alloc/alloc/fn.oom.html
     fn alloc_array<T>(&mut self, n: usize) -> Result<NonNull<T>, AllocErr>
         where Self: Sized
     {
@@ -1054,9 +1205,11 @@ pub unsafe trait Alloc {
     ///
     /// Always returns `Err` on arithmetic overflow.
     ///
-    /// Clients wishing to abort computation in response to an
-    /// reallocation error are encouraged to call the allocator's `oom`
-    /// method, rather than directly invoking `panic!` or similar.
+    /// Clients wishing to abort computation in response to a
+    /// reallocation error are encouraged to call the [`oom`] function,
+    /// rather than directly invoking `panic!` or similar.
+    ///
+    /// [`oom`]: ../../alloc/alloc/fn.oom.html
     unsafe fn realloc_array<T>(&mut self,
                                ptr: NonNull<T>,
                                n_old: usize,
@@ -1066,7 +1219,7 @@ pub unsafe trait Alloc {
         match (Layout::array::<T>(n_old), Layout::array::<T>(n_new)) {
             (Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => {
                 debug_assert!(k_old.align() == k_new.align());
-                self.realloc(ptr.as_opaque(), k_old.clone(), k_new.size()).map(NonNull::cast)
+                self.realloc(ptr.cast(), k_old.clone(), k_new.size()).map(NonNull::cast)
             }
             _ => {
                 Err(AllocErr)
@@ -1099,7 +1252,7 @@ pub unsafe trait Alloc {
     {
         match Layout::array::<T>(n) {
             Ok(ref k) if k.size() > 0 => {
-                Ok(self.dealloc(ptr.as_opaque(), k.clone()))
+                Ok(self.dealloc(ptr.cast(), k.clone()))
             }
             _ => {
                 Err(AllocErr)
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index a2ee0033872..5ba77edee6e 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -215,13 +215,6 @@ pub mod task;
 #[allow(missing_docs)]
 pub mod alloc;
 
-#[unstable(feature = "allocator_api", issue = "32838")]
-#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
-/// Use the `alloc` module instead.
-pub mod heap {
-    pub use alloc::*;
-}
-
 // note: does not need to be public
 mod iter_private;
 mod nonzero;
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index 39315d8f0c8..81a8b3ef047 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -2922,14 +2922,6 @@ impl<T: ?Sized> NonNull<T> {
             NonNull::new_unchecked(self.as_ptr() as *mut U)
         }
     }
-
-    /// Cast to an `Opaque` pointer
-    #[unstable(feature = "allocator_api", issue = "32838")]
-    pub fn as_opaque(self) -> NonNull<::alloc::Opaque> {
-        unsafe {
-            NonNull::new_unchecked(self.as_ptr() as _)
-        }
-    }
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs
index 497d5fdcac7..ec0676259ef 100644
--- a/src/librustc_allocator/expand.rs
+++ b/src/librustc_allocator/expand.rs
@@ -237,7 +237,7 @@ impl<'a> AllocFnFactory<'a> {
                 let ident = ident();
                 args.push(self.cx.arg(self.span, ident, self.ptr_u8()));
                 let arg = self.cx.expr_ident(self.span, ident);
-                self.cx.expr_cast(self.span, arg, self.ptr_opaque())
+                self.cx.expr_cast(self.span, arg, self.ptr_u8())
             }
 
             AllocatorTy::Usize => {
@@ -281,17 +281,4 @@ impl<'a> AllocFnFactory<'a> {
         let ty_u8 = self.cx.ty_path(u8);
         self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable)
     }
-
-    fn ptr_opaque(&self) -> P<Ty> {
-        let opaque = self.cx.path(
-            self.span,
-            vec![
-                self.core,
-                Ident::from_str("alloc"),
-                Ident::from_str("Opaque"),
-            ],
-        );
-        let ty_opaque = self.cx.ty_path(opaque);
-        self.cx.ty_ptr(self.span, ty_opaque, Mutability::Mutable)
-    }
 }
diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs
index 3429e3bda0f..a7aeed76309 100644
--- a/src/librustc_asan/lib.rs
+++ b/src/librustc_asan/lib.rs
@@ -10,8 +10,7 @@
 
 #![sanitizer_runtime]
 #![feature(alloc_system)]
-#![feature(allocator_api)]
-#![feature(global_allocator)]
+#![cfg_attr(stage0, feature(global_allocator))]
 #![feature(sanitizer_runtime)]
 #![feature(staged_api)]
 #![no_std]
diff --git a/src/librustc_lsan/lib.rs b/src/librustc_lsan/lib.rs
index 81a09e7e21a..a7aeed76309 100644
--- a/src/librustc_lsan/lib.rs
+++ b/src/librustc_lsan/lib.rs
@@ -9,10 +9,9 @@
 // except according to those terms.
 
 #![sanitizer_runtime]
-#![feature(sanitizer_runtime)]
 #![feature(alloc_system)]
-#![feature(allocator_api)]
-#![feature(global_allocator)]
+#![cfg_attr(stage0, feature(global_allocator))]
+#![feature(sanitizer_runtime)]
 #![feature(staged_api)]
 #![no_std]
 #![unstable(feature = "sanitizer_runtime_lib",
diff --git a/src/librustc_msan/lib.rs b/src/librustc_msan/lib.rs
index 81a09e7e21a..a7aeed76309 100644
--- a/src/librustc_msan/lib.rs
+++ b/src/librustc_msan/lib.rs
@@ -9,10 +9,9 @@
 // except according to those terms.
 
 #![sanitizer_runtime]
-#![feature(sanitizer_runtime)]
 #![feature(alloc_system)]
-#![feature(allocator_api)]
-#![feature(global_allocator)]
+#![cfg_attr(stage0, feature(global_allocator))]
+#![feature(sanitizer_runtime)]
 #![feature(staged_api)]
 #![no_std]
 #![unstable(feature = "sanitizer_runtime_lib",
diff --git a/src/librustc_tsan/lib.rs b/src/librustc_tsan/lib.rs
index 3429e3bda0f..a7aeed76309 100644
--- a/src/librustc_tsan/lib.rs
+++ b/src/librustc_tsan/lib.rs
@@ -10,8 +10,7 @@
 
 #![sanitizer_runtime]
 #![feature(alloc_system)]
-#![feature(allocator_api)]
-#![feature(global_allocator)]
+#![cfg_attr(stage0, feature(global_allocator))]
 #![feature(sanitizer_runtime)]
 #![feature(staged_api)]
 #![no_std]
diff --git a/src/libstd/alloc.rs b/src/libstd/alloc.rs
index 3b1a3a439e7..ae74a71dd06 100644
--- a/src/libstd/alloc.rs
+++ b/src/libstd/alloc.rs
@@ -8,19 +8,84 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-//! dox
+//! Memory allocation APIs
+//!
+//! In a given program, the standard library has one “global” memory allocator
+//! that is used for example by `Box<T>` and `Vec<T>`.
+//!
+//! Currently the default global allocator is unspecified.
+//! The compiler may link to a version of [jemalloc] on some platforms,
+//! but this is not guaranteed.
+//! Libraries, however, like `cdylib`s and `staticlib`s are guaranteed
+//! to use the [`System`] by default.
+//!
+//! [jemalloc]: https://github.com/jemalloc/jemalloc
+//! [`System`]: struct.System.html
+//!
+//! # The `#[global_allocator]` attribute
+//!
+//! This attribute allows configuring the choice of global allocator.
+//! You can use this to implement a completely custom global allocator
+//! to route all default allocation requests to a custom object.
+//!
+//! ```rust
+//! use std::alloc::{GlobalAlloc, System, Layout};
+//!
+//! struct MyAllocator;
+//!
+//! unsafe impl GlobalAlloc for MyAllocator {
+//!     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+//!         System.alloc(layout)
+//!     }
+//!
+//!     unsafe fn dealloc(&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);
+//! }
+//! ```
+//!
+//! The attribute is used on a `static` item whose type implements the
+//! [`GlobalAlloc`] trait. This type can be provided by an external library:
+//!
+//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html
+//!
+//! ```rust,ignore (demonstrates crates.io usage)
+//! extern crate jemallocator;
+//!
+//! use jemallacator::Jemalloc;
+//!
+//! #[global_allocator]
+//! static GLOBAL: Jemalloc = Jemalloc;
+//!
+//! fn main() {}
+//! ```
+//!
+//! The `#[global_allocator]` can only be used once in a crate
+//! or its recursive dependencies.
 
-#![unstable(issue = "32838", feature = "allocator_api")]
-
-#[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap;
-#[doc(inline)] pub use alloc_crate::alloc::{Global, Layout, oom};
-#[doc(inline)] pub use alloc_system::System;
-#[doc(inline)] pub use core::alloc::*;
+#![stable(feature = "alloc_module", since = "1.28.0")]
 
 use core::sync::atomic::{AtomicPtr, Ordering};
 use core::{mem, ptr};
 use sys_common::util::dumb_print;
 
+#[stable(feature = "alloc_module", since = "1.28.0")]
+#[doc(inline)]
+pub use alloc_crate::alloc::*;
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+#[doc(inline)]
+pub use alloc_system::System;
+
 static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
 
 /// Registers a custom OOM hook, replacing any that was previously registered.
@@ -34,6 +99,7 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
 /// about the allocation that failed.
 ///
 /// The OOM hook is a global resource.
+#[unstable(feature = "oom_hook", issue = "51245")]
 pub fn set_oom_hook(hook: fn(Layout)) {
     HOOK.store(hook as *mut (), Ordering::SeqCst);
 }
@@ -43,6 +109,7 @@ pub fn set_oom_hook(hook: fn(Layout)) {
 /// *See also the function [`set_oom_hook`].*
 ///
 /// If no custom hook is registered, the default hook will be returned.
+#[unstable(feature = "oom_hook", issue = "51245")]
 pub fn take_oom_hook() -> fn(Layout) {
     let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
     if hook.is_null() {
@@ -59,6 +126,7 @@ fn default_oom_hook(layout: Layout) {
 #[cfg(not(test))]
 #[doc(hidden)]
 #[lang = "oom"]
+#[unstable(feature = "alloc_internals", issue = "0")]
 pub extern fn rust_oom(layout: Layout) -> ! {
     let hook = HOOK.load(Ordering::SeqCst);
     let hook: fn(Layout) = if hook.is_null() {
@@ -73,8 +141,9 @@ pub extern fn rust_oom(layout: Layout) -> ! {
 #[cfg(not(test))]
 #[doc(hidden)]
 #[allow(unused_attributes)]
+#[unstable(feature = "alloc_internals", issue = "0")]
 pub mod __default_lib_allocator {
-    use super::{System, Layout, GlobalAlloc, Opaque};
+    use super::{System, Layout, GlobalAlloc};
     // for symbol names src/librustc/middle/allocator.rs
     // for signatures src/librustc_allocator/lib.rs
 
@@ -85,7 +154,7 @@ pub mod __default_lib_allocator {
     #[rustc_std_internal_symbol]
     pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
         let layout = Layout::from_size_align_unchecked(size, align);
-        System.alloc(layout) as *mut u8
+        System.alloc(layout)
     }
 
     #[no_mangle]
@@ -93,7 +162,7 @@ pub mod __default_lib_allocator {
     pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
                                        size: usize,
                                        align: usize) {
-        System.dealloc(ptr as *mut Opaque, Layout::from_size_align_unchecked(size, align))
+        System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
     }
 
     #[no_mangle]
@@ -103,13 +172,13 @@ pub mod __default_lib_allocator {
                                        align: usize,
                                        new_size: usize) -> *mut u8 {
         let old_layout = Layout::from_size_align_unchecked(old_size, align);
-        System.realloc(ptr as *mut Opaque, old_layout, new_size) as *mut u8
+        System.realloc(ptr, old_layout, new_size)
     }
 
     #[no_mangle]
     #[rustc_std_internal_symbol]
     pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
         let layout = Layout::from_size_align_unchecked(size, align);
-        System.alloc_zeroed(layout) as *mut u8
+        System.alloc_zeroed(layout)
     }
 }
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index d997fb28d42..55f9f4f7cfe 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -1124,7 +1124,7 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
         let (layout, _) = calculate_layout::<K, V>(self.capacity())
             .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
         unsafe {
-            Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout);
+            Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).cast(), layout);
             // Remember how everything was allocated out of one buffer
             // during initialization? We only need one call to free here.
         }
diff --git a/src/libstd/collections/mod.rs b/src/libstd/collections/mod.rs
index d8e79b97970..42113414183 100644
--- a/src/libstd/collections/mod.rs
+++ b/src/libstd/collections/mod.rs
@@ -438,7 +438,7 @@ pub use self::hash_map::HashMap;
 pub use self::hash_set::HashSet;
 
 #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
-pub use heap::CollectionAllocErr;
+pub use alloc::CollectionAllocErr;
 
 mod hash;
 
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index 817eea5eaf1..3160485375f 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -23,13 +23,13 @@
 // coherence challenge (e.g., specialization, neg impls, etc) we can
 // reconsider what crate these items belong in.
 
+use alloc::{AllocErr, LayoutErr, CannotReallocInPlace};
 use any::TypeId;
 use borrow::Cow;
 use cell;
 use char;
 use core::array;
 use fmt::{self, Debug, Display};
-use heap::{AllocErr, LayoutErr, CannotReallocInPlace};
 use mem::transmute;
 use num;
 use str;
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 144977460b6..1bdc1dc2b7c 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -264,7 +264,6 @@
 #![feature(fnbox)]
 #![feature(futures_api)]
 #![feature(hashmap_internals)]
-#![feature(heap_api)]
 #![feature(int_error_internals)]
 #![feature(integer_atomics)]
 #![feature(into_cow)]
@@ -500,13 +499,6 @@ pub mod process;
 pub mod sync;
 pub mod time;
 
-#[unstable(feature = "allocator_api", issue = "32838")]
-#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")]
-/// Use the `alloc` module instead.
-pub mod heap {
-    pub use alloc::*;
-}
-
 // Platform-abstraction modules
 #[macro_use]
 mod sys_common;
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 5f0cf49cd96..1535e649506 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -357,8 +357,6 @@ declare_features! (
     // Trait aliases
     (active, trait_alias, "1.24.0", Some(41517), None),
 
-    // global allocators and their internals
-    (active, global_allocator, "1.20.0", Some(27389), None),
     // rustc internal
     (active, allocator_internals, "1.20.0", None, None),
 
@@ -615,6 +613,8 @@ declare_features! (
     (accepted, macro_lifetime_matcher, "1.27.0", Some(34303), None),
     // Termination trait in tests (RFC 1937)
     (accepted, termination_trait_test, "1.27.0", Some(48854), None),
+    // The #[global_allocator] attribute
+    (accepted, global_allocator, "1.28.0", Some(27389), None),
 );
 
 // If you change this, please modify src/doc/unstable-book as well. You must
@@ -776,11 +776,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                              "the `#[rustc_const_unstable]` attribute \
                                               is an internal feature",
                                              cfg_fn!(rustc_const_unstable))),
-    ("global_allocator", Normal, Gated(Stability::Unstable,
-                                       "global_allocator",
-                                       "the `#[global_allocator]` attribute is \
-                                        an experimental feature",
-                                       cfg_fn!(global_allocator))),
+    ("global_allocator", Normal, Ungated),
     ("default_lib_allocator", Whitelisted, Gated(Stability::Unstable,
                                             "allocator_internals",
                                             "the `#[default_lib_allocator]` \
diff --git a/src/test/compile-fail/allocator/auxiliary/system-allocator.rs b/src/test/compile-fail/allocator/auxiliary/system-allocator.rs
index 37e64ba7ea1..e5650d5b7b0 100644
--- a/src/test/compile-fail/allocator/auxiliary/system-allocator.rs
+++ b/src/test/compile-fail/allocator/auxiliary/system-allocator.rs
@@ -10,7 +10,6 @@
 
 // no-prefer-dynamic
 
-#![feature(global_allocator, allocator_api)]
 #![crate_type = "rlib"]
 
 use std::alloc::System;
diff --git a/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs b/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs
index 37e64ba7ea1..e5650d5b7b0 100644
--- a/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs
+++ b/src/test/compile-fail/allocator/auxiliary/system-allocator2.rs
@@ -10,7 +10,6 @@
 
 // no-prefer-dynamic
 
-#![feature(global_allocator, allocator_api)]
 #![crate_type = "rlib"]
 
 use std::alloc::System;
diff --git a/src/test/compile-fail/allocator/function-allocator.rs b/src/test/compile-fail/allocator/function-allocator.rs
index 50f82607b53..989c102b86e 100644
--- a/src/test/compile-fail/allocator/function-allocator.rs
+++ b/src/test/compile-fail/allocator/function-allocator.rs
@@ -8,7 +8,6 @@
 // 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
diff --git a/src/test/compile-fail/allocator/not-an-allocator.rs b/src/test/compile-fail/allocator/not-an-allocator.rs
index 140cad22f34..6559335960a 100644
--- a/src/test/compile-fail/allocator/not-an-allocator.rs
+++ b/src/test/compile-fail/allocator/not-an-allocator.rs
@@ -8,8 +8,6 @@
 // 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:
diff --git a/src/test/compile-fail/allocator/two-allocators.rs b/src/test/compile-fail/allocator/two-allocators.rs
index 5aa6b5d6777..7a97a11df20 100644
--- a/src/test/compile-fail/allocator/two-allocators.rs
+++ b/src/test/compile-fail/allocator/two-allocators.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(global_allocator, allocator_api)]
-
 use std::alloc::System;
 
 #[global_allocator]
diff --git a/src/test/compile-fail/allocator/two-allocators2.rs b/src/test/compile-fail/allocator/two-allocators2.rs
index ec5d985a943..e747140dfe5 100644
--- a/src/test/compile-fail/allocator/two-allocators2.rs
+++ b/src/test/compile-fail/allocator/two-allocators2.rs
@@ -12,8 +12,6 @@
 // no-prefer-dynamic
 // error-pattern: the #[global_allocator] in
 
-#![feature(global_allocator, allocator_api)]
-
 extern crate system_allocator;
 
 use std::alloc::System;
diff --git a/src/test/compile-fail/allocator/two-allocators3.rs b/src/test/compile-fail/allocator/two-allocators3.rs
index c310d94f6df..dd86b02bd20 100644
--- a/src/test/compile-fail/allocator/two-allocators3.rs
+++ b/src/test/compile-fail/allocator/two-allocators3.rs
@@ -13,7 +13,6 @@
 // no-prefer-dynamic
 // error-pattern: the #[global_allocator] in
 
-#![feature(global_allocator)]
 
 extern crate system_allocator;
 extern crate system_allocator2;
diff --git a/src/test/compile-fail/lint-stability-fields.rs b/src/test/compile-fail/lint-stability-fields.rs
index 1b605bdb893..b1b1a9a1fbf 100644
--- a/src/test/compile-fail/lint-stability-fields.rs
+++ b/src/test/compile-fail/lint-stability-fields.rs
@@ -18,6 +18,11 @@
 mod cross_crate {
     extern crate lint_stability_fields;
 
+    mod reexport {
+        #[stable(feature = "rust1", since = "1.0.0")]
+        pub use super::lint_stability_fields::*;
+    }
+
     use self::lint_stability_fields::*;
 
     pub fn foo() {
@@ -73,6 +78,8 @@ mod cross_crate {
             // the patterns are all fine:
             { .. } = x;
 
+        // Unstable items are still unstable even when used through a stable "pub use".
+        let x = reexport::Unstable2(1, 2, 3); //~ ERROR use of unstable
 
         let x = Unstable2(1, 2, 3); //~ ERROR use of unstable
 
diff --git a/src/test/run-make-fulldeps/std-core-cycle/bar.rs b/src/test/run-make-fulldeps/std-core-cycle/bar.rs
index 62fd2ade1ca..4b885e5e2bb 100644
--- a/src/test/run-make-fulldeps/std-core-cycle/bar.rs
+++ b/src/test/run-make-fulldeps/std-core-cycle/bar.rs
@@ -16,11 +16,11 @@ use std::alloc::*;
 pub struct A;
 
 unsafe impl GlobalAlloc for A {
-    unsafe fn alloc(&self, _: Layout) -> *mut Opaque {
+    unsafe fn alloc(&self, _: Layout) -> *mut u8 {
         loop {}
     }
 
-    unsafe fn dealloc(&self, _ptr: *mut Opaque, _: Layout) {
+    unsafe fn dealloc(&self, _ptr: *mut u8, _: Layout) {
         loop {}
     }
 }
diff --git a/src/test/run-make-fulldeps/std-core-cycle/foo.rs b/src/test/run-make-fulldeps/std-core-cycle/foo.rs
index 04742bba3c8..46047fb835d 100644
--- a/src/test/run-make-fulldeps/std-core-cycle/foo.rs
+++ b/src/test/run-make-fulldeps/std-core-cycle/foo.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(global_allocator)]
 #![crate_type = "cdylib"]
 
 extern crate bar;
diff --git a/src/test/run-pass-valgrind/issue-44800.rs b/src/test/run-pass-valgrind/issue-44800.rs
index cfde6f32f66..29cfae16929 100644
--- a/src/test/run-pass-valgrind/issue-44800.rs
+++ b/src/test/run-pass-valgrind/issue-44800.rs
@@ -8,11 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(global_allocator, alloc_system, allocator_api)]
-extern crate alloc_system;
-
+use std::alloc::System;
 use std::collections::VecDeque;
-use alloc_system::System;
 
 #[global_allocator]
 static ALLOCATOR: System = System;
diff --git a/src/test/run-pass/allocator/auxiliary/custom-as-global.rs b/src/test/run-pass/allocator/auxiliary/custom-as-global.rs
index 538f36faadf..a3f05a01c5a 100644
--- a/src/test/run-pass/allocator/auxiliary/custom-as-global.rs
+++ b/src/test/run-pass/allocator/auxiliary/custom-as-global.rs
@@ -10,7 +10,6 @@
 
 // no-prefer-dynamic
 
-#![feature(global_allocator)]
 #![crate_type = "rlib"]
 
 extern crate custom;
diff --git a/src/test/run-pass/allocator/auxiliary/custom.rs b/src/test/run-pass/allocator/auxiliary/custom.rs
index 91f70aa83e8..02e86fa19f8 100644
--- a/src/test/run-pass/allocator/auxiliary/custom.rs
+++ b/src/test/run-pass/allocator/auxiliary/custom.rs
@@ -13,18 +13,18 @@
 #![feature(heap_api, allocator_api)]
 #![crate_type = "rlib"]
 
-use std::alloc::{GlobalAlloc, System, Layout, Opaque};
+use std::alloc::{GlobalAlloc, System, Layout};
 use std::sync::atomic::{AtomicUsize, Ordering};
 
 pub struct A(pub AtomicUsize);
 
 unsafe impl GlobalAlloc for A {
-    unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
         self.0.fetch_add(1, Ordering::SeqCst);
         System.alloc(layout)
     }
 
-    unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
+    unsafe fn dealloc(&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/custom.rs b/src/test/run-pass/allocator/custom.rs
index 415d39a593e..3a7f8fa8620 100644
--- a/src/test/run-pass/allocator/custom.rs
+++ b/src/test/run-pass/allocator/custom.rs
@@ -11,11 +11,11 @@
 // aux-build:helper.rs
 // no-prefer-dynamic
 
-#![feature(global_allocator, heap_api, allocator_api)]
+#![feature(allocator_api)]
 
 extern crate helper;
 
-use std::alloc::{self, Global, Alloc, System, Layout, Opaque};
+use std::alloc::{self, Global, Alloc, System, Layout};
 use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
 
 static HITS: AtomicUsize = ATOMIC_USIZE_INIT;
@@ -23,12 +23,12 @@ static HITS: AtomicUsize = ATOMIC_USIZE_INIT;
 struct A;
 
 unsafe impl alloc::GlobalAlloc for A {
-    unsafe fn alloc(&self, layout: Layout) -> *mut Opaque {
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
         HITS.fetch_add(1, Ordering::SeqCst);
         System.alloc(layout)
     }
 
-    unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) {
+    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
         HITS.fetch_add(1, Ordering::SeqCst);
         System.dealloc(ptr, layout)
     }
diff --git a/src/test/run-pass/allocator/xcrate-use.rs b/src/test/run-pass/allocator/xcrate-use.rs
index 78d604a7108..482e3b04aae 100644
--- a/src/test/run-pass/allocator/xcrate-use.rs
+++ b/src/test/run-pass/allocator/xcrate-use.rs
@@ -12,7 +12,7 @@
 // aux-build:helper.rs
 // no-prefer-dynamic
 
-#![feature(global_allocator, heap_api, allocator_api)]
+#![feature(allocator_api)]
 
 extern crate custom;
 extern crate helper;
diff --git a/src/test/run-pass/allocator/xcrate-use2.rs b/src/test/run-pass/allocator/xcrate-use2.rs
index b8e844522dc..fbde7e855c2 100644
--- a/src/test/run-pass/allocator/xcrate-use2.rs
+++ b/src/test/run-pass/allocator/xcrate-use2.rs
@@ -19,7 +19,7 @@ extern crate custom;
 extern crate custom_as_global;
 extern crate helper;
 
-use std::alloc::{Global, Alloc, GlobalAlloc, System, Layout};
+use std::alloc::{alloc, dealloc, GlobalAlloc, System, Layout};
 use std::sync::atomic::{Ordering, ATOMIC_USIZE_INIT};
 
 static GLOBAL: custom::A = custom::A(ATOMIC_USIZE_INIT);
@@ -30,10 +30,10 @@ fn main() {
         let layout = Layout::from_size_align(4, 2).unwrap();
 
         // Global allocator routes to the `custom_as_global` global
-        let ptr = Global.alloc(layout.clone());
+        let ptr = alloc(layout.clone());
         helper::work_with(&ptr);
         assert_eq!(custom_as_global::get(), n + 1);
-        Global.dealloc(ptr, layout.clone());
+        dealloc(ptr, layout.clone());
         assert_eq!(custom_as_global::get(), n + 2);
 
         // Usage of the system allocator avoids all globals
diff --git a/src/test/run-pass/realloc-16687.rs b/src/test/run-pass/realloc-16687.rs
index febd249d776..7152e721eac 100644
--- a/src/test/run-pass/realloc-16687.rs
+++ b/src/test/run-pass/realloc-16687.rs
@@ -64,7 +64,7 @@ unsafe fn test_triangle() -> bool {
             println!("deallocate({:?}, {:?}", ptr, layout);
         }
 
-        Global.dealloc(NonNull::new_unchecked(ptr).as_opaque(), layout);
+        Global.dealloc(NonNull::new_unchecked(ptr), layout);
     }
 
     unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 {
@@ -72,7 +72,7 @@ unsafe fn test_triangle() -> bool {
             println!("reallocate({:?}, old={:?}, new={:?})", ptr, old, new);
         }
 
-        let ret = Global.realloc(NonNull::new_unchecked(ptr).as_opaque(), old, new.size())
+        let ret = Global.realloc(NonNull::new_unchecked(ptr), old, new.size())
             .unwrap_or_else(|_| oom(Layout::from_size_align_unchecked(new.size(), old.align())));
 
         if PRINT {
diff --git a/src/test/run-pass/thin-lto-global-allocator.rs b/src/test/run-pass/thin-lto-global-allocator.rs
index a0534ff6735..3a0e2fe01db 100644
--- a/src/test/run-pass/thin-lto-global-allocator.rs
+++ b/src/test/run-pass/thin-lto-global-allocator.rs
@@ -11,8 +11,6 @@
 // compile-flags: -Z thinlto -C codegen-units=2
 // min-llvm-version 4.0
 
-#![feature(allocator_api, global_allocator)]
-
 #[global_allocator]
 static A: std::alloc::System = std::alloc::System;
 
diff --git a/src/test/ui/feature-gate-global_allocator.rs b/src/test/ui/feature-gate-global_allocator.rs
deleted file mode 100644
index ff3c342f9e0..00000000000
--- a/src/test/ui/feature-gate-global_allocator.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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/ui/feature-gate-global_allocator.stderr b/src/test/ui/feature-gate-global_allocator.stderr
deleted file mode 100644
index 9f8b98ede09..00000000000
--- a/src/test/ui/feature-gate-global_allocator.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0658]: the `#[global_allocator]` attribute is an experimental feature (see issue #27389)
-  --> $DIR/feature-gate-global_allocator.rs:11:1
-   |
-LL | #[global_allocator] //~ ERROR: attribute is an experimental feature
-   | ^^^^^^^^^^^^^^^^^^^
-   |
-   = help: add #![feature(global_allocator)] to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.