diff --git a/Cargo.lock b/Cargo.lock index 7cb05bce70ec4..ce8b4ca03046b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4068,6 +4068,7 @@ name = "rustc_feature" version = "0.0.0" dependencies = [ "rustc_data_structures", + "rustc_macros", "rustc_span", "serde", "serde_json", diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs index d7f2243faaab9..e9ace7088d8f0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs +++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs @@ -436,7 +436,7 @@ fn parse_cfg_attr_internal<'a>( } fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Features>) { - let gate = find_gated_cfg(|sym| sym == name); + let gate = find_gated_cfg(name); if let (Some(feats), Some(gated_cfg)) = (features, gate) { gate_cfg(gated_cfg, span, sess, feats); } diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index e315d6abea395..6cce64d700a63 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -43,7 +43,7 @@ fn check_keyword(cx: &mut AcceptContext<'_, '_>, keyword: Symbol, span: Span) -> fn check_attribute(cx: &mut AcceptContext<'_, '_>, attribute: Symbol, span: Span) -> bool { // FIXME: This should support attributes with namespace like `diagnostic::do_not_recommend`. - if rustc_feature::BUILTIN_ATTRIBUTE_MAP.contains(&attribute) { + if rustc_feature::BUILTIN_ATTRIBUTE_SET.contains(&attribute) { return true; } cx.emit_err(DocAttributeNotAttribute { span, attribute }); diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index aef7dd48ec664..240f437828259 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -10,7 +10,7 @@ use rustc_attr_ir::target::Target; use rustc_attr_ir::{AttrArgs, AttrItem, AttrPath, Attribute, AttributeKind, HashIgnoredAttrId}; use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan}; -use rustc_feature::{BUILTIN_ATTRIBUTE_MAP, Features}; +use rustc_feature::{BUILTIN_ATTRIBUTE_SET, Features}; use rustc_lint_defs::{LintId, RegisteredTools}; use rustc_session::Session; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; @@ -376,7 +376,7 @@ impl<'sess> AttributeParser<'sess> { ); self.check_attribute_stability(&attr_path, attr_span, accept.stability); if let [part] = parts.as_slice() { - debug_assert!(BUILTIN_ATTRIBUTE_MAP.contains(part)); + debug_assert!(BUILTIN_ATTRIBUTE_SET.contains(part)); } let Some(args) = ArgParser::from_attr_args( diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index f225458ebc0e6..4719ee5103877 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -11,7 +11,7 @@ use rustc_ast::{ }; use rustc_attr_ir::AttrPath; use rustc_errors::{Applicability, Diagnostic, PResult}; -use rustc_feature::BUILTIN_ATTRIBUTE_MAP; +use rustc_feature::BUILTIN_ATTRIBUTE_SET; use rustc_lint_defs::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_parse::parse_in; use rustc_session::diagnostics::report_lit_error; @@ -27,7 +27,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) { AttrKind::Synthetic(CfgTrace(_) | CfgAttrTrace(_)) | AttrKind::DocComment(..) => return, } - let builtin_attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name)); + let builtin_attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_SET.get(&name)); // Check input tokens for built-in and key-value attributes. if let Some(name) = builtin_attr_info { diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 54a1babbaae72..b2a2d3dbd60dd 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -741,9 +741,7 @@ fn print_crate_info( .iter() .filter_map(|&(name, value)| { // On stable, exclude unstable flags. - if !sess.is_nightly_build() - && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some() - { + if !sess.is_nightly_build() && find_gated_cfg(name).is_some() { return None; } diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml index 454fa20032aca..093e6dd91d11b 100644 --- a/compiler/rustc_feature/Cargo.toml +++ b/compiler/rustc_feature/Cargo.toml @@ -6,6 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start rustc_data_structures = { path = "../rustc_data_structures" } +rustc_macros = { path = "../rustc_macros" } rustc_span = { path = "../rustc_span" } serde = { version = "1.0.125", features = ["derive"] } serde_json = "1.0.59" diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index a6e6f4f78323c..37a3594e374ea 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -278,7 +278,7 @@ declare_features! ( /// Allows some increased flexibility in the name resolution rules, /// especially around globs and shadowing (RFC 1560). (accepted, item_like_imports, "1.15.0", Some(35120)), - // Allows using the `kl` and `widekl` target features and the associated intrinsics + /// Allows using the `kl` and `widekl` target features and the associated intrinsics (accepted, keylocker_x86, "1.89.0", Some(134813)), /// Allows `'a: { break 'a; }`. (accepted, label_break_value, "1.65.0", Some(48594)), diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index cc5b8ff2238ea..7e491a7569d11 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -54,20 +54,22 @@ const GATED_CFGS: &[GatedCfg] = &[ (sym::target_object_format, sym::cfg_target_object_format, Features::cfg_target_object_format), ]; -/// Find a gated cfg determined by the `pred`icate which is given the cfg's name. -pub fn find_gated_cfg(pred: impl Fn(Symbol) -> bool) -> Option<&'static GatedCfg> { - GATED_CFGS.iter().find(|(cfg_sym, ..)| pred(*cfg_sym)) +/// Find a gated cfg matching `name`. +pub fn find_gated_cfg(name: Symbol) -> Option<&'static GatedCfg> { + GATED_CFGS.iter().find(|(cfg_sym, ..)| name == *cfg_sym) } #[derive(Clone, Debug, Copy)] pub enum AttributeStability { - /// An attribute that is unstable behind a specified feature fagte + /// An attribute that is unstable behind a specified feature gate. Unstable { /// The feature gate, for example `rustc_attrs` for rustc_* attributes. gate_name: Symbol, - /// Check function to be called during the `PostExpansionVisitor` pass, which will be one of the `Features::*` functions - gate_check: fn(&Features) -> bool, - /// Notes to be displayed when an attempt is made to use the attribute without its feature gate. + /// Check function to be called during the `PostExpansionVisitor` pass, which will be one + /// of the `Features::*` functions + gate_check: GateFn, + /// Notes to be displayed when an attempt is made to use the attribute without its feature + /// gate. notes: &'static [&'static str], }, /// A stable attribute, can be used on all release channels @@ -417,15 +419,15 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ ]; pub fn is_builtin_attr_name(name: Symbol) -> bool { - BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() + BUILTIN_ATTRIBUTE_SET.contains(&name) } -pub static BUILTIN_ATTRIBUTE_MAP: LazyLock> = LazyLock::new(|| { - let mut map = FxHashSet::default(); +pub static BUILTIN_ATTRIBUTE_SET: LazyLock> = LazyLock::new(|| { + let mut set = FxHashSet::default(); for attr in BUILTIN_ATTRIBUTES.iter() { - if !map.insert(*attr) { + if !set.insert(*attr) { panic!("duplicate builtin attribute `{}`", attr); } } - map + set }); diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 859b2025619e4..5b9b899fc463f 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -70,8 +70,7 @@ impl UnstableFeatures { let is_unstable_crate = |var: &str| krate.is_some_and(|name| var.split(',').any(|new_krate| new_krate == name)); - let bootstrap = env_var_rustc_bootstrap.ok(); - if let Some(val) = bootstrap.as_deref() { + if let Ok(val) = env_var_rustc_bootstrap.as_deref() { match val { val if val == "1" || is_unstable_crate(val) => return UnstableFeatures::Cheat, // Hypnotize ourselves so that we think we are a stable compiler and thus don't @@ -129,7 +128,7 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option { - Some(NonZeroU32::new($val).unwrap()) + Some(>::new($val).unwrap()) }; } @@ -34,7 +34,7 @@ macro_rules! declare_features { issue: to_nonzero($issue), }, reason: $reason, - pull: opt_nonzero_u32!($($pull)?), + pull: opt_nonzero_u32!($($pull)?), }),+ ]; }; @@ -211,7 +211,7 @@ declare_features! ( (removed, no_coverage, "1.74.0", Some(84605), Some("renamed to `coverage_attribute`"), 114656), /// Allows `#[no_debug]`. (removed, no_debug, "1.43.0", Some(29721), Some("removed due to lack of demand"), 69667), - // Allows the use of `no_sanitize` attribute. + /// Allows the use of `no_sanitize` attribute. /// The feature was renamed to `sanitize` and the attribute to `#[sanitize(xyz = "on|off")]` (removed, no_sanitize, "1.91.0", Some(39699), Some(r#"renamed to sanitize(xyz = "on|off")"#), 142681), /// Note: this feature was previously recorded in a separate @@ -266,7 +266,7 @@ declare_features! ( (removed, pushpop_unsafe, "1.2.0", None, None), (removed, quad_precision_float, "1.0.0", None, None), (removed, quote, "1.33.0", Some(29601), None), - (removed, ref_pat_everywhere, "1.80.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024"), 125168), + (removed, ref_pat_everywhere, "1.80.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024`"), 125168), (removed, reflect, "1.0.0", Some(27749), None), /// Allows using the `#[register_attr]` attribute. (removed, register_attr, "1.65.0", Some(66080), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 187ce8d639fb4..ca70389815141 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -5,7 +5,7 @@ use std::time::{SystemTime, UNIX_EPOCH}; use rustc_data_structures::AtomicRef; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher}; +use rustc_macros::StableHash; use rustc_span::{Span, Symbol, sym}; use super::{Feature, to_nonzero}; @@ -43,18 +43,19 @@ macro_rules! status_to_enum { /// /// 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)] +#[derive(Clone, Default, Debug, StableHash)] pub struct Features { /// `#![feature]` attrs for language features, for error reporting. enabled_lang_features: Vec, /// `#![feature]` attrs for non-language (library) features. enabled_lib_features: Vec, /// `enabled_lang_features` + `enabled_lib_features`. + #[stable_hash(ignore)] // Ignored because it's the sum of the other two fields enabled_features: FxHashSet, } /// Information about an enabled language feature. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, StableHash)] pub struct EnabledLangFeature { /// Name of the feature gate guarding the language feature. pub gate_name: Symbol, @@ -65,7 +66,7 @@ pub struct EnabledLangFeature { } /// Information about an enabled library feature. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, StableHash)] pub struct EnabledLibFeature { pub gate_name: Symbol, pub attr_sp: Span, @@ -87,11 +88,11 @@ impl Features { /// - Feature gate name. /// - The span of the `#[feature]` attribute. /// - For stable language features, version info for when it was stabilized. - pub fn enabled_lang_features(&self) -> &Vec { + pub fn enabled_lang_features(&self) -> &[EnabledLangFeature] { &self.enabled_lang_features } - pub fn enabled_lib_features(&self) -> &Vec { + pub fn enabled_lib_features(&self) -> &[EnabledLibFeature] { &self.enabled_lib_features } @@ -99,7 +100,7 @@ impl Features { &self.enabled_features } - /// Returns a iterator of enabled features in stable order. + /// Returns an iterator of enabled features in stable order. pub fn enabled_features_iter_stable_order( &self, ) -> impl Iterator + Clone { @@ -120,32 +121,6 @@ impl Features { } } -impl StableHash for Features { - fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher) { - // `enabled_features` is skipped because it's the sum of the lang and lib features. - let Features { enabled_lang_features, enabled_lib_features, enabled_features: _ } = self; - enabled_lang_features.stable_hash(hcx, hasher); - enabled_lib_features.stable_hash(hcx, hasher); - } -} - -impl StableHash for EnabledLangFeature { - fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher) { - let EnabledLangFeature { gate_name, attr_sp, stable_since } = self; - gate_name.stable_hash(hcx, hasher); - attr_sp.stable_hash(hcx, hasher); - stable_since.stable_hash(hcx, hasher); - } -} - -impl StableHash for EnabledLibFeature { - fn stable_hash(&self, hcx: &mut Hcx, hasher: &mut StableHasher) { - let EnabledLibFeature { gate_name, attr_sp } = self; - gate_name.stable_hash(hcx, hasher); - attr_sp.stable_hash(hcx, hasher); - } -} - macro_rules! declare_features { ($( $(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr), @@ -515,7 +490,7 @@ declare_features! ( (unstable, diagnostic_on_unknown, "1.96.0", Some(152900)), /// Allows macros to customize macro argument matcher diagnostics. (unstable, diagnostic_on_unmatched_args, "1.97.0", Some(155642)), - // Used by macros to not show their bodies in error messages. No-op with `-Z macro-backtrace`. + /// Used by macros to not show their bodies in error messages. No-op with `-Z macro-backtrace`. (unstable, diagnostic_opaque, "1.99.0", Some(158813)), /// Allows `#[doc(cfg(...))]`. (unstable, doc_cfg, "1.21.0", Some(43781)), @@ -578,7 +553,8 @@ declare_features! ( (incomplete, generic_const_parameter_types, "1.87.0", Some(137626)), /// Allows any generic constants being used as pattern type range ends (incomplete, generic_pattern_types, "1.86.0", Some(136574)), - /// Allows registering static items globally, possibly across crates, to iterate over at runtime. + /// Allows registering static items globally, possibly across crates, to iterate over at + /// runtime. (unstable, global_registration, "1.80.0", Some(125119)), /// Allows using guards in patterns. (incomplete, guard_patterns, "1.85.0", Some(129967)), @@ -679,7 +655,7 @@ declare_features! ( (unstable, non_exhaustive_omitted_patterns_lint, "1.57.0", Some(89554)), /// Allows `for` binders in where-clauses (incomplete, non_lifetime_binders, "1.69.0", Some(108185)), - /// Target feaures on nvptx. + /// Target features on nvptx. (unstable, nvptx_target_feature, "1.91.0", Some(150254)), /// Allows using enums in offset_of! (unstable, offset_of_enum, "1.75.0", Some(120141)), @@ -701,10 +677,12 @@ declare_features! ( (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Allows the use of raw-dylibs on ELF platforms (incomplete, raw_dylib_elf, "1.87.0", Some(135694)), + /// Allows the `Reborrow` and `CoerceShared` traits. (unstable, reborrow, "1.91.0", Some(145612)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. (incomplete, ref_pat_eat_one_layer_2024, "1.79.0", Some(123076)), - /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural variant + /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024—structural + /// variant. (incomplete, ref_pat_eat_one_layer_2024_structural, "1.81.0", Some(123076)), /// Allows using the `#[register_tool]` attribute. (unstable, register_tool, "1.41.0", Some(66079)), @@ -791,6 +769,7 @@ declare_features! ( (unstable, xtensa_target_feature, "1.98.0", Some(157063)), /// Allows `do yeet` expressions (unstable, yeet_expr, "1.62.0", Some(96373)), + /// Allows the `yield` keyword for coroutines/generators. (unstable, yield_expr, "1.87.0", Some(43122)), // !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! !!!! // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index c3d19542c1645..2db25a7a30f62 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -13,7 +13,7 @@ use rustc_ast::{AttrStyle, MetaItemKind, ast}; use rustc_attr_parsing::AttributeParser; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::{DiagCtxtHandle, IntoDiagArg, MultiSpan, msg}; -use rustc_feature::BUILTIN_ATTRIBUTE_MAP; +use rustc_feature::BUILTIN_ATTRIBUTE_SET; use rustc_hir::attrs::diagnostic::Directive; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::attrs::{ @@ -146,7 +146,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::allow | sym::expect | sym::warn | sym::deny | sym::forbid, ..] => {} [name, rest @ ..] => { - if let Some(_) = BUILTIN_ATTRIBUTE_MAP.get(name) { + if BUILTIN_ATTRIBUTE_SET.contains(name) { if rest.len() > 0 && AttributeParser::is_parsed_attribute(slice::from_ref(name)) { diff --git a/src/doc/rustc-dev-guide/src/feature-gate-check.md b/src/doc/rustc-dev-guide/src/feature-gate-check.md index 0b4fc0cd680c0..7726122b02f38 100644 --- a/src/doc/rustc-dev-guide/src/feature-gate-check.md +++ b/src/doc/rustc-dev-guide/src/feature-gate-check.md @@ -100,7 +100,7 @@ Beyond syntax, rustc also gates attributes and `cfg` options. ### Built-in attributes -- [`rustc_ast_passes::check_attribute`] inspects attributes against `BUILTIN_ATTRIBUTE_MAP`. +- [`rustc_ast_passes::check_attribute`] inspects attributes against `BUILTIN_ATTRIBUTE_SET`. - If the attribute is `AttributeGate::Gated` and the feature isn’t enabled, `feature_err` is emitted.