From 9f2c6b0b09c1f93f922f6fcd46649c3e2110f42b Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sat, 29 Oct 2022 13:04:38 +0000 Subject: [PATCH] Sanity check computed value for feeable queries. --- compiler/rustc_macros/src/query.rs | 9 +++++++++ compiler/rustc_query_impl/src/plumbing.rs | 13 +++++++++++++ .../rustc_query_system/src/query/config.rs | 5 +++-- .../rustc_query_system/src/query/plumbing.rs | 18 +++++++++++++++++- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 30c42757dbe..4047969724a 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -359,6 +359,15 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { }); if modifiers.feedable.is_some() { + assert!(modifiers.anon.is_none(), "Query {name} cannot be both `feedable` and `anon`."); + assert!( + modifiers.eval_always.is_none(), + "Query {name} cannot be both `feedable` and `eval_always`." + ); + assert!( + modifiers.no_hash.is_none(), + "Query {name} cannot be both `feedable` and `no_hash`." + ); feedable_queries.extend(quote! { #(#doc_comments)* [#attribute_stream] fn #name(#arg) #result, diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index e69f6aa3a93..8d5d84c5db4 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -252,6 +252,18 @@ macro_rules! depth_limit { }; } +macro_rules! feedable { + ([]) => {{ + false + }}; + ([(feedable) $($rest:tt)*]) => {{ + true + }}; + ([$other:tt $($modifiers:tt)*]) => { + feedable!([$($modifiers)*]) + }; +} + macro_rules! hash_result { ([]) => {{ Some(dep_graph::hash_result) @@ -491,6 +503,7 @@ macro_rules! define_queries { anon: is_anon!([$($modifiers)*]), eval_always: is_eval_always!([$($modifiers)*]), depth_limit: depth_limit!([$($modifiers)*]), + feedable: feedable!([$($modifiers)*]), dep_kind: dep_graph::DepKind::$name, hash_result: hash_result!([$($modifiers)*]), handle_cycle_error: handle_cycle_error!([$($modifiers)*]), diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index f40e174b7e7..7d1b62ab102 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -15,8 +15,8 @@ pub trait QueryConfig { const NAME: &'static str; type Key: Eq + Hash + Clone + Debug; - type Value; - type Stored: Clone; + type Value: Debug; + type Stored: Debug + Clone + std::borrow::Borrow; type Cache: QueryCache; @@ -45,6 +45,7 @@ pub struct QueryVTable { pub dep_kind: Qcx::DepKind, pub eval_always: bool, pub depth_limit: bool, + pub feedable: bool, pub compute: fn(Qcx::DepContext, K) -> V, pub hash_result: Option, &V) -> Fingerprint>, diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index eb5a35b3449..848fa67e3df 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -20,6 +20,7 @@ use rustc_data_structures::sync::Lock; use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, FatalError}; use rustc_session::Session; use rustc_span::{Span, DUMMY_SP}; +use std::borrow::Borrow; use std::cell::Cell; use std::collections::hash_map::Entry; use std::fmt::Debug; @@ -370,11 +371,26 @@ where C: QueryCache, C::Key: Clone + DepNodeParams, C::Value: Value, + C::Stored: Debug + std::borrow::Borrow, Qcx: QueryContext, { match JobOwner::<'_, C::Key>::try_start(&qcx, state, span, key.clone()) { TryGetJob::NotYetStarted(job) => { - let (result, dep_node_index) = execute_job(qcx, key, dep_node, query, job.id); + let (result, dep_node_index) = execute_job(qcx, key.clone(), dep_node, query, job.id); + if query.feedable { + // We may have put a value inside the cache from inside the execution. + // Verify that it has the same hash as what we have now, to ensure consistency. + let _ = cache.lookup(&key, |cached_result, _| { + let hasher = query.hash_result.expect("feedable forbids no_hash"); + let old_hash = qcx.dep_context().with_stable_hashing_context(|mut hcx| hasher(&mut hcx, cached_result.borrow())); + let new_hash = qcx.dep_context().with_stable_hashing_context(|mut hcx| hasher(&mut hcx, &result)); + debug_assert_eq!( + old_hash, new_hash, + "Computed query value for {:?}({:?}) is inconsistent with fed value,\ncomputed={:#?}\nfed={:#?}", + query.dep_kind, key, result, cached_result, + ); + }); + } let result = job.complete(cache, result, dep_node_index); (result, Some(dep_node_index)) }