@@ -16,12 +16,12 @@ use rustc_session::Session;
1616use rustc_session:: config:: { PrintKind , PrintRequest } ;
1717use rustc_span:: symbol:: Symbol ;
1818use rustc_target:: spec:: { MergeFunctions , PanicStrategy , SmallDataThresholdSupport } ;
19- use rustc_target:: target_features:: { RUSTC_SPECIAL_FEATURES , RUSTC_SPECIFIC_FEATURES } ;
19+ use rustc_target:: target_features:: { RUSTC_SPECIAL_FEATURES , RUSTC_SPECIFIC_FEATURES , Stability } ;
2020
2121use crate :: back:: write:: create_informational_target_machine;
2222use crate :: errors:: {
23- FixedX18InvalidArch , InvalidTargetFeaturePrefix , PossibleFeature , UnknownCTargetFeature ,
24- UnknownCTargetFeaturePrefix , UnstableCTargetFeature ,
23+ FixedX18InvalidArch , ForbiddenCTargetFeature , InvalidTargetFeaturePrefix , PossibleFeature ,
24+ UnknownCTargetFeature , UnknownCTargetFeaturePrefix , UnstableCTargetFeature ,
2525} ;
2626use crate :: llvm;
2727
@@ -280,19 +280,29 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
280280 }
281281}
282282
283- /// Used to generate cfg variables and apply features
284- /// Must express features in the way Rust understands them
283+ /// Used to generate cfg variables and apply features.
284+ /// Must express features in the way Rust understands them.
285+ ///
286+ /// We do not have to worry about RUSTC_SPECIFIC_FEATURES here, those are handled outside codegen.
285287pub fn target_features ( sess : & Session , allow_unstable : bool ) -> Vec < Symbol > {
286- let mut features = vec ! [ ] ;
287-
288- // Add base features for the target
288+ let mut features: FxHashSet < Symbol > = Default :: default ( ) ;
289+
290+ // Add base features for the target.
291+ // We do *not* add the -Ctarget-features there, and instead duplicate the logic for that below.
292+ // The reason is that if LLVM considers a feature implied but we do not, we don't want that to
293+ // show up in `cfg`. That way, `cfg` is entirely under our control -- except for the handling of
294+ // the target CPU, that is still expanded to target features (with all their implied features) by
295+ // LLVM.
289296 let target_machine = create_informational_target_machine ( sess, true ) ;
297+ // Compute which of the known target features are enabled in the 'base' target machine.
298+ // We only consider "supported" features; "forbidden" features are not reflected in `cfg` as of now.
290299 features. extend (
291300 sess. target
292- . supported_target_features ( )
301+ . rust_target_features ( )
293302 . iter ( )
303+ . filter ( |( _, gate, _) | gate. is_supported ( ) )
294304 . filter ( |( feature, _, _) | {
295- // skip checking special features, as LLVM may not understands them
305+ // skip checking special features, as LLVM may not understand them
296306 if RUSTC_SPECIAL_FEATURES . contains ( feature) {
297307 return true ;
298308 }
@@ -323,16 +333,22 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
323333 if enabled {
324334 features. extend ( sess. target . implied_target_features ( std:: iter:: once ( feature) ) ) ;
325335 } else {
336+ // We don't care about the order in `features` since the only thing we use it for is the
337+ // `features.contains` below.
338+ #[ allow( rustc:: potential_query_instability) ]
326339 features. retain ( |f| {
340+ // Keep a feature if it does not imply `feature`. Or, equivalently,
341+ // remove the reverse-dependencies of `feature`.
327342 !sess. target . implied_target_features ( std:: iter:: once ( * f) ) . contains ( & feature)
328343 } ) ;
329344 }
330345 }
331346
332347 // Filter enabled features based on feature gates
333348 sess. target
334- . supported_target_features ( )
349+ . rust_target_features ( )
335350 . iter ( )
351+ . filter ( |( _, gate, _) | gate. is_supported ( ) )
336352 . filter_map ( |& ( feature, gate, _) | {
337353 if sess. is_nightly_build ( ) || allow_unstable || gate. is_stable ( ) {
338354 Some ( feature)
@@ -392,9 +408,13 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
392408 let mut known_llvm_target_features = FxHashSet :: < & ' static str > :: default ( ) ;
393409 let mut rustc_target_features = sess
394410 . target
395- . supported_target_features ( )
411+ . rust_target_features ( )
396412 . iter ( )
397- . filter_map ( |( feature, _gate, _implied) | {
413+ . filter_map ( |( feature, gate, _implied) | {
414+ if !gate. is_supported ( ) {
415+ // Only list (experimentally) supported features.
416+ return None ;
417+ }
398418 // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these
399419 // strings.
400420 let llvm_feature = to_llvm_features ( sess, * feature) ?. llvm_feature_name ;
@@ -567,7 +587,7 @@ pub(crate) fn global_llvm_features(
567587
568588 // -Ctarget-features
569589 if !only_base_features {
570- let supported_features = sess. target . supported_target_features ( ) ;
590+ let known_features = sess. target . rust_target_features ( ) ;
571591 let mut featsmap = FxHashMap :: default ( ) ;
572592
573593 // insert implied features
@@ -601,50 +621,53 @@ pub(crate) fn global_llvm_features(
601621 }
602622 } ;
603623
624+ // Get the backend feature name, if any.
625+ // This excludes rustc-specific features, which do not get passed to LLVM.
604626 let feature = backend_feature_name ( sess, s) ?;
605627 // Warn against use of LLVM specific feature names and unstable features on the CLI.
606628 if diagnostics {
607- let feature_state = supported_features. iter ( ) . find ( |& & ( v, _, _) | v == feature) ;
608- if feature_state. is_none ( ) {
609- let rust_feature =
610- supported_features. iter ( ) . find_map ( |& ( rust_feature, _, _) | {
611- let llvm_features = to_llvm_features ( sess, rust_feature) ?;
612- if llvm_features. contains ( feature)
613- && !llvm_features. contains ( rust_feature)
614- {
615- Some ( rust_feature)
616- } else {
617- None
629+ let feature_state = known_features. iter ( ) . find ( |& & ( v, _, _) | v == feature) ;
630+ match feature_state {
631+ None => {
632+ let rust_feature =
633+ known_features. iter ( ) . find_map ( |& ( rust_feature, _, _) | {
634+ let llvm_features = to_llvm_features ( sess, rust_feature) ?;
635+ if llvm_features. contains ( feature)
636+ && !llvm_features. contains ( rust_feature)
637+ {
638+ Some ( rust_feature)
639+ } else {
640+ None
641+ }
642+ } ) ;
643+ let unknown_feature = if let Some ( rust_feature) = rust_feature {
644+ UnknownCTargetFeature {
645+ feature,
646+ rust_feature : PossibleFeature :: Some { rust_feature } ,
618647 }
619- } ) ;
620- let unknown_feature = if let Some ( rust_feature) = rust_feature {
621- UnknownCTargetFeature {
622- feature,
623- rust_feature : PossibleFeature :: Some { rust_feature } ,
624- }
625- } else {
626- UnknownCTargetFeature { feature, rust_feature : PossibleFeature :: None }
627- } ;
628- sess. dcx ( ) . emit_warn ( unknown_feature) ;
629- } else if feature_state
630- . is_some_and ( |( _name, feature_gate, _implied) | !feature_gate. is_stable ( ) )
631- {
632- // An unstable feature. Warn about using it.
633- sess. dcx ( ) . emit_warn ( UnstableCTargetFeature { feature } ) ;
648+ } else {
649+ UnknownCTargetFeature {
650+ feature,
651+ rust_feature : PossibleFeature :: None ,
652+ }
653+ } ;
654+ sess. dcx ( ) . emit_warn ( unknown_feature) ;
655+ }
656+ Some ( ( _, Stability :: Stable , _) ) => { }
657+ Some ( ( _, Stability :: Unstable ( _) , _) ) => {
658+ // An unstable feature. Warn about using it.
659+ sess. dcx ( ) . emit_warn ( UnstableCTargetFeature { feature } ) ;
660+ }
661+ Some ( ( _, Stability :: Forbidden { reason } , _) ) => {
662+ sess. dcx ( ) . emit_warn ( ForbiddenCTargetFeature { feature, reason } ) ;
663+ }
634664 }
635- }
636665
637- if diagnostics {
638666 // FIXME(nagisa): figure out how to not allocate a full hashset here.
639667 featsmap. insert ( feature, enable_disable == '+' ) ;
640668 }
641669
642- // rustc-specific features do not get passed down to LLVM…
643- if RUSTC_SPECIFIC_FEATURES . contains ( & feature) {
644- return None ;
645- }
646-
647- // ... otherwise though we run through `to_llvm_features` when
670+ // We run through `to_llvm_features` when
648671 // passing requests down to LLVM. This means that all in-language
649672 // features also work on the command line instead of having two
650673 // different names when the LLVM name and the Rust name differ.
0 commit comments