Skip to content

Commit 1f2d172

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

11 files changed

+331
-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: 94 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,25 @@ 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+
const fn from_size_alignment(size: usize, alignment: Alignment) -> Result<Self, LayoutError> {
110+
if Layout::is_size_alignment_valid(size, alignment) {
111+
// SAFETY: Layout::size invariants checked above.
112+
Ok(Layout { size, align: alignment })
113+
} else {
114+
Err(LayoutError)
104115
}
105-
106-
// SAFETY: Layout::size invariants checked above.
107-
Ok(Layout { size, align })
108116
}
109117

110118
/// Creates a layout, bypassing all checks.
@@ -132,6 +140,30 @@ impl Layout {
132140
unsafe { Layout { size, align: mem::transmute(align) } }
133141
}
134142

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

188+
/// The minimum byte alignment for a memory block of this layout.
189+
///
190+
/// The returned alignment is guaranteed to be a power of two.
191+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
192+
#[must_use = "this returns the minimum alignment, without modifying the layout"]
193+
#[inline]
194+
pub const fn alignment(&self) -> Alignment {
195+
self.align
196+
}
197+
156198
/// Constructs a `Layout` suitable for holding a value of type `T`.
157199
#[stable(feature = "alloc_layout", since = "1.28.0")]
158200
#[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")]
@@ -170,9 +212,9 @@ impl Layout {
170212
#[must_use]
171213
#[inline]
172214
pub const fn for_value<T: ?Sized>(t: &T) -> Self {
173-
let (size, align) = (size_of_val(t), align_of_val(t));
215+
let (size, alignment) = (size_of_val(t), Alignment::of_val(t));
174216
// SAFETY: see rationale in `new` for why this is using the unsafe variant
175-
unsafe { Layout::from_size_align_unchecked(size, align) }
217+
unsafe { Layout::from_size_alignment_unchecked(size, alignment) }
176218
}
177219

178220
/// Produces layout describing a record that could be used to
@@ -204,11 +246,12 @@ impl Layout {
204246
/// [extern type]: ../../unstable-book/language-features/extern-types.html
205247
#[unstable(feature = "layout_for_ptr", issue = "69835")]
206248
#[must_use]
249+
#[inline]
207250
pub const unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
208251
// 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)) };
252+
let (size, alignment) = unsafe { (mem::size_of_val_raw(t), Alignment::of_val_raw(t)) };
210253
// SAFETY: see rationale in `new` for why this is using the unsafe variant
211-
unsafe { Layout::from_size_align_unchecked(size, align) }
254+
unsafe { Layout::from_size_alignment_unchecked(size, alignment) }
212255
}
213256

214257
/// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
@@ -243,13 +286,33 @@ impl Layout {
243286
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
244287
#[inline]
245288
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))
289+
if let Some(alignment) = Alignment::new(align) {
290+
self.adjust_alignment_to(alignment)
248291
} else {
249292
Err(LayoutError)
250293
}
251294
}
252295

