about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/lint/builtin.rs7
-rw-r--r--src/librustc/middle/stability.rs53
-rw-r--r--src/librustc_driver/driver.rs4
-rw-r--r--src/libsyntax/feature_gate.rs15
-rw-r--r--src/test/compile-fail/gated-bad-feature.rs1
-rw-r--r--src/test/compile-fail/stable-features.rs20
6 files changed, 77 insertions, 23 deletions
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 53054f462c8..685922cea11 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -2019,6 +2019,12 @@ declare_lint! {
 }
 
 declare_lint! {
+    pub STABLE_FEATURES,
+    Warn,
+    "stable features found in #[feature] directive"
+}
+
+declare_lint! {
     pub UNKNOWN_CRATE_TYPES,
     Deny,
     "unknown crate type found in #[crate_type] directive"
@@ -2060,6 +2066,7 @@ impl LintPass for HardwiredLints {
             UNREACHABLE_CODE,
             WARNINGS,
             UNUSED_FEATURES,
+            STABLE_FEATURES,
             UNKNOWN_CRATE_TYPES,
             VARIANT_SIZE_DIFFERENCES,
             FAT_PTR_TRANSMUTES
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 3304bd4ae29..a005ae9c222 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -201,8 +201,9 @@ impl Index {
 /// Cross-references the feature names of unstable APIs with enabled
 /// features and possibly prints errors. Returns a list of all
 /// features used.
-pub fn check_unstable_api_usage(tcx: &ty::ctxt) -> FnvHashSet<InternedString> {
-    let ref active_lib_features = tcx.sess.features.borrow().lib_features;
+pub fn check_unstable_api_usage(tcx: &ty::ctxt)
+                                -> FnvHashMap<InternedString, attr::StabilityLevel> {
+    let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features;
 
     // Put the active features into a map for quick lookup
     let active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect();
@@ -210,7 +211,7 @@ pub fn check_unstable_api_usage(tcx: &ty::ctxt) -> FnvHashSet<InternedString> {
     let mut checker = Checker {
         tcx: tcx,
         active_features: active_features,
-        used_features: FnvHashSet()
+        used_features: FnvHashMap()
     };
 
     let krate = tcx.map.krate();
@@ -223,7 +224,7 @@ pub fn check_unstable_api_usage(tcx: &ty::ctxt) -> FnvHashSet<InternedString> {
 struct Checker<'a, 'tcx: 'a> {
     tcx: &'a ty::ctxt<'tcx>,
     active_features: FnvHashSet<InternedString>,
-    used_features: FnvHashSet<InternedString>
+    used_features: FnvHashMap<InternedString, attr::StabilityLevel>
 }
 
 impl<'a, 'tcx> Checker<'a, 'tcx> {
@@ -234,7 +235,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
 
         match *stab {
             Some(Stability { level: attr::Unstable, ref feature, ref reason, .. }) => {
-                self.used_features.insert(feature.clone());
+                self.used_features.insert(feature.clone(), attr::Unstable);
 
                 if !self.active_features.contains(feature) {
                     let msg = match *reason {
@@ -247,7 +248,9 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
                                       feature.get(), span, &msg[]);
                 }
             }
-            Some(..) => {
+            Some(Stability { level, ref feature, .. }) => {
+                self.used_features.insert(feature.clone(), level);
+
                 // Stable APIs are always ok to call and deprecated APIs are
                 // handled by a lint.
             }
@@ -433,17 +436,37 @@ pub fn lookup(tcx: &ty::ctxt, id: DefId) -> Option<Stability> {
 /// Given the list of enabled features that were not language features (i.e. that
 /// were expected to be library features), and the list of features used from
 /// libraries, identify activated features that don't exist and error about them.
-pub fn check_unused_features(sess: &Session,
-                             used_lib_features: &FnvHashSet<InternedString>) {
-    let ref lib_features = sess.features.borrow().lib_features;
-    let mut active_lib_features: FnvHashMap<InternedString, Span>
-        = lib_features.clone().into_iter().collect();
-
-    for used_feature in used_lib_features {
-        active_lib_features.remove(used_feature);
+pub fn check_unused_or_stable_features(sess: &Session,
+                                       lib_features_used: &FnvHashMap<InternedString,
+                                                                      attr::StabilityLevel>) {
+    let ref declared_lib_features = sess.features.borrow().declared_lib_features;
+    let mut remaining_lib_features: FnvHashMap<InternedString, Span>
+        = declared_lib_features.clone().into_iter().collect();
+
+    let stable_msg = "this feature is stable. attribute no longer needed";
+
+    for &span in sess.features.borrow().declared_stable_lang_features.iter() {
+        sess.add_lint(lint::builtin::STABLE_FEATURES,
+                      ast::CRATE_NODE_ID,
+                      span,
+                      stable_msg.to_string());
+    }
+
+    for (used_lib_feature, level) in lib_features_used.iter() {
+        match remaining_lib_features.remove(used_lib_feature) {
+            Some(span) => {
+                if *level == attr::Stable {
+                    sess.add_lint(lint::builtin::STABLE_FEATURES,
+                                  ast::CRATE_NODE_ID,
+                                  span,
+                                  stable_msg.to_string());
+                }
+            }
+            None => ( /* used but undeclared, handled during the previous ast visit */ )
+        }
     }
 
-    for (_, &span) in &active_lib_features {
+    for (_, &span) in remaining_lib_features.iter() {
         sess.add_lint(lint::builtin::UNUSED_FEATURES,
                       ast::CRATE_NODE_ID,
                       span,
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 8ede037594a..8c89f66f7a1 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -668,8 +668,8 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
         time(time_passes, "stability checking", (), |_|
              stability::check_unstable_api_usage(&ty_cx));
 
-    time(time_passes, "unused feature checking", (), |_|
-         stability::check_unused_features(
+    time(time_passes, "unused lib feature checking", (), |_|
+         stability::check_unused_or_stable_features(
              &ty_cx.sess, lib_features_used));
 
     time(time_passes, "lint checking", (), |_|
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index d7a51e1149f..59cdb15296a 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -149,7 +149,10 @@ pub struct Features {
     pub old_orphan_check: bool,
     pub simd_ffi: bool,
     pub unmarked_api: bool,
-    pub lib_features: Vec<(InternedString, Span)>
+    /// spans of #![feature] attrs for stable language features. for error reporting
+    pub declared_stable_lang_features: Vec<Span>,
+    /// #![feature] attrs for non-language (library) features
+    pub declared_lib_features: Vec<(InternedString, Span)>
 }
 
 impl Features {
@@ -162,7 +165,8 @@ impl Features {
             old_orphan_check: false,
             simd_ffi: false,
             unmarked_api: false,
-            lib_features: Vec::new()
+            declared_stable_lang_features: Vec::new(),
+            declared_lib_features: Vec::new()
         }
     }
 }
@@ -511,6 +515,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
         cm: cm,
     };
 
+    let mut accepted_features = Vec::new();
     let mut unknown_features = Vec::new();
 
     for attr in &krate.attrs {
@@ -550,8 +555,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
                             span_handler.span_err(mi.span, "feature has been removed");
                         }
                         Some(&(_, _, Accepted)) => {
-                            span_handler.span_warn(mi.span, "feature has been added to Rust, \
-                                                             directive not necessary");
+                            accepted_features.push(mi.span);
                         }
                         None => {
                             unknown_features.push((name, mi.span));
@@ -572,7 +576,8 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
         old_orphan_check: cx.has_feature("old_orphan_check"),
         simd_ffi: cx.has_feature("simd_ffi"),
         unmarked_api: cx.has_feature("unmarked_api"),
-        lib_features: unknown_features
+        declared_stable_lang_features: accepted_features,
+        declared_lib_features: unknown_features
     }
 }
 
diff --git a/src/test/compile-fail/gated-bad-feature.rs b/src/test/compile-fail/gated-bad-feature.rs
index 39cd3e3b86a..5baafd41531 100644
--- a/src/test/compile-fail/gated-bad-feature.rs
+++ b/src/test/compile-fail/gated-bad-feature.rs
@@ -20,4 +20,3 @@
 #![feature = "foo"] //~ ERROR: malformed feature
 
 #![feature(test_removed_feature)] //~ ERROR: feature has been removed
-#![feature(test_accepted_feature)] //~ WARNING: feature has been added
diff --git a/src/test/compile-fail/stable-features.rs b/src/test/compile-fail/stable-features.rs
new file mode 100644
index 00000000000..30eb4112c3f
--- /dev/null
+++ b/src/test/compile-fail/stable-features.rs
@@ -0,0 +1,20 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Testing that the stable_features lint catches use of stable
+// language and lib features.
+
+#![deny(stable_features)]
+#![feature(test_accepted_feature)] //~ ERROR this feature is stable
+#![feature(rust1)] //~ ERROR this feature is stable
+
+fn main() {
+    let _foo: Vec<()> = Vec::new();
+}