about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2017-08-31 15:08:34 -0700
committerAlex Crichton <alex@alexcrichton.com>2017-09-05 07:37:58 -0700
commit9a231961d59135c7dc41d9b94ffe43ecc9bbd8cb (patch)
treecada5b4f27f31664a7d877c3084e3a417307b4a8
parent0182c8bbda094c7a6abf89b6c45185ba1e5d38b3 (diff)
downloadrust-9a231961d59135c7dc41d9b94ffe43ecc9bbd8cb.tar.gz
rust-9a231961d59135c7dc41d9b94ffe43ecc9bbd8cb.zip
rustc: Move stability functionality into queries
This commit primarily removes the `stability` field from `TyCtxt` as well as its
internal mutable state, instead using a query to build the stability index as
well as primarily using queries for other related lookups.

Like previous commits the calculation of the stability index is wrapped in a
`with_ignore` node to avoid regressing the current tests, and otherwise this
commit also introduces #44232 but somewhat intentionally so.
-rw-r--r--src/librustc/dep_graph/dep_node.rs5
-rw-r--r--src/librustc/hir/map/mod.rs12
-rw-r--r--src/librustc/middle/stability.rs246
-rw-r--r--src/librustc/ty/context.rs29
-rw-r--r--src/librustc/ty/maps.rs69
-rw-r--r--src/librustc_driver/driver.rs7
-rw-r--r--src/librustc_metadata/cstore_impl.rs12
-rw-r--r--src/test/compile-fail/feature-gate/issue-43106-gating-of-builtin-attrs.rs3
-rw-r--r--src/test/compile-fail/lint-output-format-2.rs8
-rw-r--r--src/test/compile-fail/lint-unknown-feature-default.rs8
-rw-r--r--src/test/compile-fail/lint-unknown-feature.rs10
-rw-r--r--src/test/compile-fail/stable-features.rs5
12 files changed, 212 insertions, 202 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 431680eb36a..810355dc2c0 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -511,8 +511,8 @@ define_dep_nodes!( <'tcx>
     [] ParamEnv(DefId),
     [] DescribeDef(DefId),
     [] DefSpan(DefId),
-    [] Stability(DefId),
-    [] Deprecation(DefId),
+    [] LookupStability(DefId),
+    [] LookupDeprecationEntry(DefId),
     [] ItemBodyNestedBodies(DefId),
     [] ConstIsRvaluePromotableToStatic(DefId),
     [] ImplParent(DefId),
@@ -573,6 +573,7 @@ define_dep_nodes!( <'tcx>
     [] Freevars(HirId),
     [] MaybeUnusedTraitImport(HirId),
     [] MaybeUnusedExternCrates,
+    [] StabilityIndex,
 );
 
 trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index e54df2d50d8..d043d8346e6 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -878,7 +878,17 @@ impl<'hir> Map<'hir> {
 
             Some(RootCrate(_)) => self.forest.krate.span,
             Some(NotPresent) | None => {
-                bug!("hir::map::Map::span: id not in map: {:?}", id)
+                // Some nodes, notably macro definitions, are not
+                // present in the map for whatever reason, but
+                // they *do* have def-ids. So if we encounter an
+                // empty hole, check for that case.
+                if let Some(def_index) = self.definitions.opt_def_index(id) {
+                    let def_path_hash = self.definitions.def_path_hash(def_index);
+                    self.dep_graph.read(def_path_hash.to_dep_node(DepKind::Hir));
+                    DUMMY_SP
+                } else {
+                    bug!("hir::map::Map::span: id not in map: {:?}", id)
+                }
             }
         }
     }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 6d7d028d286..ecf3aab05d8 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -15,20 +15,19 @@ pub use self::StabilityLevel::*;
 
 use lint;
 use hir::def::Def;
-use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, DefIndex, LOCAL_CRATE};
+use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
 use ty::{self, TyCtxt};
 use middle::privacy::AccessLevels;
-use session::Session;
 use syntax::symbol::Symbol;
 use syntax_pos::{Span, DUMMY_SP};
 use syntax::ast;
 use syntax::ast::{NodeId, Attribute};
 use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version};
 use syntax::attr::{self, Stability, Deprecation};
-use util::nodemap::{DefIdMap, FxHashSet, FxHashMap};
+use util::nodemap::{FxHashSet, FxHashMap};
 
 use hir;
-use hir::{Item, Generics, StructField, Variant};
+use hir::{Item, Generics, StructField, Variant, HirId};
 use hir::intravisit::{self, Visitor, NestedVisitorMap};
 
 use std::mem::replace;
