@@ -23,7 +23,6 @@ use rustc_middle::middle::cstore::EncodedMetadata;
2323use rustc_middle:: middle:: lang_items;
2424use rustc_middle:: mir:: mono:: { CodegenUnit , CodegenUnitNameBuilder , MonoItem } ;
2525use rustc_middle:: ty:: layout:: { HasTyCtxt , TyAndLayout } ;
26- use rustc_middle:: ty:: layout:: { FAT_PTR_ADDR , FAT_PTR_EXTRA } ;
2726use rustc_middle:: ty:: query:: Providers ;
2827use rustc_middle:: ty:: { self , Instance , Ty , TyCtxt } ;
2928use rustc_session:: cgu_reuse_tracker:: CguReuse ;
@@ -32,6 +31,7 @@ use rustc_session::Session;
3231use rustc_span:: symbol:: sym;
3332use rustc_target:: abi:: { Align , LayoutOf , VariantIdx } ;
3433
34+ use std:: convert:: TryFrom ;
3535use std:: ops:: { Deref , DerefMut } ;
3636use std:: time:: { Duration , Instant } ;
3737
@@ -128,55 +128,92 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
128128///
129129/// The `old_info` argument is a bit odd. It is intended for use in an upcast,
130130/// 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 ,
133133 source : Ty < ' tcx > ,
134134 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 ( ) ;
137138 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 ( ) ) ;
139140 match ( source. kind ( ) , target. kind ( ) ) {
140141 ( & ty:: Array ( _, len) , & ty:: Slice ( _) ) => {
141142 cx. const_usize ( len. eval_usize ( cx. tcx ( ) , ty:: ParamEnv :: reveal_all ( ) ) )
142143 }
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+ }
148181 }
149182 ( _, & 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)
155189 }
156190 _ => bug ! ( "unsized_info: invalid unsizing {:?} -> {:?}" , source, target) ,
157191 }
158192}
159193
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 > > (
162196 bx : & mut Bx ,
163197 src : Bx :: Value ,
164198 src_ty : Ty < ' tcx > ,
165199 dst_ty : Ty < ' tcx > ,
200+ old_info : Option < Bx :: Value > ,
166201) -> ( Bx :: Value , Bx :: Value ) {
167- debug ! ( "unsize_thin_ptr : {:?} => {:?}" , src_ty, dst_ty) ;
202+ debug ! ( "unsize_ptr : {:?} => {:?}" , src_ty, dst_ty) ;
168203 match ( src_ty. kind ( ) , dst_ty. kind ( ) ) {
169204 ( & ty:: Ref ( _, a, _) , & ty:: Ref ( _, b, _) | & ty:: RawPtr ( ty:: TypeAndMut { ty : b, .. } ) )
170205 | ( & 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 ( ) ) ;
172207 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 ) )
174209 }
175210 ( & ty:: Adt ( def_a, _) , & ty:: Adt ( def_b, _) ) => {
176211 assert_eq ! ( def_a, def_b) ;
177-
178212 let src_layout = bx. cx ( ) . layout_of ( src_ty) ;
179213 let dst_layout = bx. cx ( ) . layout_of ( dst_ty) ;
214+ if src_ty == dst_ty {
215+ return ( src, old_info. unwrap ( ) ) ;
216+ }
180217 let mut result = None ;
181218 for i in 0 ..src_layout. fields . count ( ) {
182219 let src_f = src_layout. field ( bx. cx ( ) , i) ;
@@ -190,18 +227,15 @@ pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
190227 let dst_f = dst_layout. field ( bx. cx ( ) , i) ;
191228 assert_ne ! ( src_f. ty, dst_f. ty) ;
192229 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 ) ) ;
194231 }
195232 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 ) ;
196235 // 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) )
203237 }
204- _ => bug ! ( "unsize_thin_ptr : called on bad types" ) ,
238+ _ => bug ! ( "unsize_ptr : called on bad types" ) ,
205239 }
206240}
207241
@@ -217,17 +251,8 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
217251 match ( src_ty. kind ( ) , dst_ty. kind ( ) ) {
218252 ( & ty:: Ref ( ..) , & ty:: Ref ( ..) | & ty:: RawPtr ( ..) ) | ( & ty:: RawPtr ( ..) , & ty:: RawPtr ( ..) ) => {
219253 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 ) ,
231256 OperandValue :: Ref ( ..) => bug ! ( ) ,
232257 } ;
233258 OperandValue :: Pair ( base, info) . store ( bx, dst) ;
0 commit comments