about summary refs log tree commit diff
path: root/compiler/rustc_feature/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-10-23 12:16:41 +0000
committerbors <bors@rust-lang.org>2024-10-23 12:16:41 +0000
commitbe01dabfefd2daa4574b974f571c7852085d60cb (patch)
treef8efa24426133446fa9c3a55be505d55e3045a5b /compiler/rustc_feature/src
parentffd978b7bf4ccdc74fe6c1b048d253eb3f3aa341 (diff)
parent44638853f545632c68d9a85f85df3418ae09f248 (diff)
downloadrust-be01dabfefd2daa4574b974f571c7852085d60cb.tar.gz
rust-be01dabfefd2daa4574b974f571c7852085d60cb.zip
Auto merge of #132027 - RalfJung:lang-feature-bool-fields, r=nnethercote
nightly feature tracking: get rid of the per-feature bool fields

The `struct Features` that tracks which features are enabled has a ton of public `bool`-typed fields that are basically caching the result of looking up the corresponding feature in `enabled_lang_features`. Having public fields with an invariant is not great, so at least they should be made private. However, it turns out caching these lookups is actually [not worth it](https://github.com/rust-lang/rust/pull/131321#issuecomment-2402068336), so this PR just entirely gets rid of these fields. (The alternative would be to make them private and have a method for each of them to expose them in a read-only way. Most of the diff of this PR would be the same in that case.)

r? `@nnethercote`
Diffstat (limited to 'compiler/rustc_feature/src')
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs48
-rw-r--r--compiler/rustc_feature/src/lib.rs14
-rw-r--r--compiler/rustc_feature/src/removed.rs2
-rw-r--r--compiler/rustc_feature/src/unstable.rs154
5 files changed, 88 insertions, 132 deletions
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 53445804694..4f71bdaca1b 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -9,7 +9,7 @@ macro_rules! declare_features {
         $(#[doc = $doc:tt])* (accepted, $feature:ident, $ver:expr, $issue:expr),
     )+) => {
         /// Formerly unstable features that have now been accepted (stabilized).
-        pub const ACCEPTED_FEATURES: &[Feature] = &[
+        pub const ACCEPTED_LANG_FEATURES: &[Feature] = &[
             $(Feature {
                 name: sym::$feature,
                 since: $ver,
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 477760a4597..753195bf691 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -12,33 +12,31 @@ use crate::{Features, Stability};
 
 type GateFn = fn(&Features) -> bool;
 
-macro_rules! cfg_fn {
-    ($field: ident) => {
-        (|features| features.$field) as GateFn
-    };
-}
-
 pub type GatedCfg = (Symbol, Symbol, GateFn);
 
 /// `cfg(...)`'s that are feature gated.
 const GATED_CFGS: &[GatedCfg] = &[
     // (name in cfg, feature, function to check if the feature is enabled)
-    (sym::overflow_checks, sym::cfg_overflow_checks, cfg_fn!(cfg_overflow_checks)),
-    (sym::ub_checks, sym::cfg_ub_checks, cfg_fn!(cfg_ub_checks)),
-    (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)),
+    (sym::overflow_checks, sym::cfg_overflow_checks, Features::cfg_overflow_checks),
+    (sym::ub_checks, sym::cfg_ub_checks, Features::cfg_ub_checks),
+    (sym::target_thread_local, sym::cfg_target_thread_local, Features::cfg_target_thread_local),
     (
         sym::target_has_atomic_equal_alignment,
         sym::cfg_target_has_atomic_equal_alignment,
-        cfg_fn!(cfg_target_has_atomic_equal_alignment),
-    ),
-    (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
-    (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)),
-    (sym::version, sym::cfg_version, cfg_fn!(cfg_version)),
-    (sym::relocation_model, sym::cfg_relocation_model, cfg_fn!(cfg_relocation_model)),
-    (sym::sanitizer_cfi_generalize_pointers, sym::cfg_sanitizer_cfi, cfg_fn!(cfg_sanitizer_cfi)),
-    (sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, cfg_fn!(cfg_sanitizer_cfi)),
+        Features::cfg_target_has_atomic_equal_alignment,
+    ),
+    (
+        sym::target_has_atomic_load_store,
+        sym::cfg_target_has_atomic,
+        Features::cfg_target_has_atomic,
+    ),
+    (sym::sanitize, sym::cfg_sanitize, Features::cfg_sanitize),
+    (sym::version, sym::cfg_version, Features::cfg_version),
+    (sym::relocation_model, sym::cfg_relocation_model, Features::cfg_relocation_model),
+    (sym::sanitizer_cfi_generalize_pointers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi),
+    (sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi),
     // this is consistent with naming of the compiler flag it's for
-    (sym::fmt_debug, sym::fmt_debug, cfg_fn!(fmt_debug)),
+    (sym::fmt_debug, sym::fmt_debug, Features::fmt_debug),
 ];
 
 /// Find a gated cfg determined by the `pred`icate which is given the cfg's name.
@@ -220,7 +218,7 @@ macro_rules! gated {
             safety: AttributeSafety::Unsafe,
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
+            gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
         }
     };
     (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
@@ -231,7 +229,7 @@ macro_rules! gated {
             safety: AttributeSafety::Unsafe,
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)),
+            gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
         }
     };
     ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
@@ -242,7 +240,7 @@ macro_rules! gated {
             safety: AttributeSafety::Normal,
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::$gate, $msg, cfg_fn!($gate)),
+            gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
         }
     };
     ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
