]> git.lizzy.rs Git - rust.git/commitdiff
Add duplicity lint for lang features
authorvarkor <github@varkor.com>
Mon, 23 Jul 2018 01:03:01 +0000 (02:03 +0100)
committervarkor <github@varkor.com>
Sun, 5 Aug 2018 14:54:49 +0000 (15:54 +0100)
src/librustc/ich/impls_syntax.rs
src/librustc/middle/stability.rs
src/libsyntax/feature_gate.rs

index 2ab0124397bbb1b1a8749e153e5ef6057a77f9a2..d086d3bd28df00227bda9bedc7b92467270a8873 100644 (file)
@@ -511,7 +511,7 @@ fn hash_stable<W: StableHasherResult>(&self,
                                           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| {
index 9b5a9dfd5b31f5af8f447c4ed203073e8b8c23c0..85d4bcbd0d4f018d7db9d10c35ef7ed7cb37d02f 100644 (file)
@@ -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)
index 77e3faa5b1faca25b7d386c1e0f44eb394009626..9ca9909ffa6df3b99caeb5644dd1f50dbdb5f669 100644 (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 @@ 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<u32> {
     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
             }