@@ -63,19 +62,18 @@ pub struct DeprecationEntry {
     pub attr: Deprecation,
     /// The def id where the attr was originally attached. `None` for non-local
     /// `DefId`'s.
-    origin: Option<DefIndex>,
+    origin: Option<HirId>,
 }
 
 impl DeprecationEntry {
-    fn local(attr: Deprecation, id: DefId) -> DeprecationEntry {
-        assert!(id.is_local());
+    fn local(attr: Deprecation, id: HirId) -> DeprecationEntry {
         DeprecationEntry {
             attr,
-            origin: Some(id.index),
+            origin: Some(id),
         }
     }
 
-    fn external(attr: Deprecation) -> DeprecationEntry {
+    pub fn external(attr: Deprecation) -> DeprecationEntry {
         DeprecationEntry {
             attr,
             origin: None,
@@ -94,17 +92,14 @@ impl DeprecationEntry {
 pub struct Index<'tcx> {
     /// This is mostly a cache, except the stabilities of local items
     /// are filled by the annotator.
-    stab_map: DefIdMap<Option<&'tcx Stability>>,
-    depr_map: DefIdMap<Option<DeprecationEntry>>,
+    stab_map: FxHashMap<HirId, &'tcx Stability>,
+    depr_map: FxHashMap<HirId, DeprecationEntry>,
 
     /// Maps for each crate whether it is part of the staged API.
     staged_api: FxHashMap<CrateNum, bool>,
 
     /// Features enabled for this crate.
     active_features: FxHashSet<Symbol>,
-
-    /// Features used by this crate. Updated before and during typeck.
-    used_features: FxHashMap<Symbol, attr::StabilityLevel>
 }
 
 // A private tree-walker for producing an Index.
@@ -178,8 +173,8 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
                     }
                 }
 
-                let def_id = self.tcx.hir.local_def_id(id);
-                self.index.stab_map.insert(def_id, Some(stab));
+                let hir_id = self.tcx.hir.node_to_hir_id(id);
+                self.index.stab_map.insert(hir_id, stab);
 
                 let orig_parent_stab = replace(&mut self.parent_stab, Some(stab));
                 visit_children(self);
@@ -188,8 +183,8 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
                 debug!("annotate: not found, parent = {:?}", self.parent_stab);
                 if let Some(stab) = self.parent_stab {
                     if stab.level.is_unstable() {
-                        let def_id = self.tcx.hir.local_def_id(id);
-                        self.index.stab_map.insert(def_id, Some(stab));
+                        let hir_id = self.tcx.hir.node_to_hir_id(id);
+                        self.index.stab_map.insert(hir_id, stab);
                     }
                 }
                 visit_children(self);
@@ -209,8 +204,8 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
             // -Zforce-unstable-if-unmarked is set.
             if let Some(stab) = self.parent_stab {
                 if stab.level.is_unstable() {
-                    let def_id = self.tcx.hir.local_def_id(id);
-                    self.index.stab_map.insert(def_id, Some(stab));
+                    let hir_id = self.tcx.hir.node_to_hir_id(id);
+                    self.index.stab_map.insert(hir_id, stab);
                 }
             }
 
@@ -220,16 +215,17 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
                 }
 
                 // `Deprecation` is just two pointers, no need to intern it
-                let def_id = self.tcx.hir.local_def_id(id);
-                let depr_entry = Some(DeprecationEntry::local(depr, def_id));
-                self.index.depr_map.insert(def_id, depr_entry.clone());
+                let hir_id = self.tcx.hir.node_to_hir_id(id);
+                let depr_entry = DeprecationEntry::local(depr, hir_id);
+                self.index.depr_map.insert(hir_id, depr_entry.clone());
 
-                let orig_parent_depr = replace(&mut self.parent_depr, depr_entry);
+                let orig_parent_depr = replace(&mut self.parent_depr,
+                                               Some(depr_entry));
                 visit_children(self);
                 self.parent_depr = orig_parent_depr;
-            } else if let parent_depr @ Some(_) = self.parent_depr.clone() {
-                let def_id = self.tcx.hir.local_def_id(id);
-                self.index.depr_map.insert(def_id, parent_depr);
+            } else if let Some(parent_depr) = self.parent_depr.clone() {
+                let hir_id = self.tcx.hir.node_to_hir_id(id);
+                self.index.depr_map.insert(hir_id, parent_depr);
                 visit_children(self);
             } else {
                 visit_children(self);
@@ -322,10 +318,10 @@ struct MissingStabilityAnnotations<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx: 'a> MissingStabilityAnnotations<'a, 'tcx> {
     fn check_missing_stability(&self, id: NodeId, span: Span) {
-        let def_id = self.tcx.hir.local_def_id(id);
-        let stab = self.tcx.stability.borrow().stab_map.get(&def_id).cloned();
+        let hir_id = self.tcx.hir.node_to_hir_id(id);
+        let stab = self.tcx.stability().local_stability(hir_id);
         let is_error = !self.tcx.sess.opts.test &&
-                        (stab == None || stab == Some(None)) &&
+                        stab.is_none() &&
                         self.access_levels.is_reachable(id);
         if is_error {
             self.tcx.sess.span_err(span, "This node does not have a stability attribute");
@@ -386,60 +382,70 @@ impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Index<'tcx> {
-    /// Construct the stability index for a crate being compiled.
-    pub fn build(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Index<'tcx> {
+        let is_staged_api =
+            tcx.sess.opts.debugging_opts.force_unstable_if_unmarked ||
+            tcx.sess.features.borrow().staged_api;
+        let mut staged_api = FxHashMap();
+        staged_api.insert(LOCAL_CRATE, is_staged_api);
+        let mut index = Index {
+            staged_api,
+            stab_map: FxHashMap(),
+            depr_map: FxHashMap(),
+            active_features: FxHashSet(),
+        };
+
         let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features;
 
         // Put the active features into a map for quick lookup
-        self.active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect();
+        index.active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect();
+
+        {
+            let krate = tcx.hir.krate();
+            let mut annotator = Annotator {
+                tcx,
+                index: &mut index,
+                parent_stab: None,
+                parent_depr: None,
+                in_trait_impl: false,
+            };
 
-        let krate = tcx.hir.krate();
-        let mut annotator = Annotator {
-            tcx,
-            index: self,
-            parent_stab: None,
-            parent_depr: None,
-            in_trait_impl: false,
-        };
+            // If the `-Z force-unstable-if-unmarked` flag is passed then we provide
+            // a parent stability annotation which indicates that this is private
+            // with the `rustc_private` feature. This is intended for use when
+            // compiling librustc crates themselves so we can leverage crates.io
+            // while maintaining the invariant that all sysroot crates are unstable
+            // by default and are unable to be used.
+            if tcx.sess.opts.debugging_opts.force_unstable_if_unmarked {
+                let reason = "this crate is being loaded from the sysroot, and \
+                              unstable location; did you mean to load this crate \
+                              from crates.io via `Cargo.toml` instead?";
+                let stability = tcx.intern_stability(Stability {
+                    level: attr::StabilityLevel::Unstable {
+                        reason: Some(Symbol::intern(reason)),
+                        issue: 27812,
+                    },
+                    feature: Symbol::intern("rustc_private"),
+                    rustc_depr: None,
+                });
+                annotator.parent_stab = Some(stability);
+            }
 
-        // If the `-Z force-unstable-if-unmarked` flag is passed then we provide
-        // a parent stability annotation which indicates that this is private
-        // with the `rustc_private` feature. This is intended for use when
-        // compiling librustc crates themselves so we can leverage crates.io
-        // while maintaining the invariant that all sysroot crates are unstable
-        // by default and are unable to be used.
-        if tcx.sess.opts.debugging_opts.force_unstable_if_unmarked {
-            let reason = "this crate is being loaded from the sysroot, and \
-                          unstable location; did you mean to load this crate \
-                          from crates.io via `Cargo.toml` instead?";
-            let stability = tcx.intern_stability(Stability {
-                level: attr::StabilityLevel::Unstable {
-                    reason: Some(Symbol::intern(reason)),
-                    issue: 27812,
-                },
-                feature: Symbol::intern("rustc_private"),
-                rustc_depr: None,
-            });
-            annotator.parent_stab = Some(stability);
+            annotator.annotate(ast::CRATE_NODE_ID,
+                               &krate.attrs,
+                               krate.span,
+                               AnnotationKind::Required,
+                               |v| intravisit::walk_crate(v, krate));
         }
+        return index
+    }
 
-        annotator.annotate(ast::CRATE_NODE_ID, &krate.attrs, krate.span, AnnotationKind::Required,
-                           |v| intravisit::walk_crate(v, krate));
+    pub fn local_stability(&self, id: HirId) -> Option<&'tcx Stability> {
+        self.stab_map.get(&id).cloned()
     }
 
-    pub fn new(sess: &Session) -> Index<'tcx> {
-        let is_staged_api =
-            sess.opts.debugging_opts.force_unstable_if_unmarked ||
-            sess.features.borrow().staged_api;
-        let mut staged_api = FxHashMap();
-        staged_api.insert(LOCAL_CRATE, is_staged_api);
-        Index {
-            staged_api,
-            stab_map: DefIdMap(),
-            depr_map: DefIdMap(),
-            active_features: FxHashSet(),
-            used_features: FxHashMap(),
-        }
+    pub fn local_deprecation_entry(&self, id: HirId) -> Option<DeprecationEntry> {
+        self.depr_map.get(&id).cloned()
     }
 }
 
@@ -547,10 +553,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             return
         }
 
-        if let Some(&Stability { ref level, ref feature, .. }) = stability {
-            self.stability.borrow_mut().used_features.insert(feature.clone(), level.clone());
-        }
-
         // Issue 38412: private items lack stability markers.
         if self.skip_stability_check_due_to_privacy(def_id) {
             return
@@ -558,7 +560,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 
         match stability {
             Some(&Stability { level: attr::Unstable {ref reason, issue}, ref feature, .. }) => {
-                if self.stability.borrow().active_features.contains(feature) {
+                if self.stability().active_features.contains(feature) {
                     return
                 }
 
@@ -672,49 +674,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    /// Lookup the stability for a node, loading external crate
-    /// metadata as necessary.
-    pub fn lookup_stability(self, id: DefId) -> Option<&'gcx Stability> {
-        if let Some(st) = self.stability.borrow().stab_map.get(&id) {
-            return *st;
-        }
-
-        let st = self.lookup_stability_uncached(id);
-        self.stability.borrow_mut().stab_map.insert(id, st);
-        st
-    }
-
     pub fn lookup_deprecation(self, id: DefId) -> Option<Deprecation> {
         self.lookup_deprecation_entry(id).map(|depr| depr.attr)
     }
-
-    pub fn lookup_deprecation_entry(self, id: DefId) -> Option<DeprecationEntry> {
-        if let Some(depr) = self.stability.borrow().depr_map.get(&id) {
-            return depr.clone();
-        }
-
-        let depr = self.lookup_deprecation_uncached(id);
-        self.stability.borrow_mut().depr_map.insert(id, depr.clone());
-        depr
-    }
-
-    fn lookup_stability_uncached(self, id: DefId) -> Option<&'gcx Stability> {
-        debug!("lookup(id={:?})", id);
-        if id.is_local() {
-            None // The stability cache is filled partially lazily
-        } else {
-            self.stability(id).map(|st| self.intern_stability(st))
-        }
-    }
-
-    fn lookup_deprecation_uncached(self, id: DefId) -> Option<DeprecationEntry> {
-        debug!("lookup(id={:?})", id);
-        if id.is_local() {
-            None // The stability cache is filled partially lazily
-        } else {
-            self.deprecation(id).map(DeprecationEntry::external)
-        }
-    }
 }
 
 /// Given the list of enabled features that were not language features (i.e. that
@@ -725,7 +687,7 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
 
     let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
 
-    if tcx.stability.borrow().staged_api[&LOCAL_CRATE] {
+    if tcx.stability().staged_api[&LOCAL_CRATE] {
         let krate = tcx.hir.krate();
         let mut missing = MissingStabilityAnnotations {
             tcx,
@@ -741,10 +703,6 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         = declared_lib_features.clone().into_iter().collect();
     remaining_lib_features.remove(&Symbol::intern("proc_macro"));
 
-    fn format_stable_since_msg(version: &str) -> String {
-        format!("this feature has been stable since {}. Attribute no longer needed", version)
-    }
-
     for &(ref stable_lang_feature, span) in &sess.features.borrow().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");
@@ -754,25 +712,23 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
                       &format_stable_since_msg(version));
     }
 
-    let index = tcx.stability.borrow();
-    for (used_lib_feature, level) in &index.used_features {
-        match remaining_lib_features.remove(used_lib_feature) {
-            Some(span) => {
-                if let &attr::StabilityLevel::Stable { since: ref version } = level {
-                    tcx.lint_node(lint::builtin::STABLE_FEATURES,
-                                  ast::CRATE_NODE_ID,
-                                  span,
-                                  &format_stable_since_msg(&version.as_str()));
-                }
-            }
-            None => ( /* used but undeclared, handled during the previous ast visit */ )
-        }
-    }
+    // 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");
+    // }
+}
 
-    for &span in remaining_lib_features.values() {
-        tcx.lint_node(lint::builtin::UNUSED_FEATURES,
-                      ast::CRATE_NODE_ID,
-                      span,
-                      "unused or unknown feature");
-    }
+fn format_stable_since_msg(version: &str) -> String {
+    format!("this feature has been stable since {}. Attribute no longer needed", version)
 }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 2104e789812..10918d702d7 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -855,9 +855,6 @@ pub struct GlobalCtxt<'tcx> {
     /// about.
     pub used_mut_nodes: RefCell<NodeSet>,
 
-    /// Maps any item's def-id to its stability index.
-    pub stability: RefCell<stability::Index<'tcx>>,
-
     /// Caches the results of trait selection. This cache is used
     /// for things that do not have to do with the parameters in scope.
     pub selection_cache: traits::SelectionCache<'tcx>,
@@ -989,7 +986,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                                   resolutions: ty::Resolutions,
                                   named_region_map: resolve_lifetime::NamedRegionMap,
                                   hir: hir_map::Map<'tcx>,
-                                  stability: stability::Index<'tcx>,
                                   crate_name: &str,
                                   f: F) -> R
                                   where F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'tcx>) -> R
@@ -1086,7 +1082,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             normalized_cache: RefCell::new(FxHashMap()),
             inhabitedness_cache: RefCell::new(FxHashMap()),
             used_mut_nodes: RefCell::new(NodeSet()),
-            stability: RefCell::new(stability),
             selection_cache: traits::SelectionCache::new(),
             evaluation_cache: traits::EvaluationCache::new(),
             rvalue_promotable_to_static: RefCell::new(NodeMap()),
@@ -1118,6 +1113,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             self.get_lang_items(LOCAL_CRATE)
         })
     }
