@@ -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