@@ -144,29 +144,54 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
144
144
///
145
145
/// The `old_info` argument is a bit odd. It is intended for use in an upcast,
146
146
/// where the new vtable for an object will be derived from the old one.
147
- pub fn unsized_info < ' tcx , Cx : CodegenMethods < ' tcx > > (
148
- cx : & Cx ,
147
+ pub fn unsized_info < ' tcx , ' a , Bx : BuilderMethods < ' a , ' tcx > > (
148
+ bx : & mut Bx ,
149
149
source : Ty < ' tcx > ,
150
150
target : Ty < ' tcx > ,
151
- old_info : Option < Cx :: Value > ,
152
- ) -> Cx :: Value {
151
+ old_info : Option < Bx :: Value > ,
152
+ ) -> Bx :: Value {
153
+ let tcx = bx. tcx ( ) ;
153
154
let ( source, target) =
154
- cx . tcx ( ) . struct_lockstep_tails_erasing_lifetimes ( source, target, cx . param_env ( ) ) ;
155
+ tcx. struct_lockstep_tails_erasing_lifetimes ( source, target, bx . param_env ( ) ) ;
155
156
match ( & source. kind , & target. kind ) {
156
157
( & ty:: Array ( _, len) , & ty:: Slice ( _) ) => {
157
- cx . const_usize ( len. eval_usize ( cx . tcx ( ) , ty:: ParamEnv :: reveal_all ( ) ) )
158
+ bx . cx ( ) . const_usize ( len. eval_usize ( tcx, ty:: ParamEnv :: reveal_all ( ) ) )
158
159
}
159
- ( & ty:: Dynamic ( ..) , & ty:: Dynamic ( ..) ) => {
160
- // For now, upcasts are limited to changes in marker
161
- // traits, and hence never actually require an actual
162
- // change to the vtable.
163
- old_info. expect ( "unsized_info: missing old info for trait upcast" )
160
+ ( & ty:: Dynamic ( ..) , & ty:: Dynamic ( ref target_data, ..) ) => {
161
+ // Trait upcast
162
+
163
+ let source_ptr = old_info. expect ( "unsized_info: missing old info for trait upcast" ) ;
164
+ let target_trait_ref = target_data. principal ( )
165
+ . expect ( "target trait object of upcast does not have principal" ) ;
166
+
167
+ let trait_ref = target_trait_ref. with_self_ty ( tcx, source) ;
168
+ let vtable = tcx. codegen_fulfill_obligation ( ( ty:: ParamEnv :: reveal_all ( ) , trait_ref) ) ;
169
+ let offset = match vtable {
170
+ Vtable :: VtableObject ( ref data) => data. vtable_base ,
171
+ // HACK(alexreg): dubious solution to ICE in `manual-self-impl-for-unsafe-obj` test.
172
+ Vtable :: VtableImpl ( _) => 0 ,
173
+ _ => bug ! ( "unsized_info: unexpected vtable kind {:?}" , vtable) ,
174
+ } ;
175
+
176
+ let vtable_layout = bx. cx ( ) . layout_of ( tcx. mk_mut_ptr ( source) ) ;
177
+ let source_ptr = bx. pointercast (
178
+ source_ptr,
179
+ bx. cx ( ) . scalar_pair_element_backend_type ( vtable_layout, 1 , true ) ,
180
+ ) ;
181
+
182
+ let target_ptr = bx. struct_gep ( source_ptr, offset as u64 ) ;
183
+
184
+ let vtable_layout = bx. cx ( ) . layout_of ( tcx. mk_mut_ptr ( target) ) ;
185
+ bx. pointercast (
186
+ target_ptr,
187
+ bx. cx ( ) . scalar_pair_element_backend_type ( vtable_layout, 1 , true ) ,
188
+ )
164
189
}
165
190
( _, & ty:: Dynamic ( ref data, ..) ) => {
166
- let vtable_ptr = cx . layout_of ( cx . tcx ( ) . mk_mut_ptr ( target) ) . field ( cx , FAT_PTR_EXTRA ) ;
167
- cx . const_ptrcast (
168
- meth:: get_vtable ( cx , source, data. principal ( ) ) ,
169
- cx . backend_type ( vtable_ptr ) ,
191
+ let vtable_layout = bx . cx ( ) . layout_of ( tcx. mk_mut_ptr ( target) ) ;
192
+ bx . pointercast (
193
+ meth:: get_vtable ( bx . cx ( ) , source, data. principal ( ) ) ,
194
+ bx . cx ( ) . scalar_pair_element_backend_type ( vtable_layout , 1 , true ) ,
170
195
)
171
196
}
172
197
_ => bug ! ( "unsized_info: invalid unsizing {:?} -> {:?}" , source, target) ,
@@ -186,7 +211,7 @@ pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
186
211
| ( & ty:: RawPtr ( ty:: TypeAndMut { ty : a, .. } ) , & ty:: RawPtr ( ty:: TypeAndMut { ty : b, .. } ) ) => {
187
212
assert ! ( bx. cx( ) . type_is_sized( a) ) ;
188
213
let ptr_ty = bx. cx ( ) . type_ptr_to ( bx. cx ( ) . backend_type ( bx. cx ( ) . layout_of ( b) ) ) ;
189
- ( bx. pointercast ( src, ptr_ty) , unsized_info ( bx. cx ( ) , a, b, None ) )
214
+ ( bx. pointercast ( src, ptr_ty) , unsized_info ( bx, a, b, None ) )
190
215
}
191
216
( & ty:: Adt ( def_a, _) , & ty:: Adt ( def_b, _) ) => {
192
217
assert_eq ! ( def_a, def_b) ;
@@ -253,11 +278,35 @@ pub fn coerce_ptr_unsized<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
253
278
}
254
279
( & ty:: Adt ( def_a, _) , & ty:: Adt ( def_b, _) ) => {
255
280
assert_eq ! ( def_a, def_b) ;
256
- unsized_info ( bx, src. ty , dst. ty , Some ( info) )
281
+
282
+ let mut result = None ;
283
+ for i in 0 ..src. fields . count ( ) {
284
+ let src_f = src. field ( bx. cx ( ) , i) ;
285
+ assert_eq ! ( src. fields. offset( i) . bytes( ) , 0 ) ;
286
+ assert_eq ! ( dst. fields. offset( i) . bytes( ) , 0 ) ;
287
+ if src_f. is_zst ( ) {
288
+ continue ;
289
+ }
290
+ assert_eq ! ( src. size, src_f. size) ;
291
+
292
+ let dst_f = dst. field ( bx. cx ( ) , i) ;
293
+ assert_eq ! ( result, None ) ;
294
+ result = if src_f == dst_f {
295
+ Some ( info)
296
+ } else {
297
+ let f = op. extract_field ( bx, i) ;
298
+ return coerce_ptr_unsized ( bx, f, dst_f) ;
299
+ } ;
300
+ }
301
+ result. unwrap ( )
257
302
}
258
303
_ => bug ! ( "coerce_ptr_unsized: called on bad types" ) ,
259
304
} ;
260
- ( base, info)
305
+ // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
306
+ // FIXME(eddyb) move these out of this `match` arm, so they're always
307
+ // applied, uniformly, no matter the source/destination types.
308
+ ( bx. bitcast ( base, bx. cx ( ) . scalar_pair_element_backend_type ( dst, 0 , true ) ) ,
309
+ bx. bitcast ( info, bx. cx ( ) . scalar_pair_element_backend_type ( dst, 1 , true ) ) )
261
310
}
262
311
OperandValue :: Immediate ( base) => {
263
312
unsize_thin_ptr ( bx, base, src. ty , dst. ty )
@@ -283,23 +332,10 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
283
332
let dst_ty = dst. layout . ty ;
284
333
match ( & src_ty. kind , & dst_ty. kind ) {
285
334
( & ty:: Ref ( ..) , & ty:: Ref ( ..) | & ty:: RawPtr ( ..) ) | ( & ty:: RawPtr ( ..) , & ty:: RawPtr ( ..) ) => {
286
- let ( base, info) = match bx. load_operand ( src) . val {
287
- OperandValue :: Pair ( base, info) => {
288
- // fat-ptr to fat-ptr unsize preserves the vtable
289
- // i.e., &'a fmt::Debug+Send => &'a fmt::Debug
290
- // So we need to pointercast the base to ensure
291
- // the types match up.
292
- // FIXME(eddyb) use `scalar_pair_element_backend_type` here,
293
- // like `unsize_thin_ptr` does.
294
- let thin_ptr = dst. layout . field ( bx. cx ( ) , FAT_PTR_ADDR ) ;
295
- ( bx. pointercast ( base, bx. cx ( ) . backend_type ( thin_ptr) ) , info)
296
- }
297
- OperandValue :: Immediate ( base) => unsize_thin_ptr ( bx, base, src_ty, dst_ty) ,
298
- OperandValue :: Ref ( ..) => bug ! ( ) ,
299
- } ;
300
- OperandValue :: Pair ( base, info) . store ( bx, dst) ;
335
+ let src_op = bx. load_operand ( src) ;
336
+ let dst_op = coerce_ptr_unsized ( bx, src_op, dst. layout ) ;
337
+ dst_op. store ( bx, dst) ; s
301
338
}
302
-
303
339
( & ty:: Adt ( def_a, _) , & ty:: Adt ( def_b, _) ) => {
304
340
assert_eq ! ( def_a, def_b) ;
305
341
0 commit comments