@@ -59,37 +59,41 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
59
59
debug ! ( "DST {} layout: {:?}" , t, layout) ;
60
60
61
61
let i = layout. fields . count ( ) - 1 ;
62
- let sized_size = layout. fields . offset ( i) . bytes ( ) ;
62
+ let unsized_offset_unadjusted = layout. fields . offset ( i) . bytes ( ) ;
63
63
let sized_align = layout. align . abi . bytes ( ) ;
64
- debug ! ( "DST {} statically sized prefix size: {} align: {}" , t, sized_size, sized_align) ;
65
- let sized_size = bx. const_usize ( sized_size) ;
64
+ debug ! (
65
+ "DST {} offset of dyn field: {}, statically sized align: {}" ,
66
+ t, unsized_offset_unadjusted, sized_align
67
+ ) ;
68
+ let unsized_offset_unadjusted = bx. const_usize ( unsized_offset_unadjusted) ;
66
69
let sized_align = bx. const_usize ( sized_align) ;
67
70
68
71
// Recurse to get the size of the dynamically sized field (must be
69
72
// the last field).
70
73
let field_ty = layout. field ( bx, i) . ty ;
71
74
let ( unsized_size, mut unsized_align) = size_and_align_of_dst ( bx, field_ty, info) ;
72
75
73
- // FIXME (#26403, #27023): We should be adding padding
74
- // to `sized_size` (to accommodate the `unsized_align`
75
- // required of the unsized field that follows) before
76
- // summing it with `sized_size`. (Note that since #26403
77
- // is unfixed, we do not yet add the necessary padding
78
- // here. But this is where the add would go.)
76
+ // # First compute the dynamic alignment
79
77
80
- // Return the sum of sizes and max of aligns.
81
- let size = bx. add ( sized_size, unsized_size) ;
82
-
83
- // Packed types ignore the alignment of their fields.
78
+ // Packed type alignment would have to be capped, but their tails always have known alignment.
79
+ // Therefore, their alignment has already been taken into account when computing `sized_align`
80
+ // and `unsized_offset_unadjusted`, so no further adjustment is needed.
84
81
if let ty:: Adt ( def, _) = t. kind ( ) {
85
82
if def. repr ( ) . packed ( ) {
83
+ let unsized_tail =
84
+ bx. tcx ( ) . struct_tail_with_normalize ( field_ty, |ty| ty, || { } ) ;
85
+ assert ! ( matches!( unsized_tail. kind( ) , ty:: Slice ( ..) | ty:: Str ) ) ;
86
+ // Therefore we do not need to adjust anything.
87
+ // It's not actually correct to say that the unsized field has this alignment, but the
88
+ // code below works correctly if we set this and it avoids having to compute
89
+ // the actual alignment (which is `unsized_align.min(packed)`).
86
90
unsized_align = sized_align;
87
91
}
88
92
}
89
93
90
94
// Choose max of two known alignments (combined value must
91
95
// be aligned according to more restrictive of the two).
92
- let align = match (
96
+ let full_align = match (
93
97
bx. const_to_opt_u128 ( sized_align, false ) ,
94
98
bx. const_to_opt_u128 ( unsized_align, false ) ,
95
99
) {
@@ -104,6 +108,21 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
104
108
}
105
109
} ;
106
110
111
+ // # Then compute the dynamic size
112
+
113
+ // The full formula for the size would be:
114
+ // let unsized_offset_adjusted = unsized_offset_unadjusted.align_to(unsized_align);
115
+ // let full_size = (unsized_offset_adjusted + unsized_size).align_to(full_align);
116
+ // However, `unsized_size` is a multiple of `unsized_align`.
117
+ // Therefore, we can equivalently do the `align_to(unsized_align)` *after* adding `unsized_size`:
118
+ // let full_size = (offset + unsized_size).align_to(unsized_align).align_to(full_align);
119
+ // Furthermore, `align >= unsized_align`, and therefore we only need to do:
120
+ // let full_size = (offset + unsized_size).align_to(full_align);
121
+ // This formula also has the advantage of working correctly when the type is packed
122
+ // and we set `unsized_align = sized_align`.
123
+
124
+ let full_size = bx. add ( unsized_offset_unadjusted, unsized_size) ;
125
+
107
126
// Issue #27023: must add any necessary padding to `size`
108
127
// (to make it a multiple of `align`) before returning it.
109
128
//
@@ -115,12 +134,12 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
115
134
//
116
135
// `(size + (align-1)) & -align`
117
136
let one = bx. const_usize ( 1 ) ;
118
- let addend = bx. sub ( align , one) ;
119
- let add = bx. add ( size , addend) ;
120
- let neg = bx. neg ( align ) ;
121
- let size = bx. and ( add, neg) ;
137
+ let addend = bx. sub ( full_align , one) ;
138
+ let add = bx. add ( full_size , addend) ;
139
+ let neg = bx. neg ( full_align ) ;
140
+ let full_size = bx. and ( add, neg) ;
122
141
123
- ( size , align )
142
+ ( full_size , full_align )
124
143
}
125
144
}
126
145
}
0 commit comments