@@ -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 } ;
@@ -312,6 +312,49 @@ pub fn bin_op_to_fcmp_predicate(ccx: &CrateContext, op: hir::BinOp_)
312
312
}
313
313
}
314
314
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
+
315
358
pub fn compare_scalar_types < ' blk , ' tcx > ( bcx : Block < ' blk , ' tcx > ,
316
359
lhs : ValueRef ,
317
360
rhs : ValueRef ,
@@ -336,6 +379,17 @@ pub fn compare_scalar_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
336
379
ty:: TyRawPtr ( mt) if common:: type_is_sized ( bcx. tcx ( ) , mt. ty ) => {
337
380
ICmp ( bcx, bin_op_to_icmp_predicate ( bcx. ccx ( ) , op, false ) , lhs, rhs, debug_loc)
338
381
}
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
+ }
339
393
ty:: TyInt ( _) => {
340
394
ICmp ( bcx, bin_op_to_icmp_predicate ( bcx. ccx ( ) , op, true ) , lhs, rhs, debug_loc)
341
395
}
@@ -523,6 +577,129 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
523
577
return cx;
524
578
}
525
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
+
526
703
pub fn cast_shift_expr_rhs ( cx : Block ,
527
704
op : hir:: BinOp_ ,
528
705
lhs : ValueRef ,
@@ -828,6 +1005,10 @@ pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t
828
1005
return ;
829
1006
}
830
1007
1008
+ debug ! ( "store_ty: {} : {:?} <- {}" ,
1009
+ cx. val_to_string( dst) , t,
1010
+ cx. val_to_string( v) ) ;
1011
+
831
1012
if common:: type_is_fat_ptr ( cx. tcx ( ) , t) {
832
1013
Store ( cx, ExtractValue ( cx, v, abi:: FAT_PTR_ADDR ) , expr:: get_dataptr ( cx, dst) ) ;
833
1014
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
839
1020
}
840
1021
}
841
1022
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
+
842
1042
pub fn from_arg_ty ( bcx : Block , val : ValueRef , ty : Ty ) -> ValueRef {
843
1043
if ty. is_bool ( ) {
844
1044
ZExt ( bcx, val, Type :: i8 ( bcx. ccx ( ) ) )
0 commit comments