]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc/middle/stability.rs
Auto merge of #53444 - varkor:lib_features-conditional, r=michaelwoerister
[rust.git] / src / librustc / middle / stability.rs
index 262a617cb6924c9b7651d9d0fc3227db0db4c927..85195b0f62e7cf58aeaaaaf3e8b55e4880c7f38f 100644 (file)
 use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
 use ty::{self, TyCtxt};
 use middle::privacy::AccessLevels;
-use session::DiagnosticMessageId;
+use session::{DiagnosticMessageId, Session};
 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};
 
@@ -685,7 +685,7 @@ pub fn check_stability(self, def_id: DefId, id: Option<NodeId>, span: Span) {
                 };
 
                 let msp: MultiSpan = span.into();
-                let cm = &self.sess.parse_sess.codemap();
+                let cm = &self.sess.parse_sess.source_map();
                 let span_key = msp.primary_span().and_then(|sp: Span|
                     if !sp.is_dummy() {
                         let file = cm.lookup_char_pos(sp.lo()).file;
@@ -780,7 +780,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
         intravisit::walk_item(self, item);
     }
 
-    fn visit_path(&mut self, path: &'tcx hir::Path, id: ast::NodeId) {
+    fn visit_path(&mut self, path: &'tcx hir::Path, id: hir::HirId) {
+        let id = self.tcx.hir.hir_to_node_id(id);
         match path.def {
             Def::Local(..) | Def::Upvar(..) |
             Def::PrimTy(..) | Def::SelfTy(..) | Def::Err => {}
@@ -813,37 +814,90 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         krate.visit_all_item_likes(&mut missing.as_deep_visitor());
     }
 
-    let ref declared_lib_features = tcx.features().declared_lib_features;
-    let mut remaining_lib_features: FxHashMap<Symbol, Span>
-        = declared_lib_features.clone().into_iter().collect();
-    remaining_lib_features.remove(&Symbol::intern("proc_macro"));
-
-    for &(ref stable_lang_feature, span) in &tcx.features().declared_stable_lang_features {
-        let version = 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(version));
-    }
-
-    // FIXME(#44232) the `used_features` table no longer exists, so we don't
-    //               lint about unknown or unused features. We should reenable
-    //               this one day!
-    //
-    // let index = tcx.stability();
-    // for (used_lib_feature, level) in &index.used_features {
-    //     remaining_lib_features.remove(used_lib_feature);
-    // }
-    //
-    // for &span in remaining_lib_features.values() {
-    //     tcx.lint_node(lint::builtin::UNUSED_FEATURES,
-    //                   ast::CRATE_NODE_ID,
-    //                   span,
-    //                   "unused or unknown feature");
-    // }
+    let declared_lang_features = &tcx.features().declared_lang_features;
+    let mut lang_features = FxHashSet();
+    for &(feature, span, since) in declared_lang_features {
+        if let Some(since) = since {
+            // Warn if the user has enabled an already-stable lang feature.
+            unnecessary_stable_feature_lint(tcx, span, feature, since);
+        }
+        if lang_features.contains(&feature) {
+            // Warn if the user enables a lang feature multiple times.
+            duplicate_feature_err(tcx.sess, span, 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 {
+        if remaining_lib_features.contains_key(&feature) {
+            // Warn if the user enables a lib feature multiple times.
+            duplicate_feature_err(tcx.sess, *span, *feature);
+        }
+        remaining_lib_features.insert(feature, span.clone());
+    }
+    // `stdbuild` has special handling for `libc`, so we need to
+    // recognise the feature when building std.
+    // Likewise, libtest is handled specially, so `test` isn't
+    // available as we'd like it to be.
+    // FIXME: only remove `libc` when `stdbuild` is active.
+    // FIXME: remove special casing for `test`.
+    remaining_lib_features.remove(&Symbol::intern("libc"));
+    remaining_lib_features.remove(&Symbol::intern("test"));
+
+    let check_features =
+        |remaining_lib_features: &mut FxHashMap<_, _>, defined_features: &Vec<_>| {
+            for &(feature, since) in defined_features {
+                if let Some(since) = since {
+                    if let Some(span) = remaining_lib_features.get(&feature) {
+                        // Warn if the user has enabled an already-stable lib feature.
+                        unnecessary_stable_feature_lint(tcx, *span, feature, since);
+                    }
+                }
+                remaining_lib_features.remove(&feature);
+                if remaining_lib_features.is_empty() {
+                    break;
+                }
+            }
+        };
+
+    // We always collect the lib features declared in the current crate, even if there are
+    // no unknown features, because the collection also does feature attribute validation.
+    let local_defined_features = tcx.lib_features().to_vec();
+    if !remaining_lib_features.is_empty() {
+        check_features(&mut remaining_lib_features, &local_defined_features);
+
+        for &cnum in &*tcx.crates() {
+            if remaining_lib_features.is_empty() {
+                break;
+            }
+            check_features(&mut remaining_lib_features, &tcx.defined_lib_features(cnum));
+        }
+    }
+
+    for (feature, span) in remaining_lib_features {
+        struct_span_err!(tcx.sess, span, E0635, "unknown feature `{}`", feature).emit();
+    }
+
+    // FIXME(#44232): the `used_features` table no longer exists, so we
+    // don't lint about unused features. We should reenable this one day!
+}
+
+fn unnecessary_stable_feature_lint<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    span: Span,
+    feature: Symbol,
+    since: Symbol
+) {
+    tcx.lint_node(lint::builtin::STABLE_FEATURES,
+        ast::CRATE_NODE_ID,
+        span,
+        &format!("the feature `{}` has been stable since {} and no longer requires \
+                  an attribute to enable", feature, since));
 }
 
-fn format_stable_since_msg(version: &str) -> String {
-    format!("this feature has been stable since {}. Attribute no longer needed", version)
+fn duplicate_feature_err(sess: &Session, span: Span, feature: Symbol) {
+    struct_span_err!(sess, span, E0636, "the feature `{}` has already been declared", feature)
+        .emit();
 }