@@ -8,7 +8,8 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
88use rustc_hir:: weak_lang_items:: WEAK_LANG_ITEMS ;
99use rustc_hir:: { LangItem , lang_items} ;
1010use rustc_middle:: middle:: codegen_fn_attrs:: {
11- CodegenFnAttrFlags , CodegenFnAttrs , PatchableFunctionEntry ,
11+ CodegenFnAttrFlags , CodegenFnAttrs , PatchableFunctionEntry , TargetFeature ,
12+ extend_with_struct_target_features,
1213} ;
1314use rustc_middle:: mir:: mono:: Linkage ;
1415use rustc_middle:: query:: Providers ;
@@ -78,23 +79,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
7879 let mut link_ordinal_span = None ;
7980 let mut no_sanitize_span = None ;
8081
82+ let fn_sig_outer = || {
83+ use DefKind :: * ;
84+
85+ let def_kind = tcx. def_kind ( did) ;
86+ if let Fn | AssocFn | Variant | Ctor ( ..) = def_kind { Some ( tcx. fn_sig ( did) ) } else { None }
87+ } ;
88+
8189 for attr in attrs. iter ( ) {
8290 // In some cases, attribute are only valid on functions, but it's the `check_attr`
8391 // pass that check that they aren't used anywhere else, rather this module.
8492 // In these cases, we bail from performing further checks that are only meaningful for
8593 // functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
8694 // report a delayed bug, just in case `check_attr` isn't doing its job.
8795 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 {
96+ let sig = fn_sig_outer ( ) ;
97+ if sig. is_none ( ) {
9498 tcx. dcx ( )
9599 . span_delayed_bug ( attr. span , "this attribute can only be applied to functions" ) ;
96- None
97100 }
101+ sig
98102 } ;
99103
100104 let Some ( Ident { name, .. } ) = attr. ident ( ) else {
@@ -246,7 +250,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
246250 && let Some ( fn_sig) = fn_sig ( )
247251 && fn_sig. skip_binder ( ) . safety ( ) == hir:: Safety :: Safe
248252 {
249- if tcx. sess . target . is_like_wasm || tcx. sess . opts . actually_rustdoc {
253+ if attr. meta_item_list ( ) . is_some_and ( |list| {
254+ list. len ( ) == 1 && list[ 0 ] . ident ( ) . is_some_and ( |x| x. name == sym:: from_args)
255+ } ) {
256+ // #[target_feature(from_args)] can be applied to safe functions and safe
257+ // trait methods.
258+ } else if tcx. sess . target . is_like_wasm || tcx. sess . opts . actually_rustdoc {
250259 // The `#[target_feature]` attribute is allowed on
251260 // WebAssembly targets on all functions, including safe
252261 // ones. Other targets require that `#[target_feature]` is
@@ -284,7 +293,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
284293 tcx,
285294 attr,
286295 supported_target_features,
287- & mut codegen_fn_attrs. target_features ,
296+ & mut codegen_fn_attrs. def_target_features ,
297+ Some ( & mut codegen_fn_attrs. target_features_from_args ) ,
288298 ) ;
289299 }
290300 sym:: linkage => {
@@ -590,16 +600,39 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
590600 let owner_id = tcx. parent ( did. to_def_id ( ) ) ;
591601 if tcx. def_kind ( owner_id) . has_codegen_attrs ( ) {
592602 codegen_fn_attrs
593- . target_features
594- . extend ( tcx. codegen_fn_attrs ( owner_id) . target_features . iter ( ) . copied ( ) ) ;
603+ . def_target_features
604+ . extend ( tcx. codegen_fn_attrs ( owner_id) . def_target_features . iter ( ) . copied ( ) ) ;
595605 }
596606 }
597607
598- // If a function uses #[target_feature] it can't be inlined into general
608+ if let Some ( sig) = fn_sig_outer ( )
609+ && codegen_fn_attrs. target_features_from_args
610+ {
611+ let mut additional_tf = vec ! [ ] ;
612+ for ty in sig. skip_binder ( ) . inputs ( ) . skip_binder ( ) {
613+ extend_with_struct_target_features (
614+ tcx,
615+ tcx. param_env ( did. to_def_id ( ) ) . and ( * ty) ,
616+ & mut additional_tf,
617+ )
618+ }
619+ if !additional_tf. is_empty ( ) && codegen_fn_attrs. inline == InlineAttr :: Always {
620+ tcx. dcx ( ) . span_err (
621+ tcx. hir ( ) . span ( tcx. local_def_id_to_hir_id ( did) ) ,
622+ "cannot use a struct with target features in a #[inline(always)] function" ,
623+ ) ;
624+ }
625+ codegen_fn_attrs
626+ . def_target_features
627+ . extend ( additional_tf. iter ( ) . map ( |tf| TargetFeature { implied : true , ..* tf } ) ) ;
628+ }
629+
630+ // If a function uses non-default target_features it can't be inlined into general
599631 // purpose functions as they wouldn't have the right target features
600632 // enabled. For that reason we also forbid #[inline(always)] as it can't be
601633 // respected.
602- if !codegen_fn_attrs. target_features . is_empty ( ) && codegen_fn_attrs. inline == InlineAttr :: Always
634+ if !codegen_fn_attrs. def_target_features . is_empty ( )
635+ && codegen_fn_attrs. inline == InlineAttr :: Always
603636 {
604637 if let Some ( span) = inline_span {
605638 tcx. dcx ( ) . span_err (
@@ -738,6 +771,20 @@ fn check_link_name_xor_ordinal(
738771 }
739772}
740773
774+ fn struct_target_features ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> & [ TargetFeature ] {
775+ let mut features = vec ! [ ] ;
776+ let supported_features = tcx. supported_target_features ( LOCAL_CRATE ) ;
777+ for attr in tcx. get_attrs ( def_id, sym:: target_feature) {
778+ from_target_feature ( tcx, attr, supported_features, & mut features, None ) ;
779+ }
780+ tcx. arena . alloc_slice ( & features)
781+ }
782+
741783pub ( crate ) fn provide ( providers : & mut Providers ) {
742- * providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..* providers } ;
784+ * providers = Providers {
785+ codegen_fn_attrs,
786+ should_inherit_track_caller,
787+ struct_target_features,
788+ ..* providers
789+ } ;
743790}
0 commit comments