Skip to content

Commit 988791e

Browse files
committed
ptr_aligment_type: add more APIs
1 parent d45e7f6 commit 988791e

11 files changed

+334
-157
lines changed

library/alloc/src/rc.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ use core::intrinsics::abort;
252252
#[cfg(not(no_global_oom_handling))]
253253
use core::iter;
254254
use core::marker::{PhantomData, Unsize};
255-
use core::mem::{self, ManuallyDrop, align_of_val_raw};
255+
use core::mem::{self, ManuallyDrop};
256256
use core::num::NonZeroUsize;
257257
use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver};
258258
#[cfg(not(no_global_oom_handling))]
@@ -3845,15 +3845,15 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize {
38453845
// Because RcInner is repr(C), it will always be the last field in memory.
38463846
// SAFETY: since the only unsized types possible are slices, trait objects,
38473847
// and extern types, the input safety requirement is currently enough to
3848-
// satisfy the requirements of align_of_val_raw; this is an implementation
3848+
// satisfy the requirements of Alignment::of_val_raw; this is an implementation
38493849
// detail of the language that must not be relied upon outside of std.
3850-
unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) }
3850+
unsafe { data_offset_alignment(Alignment::of_val_raw(ptr)) }
38513851
}
38523852

38533853
#[inline]
3854-
fn data_offset_align(align: Alignment) -> usize {
3854+
fn data_offset_alignment(alignment: Alignment) -> usize {
38553855
let layout = Layout::new::<RcInner<()>>();
3856-
layout.size() + layout.padding_needed_for(align)
3856+
layout.size() + layout.padding_needed_for(alignment)
38573857
}
38583858

38593859
/// A uniquely owned [`Rc`].
@@ -4478,7 +4478,7 @@ impl<T: ?Sized, A: Allocator> UniqueRcUninit<T, A> {
44784478

44794479
/// Returns the pointer to be written into to initialize the [`Rc`].
44804480
fn data_ptr(&mut self) -> *mut T {
4481-
let offset = data_offset_align(self.layout_for_value.alignment());
4481+
let offset = data_offset_alignment(self.layout_for_value.alignment());
44824482
unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T }
44834483
}
44844484

library/alloc/src/sync.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use core::intrinsics::abort;
1919
#[cfg(not(no_global_oom_handling))]
2020
use core::iter;
2121
use core::marker::{PhantomData, Unsize};
22-
use core::mem::{self, ManuallyDrop, align_of_val_raw};
22+
use core::mem::{self, ManuallyDrop};
2323
use core::num::NonZeroUsize;
2424
use core::ops::{CoerceUnsized, Deref, DerefMut, DerefPure, DispatchFromDyn, LegacyReceiver};
2525
#[cfg(not(no_global_oom_handling))]
@@ -4206,15 +4206,15 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize {
42064206
// Because ArcInner is repr(C), it will always be the last field in memory.
42074207
// SAFETY: since the only unsized types possible are slices, trait objects,
42084208
// and extern types, the input safety requirement is currently enough to
4209-
// satisfy the requirements of align_of_val_raw; this is an implementation
4209+
// satisfy the requirements of Alignment::of_val_raw; this is an implementation
42104210
// detail of the language that must not be relied upon outside of std.
4211-
unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) }
4211+
unsafe { data_offset_alignment(Alignment::of_val_raw(ptr)) }
42124212
}
42134213

