Add duplicity lint for lang features

This commit is contained in:
varkor 2018-07-23 02:03:01 +01:00
parent fc99ea7ffa
commit a92d3a3606
3 changed files with 40 additions and 31 deletions

View file

@ -511,7 +511,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for feature_gate::Features {
hasher: &mut StableHasher<W>) {
// Unfortunately we cannot exhaustively list fields here, since the
// struct is macro generated.
self.declared_stable_lang_features.hash_stable(hcx, hasher);
self.declared_lang_features.hash_stable(hcx, hasher);
self.declared_lib_features.hash_stable(hcx, hasher);
self.walk_feature_fields(|feature_name, value| {

View file

@ -23,7 +23,7 @@ use syntax::symbol::Symbol;
use syntax_pos::{Span, MultiSpan};
use syntax::ast;
use syntax::ast::{NodeId, Attribute};
use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version};
use syntax::feature_gate::{GateIssue, emit_feature_err};
use syntax::attr::{self, Stability, Deprecation};
use util::nodemap::{FxHashSet, FxHashMap};
@ -813,40 +813,51 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
krate.visit_all_item_likes(&mut missing.as_deep_visitor());
}
for &(ref stable_lang_feature, span) in &tcx.features().declared_stable_lang_features {
let since = find_lang_feature_accepted_version(&stable_lang_feature.as_str())
.expect("unexpectedly couldn't find version feature was stabilized");
tcx.lint_node(lint::builtin::STABLE_FEATURES,
ast::CRATE_NODE_ID,
span,
&format_stable_since_msg(*stable_lang_feature, since));
}
let ref declared_lib_features = tcx.features().declared_lib_features;
let mut remaining_lib_features = FxHashMap();
for (feature, span) in declared_lib_features.clone().into_iter() {
// Warn if the user enables a feature multiple times.
if remaining_lib_features.contains_key(&feature) {
let declared_lang_features = &tcx.features().declared_lang_features;
let mut lang_features = FxHashSet();
for &(ref feature, span, since) in declared_lang_features {
if let Some(since) = since {
// Warn if the user has enabled an already-stable lang feature.
tcx.lint_node(lint::builtin::STABLE_FEATURES,
ast::CRATE_NODE_ID,
span,
&format_stable_since_msg(*feature, since));
}
if lang_features.contains(&feature) {
// Warn if the user enables a lang feature multiple times.
tcx.lint_node(lint::builtin::DUPLICATE_FEATURES,
ast::CRATE_NODE_ID,
span,
&format!("duplicate `{}` feature attribute", feature));
}
remaining_lib_features.insert(feature, span);
lang_features.insert(feature);
}
let declared_lib_features = &tcx.features().declared_lib_features;
let mut remaining_lib_features = FxHashMap();
for (feature, span) in declared_lib_features {
// Warn if the user enables a lib feature multiple times.
if remaining_lib_features.contains_key(&feature) {
tcx.lint_node(lint::builtin::DUPLICATE_FEATURES,
ast::CRATE_NODE_ID,
*span,
&format!("duplicate `{}` feature attribute", feature));
}
remaining_lib_features.insert(feature, span.clone());
}
// FIXME(varkor): we don't properly handle lib features behind `cfg` attributes yet,
// but it happens just to affect `libc`, so we're just going to hard-code it for now.
remaining_lib_features.remove(&Symbol::intern("libc"));
for (feature, stable) in tcx.lib_features().iter() {
// Warn if the user has enabled an already-stable feature.
// Warn if the user has enabled an already-stable lib feature.
if let Some(since) = stable {
if let Some(span) = remaining_lib_features.get(&feature) {
tcx.lint_node(lint::builtin::STABLE_FEATURES,
ast::CRATE_NODE_ID,
*span,
&format_stable_since_msg(feature, &since.as_str()));
ast::CRATE_NODE_ID,
*span,
&format_stable_since_msg(feature, since));
}
}
@ -864,7 +875,7 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
// don't lint about unused features. We should reenable this one day!
}
fn format_stable_since_msg(feature: Symbol, since: &str) -> String {
fn format_stable_since_msg(feature: Symbol, since: Symbol) -> String {
// "this feature has been stable since {}. Attribute no longer needed"
format!("the feature `{}` has been stable since {} and no longer requires \
an attribute to enable", feature, since)

View file

@ -59,8 +59,8 @@ macro_rules! declare_features {
/// A set of features to be used by later passes.
#[derive(Clone)]
pub struct Features {
/// `#![feature]` attrs for stable language features, for error reporting
pub declared_stable_lang_features: Vec<(Symbol, Span)>,
/// `#![feature]` attrs for language features, for error reporting
pub declared_lang_features: Vec<(Symbol, Span, Option<Symbol>)>,
/// `#![feature]` attrs for non-language (library) features
pub declared_lib_features: Vec<(Symbol, Span)>,
$(pub $feature: bool),+
@ -69,7 +69,7 @@ macro_rules! declare_features {
impl Features {
pub fn new() -> Features {
Features {
declared_stable_lang_features: Vec::new(),
declared_lang_features: Vec::new(),
declared_lib_features: Vec::new(),
$($feature: false),+
}
@ -1220,10 +1220,6 @@ pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features:
cx.check_attribute(attr, true);
}
pub fn find_lang_feature_accepted_version(feature: &str) -> Option<&'static str> {
ACCEPTED_FEATURES.iter().find(|t| t.0 == feature).map(|t| t.1)
}
fn find_lang_feature_issue(feature: &str) -> Option<u32> {
if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) {
let issue = info.2;
@ -1940,6 +1936,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
if let Some((.., set)) = ACTIVE_FEATURES.iter().find(|f| name == f.0) {
set(&mut features, mi.span);
feature_checker.collect(&features, mi.span);
features.declared_lang_features.push((name, mi.span, None));
continue
}
@ -1950,8 +1947,9 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
continue
}
if ACCEPTED_FEATURES.iter().any(|f| name == f.0) {
features.declared_stable_lang_features.push((name, mi.span));
if let Some((_, since, ..)) = ACCEPTED_FEATURES.iter().find(|f| name == f.0) {
let since = Some(Symbol::intern(since));
features.declared_lang_features.push((name, mi.span, since));
continue
}