+
+    pub fn stability(self) -> Rc<stability::Index<'tcx>> {
+        self.dep_graph.with_ignore(|| {
+            self.stability_index(LOCAL_CRATE)
+        })
+    }
 }
 
 impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> {
@@ -2012,6 +2013,9 @@ struct NamedRegionMap {
 }
 
 pub fn provide(providers: &mut ty::maps::Providers) {
+    // FIXME(#44234) - almost all of these queries have no sub-queries and
+    // therefore no actual inputs, they're just reading tables calculated in
+    // resolve! Does this work? Unsure! That's what the issue is about
     providers.in_scope_traits = |tcx, id| tcx.gcx.trait_map.get(&id).cloned();
     providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).cloned();
     providers.named_region = |tcx, id| tcx.gcx.named_region_map.defs.get(&id).cloned();
@@ -2035,4 +2039,19 @@ pub fn provide(providers: &mut ty::maps::Providers) {
         assert_eq!(cnum, LOCAL_CRATE);
         Rc::new(tcx.maybe_unused_extern_crates.clone())
     };
+
+    providers.stability_index = |tcx, cnum| {
+        assert_eq!(cnum, LOCAL_CRATE);
+        Rc::new(stability::Index::new(tcx))
+    };
+    providers.lookup_stability = |tcx, id| {
+        assert_eq!(id.krate, LOCAL_CRATE);
+        let id = tcx.hir.definitions().def_index_to_hir_id(id.index);
+        tcx.stability().local_stability(id)
+    };
+    providers.lookup_deprecation_entry = |tcx, id| {
+        assert_eq!(id.krate, LOCAL_CRATE);
+        let id = tcx.hir.definitions().def_index_to_hir_id(id.index);
+        tcx.stability().local_deprecation_entry(id)
+    };
 }
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index ef21a3d56fe..65d70bb9fd0 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -22,6 +22,7 @@ use middle::privacy::AccessLevels;
 use middle::region;
 use middle::region::RegionMaps;
 use middle::resolve_lifetime::{Region, ObjectLifetimeDefault};
