11use crate :: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
22use crate :: ty:: print:: { FmtPrinter , Printer } ;
33use crate :: ty:: { self , Ty , TyCtxt , TypeFoldable , TypeSuperFoldable } ;
4- use crate :: ty:: { EarlyBinder , GenericArgs , GenericArgsRef , TypeVisitableExt } ;
4+ use crate :: ty:: { EarlyBinder , GenericArgs , GenericArgsRef , Lift , TypeVisitableExt } ;
55use rustc_errors:: ErrorGuaranteed ;
66use rustc_hir as hir;
77use rustc_hir:: def:: Namespace ;
@@ -135,14 +135,27 @@ pub enum InstanceDef<'tcx> {
135135 ///
136136 /// The `DefId` is for `FnPtr::addr`, the `Ty` is the type `T`.
137137 FnPtrAddrShim ( DefId , Ty < ' tcx > ) ,
138+
139+ /// Typecast shim which replaces the `Self` type with the provided type.
140+ /// This is used in vtable calls, where the type of `Self` is abstract as of the time of
141+ /// the call.
142+ ///
143+ /// For `target_instance` which are generatable shims, this is done via inserting a cast at the
144+ /// beginning of the shim generated by that instance.
145+ /// For `Item`s, we instead build a direct call shim with that cast inserted.
146+ CfiShim { target_instance : & ' tcx InstanceDef < ' tcx > , invoke_ty : Ty < ' tcx > } ,
138147}
139148
140149impl < ' tcx > Instance < ' tcx > {
141150 /// Returns the `Ty` corresponding to this `Instance`, with generic instantiations applied and
142151 /// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization.
143152 pub fn ty ( & self , tcx : TyCtxt < ' tcx > , param_env : ty:: ParamEnv < ' tcx > ) -> Ty < ' tcx > {
144- let ty = tcx. type_of ( self . def . def_id ( ) ) ;
145- tcx. instantiate_and_normalize_erasing_regions ( self . args , param_env, ty)
153+ let args = if let InstanceDef :: CfiShim { invoke_ty, .. } = self . def {
154+ tcx. mk_args_trait ( invoke_ty, ( * self . args ) . into_iter ( ) . skip ( 1 ) )
155+ } else {
156+ self . args
157+ } ;
158+ tcx. instantiate_and_normalize_erasing_regions ( args, param_env, tcx. type_of ( self . def_id ( ) ) )
146159 }
147160
148161 /// Finds a crate that contains a monomorphization of this instance that
@@ -198,6 +211,7 @@ impl<'tcx> InstanceDef<'tcx> {
198211 | InstanceDef :: DropGlue ( def_id, _)
199212 | InstanceDef :: CloneShim ( def_id, _)
200213 | InstanceDef :: FnPtrAddrShim ( def_id, _) => def_id,
214+ InstanceDef :: CfiShim { target_instance, .. } => target_instance. def_id ( ) ,
201215 }
202216 }
203217
@@ -209,6 +223,7 @@ impl<'tcx> InstanceDef<'tcx> {
209223 Some ( def_id)
210224 }
211225 InstanceDef :: VTableShim ( ..)
226+ | InstanceDef :: CfiShim { .. }
212227 | InstanceDef :: ReifyShim ( ..)
213228 | InstanceDef :: FnPtrShim ( ..)
214229 | InstanceDef :: Virtual ( ..)
@@ -319,6 +334,9 @@ impl<'tcx> InstanceDef<'tcx> {
319334 | InstanceDef :: ReifyShim ( ..)
320335 | InstanceDef :: Virtual ( ..)
321336 | InstanceDef :: VTableShim ( ..) => true ,
337+ InstanceDef :: CfiShim { target_instance, .. } => {
338+ target_instance. has_polymorphic_mir_body ( )
339+ }
322340 }
323341 }
324342
@@ -360,6 +378,10 @@ fn fmt_instance_def(f: &mut fmt::Formatter<'_>, instance_def: &InstanceDef<'_>)
360378 InstanceDef :: DropGlue ( _, Some ( ty) ) => write ! ( f, " - shim(Some({ty}))" ) ,
361379 InstanceDef :: CloneShim ( _, ty) => write ! ( f, " - shim({ty})" ) ,
362380 InstanceDef :: FnPtrAddrShim ( _, ty) => write ! ( f, " - shim({ty})" ) ,
381+ InstanceDef :: CfiShim { invoke_ty, target_instance } => {
382+ fmt_instance_def ( f, target_instance) ?;
383+ write ! ( f, " - cfi-shim({invoke_ty})" )
384+ }
363385 }
364386}
365387
@@ -600,6 +622,75 @@ impl<'tcx> Instance<'tcx> {
600622 Instance :: expect_resolve ( tcx, ty:: ParamEnv :: reveal_all ( ) , def_id, args)
601623 }
602624
625+ pub fn cfi_shim (
626+ mut self ,
627+ tcx : TyCtxt < ' tcx > ,
628+ invoke_trait : Option < ty:: PolyTraitRef < ' tcx > > ,
629+ ) -> ty:: Instance < ' tcx > {
630+ if tcx. sess . cfi_shims ( ) {
631+ let invoke_ty = if let Some ( poly_trait_ref) = invoke_trait {
632+ tcx. trait_object_ty ( poly_trait_ref)
633+ } else {
634+ Ty :: new_dynamic ( tcx, ty:: List :: empty ( ) , tcx. lifetimes . re_erased , ty:: Dyn )
635+ } ;
636+ if tcx. is_closure_like ( self . def . def_id ( ) ) {
637+ // Closures don't have a fn_sig and can't be called directly.
638+ // Adjust it into a call through
639+ // `Fn`/`FnMut`/`FnOnce`/`AsyncFn`/`AsyncFnMut`/`AsyncFnOnce`/`Coroutine`
640+ // based on its receiver.
641+ let ty:: TyKind :: Dynamic ( pep, _, _) = invoke_ty. kind ( ) else {
642+ bug ! ( "Closure-like with non-dynamic invoke_ty {invoke_ty}" )
643+ } ;
644+ let Some ( fn_trait) = pep. principal_def_id ( ) else {
645+ bug ! ( "Closure-like with no principal trait on invoke_ty {invoke_ty}" )
646+ } ;
647+ let call = tcx
648+ . associated_items ( fn_trait)
649+ . in_definition_order ( )
650+ . find ( |it| it. kind == ty:: AssocKind :: Fn )
651+ . expect ( "No call-family function on closure-like principal trait?" )
652+ . def_id ;
653+
654+ let self_ty = self . ty ( tcx, ty:: ParamEnv :: reveal_all ( ) ) ;
655+ let tupled_inputs_ty =
656+ self . args . as_closure ( ) . sig ( ) . map_bound ( |sig| sig. inputs ( ) [ 0 ] ) ;
657+ let tupled_inputs_ty = tcx. instantiate_bound_regions_with_erased ( tupled_inputs_ty) ;
658+ self . args = tcx. mk_args_trait ( self_ty, [ tupled_inputs_ty. into ( ) ] ) ;
659+ self . def = InstanceDef :: Item ( call) ;
660+ } else if let Some ( impl_id) = tcx. impl_of_method ( self . def . def_id ( ) ) {
661+ // Trait methods will have a Self polymorphic parameter, where the concreteized
662+ // implementatation will not. We need to walk back to the more general trait method
663+ // so that we can swap out Self when generating a type signature.
664+ let Some ( trait_ref) = tcx. impl_trait_ref ( impl_id) else {
665+ bug ! ( "When trying to rewrite the type on {self}, found inherent impl method" )
666+ } ;
667+ let trait_ref = trait_ref. instantiate ( tcx, self . args ) ;
668+
669+ let method_id = tcx
670+ . impl_item_implementor_ids ( impl_id)
671+ . items ( )
672+ . filter_map ( |( trait_method, impl_method) | {
673+ ( * impl_method == self . def . def_id ( ) ) . then_some ( * trait_method)
674+ } )
675+ . min ( )
676+ . unwrap ( ) ;
677+ self . def = InstanceDef :: Item ( method_id) ;
678+ self . args = trait_ref. args ;
679+ }
680+ // At this point, we should have gauranteed that the first item in the args list is
681+ // the dispatch type. We can't check for Self, because `drop_in_place` takes `T`.
682+ self . def = InstanceDef :: CfiShim {
683+ target_instance : ( & self . def ) . lift_to_tcx ( tcx) . expect ( "Could not lift for shimming" ) ,
684+ invoke_ty,
685+ } ;
686+ }
687+ self
688+ }
689+
690+ pub fn force_thin_self ( & self ) -> bool {
691+ matches ! ( self . def, InstanceDef :: Virtual ( ..) | InstanceDef :: CfiShim { .. } )
692+ }
693+
603694 #[ instrument( level = "debug" , skip( tcx) , ret) ]
604695 pub fn fn_once_adapter_instance (
605696 tcx : TyCtxt < ' tcx > ,
0 commit comments