Auto merge of #122227 - Zoxc:query-hash-verify, r=michaelwoerister

Verify that query keys result in unique dep nodes

This implements checking that query keys result into unique dep nodes as mentioned in https://github.com/rust-lang/rust/pull/112469.

We could do a perf check to see how expensive this is.

r? `@michaelwoerister`
This commit is contained in:
bors 2024-03-13 02:01:56 +00:00
commit d3555f3d8e
4 changed files with 56 additions and 2 deletions

View file

@ -321,6 +321,8 @@ pub fn enter<F, T>(&self, f: F) -> T
}
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

View file

@ -41,7 +41,7 @@
#[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;

View file

@ -7,6 +7,7 @@
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<QueryCtxt<'tcx>>,
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<QueryCtxt<'tcx>>,
@ -691,6 +730,13 @@ pub fn encode_query_results<'tcx>(
)
}
}}
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 @@ pub fn dynamic_queries<'tcx>() -> DynamicQueries<'tcx> {
>
] = &[$(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::*;

View file

@ -1674,7 +1674,9 @@ pub(crate) fn parse_function_return(slot: &mut FunctionReturn, v: Option<&str>)
"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<bool> = (None, parse_opt_bool, [TRACKED],
"control whether `#[inline]` functions are in all CGUs"),
inline_llvm: bool = (true, parse_bool, [TRACKED],