@@ -13,7 +13,7 @@ use rustc_middle::middle::codegen_fn_attrs::{
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:: lint;
18
18
use rustc_session:: parse:: feature_err;
19
19
use rustc_span:: symbol:: Ident ;
@@ -619,89 +619,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
619
619
}
620
620
621
621
if let Some ( sig) = fn_sig_outer ( ) {
622
- // Collect target features from types reachable from arguments.
623
- // We define a type as "reachable" if:
624
- // - it is a function argument
625
- // - it is a field of a reachable struct
626
- // - there is a reachable reference to it
627
- // FIXME(struct_target_features): we may want to cache the result of this computation.
628
- let mut visited_types = FxHashSet :: default ( ) ;
629
- let mut reachable_types: Vec < _ > = sig. skip_binder ( ) . inputs ( ) . skip_binder ( ) . to_owned ( ) ;
630
- let mut additional_tf = vec ! [ ] ;
631
-
632
- while let Some ( ty) = reachable_types. pop ( ) {
633
- if visited_types. contains ( & ty) {
634
- continue ;
622
+ for ty in sig. skip_binder ( ) . inputs ( ) . skip_binder ( ) {
623
+ let additional_tf =
624
+ tcx. struct_reachable_target_features ( tcx. param_env ( did. to_def_id ( ) ) . and ( * ty) ) ;
625
+ // FIXME(struct_target_features): is this really necessary?
626
+ if !additional_tf. is_empty ( ) && sig. skip_binder ( ) . abi ( ) != abi:: Abi :: Rust {
627
+ tcx. dcx ( ) . span_err (
628
+ tcx. hir ( ) . span ( tcx. local_def_id_to_hir_id ( did) ) ,
629
+ "cannot use a struct with target features in a function with non-Rust ABI" ,
630
+ ) ;
635
631
}
636
- visited_types. insert ( ty) ;
637
- match ty. kind ( ) {
638
- ty:: Alias ( ..) => {
639
- if let Ok ( t) =
640
- tcx. try_normalize_erasing_regions ( tcx. param_env ( did. to_def_id ( ) ) , ty)
641
- {
642
- reachable_types. push ( t)
643
- }
644
- }
645
-
646
- ty:: Ref ( _, inner, _) => reachable_types. push ( * inner) ,
647
- ty:: Tuple ( tys) => reachable_types. extend ( tys. iter ( ) ) ,
648
- ty:: Adt ( adt_def, args) => {
649
- additional_tf. extend_from_slice ( tcx. struct_target_features ( adt_def. did ( ) ) ) ;
650
- // This only recurses into structs as i.e. an Option<TargetFeature> is an ADT
651
- // that doesn't actually always contain a TargetFeature.
652
- if adt_def. is_struct ( ) {
653
- reachable_types. extend (
654
- adt_def
655
- . variant ( VariantIdx :: from_usize ( 0 ) )
656
- . fields
657
- . iter ( )
658
- . map ( |field| field. ty ( tcx, args) ) ,
659
- ) ;
660
- }
661
- }
662
- ty:: Bool
663
- | ty:: Char
664
- | ty:: Int ( ..)
665
- | ty:: Uint ( ..)
666
- | ty:: Float ( ..)
667
- | ty:: Foreign ( ..)
668
- | ty:: Str
669
- | ty:: Array ( ..)
670
- | ty:: Pat ( ..)
671
- | ty:: Slice ( ..)
672
- | ty:: RawPtr ( ..)
673
- | ty:: FnDef ( ..)
674
- | ty:: FnPtr ( ..)
675
- | ty:: Dynamic ( ..)
676
- | ty:: Closure ( ..)
677
- | ty:: CoroutineClosure ( ..)
678
- | ty:: Coroutine ( ..)
679
- | ty:: CoroutineWitness ( ..)
680
- | ty:: Never
681
- | ty:: Param ( ..)
682
- | ty:: Bound ( ..)
683
- | ty:: Placeholder ( ..)
684
- | ty:: Infer ( ..)
685
- | ty:: Error ( ..) => ( ) ,
632
+ if !additional_tf. is_empty ( ) && codegen_fn_attrs. inline == InlineAttr :: Always {
633
+ tcx. dcx ( ) . span_err (
634
+ tcx. hir ( ) . span ( tcx. local_def_id_to_hir_id ( did) ) ,
635
+ "cannot use a struct with target features in a #[inline(always)] function" ,
636
+ ) ;
686
637
}
638
+ codegen_fn_attrs
639
+ . target_features
640
+ . extend ( additional_tf. iter ( ) . map ( |tf| TargetFeature { implied : true , ..* tf } ) ) ;
687
641
}
688
-
689
- // FIXME(struct_target_features): is this really necessary?
690
- if !additional_tf. is_empty ( ) && sig. skip_binder ( ) . abi ( ) != abi:: Abi :: Rust {
691
- tcx. dcx ( ) . span_err (
692
- tcx. hir ( ) . span ( tcx. local_def_id_to_hir_id ( did) ) ,
693
- "cannot use a struct with target features in a function with non-Rust ABI" ,
694
- ) ;
695
- }
696
- if !additional_tf. is_empty ( ) && codegen_fn_attrs. inline == InlineAttr :: Always {
697
- tcx. dcx ( ) . span_err (
698
- tcx. hir ( ) . span ( tcx. local_def_id_to_hir_id ( did) ) ,
699
- "cannot use a struct with target features in a #[inline(always)] function" ,
700
- ) ;
701
- }
702
- codegen_fn_attrs
703
- . target_features
704
- . extend ( additional_tf. iter ( ) . map ( |tf| TargetFeature { implied : true , ..* tf } ) ) ;
705
642
}
706
643
707
644
// If a function uses non-default target_features it can't be inlined into general
@@ -858,11 +795,82 @@ fn struct_target_features(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &[TargetFeatur
858
795
tcx. arena . alloc_slice ( & features)
859
796
}
860
797
798
+ fn struct_reachable_target_features < ' tcx > (
799
+ tcx : TyCtxt < ' tcx > ,
800
+ env : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
801
+ ) -> & ' tcx [ TargetFeature ] {
802
+ // Collect target features from types reachable from `env.value`.
803
+ // We define a type as "reachable" if:
804
+ // - it is a function argument
805
+ // - it is a field of a reachable struct
806
+ // - there is a reachable reference to it
807
+ let mut visited_types = FxHashSet :: default ( ) ;
808
+ let mut reachable_types = vec ! [ env. value] ;
809
+ let mut reachable_tf = vec ! [ ] ;
810
+
811
+ while let Some ( ty) = reachable_types. pop ( ) {
812
+ if visited_types. contains ( & ty) {
813
+ continue ;
814
+ }
815
+ visited_types. insert ( ty) ;
816
+ match ty. kind ( ) {
817
+ ty:: Alias ( ..) => {
818
+ if let Ok ( t) = tcx. try_normalize_erasing_regions ( env. param_env , ty) {
819
+ reachable_types. push ( t)
820
+ }
821
+ }
822
+
823
+ ty:: Ref ( _, inner, _) => reachable_types. push ( * inner) ,
824
+ ty:: Tuple ( tys) => reachable_types. extend ( tys. iter ( ) ) ,
825
+ ty:: Adt ( adt_def, args) => {
826
+ reachable_tf. extend_from_slice ( tcx. struct_target_features ( adt_def. did ( ) ) ) ;
827
+ // This only recurses into structs as i.e. an Option<TargetFeature> is an ADT
828
+ // that doesn't actually always contain a TargetFeature.
829
+ if adt_def. is_struct ( ) {
830
+ reachable_types. extend (
831
+ adt_def
832
+ . variant ( VariantIdx :: from_usize ( 0 ) )
833
+ . fields
834
+ . iter ( )
835
+ . map ( |field| field. ty ( tcx, args) ) ,
836
+ ) ;
837
+ }
838
+ }
839
+ ty:: Bool
840
+ | ty:: Char
841
+ | ty:: Int ( ..)
842
+ | ty:: Uint ( ..)
843
+ | ty:: Float ( ..)
844
+ | ty:: Foreign ( ..)
845
+ | ty:: Str
846
+ | ty:: Array ( ..)
847
+ | ty:: Pat ( ..)
848
+ | ty:: Slice ( ..)
849
+ | ty:: RawPtr ( ..)
850
+ | ty:: FnDef ( ..)
851
+ | ty:: FnPtr ( ..)
852
+ | ty:: Dynamic ( ..)
853
+ | ty:: Closure ( ..)
854
+ | ty:: CoroutineClosure ( ..)
855
+ | ty:: Coroutine ( ..)
856
+ | ty:: CoroutineWitness ( ..)
857
+ | ty:: Never
858
+ | ty:: Param ( ..)
859
+ | ty:: Bound ( ..)
860
+ | ty:: Placeholder ( ..)
861
+ | ty:: Infer ( ..)
862
+ | ty:: Error ( ..) => ( ) ,
863
+ }
864
+ }
865
+ tcx. arena . alloc_slice ( & reachable_tf)
866
+ }
867
+
861
868
pub fn provide ( providers : & mut Providers ) {
862
869
* providers = Providers {
863
870
codegen_fn_attrs,
864
871
should_inherit_track_caller,
865
872
struct_target_features,
873
+ struct_reachable_target_features,
866
874
..* providers
867
875
} ;
868
876
}
0 commit comments