@@ -3,7 +3,7 @@ use std::convert::TryFrom;
3
3
4
4
use rustc_apfloat:: ieee:: { Double , Single } ;
5
5
use rustc_apfloat:: { Float , FloatConvert } ;
6
- use rustc_middle:: mir:: interpret:: { InterpResult , PointerArithmetic , Scalar } ;
6
+ use rustc_middle:: mir:: interpret:: { InterpResult , PointerArithmetic , Scalar , ScalarMaybeUninit } ;
7
7
use rustc_middle:: mir:: CastKind ;
8
8
use rustc_middle:: ty:: adjustment:: PointerCast ;
9
9
use rustc_middle:: ty:: layout:: { IntegerExt , LayoutOf , TyAndLayout } ;
@@ -305,22 +305,37 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
305
305
source_ty : Ty < ' tcx > ,
306
306
cast_ty : Ty < ' tcx > ,
307
307
) -> InterpResult < ' tcx > {
308
+ // We *could* forward `data` without even checking that it is initialized, but for now,
309
+ // let's only allow casting properly initialized pointers.
310
+ let ( data, old_meta) = match * self . read_immediate ( src) ? {
311
+ // If the input ptr is thin, use `Uninit` for the old metadata.
312
+ // `unsize_just_metadata` knows how to handle that.
313
+ Immediate :: Scalar ( data) => ( data. check_init ( ) ?, ScalarMaybeUninit :: Uninit ) ,
314
+ Immediate :: ScalarPair ( data, meta) => ( data. check_init ( ) ?, meta) ,
315
+ } ;
316
+
317
+ let new_meta = self . unsize_just_metadata ( old_meta, source_ty, cast_ty) ?;
318
+ self . write_immediate ( Immediate :: ScalarPair ( data. into ( ) , new_meta. into ( ) ) , dest)
319
+ }
320
+
321
+ fn unsize_just_metadata (
322
+ & mut self ,
323
+ src_meta : ScalarMaybeUninit < M :: PointerTag > ,
324
+ // The pointee types
325
+ source_ty : Ty < ' tcx > ,
326
+ cast_ty : Ty < ' tcx > ,
327
+ ) -> InterpResult < ' tcx , Scalar < M :: PointerTag > > {
308
328
// A<Struct> -> A<Trait> conversion
309
329
let ( src_pointee_ty, dest_pointee_ty) =
310
330
self . tcx . struct_lockstep_tails_erasing_lifetimes ( source_ty, cast_ty, self . param_env ) ;
311
331
312
- match ( & src_pointee_ty. kind ( ) , & dest_pointee_ty. kind ( ) ) {
332
+ Ok ( match ( & src_pointee_ty. kind ( ) , & dest_pointee_ty. kind ( ) ) {
313
333
( & ty:: Array ( _, length) , & ty:: Slice ( _) ) => {
314
- let ptr = self . read_immediate ( src) ?. to_scalar ( ) ?;
315
- // u64 cast is from usize to u64, which is always good
316
- let val =
317
- Immediate :: new_slice ( ptr, length. eval_usize ( * self . tcx , self . param_env ) , self ) ;
318
- self . write_immediate ( val, dest)
334
+ Scalar :: from_machine_usize ( length. eval_usize ( * self . tcx , self . param_env ) , self )
319
335
}
320
336
( & ty:: Dynamic ( ref data_a, ..) , & ty:: Dynamic ( ref data_b, ..) ) => {
321
- let val = self . read_immediate ( src) ?;
322
337
if data_a. principal_def_id ( ) == data_b. principal_def_id ( ) {
323
- return self . write_immediate ( * val , dest ) ;
338
+ return src_meta . check_init ( ) ;
324
339
}
325
340
// trait upcasting coercion
326
341
let vptr_entry_idx = self . tcx . vtable_trait_upcasting_coercion_new_vptr_slot ( (
@@ -330,27 +345,25 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
330
345
331
346
if let Some ( entry_idx) = vptr_entry_idx {
332
347
let entry_idx = u64:: try_from ( entry_idx) . unwrap ( ) ;
333
- let ( old_data , old_vptr) = val . to_scalar_pair ( ) ?;
348
+ let old_vptr = src_meta . check_init ( ) ?;
334
349
let old_vptr = self . scalar_to_ptr ( old_vptr) ?;
335
350
let new_vptr = self
336
351
. read_new_vtable_after_trait_upcasting_from_vtable ( old_vptr, entry_idx) ?;
337
- self . write_immediate ( Immediate :: new_dyn_trait ( old_data , new_vptr, self ) , dest )
352
+ Scalar :: from_maybe_pointer ( new_vptr, self )
338
353
} else {
339
- self . write_immediate ( * val , dest )
354
+ src_meta . check_init ( ) ?
340
355
}
341
356
}
342
357
( _, & ty:: Dynamic ( ref data, _) ) => {
343
358
// Initial cast from sized to dyn trait
344
359
let vtable = self . get_vtable ( src_pointee_ty, data. principal ( ) ) ?;
345
- let ptr = self . read_immediate ( src) ?. to_scalar ( ) ?;
346
- let val = Immediate :: new_dyn_trait ( ptr, vtable, & * self . tcx ) ;
347
- self . write_immediate ( val, dest)
360
+ Scalar :: from_maybe_pointer ( vtable, & * self . tcx )
348
361
}
349
362
350
363
_ => {
351
- span_bug ! ( self . cur_span( ) , "invalid unsizing {:?} -> {:?}" , src . layout . ty , cast_ty)
364
+ span_bug ! ( self . cur_span( ) , "invalid unsizing {:?} -> {:?}" , source_ty , cast_ty)
352
365
}
353
- }
366
+ } )
354
367
}
355
368
356
369
fn unsize_into (
@@ -360,16 +373,40 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
360
373
dest : & PlaceTy < ' tcx , M :: PointerTag > ,
361
374
) -> InterpResult < ' tcx > {
362
375
trace ! ( "Unsizing {:?} of type {} into {:?}" , * src, src. layout. ty, cast_ty. ty) ;
363
- match ( & src. layout . ty . kind ( ) , & cast_ty. ty . kind ( ) ) {
364
- ( & ty:: Ref ( _, s, _) , & ty:: Ref ( _, c, _) | & ty:: RawPtr ( TypeAndMut { ty : c, .. } ) )
365
- | ( & ty:: RawPtr ( TypeAndMut { ty : s, .. } ) , & ty:: RawPtr ( TypeAndMut { ty : c, .. } ) ) => {
376
+ let typed_metadata = self . tcx . lang_items ( ) . typed_metadata ( ) ;
377
+ match ( src. layout . ty . kind ( ) , cast_ty. ty . kind ( ) ) {
378
+ ( ty:: Ref ( _, s, _) , ty:: Ref ( _, c, _) | ty:: RawPtr ( TypeAndMut { ty : c, .. } ) )
379
+ | ( ty:: RawPtr ( TypeAndMut { ty : s, .. } ) , ty:: RawPtr ( TypeAndMut { ty : c, .. } ) ) => {
366
380
self . unsize_into_ptr ( src, dest, * s, * c)
367
381
}
368
- ( & ty:: Adt ( def_a, _) , & ty:: Adt ( def_b, _) ) => {
382
+ ( ty:: Adt ( def_a, _) , ty:: Adt ( def_b, _) ) if def_a . is_box ( ) || def_b . is_box ( ) => {
369
383
assert_eq ! ( def_a, def_b) ;
370
-
384
+ if !def_a. is_box ( ) || !def_b. is_box ( ) {
385
+ span_bug ! (
386
+ self . cur_span( ) ,
387
+ "invalid unsizing between {:?} -> {:?}" ,
388
+ src. layout. ty,
389
+ cast_ty. ty
390
+ ) ;
391
+ }
392
+ self . unsize_into_ptr ( src, dest, src. layout . ty . boxed_ty ( ) , cast_ty. ty . boxed_ty ( ) )
393
+ }
394
+ ( ty:: Adt ( def_a, substs_a) , ty:: Adt ( def_b, substs_b) )
395
+ if def_a == def_b && Some ( def_a. did ( ) ) == typed_metadata =>
396
+ {
397
+ // unsizing of TypedMetadata container
398
+ // Example: `TypedMetadata<T>` -> `TypedMetadata<dyn Trait>`
399
+ let a_pointee = substs_a. type_at ( 0 ) ;
400
+ let b_pointee = substs_b. type_at ( 0 ) ;
401
+ let src_field = self . operand_field ( src, 0 ) ?;
402
+ let src = self . read_immediate ( & src_field) ?. to_scalar_or_uninit ( ) ;
403
+ let dst_field = self . place_field ( dest, 0 ) ?;
404
+ let new_meta = self . unsize_just_metadata ( src, a_pointee, b_pointee) ?;
405
+ self . write_scalar ( new_meta, & dst_field)
406
+ }
407
+ ( ty:: Adt ( def_a, _) , ty:: Adt ( def_b, _) ) if def_a == def_b => {
371
408
// unsizing of generic struct with pointer fields
372
- // Example: `Arc<T>` -> `Arc<Trait>`
409
+ // Example: `Arc<T>` -> `Arc<dyn Trait>`
373
410
// here we need to increase the size of every &T thin ptr field to a fat ptr
374
411
for i in 0 ..src. layout . fields . count ( ) {
375
412
let cast_ty_field = cast_ty. field ( self , i) ;
0 commit comments