1
Fork 0

Unify defined_lib_features and lib_features queries

This commit is contained in:
Michael Goulet 2023-09-23 05:38:49 +00:00
parent 46ecc10c69
commit 86299a1247
9 changed files with 85 additions and 62 deletions

View file

@ -8,18 +8,14 @@ use rustc_ast::Attribute;
use rustc_attr::VERSION_PLACEHOLDER;
use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::lib_features::LibFeatures;
use rustc_middle::query::Providers;
use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
use rustc_middle::query::{LocalCrate, Providers};
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
use rustc_span::{sym, Span};
use crate::errors::{FeaturePreviouslyDeclared, FeatureStableTwice};
fn new_lib_features() -> LibFeatures {
LibFeatures { stable: Default::default(), unstable: Default::default() }
}
pub struct LibFeatureCollector<'tcx> {
tcx: TyCtxt<'tcx>,
lib_features: LibFeatures,
@ -27,10 +23,10 @@ pub struct LibFeatureCollector<'tcx> {
impl<'tcx> LibFeatureCollector<'tcx> {
fn new(tcx: TyCtxt<'tcx>) -> LibFeatureCollector<'tcx> {
LibFeatureCollector { tcx, lib_features: new_lib_features() }
LibFeatureCollector { tcx, lib_features: LibFeatures::default() }
}
fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
fn extract(&self, attr: &Attribute) -> Option<(Symbol, FeatureStability, Span)> {
let stab_attrs = [
sym::stable,
sym::unstable,
@ -72,8 +68,11 @@ impl<'tcx> LibFeatureCollector<'tcx> {
| sym::rustc_const_unstable
| sym::rustc_default_body_unstable
);
if since.is_some() || is_unstable {
return Some((feature, since, attr.span));
if is_unstable {
return Some((feature, FeatureStability::Unstable, attr.span));
}
if let Some(since) = since {
return Some((feature, FeatureStability::AcceptedSince(since), attr.span));
}
}
// We need to iterate over the other attributes, because
@ -86,37 +85,43 @@ impl<'tcx> LibFeatureCollector<'tcx> {
None
}
fn collect_feature(&mut self, feature: Symbol, since: Option<Symbol>, span: Span) {
fn collect_feature(&mut self, feature: Symbol, stability: FeatureStability, span: Span) {
let already_in_stable = self.lib_features.stable.contains_key(&feature);
let already_in_unstable = self.lib_features.unstable.contains_key(&feature);
match (since, already_in_stable, already_in_unstable) {
(Some(since), _, false) => {
if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) {
if *prev_since != since {
self.tcx.sess.emit_err(FeatureStableTwice {
span,
feature,
since,
prev_since: *prev_since,
});
return;
}
match (stability, already_in_stable, already_in_unstable) {
(FeatureStability::AcceptedSince(since), _, false) => {
if let Some((prev_since, _)) = self.lib_features.stable.get(&feature)
&& *prev_since != since
{
self.tcx.sess.emit_err(FeatureStableTwice {
span,
feature,
since,
prev_since: *prev_since,
});
return;
}
self.lib_features.stable.insert(feature, (since, span));
}
(None, false, _) => {
self.lib_features.unstable.insert(feature, span);
}
(Some(_), _, true) | (None, true, _) => {
let declared = if since.is_some() { "stable" } else { "unstable" };
let prev_declared = if since.is_none() { "stable" } else { "unstable" };
(FeatureStability::AcceptedSince(_), _, true) => {
self.tcx.sess.emit_err(FeaturePreviouslyDeclared {
span,
feature,
declared,
prev_declared,
declared: "stable",
prev_declared: "unstable",
});
}
(FeatureStability::Unstable, false, _) => {
self.lib_features.unstable.insert(feature, span);
}
(FeatureStability::Unstable, true, _) => {
self.tcx.sess.emit_err(FeaturePreviouslyDeclared {
span,
feature,
declared: "unstable",
prev_declared: "stable",
});
}
}
@ -137,11 +142,11 @@ impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> {
}
}
fn lib_features(tcx: TyCtxt<'_>, (): ()) -> LibFeatures {
fn lib_features(tcx: TyCtxt<'_>, LocalCrate: LocalCrate) -> LibFeatures {
// If `staged_api` is not enabled then we aren't allowed to define lib
// features; there is no point collecting them.
if !tcx.features().staged_api {
return new_lib_features();
return LibFeatures::default();
}
let mut collector = LibFeatureCollector::new(tcx);

View file

@ -14,6 +14,7 @@ use rustc_hir::hir_id::CRATE_HIR_ID;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::lib_features::{FeatureStability, LibFeatures};
use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
use rustc_middle::query::Providers;
@ -978,29 +979,27 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
tcx: TyCtxt<'tcx>,
remaining_lib_features: &mut FxIndexMap<&Symbol, Span>,
remaining_implications: &mut FxHashMap<Symbol, Symbol>,
defined_features: &[(Symbol, Option<Symbol>)],
defined_features: &LibFeatures,
all_implications: &FxHashMap<Symbol, Symbol>,
) {
for (feature, since) in defined_features {
if let Some(since) = since
for (feature, since) in defined_features.to_vec() {
if let FeatureStability::AcceptedSince(since) = since
&& let Some(span) = remaining_lib_features.get(&feature)
{
// Warn if the user has enabled an already-stable lib feature.
if let Some(implies) = all_implications.get(&feature) {
unnecessary_partially_stable_feature_lint(
tcx, *span, *feature, *implies, *since,
);
unnecessary_partially_stable_feature_lint(tcx, *span, feature, *implies, since);
} else {
unnecessary_stable_feature_lint(tcx, *span, *feature, *since);
unnecessary_stable_feature_lint(tcx, *span, feature, since);
}
}
remaining_lib_features.remove(feature);
remaining_lib_features.remove(&feature);
// `feature` is the feature doing the implying, but `implied_by` is the feature with
// the attribute that establishes this relationship. `implied_by` is guaranteed to be a
// feature defined in the local crate because `remaining_implications` is only the
// implications from this crate.
remaining_implications.remove(feature);
remaining_implications.remove(&feature);
if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
break;
@ -1014,7 +1013,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
// We always collect the lib features declared in the current crate, even if there are
// no unknown features, because the collection also does feature attribute validation.
let local_defined_features = tcx.lib_features(()).to_vec();
let local_defined_features = tcx.lib_features(rustc_hir::def_id::LOCAL_CRATE);
if !remaining_lib_features.is_empty() || !remaining_implications.is_empty() {
// Loading the implications of all crates is unavoidable to be able to emit the partial
// stabilization diagnostic, but it can be avoided when there are no
@ -1028,7 +1027,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
tcx,
&mut remaining_lib_features,
&mut remaining_implications,
local_defined_features.as_slice(),
local_defined_features,
&all_implications,
);
@ -1040,7 +1039,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
tcx,
&mut remaining_lib_features,
&mut remaining_implications,
tcx.defined_lib_features(cnum).to_vec().as_slice(),
tcx.lib_features(cnum),
&all_implications,
);
}
@ -1051,7 +1050,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
}
for (implied_by, feature) in remaining_implications {
let local_defined_features = tcx.lib_features(());
let local_defined_features = tcx.lib_features(rustc_hir::def_id::LOCAL_CRATE);
let span = *local_defined_features
.stable
.get(&feature)