@@ -3,7 +3,7 @@ use std::convert::TryFrom;
33
44use rustc_apfloat:: ieee:: { Double , Single } ;
55use rustc_apfloat:: { Float , FloatConvert } ;
6- use rustc_middle:: mir:: interpret:: { InterpResult , PointerArithmetic , Scalar } ;
6+ use rustc_middle:: mir:: interpret:: { InterpResult , PointerArithmetic , Scalar , ScalarMaybeUninit } ;
77use rustc_middle:: mir:: CastKind ;
88use rustc_middle:: ty:: adjustment:: PointerCast ;
99use rustc_middle:: ty:: layout:: { IntegerExt , LayoutOf , TyAndLayout } ;
@@ -305,22 +305,37 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
305305 source_ty : Ty < ' tcx > ,
306306 cast_ty : Ty < ' tcx > ,
307307 ) -> 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 > > {
308328 // A<Struct> -> A<Trait> conversion
309329 let ( src_pointee_ty, dest_pointee_ty) =
310330 self . tcx . struct_lockstep_tails_erasing_lifetimes ( source_ty, cast_ty, self . param_env ) ;
311331
312- match ( & src_pointee_ty. kind ( ) , & dest_pointee_ty. kind ( ) ) {
332+ Ok ( match ( & src_pointee_ty. kind ( ) , & dest_pointee_ty. kind ( ) ) {
313333 ( & 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 )
319335 }
320336 ( & ty:: Dynamic ( ref data_a, ..) , & ty:: Dynamic ( ref data_b, ..) ) => {
321- let val = self . read_immediate ( src) ?;
322337 if data_a. principal_def_id ( ) == data_b. principal_def_id ( ) {
323- return self . write_immediate ( * val , dest ) ;
338+ return src_meta . check_init ( ) ;
324339 }
325340 // trait upcasting coercion
326341 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> {
330345
331346 if let Some ( entry_idx) = vptr_entry_idx {
332347 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 ( ) ?;
334349 let old_vptr = self . scalar_to_ptr ( old_vptr) ?;
335350 let new_vptr = self
336351 . 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 )
338353 } else {
339- self . write_immediate ( * val , dest )
354+ src_meta . check_init ( ) ?
340355 }
341356 }
342357 ( _, & ty:: Dynamic ( ref data, _) ) => {
343358 // Initial cast from sized to dyn trait
344359 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 )
348361 }
349362
350363 _ => {
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)
352365 }
353- }
366+ } )
354367 }
355368
356369 fn unsize_into (
@@ -360,16 +373,40 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
360373 dest : & PlaceTy < ' tcx , M :: PointerTag > ,
361374 ) -> InterpResult < ' tcx > {
362375 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, .. } ) ) => {
366380 self . unsize_into_ptr ( src, dest, * s, * c)
367381 }
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 ( ) => {
369383 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 => {
371408 // unsizing of generic struct with pointer fields
372- // Example: `Arc<T>` -> `Arc<Trait>`
409+ // Example: `Arc<T>` -> `Arc<dyn Trait>`
373410 // here we need to increase the size of every &T thin ptr field to a fat ptr
374411 for i in 0 ..src. layout . fields . count ( ) {
375412 let cast_ty_field = cast_ty. field ( self , i) ;
0 commit comments