diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 348a602fd59..d646150a620 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -623,8 +623,9 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) let stable_since = features .enabled_lang_features() .iter() - .flat_map(|&(feature, _, since)| if feature == name { since } else { None }) - .next(); + .find(|feat| feat.gate_name == name) + .map(|feat| feat.stable_since) + .flatten(); if let Some(since) = stable_since { err.stable_features.push(errors::StableFeature { name, since }); } else { @@ -642,16 +643,15 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) } fn check_incompatible_features(sess: &Session, features: &Features) { - let enabled_features = features - .enabled_lang_features() - .iter() - .copied() - .map(|(name, span, _)| (name, span)) - .chain(features.enabled_lib_features().iter().copied()); + let enabled_lang_features = + features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); + let enabled_lib_features = + features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); + let enabled_features = enabled_lang_features.chain(enabled_lib_features); for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES .iter() - .filter(|&&(f1, f2)| features.enabled(f1) && features.enabled(f2)) + .filter(|(f1, f2)| features.enabled(*f1) && features.enabled(*f2)) { if let Some((f1_name, f1_span)) = enabled_features.clone().find(|(name, _)| name == f1) { if let Some((f2_name, f2_span)) = enabled_features.clone().find(|(name, _)| name == f2) @@ -673,10 +673,11 @@ fn check_new_solver_banned_features(sess: &Session, features: &Features) { } // Ban GCE with the new solver, because it does not implement GCE correctly. - if let Some(&(_, gce_span, _)) = features + if let Some(gce_span) = features .enabled_lang_features() .iter() - .find(|&&(feat, _, _)| feat == sym::generic_const_exprs) + .find(|feat| feat.gate_name == sym::generic_const_exprs) + .map(|feat| feat.attr_sp) { sess.dcx().emit_err(errors::IncompatibleFeatures { spans: vec![gce_span], diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 5bd9e2fbcb9..dc6aa110f45 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -11,8 +11,8 @@ use rustc_ast::{ use rustc_attr as attr; use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_feature::{ - ACCEPTED_LANG_FEATURES, AttributeSafety, Features, REMOVED_LANG_FEATURES, - UNSTABLE_LANG_FEATURES, + ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features, + REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES, }; use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::validate_attr; @@ -88,8 +88,11 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - // If the enabled feature is stable, record it. if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| name == f.name) { - let since = Some(Symbol::intern(f.since)); - features.set_enabled_lang_feature(name, mi.span(), since); + features.set_enabled_lang_feature(EnabledLangFeature { + gate_name: name, + attr_sp: mi.span(), + stable_since: Some(Symbol::intern(f.since)), + }); continue; } @@ -115,13 +118,19 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) - { sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed); } - features.set_enabled_lang_feature(name, mi.span(), None); + + features.set_enabled_lang_feature(EnabledLangFeature { + gate_name: name, + attr_sp: mi.span(), + stable_since: None, + }); continue; } // Otherwise, the feature is unknown. Enable it as a lib feature. // It will be checked later whether the feature really exists. - features.set_enabled_lib_feature(name, mi.span()); + features + .set_enabled_lib_feature(EnabledLibFeature { gate_name: name, attr_sp: mi.span() }); // Similar to above, detect internal lib features to suppress // the ICE message that asks for a report. diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs index 216793485e5..9f42d3ec45c 100644 --- a/compiler/rustc_feature/src/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -135,4 +135,6 @@ pub use builtin_attrs::{ is_valid_for_get_attr, }; pub use removed::REMOVED_LANG_FEATURES; -pub use unstable::{Features, INCOMPATIBLE_FEATURES, UNSTABLE_LANG_FEATURES}; +pub use unstable::{ + EnabledLangFeature, EnabledLibFeature, Features, INCOMPATIBLE_FEATURES, UNSTABLE_LANG_FEATURES, +}; diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 8182eb1e973..f29bae61124 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -36,35 +36,54 @@ macro_rules! status_to_enum { #[derive(Clone, Default, Debug)] pub struct Features { /// `#![feature]` attrs for language features, for error reporting. - enabled_lang_features: Vec<(Symbol, Span, Option)>, + enabled_lang_features: Vec, /// `#![feature]` attrs for non-language (library) features. - enabled_lib_features: Vec<(Symbol, Span)>, + enabled_lib_features: Vec, /// `enabled_lang_features` + `enabled_lib_features`. enabled_features: FxHashSet, } +/// Information about an enabled language feature. +#[derive(Debug, Copy, Clone)] +pub struct EnabledLangFeature { + /// Name of the feature gate guarding the language feature. + pub gate_name: Symbol, + /// Span of the `#[feature(...)]` attribute. + pub attr_sp: Span, + /// If the lang feature is stable, the version number when it was stabilized. + pub stable_since: Option, +} + +/// Information abhout an enabled library feature. +#[derive(Debug, Copy, Clone)] +pub struct EnabledLibFeature { + pub gate_name: Symbol, + pub attr_sp: Span, +} + impl Features { /// `since` should be set for stable features that are nevertheless enabled with a `#[feature]` /// attribute, indicating since when they are stable. - pub fn set_enabled_lang_feature(&mut self, name: Symbol, span: Span, since: Option) { - self.enabled_lang_features.push((name, span, since)); - self.enabled_features.insert(name); + pub fn set_enabled_lang_feature(&mut self, lang_feat: EnabledLangFeature) { + self.enabled_lang_features.push(lang_feat); + self.enabled_features.insert(lang_feat.gate_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 set_enabled_lib_feature(&mut self, lib_feat: EnabledLibFeature) { + self.enabled_lib_features.push(lib_feat); + self.enabled_features.insert(lib_feat.gate_name); } - /// Returns a list of triples with: - /// - feature gate name - /// - the span of the `#[feature]` attribute - /// - (for already stable features) the version since which it is stable - pub fn enabled_lang_features(&self) -> &Vec<(Symbol, Span, Option)> { + /// Returns a list of [`EnabledLangFeature`] with info about: + /// + /// - 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 { &self.enabled_lang_features } - pub fn enabled_lib_features(&self) -> &Vec<(Symbol, Span)> { + pub fn enabled_lib_features(&self) -> &Vec { &self.enabled_lib_features } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5c5cd99345e..601aaaa96ad 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2287,13 +2287,15 @@ declare_lint_pass!( impl EarlyLintPass for IncompleteInternalFeatures { fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { let features = cx.builder.features(); - features - .enabled_lang_features() - .iter() - .map(|(name, span, _)| (name, span)) - .chain(features.enabled_lib_features().iter().map(|(name, span)| (name, span))) - .filter(|(&name, _)| features.incomplete(name) || features.internal(name)) - .for_each(|(&name, &span)| { + let lang_features = + features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); + let lib_features = + features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp)); + + lang_features + .chain(lib_features) + .filter(|(name, _)| features.incomplete(*name) || features.internal(*name)) + .for_each(|(name, span)| { if features.incomplete(name) { let note = rustc_feature::find_feature_issue(name, GateIssue::Language) .map(|n| BuiltinFeatureIssueNote { n }); diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index a176b2bb1ad..b1a056883c1 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -10,7 +10,7 @@ use rustc_attr::{ }; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; -use rustc_feature::ACCEPTED_LANG_FEATURES; +use rustc_feature::{ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; @@ -937,25 +937,25 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let enabled_lang_features = tcx.features().enabled_lang_features(); let mut lang_features = UnordSet::default(); - for &(feature, span, since) in enabled_lang_features { - if let Some(since) = since { + for EnabledLangFeature { gate_name, attr_sp, stable_since } in enabled_lang_features { + if let Some(version) = stable_since { // Warn if the user has enabled an already-stable lang feature. - unnecessary_stable_feature_lint(tcx, span, feature, since); + unnecessary_stable_feature_lint(tcx, *attr_sp, *gate_name, *version); } - if !lang_features.insert(feature) { + if !lang_features.insert(gate_name) { // Warn if the user enables a lang feature multiple times. - tcx.dcx().emit_err(errors::DuplicateFeatureErr { span, feature }); + tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name }); } } let enabled_lib_features = tcx.features().enabled_lib_features(); let mut remaining_lib_features = FxIndexMap::default(); - for (feature, span) in enabled_lib_features { - if remaining_lib_features.contains_key(&feature) { + for EnabledLibFeature { gate_name, attr_sp } in enabled_lib_features { + if remaining_lib_features.contains_key(gate_name) { // Warn if the user enables a lib feature multiple times. - tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature }); + tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *attr_sp, feature: *gate_name }); } - remaining_lib_features.insert(feature, *span); + remaining_lib_features.insert(*gate_name, *attr_sp); } // `stdbuild` has special handling for `libc`, so we need to // recognise the feature when building std. @@ -987,7 +987,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { /// time, less loading from metadata is performed and thus compiler performance is improved. fn check_features<'tcx>( tcx: TyCtxt<'tcx>, - remaining_lib_features: &mut FxIndexMap<&Symbol, Span>, + remaining_lib_features: &mut FxIndexMap, remaining_implications: &mut UnordMap, defined_features: &LibFeatures, all_implications: &UnordMap, @@ -1057,7 +1057,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { } for (feature, span) in remaining_lib_features { - tcx.dcx().emit_err(errors::UnknownFeature { span, feature: *feature }); + tcx.dcx().emit_err(errors::UnknownFeature { span, feature }); } for (&implied_by, &feature) in remaining_implications.to_sorted_stable_ord() { diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs index 0665401df8e..5a72e80a0a5 100644 --- a/compiler/rustc_query_system/src/ich/impls_syntax.rs +++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs @@ -116,3 +116,20 @@ impl<'tcx> HashStable> for rustc_feature::Features { self.enabled_lib_features().hash_stable(hcx, hasher); } } + +impl<'tcx> HashStable> for rustc_feature::EnabledLangFeature { + fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { + let rustc_feature::EnabledLangFeature { gate_name, attr_sp, stable_since } = self; + gate_name.hash_stable(hcx, hasher); + attr_sp.hash_stable(hcx, hasher); + stable_since.hash_stable(hcx, hasher); + } +} + +impl<'tcx> HashStable> for rustc_feature::EnabledLibFeature { + fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) { + let rustc_feature::EnabledLibFeature { gate_name, attr_sp } = self; + gate_name.hash_stable(hcx, hasher); + attr_sp.hash_stable(hcx, hasher); + } +}