Stabilize alloc_layout_extra

This commit is contained in:
Pavel Grigorenko 2025-11-09 23:17:09 +03:00
parent 08f833aa17
commit e212560317
15 changed files with 58 additions and 51 deletions

View file

@ -14,11 +14,10 @@ diff --git a/coretests/tests/lib.rs b/coretests/tests/lib.rs
index 1e336bf..35e6f54 100644
--- a/coretests/tests/lib.rs
+++ b/coretests/tests/lib.rs
@@ -2,5 +2,4 @@
@@ -2,4 +2,3 @@
// tidy-alphabetical-start
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
#![cfg_attr(test, feature(cfg_select))]
#![feature(alloc_layout_extra)]
#![feature(array_ptr_get)]
diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs
index b735957..ea728b6 100644

View file

@ -184,7 +184,7 @@ impl Global {
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
fn alloc_impl_runtime(layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
match layout.size() {
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)),
// SAFETY: `layout` is non-zero in size,
size => unsafe {
let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) };
@ -277,7 +277,7 @@ impl Global {
// SAFETY: conditions must be upheld by the caller
0 => unsafe {
self.deallocate(ptr, old_layout);
Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0))
Ok(NonNull::slice_from_raw_parts(new_layout.dangling_ptr(), 0))
},
// SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
@ -368,7 +368,7 @@ impl Global {
#[rustc_const_unstable(feature = "const_heap", issue = "79597")]
const fn alloc_impl_const(layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
match layout.size() {
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)),
// SAFETY: `layout` is non-zero in size,
size => unsafe {
let raw_ptr = core::intrinsics::const_allocate(layout.size(), layout.align());

View file

@ -834,7 +834,7 @@ impl<T: ?Sized + CloneToUninit, A: Allocator> Box<T, A> {
}
let layout = Layout::for_value::<T>(src);
let (ptr, guard) = if layout.size() == 0 {
(layout.dangling(), None)
(layout.dangling_ptr(), None)
} else {
// Safety: layout is non-zero-sized
let ptr = alloc.allocate(layout)?.cast();

View file

@ -245,7 +245,7 @@ impl<H> WithHeader<H> {
// Some paranoia checking, mostly so that the ThinBox tests are
// more able to catch issues.
debug_assert!(value_offset == 0 && T::IS_ZST && H::IS_ZST);
layout.dangling()
layout.dangling_ptr()
} else {
let ptr = alloc::alloc(layout);
if ptr.is_null() {
@ -282,7 +282,7 @@ impl<H> WithHeader<H> {
// Some paranoia checking, mostly so that the ThinBox tests are
// more able to catch issues.
debug_assert!(value_offset == 0 && size_of::<T>() == 0 && size_of::<H>() == 0);
layout.dangling()
layout.dangling_ptr()
} else {
let ptr = alloc::alloc(layout);
if ptr.is_null() {

View file

@ -86,7 +86,6 @@
// Library features:
// tidy-alphabetical-start
#![cfg_attr(not(no_global_oom_handling), feature(string_replace_in_place))]
#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
#![feature(array_into_iter_constructors)]
#![feature(ascii_char)]

View file

@ -261,7 +261,7 @@ use core::panic::{RefUnwindSafe, UnwindSafe};
#[cfg(not(no_global_oom_handling))]
use core::pin::Pin;
use core::pin::PinCoerceUnsized;
use core::ptr::{self, NonNull, drop_in_place};
use core::ptr::{self, Alignment, NonNull, drop_in_place};
#[cfg(not(no_global_oom_handling))]
use core::slice::from_raw_parts_mut;
use core::{borrow, fmt, hint};
@ -3847,11 +3847,11 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize {
// and extern types, the input safety requirement is currently enough to
// satisfy the requirements of align_of_val_raw; this is an implementation
// detail of the language that must not be relied upon outside of std.
unsafe { data_offset_align(align_of_val_raw(ptr)) }
unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) }
}
#[inline]
fn data_offset_align(align: usize) -> usize {
fn data_offset_align(align: Alignment) -> usize {
let layout = Layout::new::<RcInner<()>>();
layout.size() + layout.padding_needed_for(align)
}
@ -4478,7 +4478,7 @@ impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> {
/// Returns the pointer to be written into to initialize the [`Rc`].
fn data_ptr(&mut self) -> *mut T {
let offset = data_offset_align(self.layout_for_value.align());
let offset = data_offset_align(self.layout_for_value.alignment());
unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T }
}

View file

@ -26,7 +26,7 @@ use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, Lega
use core::ops::{Residual, Try};
use core::panic::{RefUnwindSafe, UnwindSafe};
use core::pin::{Pin, PinCoerceUnsized};
use core::ptr::{self, NonNull};
use core::ptr::{self, Alignment, NonNull};
#[cfg(not(no_global_oom_handling))]
use core::slice::from_raw_parts_mut;
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release};
@ -4208,11 +4208,11 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize {
// and extern types, the input safety requirement is currently enough to
// satisfy the requirements of align_of_val_raw; this is an implementation
// detail of the language that must not be relied upon outside of std.
unsafe { data_offset_align(align_of_val_raw(ptr)) }
unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) }
}
#[inline]
fn data_offset_align(align: usize) -> usize {
fn data_offset_align(align: Alignment) -> usize {
let layout = Layout::new::<ArcInner<()>>();
layout.size() + layout.padding_needed_for(align)
}
@ -4258,7 +4258,7 @@ impl<T: ?Sized, A: Allocator> UniqueArcUninit<T, A> {
/// Returns the pointer to be written into to initialize the [`Arc`].
fn data_ptr(&mut self) -> *mut T {
let offset = data_offset_align(self.layout_for_value.align());
let offset = data_offset_align(self.layout_for_value.alignment());
unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T }
}

View file

@ -14,7 +14,6 @@
//
// Library features:
// tidy-alphabetical-start
#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
#![feature(array_into_iter_constructors)]
#![feature(assert_matches)]

View file

@ -104,7 +104,7 @@ pub struct ConstAllocator;
unsafe impl Allocator for ConstAllocator {
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
match layout.size() {
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)),
_ => unsafe {
let ptr = core::intrinsics::const_allocate(layout.size(), layout.align());
Ok(NonNull::new_unchecked(ptr as *mut [u8; 0] as *mut [u8]))

View file

@ -1,5 +1,4 @@
#![feature(allocator_api)]
#![feature(alloc_layout_extra)]
#![feature(const_heap)]
#![feature(deque_extend_front)]
#![feature(iter_array_chunks)]

View file

@ -217,10 +217,11 @@ impl Layout {
/// be that of 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")]
#[stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[must_use]
#[inline]
pub const fn dangling(&self) -> NonNull<u8> {
pub const fn dangling_ptr(&self) -> NonNull<u8> {
NonNull::without_provenance(self.align.as_nonzero())
}
@ -250,29 +251,23 @@ impl Layout {
}
/// Returns the amount of padding we must insert after `self`
/// to ensure that the following address will satisfy `align`
/// (measured in bytes).
/// to ensure that the following address will satisfy `alignment`.
///
/// e.g., if `self.size()` is 9, then `self.padding_needed_for(4)`
/// e.g., if `self.size()` is 9, then `self.padding_needed_for(alignment4)`
/// (where `alignment4.as_usize() == 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`
/// Note that the utility of the returned value requires `alignment`
/// 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")]
#[must_use = "this returns the padding needed, \
without modifying the `Layout`"]
/// satisfy this constraint is to ensure `alignment.as_usize() <= self.align()`.
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
#[must_use = "this returns the padding needed, without modifying the `Layout`"]
#[inline]
pub const fn padding_needed_for(&self, align: usize) -> usize {
// FIXME: Can we just change the type on this to `Alignment`?
let Some(align) = Alignment::new(align) else { return usize::MAX };
let len_rounded_up = self.size_rounded_up_to_custom_align(align);
pub const fn padding_needed_for(&self, alignment: Alignment) -> usize {
let len_rounded_up = self.size_rounded_up_to_custom_align(alignment);
// SAFETY: Cannot overflow because the rounded-up value is never less
unsafe { unchecked_sub(len_rounded_up, self.size) }
}
@ -335,6 +330,8 @@ impl Layout {
/// layout of the array and `offs` is the distance between the start
/// of each element in the array.
///
/// Does not include padding after the trailing element.
///
/// (That distance between elements is sometimes known as "stride".)
///
/// On arithmetic overflow, returns `LayoutError`.
@ -342,7 +339,6 @@ impl Layout {
/// # Examples
///
/// ```
/// #![feature(alloc_layout_extra)]
/// use std::alloc::Layout;
///
/// // All rust types have a size that's a multiple of their alignment.
@ -353,17 +349,32 @@ impl Layout {
/// // But you can manually make layouts which don't meet that rule.
/// let padding_needed = Layout::from_size_align(6, 4).unwrap();
/// let repeated = padding_needed.repeat(3).unwrap();
/// assert_eq!(repeated, (Layout::from_size_align(24, 4).unwrap(), 8));
/// assert_eq!(repeated, (Layout::from_size_align(22, 4).unwrap(), 8));
///
/// // Repeating an element zero times has zero size, but keeps the alignment (like `[T; 0]`)
/// let repeated = normal.repeat(0).unwrap();
/// assert_eq!(repeated, (Layout::from_size_align(0, 4).unwrap(), 12));
/// let repeated = padding_needed.repeat(0).unwrap();
/// assert_eq!(repeated, (Layout::from_size_align(0, 4).unwrap(), 8));
/// ```
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
#[stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutError> {
// FIXME(const-hack): the following could be way shorter with `?`
let padded = self.pad_to_align();
if let Ok(repeated) = padded.repeat_packed(n) {
Ok((repeated, padded.size()))
let Ok(result) = (if let Some(k) = n.checked_sub(1) {
let Ok(repeated) = padded.repeat_packed(k) else {
return Err(LayoutError);
};
repeated.extend_packed(*self)
} else {
Err(LayoutError)
}
debug_assert!(n == 0);
self.repeat_packed(0)
}) else {
return Err(LayoutError);
};
Ok((result, padded.size()))
}
/// Creates a layout describing the record for `self` followed by
@ -443,7 +454,8 @@ impl Layout {
/// aligned.
///
/// On arithmetic overflow, returns `LayoutError`.
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
#[stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn repeat_packed(&self, n: usize) -> Result<Self, LayoutError> {
if let Some(size) = self.size.checked_mul(n) {
@ -460,7 +472,8 @@ impl Layout {
/// and is not incorporated *at all* into the resulting layout.
///
/// On arithmetic overflow, returns `LayoutError`.
#[unstable(feature = "alloc_layout_extra", issue = "55724")]
#[stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[rustc_const_stable(feature = "alloc_layout_extra", since = "CURRENT_RUSTC_VERSION")]
#[inline]
pub const fn extend_packed(&self, next: Self) -> Result<Self, LayoutError> {
// SAFETY: each `size` is at most `isize::MAX == usize::MAX/2`, so the

View file

@ -6,7 +6,7 @@ fn const_unchecked_layout() {
const SIZE: usize = 0x2000;
const ALIGN: usize = 0x1000;
const LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(SIZE, ALIGN) };
const DANGLING: NonNull<u8> = LAYOUT.dangling();
const DANGLING: NonNull<u8> = LAYOUT.dangling_ptr();
assert_eq!(LAYOUT.size(), SIZE);
assert_eq!(LAYOUT.align(), ALIGN);
assert_eq!(Some(DANGLING), NonNull::new(ptr::without_provenance_mut(ALIGN)));

View file

@ -1,7 +1,6 @@
// tidy-alphabetical-start
#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
#![cfg_attr(test, feature(cfg_select))]
#![feature(alloc_layout_extra)]
#![feature(array_ptr_get)]
#![feature(array_try_from_fn)]
#![feature(array_try_map)]

View file

@ -142,7 +142,7 @@ impl System {
#[inline]
fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
match layout.size() {
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
0 => Ok(NonNull::slice_from_raw_parts(layout.dangling_ptr(), 0)),
// SAFETY: `layout` is non-zero in size,
size => unsafe {
let raw_ptr = if zeroed {
@ -266,7 +266,7 @@ unsafe impl Allocator for System {
// SAFETY: conditions must be upheld by the caller
0 => unsafe {
Allocator::deallocate(self, ptr, old_layout);
Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0))
Ok(NonNull::slice_from_raw_parts(new_layout.dangling_ptr(), 0))
},
// SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller

View file

@ -367,7 +367,6 @@
//
// Library features (alloc):
// tidy-alphabetical-start
#![feature(alloc_layout_extra)]
#![feature(allocator_api)]
#![feature(clone_from_ref)]
#![feature(get_mut_unchecked)]