@@ -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,30 @@ 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+         for  ty in  sig. skip_binder ( ) . inputs ( ) . skip_binder ( )  { 
621+             let  additional_tf =
622+                 tcx. struct_reachable_target_features ( tcx. param_env ( did. to_def_id ( ) ) . and ( * ty) ) ; 
623+             // FIXME(struct_target_features): is this really necessary? 
624+             if  !additional_tf. is_empty ( )  && sig. skip_binder ( ) . abi ( )  != abi:: Abi :: Rust  { 
625+                 tcx. dcx ( ) . span_err ( 
626+                     tcx. hir ( ) . span ( tcx. local_def_id_to_hir_id ( did) ) , 
627+                     "cannot use a struct with target features in a function with non-Rust ABI" , 
628+                 ) ; 
629+             } 
630+             if  !additional_tf. is_empty ( )  && codegen_fn_attrs. inline  == InlineAttr :: Always  { 
631+                 tcx. dcx ( ) . span_err ( 
632+                     tcx. hir ( ) . span ( tcx. local_def_id_to_hir_id ( did) ) , 
633+                     "cannot use a struct with target features in a #[inline(always)] function" , 
634+                 ) ; 
635+             } 
636+             codegen_fn_attrs
637+                 . target_features 
638+                 . extend ( additional_tf. iter ( ) . map ( |tf| TargetFeature  {  implied :  true ,  ..* tf } ) ) ; 
639+         } 
640+     } 
641+ 
642+     // If a function uses non-default target_features it can't be inlined into general 
617643    // purpose functions as they wouldn't have the right target features 
618644    // enabled. For that reason we also forbid #[inline(always)] as it can't be 
619645    // respected. 
@@ -758,6 +784,47 @@ fn check_link_name_xor_ordinal(
758784    } 
759785} 
760786
787+ fn  struct_target_features ( tcx :  TyCtxt < ' _ > ,  def_id :  LocalDefId )  -> & [ TargetFeature ]  { 
788+     let  mut  features = vec ! [ ] ; 
789+     let  supported_features = tcx. supported_target_features ( LOCAL_CRATE ) ; 
790+     for  attr in  tcx. get_attrs ( def_id,  sym:: target_feature)  { 
791+         from_target_feature ( tcx,  attr,  supported_features,  & mut  features) ; 
792+     } 
793+     tcx. arena . alloc_slice ( & features) 
794+ } 
795+ 
796+ fn  struct_reachable_target_features < ' tcx > ( 
797+     tcx :  TyCtxt < ' tcx > , 
798+     env :  ty:: ParamEnvAnd < ' tcx ,  Ty < ' tcx > > , 
799+ )  -> & ' tcx  [ TargetFeature ]  { 
800+     // Collect target features from types reachable from `env.value` by dereferencing a certain 
801+     // number of references and resolving aliases. 
802+ 
803+     let  mut  ty = env. value ; 
804+     if  matches ! ( ty. kind( ) ,  ty:: Alias ( ..) )  { 
805+         ty = match  tcx. try_normalize_erasing_regions ( env. param_env ,  ty)  { 
806+             Ok ( ty)  => ty, 
807+             Err ( _)  => return  tcx. arena . alloc_slice ( & [ ] ) , 
808+         } ; 
809+     } 
810+     while  let  ty:: Ref ( _,  inner,  _)  = ty. kind ( )  { 
811+         ty = * inner; 
812+     } 
813+ 
814+     let  tf = if  let  ty:: Adt ( adt_def,  ..)  = ty. kind ( )  { 
815+         tcx. struct_target_features ( adt_def. did ( ) ) 
816+     }  else  { 
817+         & [ ] 
818+     } ; 
819+     tcx. arena . alloc_slice ( tf) 
820+ } 
821+ 
761822pub  fn  provide ( providers :  & mut  Providers )  { 
762-     * 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+         struct_reachable_target_features, 
828+         ..* providers
829+     } ; 
763830} 
0 commit comments