Add duplicity lint for lang features
This commit is contained in:
parent
fc99ea7ffa
commit
a92d3a3606
3 changed files with 40 additions and 31 deletions
|
@ -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| {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue