@@ -16,12 +16,12 @@ use rustc_session::Session;
16
16
use rustc_session:: config:: { PrintKind , PrintRequest } ;
17
17
use rustc_span:: symbol:: Symbol ;
18
18
use 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 } ;
20
20
21
21
use crate :: back:: write:: create_informational_target_machine;
22
22
use crate :: errors:: {
23
- FixedX18InvalidArch , InvalidTargetFeaturePrefix , PossibleFeature , UnknownCTargetFeature ,
24
- UnknownCTargetFeaturePrefix , UnstableCTargetFeature ,
23
+ FixedX18InvalidArch , ForbiddenCTargetFeature , InvalidTargetFeaturePrefix , PossibleFeature ,
24
+ UnknownCTargetFeature , UnknownCTargetFeaturePrefix , UnstableCTargetFeature ,
25
25
} ;
26
26
use crate :: llvm;
27
27
@@ -280,19 +280,29 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
280
280
}
281
281
}
282
282
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.
285
287
pub 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.
289
296
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.
290
299
features. extend (
291
300
sess. target
292
- . supported_target_features ( )
301
+ . rust_target_features ( )
293
302
. iter ( )
303
+ . filter ( |( _, gate, _) | gate. is_supported ( ) )
294
304
. filter ( |( feature, _, _) | {
295
- // skip checking special features, as LLVM may not understands them
305
+ // skip checking special features, as LLVM may not understand them
296
306
if RUSTC_SPECIAL_FEATURES . contains ( feature) {
297
307
return true ;
298
308
}
@@ -323,16 +333,22 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> {
323
333
if enabled {
324
334
features. extend ( sess. target . implied_target_features ( std:: iter:: once ( feature) ) ) ;
325
335
} 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) ]
326
339
features. retain ( |f| {
340
+ // Keep a feature if it does not imply `feature`. Or, equivalently,
341
+ // remove the reverse-dependencies of `feature`.
327
342
!sess. target . implied_target_features ( std:: iter:: once ( * f) ) . contains ( & feature)
328
343
} ) ;
329
344
}
330
345
}
331
346
332
347
// Filter enabled features based on feature gates
333
348
sess. target
334
- . supported_target_features ( )
349
+ . rust_target_features ( )
335
350
. iter ( )
351
+ . filter ( |( _, gate, _) | gate. is_supported ( ) )
336
352
. filter_map ( |& ( feature, gate, _) | {
337
353
if sess. is_nightly_build ( ) || allow_unstable || gate. is_stable ( ) {
338
354
Some ( feature)
@@ -392,9 +408,13 @@ fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMach
392
408
let mut known_llvm_target_features = FxHashSet :: < & ' static str > :: default ( ) ;
393
409
let mut rustc_target_features = sess
394
410
. target
395
- . supported_target_features ( )
411
+ . rust_target_features ( )
396
412
. 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
+ }
398
418
// LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these
399
419
// strings.
400
420
let llvm_feature = to_llvm_features ( sess, * feature) ?. llvm_feature_name ;
@@ -567,7 +587,7 @@ pub(crate) fn global_llvm_features(
567
587
568
588
// -Ctarget-features
569
589
if !only_base_features {
570
- let supported_features = sess. target . supported_target_features ( ) ;
590
+ let known_features = sess. target . rust_target_features ( ) ;
571
591
let mut featsmap = FxHashMap :: default ( ) ;
572
592
573
593
// insert implied features
@@ -601,50 +621,53 @@ pub(crate) fn global_llvm_features(
601
621
}
602
622
} ;
603
623
624
+ // Get the backend feature name, if any.
625
+ // This excludes rustc-specific features, which do not get passed to LLVM.
604
626
let feature = backend_feature_name ( sess, s) ?;
605
627
// Warn against use of LLVM specific feature names and unstable features on the CLI.
606
628
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 } ,
618
647
}
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
+ }
634
664
}
635
- }
636
665
637
- if diagnostics {
638
666
// FIXME(nagisa): figure out how to not allocate a full hashset here.
639
667
featsmap. insert ( feature, enable_disable == '+' ) ;
640
668
}
641
669
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
648
671
// passing requests down to LLVM. This means that all in-language
649
672
// features also work on the command line instead of having two
650
673
// different names when the LLVM name and the Rust name differ.
0 commit comments