296+
/// Creates a layout describing the record that can hold a value
297+
/// of the same layout as `self`, but that also is aligned to
298+
/// alignment `alignment`.
299+
///
300+
/// If `self` already meets the prescribed alignment, then returns
301+
/// `self`.
302+
///
303+
/// Note that this method does not add any padding to the overall
304+
/// size, regardless of whether the returned layout has a different
305+
/// alignment. In other words, if `K` has size 16, `K.align_to(32)`
306+
/// will *still* have size 16.
307+
///
308+
/// Returns an error if the combination of `self.size()` and the given
309+
/// `alignment` violates the conditions listed in [`Layout::from_size_alignment`].
310+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
311+
#[inline]
312+
pub const fn adjust_alignment_to(&self, alignment: Alignment) -> Result<Self, LayoutError> {
313+
Layout::from_size_alignment(self.size, Alignment::max(self.align, alignment))
314+
}
315+
253316
/// Returns the amount of padding we must insert after `self`
254317
/// to ensure that the following address will satisfy `alignment`.
255318
///
@@ -267,7 +330,7 @@ impl Layout {
267330
#[must_use = "this returns the padding needed, without modifying the `Layout`"]
268331
#[inline]
269332
pub const fn padding_needed_for(&self, alignment: Alignment) -> usize {
270-
let len_rounded_up = self.size_rounded_up_to_custom_align(alignment);
333+
let len_rounded_up = self.size_rounded_up_to_custom_alignment(alignment);
271334
// SAFETY: Cannot overflow because the rounded-up value is never less
272335
unsafe { unchecked_sub(len_rounded_up, self.size) }
273336
}
@@ -277,7 +340,7 @@ impl Layout {
277340
/// This can return at most `Alignment::MAX` (aka `isize::MAX + 1`)
278341
/// because the original size is at most `isize::MAX`.
279342
#[inline]
280-
const fn size_rounded_up_to_custom_align(&self, align: Alignment) -> usize {
343+
const fn size_rounded_up_to_custom_alignment(&self, alignment: Alignment) -> usize {
281344
// SAFETY:
282345
// Rounded up value is:
283346
// size_rounded_up = (size + align - 1) & !(align - 1);
@@ -297,7 +360,7 @@ impl Layout {
297360
// (Size 0 Align MAX is already aligned, so stays the same, but things like
298361
// Size 1 Align MAX or Size isize::MAX Align 2 round up to `isize::MAX + 1`.)
299362
unsafe {
300-
let align_m1 = unchecked_sub(align.as_usize(), 1);
363+
let align_m1 = unchecked_sub(alignment.as_usize(), 1);
301364
unchecked_add(self.size, align_m1) & !align_m1
302365
}
303366
}
@@ -317,10 +380,10 @@ impl Layout {
317380
// > `size`, when rounded up to the nearest multiple of `align`,
318381
// > must not overflow isize (i.e., the rounded value must be
319382
// > less than or equal to `isize::MAX`)
320-
let new_size = self.size_rounded_up_to_custom_align(self.align);
383+
let new_size = self.size_rounded_up_to_custom_alignment(self.align);
321384

322385
// SAFETY: padded size is guaranteed to not exceed `isize::MAX`.
323-
unsafe { Layout::from_size_align_unchecked(new_size, self.align()) }
386+
unsafe { Layout::from_size_alignment_unchecked(new_size, self.alignment()) }
324387
}
325388

326389
/// Creates a layout describing the record for `n` instances of
@@ -426,16 +489,16 @@ impl Layout {
426489
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
427490
#[inline]
428491
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);
492+
let new_alignment = Alignment::max(self.align, next.align);
493+
let offset = self.size_rounded_up_to_custom_alignment(next.align);
431494

432495
// SAFETY: `offset` is at most `isize::MAX + 1` (such as from aligning
433496
// to `Alignment::MAX`) and `next.size` is at most `isize::MAX` (from the
434497
// `Layout` type invariant). Thus the largest possible `new_size` is
435498
// `isize::MAX + 1 + isize::MAX`, which is `usize::MAX`, and cannot overflow.
436499
let new_size = unsafe { unchecked_add(offset, next.size) };
437500

438-
if let Ok(layout) = Layout::from_size_alignment(new_size, new_align) {
501+
if let Ok(layout) = Layout::from_size_alignment(new_size, new_alignment) {
439502
Ok((layout, offset))
440503
} else {
441504
Err(LayoutError)
@@ -496,15 +559,15 @@ impl Layout {
496559

497560
#[inline]
498561
const fn inner(element_layout: Layout, n: usize) -> Result<Layout, LayoutError> {
499-
let Layout { size: element_size, align } = element_layout;
562+
let Layout { size: element_size, align: alignment } = element_layout;
500563

501564
// We need to check two things about the size:
502565
// - That the total size won't overflow a `usize`, and
503566
// - That the total size still fits in an `isize`.
504567
// By using division we can check them both with a single threshold.
505568
// That'd usually be a bad idea, but thankfully here the element size
506569
// 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 {
570+
if element_size != 0 && n > Layout::max_size_for_alignment(alignment) / element_size {
508571
return Err(LayoutError);
509572
}
510573

@@ -517,17 +580,9 @@ impl Layout {
517580
// SAFETY: We just checked above that the `array_size` will not
518581
// exceed `isize::MAX` even when rounded up to the alignment.
519582
// And `Alignment` guarantees it's a power of two.
520-
unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) }
583+
unsafe { Ok(Layout::from_size_alignment_unchecked(array_size, alignment)) }
521584
}
522585
}
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-
}
531586
}
532587

533588
#[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)