@@ -8,11 +8,11 @@ use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
8
8
use rustc_hir:: weak_lang_items:: WEAK_LANG_ITEMS ;
9
9
use rustc_hir:: { lang_items, LangItem } ;
10
10
use rustc_middle:: middle:: codegen_fn_attrs:: {
11
- CodegenFnAttrFlags , CodegenFnAttrs , PatchableFunctionEntry ,
11
+ CodegenFnAttrFlags , CodegenFnAttrs , PatchableFunctionEntry , TargetFeature ,
12
12
} ;
13
13
use rustc_middle:: mir:: mono:: Linkage ;
14
14
use rustc_middle:: query:: Providers ;
15
- use rustc_middle:: ty:: { self as ty, TyCtxt } ;
15
+ use rustc_middle:: ty:: { self as ty, Ty , TyCtxt } ;
16
16
use rustc_session:: lint;
17
17
use rustc_session:: parse:: feature_err;
18
18
use rustc_span:: symbol:: Ident ;
@@ -78,23 +78,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
78
78
let mut link_ordinal_span = None ;
79
79
let mut no_sanitize_span = None ;
80
80
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
+
81
88
for attr in attrs. iter ( ) {
82
89
// In some cases, attribute are only valid on functions, but it's the `check_attr`
83
90
// pass that check that they aren't used anywhere else, rather this module.
84
91
// In these cases, we bail from performing further checks that are only meaningful for
85
92
// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
86
93
// report a delayed bug, just in case `check_attr` isn't doing its job.
87
94
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 ( ) {
94
97
tcx. dcx ( )
95
98
. span_delayed_bug ( attr. span , "this attribute can only be applied to functions" ) ;
96
- None
97
99
}
100
+ sig
98
101
} ;
99
102
100
103
let Some ( Ident { name, .. } ) = attr. ident ( ) else {
@@ -264,7 +267,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
264
267
&& let Some ( fn_sig) = fn_sig ( )
265
268
&& fn_sig. skip_binder ( ) . safety ( ) == hir:: Safety :: Safe
266
269
{
267
- if tcx. sess . target . is_like_wasm || tcx. sess . opts . actually_rustdoc {
270
+ if attr. meta_item_list ( ) . is_some_and ( |list| {
271
+ list. len ( ) == 1 && list[ 0 ] . ident ( ) . is_some_and ( |x| x. name == sym:: from_args)
272
+ } ) {
273
+ // #[target_feature(from_args)] can be applied to safe functions and safe
274
+ // trait methods.
275
+ } else if tcx. sess . target . is_like_wasm || tcx. sess . opts . actually_rustdoc {
268
276
// The `#[target_feature]` attribute is allowed on
269
277
// WebAssembly targets on all functions, including safe
270
278
// ones. Other targets require that `#[target_feature]` is
@@ -303,6 +311,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
303
311
attr,
304
312
supported_target_features,
305
313
& mut codegen_fn_attrs. target_features ,
314
+ Some ( & mut codegen_fn_attrs. target_features_from_args ) ,
306
315
) ;
307
316
}
308
317
sym:: linkage => {
@@ -613,7 +622,29 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
613
622
}
614
623
}
615
624
616
- // If a function uses #[target_feature] it can't be inlined into general
625
+ if let Some ( sig) = fn_sig_outer ( )
626
+ && codegen_fn_attrs. target_features_from_args
627
+ {
628
+ let mut additional_tf = vec ! [ ] ;
629
+ for ty in sig. skip_binder ( ) . inputs ( ) . skip_binder ( ) {
630
+ extend_with_struct_target_features (
631
+ tcx,
632
+ tcx. param_env ( did. to_def_id ( ) ) . and ( * ty) ,
633
+ & mut additional_tf,
634
+ )
635
+ }
636
+ if !additional_tf. is_empty ( ) && codegen_fn_attrs. inline == InlineAttr :: Always {
637
+ tcx. dcx ( ) . span_err (
638
+ tcx. hir ( ) . span ( tcx. local_def_id_to_hir_id ( did) ) ,
639
+ "cannot use a struct with target features in a #[inline(always)] function" ,
640
+ ) ;
641
+ }
642
+ codegen_fn_attrs
643
+ . target_features
644
+ . extend ( additional_tf. iter ( ) . map ( |tf| TargetFeature { implied : true , ..* tf } ) ) ;
645
+ }
646
+
647
+ // If a function uses non-default target_features it can't be inlined into general
617
648
// purpose functions as they wouldn't have the right target features
618
649
// enabled. For that reason we also forbid #[inline(always)] as it can't be
619
650
// respected.
@@ -755,6 +786,44 @@ fn check_link_name_xor_ordinal(
755
786
}
756
787
}
757
788
789
+ fn struct_target_features ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> & [ TargetFeature ] {
790
+ let mut features = vec ! [ ] ;
791
+ let supported_features = tcx. supported_target_features ( LOCAL_CRATE ) ;
792
+ for attr in tcx. get_attrs ( def_id, sym:: target_feature) {
793
+ from_target_feature ( tcx, attr, supported_features, & mut features, None ) ;
794
+ }
795
+ tcx. arena . alloc_slice ( & features)
796
+ }
797
+
798
+ fn extend_with_struct_target_features < ' tcx > (
799
+ tcx : TyCtxt < ' tcx > ,
800
+ env : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
801
+ target_features : & mut Vec < TargetFeature > ,
802
+ ) {
803
+ // Collect target features from types reachable from `env.value` by dereferencing a certain
804
+ // number of references and resolving aliases.
805
+
806
+ let mut ty = env. value ;
807
+ if matches ! ( ty. kind( ) , ty:: Alias ( ..) ) {
808
+ ty = match tcx. try_normalize_erasing_regions ( env. param_env , ty) {
809
+ Ok ( ty) => ty,
810
+ Err ( _) => return ,
811
+ } ;
812
+ }
813
+ while let ty:: Ref ( _, inner, _) = ty. kind ( ) {
814
+ ty = * inner;
815
+ }
816
+
817
+ if let ty:: Adt ( adt_def, ..) = ty. kind ( ) {
818
+ target_features. extend_from_slice ( & tcx. struct_target_features ( adt_def. did ( ) ) ) ;
819
+ }
820
+ }
821
+
758
822
pub fn provide ( providers : & mut Providers ) {
759
- * providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..* providers } ;
823
+ * providers = Providers {
824
+ codegen_fn_attrs,
825
+ should_inherit_track_caller,
826
+ struct_target_features,
827
+ ..* providers
828
+ } ;
760
829
}
0 commit comments