Skip to content

Commit 47829f5

Browse files
committed
ptr_aligment_type: add more APIs
1 parent c271428 commit 47829f5

10 files changed

+326
-152
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))]
@@ -3759,15 +3759,15 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize {
37593759
// Because RcInner is repr(C), it will always be the last field in memory.
37603760
// SAFETY: since the only unsized types possible are slices, trait objects,
37613761
// and extern types, the input safety requirement is currently enough to
3762-
// satisfy the requirements of align_of_val_raw; this is an implementation
3762+
// satisfy the requirements of Alignment::of_val_raw; this is an implementation
37633763
// detail of the language that must not be relied upon outside of std.
3764-
unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) }
3764+
unsafe { data_offset_alignment(Alignment::of_val_raw(ptr)) }
37653765
}
37663766

37673767
#[inline]
3768-
fn data_offset_align(align: Alignment) -> usize {
3768+
fn data_offset_alignment(alignment: Alignment) -> usize {
37693769
let layout = Layout::new::<RcInner<()>>();
3770-
layout.size() + layout.padding_needed_for(align)
3770+
layout.size() + layout.padding_needed_for(alignment)
37713771
}
37723772

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

43804380
/// Returns the pointer to be written into to initialize the [`Rc`].
43814381
fn data_ptr(&mut self) -> *mut T {
4382-
let offset = data_offset_align(self.layout_for_value.alignment());
4382+
let offset = data_offset_alignment(self.layout_for_value.alignment());
43834383
unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T }
43844384
}
43854385

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))]
@@ -4117,15 +4117,15 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> usize {
41174117
// Because ArcInner is repr(C), it will always be the last field in memory.
41184118
// SAFETY: since the only unsized types possible are slices, trait objects,
41194119
// and extern types, the input safety requirement is currently enough to
4120-
// satisfy the requirements of align_of_val_raw; this is an implementation
4120+
// satisfy the requirements of Alignment::of_val_raw; this is an implementation
41214121
// detail of the language that must not be relied upon outside of std.
4122-
unsafe { data_offset_align(Alignment::new_unchecked(align_of_val_raw(ptr))) }
4122+
unsafe { data_offset_alignment(Alignment::of_val_raw(ptr)) }
41234123
}
41244124

