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` 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 - } - - #[inline] - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { - __rust_dealloc(ptr as *mut u8, 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 - } - - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { - let ptr = __rust_alloc_zeroed(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()) } +/// 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()) +} + +/// 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) +} + +/// 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, AllocErr> { - NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + NonNull::new(alloc(layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { - GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + dealloc(ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) - -> Result, AllocErr> + -> Result, 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, AllocErr> { - NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, 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(ptr: Unique) { // We do not allocate for Box 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 Arc { 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 ArcFromSlice 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 Drop for Weak { 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 Root { self.as_mut().as_leaf_mut().parent = ptr::null(); unsafe { - Global.dealloc(NonNull::from(top).as_opaque(), Layout::new::>()); + Global.dealloc(NonNull::from(top).cast(), Layout::new::>()); } } } @@ -478,7 +478,7 @@ impl NodeRef { debug_assert!(!self.is_shared_root()); let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(node.as_opaque(), Layout::new::>()); + Global.dealloc(node.cast(), Layout::new::>()); ret } } @@ -499,7 +499,7 @@ impl NodeRef { > { let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(node.as_opaque(), Layout::new::>()); + Global.dealloc(node.cast(), Layout::new::>()); ret } } @@ -1321,12 +1321,12 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } Global.dealloc( - right_node.node.as_opaque(), + right_node.node.cast(), Layout::new::>(), ); } else { Global.dealloc( - right_node.node.as_opaque(), + right_node.node.cast(), Layout::new::>(), ); } 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 or the MIT license -// , 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; - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result; - 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 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 { - 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 { - 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 RawVec { // handles ZSTs and `cap = 0` alike let ptr = if alloc_size == 0 { - NonNull::::dangling().as_opaque() + NonNull::::dangling() } else { let align = mem::align_of::(); let layout = Layout::from_size_align(alloc_size, align).unwrap(); @@ -103,13 +103,13 @@ impl RawVec { 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 RawVec { 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 RawVec { 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 RawVec { // 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 RawVec { let new_size = elem_size * amount; let align = mem::align_of::(); 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 RawVec { 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 RawVec { let elem_size = mem::size_of::(); 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, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, 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, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, 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 RcFromSlice 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 { - mem: NonNull, + mem: NonNull, elems: *mut T, layout: Layout, n_elems: usize, @@ -755,7 +755,7 @@ impl RcFromSlice 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 { 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 Drop for Weak { // 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, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, 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`. - /// 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, pub usize); +pub struct Excess(pub NonNull, pub usize); fn size_align() -> (usize, usize) { (mem::size_of::(), mem::align_of::()) @@ -64,6 +46,7 @@ fn size_align() -> (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 { 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() -> Self { let (size, align) = size_align::(); @@ -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: &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 { 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(n: usize) -> Result { Layout::new::() @@ -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 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::()).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: /// - /// **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 { + /// * `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. + /// + /// [`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, 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, 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, layout: Layout); + unsafe fn dealloc(&mut self, ptr: NonNull, 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, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, 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, 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, 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 { 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, + ptr: NonNull, layout: Layout, new_size: usize) -> Result { 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, + ptr: NonNull, 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, + ptr: NonNull, 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(&mut self) -> Result, AllocErr> where Self: Sized { @@ -978,7 +1127,7 @@ pub unsafe trait Alloc { { let k = Layout::new::(); 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(&mut self, n: usize) -> Result, 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(&mut self, ptr: NonNull, n_old: usize, @@ -1066,7 +1219,7 @@ pub unsafe trait Alloc { match (Layout::array::(n_old), Layout::array::(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::(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 NonNull { 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 { - 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` and `Vec`. +//! +//! 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 { let (layout, _) = calculate_layout::(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 or the MIT license -// , 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`.