Introduce Enabled{Lang,Lib}Feature
Instead of passing around random n-tuples of e.g. `(gate_name, attr_sp, since)`.
This commit is contained in:
parent
5ae4d75eff
commit
3528149f73
@ -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],
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
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 @@ fn feature_list(attr: &Attribute) -> ThinVec<ast::MetaItemInner> {
|
|||||||
|
|
||||||
// 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 @@ fn feature_list(attr: &Attribute) -> ThinVec<ast::MetaItemInner> {
|
|||||||
{
|
{
|
||||||
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.
|
||||||
|
@ -135,4 +135,6 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
|
|||||||
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,
|
||||||
|
};
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2287,13 +2287,15 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
|
|||||||
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 });
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
};
|
};
|
||||||
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};
|
||||||
@ -937,25 +937,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.
|
||||||
@ -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.
|
/// 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>,
|
||||||
@ -1057,7 +1057,7 @@ fn check_features<'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
||||||
|
@ -116,3 +116,20 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableH
|
|||||||
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user