+use middle::stability::{self, DeprecationEntry};
 use middle::lang_items::{LanguageItems, LangItem};
 use mir;
 use mir::transform::{MirSuite, MirPassIndex};
@@ -434,13 +435,13 @@ impl<'tcx> QueryDescription for queries::def_span<'tcx> {
 }
 
 
-impl<'tcx> QueryDescription for queries::stability<'tcx> {
+impl<'tcx> QueryDescription for queries::lookup_stability<'tcx> {
     fn describe(_: TyCtxt, _: DefId) -> String {
         bug!("stability")
     }
 }
 
-impl<'tcx> QueryDescription for queries::deprecation<'tcx> {
+impl<'tcx> QueryDescription for queries::lookup_deprecation_entry<'tcx> {
     fn describe(_: TyCtxt, _: DefId) -> String {
         bug!("deprecation")
     }
@@ -748,6 +749,12 @@ impl<'tcx> QueryDescription for queries::maybe_unused_extern_crates<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription for queries::stability_index<'tcx> {
+    fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+        format!("calculating the stability index for the local crate")
+    }
+}
+
 // If enabled, send a message to the profile-queries thread
 macro_rules! profq_msg {
     ($tcx:expr, $msg:expr) => {
@@ -1272,8 +1279,8 @@ define_maps! { <'tcx>
 
     [] fn describe_def: DescribeDef(DefId) -> Option<Def>,
     [] fn def_span: DefSpan(DefId) -> Span,
-    [] fn stability: Stability(DefId) -> Option<attr::Stability>,
-    [] fn deprecation: Deprecation(DefId) -> Option<attr::Deprecation>,
+    [] fn lookup_stability: LookupStability(DefId) -> Option<&'tcx attr::Stability>,
+    [] fn lookup_deprecation_entry: LookupDeprecationEntry(DefId) -> Option<DeprecationEntry>,
     [] fn item_attrs: ItemAttrs(DefId) -> Rc<[ast::Attribute]>,
     [] fn fn_arg_names: FnArgNames(DefId) -> Vec<ast::Name>,
     [] fn impl_parent: ImplParent(DefId) -> Option<DefId>,
@@ -1337,37 +1344,39 @@ define_maps! { <'tcx>
     [] fn all_trait_implementations: AllTraitImplementations(CrateNum)
         -> Rc<Vec<DefId>>,
 
-    [] is_dllimport_foreign_item: IsDllimportForeignItem(DefId) -> bool,
-    [] is_statically_included_foreign_item: IsStaticallyIncludedForeignItem(DefId) -> bool,
-    [] native_library_kind: NativeLibraryKind(DefId)
+    [] fn is_dllimport_foreign_item: IsDllimportForeignItem(DefId) -> bool,
+    [] fn is_statically_included_foreign_item: IsStaticallyIncludedForeignItem(DefId) -> bool,
+    [] fn native_library_kind: NativeLibraryKind(DefId)
         -> Option<NativeLibraryKind>,
-    [] link_args: link_args_node(CrateNum) -> Rc<Vec<String>>,
+    [] fn link_args: link_args_node(CrateNum) -> Rc<Vec<String>>,
 
-    [] named_region: NamedRegion(HirId) -> Option<Region>,
-    [] is_late_bound: IsLateBound(HirId) -> bool,
-    [] object_lifetime_defaults: ObjectLifetimeDefaults(HirId)
+    [] fn named_region: NamedRegion(HirId) -> Option<Region>,
+    [] fn is_late_bound: IsLateBound(HirId) -> bool,
+    [] fn object_lifetime_defaults: ObjectLifetimeDefaults(HirId)
         -> Option<Rc<Vec<ObjectLifetimeDefault>>>,
 
-    [] visibility: Visibility(DefId) -> ty::Visibility,
-    [] dep_kind: DepKind(CrateNum) -> DepKind,
-    [] crate_name: CrateName(CrateNum) -> Symbol,
-    [] item_children: ItemChildren(DefId) -> Rc<Vec<Export>>,
-    [] extern_mod_stmt_cnum: ExternModStmtCnum(HirId) -> Option<CrateNum>,
-
-    [] get_lang_items: get_lang_items_node(CrateNum) -> Rc<LanguageItems>,
-    [] defined_lang_items: DefinedLangItems(CrateNum) -> Rc<Vec<(DefIndex, usize)>>,
-    [] missing_lang_items: MissingLangItems(CrateNum) -> Rc<Vec<LangItem>>,
-    [] extern_const_body: ExternConstBody(DefId) -> &'tcx hir::Body,
-    [] visible_parent_map: visible_parent_map_node(CrateNum)
+    [] fn visibility: Visibility(DefId) -> ty::Visibility,
+    [] fn dep_kind: DepKind(CrateNum) -> DepKind,
+    [] fn crate_name: CrateName(CrateNum) -> Symbol,
+    [] fn item_children: ItemChildren(DefId) -> Rc<Vec<Export>>,
+    [] fn extern_mod_stmt_cnum: ExternModStmtCnum(HirId) -> Option<CrateNum>,
+
+    [] fn get_lang_items: get_lang_items_node(CrateNum) -> Rc<LanguageItems>,
+    [] fn defined_lang_items: DefinedLangItems(CrateNum) -> Rc<Vec<(DefIndex, usize)>>,
+    [] fn missing_lang_items: MissingLangItems(CrateNum) -> Rc<Vec<LangItem>>,
+    [] fn extern_const_body: ExternConstBody(DefId) -> &'tcx hir::Body,
+    [] fn visible_parent_map: visible_parent_map_node(CrateNum)
         -> Rc<DefIdMap<DefId>>,
-    [] missing_extern_crate_item: MissingExternCrateItem(CrateNum) -> bool,
-    [] used_crate_source: UsedCrateSource(CrateNum) -> Rc<CrateSource>,
-    [] postorder_cnums: postorder_cnums_node(CrateNum) -> Rc<Vec<CrateNum>>,
+    [] fn missing_extern_crate_item: MissingExternCrateItem(CrateNum) -> bool,
+    [] fn used_crate_source: UsedCrateSource(CrateNum) -> Rc<CrateSource>,
+    [] fn postorder_cnums: postorder_cnums_node(CrateNum) -> Rc<Vec<CrateNum>>,
 
-    [] freevars: Freevars(HirId) -> Option<Rc<Vec<hir::Freevar>>>,
-    [] maybe_unused_trait_import: MaybeUnusedTraitImport(HirId) -> bool,
-    [] maybe_unused_extern_crates: maybe_unused_extern_crates_node(CrateNum)
+    [] fn freevars: Freevars(HirId) -> Option<Rc<Vec<hir::Freevar>>>,
+    [] fn maybe_unused_trait_import: MaybeUnusedTraitImport(HirId) -> bool,
+    [] fn maybe_unused_extern_crates: maybe_unused_extern_crates_node(CrateNum)
         -> Rc<Vec<(HirId, Span)>>,
+
+    [] fn stability_index: stability_index_node(CrateNum) -> Rc<stability::Index<'tcx>>,
 }
 
 fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
@@ -1473,3 +1482,7 @@ fn postorder_cnums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
 fn maybe_unused_extern_crates_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
     DepConstructor::MaybeUnusedExternCrates
 }
+
+fn stability_index_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
+    DepConstructor::StabilityIndex
+}
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index afd89f70992..b4dde2120a8 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -934,8 +934,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
               "static item recursion checking",
               || static_recursion::check_crate(sess, &hir_map))?;
 
-    let index = stability::Index::new(&sess);
-
     let mut local_providers = ty::maps::Providers::default();
     borrowck::provide(&mut local_providers);
     mir::provide(&mut local_providers);
@@ -1022,7 +1020,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
                              resolutions,
                              named_region_map,
                              hir_map,
-                             index,
                              name,
                              |tcx| {
         let incremental_hashes_map =
@@ -1034,10 +1031,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
              "load_dep_graph",
              || rustc_incremental::load_dep_graph(tcx, &incremental_hashes_map));
 
-        time(time_passes, "stability index", || {
-            tcx.stability.borrow_mut().build(tcx)
-        });
-
         time(time_passes,
              "stability checking",
              || stability::check_unstable_api_usage(tcx));
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 58ca22f7bf3..dbb188e923a 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -19,6 +19,7 @@ use rustc::middle::cstore::{CrateStore, DepKind,
                             MetadataLoader, LinkMeta,
                             LoadedMacro, EncodedMetadata,
                             EncodedMetadataHashes, NativeLibraryKind};
+use rustc::middle::stability::DeprecationEntry;
 use rustc::hir::def;
 use rustc::session::Session;
 use rustc::ty::{self, TyCtxt};
@@ -142,8 +143,12 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     is_default_impl => { cdata.is_default_impl(def_id.index) }
     describe_def => { cdata.get_def(def_id.index) }
     def_span => { cdata.get_span(def_id.index, &tcx.sess) }
-    stability => { cdata.get_stability(def_id.index) }
-    deprecation => { cdata.get_deprecation(def_id.index) }
+    lookup_stability => {
+        cdata.get_stability(def_id.index).map(|s| tcx.intern_stability(s))
+    }
+    lookup_deprecation_entry => {
+        cdata.get_deprecation(def_id.index).map(DeprecationEntry::external)
+    }
     item_attrs => { cdata.get_item_attrs(def_id.index, &tcx.dep_graph) }
     // FIXME(#38501) We've skipped a `read` on the `HirBody` of
     // a `fn` when encoding, so the dep-tracking wouldn't work.
@@ -242,6 +247,9 @@ pub fn provide_local<'tcx>(providers: &mut Providers<'tcx>) {
         }
     }
 
