From a92d3a36066e966b405a28db2ee4ae61a934f3c8 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 23 Jul 2018 02:03:01 +0100 Subject: [PATCH] Add duplicity lint for lang features --- src/librustc/ich/impls_syntax.rs | 2 +- src/librustc/middle/stability.rs | 49 +++++++++++++++++++------------- src/libsyntax/feature_gate.rs | 16 +++++------ 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 2ab0124397b..d086d3bd28d 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -511,7 +511,7 @@ fn hash_stable(&self, hasher: &mut StableHasher) { // 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| { diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 9b5a9dfd5b3..85d4bcbd0d4 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -23,7 +23,7 @@ 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 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)); + } + 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.clone().into_iter() { - // Warn if the user enables a feature multiple times. + 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, + *span, &format!("duplicate `{}` feature attribute", feature)); } - remaining_lib_features.insert(feature, span); + 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) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 77e3faa5b1f..9ca9909ffa6 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -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)>, /// `#![feature]` attrs for non-language (library) features pub declared_lib_features: Vec<(Symbol, Span)>, $(pub $feature: bool),+ @@ -69,7 +69,7 @@ pub struct 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 { if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.0 == feature) { let issue = info.2; @@ -1940,6 +1936,7 @@ fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { 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 @@ fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) { 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 } -- 2.44.0