@@ -8,11 +8,11 @@ use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
88use rustc_hir:: weak_lang_items:: WEAK_LANG_ITEMS ;
99use rustc_hir:: { lang_items, LangItem } ;
1010use rustc_middle:: middle:: codegen_fn_attrs:: {
11- CodegenFnAttrFlags , CodegenFnAttrs , PatchableFunctionEntry ,
11+ CodegenFnAttrFlags , CodegenFnAttrs , PatchableFunctionEntry , TargetFeature ,
1212} ;
1313use rustc_middle:: mir:: mono:: Linkage ;
1414use rustc_middle:: query:: Providers ;
15- use rustc_middle:: ty:: { self as ty, TyCtxt } ;
15+ use rustc_middle:: ty:: { self as ty, Ty , TyCtxt } ;
1616use rustc_session:: lint;
1717use rustc_session:: parse:: feature_err;
1818use rustc_span:: symbol:: Ident ;
@@ -78,23 +78,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
7878 let mut link_ordinal_span = None ;
7979 let mut no_sanitize_span = None ;
8080
81+ let fn_sig_outer = || {
82+ use DefKind :: * ;
83+
84+ let def_kind = tcx. def_kind ( did) ;
85+ if let Fn | AssocFn | Variant | Ctor ( ..) = def_kind { Some ( tcx. fn_sig ( did) ) } else { None }
86+ } ;
87+
8188 for attr in attrs. iter ( ) {
8289 // In some cases, attribute are only valid on functions, but it's the `check_attr`
8390 // pass that check that they aren't used anywhere else, rather this module.
8491 // In these cases, we bail from performing further checks that are only meaningful for
8592 // functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
8693 // report a delayed bug, just in case `check_attr` isn't doing its job.
8794 let fn_sig = || {
88- use DefKind :: * ;
89-
90- let def_kind = tcx. def_kind ( did) ;
91- if let Fn | AssocFn | Variant | Ctor ( ..) = def_kind {
92- Some ( tcx. fn_sig ( did) )
93- } else {
95+ let sig = fn_sig_outer ( ) ;
96+ if sig. is_none ( ) {
9497 tcx. dcx ( )
9598 . span_delayed_bug ( attr. span , "this attribute can only be applied to functions" ) ;
96- None
9799 }
100+ sig
98101 } ;
99102
100103 let Some ( Ident { name, .. } ) = attr. ident ( ) else {
@@ -613,7 +616,34 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
613616 }
614617 }
615618
616- // If a function uses #[target_feature] it can't be inlined into general
619+ if let Some ( sig) = fn_sig_outer ( ) {
620+ let mut additional_tf = vec ! [ ] ;
621+ for ty in sig. skip_binder ( ) . inputs ( ) . skip_binder ( ) {
622+ extend_with_struct_target_features (
623+ tcx,
624+ tcx. param_env ( did. to_def_id ( ) ) . and ( * ty) ,
625+ & mut additional_tf,
626+ )
627+ }
628+ // FIXME(struct_target_features): is this really necessary?
629+ if !additional_tf. is_empty ( ) && sig. skip_binder ( ) . abi ( ) != abi:: Abi :: Rust {
630+ tcx. dcx ( ) . span_err (
631+ tcx. hir ( ) . span ( tcx. local_def_id_to_hir_id ( did) ) ,
632+ "cannot use a struct with target features in a function with non-Rust ABI" ,
633+ ) ;
634+ }
635+ if !additional_tf. is_empty ( ) && codegen_fn_attrs. inline == InlineAttr :: Always {
636+ tcx. dcx ( ) . span_err (
637+ tcx. hir ( ) . span ( tcx. local_def_id_to_hir_id ( did) ) ,
638+ "cannot use a struct with target features in a #[inline(always)] function" ,
639+ ) ;
640+ }
641+ codegen_fn_attrs
642+ . target_features
643+ . extend ( additional_tf. iter ( ) . map ( |tf| TargetFeature { implied : true , ..* tf } ) ) ;
644+ }
645+
646+ // If a function uses non-default target_features it can't be inlined into general
617647 // purpose functions as they wouldn't have the right target features
618648 // enabled. For that reason we also forbid #[inline(always)] as it can't be
619649 // respected.
@@ -758,6 +788,44 @@ fn check_link_name_xor_ordinal(
758788 }
759789}
760790
791+ fn struct_target_features ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> & [ TargetFeature ] {
792+ let mut features = vec ! [ ] ;
793+ let supported_features = tcx. supported_target_features ( LOCAL_CRATE ) ;
794+ for attr in tcx. get_attrs ( def_id, sym:: target_feature) {
795+ from_target_feature ( tcx, attr, supported_features, & mut features) ;
796+ }
797+ tcx. arena . alloc_slice ( & features)
798+ }
799+
800+ fn extend_with_struct_target_features < ' tcx > (
801+ tcx : TyCtxt < ' tcx > ,
802+ env : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
803+ target_features : & mut Vec < TargetFeature > ,
804+ ) {
805+ // Collect target features from types reachable from `env.value` by dereferencing a certain
806+ // number of references and resolving aliases.
807+
808+ let mut ty = env. value ;
809+ if matches ! ( ty. kind( ) , ty:: Alias ( ..) ) {
810+ ty = match tcx. try_normalize_erasing_regions ( env. param_env , ty) {
811+ Ok ( ty) => ty,
812+ Err ( _) => return ,
813+ } ;
814+ }
815+ while let ty:: Ref ( _, inner, _) = ty. kind ( ) {
816+ ty = * inner;
817+ }
818+
819+ if let ty:: Adt ( adt_def, ..) = ty. kind ( ) {
820+ target_features. extend_from_slice ( & tcx. struct_target_features ( adt_def. did ( ) ) ) ;
821+ }
822+ }
823+
761824pub fn provide ( providers : & mut Providers ) {
762- * providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..* providers } ;
825+ * providers = Providers {
826+ codegen_fn_attrs,
827+ should_inherit_track_caller,
828+ struct_target_features,
829+ ..* providers
830+ } ;
763831}
0 commit comments