Rollup merge of #132114 - jieyouxu:features-bundle, r=fee1-dead

Use `Enabled{Lang,Lib}Feature`  instead of n-tuples

Instead of passing around e.g. `(gate_name, attr_span, stable_since)` 3-tuples for enabled lang features or `(gate_name, attr_span)` 2-tuples for enabled lib features, use `Enabled{Lang,Lib}Feature` structs with named fields.

Also did some minor code-golfing of involved iterator chains to hopefully make them easier to follow.

Follow-up to https://github.com/rust-lang/rust/pull/132098#issuecomment-2434523431 cc `@RalfJung.`
This commit is contained in:
Matthias Krüger 2024-10-26 06:29:47 +02:00 committed by GitHub
commit 8207d89b5e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 101 additions and 51 deletions

View File

@ -623,8 +623,9 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
let stable_since = features let stable_since = features
.enabled_lang_features() .enabled_lang_features()
.iter() .iter()
.flat_map(|&(feature, _, since)| if feature == name { since } else { None }) .find(|feat| feat.gate_name == name)
.next(); .map(|feat| feat.stable_since)
.flatten();
if let Some(since) = stable_since { if let Some(since) = stable_since {
err.stable_features.push(errors::StableFeature { name, since }); err.stable_features.push(errors::StableFeature { name, since });
} else { } else {
@ -642,16 +643,15 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
} }
fn check_incompatible_features(sess: &Session, features: &Features) { fn check_incompatible_features(sess: &Session, features: &Features) {
let enabled_features = features let enabled_lang_features =
.enabled_lang_features() features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
.iter() let enabled_lib_features =
.copied() features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
.map(|(name, span, _)| (name, span)) let enabled_features = enabled_lang_features.chain(enabled_lib_features);
.chain(features.enabled_lib_features().iter().copied());
for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES
.iter() .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((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) 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. // 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() .enabled_lang_features()
.iter() .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 { sess.dcx().emit_err(errors::IncompatibleFeatures {
spans: vec![gce_span], spans: vec![gce_span],

View File

@ -11,8 +11,8 @@ use rustc_ast::{
use rustc_attr as attr; use rustc_attr as attr;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace; use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_feature::{ use rustc_feature::{
ACCEPTED_LANG_FEATURES, AttributeSafety, Features, REMOVED_LANG_FEATURES, ACCEPTED_LANG_FEATURES, AttributeSafety, EnabledLangFeature, EnabledLibFeature, Features,
UNSTABLE_LANG_FEATURES, REMOVED_LANG_FEATURES, UNSTABLE_LANG_FEATURES,
}; };
use rustc_lint_defs::BuiltinLintDiag; use rustc_lint_defs::BuiltinLintDiag;
use rustc_parse::validate_attr; 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 the enabled feature is stable, record it.
if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| name == f.name) { 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(EnabledLangFeature {
features.set_enabled_lang_feature(name, mi.span(), since); gate_name: name,
attr_sp: mi.span(),
stable_since: Some(Symbol::intern(f.since)),
});
continue; 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); 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; continue;
} }
// Otherwise, the feature is unknown. Enable it as a lib feature. // Otherwise, the feature is unknown. Enable it as a lib feature.
// It will be checked later whether the feature really exists. // 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 // Similar to above, detect internal lib features to suppress
// the ICE message that asks for a report. // the ICE message that asks for a report.

View File

@ -135,4 +135,6 @@ pub use builtin_attrs::{
is_valid_for_get_attr, is_valid_for_get_attr,
}; };
pub use removed::REMOVED_LANG_FEATURES; 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,
};

View File

@ -36,35 +36,54 @@ macro_rules! status_to_enum {
#[derive(Clone, Default, Debug)] #[derive(Clone, Default, Debug)]
pub struct Features { pub struct Features {
/// `#![feature]` attrs for language features, for error reporting. /// `#![feature]` attrs for language features, for error reporting.
enabled_lang_features: Vec<(Symbol, Span, Option<Symbol>)>, enabled_lang_features: Vec<EnabledLangFeature>,
/// `#![feature]` attrs for non-language (library) features. /// `#![feature]` attrs for non-language (library) features.
enabled_lib_features: Vec<(Symbol, Span)>, enabled_lib_features: Vec<EnabledLibFeature>,
/// `enabled_lang_features` + `enabled_lib_features`. /// `enabled_lang_features` + `enabled_lib_features`.
enabled_features: FxHashSet<Symbol>, enabled_features: FxHashSet<Symbol>,
} }
/// 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<Symbol>,
}
/// Information abhout an enabled library feature.
#[derive(Debug, Copy, Clone)]
pub struct EnabledLibFeature {
pub gate_name: Symbol,
pub attr_sp: Span,
}
impl Features { impl Features {
/// `since` should be set for stable features that are nevertheless enabled with a `#[feature]` /// `since` should be set for stable features that are nevertheless enabled with a `#[feature]`
/// attribute, indicating since when they are stable. /// attribute, indicating since when they are stable.
pub fn set_enabled_lang_feature(&mut self, name: Symbol, span: Span, since: Option<Symbol>) { pub fn set_enabled_lang_feature(&mut self, lang_feat: EnabledLangFeature) {
self.enabled_lang_features.push((name, span, since)); self.enabled_lang_features.push(lang_feat);
self.enabled_features.insert(name); self.enabled_features.insert(lang_feat.gate_name);
} }
pub fn set_enabled_lib_feature(&mut self, name: Symbol, span: Span) { pub fn set_enabled_lib_feature(&mut self, lib_feat: EnabledLibFeature) {
self.enabled_lib_features.push((name, span)); self.enabled_lib_features.push(lib_feat);
self.enabled_features.insert(name); self.enabled_features.insert(lib_feat.gate_name);
} }
/// Returns a list of triples with: /// Returns a list of [`EnabledLangFeature`] with info about:
/// - feature gate name ///
/// - the span of the `#[feature]` attribute /// - Feature gate name.
/// - (for already stable features) the version since which it is stable /// - The span of the `#[feature]` attribute.
pub fn enabled_lang_features(&self) -> &Vec<(Symbol, Span, Option<Symbol>)> { /// - For stable language features, version info for when it was stabilized.
pub fn enabled_lang_features(&self) -> &Vec<EnabledLangFeature> {
&self.enabled_lang_features &self.enabled_lang_features
} }
pub fn enabled_lib_features(&self) -> &Vec<(Symbol, Span)> { pub fn enabled_lib_features(&self) -> &Vec<EnabledLibFeature> {
&self.enabled_lib_features &self.enabled_lib_features
} }

View File

@ -2289,13 +2289,15 @@ declare_lint_pass!(
impl EarlyLintPass for IncompleteInternalFeatures { impl EarlyLintPass for IncompleteInternalFeatures {
fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) { fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
let features = cx.builder.features(); let features = cx.builder.features();
features let lang_features =
.enabled_lang_features() features.enabled_lang_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
.iter() let lib_features =
.map(|(name, span, _)| (name, span)) features.enabled_lib_features().iter().map(|feat| (feat.gate_name, feat.attr_sp));
.chain(features.enabled_lib_features().iter().map(|(name, span)| (name, span)))
.filter(|(&name, _)| features.incomplete(name) || features.internal(name)) lang_features
.for_each(|(&name, &span)| { .chain(lib_features)
.filter(|(name, _)| features.incomplete(*name) || features.internal(*name))
.for_each(|(name, span)| {
if features.incomplete(name) { if features.incomplete(name) {
let note = rustc_feature::find_feature_issue(name, GateIssue::Language) let note = rustc_feature::find_feature_issue(name, GateIssue::Language)
.map(|n| BuiltinFeatureIssueNote { n }); .map(|n| BuiltinFeatureIssueNote { n });

View File

@ -10,7 +10,7 @@ use rustc_attr::{
}; };
use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet}; 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 as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalModDefId};
@ -994,25 +994,25 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
let enabled_lang_features = tcx.features().enabled_lang_features(); let enabled_lang_features = tcx.features().enabled_lang_features();
let mut lang_features = UnordSet::default(); let mut lang_features = UnordSet::default();
for &(feature, span, since) in enabled_lang_features { for EnabledLangFeature { gate_name, attr_sp, stable_since } in enabled_lang_features {
if let Some(since) = since { if let Some(version) = stable_since {
// Warn if the user has enabled an already-stable lang feature. // 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. // 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 enabled_lib_features = tcx.features().enabled_lib_features();
let mut remaining_lib_features = FxIndexMap::default(); let mut remaining_lib_features = FxIndexMap::default();
for (feature, span) in enabled_lib_features { for EnabledLibFeature { gate_name, attr_sp } in enabled_lib_features {
if remaining_lib_features.contains_key(&feature) { if remaining_lib_features.contains_key(gate_name) {
// Warn if the user enables a lib feature multiple times. // 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 // `stdbuild` has special handling for `libc`, so we need to
// recognise the feature when building std. // recognise the feature when building std.
@ -1044,7 +1044,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
/// time, less loading from metadata is performed and thus compiler performance is improved. /// time, less loading from metadata is performed and thus compiler performance is improved.
fn check_features<'tcx>( fn check_features<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
remaining_lib_features: &mut FxIndexMap<&Symbol, Span>, remaining_lib_features: &mut FxIndexMap<Symbol, Span>,
remaining_implications: &mut UnordMap<Symbol, Symbol>, remaining_implications: &mut UnordMap<Symbol, Symbol>,
defined_features: &LibFeatures, defined_features: &LibFeatures,
all_implications: &UnordMap<Symbol, Symbol>, all_implications: &UnordMap<Symbol, Symbol>,
@ -1114,7 +1114,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
} }
for (feature, span) in remaining_lib_features { 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() { for (&implied_by, &feature) in remaining_implications.to_sorted_stable_ord() {

View File

@ -116,3 +116,20 @@ impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
self.enabled_lib_features().hash_stable(hcx, hasher); self.enabled_lib_features().hash_stable(hcx, hasher);
} }
} }
impl<'tcx> HashStable<StableHashingContext<'tcx>> 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<StableHashingContext<'tcx>> 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);
}
}