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,47 @@ 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 =
693+ tcx. get_attr ( did, sym:: target_feature) . map_or_else ( || tcx. def_span ( did) , |a| a. span ) ;
694+ tcx. dcx ( )
695+ . create_err ( TargetFeatureDisableOrEnable {
696+ features,
697+ span : Some ( span) ,
698+ missing_features : Some ( MissingFeatures ) ,
699+ } )
700+ . emit ( ) ;
701+ }
702+
683703 codegen_fn_attrs
684704}
685705
706+ /// Given a map from target_features to whether they are enabled or disabled, ensure only valid
707+ /// combinations are allowed.
708+ pub fn check_tied_features (
709+ sess : & Session ,
710+ features : & FxHashMap < & str , bool > ,
711+ ) -> Option < & ' static [ & ' static str ] > {
712+ if !features. is_empty ( ) {
713+ for tied in sess. target . tied_target_features ( ) {
714+ // Tied features must be set to the same value, or not set at all
715+ let mut tied_iter = tied. iter ( ) ;
716+ let enabled = features. get ( tied_iter. next ( ) . unwrap ( ) ) ;
717+ if tied_iter. any ( |f| enabled != features. get ( f) ) {
718+ return Some ( tied) ;
719+ }
720+ }
721+ }
722+ None
723+ }
724+
686725/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
687726/// applied to the method prototype.
688727fn should_inherit_track_caller ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
0 commit comments