11use rustc_ast:: { ast, attr, MetaItemKind , NestedMetaItem } ;
22use rustc_attr:: { list_contains_name, InlineAttr , InstructionSetAttr , OptimizeAttr } ;
3+ use rustc_data_structures:: fx:: FxHashMap ;
34use rustc_errors:: codes:: * ;
45use rustc_errors:: { struct_span_code_err, DiagMessage , SubdiagMessage } ;
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:: { lint, Session } ;
1819use rustc_span:: symbol:: Ident ;
1920use rustc_span:: { sym, Span } ;
2021use rustc_target:: spec:: { abi, SanitizerSet } ;
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 {
@@ -680,9 +681,49 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
680681 }
681682 }
682683
684+ if let Some ( features) = check_tied_features (
685+ tcx. sess ,
686+ & codegen_fn_attrs
687+ . target_features
688+ . iter ( )
689+ . map ( |features| ( features. name . as_str ( ) , true ) )
690+ . collect ( ) ,
691+ ) {
692+ let span = tcx
693+ . get_attrs ( did, sym:: target_feature)
694+ . next ( )
695+ . map_or_else ( || tcx. def_span ( did) , |a| a. span ) ;
696+ tcx. dcx ( )
697+ . create_err ( TargetFeatureDisableOrEnable {
698+ features,
699+ span : Some ( span) ,
700+ missing_features : Some ( MissingFeatures ) ,
701+ } )
702+ . emit ( ) ;
703+ }
704+
683705 codegen_fn_attrs
684706}
685707
708+ /// Given a map from target_features to whether they are enabled or disabled, ensure only valid
709+ /// combinations are allowed.
710+ pub fn check_tied_features (
711+ sess : & Session ,
712+ features : & FxHashMap < & str , bool > ,
713+ ) -> Option < & ' static [ & ' static str ] > {
714+ if !features. is_empty ( ) {
715+ for tied in sess. target . tied_target_features ( ) {
716+ // Tied features must be set to the same value, or not set at all
717+ let mut tied_iter = tied. iter ( ) ;
718+ let enabled = features. get ( tied_iter. next ( ) . unwrap ( ) ) ;
719+ if tied_iter. any ( |f| enabled != features. get ( f) ) {
720+ return Some ( tied) ;
721+ }
722+ }
723+ }
724+ None
725+ }
726+
686727/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
687728/// applied to the method prototype.
688729fn should_inherit_track_caller ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
0 commit comments