diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index da11d090b74..c2218822696 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -321,6 +321,8 @@ impl Compiler { } self.sess.time("serialize_dep_graph", || gcx.enter(rustc_incremental::save_dep_graph)); + + gcx.enter(rustc_query_impl::query_key_hash_verify_all); } // The timer's lifetime spans the dropping of `queries`, which contains diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 33116737a42..52767155532 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -41,7 +41,7 @@ use rustc_span::{ErrorGuaranteed, Span}; #[macro_use] mod plumbing; -pub use crate::plumbing::QueryCtxt; +pub use crate::plumbing::{query_key_hash_verify_all, QueryCtxt}; mod profiling_support; pub use self::profiling_support::alloc_self_profile_query_strings; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index b06d75be390..aa965779731 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -7,6 +7,7 @@ use crate::rustc_middle::ty::TyEncoder; use crate::QueryConfigRestored; use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_data_structures::sync::Lock; +use rustc_data_structures::unord::UnordMap; use rustc_errors::DiagInner; use rustc_index::Idx; @@ -189,6 +190,16 @@ pub(super) fn encode_all_query_results<'tcx>( } } +pub fn query_key_hash_verify_all<'tcx>(tcx: TyCtxt<'tcx>) { + if tcx.sess().opts.unstable_opts.incremental_verify_ich || cfg!(debug_assertions) { + tcx.sess.time("query_key_hash_verify_all", || { + for verify in super::QUERY_KEY_HASH_VERIFY.iter() { + verify(tcx); + } + }) + } +} + macro_rules! handle_cycle_error { ([]) => {{ rustc_query_system::HandleCycleError::Error @@ -370,6 +381,34 @@ pub(crate) fn encode_query_results<'a, 'tcx, Q>( }); } +pub(crate) fn query_key_hash_verify<'tcx>( + query: impl QueryConfig>, + qcx: QueryCtxt<'tcx>, +) { + let _timer = + qcx.profiler().generic_activity_with_arg("query_key_hash_verify_for", query.name()); + + let mut map = UnordMap::default(); + + let cache = query.query_cache(qcx); + cache.iter(&mut |key, _, _| { + let node = DepNode::construct(qcx.tcx, query.dep_kind(), key); + if let Some(other_key) = map.insert(node, *key) { + bug!( + "query key:\n\ + `{:?}`\n\ + and key:\n\ + `{:?}`\n\ + mapped to the same dep node:\n\ + {:?}", + key, + other_key, + node + ); + } + }); +} + fn try_load_from_on_disk_cache<'tcx, Q>(query: Q, tcx: TyCtxt<'tcx>, dep_node: DepNode) where Q: QueryConfig>, @@ -691,6 +730,13 @@ macro_rules! define_queries { ) } }} + + pub fn query_key_hash_verify<'tcx>(tcx: TyCtxt<'tcx>) { + $crate::plumbing::query_key_hash_verify( + query_impl::$name::QueryType::config(tcx), + QueryCtxt::new(tcx), + ) + } })*} pub(crate) fn engine(incremental: bool) -> QueryEngine { @@ -730,6 +776,10 @@ macro_rules! define_queries { > ] = &[$(expand_if_cached!([$($modifiers)*], query_impl::$name::encode_query_results)),*]; + const QUERY_KEY_HASH_VERIFY: &[ + for<'tcx> fn(TyCtxt<'tcx>) + ] = &[$(query_impl::$name::query_key_hash_verify),*]; + #[allow(nonstandard_style)] mod query_callbacks { use super::*; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index ea4b8f2463e..f713e8911c8 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1674,7 +1674,9 @@ options! { "print high-level information about incremental reuse (or the lack thereof) \ (default: no)"), incremental_verify_ich: bool = (false, parse_bool, [UNTRACKED], - "verify incr. comp. hashes of green query instances (default: no)"), + "verify extended properties for incr. comp. (default: no): + - hashes of green query instances + - hash collisions of query keys"), inline_in_all_cgus: Option = (None, parse_opt_bool, [TRACKED], "control whether `#[inline]` functions are in all CGUs"), inline_llvm: bool = (true, parse_bool, [TRACKED],