@@ -8,7 +8,8 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
8
8
use rustc_hir:: weak_lang_items:: WEAK_LANG_ITEMS ;
9
9
use rustc_hir:: { LangItem , lang_items} ;
10
10
use rustc_middle:: middle:: codegen_fn_attrs:: {
11
- CodegenFnAttrFlags , CodegenFnAttrs , PatchableFunctionEntry ,
11
+ CodegenFnAttrFlags , CodegenFnAttrs , PatchableFunctionEntry , TargetFeature ,
12
+ extend_with_struct_target_features,
12
13
} ;
13
14
use rustc_middle:: mir:: mono:: Linkage ;
14
15
use rustc_middle:: query:: Providers ;
@@ -78,23 +79,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
78
79
let mut link_ordinal_span = None ;
79
80
let mut no_sanitize_span = None ;
80
81
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
+
81
89
for attr in attrs. iter ( ) {
82
90
// In some cases, attribute are only valid on functions, but it's the `check_attr`
83
91
// pass that check that they aren't used anywhere else, rather this module.
84
92
// In these cases, we bail from performing further checks that are only meaningful for
85
93
// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
86
94
// report a delayed bug, just in case `check_attr` isn't doing its job.
87
95
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 ( ) {
94
98
tcx. dcx ( )
95
99
. span_delayed_bug ( attr. span , "this attribute can only be applied to functions" ) ;
96
- None
97
100
}
101
+ sig
98
102
} ;
99
103
100
104
let Some ( Ident { name, .. } ) = attr. ident ( ) else {
@@ -246,7 +250,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
246
250
&& let Some ( fn_sig) = fn_sig ( )
247
251
&& fn_sig. skip_binder ( ) . safety ( ) == hir:: Safety :: Safe
248
252
{
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 {
250
259
// The `#[target_feature]` attribute is allowed on
251
260
// WebAssembly targets on all functions, including safe
252
261
// ones. Other targets require that `#[target_feature]` is
@@ -284,7 +293,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
284
293
tcx,
285
294
attr,
286
295
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 ) ,
288
298
) ;
289
299
}
290
300
sym:: linkage => {
@@ -590,16 +600,39 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
590
600
let owner_id = tcx. parent ( did. to_def_id ( ) ) ;
591
601
if tcx. def_kind ( owner_id) . has_codegen_attrs ( ) {
592
602
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 ( ) ) ;
595
605
}
596
606
}
597
607
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
599
631
// purpose functions as they wouldn't have the right target features
600
632
// enabled. For that reason we also forbid #[inline(always)] as it can't be
601
633
// 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
603
636
{
604
637
if let Some ( span) = inline_span {
605
638
tcx. dcx ( ) . span_err (
@@ -738,6 +771,20 @@ fn check_link_name_xor_ordinal(
738
771
}
739
772
}
740
773
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
+
741
783
pub ( 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
+ } ;
743
790
}
0 commit comments