@@ -9,11 +9,11 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
9
9
use rustc_hir:: weak_lang_items:: WEAK_LANG_ITEMS ;
10
10
use rustc_hir:: { LangItem , lang_items} ;
11
11
use rustc_middle:: middle:: codegen_fn_attrs:: {
12
- CodegenFnAttrFlags , CodegenFnAttrs , PatchableFunctionEntry ,
12
+ CodegenFnAttrFlags , CodegenFnAttrs , PatchableFunctionEntry , TargetFeature ,
13
13
} ;
14
14
use rustc_middle:: mir:: mono:: Linkage ;
15
15
use rustc_middle:: query:: Providers ;
16
- use rustc_middle:: ty:: { self as ty, TyCtxt } ;
16
+ use rustc_middle:: ty:: { self as ty, Ty , TyCtxt } ;
17
17
use rustc_session:: parse:: feature_err;
18
18
use rustc_session:: { Session , lint} ;
19
19
use rustc_span:: symbol:: Ident ;
@@ -79,23 +79,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
79
79
let mut link_ordinal_span = None ;
80
80
let mut no_sanitize_span = None ;
81
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
+
82
89
for attr in attrs. iter ( ) {
83
90
// In some cases, attribute are only valid on functions, but it's the `check_attr`
84
91
// pass that check that they aren't used anywhere else, rather this module.
85
92
// In these cases, we bail from performing further checks that are only meaningful for
86
93
// functions (such as calling `fn_sig`, which ICEs if given a non-function). We also
87
94
// report a delayed bug, just in case `check_attr` isn't doing its job.
88
95
let fn_sig = || {
89
- use DefKind :: * ;
90
-
91
- let def_kind = tcx. def_kind ( did) ;
92
- if let Fn | AssocFn | Variant | Ctor ( ..) = def_kind {
93
- Some ( tcx. fn_sig ( did) )
94
- } else {
96
+ let sig = fn_sig_outer ( ) ;
97
+ if sig. is_none ( ) {
95
98
tcx. dcx ( )
96
99
. span_delayed_bug ( attr. span , "this attribute can only be applied to functions" ) ;
97
- None
98
100
}
101
+ sig
99
102
} ;
100
103
101
104
let Some ( Ident { name, .. } ) = attr. ident ( ) else {
@@ -596,7 +599,30 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
596
599
}
597
600
}
598
601
599
- // If a function uses #[target_feature] it can't be inlined into general
602
+ if let Some ( sig) = fn_sig_outer ( ) {
603
+ for ty in sig. skip_binder ( ) . inputs ( ) . skip_binder ( ) {
604
+ let additional_tf =
605
+ tcx. struct_reachable_target_features ( tcx. param_env ( did. to_def_id ( ) ) . and ( * ty) ) ;
606
+ // FIXME(struct_target_features): is this really necessary?
607
+ if !additional_tf. is_empty ( ) && sig. skip_binder ( ) . abi ( ) != abi:: Abi :: Rust {
608
+ tcx. dcx ( ) . span_err (
609
+ tcx. hir ( ) . span ( tcx. local_def_id_to_hir_id ( did) ) ,
610
+ "cannot use a struct with target features in a function with non-Rust ABI" ,
611
+ ) ;
612
+ }
613
+ if !additional_tf. is_empty ( ) && codegen_fn_attrs. inline == InlineAttr :: Always {
614
+ tcx. dcx ( ) . span_err (
615
+ tcx. hir ( ) . span ( tcx. local_def_id_to_hir_id ( did) ) ,
616
+ "cannot use a struct with target features in a #[inline(always)] function" ,
617
+ ) ;
618
+ }
619
+ codegen_fn_attrs
620
+ . target_features
621
+ . extend ( additional_tf. iter ( ) . map ( |tf| TargetFeature { implied : true , ..* tf } ) ) ;
622
+ }
623
+ }
624
+
625
+ // If a function uses non-default target_features it can't be inlined into general
600
626
// purpose functions as they wouldn't have the right target features
601
627
// enabled. For that reason we also forbid #[inline(always)] as it can't be
602
628
// respected.
@@ -779,6 +805,47 @@ fn check_link_name_xor_ordinal(
779
805
}
780
806
}
781
807
808
+ fn struct_target_features ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> & [ TargetFeature ] {
809
+ let mut features = vec ! [ ] ;
810
+ let supported_features = tcx. supported_target_features ( LOCAL_CRATE ) ;
811
+ for attr in tcx. get_attrs ( def_id, sym:: target_feature) {
812
+ from_target_feature ( tcx, attr, supported_features, & mut features) ;
813
+ }
814
+ tcx. arena . alloc_slice ( & features)
815
+ }
816
+
817
+ fn struct_reachable_target_features < ' tcx > (
818
+ tcx : TyCtxt < ' tcx > ,
819
+ env : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
820
+ ) -> & ' tcx [ TargetFeature ] {
821
+ // Collect target features from types reachable from `env.value` by dereferencing a certain
822
+ // number of references and resolving aliases.
823
+
824
+ let mut ty = env. value ;
825
+ if matches ! ( ty. kind( ) , ty:: Alias ( ..) ) {
826
+ ty = match tcx. try_normalize_erasing_regions ( env. param_env , ty) {
827
+ Ok ( ty) => ty,
828
+ Err ( _) => return tcx. arena . alloc_slice ( & [ ] ) ,
829
+ } ;
830
+ }
831
+ while let ty:: Ref ( _, inner, _) = ty. kind ( ) {
832
+ ty = * inner;
833
+ }
834
+
835
+ let tf = if let ty:: Adt ( adt_def, ..) = ty. kind ( ) {
836
+ tcx. struct_target_features ( adt_def. did ( ) )
837
+ } else {
838
+ & [ ]
839
+ } ;
840
+ tcx. arena . alloc_slice ( tf)
841
+ }
842
+
782
843
pub ( crate ) fn provide ( providers : & mut Providers ) {
783
- * providers = Providers { codegen_fn_attrs, should_inherit_track_caller, ..* providers } ;
844
+ * providers = Providers {
845
+ codegen_fn_attrs,
846
+ should_inherit_track_caller,
847
+ struct_target_features,
848
+ struct_reachable_target_features,
849
+ ..* providers
850
+ } ;
784
851
}
0 commit comments