about summary refs log tree commit diff
path: root/compiler/rustc_query_system/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_query_system/src')
-rw-r--r--compiler/rustc_query_system/src/dep_graph/dep_node.rs4
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs12
-rw-r--r--compiler/rustc_query_system/src/dep_graph/mod.rs11
-rw-r--r--compiler/rustc_query_system/src/ich/hcx.rs212
-rw-r--r--compiler/rustc_query_system/src/ich/impls_hir.rs155
-rw-r--r--compiler/rustc_query_system/src/ich/impls_syntax.rs146
-rw-r--r--compiler/rustc_query_system/src/ich/mod.rs19
-rw-r--r--compiler/rustc_query_system/src/lib.rs2
-rw-r--r--compiler/rustc_query_system/src/query/config.rs11
9 files changed, 550 insertions, 22 deletions
diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
index 46dc0c720ce..dd500015374 100644
--- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs
@@ -43,10 +43,10 @@
 //!   lost during fingerprint computation.
 
 use super::{DepContext, DepKind};
+use crate::ich::StableHashingContext;
 
 use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-
 use std::fmt;
 use std::hash::Hash;
 
@@ -119,7 +119,7 @@ pub trait DepNodeParams<Ctxt: DepContext>: fmt::Debug + Sized {
 
 impl<Ctxt: DepContext, T> DepNodeParams<Ctxt> for T
 where
-    T: HashStable<Ctxt::StableHashingContext> + fmt::Debug,
+    T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
 {
     #[inline]
     default fn can_reconstruct_query_key() -> bool {
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 23a43771842..114d12fb90b 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -1,3 +1,4 @@
+use parking_lot::Mutex;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::profiling::{EventId, QueryInvocationId, SelfProfilerRef};
@@ -7,8 +8,6 @@ use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
 use rustc_index::vec::IndexVec;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
-
-use parking_lot::Mutex;
 use smallvec::{smallvec, SmallVec};
 use std::collections::hash_map::Entry;
 use std::fmt::Debug;
@@ -19,6 +18,7 @@ use std::sync::atomic::Ordering::Relaxed;
 use super::query::DepGraphQuery;
 use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex};
 use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId};
+use crate::ich::StableHashingContext;
 use crate::query::{QueryContext, QuerySideEffects};
 
 #[cfg(debug_assertions)]
@@ -96,9 +96,9 @@ struct DepGraphData<K: DepKind> {
     dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>,
 }
 
-pub fn hash_result<HashCtxt, R>(hcx: &mut HashCtxt, result: &R) -> Option<Fingerprint>
+pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Option<Fingerprint>
 where
-    R: HashStable<HashCtxt>,
+    R: for<'a> HashStable<StableHashingContext<'a>>,
 {
     let mut stable_hasher = StableHasher::new();
     result.hash_stable(hcx, &mut stable_hasher);
@@ -215,7 +215,7 @@ impl<K: DepKind> DepGraph<K> {
         cx: Ctxt,
         arg: A,
         task: fn(Ctxt, A) -> R,
-        hash_result: fn(&mut Ctxt::StableHashingContext, &R) -> Option<Fingerprint>,
+        hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
     ) -> (R, DepNodeIndex) {
         if self.is_fully_enabled() {
             self.with_task_impl(key, cx, arg, task, hash_result)
@@ -234,7 +234,7 @@ impl<K: DepKind> DepGraph<K> {
         cx: Ctxt,
         arg: A,
         task: fn(Ctxt, A) -> R,
-        hash_result: fn(&mut Ctxt::StableHashingContext, &R) -> Option<Fingerprint>,
+        hash_result: fn(&mut StableHashingContext<'_>, &R) -> Option<Fingerprint>,
     ) -> (R, DepNodeIndex) {
         // This function is only called when the graph is enabled.
         let data = self.data.as_ref().unwrap();
diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs
index b5be1192ce7..2afef210254 100644
--- a/compiler/rustc_query_system/src/dep_graph/mod.rs
+++ b/compiler/rustc_query_system/src/dep_graph/mod.rs
@@ -9,6 +9,7 @@ pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, Wor
 pub use query::DepGraphQuery;
 pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex};
 
+use crate::ich::StableHashingContext;
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sync::Lock;
 use rustc_serialize::{opaque::FileEncoder, Encodable};
@@ -19,10 +20,9 @@ use std::hash::Hash;
 
 pub trait DepContext: Copy {
     type DepKind: self::DepKind;
-    type StableHashingContext;
 
     /// Create a hashing context for hashing new results.
-    fn create_stable_hashing_context(&self) -> Self::StableHashingContext;
+    fn create_stable_hashing_context(&self) -> StableHashingContext<'_>;
 
     /// Access the DepGraph.
     fn dep_graph(&self) -> &DepGraph<Self::DepKind>;
@@ -36,18 +36,13 @@ pub trait DepContext: Copy {
 
 pub trait HasDepContext: Copy {
     type DepKind: self::DepKind;
-    type StableHashingContext;
-    type DepContext: self::DepContext<
-        DepKind = Self::DepKind,
-        StableHashingContext = Self::StableHashingContext,
-    >;
+    type DepContext: self::DepContext<DepKind = Self::DepKind>;
 
     fn dep_context(&self) -> &Self::DepContext;
 }
 
 impl<T: DepContext> HasDepContext for T {
     type DepKind = T::DepKind;
-    type StableHashingContext = T::StableHashingContext;
     type DepContext = Self;
 
     fn dep_context(&self) -> &Self::DepContext {
diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs
new file mode 100644
index 00000000000..f2e935c59fc
--- /dev/null
+++ b/compiler/rustc_query_system/src/ich/hcx.rs
@@ -0,0 +1,212 @@
+use crate::ich;
+use rustc_ast as ast;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::Lrc;
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::definitions::{DefPathHash, Definitions};
+use rustc_session::cstore::CrateStore;
+use rustc_session::Session;
+use rustc_span::source_map::SourceMap;
+use rustc_span::symbol::Symbol;
+use rustc_span::{BytePos, CachingSourceMapView, SourceFile, Span, SpanData};
+
+fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
+    debug_assert!(!ich::IGNORED_ATTRIBUTES.is_empty());
+    ich::IGNORED_ATTRIBUTES.iter().copied().collect()
+}
+
+/// This is the context state available during incr. comp. hashing. It contains
+/// enough information to transform `DefId`s and `HirId`s into stable `DefPath`s (i.e.,
+/// a reference to the `TyCtxt`) and it holds a few caches for speeding up various
+/// things (e.g., each `DefId`/`DefPath` is only hashed once).
+#[derive(Clone)]
+pub struct StableHashingContext<'a> {
+    definitions: &'a Definitions,
+    cstore: &'a dyn CrateStore,
+    pub(super) body_resolver: BodyResolver<'a>,
+    hash_spans: bool,
+    hash_bodies: bool,
+    pub(super) node_id_hashing_mode: NodeIdHashingMode,
+
+    // Very often, we are hashing something that does not need the
+    // `CachingSourceMapView`, so we initialize it lazily.
+    raw_source_map: &'a SourceMap,
+    caching_source_map: Option<CachingSourceMapView<'a>>,
+}
+
+#[derive(PartialEq, Eq, Clone, Copy)]
+pub enum NodeIdHashingMode {
+    Ignore,
+    HashDefPath,
+}
+
+/// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`.
+/// We could also just store a plain reference to the `hir::Crate` but we want
+/// to avoid that the crate is used to get untracked access to all of the HIR.
+#[derive(Clone, Copy)]
+pub(super) struct BodyResolver<'tcx>(&'tcx hir::Crate<'tcx>);
+
+impl<'tcx> BodyResolver<'tcx> {
+    /// Returns a reference to the `hir::Body` with the given `BodyId`.
+    /// **Does not do any tracking**; use carefully.
+    pub(super) fn body(self, id: hir::BodyId) -> &'tcx hir::Body<'tcx> {
+        self.0.body(id)
+    }
+}
+
+impl<'a> StableHashingContext<'a> {
+    /// The `krate` here is only used for mapping `BodyId`s to `Body`s.
+    /// Don't use it for anything else or you'll run the risk of
+    /// leaking data out of the tracking system.
+    #[inline]
+    fn new_with_or_without_spans(
+        sess: &'a Session,
+        krate: &'a hir::Crate<'a>,
+        definitions: &'a Definitions,
+        cstore: &'a dyn CrateStore,
+        always_ignore_spans: bool,
+    ) -> Self {
+        let hash_spans_initial =
+            !always_ignore_spans && !sess.opts.debugging_opts.incremental_ignore_spans;
+
+        StableHashingContext {
+            body_resolver: BodyResolver(krate),
+            definitions,
+            cstore,
+            caching_source_map: None,
+            raw_source_map: sess.source_map(),
+            hash_spans: hash_spans_initial,
+            hash_bodies: true,
+            node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
+        }
+    }
+
+    #[inline]
+    pub fn new(
+        sess: &'a Session,
+        krate: &'a hir::Crate<'a>,
+        definitions: &'a Definitions,
+        cstore: &'a dyn CrateStore,
+    ) -> Self {
+        Self::new_with_or_without_spans(
+            sess,
+            krate,
+            definitions,
+            cstore,
+            /*always_ignore_spans=*/ false,
+        )
+    }
+
+    #[inline]
+    pub fn ignore_spans(
+        sess: &'a Session,
+        krate: &'a hir::Crate<'a>,
+        definitions: &'a Definitions,
+        cstore: &'a dyn CrateStore,
+    ) -> Self {
+        let always_ignore_spans = true;
+        Self::new_with_or_without_spans(sess, krate, definitions, cstore, always_ignore_spans)
+    }
+
+    #[inline]
+    pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self, hash_bodies: bool, f: F) {
+        let prev_hash_bodies = self.hash_bodies;
+        self.hash_bodies = hash_bodies;
+        f(self);
+        self.hash_bodies = prev_hash_bodies;
+    }
+
+    #[inline]
+    pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
+        let prev_hash_spans = self.hash_spans;
+        self.hash_spans = hash_spans;
+        f(self);
+        self.hash_spans = prev_hash_spans;
+    }
+
+    #[inline]
+    pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(
+        &mut self,
+        mode: NodeIdHashingMode,
+        f: F,
+    ) {
+        let prev = self.node_id_hashing_mode;
+        self.node_id_hashing_mode = mode;
+        f(self);
+        self.node_id_hashing_mode = prev;
+    }
+
+    #[inline]
+    pub fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
+        if let Some(def_id) = def_id.as_local() {
+            self.local_def_path_hash(def_id)
+        } else {
+            self.cstore.def_path_hash(def_id)
+        }
+    }
+
+    #[inline]
+    pub fn local_def_path_hash(&self, def_id: LocalDefId) -> DefPathHash {
+        self.definitions.def_path_hash(def_id)
+    }
+
+    #[inline]
+    pub fn hash_bodies(&self) -> bool {
+        self.hash_bodies
+    }
+
+    #[inline]
+    pub fn source_map(&mut self) -> &mut CachingSourceMapView<'a> {
+        match self.caching_source_map {
+            Some(ref mut sm) => sm,
+            ref mut none => {
+                *none = Some(CachingSourceMapView::new(self.raw_source_map));
+                none.as_mut().unwrap()
+            }
+        }
+    }
+
+    #[inline]
+    pub fn is_ignored_attr(&self, name: Symbol) -> bool {
+        thread_local! {
+            static IGNORED_ATTRIBUTES: FxHashSet<Symbol> = compute_ignored_attr_names();
+        }
+        IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
+    }
+}
+
+impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
+    #[inline]
+    fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
+        panic!("Node IDs should not appear in incremental state");
+    }
+}
+
+impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
+    #[inline]
+    fn hash_spans(&self) -> bool {
+        self.hash_spans
+    }
+
+    #[inline]
+    fn def_path_hash(&self, def_id: DefId) -> DefPathHash {
+        self.def_path_hash(def_id)
+    }
+
+    #[inline]
+    fn def_span(&self, def_id: LocalDefId) -> Span {
+        self.definitions.def_span(def_id)
+    }
+
+    #[inline]
+    fn span_data_to_lines_and_cols(
+        &mut self,
+        span: &SpanData,
+    ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
+        self.source_map().span_data_to_lines_and_cols(span)
+    }
+}
+
+impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}
diff --git a/compiler/rustc_query_system/src/ich/impls_hir.rs b/compiler/rustc_query_system/src/ich/impls_hir.rs
new file mode 100644
index 00000000000..04eb263a977
--- /dev/null
+++ b/compiler/rustc_query_system/src/ich/impls_hir.rs
@@ -0,0 +1,155 @@
+//! This module contains `HashStable` implementations for various HIR data
+//! types in no particular order.
+
+use crate::ich::{NodeIdHashingMode, StableHashingContext};
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_hir as hir;
+use rustc_hir::definitions::DefPathHash;
+use smallvec::SmallVec;
+use std::mem;
+
+impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
+    #[inline]
+    fn hash_hir_id(&mut self, hir_id: hir::HirId, hasher: &mut StableHasher) {
+        let hcx = self;
+        match hcx.node_id_hashing_mode {
+            NodeIdHashingMode::Ignore => {
+                // Don't do anything.
+            }
+            NodeIdHashingMode::HashDefPath => {
+                let hir::HirId { owner, local_id } = hir_id;
+
+                hcx.local_def_path_hash(owner).hash_stable(hcx, hasher);
+                local_id.hash_stable(hcx, hasher);
+            }
+        }
+    }
+
+    #[inline]
+    fn hash_body_id(&mut self, id: hir::BodyId, hasher: &mut StableHasher) {
+        let hcx = self;
+        if hcx.hash_bodies() {
+            hcx.body_resolver.body(id).hash_stable(hcx, hasher);
+        }
+    }
+
+    #[inline]
+    fn hash_reference_to_item(&mut self, id: hir::HirId, hasher: &mut StableHasher) {
+        let hcx = self;
+
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            id.hash_stable(hcx, hasher);
+        })
+    }
+
+    #[inline]
+    fn hash_hir_mod(&mut self, module: &hir::Mod<'_>, hasher: &mut StableHasher) {
+        let hcx = self;
+        let hir::Mod { inner: ref inner_span, ref item_ids } = *module;
+
+        inner_span.hash_stable(hcx, hasher);
+
+        // Combining the `DefPathHash`s directly is faster than feeding them
+        // into the hasher. Because we use a commutative combine, we also don't
+        // have to sort the array.
+        let item_ids_hash = item_ids
+            .iter()
+            .map(|id| {
+                let def_path_hash = id.to_stable_hash_key(hcx);
+                def_path_hash.0
+            })
+            .fold(Fingerprint::ZERO, |a, b| a.combine_commutative(b));
+
+        item_ids.len().hash_stable(hcx, hasher);
+        item_ids_hash.hash_stable(hcx, hasher);
+    }
+
+    fn hash_hir_expr(&mut self, expr: &hir::Expr<'_>, hasher: &mut StableHasher) {
+        self.while_hashing_hir_bodies(true, |hcx| {
+            let hir::Expr { hir_id: _, ref span, ref kind } = *expr;
+
+            span.hash_stable(hcx, hasher);
+            kind.hash_stable(hcx, hasher);
+        })
+    }
+
+    fn hash_hir_ty(&mut self, ty: &hir::Ty<'_>, hasher: &mut StableHasher) {
+        self.while_hashing_hir_bodies(true, |hcx| {
+            let hir::Ty { hir_id: _, ref kind, ref span } = *ty;
+
+            kind.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+        })
+    }
+
+    fn hash_hir_visibility_kind(
+        &mut self,
+        vis: &hir::VisibilityKind<'_>,
+        hasher: &mut StableHasher,
+    ) {
+        let hcx = self;
+        mem::discriminant(vis).hash_stable(hcx, hasher);
+        match *vis {
+            hir::VisibilityKind::Public | hir::VisibilityKind::Inherited => {
+                // No fields to hash.
+            }
+            hir::VisibilityKind::Crate(sugar) => {
+                sugar.hash_stable(hcx, hasher);
+            }
+            hir::VisibilityKind::Restricted { ref path, hir_id } => {
+                hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+                    hir_id.hash_stable(hcx, hasher);
+                });
+                path.hash_stable(hcx, hasher);
+            }
+        }
+    }
+
+    #[inline]
+    fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F) {
+        let prev_hash_node_ids = self.node_id_hashing_mode;
+        self.node_id_hashing_mode = NodeIdHashingMode::Ignore;
+
+        f(self);
+
+        self.node_id_hashing_mode = prev_hash_node_ids;
+    }
+}
+
+impl<'a> HashStable<StableHashingContext<'a>> for hir::Body<'_> {
+    #[inline]
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+        let hir::Body { params, value, generator_kind } = self;
+
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::Ignore, |hcx| {
+            params.hash_stable(hcx, hasher);
+            value.hash_stable(hcx, hasher);
+            generator_kind.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+impl<'a> HashStable<StableHashingContext<'a>> for hir::TraitCandidate {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            let hir::TraitCandidate { def_id, import_ids } = self;
+
+            def_id.hash_stable(hcx, hasher);
+            import_ids.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+impl<'a> ToStableHashKey<StableHashingContext<'a>> for hir::TraitCandidate {
+    type KeyType = (DefPathHash, SmallVec<[DefPathHash; 1]>);
+
+    fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Self::KeyType {
+        let hir::TraitCandidate { def_id, import_ids } = self;
+
+        (
+            hcx.def_path_hash(*def_id),
+            import_ids.iter().map(|def_id| hcx.local_def_path_hash(*def_id)).collect(),
+        )
+    }
+}
diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs
new file mode 100644
index 00000000000..acf2990b643
--- /dev/null
+++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs
@@ -0,0 +1,146 @@
+//! This module contains `HashStable` implementations for various data types
+//! from `rustc_ast` in no particular order.
+
+use crate::ich::StableHashingContext;
+
+use rustc_ast as ast;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_span::{BytePos, NormalizedPos, SourceFile};
+use std::assert_matches::assert_matches;
+
+use smallvec::SmallVec;
+
+impl<'ctx> rustc_target::HashStableContext for StableHashingContext<'ctx> {}
+
+impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+        if self.is_empty() {
+            self.len().hash_stable(hcx, hasher);
+            return;
+        }
+
+        // Some attributes are always ignored during hashing.
+        let filtered: SmallVec<[&ast::Attribute; 8]> = self
+            .iter()
+            .filter(|attr| {
+                !attr.is_doc_comment()
+                    && !attr.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name))
+            })
+            .collect();
+
+        filtered.len().hash_stable(hcx, hasher);
+        for attr in filtered {
+            attr.hash_stable(hcx, hasher);
+        }
+    }
+}
+
+impl<'ctx> rustc_ast::HashStableContext for StableHashingContext<'ctx> {
+    fn hash_attr(&mut self, attr: &ast::Attribute, hasher: &mut StableHasher) {
+        // Make sure that these have been filtered out.
+        debug_assert!(!attr.ident().map_or(false, |ident| self.is_ignored_attr(ident.name)));
+        debug_assert!(!attr.is_doc_comment());
+
+        let ast::Attribute { kind, id: _, style, span } = attr;
+        if let ast::AttrKind::Normal(item, tokens) = kind {
+            item.hash_stable(self, hasher);
+            style.hash_stable(self, hasher);
+            span.hash_stable(self, hasher);
+            assert_matches!(
+                tokens.as_ref(),
+                None,
+                "Tokens should have been removed during lowering!"
+            );
+        } else {
+            unreachable!();
+        }
+    }
+}
+
+impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
+        let SourceFile {
+            name: _, // We hash the smaller name_hash instead of this
+            name_hash,
+            cnum,
+            // Do not hash the source as it is not encoded
+            src: _,
+            ref src_hash,
+            external_src: _,
+            start_pos,
+            end_pos: _,
+            ref lines,
+            ref multibyte_chars,
+            ref non_narrow_chars,
+            ref normalized_pos,
+        } = *self;
+
+        (name_hash as u64).hash_stable(hcx, hasher);
+
+        src_hash.hash_stable(hcx, hasher);
+
+        // We only hash the relative position within this source_file
+        lines.len().hash_stable(hcx, hasher);
+        for &line in lines.iter() {
+            stable_byte_pos(line, start_pos).hash_stable(hcx, hasher);
+        }
+
+        // We only hash the relative position within this source_file
+        multibyte_chars.len().hash_stable(hcx, hasher);
+        for &char_pos in multibyte_chars.iter() {
+            stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher);
+        }
+
+        non_narrow_chars.len().hash_stable(hcx, hasher);
+        for &char_pos in non_narrow_chars.iter() {
+            stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher);
+        }
+
+        normalized_pos.len().hash_stable(hcx, hasher);
+        for &char_pos in normalized_pos.iter() {
+            stable_normalized_pos(char_pos, start_pos).hash_stable(hcx, hasher);
+        }
+
+        cnum.hash_stable(hcx, hasher);
+    }
+}
+
+fn stable_byte_pos(pos: BytePos, source_file_start: BytePos) -> u32 {
+    pos.0 - source_file_start.0
+}
+
+fn stable_multibyte_char(mbc: rustc_span::MultiByteChar, source_file_start: BytePos) -> (u32, u32) {
+    let rustc_span::MultiByteChar { pos, bytes } = mbc;
+
+    (pos.0 - source_file_start.0, bytes as u32)
+}
+
+fn stable_non_narrow_char(
+    swc: rustc_span::NonNarrowChar,
+    source_file_start: BytePos,
+) -> (u32, u32) {
+    let pos = swc.pos();
+    let width = swc.width();
+
+    (pos.0 - source_file_start.0, width as u32)
+}
+
+fn stable_normalized_pos(np: NormalizedPos, source_file_start: BytePos) -> (u32, u32) {
+    let NormalizedPos { pos, diff } = np;
+
+    (pos.0 - source_file_start.0, diff)
+}
+
+impl<'tcx> HashStable<StableHashingContext<'tcx>> for rustc_feature::Features {
+    fn hash_stable(&self, hcx: &mut StableHashingContext<'tcx>, hasher: &mut StableHasher) {
+        // Unfortunately we cannot exhaustively list fields here, since the
+        // struct is macro generated.
+        self.declared_lang_features.hash_stable(hcx, hasher);
+        self.declared_lib_features.hash_stable(hcx, hasher);
+
+        self.walk_feature_fields(|feature_name, value| {
+            feature_name.hash_stable(hcx, hasher);
+            value.hash_stable(hcx, hasher);
+        });
+    }
+}
diff --git a/compiler/rustc_query_system/src/ich/mod.rs b/compiler/rustc_query_system/src/ich/mod.rs
new file mode 100644
index 00000000000..54416902e5f
--- /dev/null
+++ b/compiler/rustc_query_system/src/ich/mod.rs
@@ -0,0 +1,19 @@
+//! ICH - Incremental Compilation Hash
+
+pub use self::hcx::{NodeIdHashingMode, StableHashingContext};
+use rustc_span::symbol::{sym, Symbol};
+
+mod hcx;
+mod impls_hir;
+mod impls_syntax;
+
+pub const IGNORED_ATTRIBUTES: &[Symbol] = &[
+    sym::cfg,
+    sym::rustc_if_this_changed,
+    sym::rustc_then_this_would_need,
+    sym::rustc_dirty,
+    sym::rustc_clean,
+    sym::rustc_partition_reused,
+    sym::rustc_partition_codegened,
+    sym::rustc_expected_cgu_reuse,
+];
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index c205f0fb531..bc23de069b0 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -1,3 +1,4 @@
+#![feature(assert_matches)]
 #![feature(bool_to_option)]
 #![feature(core_intrinsics)]
 #![feature(hash_raw_entry)]
