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