@@ -25,39 +25,73 @@ pub(crate) fn unsized_info<'tcx>(
2525 . bcx
2626 . ins ( )
2727 . iconst ( fx. pointer_type , len. eval_usize ( fx. tcx , ParamEnv :: reveal_all ( ) ) as i64 ) ,
28- ( & ty:: Dynamic ( ..) , & ty:: Dynamic ( ..) ) => {
29- // For now, upcasts are limited to changes in marker
30- // traits, and hence never actually require an actual
31- // change to the vtable.
32- old_info. expect ( "unsized_info: missing old info for trait upcast" )
28+ ( & ty:: Dynamic ( ref data_a, ..) , & ty:: Dynamic ( ref data_b, ..) ) => {
29+ let old_info =
30+ old_info. expect ( "unsized_info: missing old info for trait upcasting coercion" ) ;
31+ if data_a. principal_def_id ( ) == data_b. principal_def_id ( ) {
32+ return old_info;
33+ }
34+ // trait upcasting coercion
35+
36+ // if both of the two `principal`s are `None`, this function would have returned early above.
37+ // and if one of the two `principal`s is `None`, typechecking would have rejected this case.
38+ let principal_a = data_a
39+ . principal ( )
40+ . expect ( "unsized_info: missing principal trait for trait upcasting coercion" ) ;
41+ let principal_b = data_b
42+ . principal ( )
43+ . expect ( "unsized_info: missing principal trait for trait upcasting coercion" ) ;
44+
45+ let vptr_entry_idx = fx. tcx . vtable_trait_upcasting_coercion_new_vptr_slot ( (
46+ principal_a. with_self_ty ( fx. tcx , source) ,
47+ principal_b. with_self_ty ( fx. tcx , source) ,
48+ ) ) ;
49+
50+ if let Some ( entry_idx) = vptr_entry_idx {
51+ let entry_idx = u32:: try_from ( entry_idx) . unwrap ( ) ;
52+ let entry_offset = entry_idx * fx. pointer_type . bytes ( ) ;
53+ let vptr_ptr = Pointer :: new ( old_info) . offset_i64 ( fx, entry_offset. into ( ) ) . load (
54+ fx,
55+ fx. pointer_type ,
56+ crate :: vtable:: vtable_memflags ( ) ,
57+ ) ;
58+ vptr_ptr
59+ } else {
60+ old_info
61+ }
3362 }
3463 ( _, & ty:: Dynamic ( ref data, ..) ) => crate :: vtable:: get_vtable ( fx, source, data. principal ( ) ) ,
3564 _ => bug ! ( "unsized_info: invalid unsizing {:?} -> {:?}" , source, target) ,
3665 }
3766}
3867
39- /// Coerce `src` to `dst_ty`. `src_ty` must be a thin pointer.
40- fn unsize_thin_ptr < ' tcx > (
68+ /// Coerce `src` to `dst_ty`.
69+ fn unsize_ptr < ' tcx > (
4170 fx : & mut FunctionCx < ' _ , ' _ , ' tcx > ,
4271 src : Value ,
4372 src_layout : TyAndLayout < ' tcx > ,
4473 dst_layout : TyAndLayout < ' tcx > ,
74+ old_info : Option < Value > ,
4575) -> ( Value , Value ) {
4676 match ( & src_layout. ty . kind ( ) , & dst_layout. ty . kind ( ) ) {
4777 ( & ty:: Ref ( _, a, _) , & ty:: Ref ( _, b, _) )
4878 | ( & ty:: Ref ( _, a, _) , & ty:: RawPtr ( ty:: TypeAndMut { ty : b, .. } ) )
4979 | ( & ty:: RawPtr ( ty:: TypeAndMut { ty : a, .. } ) , & ty:: RawPtr ( ty:: TypeAndMut { ty : b, .. } ) ) => {
5080 assert ! ( !fx. layout_of( a) . is_unsized( ) ) ;
51- ( src, unsized_info ( fx, a, b, None ) )
81+ ( src, unsized_info ( fx, a, b, old_info ) )
5282 }
5383 ( & ty:: Adt ( def_a, _) , & ty:: Adt ( def_b, _) ) if def_a. is_box ( ) && def_b. is_box ( ) => {
5484 let ( a, b) = ( src_layout. ty . boxed_ty ( ) , dst_layout. ty . boxed_ty ( ) ) ;
5585 assert ! ( !fx. layout_of( a) . is_unsized( ) ) ;
56- ( src, unsized_info ( fx, a, b, None ) )
86+ ( src, unsized_info ( fx, a, b, old_info ) )
5787 }
5888 ( & ty:: Adt ( def_a, _) , & ty:: Adt ( def_b, _) ) => {
5989 assert_eq ! ( def_a, def_b) ;
6090
91+ if src_layout == dst_layout {
92+ return ( src, old_info. unwrap ( ) ) ;
93+ }
94+
6195 let mut result = None ;
6296 for i in 0 ..src_layout. fields . count ( ) {
6397 let src_f = src_layout. field ( fx, i) ;
@@ -71,11 +105,11 @@ fn unsize_thin_ptr<'tcx>(
71105 let dst_f = dst_layout. field ( fx, i) ;
72106 assert_ne ! ( src_f. ty, dst_f. ty) ;
73107 assert_eq ! ( result, None ) ;
74- result = Some ( unsize_thin_ptr ( fx, src, src_f, dst_f) ) ;
108+ result = Some ( unsize_ptr ( fx, src, src_f, dst_f, old_info ) ) ;
75109 }
76110 result. unwrap ( )
77111 }
78- _ => bug ! ( "unsize_thin_ptr : called on bad types" ) ,
112+ _ => bug ! ( "unsize_ptr : called on bad types" ) ,
79113 }
80114}
81115
@@ -91,12 +125,11 @@ pub(crate) fn coerce_unsized_into<'tcx>(
91125 let mut coerce_ptr = || {
92126 let ( base, info) =
93127 if fx. layout_of ( src. layout ( ) . ty . builtin_deref ( true ) . unwrap ( ) . ty ) . is_unsized ( ) {
94- // fat-ptr to fat-ptr unsize preserves the vtable
95- // i.e., &'a fmt::Debug+Send => &'a fmt::Debug
96- src. load_scalar_pair ( fx)
128+ let ( old_base, old_info) = src. load_scalar_pair ( fx) ;
129+ unsize_ptr ( fx, old_base, src. layout ( ) , dst. layout ( ) , Some ( old_info) )
97130 } else {
98131 let base = src. load_scalar ( fx) ;
99- unsize_thin_ptr ( fx, base, src. layout ( ) , dst. layout ( ) )
132+ unsize_ptr ( fx, base, src. layout ( ) , dst. layout ( ) , None )
100133 } ;
101134 dst. write_cvalue ( fx, CValue :: by_val_pair ( base, info, dst. layout ( ) ) ) ;
102135 } ;
0 commit comments