@@ -253,7 +251,7 @@ macro_rules! gated {
             safety: AttributeSafety::Normal,
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::$attr, $msg, cfg_fn!($attr)),
+            gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
         }
     };
 }
@@ -282,7 +280,7 @@ macro_rules! rustc_attr {
             safety: AttributeSafety::Normal,
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, cfg_fn!(rustc_attrs)),
+            gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, Features::rustc_attrs),
         }
     };
 }
@@ -935,7 +933,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
             Stability::Unstable,
             sym::rustc_attrs,
             "diagnostic items compiler internal support for linting",
-            cfg_fn!(rustc_attrs),
+            Features::rustc_attrs,
         ),
     },
     gated!(
@@ -1193,7 +1191,7 @@ pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>>
 pub fn is_stable_diagnostic_attribute(sym: Symbol, features: &Features) -> bool {
     match sym {
         sym::on_unimplemented => true,
-        sym::do_not_recommend => features.do_not_recommend,
+        sym::do_not_recommend => features.do_not_recommend(),
         _ => false,
     }
 }
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 8f4c0b0ac95..216793485e5 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -94,13 +94,13 @@ impl UnstableFeatures {
 
 fn find_lang_feature_issue(feature: Symbol) -> Option<NonZero<u32>> {
     // Search in all the feature lists.
-    if let Some(f) = UNSTABLE_FEATURES.iter().find(|f| f.feature.name == feature) {
-        return f.feature.issue;
+    if let Some(f) = UNSTABLE_LANG_FEATURES.iter().find(|f| f.name == feature) {
+        return f.issue;
     }
-    if let Some(f) = ACCEPTED_FEATURES.iter().find(|f| f.name == feature) {
+    if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| f.name == feature) {
         return f.issue;
     }
-    if let Some(f) = REMOVED_FEATURES.iter().find(|f| f.feature.name == feature) {
+    if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| f.feature.name == feature) {
         return f.feature.issue;
     }
     panic!("feature `{feature}` is not declared anywhere");
@@ -127,12 +127,12 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
     }
 }
 
-pub use accepted::ACCEPTED_FEATURES;
+pub use accepted::ACCEPTED_LANG_FEATURES;
 pub use builtin_attrs::{
     AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,
     BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, deprecated_attributes,
     encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute,
     is_valid_for_get_attr,
 };
-pub use removed::REMOVED_FEATURES;
-pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_FEATURES};
+pub use removed::REMOVED_LANG_FEATURES;
+pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_LANG_FEATURES};
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index d797fee000d..fe3a67fd667 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -14,7 +14,7 @@ macro_rules! declare_features {
         $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, $reason:expr),
     )+) => {
         /// Formerly unstable features that have now been removed.
-        pub const REMOVED_FEATURES: &[RemovedFeature] = &[
+        pub const REMOVED_LANG_FEATURES: &[RemovedFeature] = &[
             $(RemovedFeature {
                 feature: Feature {
                     name: sym::$feature,
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 0606f2914c3..8f4c208f1fb 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -6,11 +6,6 @@ use rustc_span::symbol::{Symbol, sym};
 
 use super::{Feature, to_nonzero};
 
-pub struct UnstableFeature {
-    pub feature: Feature,
-    set_enabled: fn(&mut Features),
-}
-
 #[derive(PartialEq)]
 enum FeatureStatus {
     Default,
@@ -30,110 +25,73 @@ macro_rules! status_to_enum {
     };
 }
 
+/// A set of features to be used by later passes.
+///
+/// There are two ways to check if a language feature `foo` is enabled:
+/// - Directly with the `foo` method, e.g. `if tcx.features().foo() { ... }`.
+/// - With the `enabled` method, e.g. `if tcx.features.enabled(sym::foo) { ... }`.
+///
+/// The former is preferred. `enabled` should only be used when the feature symbol is not a
+/// constant, e.g. a parameter, or when the feature is a library feature.
+#[derive(Clone, Default, Debug)]
+pub struct Features {
+    /// `#![feature]` attrs for language features, for error reporting.
+    enabled_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
+    /// `#![feature]` attrs for non-language (library) features.
+    enabled_lib_features: Vec<(Symbol, Span)>,
+    /// `enabled_lang_features` + `enabled_lib_features`.
+    enabled_features: FxHashSet<Symbol>,
+}
+
+impl Features {
+    pub fn set_enabled_lang_feature(&mut self, name: Symbol, span: Span, since: Option<Symbol>) {
+        self.enabled_lang_features.push((name, span, since));
+        self.enabled_features.insert(name);
+    }
+
+    pub fn set_enabled_lib_feature(&mut self, name: Symbol, span: Span) {
+        self.enabled_lib_features.push((name, span));
+        self.enabled_features.insert(name);
+    }
+
+    pub fn enabled_lang_features(&self) -> &Vec<(Symbol, Span, Option<Symbol>)> {
+        &self.enabled_lang_features
+    }
+
+    pub fn enabled_lib_features(&self) -> &Vec<(Symbol, Span)> {
+        &self.enabled_lib_features
+    }
+
+    pub fn enabled_features(&self) -> &FxHashSet<Symbol> {
+        &self.enabled_features
+    }
+
+    /// Is the given feature enabled (via `#[feature(...)]`)?
+    pub fn enabled(&self, feature: Symbol) -> bool {
+        self.enabled_features.contains(&feature)
+    }
+}
+
 macro_rules! declare_features {
     ($(
         $(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr),
     )+) => {
         /// Unstable language features that are being implemented or being
         /// considered for acceptance (stabilization) or removal.
-        pub const UNSTABLE_FEATURES: &[UnstableFeature] = &[
-            $(UnstableFeature {
-                feature: Feature {
-                    name: sym::$feature,
-                    since: $ver,
-                    issue: to_nonzero($issue),
-                },
-                // Sets this feature's corresponding bool within `features`.
-                set_enabled: |features| features.$feature = true,
+        pub const UNSTABLE_LANG_FEATURES: &[Feature] = &[
+            $(Feature {
+                name: sym::$feature,
+                since: $ver,
+                issue: to_nonzero($issue),
             }),+
         ];
 
-        const NUM_FEATURES: usize = UNSTABLE_FEATURES.len();
-
-        /// A set of features to be used by later passes.
-        #[derive(Clone, Default, Debug)]
-        pub struct Features {
-            /// `#![feature]` attrs for language features, for error reporting.
-            enabled_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
-            /// `#![feature]` attrs for non-language (library) features.
-            enabled_lib_features: Vec<(Symbol, Span)>,
-            /// `enabled_lang_features` + `enabled_lib_features`.
-            enabled_features: FxHashSet<Symbol>,
-            /// State of individual features (unstable lang features only).
-            /// This is `true` if and only if the corresponding feature is listed in `enabled_lang_features`.
-            $(
-                $(#[doc = $doc])*
-                pub $feature: bool
-            ),+
-        }
-
         impl Features {
-            pub fn set_enabled_lang_feature(
-                &mut self,
-                name: Symbol,
-                span: Span,
-                since: Option<Symbol>,
-                feature: Option<&UnstableFeature>,
-            ) {
-                self.enabled_lang_features.push((name, span, since));
-                self.enabled_features.insert(name);
-                if let Some(feature) = feature {
-                    assert_eq!(feature.feature.name, name);
-                    (feature.set_enabled)(self);
-                } else {
-                    // Ensure we don't skip a `set_enabled` call.
-                    debug_assert!(UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name).is_none());
-                }
-            }
-
-            pub fn set_enabled_lib_feature(&mut self, name: Symbol, span: Span) {
-                self.enabled_lib_features.push((name, span));
-                self.enabled_features.insert(name);
-                // Ensure we don't skip a `set_enabled` call.
-                debug_assert!(UNSTABLE_FEATURES.iter().find(|f| name == f.feature.name).is_none());
-            }
-
-            /// This is intended for hashing the set of enabled language features.
-            ///
-            /// The expectation is that this produces much smaller code than other alternatives.
-            ///
-            /// Note that the total feature count is pretty small, so this is not a huge array.
-            #[inline]
-            pub fn all_lang_features(&self) -> [u8; NUM_FEATURES] {
-                [$(self.$feature as u8),+]
-            }
-
-            pub fn enabled_lang_features(&self) -> &Vec<(Symbol, Span, Option<Symbol>)> {
-                &self.enabled_lang_features
-            }
-
-            pub fn enabled_lib_features(&self) -> &Vec<(Symbol, Span)> {
-                &self.enabled_lib_features
-            }
-
-            pub fn enabled_features(&self) -> &FxHashSet<Symbol> {
-                &self.enabled_features
-            }
-
-            /// Is the given feature enabled (via `#[feature(...)]`)?
-            pub fn enabled(&self, feature: Symbol) -> bool {
-                let e = self.enabled_features.contains(&feature);
-                if cfg!(debug_assertions) {
-                    // Ensure this matches `self.$feature`, if that exists.
-                    let e2 = match feature {
-                        $( sym::$feature => Some(self.$feature), )*
-                        _ => None,
-                    };
-                    if let Some(e2) = e2 {
-                        assert_eq!(
-                            e, e2,
-                            "mismatch in feature state for `{feature}`: \
-                            `enabled_features` says {e} but `self.{feature}` says {e2}"
-                        );
-                    }
+            $(
+                pub fn $feature(&self) -> bool {
+                    self.enabled_features.contains(&sym::$feature)
                 }
-                e
-            }
+            )*
 
             /// Some features are known to be incomplete and using them is likely to have
             /// unanticipated results, such as compiler crashes. We warn the user about these