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