@@ -252,7 +252,9 @@ pub(crate) fn size_and_align_of<'tcx>(
252252 assert ! ( !layout. ty. is_simd( ) ) ;
253253
254254 let i = layout. fields . count ( ) - 1 ;
255- let sized_size = layout. fields . offset ( i) . bytes ( ) ;
255+ let unsized_offset_unadjusted = layout. fields . offset ( i) . bytes ( ) ;
256+ let unsized_offset_unadjusted =
257+ fx. bcx . ins ( ) . iconst ( fx. pointer_type , unsized_offset_unadjusted as i64 ) ;
256258 let sized_align = layout. align . abi . bytes ( ) ;
257259 let sized_align = fx. bcx . ins ( ) . iconst ( fx. pointer_type , sized_align as i64 ) ;
258260
@@ -261,27 +263,41 @@ pub(crate) fn size_and_align_of<'tcx>(
261263 let field_layout = layout. field ( fx, i) ;
262264 let ( unsized_size, mut unsized_align) = size_and_align_of ( fx, field_layout, info) ;
263265
264- // FIXME (#26403, #27023): We should be adding padding
265- // to `sized_size` (to accommodate the `unsized_align`
266- // required of the unsized field that follows) before
267- // summing it with `sized_size`. (Note that since #26403
268- // is unfixed, we do not yet add the necessary padding
269- // here. But this is where the add would go.)
270-
271- // Return the sum of sizes and max of aligns.
272- let size = fx. bcx . ins ( ) . iadd_imm ( unsized_size, sized_size as i64 ) ;
273-
274- // Packed types ignore the alignment of their fields.
275- if let ty:: Adt ( def, _) = layout. ty . kind ( ) {
276- if def. repr ( ) . packed ( ) {
277- unsized_align = sized_align;
266+ // # First compute the dynamic alignment
267+
268+ // For packed types, we need to cap the alignment.
269+ if let ty:: Adt ( def, _) = ty. kind ( ) {
270+ if let Some ( packed) = def. repr ( ) . pack {
271+ if packed. bytes ( ) == 1 {
272+ // We know this will be capped to 1.
273+ unsized_align = fx. bcx . ins ( ) . iconst ( fx. pointer_type , 1 ) ;
274+ } else {
275+ // We have to dynamically compute `min(unsized_align, packed)`.
276+ let packed = fx. bcx . ins ( ) . iconst ( fx. pointer_type , packed. bytes ( ) as i64 ) ;
277+ let cmp =
278+ fx. bcx . ins ( ) . icmp ( IntCC :: UnsignedGreaterThan , unsized_align, packed) ;
279+ unsized_align = fx. bcx . ins ( ) . select ( cmp, unsized_align, packed) ;
280+ }
278281 }
279282 }
280283
281284 // Choose max of two known alignments (combined value must
282285 // be aligned according to more restrictive of the two).
283286 let cmp = fx. bcx . ins ( ) . icmp ( IntCC :: UnsignedGreaterThan , sized_align, unsized_align) ;
284- let align = fx. bcx . ins ( ) . select ( cmp, sized_align, unsized_align) ;
287+ let full_align = fx. bcx . ins ( ) . select ( cmp, sized_align, unsized_align) ;
288+
289+ // # Then compute the dynamic size
290+
291+ // The full formula for the size would be:
292+ // let unsized_offset_adjusted = unsized_offset_unadjusted.align_to(unsized_align);
293+ // let full_size = (unsized_offset_adjusted + unsized_size).align_to(full_align);
294+ // However, `unsized_size` is a multiple of `unsized_align`.
295+ // Therefore, we can equivalently do the `align_to(unsized_align)` *after* adding `unsized_size`:
296+ // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(unsized_align).align_to(full_align);
297+ // Furthermore, `align >= unsized_align`, and therefore we only need to do:
298+ // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(full_align);
299+
300+ let full_size = fx. bcx . ins ( ) . iadd ( unsized_offset_unadjusted, unsized_size) ;
285301
286302 // Issue #27023: must add any necessary padding to `size`
287303 // (to make it a multiple of `align`) before returning it.
@@ -293,12 +309,12 @@ pub(crate) fn size_and_align_of<'tcx>(
293309 // emulated via the semi-standard fast bit trick:
294310 //
295311 // `(size + (align-1)) & -align`
296- let addend = fx. bcx . ins ( ) . iadd_imm ( align , -1 ) ;
297- let add = fx. bcx . ins ( ) . iadd ( size , addend) ;
298- let neg = fx. bcx . ins ( ) . ineg ( align ) ;
299- let size = fx. bcx . ins ( ) . band ( add, neg) ;
312+ let addend = fx. bcx . ins ( ) . iadd_imm ( full_align , -1 ) ;
313+ let add = fx. bcx . ins ( ) . iadd ( full_size , addend) ;
314+ let neg = fx. bcx . ins ( ) . ineg ( full_align ) ;
315+ let full_size = fx. bcx . ins ( ) . band ( add, neg) ;
300316
301- ( size , align )
317+ ( full_size , full_align )
302318 }
303319 _ => bug ! ( "size_and_align_of_dst: {ty} not supported" ) ,
304320 }
0 commit comments