@@ -23,7 +23,6 @@ use rustc_middle::middle::cstore::EncodedMetadata;
23
23
use rustc_middle:: middle:: lang_items;
24
24
use rustc_middle:: mir:: mono:: { CodegenUnit , CodegenUnitNameBuilder , MonoItem } ;
25
25
use rustc_middle:: ty:: layout:: { HasTyCtxt , TyAndLayout } ;
26
- use rustc_middle:: ty:: layout:: { FAT_PTR_ADDR , FAT_PTR_EXTRA } ;
27
26
use rustc_middle:: ty:: query:: Providers ;
28
27
use rustc_middle:: ty:: { self , Instance , Ty , TyCtxt } ;
29
28
use rustc_session:: cgu_reuse_tracker:: CguReuse ;
@@ -32,6 +31,7 @@ use rustc_session::Session;
32
31
use rustc_span:: symbol:: sym;
33
32
use rustc_target:: abi:: { Align , LayoutOf , VariantIdx } ;
34
33
34
+ use std:: convert:: TryFrom ;
35
35
use std:: ops:: { Deref , DerefMut } ;
36
36
use std:: time:: { Duration , Instant } ;
37
37
@@ -128,55 +128,92 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
128
128
///
129
129
/// The `old_info` argument is a bit odd. It is intended for use in an upcast,
130
130
/// where the new vtable for an object will be derived from the old one.
131
- pub fn unsized_info < ' tcx , Cx : CodegenMethods < ' tcx > > (
132
- cx : & Cx ,
131
+ pub fn unsized_info < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > (
132
+ bx : & mut Bx ,
133
133
source : Ty < ' tcx > ,
134
134
target : Ty < ' tcx > ,
135
- old_info : Option < Cx :: Value > ,
136
- ) -> Cx :: Value {
135
+ old_info : Option < Bx :: Value > ,
136
+ ) -> Bx :: Value {
137
+ let cx = bx. cx ( ) ;
137
138
let ( source, target) =
138
- cx. tcx ( ) . struct_lockstep_tails_erasing_lifetimes ( source, target, cx . param_env ( ) ) ;
139
+ cx. tcx ( ) . struct_lockstep_tails_erasing_lifetimes ( source, target, bx . param_env ( ) ) ;
139
140
match ( source. kind ( ) , target. kind ( ) ) {
140
141
( & ty:: Array ( _, len) , & ty:: Slice ( _) ) => {
141
142
cx. const_usize ( len. eval_usize ( cx. tcx ( ) , ty:: ParamEnv :: reveal_all ( ) ) )
142
143
}
143
- ( & ty:: Dynamic ( ..) , & ty:: Dynamic ( ..) ) => {
144
- // For now, upcasts are limited to changes in marker
145
- // traits, and hence never actually require an actual
146
- // change to the vtable.
147
- old_info. expect ( "unsized_info: missing old info for trait upcast" )
144
+ ( & ty:: Dynamic ( ref data_a, ..) , & ty:: Dynamic ( ref data_b, ..) ) => {
145
+ let old_info =
146
+ old_info. expect ( "unsized_info: missing old info for trait upcasting coercion" ) ;
147
+ if data_a. principal_def_id ( ) == data_b. principal_def_id ( ) {
148
+ return old_info;
149
+ }
150
+
151
+ // trait upcasting coercion
152
+
153
+ // if both of the two `principal`s are `None`, this function would have returned early above.
154
+ // and if one of the two `principal`s is `None`, typechecking would have rejected this case.
155
+ let principal_a = data_a
156
+ . principal ( )
157
+ . expect ( "unsized_info: missing principal trait for trait upcasting coercion" ) ;
158
+ let principal_b = data_b
159
+ . principal ( )
160
+ . expect ( "unsized_info: missing principal trait for trait upcasting coercion" ) ;
161
+
162
+ let vptr_entry_idx = cx. tcx ( ) . vtable_trait_upcasting_coercion_new_vptr_slot ( (
163
+ principal_a. with_self_ty ( cx. tcx ( ) , source) ,
164
+ principal_b. with_self_ty ( cx. tcx ( ) , source) ,
165
+ ) ) ;
166
+
167
+ if let Some ( entry_idx) = vptr_entry_idx {
168
+ let ptr_ty = cx. type_i8p ( ) ;
169
+ let ptr_align = cx. tcx ( ) . data_layout . pointer_align . abi ;
170
+ let llvtable = bx. pointercast ( old_info, bx. type_ptr_to ( ptr_ty) ) ;
171
+ let gep =
172
+ bx. inbounds_gep ( llvtable, & [ bx. const_usize ( u64:: try_from ( entry_idx) . unwrap ( ) ) ] ) ;
173
+ let new_vptr = bx. load ( ptr_ty, gep, ptr_align) ;
174
+ bx. nonnull_metadata ( new_vptr) ;
175
+ // Vtable loads are invariant.
176
+ bx. set_invariant_load ( new_vptr) ;
177
+ new_vptr
178
+ } else {
179
+ old_info
180
+ }
148
181
}
149
182
( _, & ty:: Dynamic ( ref data, ..) ) => {
150
- let vtable_ptr = cx. layout_of ( cx. tcx ( ) . mk_mut_ptr ( target) ) . field ( cx, FAT_PTR_EXTRA ) ;
151
- cx. const_ptrcast (
152
- meth:: get_vtable ( cx, source, data. principal ( ) ) ,
153
- cx. backend_type ( vtable_ptr) ,
154
- )
183
+ let vtable_ptr_ty = cx. scalar_pair_element_backend_type (
184
+ cx. layout_of ( cx. tcx ( ) . mk_mut_ptr ( target) ) ,
185
+ 1 ,
186
+ true ,
187
+ ) ;
188
+ cx. const_ptrcast ( meth:: get_vtable ( cx, source, data. principal ( ) ) , vtable_ptr_ty)
155
189
}
156
190
_ => bug ! ( "unsized_info: invalid unsizing {:?} -> {:?}" , source, target) ,
157
191
}
158
192
}
159
193
160
- /// Coerces `src` to `dst_ty`. `src_ty` must be a thin pointer.
161
- pub fn unsize_thin_ptr < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > (
194
+ /// Coerces `src` to `dst_ty`. `src_ty` must be a pointer.
195
+ pub fn unsize_ptr < ' a , ' tcx , Bx : BuilderMethods < ' a , ' tcx > > (
162
196
bx : & mut Bx ,
163
197
src : Bx :: Value ,
164
198
src_ty : Ty < ' tcx > ,
165
199
dst_ty : Ty < ' tcx > ,
200
+ old_info : Option < Bx :: Value > ,
166
201
) -> ( Bx :: Value , Bx :: Value ) {
167
- debug ! ( "unsize_thin_ptr : {:?} => {:?}" , src_ty, dst_ty) ;
202
+ debug ! ( "unsize_ptr : {:?} => {:?}" , src_ty, dst_ty) ;
168
203
match ( src_ty. kind ( ) , dst_ty. kind ( ) ) {
169
204
( & ty:: Ref ( _, a, _) , & ty:: Ref ( _, b, _) | & ty:: RawPtr ( ty:: TypeAndMut { ty : b, .. } ) )
170
205
| ( & ty:: RawPtr ( ty:: TypeAndMut { ty : a, .. } ) , & ty:: RawPtr ( ty:: TypeAndMut { ty : b, .. } ) ) => {
171
- assert ! ( bx. cx( ) . type_is_sized( a) ) ;
206
+ assert_eq ! ( bx. cx( ) . type_is_sized( a) , old_info . is_none ( ) ) ;
172
207
let ptr_ty = bx. cx ( ) . type_ptr_to ( bx. cx ( ) . backend_type ( bx. cx ( ) . layout_of ( b) ) ) ;
173
- ( bx. pointercast ( src, ptr_ty) , unsized_info ( bx. cx ( ) , a, b, None ) )
208
+ ( bx. pointercast ( src, ptr_ty) , unsized_info ( bx, a, b, old_info ) )
174
209
}
175
210
( & ty:: Adt ( def_a, _) , & ty:: Adt ( def_b, _) ) => {
176
211
assert_eq ! ( def_a, def_b) ;
177
-
178
212
let src_layout = bx. cx ( ) . layout_of ( src_ty) ;
179
213
let dst_layout = bx. cx ( ) . layout_of ( dst_ty) ;
214
+ if src_ty == dst_ty {
215
+ return ( src, old_info. unwrap ( ) ) ;
216
+ }
180
217
let mut result = None ;
181
218
for i in 0 ..src_layout. fields . count ( ) {
182
219
let src_f = src_layout. field ( bx. cx ( ) , i) ;
@@ -190,18 +227,15 @@ pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
190
227
let dst_f = dst_layout. field ( bx. cx ( ) , i) ;
191
228
assert_ne ! ( src_f. ty, dst_f. ty) ;
192
229
assert_eq ! ( result, None ) ;
193
- result = Some ( unsize_thin_ptr ( bx, src, src_f. ty , dst_f. ty ) ) ;
230
+ result = Some ( unsize_ptr ( bx, src, src_f. ty , dst_f. ty , old_info ) ) ;
194
231
}
195
232
let ( lldata, llextra) = result. unwrap ( ) ;
233
+ let lldata_ty = bx. cx ( ) . scalar_pair_element_backend_type ( dst_layout, 0 , true ) ;
234
+ let llextra_ty = bx. cx ( ) . scalar_pair_element_backend_type ( dst_layout, 1 , true ) ;
196
235
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
197
- // FIXME(eddyb) move these out of this `match` arm, so they're always
198
- // applied, uniformly, no matter the source/destination types.
199
- (
200
- bx. bitcast ( lldata, bx. cx ( ) . scalar_pair_element_backend_type ( dst_layout, 0 , true ) ) ,
201
- bx. bitcast ( llextra, bx. cx ( ) . scalar_pair_element_backend_type ( dst_layout, 1 , true ) ) ,
202
- )
236
+ ( bx. bitcast ( lldata, lldata_ty) , bx. bitcast ( llextra, llextra_ty) )
203
237
}
204
- _ => bug ! ( "unsize_thin_ptr : called on bad types" ) ,
238
+ _ => bug ! ( "unsize_ptr : called on bad types" ) ,
205
239
}
206
240
}
207
241
@@ -217,17 +251,8 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
217
251
match ( src_ty. kind ( ) , dst_ty. kind ( ) ) {
218
252
( & ty:: Ref ( ..) , & ty:: Ref ( ..) | & ty:: RawPtr ( ..) ) | ( & ty:: RawPtr ( ..) , & ty:: RawPtr ( ..) ) => {
219
253
let ( base, info) = match bx. load_operand ( src) . val {
220
- OperandValue :: Pair ( base, info) => {
221
- // fat-ptr to fat-ptr unsize preserves the vtable
222
- // i.e., &'a fmt::Debug+Send => &'a fmt::Debug
223
- // So we need to pointercast the base to ensure
224
- // the types match up.
225
- // FIXME(eddyb) use `scalar_pair_element_backend_type` here,
226
- // like `unsize_thin_ptr` does.
227
- let thin_ptr = dst. layout . field ( bx. cx ( ) , FAT_PTR_ADDR ) ;
228
- ( bx. pointercast ( base, bx. cx ( ) . backend_type ( thin_ptr) ) , info)
229
- }
230
- OperandValue :: Immediate ( base) => unsize_thin_ptr ( bx, base, src_ty, dst_ty) ,
254
+ OperandValue :: Pair ( base, info) => unsize_ptr ( bx, base, src_ty, dst_ty, Some ( info) ) ,
255
+ OperandValue :: Immediate ( base) => unsize_ptr ( bx, base, src_ty, dst_ty, None ) ,
231
256
OperandValue :: Ref ( ..) => bug ! ( ) ,
232
257
} ;
233
258
OperandValue :: Pair ( base, info) . store ( bx, dst) ;
0 commit comments