@@ -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" ) ]
0 commit comments