+    // FIXME(#44234) - almost all of these queries have no sub-queries and
+    // therefore no actual inputs, they're just reading tables calculated in
+    // resolve! Does this work? Unsure! That's what the issue is about
     *providers = Providers {
         is_const_fn,
         is_dllimport_foreign_item: |tcx, id| {
diff --git a/src/test/compile-fail/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/compile-fail/feature-gate/issue-43106-gating-of-builtin-attrs.rs
index 6eec1779a2d..06b87206669 100644
--- a/src/test/compile-fail/feature-gate/issue-43106-gating-of-builtin-attrs.rs
+++ b/src/test/compile-fail/feature-gate/issue-43106-gating-of-builtin-attrs.rs
@@ -99,7 +99,8 @@
 
 // For #![crate_id], see issue #43142. (I cannot bear to enshrine current behavior in a test)
 
-#![feature                    ( x0600)] //~ WARN unused or unknown feature
+// FIXME(#44232) we should warn that this isn't used.
+#![feature                    ( x0600)]
 
 // For #![no_start], see issue #43144. (I cannot bear to enshrine current behavior in a test)
 
diff --git a/src/test/compile-fail/lint-output-format-2.rs b/src/test/compile-fail/lint-output-format-2.rs
index 0e68ff752e5..ef072d4bbb3 100644
--- a/src/test/compile-fail/lint-output-format-2.rs
+++ b/src/test/compile-fail/lint-output-format-2.rs
@@ -8,21 +8,21 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags: -F unused_features
 // aux-build:lint_output_format.rs
 
+// FIXME(#44232) we should warn that this isn't used.
 #![feature(foo)]
-//~^ ERROR unused or unknown feature
-//~| NOTE requested on the command line with `-F unused-features`
 
 #![feature(test_feature)]
+#![feature(rustc_attrs)]
 
 extern crate lint_output_format;
 use lint_output_format::{foo, bar};
 //~^ WARNING use of deprecated item: text
 //~| NOTE #[warn(deprecated)] on by default
 
-fn main() {
+#[rustc_error]
+fn main() { //~ ERROR: compilation successful
     let _x = foo();
     //~^ WARNING use of deprecated item: text
     //~| NOTE #[warn(deprecated)] on by default
diff --git a/src/test/compile-fail/lint-unknown-feature-default.rs b/src/test/compile-fail/lint-unknown-feature-default.rs
index afd1a3933bf..79ba3ea45e1 100644
--- a/src/test/compile-fail/lint-unknown-feature-default.rs
+++ b/src/test/compile-fail/lint-unknown-feature-default.rs
@@ -10,8 +10,10 @@
 
 // Tests the default for the unused_features lint
 
-#![deny(warnings)]
+// FIXME(#44232) we should warn that this isn't used.
+#![feature(this_is_not_a_feature)]
 
-#![feature(this_is_not_a_feature)] //~ ERROR: unused or unknown feature
+#![feature(rustc_attrs)]
 
-fn main() { }
+#[rustc_error]
+fn main() { } //~ ERROR: compilation successful
diff --git a/src/test/compile-fail/lint-unknown-feature.rs b/src/test/compile-fail/lint-unknown-feature.rs
index ac1720b339e..d230297aaba 100644
--- a/src/test/compile-fail/lint-unknown-feature.rs
+++ b/src/test/compile-fail/lint-unknown-feature.rs
@@ -8,8 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![deny(unused_features)]
+#![warn(unused_features)]
 
-#![feature(this_is_not_a_feature)] //~ ERROR: unused or unknown feature
+// FIXME(#44232) we should warn that this isn't used.
+#![feature(this_is_not_a_feature)]
 
-fn main() {}
+#![feature(rustc_attrs)]
+
+#[rustc_error]
+fn main() {} //~ ERROR: compilation successful
diff --git a/src/test/compile-fail/stable-features.rs b/src/test/compile-fail/stable-features.rs
index 6f8c95c3840..5993f4b5a09 100644
--- a/src/test/compile-fail/stable-features.rs
+++ b/src/test/compile-fail/stable-features.rs
@@ -12,8 +12,11 @@
 // language and lib features.
 
 #![deny(stable_features)]
+
 #![feature(test_accepted_feature)] //~ ERROR this feature has been stable since 1.0.0
-#![feature(rust1)] //~ ERROR this feature has been stable since 1.0.0
+
+// FIXME(#44232) we should error that this isn't used.
+#![feature(rust1)]
 
 fn main() {
     let _foo: Vec<()> = Vec::new();