11use rustc_ast:: { MetaItemKind , NestedMetaItem , ast, attr} ;
22use rustc_attr:: { InlineAttr , InstructionSetAttr , OptimizeAttr , list_contains_name} ;
3+ use rustc_data_structures:: fx:: FxHashMap ;
34use rustc_errors:: codes:: * ;
45use rustc_errors:: { DiagMessage , SubdiagMessage , struct_span_code_err} ;
56use rustc_hir as hir;
@@ -13,13 +14,13 @@ use rustc_middle::middle::codegen_fn_attrs::{
1314use rustc_middle:: mir:: mono:: Linkage ;
1415use rustc_middle:: query:: Providers ;
1516use rustc_middle:: ty:: { self as ty, TyCtxt } ;
16- use rustc_session:: lint;
1717use rustc_session:: parse:: feature_err;
18+ use rustc_session:: { Session , lint} ;
1819use rustc_span:: symbol:: Ident ;
1920use rustc_span:: { Span , sym} ;
2021use rustc_target:: spec:: { SanitizerSet , abi} ;
2122
22- use crate :: errors;
23+ use crate :: errors:: { self , MissingFeatures , TargetFeatureDisableOrEnable } ;
2324use crate :: target_features:: { check_target_feature_trait_unsafe, from_target_feature} ;
2425
2526fn linkage_by_name ( tcx : TyCtxt < ' _ > , def_id : LocalDefId , name : & str ) -> Linkage {
@@ -662,9 +663,49 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
662663 }
663664 }
664665
666+ if let Some ( features) = check_tied_features (
667+ tcx. sess ,
668+ & codegen_fn_attrs
669+ . target_features
670+ . iter ( )
671+ . map ( |features| ( features. name . as_str ( ) , true ) )
672+ . collect ( ) ,
673+ ) {
674+ let span = tcx
675+ . get_attrs ( did, sym:: target_feature)
676+ . next ( )
677+ . map_or_else ( || tcx. def_span ( did) , |a| a. span ) ;
678+ tcx. dcx ( )
679+ . create_err ( TargetFeatureDisableOrEnable {
680+ features,
681+ span : Some ( span) ,
682+ missing_features : Some ( MissingFeatures ) ,
683+ } )
684+ . emit ( ) ;
685+ }
686+
665687 codegen_fn_attrs
666688}
667689
690+ /// Given a map from target_features to whether they are enabled or disabled, ensure only valid
691+ /// combinations are allowed.
692+ pub fn check_tied_features (
693+ sess : & Session ,
694+ features : & FxHashMap < & str , bool > ,
695+ ) -> Option < & ' static [ & ' static str ] > {
696+ if !features. is_empty ( ) {
697+ for tied in sess. target . tied_target_features ( ) {
698+ // Tied features must be set to the same value, or not set at all
699+ let mut tied_iter = tied. iter ( ) ;
700+ let enabled = features. get ( tied_iter. next ( ) . unwrap ( ) ) ;
701+ if tied_iter. any ( |f| enabled != features. get ( f) ) {
702+ return Some ( tied) ;
703+ }
704+ }
705+ }
706+ None
707+ }
708+
668709/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
669710/// applied to the method prototype.
670711fn should_inherit_track_caller ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
0 commit comments