1
1
use rustc_ast:: { MetaItemKind , NestedMetaItem , ast, attr} ;
2
2
use rustc_attr:: { InlineAttr , InstructionSetAttr , OptimizeAttr , list_contains_name} ;
3
+ use rustc_data_structures:: fx:: FxHashMap ;
3
4
use rustc_errors:: codes:: * ;
4
5
use rustc_errors:: { DiagMessage , SubdiagMessage , struct_span_code_err} ;
5
6
use rustc_hir as hir;
@@ -13,13 +14,13 @@ use rustc_middle::middle::codegen_fn_attrs::{
13
14
use rustc_middle:: mir:: mono:: Linkage ;
14
15
use rustc_middle:: query:: Providers ;
15
16
use rustc_middle:: ty:: { self as ty, TyCtxt } ;
16
- use rustc_session:: lint;
17
17
use rustc_session:: parse:: feature_err;
18
+ use rustc_session:: { Session , lint} ;
18
19
use rustc_span:: symbol:: Ident ;
19
20
use rustc_span:: { Span , sym} ;
20
21
use rustc_target:: spec:: { SanitizerSet , abi} ;
21
22
22
- use crate :: errors;
23
+ use crate :: errors:: { self , MissingFeatures , TargetFeatureDisableOrEnable } ;
23
24
use crate :: target_features:: { check_target_feature_trait_unsafe, from_target_feature} ;
24
25
25
26
fn linkage_by_name ( tcx : TyCtxt < ' _ > , def_id : LocalDefId , name : & str ) -> Linkage {
@@ -662,9 +663,49 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
662
663
}
663
664
}
664
665
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
+
665
687
codegen_fn_attrs
666
688
}
667
689
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
+
668
709
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
669
710
/// applied to the method prototype.
670
711
fn should_inherit_track_caller ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
0 commit comments