@@ -55,7 +55,7 @@ use trans::builder::{Builder, noname};
55
55
use trans:: callee;
56
56
use trans:: cleanup:: { self , CleanupMethods , DropHint } ;
57
57
use trans:: closure;
58
- use trans:: common:: { Block , C_bool , C_bytes_in_context , C_i32 , C_int , C_integral } ;
58
+ use trans:: common:: { Block , C_bool , C_bytes_in_context , C_i32 , C_int , C_uint , C_integral } ;
59
59
use trans:: common:: { C_null , C_struct_in_context , C_u64 , C_u8 , C_undef } ;
60
60
use trans:: common:: { CrateContext , DropFlagHintsMap , Field , FunctionContext } ;
61
61
use trans:: common:: { Result , NodeIdAndSpan , VariantInfo } ;
@@ -577,6 +577,129 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
577
577
return cx;
578
578
}
579
579
580
+
581
+ /// Retrieve the information we are losing (making dynamic) in an unsizing
582
+ /// adjustment.
583
+ ///
584
+ /// The `old_info` argument is a bit funny. It is intended for use
585
+ /// in an upcast, where the new vtable for an object will be drived
586
+ /// from the old one.
587
+ pub fn unsized_info < ' ccx , ' tcx > ( ccx : & CrateContext < ' ccx , ' tcx > ,
588
+ source : Ty < ' tcx > ,
589
+ target : Ty < ' tcx > ,
590
+ old_info : Option < ValueRef > ,
591
+ param_substs : & ' tcx Substs < ' tcx > )
592
+ -> ValueRef {
593
+ let ( source, target) = ccx. tcx ( ) . struct_lockstep_tails ( source, target) ;
594
+ match ( & source. sty , & target. sty ) {
595
+ ( & ty:: TyArray ( _, len) , & ty:: TySlice ( _) ) => C_uint ( ccx, len) ,
596
+ ( & ty:: TyTrait ( _) , & ty:: TyTrait ( _) ) => {
597
+ // For now, upcasts are limited to changes in marker
598
+ // traits, and hence never actually require an actual
599
+ // change to the vtable.
600
+ old_info. expect ( "unsized_info: missing old info for trait upcast" )
601
+ }
602
+ ( _, & ty:: TyTrait ( box ty:: TraitTy { ref principal, .. } ) ) => {
603
+ // Note that we preserve binding levels here:
604
+ let substs = principal. 0 . substs . with_self_ty ( source) . erase_regions ( ) ;
605
+ let substs = ccx. tcx ( ) . mk_substs ( substs) ;
606
+ let trait_ref = ty:: Binder ( ty:: TraitRef { def_id : principal. def_id ( ) ,
607
+ substs : substs } ) ;
608
+ consts:: ptrcast ( meth:: get_vtable ( ccx, trait_ref, param_substs) ,
609
+ Type :: vtable_ptr ( ccx) )
610
+ }
611
+ _ => ccx. sess ( ) . bug ( & format ! ( "unsized_info: invalid unsizing {:?} -> {:?}" ,
612
+ source,
613
+ target) )
614
+ }
615
+ }
616
+
617
+ /// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer.
618
+ pub fn unsize_thin_ptr < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > ,
619
+ src : ValueRef ,
620
+ src_ty : Ty < ' tcx > ,
621
+ dst_ty : Ty < ' tcx > )
622
+ -> ( ValueRef , ValueRef ) {
623
+ debug ! ( "unsize_thin_ptr: {:?} => {:?}" , src_ty, dst_ty) ;
624
+ match ( & src_ty. sty , & dst_ty. sty ) {
625
+ ( & ty:: TyBox ( a) , & ty:: TyBox ( b) ) |
626
+ ( & ty:: TyRef ( _, ty:: TypeAndMut { ty : a, .. } ) ,
627
+ & ty:: TyRef ( _, ty:: TypeAndMut { ty : b, .. } ) ) |
628
+ ( & ty:: TyRef ( _, ty:: TypeAndMut { ty : a, .. } ) ,
629
+ & ty:: TyRawPtr ( ty:: TypeAndMut { ty : b, .. } ) ) |
630
+ ( & ty:: TyRawPtr ( ty:: TypeAndMut { ty : a, .. } ) ,
631
+ & ty:: TyRawPtr ( ty:: TypeAndMut { ty : b, .. } ) ) => {
632
+ assert ! ( common:: type_is_sized( bcx. tcx( ) , a) ) ;
633
+ let ptr_ty = type_of:: in_memory_type_of ( bcx. ccx ( ) , b) . ptr_to ( ) ;
634
+ ( PointerCast ( bcx, src, ptr_ty) ,
635
+ unsized_info ( bcx. ccx ( ) , a, b, None , bcx. fcx . param_substs ) )
636
+ }
637
+ _ => bcx. sess ( ) . bug (
638
+ & format ! ( "unsize_thin_ptr: called on bad types" ) )
639
+ }
640
+ }
641
+
642
+ /// Coerce `src`, which is a reference to a value of type `src_ty`,
643
+ /// to a value of type `dst_ty` and store the result in `dst`
644
+ pub fn coerce_unsized_into < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > ,
645
+ src : ValueRef ,
646
+ src_ty : Ty < ' tcx > ,
647
+ dst : ValueRef ,
648
+ dst_ty : Ty < ' tcx > ) {
649
+ match ( & src_ty. sty , & dst_ty. sty ) {
650
+ ( & ty:: TyBox ( ..) , & ty:: TyBox ( ..) ) |
651
+ ( & ty:: TyRef ( ..) , & ty:: TyRef ( ..) ) |
652
+ ( & ty:: TyRef ( ..) , & ty:: TyRawPtr ( ..) ) |
653
+ ( & ty:: TyRawPtr ( ..) , & ty:: TyRawPtr ( ..) ) => {
654
+ let ( base, info) = if common:: type_is_fat_ptr ( bcx. tcx ( ) , src_ty) {
655
+ // fat-ptr to fat-ptr unsize preserves the vtable
656
+ load_fat_ptr ( bcx, src, src_ty)
657
+ } else {
658
+ let base = load_ty ( bcx, src, src_ty) ;
659
+ unsize_thin_ptr ( bcx, base, src_ty, dst_ty)
660
+ } ;
661
+ store_fat_ptr ( bcx, base, info, dst, dst_ty) ;
662
+ }
663
+
664
+ // This can be extended to enums and tuples in the future.
665
+ // (&ty::TyEnum(def_id_a, _), &ty::TyEnum(def_id_b, _)) |
666
+ ( & ty:: TyStruct ( def_a, _) , & ty:: TyStruct ( def_b, _) ) => {
667
+ assert_eq ! ( def_a, def_b) ;
668
+
669
+ let src_repr = adt:: represent_type ( bcx. ccx ( ) , src_ty) ;
670
+ let src_fields = match & * src_repr {
671
+ & adt:: Repr :: Univariant ( ref s, _) => & s. fields ,
672
+ _ => bcx. sess ( ) . bug ( "struct has non-univariant repr" )
673
+ } ;
674
+ let dst_repr = adt:: represent_type ( bcx. ccx ( ) , dst_ty) ;
675
+ let dst_fields = match & * dst_repr {
676
+ & adt:: Repr :: Univariant ( ref s, _) => & s. fields ,
677
+ _ => bcx. sess ( ) . bug ( "struct has non-univariant repr" )
678
+ } ;
679
+
680
+ let iter = src_fields. iter ( ) . zip ( dst_fields) . enumerate ( ) ;
681
+ for ( i, ( src_fty, dst_fty) ) in iter {
682
+ if type_is_zero_size ( bcx. ccx ( ) , dst_fty) { continue ; }
683
+
684
+ let src_f = adt:: trans_field_ptr ( bcx, & src_repr, src, 0 , i) ;
685
+ let dst_f = adt:: trans_field_ptr ( bcx, & dst_repr, dst, 0 , i) ;
686
+ if src_fty == dst_fty {
687
+ memcpy_ty ( bcx, dst_f, src_f, src_fty) ;
688
+ } else {
689
+ coerce_unsized_into (
690
+ bcx,
691
+ src_f, src_fty,
692
+ dst_f, dst_fty
693
+ ) ;
694
+ }
695
+ }
696
+ }
697
+ _ => bcx. sess ( ) . bug ( & format ! ( "coerce_unsized_into: invalid coercion {:?} -> {:?}" ,
698
+ src_ty,
699
+ dst_ty) )
700
+ }
701
+ }
702
+
580
703
pub fn cast_shift_expr_rhs ( cx : Block ,
581
704
op : hir:: BinOp_ ,
582
705
lhs : ValueRef ,
0 commit comments