summaryrefslogtreecommitdiff
path: root/src/libcore/alloc
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-07-27 17:39:01 +0000
committerbors <bors@rust-lang.org>2020-07-27 17:39:01 +0000
commit54e000891ffccd4cbfb92146b92736c83085df63 (patch)
tree1200bb13eb9ae22def4c43bc657bc56da8faedc6 /src/libcore/alloc
parent4a90e36c85336d1d4b209556c1a9733210bbff19 (diff)
parent6d9705220fec4553d693a7c19d99496e14c89edf (diff)
downloadrust-tmp-nightly.tar.gz
Auto merge of #73265 - mark-i-m:mv-std, r=<try>tmp-nightly
mv std libs to library/ This is the first step in refactoring the directory layout of this repository, with further followup steps planned (but not done yet). Background: currently, all crates are under src/, without nested src directories and with the unconventional `lib*` prefixes (e.g., `src/libcore/lib.rs`). This directory structures is not idiomatic and makes the `src/` directory rather overwhelming. To improve contributor experience and make things a bit more approachable, we are reorganizing the repo a bit. In this PR, we move the standard libs (basically anything that is "runtime", as opposed to part of the compiler, build system, or one of the tools, etc). The new layout moves these libraries to a new `library/` directory in the root of the repo. Additionally, we remove the `lib*` prefixes and add nested `src/` directories. The other crates/tools in this repo are not touched. So in summary: ``` library/<crate>/src/*.rs src/<all the rest> // unchanged ``` where `<crate>` is: - core - alloc - std - test - proc_macro - panic_abort - panic_unwind - profiler_builtins - term - unwind - rtstartup - backtrace - rustc-std-workspace-* There was a lot of discussion about this and a few rounds of compiler team approvals, FCPs, MCPs, and nominations. The original MCP is https://github.com/rust-lang/compiler-team/issues/298. The final approval of the compiler team was given here: https://github.com/rust-lang/rust/pull/73265#issuecomment-659498446. The name `library` was chosen to complement a later move of the compiler crates to a `compiler/` directory. There was a lot of discussion around adding the nested `src/` directories. Note that this does increase the nesting depth (plausibly important for manual traversal of the tree, e.g., through GitHub's UI or `cd`), but this is deemed to be better as it fits the standard layout of Rust crates throughout most of the ecosystem, though there is some debate about how much this should apply to multi-crate projects. Overall, there seem to be more people in favor of nested `src/` than against. After this PR, there are no dependencies out of the `library/` directory except on the `build_helper` (or crates.io crates).
Diffstat (limited to 'src/libcore/alloc')
-rw-r--r--src/libcore/alloc/global.rs208
-rw-r--r--src/libcore/alloc/layout.rs410
-rw-r--r--src/libcore/alloc/mod.rs446
3 files changed, 0 insertions, 1064 deletions
diff --git a/src/libcore/alloc/global.rs b/src/libcore/alloc/global.rs
deleted file mode 100644
index c198797e650..00000000000
--- a/src/libcore/alloc/global.rs
+++ /dev/null
@@ -1,208 +0,0 @@
-use crate::alloc::Layout;
-use crate::cmp;
-use crate::ptr;
-
-/// A memory allocator that can be registered as the standard library’s default
-/// through the `#[global_allocator]` attribute.
-///
-/// 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())
-/// }
-/// }
-/// ```
-///
-/// # Safety
-///
-/// 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.
- ///
- /// # Safety
- ///
- /// 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 this 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 [`handle_alloc_error`] function,
- /// rather than directly invoking `panic!` or similar.
- ///
- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.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
- ///
- /// 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 allocate that block of memory,
- #[stable(feature = "global_alloc", since = "1.28.0")]
- unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
-
- /// 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 [`handle_alloc_error`] function,
- /// rather than directly invoking `panic!` or similar.
- ///
- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
- #[stable(feature = "global_alloc", since = "1.28.0")]
- unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
- let size = layout.size();
- // SAFETY: the safety contract for `alloc` must be upheld by the caller.
- let ptr = unsafe { self.alloc(layout) };
- if !ptr.is_null() {
- // SAFETY: as allocation succeeded, the region from `ptr`
- // of size `size` is guaranteed to be valid for writes.
- unsafe { ptr::write_bytes(ptr, 0, size) };
- }
- ptr
- }
-
- /// Shrink or grow a block of memory to the given `new_size`.
- /// The block is described by the given `ptr` pointer and `layout`.
- ///
- /// If this returns a non-null pointer, then ownership of the memory block
- /// referenced by `ptr` has been transferred to this allocator.
- /// 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). The new memory block is allocated with `layout`, but
- /// with the `size` updated to `new_size`.
- ///
- /// 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
- ///
- /// 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 allocate 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 [`handle_alloc_error`] function,
- /// rather than directly invoking `panic!` or similar.
- ///
- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
- #[stable(feature = "global_alloc", since = "1.28.0")]
- unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
- // SAFETY: the caller must ensure that the `new_size` does not overflow.
- // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid.
- let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
- // SAFETY: the caller must ensure that `new_layout` is greater than zero.
- let new_ptr = unsafe { self.alloc(new_layout) };
- if !new_ptr.is_null() {
- // SAFETY: the previously allocated block cannot overlap the newly allocated block.
- // The safety contract for `dealloc` must be upheld by the caller.
- unsafe {
- ptr::copy_nonoverlapping(ptr, new_ptr, cmp::min(layout.size(), new_size));
- self.dealloc(ptr, layout);
- }
- }
- new_ptr
- }
-}
diff --git a/src/libcore/alloc/layout.rs b/src/libcore/alloc/layout.rs
deleted file mode 100644
index 7129f0f2402..00000000000
--- a/src/libcore/alloc/layout.rs
+++ /dev/null
@@ -1,410 +0,0 @@
-use crate::cmp;
-use crate::fmt;
-use crate::mem;
-use crate::num::NonZeroUsize;
-use crate::ptr::NonNull;
-
-const fn size_align<T>() -> (usize, usize) {
- (mem::size_of::<T>(), mem::align_of::<T>())
-}
-
-/// Layout of a block of memory.
-///
-/// An instance of `Layout` describes a particular layout of memory.
-/// You build a `Layout` up as an input to give to an allocator.
-///
-/// All layouts have an associated size and a power-of-two alignment.
-///
-/// (Note that layouts are *not* required to have non-zero size,
-/// even though `GlobalAlloc` requires that all memory requests
-/// be non-zero in size. A caller must either ensure that conditions
-/// like this are met, use specific allocators with looser
-/// requirements, or use the more lenient `AllocRef` interface.)
-#[stable(feature = "alloc_layout", since = "1.28.0")]
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-#[lang = "alloc_layout"]
-pub struct Layout {
- // size of the requested block of memory, measured in bytes.
- size_: usize,
-
- // alignment of the requested block of memory, measured in bytes.
- // we ensure that this is always a power-of-two, because API's
- // like `posix_memalign` require it and it is a reasonable
- // constraint to impose on Layout constructors.
- //
- // (However, we do not analogously require `align >= sizeof(void*)`,
- // even though that is *also* a requirement of `posix_memalign`.)
- align_: NonZeroUsize,
-}
-
-impl Layout {
- /// Constructs a `Layout` from a given `size` and `align`,
- /// or returns `LayoutErr` if any of the following conditions
- /// are not met:
- ///
- /// * `align` must not be zero,
- ///
- /// * `align` must be a power of two,
- ///
- /// * `size`, when rounded up to the nearest multiple of `align`,
- /// must not overflow (i.e., the rounded value must be less than
- /// or equal to `usize::MAX`).
- #[stable(feature = "alloc_layout", since = "1.28.0")]
- #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
- #[inline]
- pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
- if !align.is_power_of_two() {
- return Err(LayoutErr { private: () });
- }
-
- // (power-of-two implies align != 0.)
-
- // Rounded up size is:
- // size_rounded_up = (size + align - 1) & !(align - 1);
- //
- // We know from above that align != 0. If adding (align - 1)
- // does not overflow, then rounding up will be fine.
- //
- // Conversely, &-masking with !(align - 1) will subtract off
- // only low-order-bits. Thus if overflow occurs with the sum,
- // the &-mask cannot subtract enough to undo that overflow.
- //
- // Above implies that checking for summation overflow is both
- // necessary and sufficient.
- if size > usize::MAX - (align - 1) {
- return Err(LayoutErr { private: () });
- }
-
- // SAFETY: the conditions for `from_size_align_unchecked` have been
- // checked above.
- unsafe { Ok(Layout::from_size_align_unchecked(size, align)) }
- }
-
- /// Creates a layout, bypassing all checks.
- ///
- /// # Safety
- ///
- /// 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")]
- #[rustc_const_stable(feature = "alloc_layout", since = "1.28.0")]
- #[inline]
- pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
- // SAFETY: the caller must ensure that `align` is greater than zero.
- Layout { size_: size, align_: unsafe { NonZeroUsize::new_unchecked(align) } }
- }
-
- /// The minimum size in bytes for a memory block of this layout.
- #[stable(feature = "alloc_layout", since = "1.28.0")]
- #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
- #[inline]
- pub const 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")]
- #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
- #[inline]
- pub const 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")]
- #[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")]
- #[inline]
- pub const fn new<T>() -> Self {
- let (size, align) = size_align::<T>();
- // SAFETY: the align is guaranteed by Rust to be a power of two and
- // the size+align combo is guaranteed to fit in our address space. As a
- // result use the unchecked constructor here to avoid inserting code
- // that panics if it isn't optimized well enough.
- unsafe { Layout::from_size_align_unchecked(size, align) }
- }
-
- /// 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));
- debug_assert!(Layout::from_size_align(size, align).is_ok());
- // SAFETY: see rationale in `new` for why this is using the unsafe variant
- unsafe { Layout::from_size_align_unchecked(size, align) }
- }
-
- /// 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).
- ///
- /// # Safety
- ///
- /// This function is only safe to call if the following conditions hold:
- ///
- /// - If `T` is `Sized`, this function is always safe to call.
- /// - If the unsized tail of `T` is:
- /// - a [slice], then the length of the slice tail must be an intialized
- /// integer, and the size of the *entire value*
- /// (dynamic tail length + statically sized prefix) must fit in `isize`.
- /// - a [trait object], then the vtable part of the pointer must point
- /// to a valid vtable for the type `T` acquired by an unsizing coersion,
- /// and the size of the *entire value*
- /// (dynamic tail length + statically sized prefix) must fit in `isize`.
- /// - an (unstable) [extern type], then this function is always safe to
- /// call, but may panic or otherwise return the wrong value, as the
- /// extern type's layout is not known. This is the same behavior as
- /// [`Layout::for_value`] on a reference to an extern type tail.
- /// - otherwise, it is conservatively not allowed to call this function.
- ///
- /// [slice]: ../../std/primitive.slice.html
- /// [trait object]: ../../book/ch17-02-trait-objects.html
- /// [extern type]: ../../unstable-book/language-features/extern-types.html
- #[unstable(feature = "layout_for_ptr", issue = "69835")]
- pub unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
- // SAFETY: we pass along the prerequisites of these functions to the caller
- let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) };
- debug_assert!(Layout::from_size_align(size, align).is_ok());
- // SAFETY: see rationale in `new` for why this is using the unsafe variant
- unsafe { Layout::from_size_align_unchecked(size, align) }
- }
-
- /// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
- ///
- /// Note that the pointer value may potentially represent a valid pointer,
- /// which means this must not be used as a "not yet initialized"
- /// sentinel value. Types that lazily allocate must track initialization by
- /// some other means.
- #[unstable(feature = "alloc_layout_extra", issue = "55724")]
- #[inline]
- pub const fn dangling(&self) -> NonNull<u8> {
- // SAFETY: align is guaranteed to be non-zero
- unsafe { NonNull::new_unchecked(self.align() as *mut u8) }
- }
-
- /// Creates a layout describing the record that can hold a value
- /// of the same layout as `self`, but that also is aligned to
- /// alignment `align` (measured in bytes).
- ///
- /// If `self` already meets the prescribed alignment, then returns
- /// `self`.
- ///
- /// Note that this method does not add any padding to the overall
- /// size, regardless of whether the returned layout has a different
- /// alignment. In other words, if `K` has size 16, `K.align_to(32)`
- /// will *still* have size 16.
- ///
- /// Returns an error if the combination of `self.size()` and the given
- /// `align` violates the conditions listed in
- /// [`Layout::from_size_align`](#method.from_size_align).
- #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
- #[inline]
- pub fn align_to(&self, align: usize) -> Result<Self, LayoutErr> {
- Layout::from_size_align(self.size(), cmp::max(self.align(), align))
- }
-
- /// Returns the amount of padding we must insert after `self`
- /// to ensure that the following address will satisfy `align`
- /// (measured in bytes).
- ///
- /// e.g., if `self.size()` is 9, then `self.padding_needed_for(4)`
- /// returns 3, because that is the minimum number of bytes of
- /// padding required to get a 4-aligned address (assuming that the
- /// corresponding memory block starts at a 4-aligned address).
- ///
- /// The return value of this function has no meaning if `align` is
- /// not a power-of-two.
- ///
- /// Note that the utility of the returned value requires `align`
- /// 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 = "alloc_layout_extra", issue = "55724")]
- #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
- #[inline]
- pub const fn padding_needed_for(&self, align: usize) -> usize {
- let len = self.size();
-
- // Rounded up value is:
- // len_rounded_up = (len + align - 1) & !(align - 1);
- // and then we return the padding difference: `len_rounded_up - len`.
- //
- // We use modular arithmetic throughout:
- //
- // 1. align is guaranteed to be > 0, so align - 1 is always
- // valid.
- //
- // 2. `len + align - 1` can overflow by at most `align - 1`,
- // so the &-mask with `!(align - 1)` will ensure that in the
- // case of overflow, `len_rounded_up` will itself be 0.
- // Thus the returned padding, when added to `len`, yields 0,
- // which trivially satisfies the alignment `align`.
- //
- // (Of course, attempts to allocate blocks of memory whose
- // size and padding overflow in the above manner should cause
- // the allocator to yield an error anyway.)
-
- let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
- len_rounded_up.wrapping_sub(len)
- }
-
- /// Creates a layout by rounding the size of this layout up to a multiple
- /// of the layout's alignment.
- ///
- /// This is equivalent to adding the result of `padding_needed_for`
- /// to the layout's current size.
- #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
- #[inline]
- pub fn pad_to_align(&self) -> Layout {
- let pad = self.padding_needed_for(self.align());
- // This cannot overflow. Quoting from the invariant of 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`)
- let new_size = self.size() + pad;
-
- Layout::from_size_align(new_size, self.align()).unwrap()
- }
-
- /// Creates a layout describing the record for `n` instances of
- /// `self`, with a suitable amount of padding between each to
- /// ensure that each instance is given its requested size and
- /// alignment. On success, returns `(k, offs)` where `k` is the
- /// layout of the array and `offs` is the distance between the start
- /// of each element in the array.
- ///
- /// On arithmetic overflow, returns `LayoutErr`.
- #[unstable(feature = "alloc_layout_extra", issue = "55724")]
- #[inline]
- pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
- // This cannot overflow. Quoting from the invariant of 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`)
- let padded_size = self.size() + self.padding_needed_for(self.align());
- let alloc_size = padded_size.checked_mul(n).ok_or(LayoutErr { private: () })?;
-
- // SAFETY: self.align is already known to be valid and alloc_size has been
- // padded already.
- unsafe { Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size)) }
- }
-
- /// Creates a layout describing the record for `self` followed by
- /// `next`, including any necessary padding to ensure that `next`
- /// will be properly aligned, but *no trailing padding*.
- ///
- /// In order to match C representation layout `repr(C)`, you should
- /// call `pad_to_align` after extending the layout with all fields.
- /// (There is no way to match the default Rust representation
- /// layout `repr(Rust)`, as it is unspecified.)
- ///
- /// Note that the alignment of the resulting layout will be the maximum of
- /// those of `self` and `next`, in order to ensure alignment of both parts.
- ///
- /// Returns `Ok((k, offset))`, where `k` is layout of the concatenated
- /// record and `offset` is the relative location, in bytes, of the
- /// start of the `next` embedded within the concatenated record
- /// (assuming that the record itself starts at offset 0).
- ///
- /// On arithmetic overflow, returns `LayoutErr`.
- ///
- /// # Examples
- ///
- /// To calculate the layout of a `#[repr(C)]` structure and the offsets of
- /// the fields from its fields' layouts:
- ///
- /// ```rust
- /// # use std::alloc::{Layout, LayoutErr};
- /// pub fn repr_c(fields: &[Layout]) -> Result<(Layout, Vec<usize>), LayoutErr> {
- /// let mut offsets = Vec::new();
- /// let mut layout = Layout::from_size_align(0, 1)?;
- /// for &field in fields {
- /// let (new_layout, offset) = layout.extend(field)?;
- /// layout = new_layout;
- /// offsets.push(offset);
- /// }
- /// // Remember to finalize with `pad_to_align`!
- /// Ok((layout.pad_to_align(), offsets))
- /// }
- /// # // test that it works
- /// # #[repr(C)] struct S { a: u64, b: u32, c: u16, d: u32 }
- /// # let s = Layout::new::<S>();
- /// # let u16 = Layout::new::<u16>();
- /// # let u32 = Layout::new::<u32>();
- /// # let u64 = Layout::new::<u64>();
- /// # assert_eq!(repr_c(&[u64, u32, u16, u32]), Ok((s, vec![0, 8, 12, 16])));
- /// ```
- #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
- #[inline]
- pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
- let new_align = cmp::max(self.align(), next.align());
- let pad = self.padding_needed_for(next.align());
-
- let offset = self.size().checked_add(pad).ok_or(LayoutErr { private: () })?;
- let new_size = offset.checked_add(next.size()).ok_or(LayoutErr { private: () })?;
-
- let layout = Layout::from_size_align(new_size, new_align)?;
- Ok((layout, offset))
- }
-
- /// Creates a layout describing the record for `n` instances of
- /// `self`, with no padding between each instance.
- ///
- /// Note that, unlike `repeat`, `repeat_packed` does not guarantee
- /// that the repeated instances of `self` will be properly
- /// aligned, even if a given instance of `self` is properly
- /// aligned. In other words, if the layout returned by
- /// `repeat_packed` is used to allocate an array, it is not
- /// guaranteed that all elements in the array will be properly
- /// aligned.
- ///
- /// On arithmetic overflow, returns `LayoutErr`.
- #[unstable(feature = "alloc_layout_extra", issue = "55724")]
- #[inline]
- pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutErr> {
- let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?;
- Layout::from_size_align(size, self.align())
- }
-
- /// Creates a layout describing the record for `self` followed by
- /// `next` with no additional padding between the two. Since no
- /// padding is inserted, the alignment of `next` is irrelevant,
- /// and is not incorporated *at all* into the resulting layout.
- ///
- /// On arithmetic overflow, returns `LayoutErr`.
- #[unstable(feature = "alloc_layout_extra", issue = "55724")]
- #[inline]
- pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutErr> {
- let new_size = self.size().checked_add(next.size()).ok_or(LayoutErr { private: () })?;
- Layout::from_size_align(new_size, self.align())
- }
-
- /// Creates a layout describing the record for a `[T; n]`.
- ///
- /// On arithmetic overflow, returns `LayoutErr`.
- #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
- #[inline]
- pub fn array<T>(n: usize) -> Result<Self, LayoutErr> {
- let (layout, offset) = Layout::new::<T>().repeat(n)?;
- debug_assert_eq!(offset, mem::size_of::<T>());
- Ok(layout.pad_to_align())
- }
-}
-
-/// 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")
- }
-}
diff --git a/src/libcore/alloc/mod.rs b/src/libcore/alloc/mod.rs
deleted file mode 100644
index be4e051b1ca..00000000000
--- a/src/libcore/alloc/mod.rs
+++ /dev/null
@@ -1,446 +0,0 @@
-//! Memory allocation APIs
-
-#![stable(feature = "alloc_module", since = "1.28.0")]
-
-mod global;
-mod layout;
-
-#[stable(feature = "global_alloc", since = "1.28.0")]
-pub use self::global::GlobalAlloc;
-#[stable(feature = "alloc_layout", since = "1.28.0")]
-pub use self::layout::{Layout, LayoutErr};
-
-use crate::fmt;
-use crate::ptr::{self, NonNull};
-
-/// 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(Copy, 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")
- }
-}
-
-/// A desired initial state for allocated memory.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[unstable(feature = "allocator_api", issue = "32838")]
-pub enum AllocInit {
- /// The contents of the new memory are uninitialized.
- Uninitialized,
- /// The new memory is guaranteed to be zeroed.
- Zeroed,
-}
-
-impl AllocInit {
- /// Initialize the specified memory block.
- ///
- /// This behaves like calling [`AllocInit::init_offset(memory, 0)`][off].
- ///
- /// [off]: AllocInit::init_offset
- ///
- /// # Safety
- ///
- /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
- ///
- /// [valid]: ../../core/ptr/index.html#safety
- #[inline]
- #[unstable(feature = "allocator_api", issue = "32838")]
- pub unsafe fn init(self, memory: MemoryBlock) {
- // SAFETY: the safety contract for `init_offset` must be
- // upheld by the caller.
- unsafe { self.init_offset(memory, 0) }
- }
-
- /// Initialize the memory block like specified by `init` at the specified `offset`.
- ///
- /// This is a no-op for [`AllocInit::Uninitialized`][] and writes zeroes for
- /// [`AllocInit::Zeroed`][] at `ptr + offset` until `ptr + layout.size()`.
- ///
- /// # Safety
- ///
- /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
- /// * `offset` must be smaller than or equal to `memory.size`
- ///
- /// [valid]: ../../core/ptr/index.html#safety
- #[inline]
- #[unstable(feature = "allocator_api", issue = "32838")]
- pub unsafe fn init_offset(self, memory: MemoryBlock, offset: usize) {
- debug_assert!(
- offset <= memory.size,
- "`offset` must be smaller than or equal to `memory.size`"
- );
- match self {
- AllocInit::Uninitialized => (),
- AllocInit::Zeroed => {
- // SAFETY: the caller must guarantee that `offset` is smaller than or equal to `memory.size`,
- // so the memory from `memory.ptr + offset` of length `memory.size - offset`
- // is guaranteed to be contaned in `memory` and thus valid for writes.
- unsafe { memory.ptr.as_ptr().add(offset).write_bytes(0, memory.size - offset) }
- }
- }
- }
-}
-
-/// Represents a block of allocated memory returned by an allocator.
-#[derive(Debug, Copy, Clone)]
-#[unstable(feature = "allocator_api", issue = "32838")]
-pub struct MemoryBlock {
- pub ptr: NonNull<u8>,
- pub size: usize,
-}
-
-/// A placement constraint when growing or shrinking an existing allocation.
-#[derive(Debug, Copy, Clone, PartialEq, Eq)]
-#[unstable(feature = "allocator_api", issue = "32838")]
-pub enum ReallocPlacement {
- /// The allocator is allowed to move the allocation to a different memory address.
- // FIXME(wg-allocators#46): Add a section to the module documentation "What is a legal
- // allocator" and link it at "valid location".
- ///
- /// If the allocation _does_ move, it's the responsibility of the allocator
- /// to also move the data from the previous location to the new location.
- MayMove,
- /// The address of the new memory must not change.
- ///
- /// If the allocation would have to be moved to a new location to fit, the
- /// reallocation request will fail.
- InPlace,
-}
-
-/// An implementation of `AllocRef` can allocate, grow, shrink, and deallocate arbitrary blocks of
-/// data described via [`Layout`][].
-///
-/// `AllocRef` is designed to be implemented on ZSTs, references, or smart pointers because having
-/// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
-/// allocated memory.
-///
-/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `AllocRef`. If an underlying
-/// allocator does not support this (like jemalloc) or return a null pointer (such as
-/// `libc::malloc`), this must be caught by the implementation.
-///
-/// ### Currently allocated memory
-///
-/// 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 [`alloc`], [`grow`], or
-/// [`shrink`], and
-///
-/// * the memory block has not been subsequently deallocated, where blocks are either deallocated
-/// directly by being passed to [`dealloc`] or were changed by being passed to [`grow`] or
-/// [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer
-/// remains valid.
-///
-/// [`alloc`]: AllocRef::alloc
-/// [`grow`]: AllocRef::grow
-/// [`shrink`]: AllocRef::shrink
-/// [`dealloc`]: AllocRef::dealloc
-///
-/// ### Memory fitting
-///
-/// Some of the methods require that a layout *fit* a memory block. What it means for a layout to
-/// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the
-/// following conditions must hold:
-///
-/// * The block must be allocated with the same alignment as [`layout.align()`], and
-///
-/// * The provided [`layout.size()`] must fall in the range `min ..= max`, where:
-/// - `min` is the size of the layout most recently used to allocate the block, and
-/// - `max` is the latest actual size returned from [`alloc`], [`grow`], or [`shrink`].
-///
-/// [`layout.align()`]: Layout::align
-/// [`layout.size()`]: Layout::size
-///
-/// # Safety
-///
-/// * Memory blocks returned from an allocator must point to valid memory and retain their validity
-/// until the instance and all of its clones are dropped,
-///
-/// * cloning or moving the allocator must not invalidate memory blocks returned from this
-/// allocator. A cloned allocator must behave like the same allocator, and
-///
-/// * any pointer to a memory block which is [*currently allocated*] may be passed to any other
-/// method of the allocator.
-///
-/// [*currently allocated*]: #currently-allocated-memory
-#[unstable(feature = "allocator_api", issue = "32838")]
-pub unsafe trait AllocRef {
- /// Attempts to allocate a block of memory.
- ///
- /// On success, returns a [`MemoryBlock`][] meeting the size and alignment guarantees of `layout`.
- ///
- /// The returned block may have a larger size than specified by `layout.size()` and is
- /// initialized as specified by [`init`], all the way up to the returned size of the block.
- ///
- /// [`init`]: AllocInit
- ///
- /// # Errors
- ///
- /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
- /// allocator's size or alignment constraints.
- ///
- /// Implementations are encouraged to return `Err` 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 an allocation error are encouraged to
- /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
- ///
- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
- fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr>;
-
- /// Deallocates the memory referenced by `ptr`.
- ///
- /// # Safety
- ///
- /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, and
- /// * `layout` must [*fit*] that block of memory.
- ///
- /// [*currently allocated*]: #currently-allocated-memory
- /// [*fit*]: #memory-fitting
- unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);
-
- /// Attempts to extend the memory block.
- ///
- /// Returns a new [`MemoryBlock`][] containing a pointer and the actual size of the allocated
- /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s
- /// alignment and a size given by `new_size`. To accomplish this, the allocator may extend the
- /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
- /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
- ///
- /// If [`MayMove`] is used then ownership of the memory block referenced by `ptr`
- /// is transferred to this allocator. The memory may or may not be freed, and should be
- /// considered unusable (unless of course it is transferred back to the caller again via the
- /// return value of this method).
- ///
- /// If this method returns `Err`, then ownership of the memory block has not been transferred to
- /// this allocator, and the contents of the memory block are unaltered.
- ///
- /// The memory block will contain the following contents after a successful call to `grow`:
- /// * Bytes `0..layout.size()` are preserved from the original allocation.
- /// * Bytes `layout.size()..old_size` will either be preserved or initialized according to
- /// [`init`], depending on the allocator implementation. `old_size` refers to the size of
- /// the `MemoryBlock` prior to the `grow` call, which may be larger than the size
- /// that was originally requested when it was allocated.
- /// * Bytes `old_size..new_size` are initialized according to [`init`]. `new_size` refers to
- /// the size of the `MemoryBlock` returned by the `grow` call.
- ///
- /// [`InPlace`]: ReallocPlacement::InPlace
- /// [`MayMove`]: ReallocPlacement::MayMove
- /// [`placement`]: ReallocPlacement
- /// [`init`]: AllocInit
- ///
- /// # Safety
- ///
- /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator,
- /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.),
- // We can't require that `new_size` is strictly greater than `memory.size` because of ZSTs.
- // An alternative would be
- // * `new_size must be strictly greater than `memory.size` or both are zero
- /// * `new_size` must be greater than or equal to `layout.size()`, and
- /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow
- /// (i.e., the rounded value must be less than or equal to `usize::MAX`).
- ///
- /// [*currently allocated*]: #currently-allocated-memory
- /// [*fit*]: #memory-fitting
- ///
- /// # Errors
- ///
- /// Returns `Err` if the new layout does not meet the allocator's size and alignment
- /// constraints of the allocator, or if growing otherwise fails.
- ///
- /// Implementations are encouraged to return `Err` 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 an allocation error are encouraged to
- /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
- ///
- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
- unsafe fn grow(
- &mut self,
- ptr: NonNull<u8>,
- layout: Layout,
- new_size: usize,
- placement: ReallocPlacement,
- init: AllocInit,
- ) -> Result<MemoryBlock, AllocErr> {
- match placement {
- ReallocPlacement::InPlace => Err(AllocErr),
- ReallocPlacement::MayMove => {
- let size = layout.size();
- debug_assert!(
- new_size >= size,
- "`new_size` must be greater than or equal to `layout.size()`"
- );
-
- if new_size == size {
- return Ok(MemoryBlock { ptr, size });
- }
-
- let new_layout =
- // SAFETY: the caller must ensure that the `new_size` does not overflow.
- // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout.
- // The caller must ensure that `new_size` is greater than zero.
- unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
- let new_memory = self.alloc(new_layout, init)?;
-
- // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new
- // memory allocation are valid for reads and writes for `size` bytes. Also, because the old
- // allocation wasn't yet deallocated, it cannot overlap `new_memory`. Thus, the call to
- // `copy_nonoverlapping` is safe.
- // The safety contract for `dealloc` must be upheld by the caller.
- unsafe {
- ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), size);
- self.dealloc(ptr, layout);
- Ok(new_memory)
- }
- }
- }
- }
-
- /// Attempts to shrink the memory block.
- ///
- /// Returns a new [`MemoryBlock`][] containing a pointer and the actual size of the allocated
- /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s
- /// alignment and a size given by `new_size`. To accomplish this, the allocator may shrink the
- /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
- /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
- ///
- /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
- /// transferred to this allocator. The memory may or may not have been freed, and should be
- /// considered unusable unless it was transferred back to the caller again via the
- /// return value of this method.
- ///
- /// If this method returns `Err`, then ownership of the memory block has not been transferred to
- /// this allocator, and the contents of the memory block are unaltered.
- ///
- /// The behavior of how the allocator tries to shrink the memory is specified by [`placement`].
- ///
- /// [`InPlace`]: ReallocPlacement::InPlace
- /// [`placement`]: ReallocPlacement
- ///
- /// # Safety
- ///
- /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator,
- /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), and
- // We can't require that `new_size` is strictly smaller than `memory.size` because of ZSTs.
- // An alternative would be
- // * `new_size must be strictly smaller than `memory.size` or both are zero
- /// * `new_size` must be smaller than or equal to `layout.size()`.
- ///
- /// [*currently allocated*]: #currently-allocated-memory
- /// [*fit*]: #memory-fitting
- ///
- /// # Errors
- ///
- /// Returns `Err` if the new layout does not meet the allocator's size and alignment
- /// constraints of the allocator, or if shrinking otherwise fails.
- ///
- /// Implementations are encouraged to return `Err` 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 an allocation error are encouraged to
- /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
- ///
- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
- unsafe fn shrink(
- &mut self,
- ptr: NonNull<u8>,
- layout: Layout,
- new_size: usize,
- placement: ReallocPlacement,
- ) -> Result<MemoryBlock, AllocErr> {
- match placement {
- ReallocPlacement::InPlace => Err(AllocErr),
- ReallocPlacement::MayMove => {
- let size = layout.size();
- debug_assert!(
- new_size <= size,
- "`new_size` must be smaller than or equal to `layout.size()`"
- );
-
- if new_size == size {
- return Ok(MemoryBlock { ptr, size });
- }
-
- let new_layout =
- // SAFETY: the caller must ensure that the `new_size` does not overflow.
- // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout.
- // The caller must ensure that `new_size` is greater than zero.
- unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
- let new_memory = self.alloc(new_layout, AllocInit::Uninitialized)?;
-
- // SAFETY: because `new_size` must be lower than or equal to `size`, both the old and new
- // memory allocation are valid for reads and writes for `new_size` bytes. Also, because the
- // old allocation wasn't yet deallocated, it cannot overlap `new_memory`. Thus, the call to
- // `copy_nonoverlapping` is safe.
- // The safety contract for `dealloc` must be upheld by the caller.
- unsafe {
- ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), new_size);
- self.dealloc(ptr, layout);
- Ok(new_memory)
- }
- }
- }
- }
-
- /// Creates a "by reference" adaptor for this instance of `AllocRef`.
- ///
- /// The returned adaptor also implements `AllocRef` and will simply borrow this.
- #[inline(always)]
- fn by_ref(&mut self) -> &mut Self {
- self
- }
-}
-
-#[unstable(feature = "allocator_api", issue = "32838")]
-unsafe impl<A> AllocRef for &mut A
-where
- A: AllocRef + ?Sized,
-{
- #[inline]
- fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
- (**self).alloc(layout, init)
- }
-
- #[inline]
- unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
- // SAFETY: the safety contract must be upheld by the caller
- unsafe { (**self).dealloc(ptr, layout) }
- }
-
- #[inline]
- unsafe fn grow(
- &mut self,
- ptr: NonNull<u8>,
- layout: Layout,
- new_size: usize,
- placement: ReallocPlacement,
- init: AllocInit,
- ) -> Result<MemoryBlock, AllocErr> {
- // SAFETY: the safety contract must be upheld by the caller
- unsafe { (**self).grow(ptr, layout, new_size, placement, init) }
- }
-
- #[inline]
- unsafe fn shrink(
- &mut self,
- ptr: NonNull<u8>,
- layout: Layout,
- new_size: usize,
- placement: ReallocPlacement,
- ) -> Result<MemoryBlock, AllocErr> {
- // SAFETY: the safety contract must be upheld by the caller
- unsafe { (**self).shrink(ptr, layout, new_size, placement) }
- }
-}