From 25de80ad232b84ce581fe67cc08b43e9db6b0b1f Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Mon, 10 Feb 2020 16:42:00 +0100 Subject: [PATCH] Remove common usage pattern from `AllocRef` --- src/liballoc/raw_vec.rs | 13 +- src/libcore/alloc.rs | 201 +---------------------------- src/test/ui/allocator-alloc-one.rs | 18 --- 3 files changed, 9 insertions(+), 223 deletions(-) delete mode 100644 src/test/ui/allocator-alloc-one.rs diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index e1b549bed18..144654946a2 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -280,7 +280,7 @@ pub fn double(&mut self) { // 0, getting to here necessarily means the `RawVec` is overfull. assert!(elem_size != 0, "capacity overflow"); - let (new_cap, uniq) = match self.current_layout() { + let (new_cap, ptr) = match self.current_layout() { Some(cur) => { // Since we guarantee that we never allocate more than // `isize::MAX` bytes, `elem_size * self.cap <= isize::MAX` as @@ -297,7 +297,7 @@ pub fn double(&mut self) { alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow()); let ptr_res = self.a.realloc(NonNull::from(self.ptr).cast(), cur, new_size); match ptr_res { - Ok(ptr) => (new_cap, ptr.cast().into()), + Ok(ptr) => (new_cap, ptr), Err(_) => handle_alloc_error(Layout::from_size_align_unchecked( new_size, cur.align(), @@ -308,13 +308,14 @@ pub fn double(&mut self) { // Skip to 4 because tiny `Vec`'s are dumb; but not if that // would cause overflow. let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; - match self.a.alloc_array::(new_cap) { - Ok(ptr) => (new_cap, ptr.into()), - Err(_) => handle_alloc_error(Layout::array::(new_cap).unwrap()), + let layout = Layout::array::(new_cap).unwrap(); + match self.a.alloc(layout) { + Ok(ptr) => (new_cap, ptr), + Err(_) => handle_alloc_error(layout), } } }; - self.ptr = uniq; + self.ptr = ptr.cast().into(); self.cap = new_cap; } } diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 38df843d258..c75ef44655f 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -593,9 +593,8 @@ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut /// /// * the starting address for that memory block was previously /// returned by a previous call to an allocation method (`alloc`, -/// `alloc_zeroed`, `alloc_excess`, `alloc_one`, `alloc_array`) or -/// reallocation method (`realloc`, `realloc_excess`, or -/// `realloc_array`), and +/// `alloc_zeroed`, `alloc_excess`) or reallocation method +/// (`realloc`, `realloc_excess`), and /// /// * the memory block has not been subsequently deallocated, where /// blocks are deallocated either by being passed to a deallocation @@ -606,11 +605,6 @@ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut /// methods in the `AllocRef` trait state that allocation requests /// must be non-zero size, or else undefined behavior can result. /// -/// * However, some higher-level allocation methods (`alloc_one`, -/// `alloc_array`) are well-defined on zero-sized types and can -/// optionally support them: it is left up to the implementor -/// whether to return `Err`, or to return `Ok` with some pointer. -/// /// * If an `AllocRef` implementation chooses to return `Ok` in this /// case (i.e., the pointer denotes a zero-sized inaccessible block) /// then that returned pointer must be considered "currently @@ -1035,195 +1029,4 @@ unsafe fn shrink_in_place( // new_layout.size() <= layout.size() [required by this method] if l <= new_size { Ok(()) } else { Err(CannotReallocInPlace) } } - - // == COMMON USAGE PATTERNS == - // alloc_one, dealloc_one, alloc_array, realloc_array. dealloc_array - - /// Allocates a block suitable for holding an instance of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `realloc`/`dealloc` methods of this allocator. - /// - /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` - /// must be considered "currently allocated" and must be - /// acceptable input to methods such as `realloc` or `dealloc`, - /// *even if* `T` is a zero-sized type. In other words, if your - /// `AllocRef` implementation overrides this method in a manner - /// that can return a zero-sized `ptr`, then all reallocation and - /// deallocation methods need to be similarly overridden to accept - /// such values as input. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `T` does not meet allocator's size or alignment constraints. - /// - /// For zero-sized `T`, may return either of `Ok` or `Err`, but - /// will *not* yield undefined behavior. - /// - /// 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_one(&mut self) -> Result, AllocErr> - where - Self: Sized, - { - let k = Layout::new::(); - if k.size() > 0 { unsafe { self.alloc(k).map(|p| p.cast()) } } else { Err(AllocErr) } - } - - /// Deallocates a block suitable for holding an instance of `T`. - /// - /// The given block must have been produced by this allocator, - /// and must be suitable for storing a `T` (in terms of alignment - /// as well as minimum and maximum size); otherwise yields - /// undefined behavior. - /// - /// Captures a common usage pattern for allocators. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure both: - /// - /// * `ptr` must denote a block of memory currently allocated via this allocator - /// - /// * the layout of `T` must *fit* that block of memory. - unsafe fn dealloc_one(&mut self, ptr: NonNull) - where - Self: Sized, - { - let k = Layout::new::(); - if k.size() > 0 { - self.dealloc(ptr.cast(), k); - } - } - - /// Allocates a block suitable for holding `n` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `realloc`/`dealloc` methods of this allocator. - /// - /// Note to implementors: If this returns `Ok(ptr)`, then `ptr` - /// must be considered "currently allocated" and must be - /// acceptable input to methods such as `realloc` or `dealloc`, - /// *even if* `T` is a zero-sized type. In other words, if your - /// `AllocRef` implementation overrides this method in a manner - /// that can return a zero-sized `ptr`, then all reallocation and - /// deallocation methods need to be similarly overridden to accept - /// such values as input. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `[T; n]` does not meet allocator's size or alignment - /// constraints. - /// - /// For zero-sized `T` or `n == 0`, may return either of `Ok` or - /// `Err`, but will *not* yield undefined behavior. - /// - /// Always returns `Err` on arithmetic overflow. - /// - /// 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_array(&mut self, n: usize) -> Result, AllocErr> - where - Self: Sized, - { - match Layout::array::(n) { - Ok(layout) if layout.size() > 0 => unsafe { self.alloc(layout).map(|p| p.cast()) }, - _ => Err(AllocErr), - } - } - - /// Reallocates a block previously suitable for holding `n_old` - /// instances of `T`, returning a block suitable for holding - /// `n_new` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// The returned block is suitable for passing to the - /// `realloc`/`dealloc` methods of this allocator. - /// - /// # 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, - /// - /// * the layout of `[T; n_old]` must *fit* that block of memory. - /// - /// # Errors - /// - /// Returning `Err` indicates that either memory is exhausted or - /// `[T; n_new]` does not meet allocator's size or alignment - /// constraints. - /// - /// For zero-sized `T` or `n_new == 0`, may return either of `Ok` or - /// `Err`, but will *not* yield undefined behavior. - /// - /// Always returns `Err` on arithmetic overflow. - /// - /// 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_array( - &mut self, - ptr: NonNull, - n_old: usize, - n_new: usize, - ) -> Result, AllocErr> - where - Self: Sized, - { - match (Layout::array::(n_old), Layout::array::(n_new)) { - (Ok(k_old), Ok(k_new)) if k_old.size() > 0 && k_new.size() > 0 => { - debug_assert!(k_old.align() == k_new.align()); - self.realloc(ptr.cast(), k_old, k_new.size()).map(NonNull::cast) - } - _ => Err(AllocErr), - } - } - - /// Deallocates a block suitable for holding `n` instances of `T`. - /// - /// Captures a common usage pattern for allocators. - /// - /// # Safety - /// - /// This function is unsafe because undefined behavior can result - /// if the caller does not ensure both: - /// - /// * `ptr` must denote a block of memory currently allocated via this allocator - /// - /// * the layout of `[T; n]` must *fit* that block of memory. - /// - /// # Errors - /// - /// Returning `Err` indicates that either `[T; n]` or the given - /// memory block does not meet allocator's size or alignment - /// constraints. - /// - /// Always returns `Err` on arithmetic overflow. - unsafe fn dealloc_array(&mut self, ptr: NonNull, n: usize) -> Result<(), AllocErr> - where - Self: Sized, - { - match Layout::array::(n) { - Ok(k) if k.size() > 0 => Ok(self.dealloc(ptr.cast(), k)), - _ => Err(AllocErr), - } - } } diff --git a/src/test/ui/allocator-alloc-one.rs b/src/test/ui/allocator-alloc-one.rs deleted file mode 100644 index b821a2c5939..00000000000 --- a/src/test/ui/allocator-alloc-one.rs +++ /dev/null @@ -1,18 +0,0 @@ -// run-pass - -#![allow(stable_features)] - -#![feature(allocator_api, nonnull)] - -use std::alloc::{AllocRef, Global, Layout, handle_alloc_error}; - -fn main() { - unsafe { - let ptr = Global.alloc_one::().unwrap_or_else(|_| { - handle_alloc_error(Layout::new::()) - }); - *ptr.as_ptr() = 4; - assert_eq!(*ptr.as_ptr(), 4); - Global.dealloc_one(ptr); - } -}