@@ -25,39 +25,73 @@ pub(crate) fn unsized_info<'tcx>(
25
25
. bcx
26
26
. ins ( )
27
27
. 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
+ }
33
62
}
34
63
( _, & ty:: Dynamic ( ref data, ..) ) => crate :: vtable:: get_vtable ( fx, source, data. principal ( ) ) ,
35
64
_ => bug ! ( "unsized_info: invalid unsizing {:?} -> {:?}" , source, target) ,
36
65
}
37
66
}
38
67
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 > (
41
70
fx : & mut FunctionCx < ' _ , ' _ , ' tcx > ,
42
71
src : Value ,
43
72
src_layout : TyAndLayout < ' tcx > ,
44
73
dst_layout : TyAndLayout < ' tcx > ,
74
+ old_info : Option < Value > ,
45
75
) -> ( Value , Value ) {
46
76
match ( & src_layout. ty . kind ( ) , & dst_layout. ty . kind ( ) ) {
47
77
( & ty:: Ref ( _, a, _) , & ty:: Ref ( _, b, _) )
48
78
| ( & ty:: Ref ( _, a, _) , & ty:: RawPtr ( ty:: TypeAndMut { ty : b, .. } ) )
49
79
| ( & ty:: RawPtr ( ty:: TypeAndMut { ty : a, .. } ) , & ty:: RawPtr ( ty:: TypeAndMut { ty : b, .. } ) ) => {
50
80
assert ! ( !fx. layout_of( a) . is_unsized( ) ) ;
51
- ( src, unsized_info ( fx, a, b, None ) )
81
+ ( src, unsized_info ( fx, a, b, old_info ) )
52
82
}
53
83
( & ty:: Adt ( def_a, _) , & ty:: Adt ( def_b, _) ) if def_a. is_box ( ) && def_b. is_box ( ) => {
54
84
let ( a, b) = ( src_layout. ty . boxed_ty ( ) , dst_layout. ty . boxed_ty ( ) ) ;
55
85
assert ! ( !fx. layout_of( a) . is_unsized( ) ) ;
56
- ( src, unsized_info ( fx, a, b, None ) )
86
+ ( src, unsized_info ( fx, a, b, old_info ) )
57
87
}
58
88
( & ty:: Adt ( def_a, _) , & ty:: Adt ( def_b, _) ) => {
59
89
assert_eq ! ( def_a, def_b) ;
60
90
91
+ if src_layout == dst_layout {
92
+ return ( src, old_info. unwrap ( ) ) ;
93
+ }
94
+
61
95
let mut result = None ;
62
96
for i in 0 ..src_layout. fields . count ( ) {
63
97
let src_f = src_layout. field ( fx, i) ;
@@ -71,11 +105,11 @@ fn unsize_thin_ptr<'tcx>(
71
105
let dst_f = dst_layout. field ( fx, i) ;
72
106
assert_ne ! ( src_f. ty, dst_f. ty) ;
73
107
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 ) ) ;
75
109
}
76
110
result. unwrap ( )
77
111
}
78
- _ => bug ! ( "unsize_thin_ptr : called on bad types" ) ,
112
+ _ => bug ! ( "unsize_ptr : called on bad types" ) ,
79
113
}
80
114
}
81
115
@@ -91,12 +125,11 @@ pub(crate) fn coerce_unsized_into<'tcx>(
91
125
let mut coerce_ptr = || {
92
126
let ( base, info) =
93
127
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) )
97
130
} else {
98
131
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 )
100
133
} ;
101
134
dst. write_cvalue ( fx, CValue :: by_val_pair ( base, info, dst. layout ( ) ) ) ;
102
135
} ;
0 commit comments