diff options
| author | Stefan Lankes <stlankes@users.noreply.github.com> | 2020-04-04 07:41:05 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-04-04 07:41:05 +0200 |
| commit | aa223304dc130c5ace18d48c53b192b14088862e (patch) | |
| tree | 1971ea5717f0e2ef2dc9468b3a0e96c209d481fe /src/libcore | |
| parent | 9f6b96e461003853bf36052cfaf79b12e1c35413 (diff) | |
| parent | 9e55101bb681010c82c3c827305e2665fc8f2aa0 (diff) | |
Merge branch 'master' into abi
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/alloc.rs | 1043 | ||||
| -rw-r--r-- | src/libcore/alloc/global.rs | 198 | ||||
| -rw-r--r-- | src/libcore/alloc/layout.rs | 346 | ||||
| -rw-r--r-- | src/libcore/alloc/mod.rs | 367 | ||||
| -rw-r--r-- | src/libcore/array/iter.rs | 18 | ||||
| -rw-r--r-- | src/libcore/clone.rs | 3 | ||||
| -rw-r--r-- | src/libcore/cmp.rs | 2 | ||||
| -rw-r--r-- | src/libcore/convert/mod.rs | 8 | ||||
| -rw-r--r-- | src/libcore/convert/num.rs | 15 | ||||
| -rw-r--r-- | src/libcore/fmt/mod.rs | 2 | ||||
| -rw-r--r-- | src/libcore/hint.rs | 2 | ||||
| -rw-r--r-- | src/libcore/intrinsics.rs | 20 | ||||
| -rw-r--r-- | src/libcore/iter/traits/iterator.rs | 8 | ||||
| -rw-r--r-- | src/libcore/macros/mod.rs | 16 | ||||
| -rw-r--r-- | src/libcore/marker.rs | 3 | ||||
| -rw-r--r-- | src/libcore/num/f32.rs | 14 | ||||
| -rw-r--r-- | src/libcore/num/f64.rs | 14 | ||||
| -rw-r--r-- | src/libcore/num/mod.rs | 6 | ||||
| -rw-r--r-- | src/libcore/ops/range.rs | 10 | ||||
| -rw-r--r-- | src/libcore/ptr/const_ptr.rs | 4 | ||||
| -rw-r--r-- | src/libcore/ptr/mut_ptr.rs | 4 | ||||
| -rw-r--r-- | src/libcore/raw.rs | 3 | ||||
| -rw-r--r-- | src/libcore/slice/mod.rs | 2 | ||||
| -rw-r--r-- | src/libcore/str/mod.rs | 41 | ||||
| -rw-r--r-- | src/libcore/str/pattern.rs | 85 | ||||
| -rw-r--r-- | src/libcore/time.rs | 4 |
26 files changed, 1097 insertions, 1141 deletions
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs deleted file mode 100644 index be20a1cde36..00000000000 --- a/src/libcore/alloc.rs +++ /dev/null @@ -1,1043 +0,0 @@ -//! Memory allocation APIs - -// ignore-tidy-undocumented-unsafe - -#![stable(feature = "alloc_module", since = "1.28.0")] - -use crate::cmp; -use crate::fmt; -use crate::mem; -use crate::num::NonZeroUsize; -use crate::ptr::{self, NonNull}; -use crate::usize; - -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 non-negative size and a -/// power-of-two alignment. -/// -/// (Note however that layouts are *not* required to have positive -/// size, even though many allocators require that all memory -/// requests have positive size. A caller to the `AllocRef::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)] -#[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 - /// `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: () }); - } - - 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 { - 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")] - #[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>(); - // Note that the align is guaranteed by rustc 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)); - // See rationale in `new` for why this is using an unsafe variant below - debug_assert!(Layout::from_size_align(size, align).is_ok()); - 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 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 - #[inline] - #[cfg(not(bootstrap))] - #[unstable(feature = "layout_for_ptr", issue = "69835")] - pub unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self { - let (size, align) = (mem::size_of_val_raw(t), mem::align_of_val_raw(t)); - // See rationale in `new` for why this is using an unsafe variant below - debug_assert!(Layout::from_size_align(size, align).is_ok()); - 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")] - pub const fn dangling(&self) -> NonNull<u8> { - // align is non-zero and a power of two - 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). - #[unstable(feature = "alloc_layout_extra", issue = "55724")] - #[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. - #[unstable(feature = "alloc_layout_extra", issue = "55724")] - #[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: () })?; - - unsafe { - // self.align is already known to be valid and alloc_size has been - // padded already. - 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. Note that the resulting layout will - /// satisfy the alignment properties of both `self` and `next`. - /// - /// The resulting layout will be the same as that of a C struct containing - /// two fields with the layouts of `self` and `next`, in that order. - /// - /// Returns `Some((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`. - #[unstable(feature = "alloc_layout_extra", issue = "55724")] - #[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`. - #[unstable(feature = "alloc_layout_extra", issue = "55724")] - #[inline] - pub fn array<T>(n: usize) -> Result<Self, LayoutErr> { - Layout::new::<T>().repeat(n).map(|(k, offs)| { - debug_assert!(offs == mem::size_of::<T>()); - k - }) - } -} - -/// 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 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") - } -} - -/// 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. -/// -/// [`grow_in_place`]: ./trait.AllocRef.html#method.grow_in_place -/// [`shrink_in_place`]: ./trait.AllocRef.html#method.shrink_in_place -#[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" - } -} - -// (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()) - } -} - -/// 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(); - let ptr = self.alloc(layout); - if !ptr.is_null() { - 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 { - 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, new_ptr, cmp::min(layout.size(), new_size)); - self.dealloc(ptr, layout); - } - new_ptr - } -} - -/// An implementation of `AllocRef` can allocate, reallocate, 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. -/// -/// 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 (`alloc`, -/// `alloc_zeroed`) or reallocation method (`realloc`), and -/// -/// * the memory block has not been subsequently deallocated, where -/// blocks are deallocated either by being passed to a deallocation -/// method (`dealloc`) or by being passed to a reallocation method -/// (see above) that returns `Ok`. -/// -/// 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 case -/// must be caught. In this case [`Layout::dangling()`] can be used to -/// create a dangling, but aligned `NonNull<u8>`. -/// -/// 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 two conditions must hold: -/// -/// 1. The block's starting address must be aligned to `layout.align()`. -/// -/// 2. The block's size must fall in the range `[use_min, use_max]`, where: -/// -/// * `use_min` is `layout.size()`, and -/// -/// * `use_max` is the capacity that was returned. -/// -/// Note that: -/// -/// * the size of the layout most recently used to allocate the block -/// is guaranteed to be in the range `[use_min, use_max]`, and -/// -/// * a lower-bound on `use_max` can be safely approximated by a call to -/// `usable_size`. -/// -/// * if a layout `k` fits a memory block (denoted by `ptr`) -/// currently allocated via an allocator `a`, then it is legal to -/// use that layout to deallocate it, i.e., `a.dealloc(ptr, k);`. -/// -/// * if an allocator does not support overallocating, it is fine to -/// simply return `layout.size()` as the allocated size. -/// -/// [`GlobalAlloc`]: self::GlobalAlloc -/// [`Layout::dangling()`]: self::Layout::dangling -/// -/// # Safety -/// -/// The `AllocRef` trait is an `unsafe` trait for a number of reasons, and -/// implementors must ensure that they adhere to these contracts: -/// -/// * Pointers returned from allocation functions must point to valid memory and -/// retain their validity until at least one instance of `AllocRef` is dropped -/// itself. -/// -/// * Cloning or moving the allocator must not invalidate pointers returned -/// from this allocator. Cloning must return a reference to the same allocator. -/// -/// * `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. -#[unstable(feature = "allocator_api", issue = "32838")] -pub unsafe trait AllocRef { - /// On success, returns a pointer meeting the size and alignment - /// guarantees of `layout` and the actual size of the allocated block, - /// which must be greater than or equal to `layout.size()`. - /// - /// If this method returns an `Ok(addr)`, then the `addr` returned - /// will be non-null address pointing to a block of storage - /// suitable for holding an instance of `layout`. - /// - /// The returned block of storage may or may not have its contents - /// initialized. (Extension subtraits might restrict this - /// behavior, e.g., to ensure initialization to particular sets of - /// bit patterns.) - /// - /// # 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) -> Result<(NonNull<u8>, usize), AllocErr>; - - /// Deallocate the memory referenced by `ptr`. - /// - /// # 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 *fit* that block of memory, - /// - /// * 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<u8>, layout: Layout); - - /// Behaves like `alloc`, but also ensures that the contents - /// are set to zero before being returned. - /// - /// # Errors - /// - /// Returning `Err` 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 - fn alloc_zeroed(&mut self, layout: Layout) -> Result<(NonNull<u8>, usize), AllocErr> { - let size = layout.size(); - let result = self.alloc(layout); - if let Ok((p, _)) = result { - unsafe { ptr::write_bytes(p.as_ptr(), 0, size) } - } - result - } - - // == METHODS FOR MEMORY REUSE == - // realloc, realloc_zeroed, grow_in_place, grow_in_place_zeroed, shrink_in_place - - /// Returns a pointer suitable for holding data described by - /// a new layout with `layout`’s alignment and a size given - /// by `new_size` and the actual size of the allocated block. - /// The latter is greater than or equal to `layout.size()`. - /// To accomplish this, the allocator may extend or shrink - /// the allocation referenced by `ptr` to fit the new layout. - /// - /// 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 of course 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. - /// - /// # 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 *fit* the `ptr` (see above). (The `new_size` - /// argument need not fit it.) - /// - /// * `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 `Err` only if the new layout - /// does not meet the allocator's size - /// and alignment constraints of the allocator, or if reallocation - /// 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 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 - unsafe fn realloc( - &mut self, - ptr: NonNull<u8>, - layout: Layout, - new_size: usize, - ) -> Result<(NonNull<u8>, usize), AllocErr> { - let old_size = layout.size(); - - if new_size > old_size { - if let Ok(size) = self.grow_in_place(ptr, layout, new_size) { - return Ok((ptr, size)); - } - } else if new_size < old_size { - if let Ok(size) = self.shrink_in_place(ptr, layout, new_size) { - return Ok((ptr, size)); - } - } else { - return Ok((ptr, new_size)); - } - - // otherwise, fall back on alloc + copy + dealloc. - 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(), new_ptr.as_ptr(), cmp::min(old_size, new_size)); - self.dealloc(ptr, layout); - } - result - } - - /// Behaves like `realloc`, but also ensures that the new contents - /// are set to zero before being returned. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `realloc` is. - /// - /// # Errors - /// - /// Returns `Err` only if the new layout - /// does not meet the allocator's size - /// and alignment constraints of the allocator, or if reallocation - /// 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 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 - unsafe fn realloc_zeroed( - &mut self, - ptr: NonNull<u8>, - layout: Layout, - new_size: usize, - ) -> Result<(NonNull<u8>, usize), AllocErr> { - let old_size = layout.size(); - - if new_size > old_size { - if let Ok(size) = self.grow_in_place_zeroed(ptr, layout, new_size) { - return Ok((ptr, size)); - } - } else if new_size < old_size { - if let Ok(size) = self.shrink_in_place(ptr, layout, new_size) { - return Ok((ptr, size)); - } - } else { - return Ok((ptr, new_size)); - } - - // otherwise, fall back on alloc + copy + dealloc. - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - let result = self.alloc_zeroed(new_layout); - if let Ok((new_ptr, _)) = result { - ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), cmp::min(old_size, new_size)); - self.dealloc(ptr, layout); - } - result - } - - /// Attempts to extend the allocation referenced by `ptr` to fit `new_size`. - /// - /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_size`, and thus can - /// be used to carry data of a layout of that size and same alignment as - /// `layout`. The returned value is the new size of the allocated block. - /// (The allocator is allowed to expend effort to accomplish this, such - /// as extending the memory block to include successor blocks, or virtual - /// memory tricks.) - /// - /// Regardless of what this method returns, ownership of the - /// memory block referenced by `ptr` has not been transferred, 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 *fit* the `ptr` (see above); note the - /// `new_size` argument need not fit it, - /// - /// * `new_size` must not be less than `layout.size()`, - /// - /// # Errors - /// - /// Returns `Err(CannotReallocInPlace)` when the allocator is - /// unable to assert that the memory block referenced by `ptr` - /// could fit `layout`. - /// - /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error` - /// 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. - #[inline] - unsafe fn grow_in_place( - &mut self, - ptr: NonNull<u8>, - layout: Layout, - new_size: usize, - ) -> Result<usize, CannotReallocInPlace> { - let _ = ptr; - let _ = layout; - let _ = new_size; - Err(CannotReallocInPlace) - } - - /// Behaves like `grow_in_place`, but also ensures that the new - /// contents are set to zero before being returned. - /// - /// # Safety - /// - /// This function is unsafe for the same reasons that `grow_in_place` is. - /// - /// # Errors - /// - /// Returns `Err(CannotReallocInPlace)` when the allocator is - /// unable to assert that the memory block referenced by `ptr` - /// could fit `layout`. - /// - /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error` - /// 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_zeroed( - &mut self, - ptr: NonNull<u8>, - layout: Layout, - new_size: usize, - ) -> Result<usize, CannotReallocInPlace> { - let size = self.grow_in_place(ptr, layout, new_size)?; - ptr.as_ptr().add(layout.size()).write_bytes(0, new_size - layout.size()); - Ok(size) - } - - /// Attempts to shrink the allocation referenced by `ptr` to fit `new_size`. - /// - /// If this returns `Ok`, then the allocator has asserted that the - /// memory block referenced by `ptr` now fits `new_size`, and - /// thus can only be used to carry data of that smaller - /// layout. The returned value is the new size the allocated block. - /// (The allocator is allowed to take advantage of this, - /// carving off portions of the block for reuse elsewhere.) The - /// truncated contents of the block within the smaller layout are - /// unaltered, and ownership of block has not been transferred. - /// - /// If this returns `Err`, then the memory block is considered to - /// still represent the original (larger) `layout`. None of the - /// block has been carved off for reuse elsewhere, ownership of - /// the memory block has not been transferred, 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 *fit* the `ptr` (see above); note the - /// `new_size` argument need not fit it, - /// - /// * `new_size` must not be greater than `layout.size()`, - /// - /// # Errors - /// - /// Returns `Err(CannotReallocInPlace)` when the allocator is - /// unable to assert that the memory block referenced by `ptr` - /// could fit `layout`. - /// - /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error` - /// 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. - #[inline] - unsafe fn shrink_in_place( - &mut self, - ptr: NonNull<u8>, - layout: Layout, - new_size: usize, - ) -> Result<usize, CannotReallocInPlace> { - let _ = ptr; - let _ = layout; - let _ = new_size; - Err(CannotReallocInPlace) - } -} diff --git a/src/libcore/alloc/global.rs b/src/libcore/alloc/global.rs new file mode 100644 index 00000000000..147fe696ac0 --- /dev/null +++ b/src/libcore/alloc/global.rs @@ -0,0 +1,198 @@ +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(); + let ptr = self.alloc(layout); + if !ptr.is_null() { + 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 { + 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, 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 new file mode 100644 index 00000000000..fa644cfe99e --- /dev/null +++ b/src/libcore/alloc/layout.rs @@ -0,0 +1,346 @@ +// ignore-tidy-undocumented-unsafe + +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: () }); + } + + 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 { + 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")] + #[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>(); + // Note that the align is guaranteed by rustc 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)); + // See rationale in `new` for why this is using an unsafe variant below + debug_assert!(Layout::from_size_align(size, align).is_ok()); + 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> { + // align is non-zero and a power of two + 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). + #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[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. + #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[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: () })?; + + unsafe { + // self.align is already known to be valid and alloc_size has been + // padded already. + 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. Note that the resulting layout will + /// satisfy the alignment properties of both `self` and `next`. + /// + /// The resulting layout will be the same as that of a C struct containing + /// two fields with the layouts of `self` and `next`, in that order. + /// + /// Returns `Some((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`. + #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[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`. + #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[inline] + pub fn array<T>(n: usize) -> Result<Self, LayoutErr> { + Layout::new::<T>().repeat(n).map(|(k, offs)| { + debug_assert!(offs == mem::size_of::<T>()); + k + }) + } +} + +/// 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 new file mode 100644 index 00000000000..e1892edb7c7 --- /dev/null +++ b/src/libcore/alloc/mod.rs @@ -0,0 +1,367 @@ +//! 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(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) { + 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 => { + 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 = Layout::from_size_align_unchecked(new_size, layout.align()); + let new_memory = self.alloc(new_layout, init)?; + 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 = Layout::from_size_align_unchecked(new_size, layout.align()); + let new_memory = self.alloc(new_layout, AllocInit::Uninitialized)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), new_size); + self.dealloc(ptr, layout); + Ok(new_memory) + } + } + } +} diff --git a/src/libcore/array/iter.rs b/src/libcore/array/iter.rs index 80eaae0d4af..f6b8d4ba081 100644 --- a/src/libcore/array/iter.rs +++ b/src/libcore/array/iter.rs @@ -39,7 +39,7 @@ where alive: Range<usize>, } -impl<T, const N: usize> IntoIter<T, { N }> +impl<T, const N: usize> IntoIter<T, N> where [T; N]: LengthAtMost32, { @@ -99,7 +99,7 @@ where } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] -impl<T, const N: usize> Iterator for IntoIter<T, { N }> +impl<T, const N: usize> Iterator for IntoIter<T, N> where [T; N]: LengthAtMost32, { @@ -146,7 +146,7 @@ where } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] -impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, { N }> +impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> where [T; N]: LengthAtMost32, { @@ -182,7 +182,7 @@ where } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] -impl<T, const N: usize> Drop for IntoIter<T, { N }> +impl<T, const N: usize> Drop for IntoIter<T, N> where [T; N]: LengthAtMost32, { @@ -195,7 +195,7 @@ where } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] -impl<T, const N: usize> ExactSizeIterator for IntoIter<T, { N }> +impl<T, const N: usize> ExactSizeIterator for IntoIter<T, N> where [T; N]: LengthAtMost32, { @@ -210,17 +210,17 @@ where } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] -impl<T, const N: usize> FusedIterator for IntoIter<T, { N }> where [T; N]: LengthAtMost32 {} +impl<T, const N: usize> FusedIterator for IntoIter<T, N> where [T; N]: LengthAtMost32 {} // The iterator indeed reports the correct length. The number of "alive" // elements (that will still be yielded) is the length of the range `alive`. // This range is decremented in length in either `next` or `next_back`. It is // always decremented by 1 in those methods, but only if `Some(_)` is returned. #[stable(feature = "array_value_iter_impls", since = "1.40.0")] -unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, { N }> where [T; N]: LengthAtMost32 {} +unsafe impl<T, const N: usize> TrustedLen for IntoIter<T, N> where [T; N]: LengthAtMost32 {} #[stable(feature = "array_value_iter_impls", since = "1.40.0")] -impl<T: Clone, const N: usize> Clone for IntoIter<T, { N }> +impl<T: Clone, const N: usize> Clone for IntoIter<T, N> where [T; N]: LengthAtMost32, { @@ -249,7 +249,7 @@ where } #[stable(feature = "array_value_iter_impls", since = "1.40.0")] -impl<T: fmt::Debug, const N: usize> fmt::Debug for IntoIter<T, { N }> +impl<T: fmt::Debug, const N: usize> fmt::Debug for IntoIter<T, N> where [T; N]: LengthAtMost32, { diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index eb101fc72fd..6165941eb3d 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -169,7 +169,8 @@ pub struct AssertParamIsCopy<T: Copy + ?Sized> { /// Implementations of `Clone` for primitive types. /// /// Implementations that cannot be described in Rust -/// are implemented in `SelectionContext::copy_clone_conditions()` in librustc. +/// are implemented in `traits::SelectionContext::copy_clone_conditions()` +/// in `rustc_trait_selection`. mod impls { use super::Clone; diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 604be7d5f68..8c542136a7f 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -817,7 +817,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> { /// When comparison is impossible: /// /// ``` - /// let result = std::f64::NAN.partial_cmp(&1.0); + /// let result = f64::NAN.partial_cmp(&1.0); /// assert_eq!(result, None); /// ``` #[must_use] diff --git a/src/libcore/convert/mod.rs b/src/libcore/convert/mod.rs index 47ab8715cfa..eef9ee7cb00 100644 --- a/src/libcore/convert/mod.rs +++ b/src/libcore/convert/mod.rs @@ -41,6 +41,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::fmt; +use crate::hash::{Hash, Hasher}; mod num; @@ -746,3 +747,10 @@ impl From<!> for Infallible { x } } + +#[stable(feature = "convert_infallible_hash", since = "1.44.0")] +impl Hash for Infallible { + fn hash<H: Hasher>(&self, _: &mut H) { + match *self {} + } +} diff --git a/src/libcore/convert/num.rs b/src/libcore/convert/num.rs index 752199c94b8..66ae760fc1f 100644 --- a/src/libcore/convert/num.rs +++ b/src/libcore/convert/num.rs @@ -13,9 +13,9 @@ mod private { /// Typically doesn’t need to be used directly. #[unstable(feature = "convert_float_to_int", issue = "67057")] pub trait FloatToInt<Int>: private::Sealed + Sized { - #[unstable(feature = "float_approx_unchecked_to", issue = "67058")] + #[unstable(feature = "convert_float_to_int", issue = "67057")] #[doc(hidden)] - unsafe fn approx_unchecked(self) -> Int; + unsafe fn to_int_unchecked(self) -> Int; } macro_rules! impl_float_to_int { @@ -27,8 +27,15 @@ macro_rules! impl_float_to_int { impl FloatToInt<$Int> for $Float { #[doc(hidden)] #[inline] - unsafe fn approx_unchecked(self) -> $Int { - crate::intrinsics::float_to_int_approx_unchecked(self) + unsafe fn to_int_unchecked(self) -> $Int { + #[cfg(bootstrap)] + { + crate::intrinsics::float_to_int_approx_unchecked(self) + } + #[cfg(not(bootstrap))] + { + crate::intrinsics::float_to_int_unchecked(self) + } } } )+ diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index fe728d42c76..95411b525d0 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -852,7 +852,7 @@ pub trait LowerHex { /// } /// } /// -/// let l = Length(i32::max_value()); +/// let l = Length(i32::MAX); /// /// assert_eq!(format!("l as hex is: {:X}", l), "l as hex is: 7FFFFFFF"); /// diff --git a/src/libcore/hint.rs b/src/libcore/hint.rs index 698c97999c4..d406b3ce6ef 100644 --- a/src/libcore/hint.rs +++ b/src/libcore/hint.rs @@ -43,7 +43,7 @@ use crate::intrinsics; /// /// assert_eq!(div_1(7, 0), 7); /// assert_eq!(div_1(9, 1), 4); -/// assert_eq!(div_1(11, std::u32::MAX), 0); +/// assert_eq!(div_1(11, u32::MAX), 0); /// ``` #[inline] #[stable(feature = "unreachable", since = "1.27.0")] diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 0c956104221..4a11fb39389 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1582,8 +1582,16 @@ extern "rust-intrinsic" { /// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range /// (<https://github.com/rust-lang/rust/issues/10184>) /// This is under stabilization at <https://github.com/rust-lang/rust/issues/67058> + #[cfg(bootstrap)] pub fn float_to_int_approx_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; + /// Convert with LLVM’s fptoui/fptosi, which may return undef for values out of range + /// (<https://github.com/rust-lang/rust/issues/10184>) + /// + /// Stabilized as `f32::to_int_unchecked` and `f64::to_int_unchecked`. + #[cfg(not(bootstrap))] + pub fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; + /// Returns the number of bits set in an integer type `T` /// /// The stabilized versions of this intrinsic are available on the integer @@ -1731,11 +1739,11 @@ extern "rust-intrinsic" { pub fn mul_with_overflow<T: Copy>(x: T, y: T) -> (T, bool); /// Performs an exact division, resulting in undefined behavior where - /// `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` + /// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1` pub fn exact_div<T: Copy>(x: T, y: T) -> T; /// Performs an unchecked division, resulting in undefined behavior - /// where y = 0 or x = `T::min_value()` and y = -1 + /// where y = 0 or x = `T::MIN` and y = -1 /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `checked_div` method. For example, @@ -1743,7 +1751,7 @@ extern "rust-intrinsic" { #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] pub fn unchecked_div<T: Copy>(x: T, y: T) -> T; /// Returns the remainder of an unchecked division, resulting in - /// undefined behavior where y = 0 or x = `T::min_value()` and y = -1 + /// undefined behavior where y = 0 or x = `T::MIN` and y = -1 /// /// The stabilized versions of this intrinsic are available on the integer /// primitives via the `checked_rem` method. For example, @@ -1769,17 +1777,17 @@ extern "rust-intrinsic" { pub fn unchecked_shr<T: Copy>(x: T, y: T) -> T; /// Returns the result of an unchecked addition, resulting in - /// undefined behavior when `x + y > T::max_value()` or `x + y < T::min_value()`. + /// undefined behavior when `x + y > T::MAX` or `x + y < T::MIN`. #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] pub fn unchecked_add<T: Copy>(x: T, y: T) -> T; /// Returns the result of an unchecked subtraction, resulting in - /// undefined behavior when `x - y > T::max_value()` or `x - y < T::min_value()`. + /// undefined behavior when `x - y > T::MAX` or `x - y < T::MIN`. #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] pub fn unchecked_sub<T: Copy>(x: T, y: T) -> T; /// Returns the result of an unchecked multiplication, resulting in - /// undefined behavior when `x * y > T::max_value()` or `x * y < T::min_value()`. + /// undefined behavior when `x * y > T::MAX` or `x * y < T::MIN`. #[rustc_const_unstable(feature = "const_int_unchecked_arith", issue = "none")] pub fn unchecked_mul<T: Copy>(x: T, y: T) -> T; diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index daa880e7cd5..c8829817e19 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -198,7 +198,7 @@ pub trait Iterator { /// // and the maximum possible lower bound /// let iter = 0..; /// - /// assert_eq!((usize::max_value(), None), iter.size_hint()); + /// assert_eq!((usize::MAX, None), iter.size_hint()); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -2920,7 +2920,7 @@ pub trait Iterator { /// assert_eq!([1.].iter().partial_cmp([1., 2.].iter()), Some(Ordering::Less)); /// assert_eq!([1., 2.].iter().partial_cmp([1.].iter()), Some(Ordering::Greater)); /// - /// assert_eq!([std::f64::NAN].iter().partial_cmp([1.].iter()), None); + /// assert_eq!([f64::NAN].iter().partial_cmp([1.].iter()), None); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn partial_cmp<I>(self, other: I) -> Option<Ordering> @@ -3170,7 +3170,7 @@ pub trait Iterator { /// assert!(![1, 3, 2, 4].iter().is_sorted()); /// assert!([0].iter().is_sorted()); /// assert!(std::iter::empty::<i32>().is_sorted()); - /// assert!(![0.0, 1.0, std::f32::NAN].iter().is_sorted()); + /// assert!(![0.0, 1.0, f32::NAN].iter().is_sorted()); /// ``` #[inline] #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] @@ -3197,7 +3197,7 @@ pub trait Iterator { /// assert!(![1, 3, 2, 4].iter().is_sorted_by(|a, b| a.partial_cmp(b))); /// assert!([0].iter().is_sorted_by(|a, b| a.partial_cmp(b))); /// assert!(std::iter::empty::<i32>().is_sorted_by(|a, b| a.partial_cmp(b))); - /// assert!(![0.0, 1.0, std::f32::NAN].iter().is_sorted_by(|a, b| a.partial_cmp(b))); + /// assert!(![0.0, 1.0, f32::NAN].iter().is_sorted_by(|a, b| a.partial_cmp(b))); /// ``` /// /// [`is_sorted`]: trait.Iterator.html#method.is_sorted diff --git a/src/libcore/macros/mod.rs b/src/libcore/macros/mod.rs index f67762cd043..9c885ef99a9 100644 --- a/src/libcore/macros/mod.rs +++ b/src/libcore/macros/mod.rs @@ -1070,8 +1070,10 @@ pub(crate) mod builtin { /// Includes a utf8-encoded file as a string. /// - /// The file is located relative to the current file. (similarly to how - /// modules are found) + /// The file is located relative to the current file (similarly to how + /// modules are found). The provided path is interpreted in a platform-specific + /// way at compile time. So, for instance, an invocation with a Windows path + /// containing backslashes `\` would not compile correctly on Unix. /// /// This macro will yield an expression of type `&'static str` which is the /// contents of the file. @@ -1108,8 +1110,10 @@ pub(crate) mod builtin { /// Includes a file as a reference to a byte array. /// - /// The file is located relative to the current file. (similarly to how - /// modules are found) + /// The file is located relative to the current file (similarly to how + /// modules are found). The provided path is interpreted in a platform-specific + /// way at compile time. So, for instance, an invocation with a Windows path + /// containing backslashes `\` would not compile correctly on Unix. /// /// This macro will yield an expression of type `&'static [u8; N]` which is /// the contents of the file. @@ -1202,7 +1206,9 @@ pub(crate) mod builtin { /// Parses a file as an expression or an item according to the context. /// /// The file is located relative to the current file (similarly to how - /// modules are found). + /// modules are found). The provided path is interpreted in a platform-specific + /// way at compile time. So, for instance, an invocation with a Windows path + /// containing backslashes `\` would not compile correctly on Unix. /// /// Using this macro is often a bad idea, because if the file is /// parsed as an expression, it is going to be placed in the diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index b131cf84e18..35bceaa25c3 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -759,7 +759,8 @@ impl<T: ?Sized> Unpin for *mut T {} /// Implementations of `Copy` for primitive types. /// /// Implementations that cannot be described in Rust -/// are implemented in `SelectionContext::copy_clone_conditions()` in librustc. +/// are implemented in `traits::SelectionContext::copy_clone_conditions()` +/// in `rustc_trait_selection`. mod copy_impls { use super::Copy; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 3fdc2bae338..4ab82add32b 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -464,15 +464,13 @@ impl f32 { /// assuming that the value is finite and fits in that type. /// /// ``` - /// #![feature(float_approx_unchecked_to)] - /// /// let value = 4.6_f32; - /// let rounded = unsafe { value.approx_unchecked_to::<u16>() }; + /// let rounded = unsafe { value.to_int_unchecked::<u16>() }; /// assert_eq!(rounded, 4); /// /// let value = -128.9_f32; - /// let rounded = unsafe { value.approx_unchecked_to::<i8>() }; - /// assert_eq!(rounded, std::i8::MIN); + /// let rounded = unsafe { value.to_int_unchecked::<i8>() }; + /// assert_eq!(rounded, i8::MIN); /// ``` /// /// # Safety @@ -482,13 +480,13 @@ impl f32 { /// * Not be `NaN` /// * Not be infinite /// * Be representable in the return type `Int`, after truncating off its fractional part - #[unstable(feature = "float_approx_unchecked_to", issue = "67058")] + #[stable(feature = "float_approx_unchecked_to", since = "1.44.0")] #[inline] - pub unsafe fn approx_unchecked_to<Int>(self) -> Int + pub unsafe fn to_int_unchecked<Int>(self) -> Int where Self: FloatToInt<Int>, { - FloatToInt::<Int>::approx_unchecked(self) + FloatToInt::<Int>::to_int_unchecked(self) } /// Raw transmutation to `u32`. diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 129df937c0b..20818a9b750 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -478,15 +478,13 @@ impl f64 { /// assuming that the value is finite and fits in that type. /// /// ``` - /// #![feature(float_approx_unchecked_to)] - /// /// let value = 4.6_f32; - /// let rounded = unsafe { value.approx_unchecked_to::<u16>() }; + /// let rounded = unsafe { value.to_int_unchecked::<u16>() }; /// assert_eq!(rounded, 4); /// /// let value = -128.9_f32; - /// let rounded = unsafe { value.approx_unchecked_to::<i8>() }; - /// assert_eq!(rounded, std::i8::MIN); + /// let rounded = unsafe { value.to_int_unchecked::<i8>() }; + /// assert_eq!(rounded, i8::MIN); /// ``` /// /// # Safety @@ -496,13 +494,13 @@ impl f64 { /// * Not be `NaN` /// * Not be infinite /// * Be representable in the return type `Int`, after truncating off its fractional part - #[unstable(feature = "float_approx_unchecked_to", issue = "67058")] + #[stable(feature = "float_approx_unchecked_to", since = "1.44.0")] #[inline] - pub unsafe fn approx_unchecked_to<Int>(self) -> Int + pub unsafe fn to_int_unchecked<Int>(self) -> Int where Self: FloatToInt<Int>, { - FloatToInt::<Int>::approx_unchecked(self) + FloatToInt::<Int>::to_int_unchecked(self) } /// Raw transmutation to `u64`. diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 853092dd85e..7ba4004d860 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -174,7 +174,7 @@ NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize } /// let zero = Wrapping(0u32); /// let one = Wrapping(1u32); /// -/// assert_eq!(std::u32::MAX, (zero - one).0); +/// assert_eq!(u32::MAX, (zero - one).0); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] @@ -4376,7 +4376,7 @@ impl u8 { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_uppercase(&self) -> u8 { - // Unset the fith bit if this is a lowercase letter + // Unset the fifth bit if this is a lowercase letter *self & !((self.is_ascii_lowercase() as u8) << 5) } @@ -4399,7 +4399,7 @@ impl u8 { #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] pub fn to_ascii_lowercase(&self) -> u8 { - // Set the fith bit if this is an uppercase letter + // Set the fifth bit if this is an uppercase letter *self | ((self.is_ascii_uppercase() as u8) << 5) } diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index adee8cea442..946a765e18f 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -139,10 +139,9 @@ impl<Idx: PartialOrd<Idx>> Range<Idx> { /// ``` /// #![feature(range_is_empty)] /// - /// use std::f32::NAN; /// assert!(!(3.0..5.0).is_empty()); - /// assert!( (3.0..NAN).is_empty()); - /// assert!( (NAN..5.0).is_empty()); + /// assert!( (3.0..f32::NAN).is_empty()); + /// assert!( (f32::NAN..5.0).is_empty()); /// ``` #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] pub fn is_empty(&self) -> bool { @@ -496,10 +495,9 @@ impl<Idx: PartialOrd<Idx>> RangeInclusive<Idx> { /// ``` /// #![feature(range_is_empty)] /// - /// use std::f32::NAN; /// assert!(!(3.0..=5.0).is_empty()); - /// assert!( (3.0..=NAN).is_empty()); - /// assert!( (NAN..=5.0).is_empty()); + /// assert!( (3.0..=f32::NAN).is_empty()); + /// assert!( (f32::NAN..=5.0).is_empty()); /// ``` /// /// This method returns `true` after iteration has finished: diff --git a/src/libcore/ptr/const_ptr.rs b/src/libcore/ptr/const_ptr.rs index a540016854d..52e224d2a02 100644 --- a/src/libcore/ptr/const_ptr.rs +++ b/src/libcore/ptr/const_ptr.rs @@ -659,8 +659,8 @@ impl<T: ?Sized> *const T { /// `align`. /// /// If it is not possible to align the pointer, the implementation returns - /// `usize::max_value()`. It is permissible for the implementation to *always* - /// return `usize::max_value()`. Only your algorithm's performance can depend + /// `usize::MAX`. It is permissible for the implementation to *always* + /// return `usize::MAX`. Only your algorithm's performance can depend /// on getting a usable offset here, not its correctness. /// /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be diff --git a/src/libcore/ptr/mut_ptr.rs b/src/libcore/ptr/mut_ptr.rs index 01d830ca186..9f85d781d69 100644 --- a/src/libcore/ptr/mut_ptr.rs +++ b/src/libcore/ptr/mut_ptr.rs @@ -847,8 +847,8 @@ impl<T: ?Sized> *mut T { /// `align`. /// /// If it is not possible to align the pointer, the implementation returns - /// `usize::max_value()`. It is permissible for the implementation to *always* - /// return `usize::max_value()`. Only your algorithm's performance can depend + /// `usize::MAX`. It is permissible for the implementation to *always* + /// return `usize::MAX`. Only your algorithm's performance can depend /// on getting a usable offset here, not its correctness. /// /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index 75c329a7d6c..cb0fb8795e5 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -6,7 +6,8 @@ //! They can be used as targets of transmutes in unsafe code for manipulating //! the raw representations directly. //! -//! Their definition should always match the ABI defined in `rustc::back::abi`. +//! Their definition should always match the ABI defined in +//! `rustc_middle::ty::layout`. /// The representation of a trait object like `&SomeTrait`. /// diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 2140a7be9ef..9be52e2dfb0 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -2588,7 +2588,7 @@ impl<T> [T] { /// assert!(![1, 3, 2, 4].is_sorted()); /// assert!([0].is_sorted()); /// assert!(empty.is_sorted()); - /// assert!(![0.0, 1.0, std::f32::NAN].is_sorted()); + /// assert!(![0.0, 1.0, f32::NAN].is_sorted()); /// ``` #[inline] #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index 013ca182c13..dc7637cfdb9 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -9,7 +9,7 @@ #![stable(feature = "rust1", since = "1.0.0")] use self::pattern::Pattern; -use self::pattern::{DoubleEndedSearcher, ReverseSearcher, SearchStep, Searcher}; +use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; use crate::char; use crate::fmt::{self, Write}; @@ -2642,7 +2642,7 @@ impl str { /// # Panics /// /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is - /// beyond the last code point of the string slice. + /// past the end of the last code point of the string slice. /// /// # Examples /// @@ -2683,7 +2683,7 @@ impl str { /// # Panics /// /// Panics if `mid` is not on a UTF-8 code point boundary, or if it is - /// beyond the last code point of the string slice. + /// past the end of the last code point of the string slice. /// /// # Examples /// @@ -3986,26 +3986,15 @@ impl str { /// ``` /// #![feature(str_strip)] /// - /// assert_eq!("foobar".strip_prefix("foo"), Some("bar")); - /// assert_eq!("foobar".strip_prefix("bar"), None); + /// assert_eq!("foo:bar".strip_prefix("foo:"), Some("bar")); + /// assert_eq!("foo:bar".strip_prefix("bar"), None); /// assert_eq!("foofoo".strip_prefix("foo"), Some("foo")); /// ``` #[must_use = "this returns the remaining substring as a new slice, \ without modifying the original"] #[unstable(feature = "str_strip", reason = "newly added", issue = "67302")] pub fn strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<&'a str> { - let mut matcher = prefix.into_searcher(self); - if let SearchStep::Match(start, len) = matcher.next() { - debug_assert_eq!( - start, 0, - "The first search step from Searcher \ - must include the first character" - ); - // SAFETY: `Searcher` is known to return valid indices. - unsafe { Some(self.get_unchecked(len..)) } - } else { - None - } + prefix.strip_prefix_of(self) } /// Returns a string slice with the suffix removed. @@ -4020,8 +4009,8 @@ impl str { /// /// ``` /// #![feature(str_strip)] - /// assert_eq!("barfoo".strip_suffix("foo"), Some("bar")); - /// assert_eq!("barfoo".strip_suffix("bar"), None); + /// assert_eq!("bar:foo".strip_suffix(":foo"), Some("bar")); + /// assert_eq!("bar:foo".strip_suffix("bar"), None); /// assert_eq!("foofoo".strip_suffix("foo"), Some("foo")); /// ``` #[must_use = "this returns the remaining substring as a new slice, \ @@ -4032,19 +4021,7 @@ impl str { P: Pattern<'a>, <P as Pattern<'a>>::Searcher: ReverseSearcher<'a>, { - let mut matcher = suffix.into_searcher(self); - if let SearchStep::Match(start, end) = matcher.next_back() { - debug_assert_eq!( - end, - self.len(), - "The first search step from ReverseSearcher \ - must include the last character" - ); - // SAFETY: `Searcher` is known to return valid indices. - unsafe { Some(self.get_unchecked(..start)) } - } else { - None - } + suffix.strip_suffix_of(self) } /// Returns a string slice with all suffixes that match a pattern diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index ffa418cba6c..30fd55f7b7f 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -47,6 +47,22 @@ pub trait Pattern<'a>: Sized { matches!(self.into_searcher(haystack).next(), SearchStep::Match(0, _)) } + /// Removes the pattern from the front of haystack, if it matches. + #[inline] + fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + if let SearchStep::Match(start, len) = self.into_searcher(haystack).next() { + debug_assert_eq!( + start, 0, + "The first search step from Searcher \ + must include the first character" + ); + // SAFETY: `Searcher` is known to return valid indices. + unsafe { Some(haystack.get_unchecked(len..)) } + } else { + None + } + } + /// Checks whether the pattern matches at the back of the haystack #[inline] fn is_suffix_of(self, haystack: &'a str) -> bool @@ -55,6 +71,26 @@ pub trait Pattern<'a>: Sized { { matches!(self.into_searcher(haystack).next_back(), SearchStep::Match(_, j) if haystack.len() == j) } + + /// Removes the pattern from the back of haystack, if it matches. + #[inline] + fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> + where + Self::Searcher: ReverseSearcher<'a>, + { + if let SearchStep::Match(start, end) = self.into_searcher(haystack).next_back() { + debug_assert_eq!( + end, + haystack.len(), + "The first search step from ReverseSearcher \ + must include the last character" + ); + // SAFETY: `Searcher` is known to return valid indices. + unsafe { Some(haystack.get_unchecked(..start)) } + } else { + None + } + } } // Searcher @@ -449,12 +485,25 @@ impl<'a> Pattern<'a> for char { } #[inline] + fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + self.encode_utf8(&mut [0u8; 4]).strip_prefix_of(haystack) + } + + #[inline] fn is_suffix_of(self, haystack: &'a str) -> bool where Self::Searcher: ReverseSearcher<'a>, { self.encode_utf8(&mut [0u8; 4]).is_suffix_of(haystack) } + + #[inline] + fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> + where + Self::Searcher: ReverseSearcher<'a>, + { + self.encode_utf8(&mut [0u8; 4]).strip_suffix_of(haystack) + } } ///////////////////////////////////////////////////////////////////////////// @@ -570,12 +619,25 @@ macro_rules! pattern_methods { } #[inline] + fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + ($pmap)(self).strip_prefix_of(haystack) + } + + #[inline] fn is_suffix_of(self, haystack: &'a str) -> bool where $t: ReverseSearcher<'a>, { ($pmap)(self).is_suffix_of(haystack) } + + #[inline] + fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> + where + $t: ReverseSearcher<'a>, + { + ($pmap)(self).strip_suffix_of(haystack) + } }; } @@ -715,11 +777,34 @@ impl<'a, 'b> Pattern<'a> for &'b str { haystack.as_bytes().starts_with(self.as_bytes()) } + /// Removes the pattern from the front of haystack, if it matches. + #[inline] + fn strip_prefix_of(self, haystack: &'a str) -> Option<&'a str> { + if self.is_prefix_of(haystack) { + // SAFETY: prefix was just verified to exist. + unsafe { Some(haystack.get_unchecked(self.as_bytes().len()..)) } + } else { + None + } + } + /// Checks whether the pattern matches at the back of the haystack #[inline] fn is_suffix_of(self, haystack: &'a str) -> bool { haystack.as_bytes().ends_with(self.as_bytes()) } + + /// Removes the pattern from the back of haystack, if it matches. + #[inline] + fn strip_suffix_of(self, haystack: &'a str) -> Option<&'a str> { + if self.is_suffix_of(haystack) { + let i = haystack.len() - self.as_bytes().len(); + // SAFETY: suffix was just verified to exist. + unsafe { Some(haystack.get_unchecked(..i)) } + } else { + None + } + } } ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 2ece2150e6b..924a64847a7 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -389,7 +389,7 @@ impl Duration { /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1))); - /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None); + /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None); /// ``` #[stable(feature = "duration_checked_ops", since = "1.16.0")] #[inline] @@ -460,7 +460,7 @@ impl Duration { /// use std::time::Duration; /// /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2))); - /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None); + /// assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None); /// ``` #[stable(feature = "duration_checked_ops", since = "1.16.0")] #[inline] |
