@@ -132,18 +132,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
132
132
let ptr_arg = args_ptrs[ 0 ] ;
133
133
let offset = self . memory . read_isize ( args_ptrs[ 1 ] ) ?;
134
134
135
- match self . memory . read_ptr ( ptr_arg) {
136
- Ok ( ptr) => {
137
- let result_ptr = ptr. offset ( offset as isize * pointee_size) ;
138
- self . memory . write_ptr ( dest, result_ptr) ?;
139
- }
140
- Err ( EvalError :: ReadBytesAsPointer ) => {
141
- let addr = self . memory . read_isize ( ptr_arg) ?;
142
- let result_addr = addr + offset * pointee_size as i64 ;
143
- self . memory . write_isize ( dest, result_addr) ?;
144
- }
145
- Err ( e) => return Err ( e) ,
146
- }
135
+ let ptr = self . memory . read_ptr ( ptr_arg) ?;
136
+ let result_ptr = ptr. offset ( offset as isize * pointee_size) ;
137
+ self . memory . write_ptr ( dest, result_ptr) ?;
147
138
}
148
139
149
140
"overflowing_sub" => {
@@ -188,22 +179,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
188
179
189
180
"size_of_val" => {
190
181
let ty = substs. type_at ( 0 ) ;
191
- if self . type_is_sized ( ty) {
192
- let size = self . type_size ( ty) as u64 ;
193
- self . memory . write_uint ( dest, size, pointer_size) ?;
194
- } else {
195
- match ty. sty {
196
- ty:: TySlice ( _) | ty:: TyStr => {
197
- let elem_ty = ty. sequence_element_type ( self . tcx ) ;
198
- let elem_size = self . type_size ( elem_ty) as u64 ;
199
- let ptr_size = self . memory . pointer_size ( ) as isize ;
200
- let n = self . memory . read_usize ( args_ptrs[ 0 ] . offset ( ptr_size) ) ?;
201
- self . memory . write_uint ( dest, n * elem_size, pointer_size) ?;
202
- }
203
-
204
- _ => return Err ( EvalError :: Unimplemented ( format ! ( "unimplemented: size_of_val::<{:?}>" , ty) ) ) ,
205
- }
206
- }
182
+ let ( size, _) = self . size_and_align_of_dst ( ty, args_ptrs[ 0 ] ) ?;
183
+ self . memory . write_uint ( dest, size, pointer_size) ?;
207
184
}
208
185
// FIXME: wait for eval_operand_to_ptr to be gone
209
186
/*
@@ -248,4 +225,114 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
248
225
// current frame.
249
226
Ok ( ( ) )
250
227
}
228
+
229
+ fn size_and_align_of_dst (
230
+ & self ,
231
+ ty : ty:: Ty < ' tcx > ,
232
+ value : Pointer ,
233
+ ) -> EvalResult < ' tcx , ( u64 , u64 ) > {
234
+ let pointer_size = self . memory . pointer_size ( ) ;
235
+ if self . type_is_sized ( ty) {
236
+ Ok ( ( self . type_size ( ty) as u64 , self . type_align ( ty) as u64 ) )
237
+ } else {
238
+ match ty. sty {
239
+ ty:: TyAdt ( def, substs) => {
240
+ // First get the size of all statically known fields.
241
+ // Don't use type_of::sizing_type_of because that expects t to be sized,
242
+ // and it also rounds up to alignment, which we want to avoid,
243
+ // as the unsized field's alignment could be smaller.
244
+ assert ! ( !ty. is_simd( ) ) ;
245
+ let layout = self . type_layout ( ty) ;
246
+ debug ! ( "DST {} layout: {:?}" , ty, layout) ;
247
+
248
+ // Returns size in bytes of all fields except the last one
249
+ // (we will be recursing on the last one).
250
+ fn local_prefix_bytes ( variant : & ty:: layout:: Struct ) -> u64 {
251
+ let fields = variant. offset_after_field . len ( ) ;
252
+ if fields > 1 {
253
+ variant. offset_after_field [ fields - 2 ] . bytes ( )
254
+ } else {
255
+ 0
256
+ }
257
+ }
258
+
259
+ let ( sized_size, sized_align) = match * layout {
260
+ ty:: layout:: Layout :: Univariant { ref variant, .. } => {
261
+ ( local_prefix_bytes ( variant) , variant. align . abi ( ) )
262
+ }
263
+ _ => {
264
+ bug ! ( "size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}" ,
265
+ ty, layout) ;
266
+ }
267
+ } ;
268
+ debug ! ( "DST {} statically sized prefix size: {} align: {}" ,
269
+ ty, sized_size, sized_align) ;
270
+
271
+ // Recurse to get the size of the dynamically sized field (must be
272
+ // the last field).
273
+ let last_field = def. struct_variant ( ) . fields . last ( ) . unwrap ( ) ;
274
+ let field_ty = self . field_ty ( substs, last_field) ;
275
+ let ( unsized_size, unsized_align) = self . size_and_align_of_dst ( field_ty, value) ?;
276
+
277
+ // FIXME (#26403, #27023): We should be adding padding
278
+ // to `sized_size` (to accommodate the `unsized_align`
279
+ // required of the unsized field that follows) before
280
+ // summing it with `sized_size`. (Note that since #26403
281
+ // is unfixed, we do not yet add the necessary padding
282
+ // here. But this is where the add would go.)
283
+
284
+ // Return the sum of sizes and max of aligns.
285
+ let size = sized_size + unsized_size;
286
+
287
+ // Choose max of two known alignments (combined value must
288
+ // be aligned according to more restrictive of the two).
289
+ let align = :: std:: cmp:: max ( sized_align, unsized_align) ;
290
+
291
+ // Issue #27023: must add any necessary padding to `size`
292
+ // (to make it a multiple of `align`) before returning it.
293
+ //
294
+ // Namely, the returned size should be, in C notation:
295
+ //
296
+ // `size + ((size & (align-1)) ? align : 0)`
297
+ //
298
+ // emulated via the semi-standard fast bit trick:
299
+ //
300
+ // `(size + (align-1)) & -align`
301
+
302
+ if size & ( align - 1 ) != 0 {
303
+ Ok ( ( size + align, align) )
304
+ } else {
305
+ Ok ( ( size, align) )
306
+ }
307
+ }
308
+ ty:: TyTrait ( ..) => {
309
+ let ( _, vtable) = self . get_fat_ptr ( value) ;
310
+ let vtable = self . memory . read_ptr ( vtable) ?;
311
+ // the second entry in the vtable is the dynamic size of the object.
312
+ let size = self . memory . read_usize ( vtable. offset ( pointer_size as isize ) ) ?;
313
+ let align = self . memory . read_usize ( vtable. offset ( pointer_size as isize * 2 ) ) ?;
314
+ Ok ( ( size, align) )
315
+ }
316
+
317
+ ty:: TySlice ( _) | ty:: TyStr => {
318
+ let elem_ty = ty. sequence_element_type ( self . tcx ) ;
319
+ let elem_size = self . type_size ( elem_ty) as u64 ;
320
+ let ( _, len_ptr) = self . get_fat_ptr ( value) ;
321
+ let n = self . memory . read_usize ( len_ptr) ?;
322
+ let align = self . type_align ( elem_ty) ;
323
+ Ok ( ( n * elem_size, align as u64 ) )
324
+ }
325
+
326
+ _ => bug ! ( "size_of_val::<{:?}>" , ty) ,
327
+ }
328
+ }
329
+ }
330
+ /// Returns the normalized type of a struct field
331
+ fn field_ty (
332
+ & self ,
333
+ param_substs : & Substs < ' tcx > ,
334
+ f : ty:: FieldDef < ' tcx > ,
335
+ ) -> ty:: Ty < ' tcx > {
336
+ self . tcx . normalize_associated_type ( & f. ty ( self . tcx , param_substs) )
337
+ }
251
338
}
0 commit comments