1
1
use crate :: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
2
2
use crate :: ty:: print:: { FmtPrinter , Printer } ;
3
3
use crate :: ty:: { self , Ty , TyCtxt , TypeFoldable , TypeSuperFoldable } ;
4
- use crate :: ty:: { EarlyBinder , GenericArgs , GenericArgsRef , TypeVisitableExt } ;
4
+ use crate :: ty:: { EarlyBinder , GenericArgs , GenericArgsRef , Lift , TypeVisitableExt } ;
5
5
use rustc_errors:: ErrorGuaranteed ;
6
6
use rustc_hir as hir;
7
7
use rustc_hir:: def:: Namespace ;
@@ -135,14 +135,27 @@ pub enum InstanceDef<'tcx> {
135
135
///
136
136
/// The `DefId` is for `FnPtr::addr`, the `Ty` is the type `T`.
137
137
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 > } ,
138
147
}
139
148
140
149
impl < ' tcx > Instance < ' tcx > {
141
150
/// Returns the `Ty` corresponding to this `Instance`, with generic instantiations applied and
142
151
/// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization.
143
152
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 ( ) ) )
146
159
}
147
160
148
161
/// Finds a crate that contains a monomorphization of this instance that
@@ -198,6 +211,7 @@ impl<'tcx> InstanceDef<'tcx> {
198
211
| InstanceDef :: DropGlue ( def_id, _)
199
212
| InstanceDef :: CloneShim ( def_id, _)
200
213
| InstanceDef :: FnPtrAddrShim ( def_id, _) => def_id,
214
+ InstanceDef :: CfiShim { target_instance, .. } => target_instance. def_id ( ) ,
201
215
}
202
216
}
203
217
@@ -209,6 +223,7 @@ impl<'tcx> InstanceDef<'tcx> {
209
223
Some ( def_id)
210
224
}
211
225
InstanceDef :: VTableShim ( ..)
226
+ | InstanceDef :: CfiShim { .. }
212
227
| InstanceDef :: ReifyShim ( ..)
213
228
| InstanceDef :: FnPtrShim ( ..)
214
229
| InstanceDef :: Virtual ( ..)
@@ -319,6 +334,9 @@ impl<'tcx> InstanceDef<'tcx> {
319
334
| InstanceDef :: ReifyShim ( ..)
320
335
| InstanceDef :: Virtual ( ..)
321
336
| InstanceDef :: VTableShim ( ..) => true ,
337
+ InstanceDef :: CfiShim { target_instance, .. } => {
338
+ target_instance. has_polymorphic_mir_body ( )
339
+ }
322
340
}
323
341
}
324
342
@@ -360,6 +378,10 @@ fn fmt_instance_def(f: &mut fmt::Formatter<'_>, instance_def: &InstanceDef<'_>)
360
378
InstanceDef :: DropGlue ( _, Some ( ty) ) => write ! ( f, " - shim(Some({ty}))" ) ,
361
379
InstanceDef :: CloneShim ( _, ty) => write ! ( f, " - shim({ty})" ) ,
362
380
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
+ }
363
385
}
364
386
}
365
387
@@ -600,6 +622,75 @@ impl<'tcx> Instance<'tcx> {
600
622
Instance :: expect_resolve ( tcx, ty:: ParamEnv :: reveal_all ( ) , def_id, args)
601
623
}
602
624
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
+
603
694
#[ instrument( level = "debug" , skip( tcx) , ret) ]
604
695
pub fn fn_once_adapter_instance (
605
696
tcx : TyCtxt < ' tcx > ,
0 commit comments