@@ -55,7 +55,7 @@ use trans::builder::{Builder, noname};
5555use trans:: callee;
5656use trans:: cleanup:: { self , CleanupMethods , DropHint } ;
5757use 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 } ;
5959use trans:: common:: { C_null , C_struct_in_context , C_u64 , C_u8 , C_undef } ;
6060use trans:: common:: { CrateContext , DropFlagHintsMap , Field , FunctionContext } ;
6161use trans:: common:: { Result , NodeIdAndSpan , VariantInfo } ;
@@ -312,6 +312,49 @@ pub fn bin_op_to_fcmp_predicate(ccx: &CrateContext, op: hir::BinOp_)
312312 }
313313}
314314
315+ pub fn compare_fat_ptrs < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > ,
316+ lhs_addr : ValueRef ,
317+ lhs_extra : ValueRef ,
318+ rhs_addr : ValueRef ,
319+ rhs_extra : ValueRef ,
320+ _t : Ty < ' tcx > ,
321+ op : hir:: BinOp_ ,
322+ debug_loc : DebugLoc )
323+ -> ValueRef {
324+ match op {
325+ hir:: BiEq => {
326+ let addr_eq = ICmp ( bcx, llvm:: IntEQ , lhs_addr, rhs_addr, debug_loc) ;
327+ let extra_eq = ICmp ( bcx, llvm:: IntEQ , lhs_extra, rhs_extra, debug_loc) ;
328+ And ( bcx, addr_eq, extra_eq, debug_loc)
329+ }
330+ hir:: BiNe => {
331+ let addr_eq = ICmp ( bcx, llvm:: IntNE , lhs_addr, rhs_addr, debug_loc) ;
332+ let extra_eq = ICmp ( bcx, llvm:: IntNE , lhs_extra, rhs_extra, debug_loc) ;
333+ Or ( bcx, addr_eq, extra_eq, debug_loc)
334+ }
335+ hir:: BiLe | hir:: BiLt | hir:: BiGe | hir:: BiGt => {
336+ // a OP b ~ a.0 STRICT(OP) b.0 | (a.0 == b.0 && a.1 OP a.1)
337+ let ( op, strict_op) = match op {
338+ hir:: BiLt => ( llvm:: IntULT , llvm:: IntULT ) ,
339+ hir:: BiLe => ( llvm:: IntULE , llvm:: IntULT ) ,
340+ hir:: BiGt => ( llvm:: IntUGT , llvm:: IntUGT ) ,
341+ hir:: BiGe => ( llvm:: IntUGE , llvm:: IntUGT ) ,
342+ _ => unreachable ! ( )
343+ } ;
344+
345+ let addr_eq = ICmp ( bcx, llvm:: IntEQ , lhs_addr, rhs_addr, debug_loc) ;
346+ let extra_op = ICmp ( bcx, op, lhs_extra, rhs_extra, debug_loc) ;
347+ let addr_eq_extra_op = And ( bcx, addr_eq, extra_op, debug_loc) ;
348+
349+ let addr_strict = ICmp ( bcx, strict_op, lhs_addr, rhs_addr, debug_loc) ;
350+ Or ( bcx, addr_strict, addr_eq_extra_op, debug_loc)
351+ }
352+ _ => {
353+ bcx. tcx ( ) . sess . bug ( "unexpected fat ptr binop" ) ;
354+ }
355+ }
356+ }
357+
315358pub fn compare_scalar_types < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > ,
316359 lhs : ValueRef ,
317360 rhs : ValueRef ,
@@ -336,6 +379,17 @@ pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
336379 ty:: TyRawPtr ( mt) if common:: type_is_sized ( bcx. tcx ( ) , mt. ty ) => {
337380 ICmp ( bcx, bin_op_to_icmp_predicate ( bcx. ccx ( ) , op, false ) , lhs, rhs, debug_loc)
338381 }
382+ ty:: TyRawPtr ( _) => {
383+ let lhs_addr = Load ( bcx, GEPi ( bcx, lhs, & [ 0 , abi:: FAT_PTR_ADDR ] ) ) ;
384+ let lhs_extra = Load ( bcx, GEPi ( bcx, lhs, & [ 0 , abi:: FAT_PTR_EXTRA ] ) ) ;
385+
386+ let rhs_addr = Load ( bcx, GEPi ( bcx, rhs, & [ 0 , abi:: FAT_PTR_ADDR ] ) ) ;
387+ let rhs_extra = Load ( bcx, GEPi ( bcx, rhs, & [ 0 , abi:: FAT_PTR_EXTRA ] ) ) ;
388+ compare_fat_ptrs ( bcx,
389+ lhs_addr, lhs_extra,
390+ rhs_addr, rhs_extra,
391+ t, op, debug_loc)
392+ }
339393 ty:: TyInt ( _) => {
340394 ICmp ( bcx, bin_op_to_icmp_predicate ( bcx. ccx ( ) , op, true ) , lhs, rhs, debug_loc)
341395 }
@@ -523,6 +577,129 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
523577 return cx;
524578}
525579
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+
526703pub fn cast_shift_expr_rhs ( cx : Block ,
527704 op : hir:: BinOp_ ,
528705 lhs : ValueRef ,
@@ -828,6 +1005,10 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t
8281005 return ;
8291006 }
8301007
1008+ debug ! ( "store_ty: {} : {:?} <- {}" ,
1009+ cx. val_to_string( dst) , t,
1010+ cx. val_to_string( v) ) ;
1011+
8311012 if common:: type_is_fat_ptr ( cx. tcx ( ) , t) {
8321013 Store ( cx, ExtractValue ( cx, v, abi:: FAT_PTR_ADDR ) , expr:: get_dataptr ( cx, dst) ) ;
8331014 Store ( cx, ExtractValue ( cx, v, abi:: FAT_PTR_EXTRA ) , expr:: get_meta ( cx, dst) ) ;
@@ -839,6 +1020,25 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t
8391020 }
8401021}
8411022
1023+ pub fn store_fat_ptr < ' blk , ' tcx > ( cx : Block < ' blk , ' tcx > ,
1024+ data : ValueRef ,
1025+ extra : ValueRef ,
1026+ dst : ValueRef ,
1027+ _ty : Ty < ' tcx > ) {
1028+ // FIXME: emit metadata
1029+ Store ( cx, data, expr:: get_dataptr ( cx, dst) ) ;
1030+ Store ( cx, extra, expr:: get_meta ( cx, dst) ) ;
1031+ }
1032+
1033+ pub fn load_fat_ptr < ' blk , ' tcx > ( cx : Block < ' blk , ' tcx > ,
1034+ src : ValueRef ,
1035+ _ty : Ty < ' tcx > ) -> ( ValueRef , ValueRef )
1036+ {
1037+ // FIXME: emit metadata
1038+ ( Load ( cx, expr:: get_dataptr ( cx, src) ) ,
1039+ Load ( cx, expr:: get_meta ( cx, src) ) )
1040+ }
1041+
8421042pub fn from_arg_ty ( bcx : Block , val : ValueRef , ty : Ty ) -> ValueRef {
8431043 if ty. is_bool ( ) {
8441044 ZExt ( bcx, val, Type :: i8 ( bcx. ccx ( ) ) )
0 commit comments