41254125
#[inline]
4126-
fn data_offset_align(align: Alignment) -> usize {
4126+
fn data_offset_alignment(alignment: Alignment) -> usize {
41274127
let layout = Layout::new::<ArcInner<()>>();
4128-
layout.size() + layout.padding_needed_for(align)
4128+
layout.size() + layout.padding_needed_for(alignment)
41294129
}
41304130

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

41574157
/// Returns the pointer to be written into to initialize the [`Arc`].
41584158
fn data_ptr(&mut self) -> *mut T {
4159-
let offset = data_offset_align(self.layout_for_value.alignment());
4159+
let offset = data_offset_alignment(self.layout_for_value.alignment());
41604160
unsafe { self.ptr.as_ptr().byte_add(offset) as *mut T }
41614161
}
41624162

library/core/src/alloc/layout.rs

Lines changed: 98 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use crate::{assert_unsafe_precondition, fmt, mem};
1616
//
1717
// * https://github.com/rust-lang/rust/pull/72189
1818
// * https://github.com/rust-lang/rust/pull/79827
19-
const fn size_align<T>() -> (usize, usize) {
20-
(size_of::<T>(), align_of::<T>())
19+
const fn size_alignment<T>() -> (usize, Alignment) {
20+
(size_of::<T>(), Alignment::of::<T>())
2121
}
2222

2323
/// Layout of a block of memory.
@@ -76,15 +76,16 @@ impl Layout {
7676
}
7777

7878
const fn is_size_align_valid(size: usize, align: usize) -> bool {
79-
let Some(align) = Alignment::new(align) else { return false };
80-
if size > Self::max_size_for_align(align) {
81-
return false;
82-
}
83-
true
79+
let Some(alignment) = Alignment::new(align) else { return false };
80+
Self::is_size_alignment_valid(size, alignment)
81+
}
82+
83+
const fn is_size_alignment_valid(size: usize, alignment: Alignment) -> bool {
84+
size <= Self::max_size_for_alignment(alignment)
8485
}
8586

8687
#[inline(always)]
87-
const fn max_size_for_align(align: Alignment) -> usize {
88+
const fn max_size_for_alignment(alignment: Alignment) -> usize {
8889
// (power-of-two implies align != 0.)
8990

9091
// Rounded up size is:
@@ -102,18 +103,25 @@ impl Layout {
102103

103104
// SAFETY: the maximum possible alignment is `isize::MAX + 1`,
104105
// so the subtraction cannot overflow.
105-
unsafe { unchecked_sub(isize::MAX as usize + 1, align.as_usize()) }
106+
unsafe { unchecked_sub(isize::MAX as usize + 1, alignment.as_usize()) }
106107
}
107108

108-
/// Internal helper constructor to skip revalidating alignment validity.
109+
/// Constructs a `Layout` from a given `size` and `alignment`,
110+
/// or returns `LayoutError` if any of the following conditions
111+
/// are not met:
112+
///
113+
/// * `size`, when rounded up to the nearest multiple of `alignment`,
114+
/// must not overflow `isize` (i.e., the rounded value must be
115+
/// less than or equal to `isize::MAX`).
116+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
109117
#[inline]
110-
const fn from_size_alignment(size: usize, align: Alignment) -> Result<Self, LayoutError> {
111-
if size > Self::max_size_for_align(align) {
112-
return Err(LayoutError);
118+
const fn from_size_alignment(size: usize, alignment: Alignment) -> Result<Self, LayoutError> {
119+
if Layout::is_size_alignment_valid(size, alignment) {
120+
// SAFETY: Layout::size invariants checked above.
121+
Ok(Layout { size, align: alignment })
122+
} else {
123+
Err(LayoutError)
113124
}
114-
115-
// SAFETY: Layout::size invariants checked above.
116-
Ok(Layout { size, align })
117125
}
118126

119127
/// Creates a layout, bypassing all checks.
@@ -141,6 +149,30 @@ impl Layout {
141149
unsafe { Layout { size, align: mem::transmute(align) } }
142150
}
143151

152+
/// Creates a layout, bypassing all checks.
153+
///
154+
/// # Safety
155+
///
156+
/// This function is unsafe as it does not verify the preconditions from
157+
/// [`Layout::from_size_alignment`].
158+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
159+
#[must_use]
160+
#[inline]
161+
#[track_caller]
162+
pub const unsafe fn from_size_alignment_unchecked(size: usize, alignment: Alignment) -> Self {
163+
assert_unsafe_precondition!(
164+
check_library_ub,
165+
"Layout::from_size_alignment_unchecked requires \
166+
that the rounded-up allocation size does not exceed isize::MAX",
167+
(
168+
size: usize = size,
169+
alignment: Alignment = alignment,
170+
) => Layout::is_size_alignment_valid(size, alignment)
171+
);
172+
// SAFETY: the caller is required to uphold the preconditions.
173+
Layout { size, align: alignment }
174+
}
175+
144176
/// The minimum size in bytes for a memory block of this layout.
145177
#[stable(feature = "alloc_layout", since = "1.28.0")]
146178
#[rustc_const_stable(feature = "const_alloc_layout_size_align", since = "1.50.0")]
@@ -162,17 +194,27 @@ impl Layout {
162194
self.align.as_usize()
163195
}
164196

197+
/// The minimum byte alignment for a memory block of this layout.
198+
///
199+
/// The returned alignment is guaranteed to be a power of two.
200+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
201+
#[must_use = "this returns the minimum alignment, without modifying the layout"]
202+
#[inline]
203+
pub const fn alignment(&self) -> Alignment {
204+
self.align
205+
}
206+
165207
/// Constructs a `Layout` suitable for holding a value of type `T`.
166208
#[stable(feature = "alloc_layout", since = "1.28.0")]
167209
#[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")]
168210
#[must_use]
169211
#[inline]
170212
pub const fn new<T>() -> Self {
171-
let (size, align) = size_align::<T>();
213+
let (size, alignment) = size_alignment::<T>();
172214
// SAFETY: if the type is instantiated, rustc already ensures that its
173215
// layout is valid. Use the unchecked constructor to avoid inserting a
174216
// panicking codepath that needs to be optimized out.
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
@@ -183,9 +225,9 @@ impl Layout {
183225
#[must_use]
184226
#[inline]
185227
pub const fn for_value<T: ?Sized>(t: &T) -> Self {
186-
let (size, align) = (size_of_val(t), align_of_val(t));
228+
let (size, alignment) = (size_of_val(t), Alignment::of_val(t));
187229
// SAFETY: see rationale in `new` for why this is using the unsafe variant
188-
unsafe { Layout::from_size_align_unchecked(size, align) }
230+
unsafe { Layout::from_size_alignment_unchecked(size, alignment) }
189231
}
190232

191233
/// Produces layout describing a record that could be used to
@@ -217,11 +259,12 @@ impl Layout {
217259
/// [extern type]: ../../unstable-book/language-features/extern-types.html
218260
#[unstable(feature = "layout_for_ptr", issue = "69835")]
219261
#[must_use]
262+
#[inline]
220263
pub const unsafe fn for_value_raw<T: ?Sized>(t: *const T) -> Self {
221264
// SAFETY: we pass along the prerequisites of these functions to the caller
222-
let (size, align) = unsafe { (mem::size_of_val_raw(t), mem::align_of_val_raw(t)) };
265+
let (size, alignment) = unsafe { (mem::size_of_val_raw(t), Alignment::of_val_raw(t)) };
223266
// SAFETY: see rationale in `new` for why this is using the unsafe variant
224-
unsafe { Layout::from_size_align_unchecked(size, align) }
267+
unsafe { Layout::from_size_alignment_unchecked(size, alignment) }
225268
}
226269

227270
/// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
@@ -256,13 +299,33 @@ impl Layout {
256299
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
257300
#[inline]
258301
pub const fn align_to(&self, align: usize) -> Result<Self, LayoutError> {
259-
if let Some(align) = Alignment::new(align) {
260-
Layout::from_size_alignment(self.size, Alignment::max(self.align, align))
302+
if let Some(alignment) = Alignment::new(align) {
303+
self.adjust_alignment_to(alignment)
261304
} else {
262305
Err(LayoutError)
263306
}
264307
}
265308

309+
/// Creates a layout describing the record that can hold a value
310+
/// of the same layout as `self`, but that also is aligned to
311+
/// alignment `alignment`.
312+
///
313+
/// If `self` already meets the prescribed alignment, then returns
314+
/// `self`.
315+
///
316+
/// Note that this method does not add any padding to the overall
317+
/// size, regardless of whether the returned layout has a different
318+
/// alignment. In other words, if `K` has size 16, `K.align_to(32)`
319+
/// will *still* have size 16.
320+
///
321+
/// Returns an error if the combination of `self.size()` and the given
322+
/// `alignment` violates the conditions listed in [`Layout::from_size_alignment`].
323+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
324+
#[inline]
325+
pub const fn adjust_alignment_to(&self, alignment: Alignment) -> Result<Self, LayoutError> {
326+
Layout::from_size_alignment(self.size, Alignment::max(self.align, alignment))
327+
}
328+
266329
/// Returns the amount of padding we must insert after `self`
267330
/// to ensure that the following address will satisfy `alignment`.
268331
///
@@ -280,7 +343,7 @@ impl Layout {
280343
#[must_use = "this returns the padding needed, without modifying the `Layout`"]
281344
#[inline]
282345
pub const fn padding_needed_for(&self, alignment: Alignment) -> usize {
283-
let len_rounded_up = self.size_rounded_up_to_custom_align(alignment);
346+
let len_rounded_up = self.size_rounded_up_to_custom_alignment(alignment);
284347
// SAFETY: Cannot overflow because the rounded-up value is never less
285348
unsafe { unchecked_sub(len_rounded_up, self.size) }
286349
}
@@ -290,7 +353,7 @@ impl Layout {
290353
/// This can return at most `Alignment::MAX` (aka `isize::MAX + 1`)
291354
/// because the original size is at most `isize::MAX`.
292355
#[inline]
293-
const fn size_rounded_up_to_custom_align(&self, align: Alignment) -> usize {
356+
const fn size_rounded_up_to_custom_alignment(&self, alignment: Alignment) -> usize {
294357
// SAFETY:
295358
// Rounded up value is:
296359
// size_rounded_up = (size + align - 1) & !(align - 1);
@@ -310,7 +373,7 @@ impl Layout {
310373
// (Size 0 Align MAX is already aligned, so stays the same, but things like
311374
// Size 1 Align MAX or Size isize::MAX Align 2 round up to `isize::MAX + 1`.)
312375
unsafe {
313-
let align_m1 = unchecked_sub(align.as_usize(), 1);
376+
let align_m1 = unchecked_sub(alignment.as_usize(), 1);
314377
unchecked_add(self.size, align_m1) & !align_m1
315378
}
316379
}
@@ -330,10 +393,10 @@ impl Layout {
330393
// > `size`, when rounded up to the nearest multiple of `align`,
331394
// > must not overflow isize (i.e., the rounded value must be
332395
// > less than or equal to `isize::MAX`)
333-
let new_size = self.size_rounded_up_to_custom_align(self.align);
396+
let new_size = self.size_rounded_up_to_custom_alignment(self.align);
334397

335398
// SAFETY: padded size is guaranteed to not exceed `isize::MAX`.
336-
unsafe { Layout::from_size_align_unchecked(new_size, self.align()) }
399+
unsafe { Layout::from_size_alignment_unchecked(new_size, self.alignment()) }
337400
}
338401

339402
/// Creates a layout describing the record for `n` instances of
@@ -433,16 +496,16 @@ impl Layout {
433496
#[rustc_const_stable(feature = "const_alloc_layout", since = "1.85.0")]
434497
#[inline]
435498
pub const fn extend(&self, next: Self) -> Result<(Self, usize), LayoutError> {
436-
let new_align = Alignment::max(self.align, next.align);
437-
let offset = self.size_rounded_up_to_custom_align(next.align);
499+
let new_alignment = Alignment::max(self.align, next.align);
500+
let offset = self.size_rounded_up_to_custom_alignment(next.align);
438501

439502
// SAFETY: `offset` is at most `isize::MAX + 1` (such as from aligning
440503
// to `Alignment::MAX`) and `next.size` is at most `isize::MAX` (from the
441504
// `Layout` type invariant). Thus the largest possible `new_size` is
442505
// `isize::MAX + 1 + isize::MAX`, which is `usize::MAX`, and cannot overflow.
443506
let new_size = unsafe { unchecked_add(offset, next.size) };
444507

445-
if let Ok(layout) = Layout::from_size_alignment(new_size, new_align) {
508+
if let Ok(layout) = Layout::from_size_alignment(new_size, new_alignment) {
446509
Ok((layout, offset))
447510
} else {
448511
Err(LayoutError)
@@ -503,15 +566,15 @@ impl Layout {
503566

504567
#[inline]
505568
const fn inner(element_layout: Layout, n: usize) -> Result<Layout, LayoutError> {
506-
let Layout { size: element_size, align } = element_layout;
569+
let Layout { size: element_size, align: alignment } = element_layout;
507570

508571
// We need to check two things about the size:
509572
// - That the total size won't overflow a `usize`, and
510573
// - That the total size still fits in an `isize`.
511574
// By using division we can check them both with a single threshold.
512575
// That'd usually be a bad idea, but thankfully here the element size
513576
// and alignment are constants, so the compiler will fold all of it.
514-
if element_size != 0 && n > Layout::max_size_for_align(align) / element_size {
577+
if element_size != 0 && n > Layout::max_size_for_alignment(alignment) / element_size {
515578
return Err(LayoutError);
516579
}
517580

@@ -524,17 +587,9 @@ impl Layout {
524587
// SAFETY: We just checked above that the `array_size` will not
525588
// exceed `isize::MAX` even when rounded up to the alignment.
526589
// And `Alignment` guarantees it's a power of two.
527-
unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) }
590+
unsafe { Ok(Layout::from_size_alignment_unchecked(array_size, alignment)) }
528591
}
529592
}
530-
531-
/// Perma-unstable access to `align` as `Alignment` type.
532-
#[unstable(issue = "none", feature = "std_internals")]
533-
#[doc(hidden)]
534-
#[inline]
535-
pub const fn alignment(&self) -> Alignment {
536-
self.align
537-
}
538593
}
539594

540595
#[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
@@ -8,6 +8,7 @@
88
use crate::alloc::Layout;
99
use crate::marker::{Destruct, DiscriminantKind};
1010
use crate::panic::const_assert;
11+
use crate::ptr::Alignment;
1112
use crate::{clone, cmp, fmt, hash, intrinsics, ptr};
1213

1314
mod manually_drop;
@@ -1246,6 +1247,10 @@ pub trait SizedTypeProperties: Sized {
12461247
#[lang = "mem_align_const"]
12471248
const ALIGN: usize = intrinsics::align_of::<Self>();
12481249

1250+
#[doc(hidden)]
1251+
#[unstable(feature = "ptr_alignment_type", issue = "102070")]
1252+
const ALIGNMENT: Alignment = Alignment::of::<Self>();
1253+
12491254
/// `true` if this type requires no storage.
12501255
/// `false` if its [size](size_of) is greater than zero.
12511256
///

0 commit comments

Comments
 (0)