42144214
#[inline]
4215-
fn data_offset_align(align: Alignment) -> usize {
4215+
fn data_offset_alignment(alignment: Alignment) -> usize {
42164216
let layout = Layout::new::<ArcInner<()>>();
4217-
layout.size() + layout.padding_needed_for(align)
4217+
layout.size() + layout.padding_needed_for(alignment)
42184218
}
42194219

42204220
/// A unique owning pointer to an [`ArcInner`] **that does not imply the contents are initialized,**
@@ -4258,7 +4258,7 @@ impl<T: ?Sized, A: Allocator> UniqueArcUninit<T, A> {
42584258

42594259
/// Returns the pointer to be written into to initialize the [`Arc`].
42604260
fn data_ptr(&mut self) -> *mut T {
4261-
let offset = data_offset_align(self.layout_for_value.alignment());
4261+
let offset = data_offset_alignment(self.layout_for_value.alignment());
42624262
unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T }
42634263
}
42644264

library/core/src/alloc/layout.rs

Lines changed: 97 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,16 @@ impl Layout {
6767

6868
#[inline]
6969
const fn is_size_align_valid(size: usize, align: usize) -> bool {
70-
let Some(align) = Alignment::new(align) else { return false };
71-
if size > Self::max_size_for_align(align) {
72-
return false;
73-
}
74-
true
70+
let Some(alignment) = Alignment::new(align) else { return false };
71+
Self::is_size_alignment_valid(size, alignment)
72+
}
73+
74+
const fn is_size_alignment_valid(size: usize, alignment: Alignment) -> bool {
75+
size <= Self::max_size_for_alignment(alignment)
7576
}
7677

7778
#[inline(always)]
78-
const fn max_size_for_align(align: Alignment) -> usize {
79+
const fn max_size_for_alignment(alignment: Alignment) -> usize {
7980
// (power-of-two implies align != 0.)
8081

8182
// Rounded up size is:
@@ -93,18 +94,28 @@ impl Layout {
9394

9495
// SAFETY: the maximum possible alignment is `isize::MAX + 1`,
9596
// so the subtraction cannot overflow.
96-
unsafe { unchecked_sub(isize::MAX as usize + 1, align.as_usize()) }
97+
unsafe { unchecked_sub(isize::MAX as usize + 1, alignment.as_usize()) }
9798
}
9899

99-
/// Internal helper constructor to skip revalidating alignment validity.
100+
/// Constructs a `Layout` from a given `size` and `alignment`,
101+
/// or returns `LayoutError` if any of the following conditions
102+
/// are not met:
103+
///
104+
/// * `size`, when rounded up to the nearest multiple of `alignment`,
105+
/// must not overflow `isize` (i.e., the rounded value must be
106+
/// less than or equal to `isize::MAX`).
107+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
100108
#[inline]
101-
const fn from_size_alignment(size: usize, align: Alignment) -> Result<Self, LayoutError> {
102-
if size > Self::max_size_for_align(align) {
103-
return Err(LayoutError);
109+
pub const fn from_size_alignment(
110+
size: usize,
111+
alignment: Alignment,
112+
) -> Result<Self, LayoutError> {
113+
if Layout::is_size_alignment_valid(size, alignment) {
114+
// SAFETY: Layout::size invariants checked above.
115+
Ok(Layout { size, align: alignment })
116+
} else {
117+
Err(LayoutError)
104118
}
105-
106-
// SAFETY: Layout::size invariants checked above.
107-
Ok(Layout { size, align })
108119
}
109120

110121
/// Creates a layout, bypassing all checks.
@@ -132,6 +143,30 @@ impl Layout {
132143
unsafe { Layout { size, align: mem::transmute(align) } }
133144
}
134145

146+
/// Creates a layout, bypassing all checks.
147+
///
148+
/// # Safety
149+
///
150+
/// This function is unsafe as it does not verify the preconditions from
151+
/// [`Layout::from_size_alignment`].
152+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
153+
#[must_use]
154+
#[inline]
155+
#[track_caller]
156+
pub const unsafe fn from_size_alignment_unchecked(size: usize, alignment: Alignment) -> Self {
157+
assert_unsafe_precondition!(
158+
check_library_ub,
159+
"Layout::from_size_alignment_unchecked requires \
160+
that the rounded-up allocation size does not exceed isize::MAX",
161+
(
162+
size: usize = size,
163+
alignment: Alignment = alignment,
164+
) => Layout::is_size_alignment_valid(size, alignment)
165+
);
166+
// SAFETY: the caller is required to uphold the preconditions.
167+
Layout { size, align: alignment }
168+
}
169+
135170
/// The minimum size in bytes for a memory block of this layout.
136171
#[stable(feature = "alloc_layout", since = "1.28.0")]
137172
#[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
@@ -153,6 +188,16 @@ impl Layout {
153188
self.align.as_usize()
154189
}
155190

191+
/// The minimum byte alignment for a memory block of this layout.
192+
///
193+
/// The returned alignment is guaranteed to be a power of two.
194+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
195+
#[must_use = "this returns the minimum alignment, without modifying the layout"]
196+
#[inline]
197+
pub const fn alignment(&self) -> Alignment {
198+
self.align
199+
}
200+
156201
/// Constructs a `Layout` suitable for holding a value of type `T`.
157202
#[stable(feature = "alloc_layout", since = "1.28.0")]
158203
#[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")]
@@ -170,9 +215,9 @@ impl Layout {
170215
#[must_use]
171216
#[inline]
172217
pub const fn for_value<T: ?Sized>(t: &T) -> Self {
173-
let (size, align) = (size_of_val(t), align_of_val(t));
218+
let (size, alignment) = (size_of_val(t), Alignment::of_val(t));
174219
// SAFETY: see rationale in `new` for why this is using the unsafe variant
175-
unsafe { Layout::from_size_align_unchecked(size, align) }
220+
unsafe { Layout::from_size_alignment_unchecked(size, alignment) }
176221
}
177222

178223
/// Produces layout describing a record that could be used to
@@ -204,11 +249,12 @@ impl Layout {
204249
/// [extern type]: ../../unstable-book/language-features/extern-types.html
205250
#[unstable(feature = "layout_for_ptr", issue = "69835")]
206251
#[must_use]
252+
#[inline]
207253
pub const unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
208254
// SAFETY: we pass along the prerequisites of these functions to the caller
209-
let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) };
255+
let (size, alignment) = unsafe { (mem::size_of_val_raw(t), Alignment::of_val_raw(t)) };
210256
// SAFETY: see rationale in `new` for why this is using the unsafe variant
211-
unsafe { Layout::from_size_align_unchecked(size, align) }
257+
unsafe { Layout::from_size_alignment_unchecked(size, alignment) }
212258
}
213259

214260
/// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
@@ -243,13 +289,33 @@ impl Layout {
243289
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
244290
#[inline]
245291
pub const fn align_to(&self, align: usize) -> Result<Self, LayoutError> {
246-
if let Some(align) = Alignment::new(align) {
247-
Layout::from_size_alignment(self.size, Alignment::max(self.align, align))
292+
if let Some(alignment) = Alignment::new(align) {
293+
self.adjust_alignment_to(alignment)
248294
} else {
249295
Err(LayoutError)
250296
}
251297
}
252298

299+
/// Creates a layout describing the record that can hold a value
300+
/// of the same layout as `self`, but that also is aligned to
301+
/// alignment `alignment`.
302+
///
303+
/// If `self` already meets the prescribed alignment, then returns
304+
/// `self`.
305+
///
306+
/// Note that this method does not add any padding to the overall
307+
/// size, regardless of whether the returned layout has a different
308+
/// alignment. In other words, if `K` has size 16, `K.align_to(32)`
309+
/// will *still* have size 16.
310+
///
311+
/// Returns an error if the combination of `self.size()` and the given
312+
/// `alignment` violates the conditions listed in [`Layout::from_size_alignment`].
313+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
314+
#[inline]
315+
pub const fn adjust_alignment_to(&self, alignment: Alignment) -> Result<Self, LayoutError> {
316+
Layout::from_size_alignment(self.size, Alignment::max(self.align, alignment))
317+
}
318+
253319
/// Returns the amount of padding we must insert after `self`
254320
/// to ensure that the following address will satisfy `alignment`.
255321
///
@@ -267,7 +333,7 @@ impl Layout {
267333
#[must_use = "this returns the padding needed, without modifying the `Layout`"]
268334
#[inline]
269335
pub const fn padding_needed_for(&self, alignment: Alignment) -> usize {
270-
let len_rounded_up = self.size_rounded_up_to_custom_align(alignment);
336+
let len_rounded_up = self.size_rounded_up_to_custom_alignment(alignment);
271337
// SAFETY: Cannot overflow because the rounded-up value is never less
272338
unsafe { unchecked_sub(len_rounded_up, self.size) }
273339
}
@@ -277,7 +343,7 @@ impl Layout {
277343
/// This can return at most `Alignment::MAX` (aka `isize::MAX + 1`)
278344
/// because the original size is at most `isize::MAX`.
279345
#[inline]
280-
const fn size_rounded_up_to_custom_align(&self, align: Alignment) -> usize {
346+
const fn size_rounded_up_to_custom_alignment(&self, alignment: Alignment) -> usize {
281347
// SAFETY:
282348
// Rounded up value is:
283349
// size_rounded_up = (size + align - 1) & !(align - 1);
@@ -297,7 +363,7 @@ impl Layout {
297363
// (Size 0 Align MAX is already aligned, so stays the same, but things like
298364
// Size 1 Align MAX or Size isize::MAX Align 2 round up to `isize::MAX + 1`.)
299365
unsafe {
300-
let align_m1 = unchecked_sub(align.as_usize(), 1);
366+
let align_m1 = unchecked_sub(alignment.as_usize(), 1);
301367
unchecked_add(self.size, align_m1) & !align_m1
302368
}
303369
}
@@ -317,10 +383,10 @@ impl Layout {
317383
// > `size`, when rounded up to the nearest multiple of `align`,
318384
// > must not overflow isize (i.e., the rounded value must be
319385
// > less than or equal to `isize::MAX`)
320-
let new_size = self.size_rounded_up_to_custom_align(self.align);
386+
let new_size = self.size_rounded_up_to_custom_alignment(self.align);
321387

322388
// SAFETY: padded size is guaranteed to not exceed `isize::MAX`.
323-
unsafe { Layout::from_size_align_unchecked(new_size, self.align()) }
389+
unsafe { Layout::from_size_alignment_unchecked(new_size, self.alignment()) }
324390
}
325391

326392
/// Creates a layout describing the record for `n` instances of
@@ -426,16 +492,16 @@ impl Layout {
426492
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
427493
#[inline]
428494
pub const fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> {
429-
let new_align = Alignment::max(self.align, next.align);
430-
let offset = self.size_rounded_up_to_custom_align(next.align);
495+
let new_alignment = Alignment::max(self.align, next.align);
496+
let offset = self.size_rounded_up_to_custom_alignment(next.align);
431497

432498
// SAFETY: `offset` is at most `isize::MAX + 1` (such as from aligning
433499
// to `Alignment::MAX`) and `next.size` is at most `isize::MAX` (from the
434500
// `Layout` type invariant). Thus the largest possible `new_size` is
435501
// `isize::MAX + 1 + isize::MAX`, which is `usize::MAX`, and cannot overflow.
436502
let new_size = unsafe { unchecked_add(offset, next.size) };
437503

438-
if let Ok(layout) = Layout::from_size_alignment(new_size, new_align) {
504+
if let Ok(layout) = Layout::from_size_alignment(new_size, new_alignment) {
439505
Ok((layout, offset))
440506
} else {
441507
Err(LayoutError)
@@ -496,15 +562,15 @@ impl Layout {
496562

497563
#[inline]
498564
const fn inner(element_layout: Layout, n: usize) -> Result<Layout, LayoutError> {
499-
let Layout { size: element_size, align } = element_layout;
565+
let Layout { size: element_size, align: alignment } = element_layout;
500566

501567
// We need to check two things about the size:
502568
// - That the total size won't overflow a `usize`, and
503569
// - That the total size still fits in an `isize`.
504570
// By using division we can check them both with a single threshold.
505571
// That'd usually be a bad idea, but thankfully here the element size
506572
// and alignment are constants, so the compiler will fold all of it.
507-
if element_size != 0 && n > Layout::max_size_for_align(align) / element_size {
573+
if element_size != 0 && n > Layout::max_size_for_alignment(alignment) / element_size {
508574
return Err(LayoutError);
509575
}
510576

@@ -517,17 +583,9 @@ impl Layout {
517583
// SAFETY: We just checked above that the `array_size` will not
518584
// exceed `isize::MAX` even when rounded up to the alignment.
519585
// And `Alignment` guarantees it's a power of two.
520-
unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) }
586+
unsafe { Ok(Layout::from_size_alignment_unchecked(array_size, alignment)) }
521587
}
522588
}
523-
524-
/// Perma-unstable access to `align` as `Alignment` type.
525-
#[unstable(issue = "none", feature = "std_internals")]
526-
#[doc(hidden)]
527-
#[inline]
528-
pub const fn alignment(&self) -> Alignment {
529-
self.align
530-
}
531589
}
532590

533591
#[stable(feature = "alloc_layout", since = "1.28.0")]

library/core/src/mem/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use crate::alloc::Layout;
99
use crate::clone::TrivialClone;
1010
use crate::marker::{Destruct, DiscriminantKind};
1111
use crate::panic::const_assert;
12+
use crate::ptr::Alignment;
1213
use crate::{clone, cmp, fmt, hash, intrinsics, ptr};
1314

1415
mod manually_drop;
@@ -1250,6 +1251,10 @@ pub trait SizedTypeProperties: Sized {
12501251
#[lang = "mem_align_const"]
12511252
const ALIGN: usize = intrinsics::align_of::<Self>();
12521253

1254+
#[doc(hidden)]
1255+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
1256+
const ALIGNMENT: Alignment = Alignment::of::<Self>();
1257+
12531258
/// `true` if this type requires no storage.
12541259
/// `false` if its [size](size_of) is greater than zero.
12551260
///

0 commit comments

Comments
 (0)