@@ -84,37 +84,40 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
84
84
debug ! ( "DST {} layout: {:?}" , t, layout) ;
85
85
86
86
let i = layout. fields . count ( ) - 1 ;
87
- let sized_size = layout. fields . offset ( i) . bytes ( ) ;
87
+ let unsized_offset_unadjusted = layout. fields . offset ( i) . bytes ( ) ;
88
88
let sized_align = layout. align . abi . bytes ( ) ;
89
- debug ! ( "DST {} statically sized prefix size: {} align: {}" , t, sized_size, sized_align) ;
90
- let sized_size = bx. const_usize ( sized_size) ;
89
+ debug ! (
90
+ "DST {} offset of dyn field: {}, statically sized align: {}" ,
91
+ t, unsized_offset_unadjusted, sized_align
92
+ ) ;
93
+ let unsized_offset_unadjusted = bx. const_usize ( unsized_offset_unadjusted) ;
91
94
let sized_align = bx. const_usize ( sized_align) ;
92
95
93
96
// Recurse to get the size of the dynamically sized field (must be
94
97
// the last field).
95
98
let field_ty = layout. field ( bx, i) . ty ;
96
99
let ( unsized_size, mut unsized_align) = size_and_align_of_dst ( bx, field_ty, info) ;
97
100
98
- // FIXME (#26403, #27023): We should be adding padding
99
- // to `sized_size` (to accommodate the `unsized_align`
100
- // required of the unsized field that follows) before
101
- // summing it with `sized_size`. (Note that since #26403
102
- // is unfixed, we do not yet add the necessary padding
103
- // here. But this is where the add would go.)
104
-
105
- // Return the sum of sizes and max of aligns .
106
- let size = bx. add ( sized_size , unsized_size ) ;
107
-
108
- // Packed types ignore the alignment of their fields .
109
- if let ty :: Adt ( def , _ ) = t . kind ( ) {
110
- if def . repr ( ) . packed ( ) {
111
- unsized_align = sized_align ;
101
+ // # First compute the dynamic alignment
102
+
103
+ // For packed types, we need to cap the alignment.
104
+ if let ty :: Adt ( def , _ ) = t . kind ( )
105
+ && let Some ( packed ) = def . repr ( ) . pack
106
+ {
107
+ if packed . bytes ( ) == 1 {
108
+ // We know this will be capped to 1 .
109
+ unsized_align = bx. const_usize ( 1 ) ;
110
+ } else {
111
+ // We have to dynamically compute `min(unsized_align, packed)` .
112
+ let packed = bx . const_usize ( packed . bytes ( ) ) ;
113
+ let cmp = bx . icmp ( IntPredicate :: IntULT , unsized_align , packed) ;
114
+ unsized_align = bx . select ( cmp , unsized_align , packed ) ;
112
115
}
113
116
}
114
117
115
118
// Choose max of two known alignments (combined value must
116
119
// be aligned according to more restrictive of the two).
117
- let align = match (
120
+ let full_align = match (
118
121
bx. const_to_opt_u128 ( sized_align, false ) ,
119
122
bx. const_to_opt_u128 ( unsized_align, false ) ,
120
123
) {
@@ -129,6 +132,19 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
129
132
}
130
133
} ;
131
134
135
+ // # Then compute the dynamic size
136
+
137
+ // The full formula for the size would be:
138
+ // let unsized_offset_adjusted = unsized_offset_unadjusted.align_to(unsized_align);
139
+ // let full_size = (unsized_offset_adjusted + unsized_size).align_to(full_align);
140
+ // However, `unsized_size` is a multiple of `unsized_align`.
141
+ // Therefore, we can equivalently do the `align_to(unsized_align)` *after* adding `unsized_size`:
142
+ // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(unsized_align).align_to(full_align);
143
+ // Furthermore, `align >= unsized_align`, and therefore we only need to do:
144
+ // let full_size = (unsized_offset_unadjusted + unsized_size).align_to(full_align);
145
+
146
+ let full_size = bx. add ( unsized_offset_unadjusted, unsized_size) ;
147
+
132
148
// Issue #27023: must add any necessary padding to `size`
133
149
// (to make it a multiple of `align`) before returning it.
134
150
//
@@ -140,12 +156,12 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
140
156
//
141
157
// `(size + (align-1)) & -align`
142
158
let one = bx. const_usize ( 1 ) ;
143
- let addend = bx. sub ( align , one) ;
144
- let add = bx. add ( size , addend) ;
145
- let neg = bx. neg ( align ) ;
146
- let size = bx. and ( add, neg) ;
159
+ let addend = bx. sub ( full_align , one) ;
160
+ let add = bx. add ( full_size , addend) ;
161
+ let neg = bx. neg ( full_align ) ;
162
+ let full_size = bx. and ( add, neg) ;
147
163
148
- ( size , align )
164
+ ( full_size , full_align )
149
165
}
150
166
_ => bug ! ( "size_and_align_of_dst: {t} not supported" ) ,
151
167
}
0 commit comments