@@ -14,4 +15,5 @@ extern crate rustc_macros;
 
 pub mod cache;
 pub mod dep_graph;
+pub mod ich;
 pub mod query;
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index d1e527dff98..76a165ed8e6 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -2,6 +2,7 @@
 
 use crate::dep_graph::DepNode;
 use crate::dep_graph::SerializedDepNodeIndex;
+use crate::ich::StableHashingContext;
 use crate::query::caches::QueryCache;
 use crate::query::{QueryCacheStore, QueryContext, QueryState};
 
@@ -23,7 +24,7 @@ pub(crate) struct QueryVtable<CTX: QueryContext, K, V> {
     pub dep_kind: CTX::DepKind,
     pub eval_always: bool,
 
-    pub hash_result: fn(&mut CTX::StableHashingContext, &V) -> Option<Fingerprint>,
+    pub hash_result: fn(&mut StableHashingContext<'_>, &V) -> Option<Fingerprint>,
     pub handle_cycle_error: fn(CTX, DiagnosticBuilder<'_>) -> V,
     pub cache_on_disk: fn(CTX, &K, Option<&V>) -> bool,
     pub try_load_from_disk: fn(CTX, SerializedDepNodeIndex) -> Option<V>,
@@ -39,7 +40,7 @@ impl<CTX: QueryContext, K, V> QueryVtable<CTX, K, V> {
 
     pub(crate) fn hash_result(
         &self,
-        hcx: &mut CTX::StableHashingContext,
+        hcx: &mut StableHashingContext<'_>,
         value: &V,
     ) -> Option<Fingerprint> {
         (self.hash_result)(hcx, value)
@@ -74,10 +75,8 @@ pub trait QueryAccessors<CTX: QueryContext>: QueryConfig {
     // Don't use this method to compute query results, instead use the methods on TyCtxt
     fn compute_fn(tcx: CTX, key: &Self::Key) -> fn(CTX::DepContext, Self::Key) -> Self::Value;
 
-    fn hash_result(
-        hcx: &mut CTX::StableHashingContext,
-        result: &Self::Value,
-    ) -> Option<Fingerprint>;
+    fn hash_result(hcx: &mut StableHashingContext<'_>, result: &Self::Value)
+    -> Option<Fingerprint>;
 
     fn handle_cycle_error(tcx: CTX, diag: DiagnosticBuilder<'_>) -> Self::Value;
 }