1
1
use rustc_ast:: { ast, attr, MetaItemKind , NestedMetaItem } ;
2
2
use rustc_attr:: { list_contains_name, InlineAttr , InstructionSetAttr , OptimizeAttr } ;
3
+ use rustc_data_structures:: fx:: FxHashMap ;
3
4
use rustc_errors:: codes:: * ;
4
5
use rustc_errors:: { struct_span_code_err, DiagMessage , SubdiagMessage } ;
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:: { lint, Session } ;
18
19
use rustc_span:: symbol:: Ident ;
19
20
use rustc_span:: { sym, Span } ;
20
21
use rustc_target:: spec:: { abi, SanitizerSet } ;
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 {
@@ -680,9 +681,47 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
680
681
}
681
682
}
682
683
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
+
683
703
codegen_fn_attrs
684
704
}
685
705
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
+
686
725
/// Checks if the provided DefId is a method in a trait impl for a trait which has track_caller
687
726
/// applied to the method prototype.
688
727
fn should_inherit_track_caller ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> bool {
0 commit comments