Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ use std::sync::Arc;
use rustc_abi::Align;
use rustc_arena::TypedArena;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::steal::Steal;
Expand All @@ -88,9 +87,7 @@ use rustc_index::IndexVec;
use rustc_lint_defs::LintId;
use rustc_macros::rustc_queries;
use rustc_query_system::ich::StableHashingContext;
use rustc_query_system::query::{
QueryCache, QueryMode, QueryStackDeferred, QueryState, try_get_cached,
};
use rustc_query_system::query::{QueryMode, QueryStackDeferred, QueryState};
use rustc_session::Limits;
use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
use rustc_session::cstore::{
Expand Down
114 changes: 70 additions & 44 deletions compiler/rustc_middle/src/query/plumbing.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
use std::fmt::Debug;
use std::ops::Deref;

use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sync::{AtomicU64, WorkerLocal};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::hir_id::OwnerId;
use rustc_macros::HashStable;
use rustc_query_system::HandleCycleError;
use rustc_query_system::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
use rustc_query_system::dep_graph::{DepNodeIndex, DepNodeParams, SerializedDepNodeIndex};
use rustc_query_system::ich::StableHashingContext;
pub(crate) use rustc_query_system::query::QueryJobId;
use rustc_query_system::query::*;
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
pub use sealed::IntoQueryParam;

use super::erase::EraseType;
use crate::dep_graph;
use crate::dep_graph::DepKind;
use crate::query::erase::{Erase, restore};
use crate::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache};
use crate::query::{
DynamicQueries, ExternProviders, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates,
Expand Down Expand Up @@ -565,53 +571,77 @@ macro_rules! define_feedable {

let tcx = self.tcx;
let erased = queries::$name::provided_to_erased(tcx, value);
let value = restore::<$V>(erased);
let cache = &tcx.query_system.caches.$name;

let name: &'static str = stringify!($name);
let dep_kind: dep_graph::DepKind = dep_graph::dep_kinds::$name;
let hasher: Option<fn(&mut StableHashingContext<'_>, &_) -> _> = hash_result!([$($modifiers)*]);
match try_get_cached(tcx, cache, &key) {
Some(old) => {
let old = restore::<$V>(old);
if let Some(hasher) = hasher {
let (value_hash, old_hash): (Fingerprint, Fingerprint) = tcx.with_stable_hashing_context(|mut hcx|
(hasher(&mut hcx, &value), hasher(&mut hcx, &old))
);
if old_hash != value_hash {
// We have an inconsistency. This can happen if one of the two
// results is tainted by errors. In this case, delay a bug to
// ensure compilation is doomed, and keep the `old` value.
tcx.dcx().delayed_bug(format!(
"Trying to feed an already recorded value for query {} key={key:?}:\n\
old value: {old:?}\nnew value: {value:?}",
stringify!($name),
));
}
} else {
// The query is `no_hash`, so we have no way to perform a sanity check.
// If feeding the same value multiple times needs to be supported,
// the query should not be marked `no_hash`.
bug!(
"Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}",
stringify!($name),
)
}
}
None => {
let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::dep_kinds::$name, &key);
let dep_node_index = tcx.dep_graph.with_feed_task(
dep_node,
tcx,
&value,
hash_result!([$($modifiers)*]),
);
cache.complete(key, erased, dep_node_index);
}
}

$crate::query::plumbing::query_feed_inner(
tcx,
name,
dep_kind,
hasher,
cache,
key,
erased,
);
}
})*
}
}

/// Common implementation of query feeding, used by `define_feedable!`.
pub(crate) fn query_feed_inner<'tcx, Cache, Value>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you put this closer to query_get_at and co? It serves a similar purpose.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, the downside would be that it's no longer adjacent to the calling code in define_feedable!, so coordinated changes to both would be much less convenient.

I can move it if you want, but to me it seems better off here.

tcx: TyCtxt<'tcx>,
name: &'static str,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be recoverable from dep_kind in a panic message.

Copy link
Contributor Author

@Zalathar Zalathar Oct 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, via tcx.dep_kind_info(dep_kind).name? That should be easy enough.

dep_kind: DepKind,
hasher: Option<fn(&mut StableHashingContext<'_>, &Value) -> Fingerprint>,
cache: &Cache,
key: Cache::Key,
erased: Erase<Value>,
) where
Cache: QueryCache<Value = Erase<Value>>,
Cache::Key: DepNodeParams<TyCtxt<'tcx>>,
Value: EraseType + Debug,
{
let value = restore::<Value>(erased);

match try_get_cached(tcx, cache, &key) {
Some(old) => {
let old = restore::<Value>(old);
if let Some(hasher) = hasher {
let (value_hash, old_hash): (Fingerprint, Fingerprint) = tcx
.with_stable_hashing_context(|mut hcx| {
(hasher(&mut hcx, &value), hasher(&mut hcx, &old))
});
if old_hash != value_hash {
// We have an inconsistency. This can happen if one of the two
// results is tainted by errors. In this case, delay a bug to
// ensure compilation is doomed, and keep the `old` value.
tcx.dcx().delayed_bug(format!(
"Trying to feed an already recorded value for query {name} key={key:?}:\n\
old value: {old:?}\nnew value: {value:?}",
));
}
} else {
// The query is `no_hash`, so we have no way to perform a sanity check.
// If feeding the same value multiple times needs to be supported,
// the query should not be marked `no_hash`.
bug!(
"Trying to feed an already recorded value for query {name} key={key:?}:\n\
old value: {old:?}\nnew value: {value:?}",
)
}
}
None => {
let dep_node = dep_graph::DepNode::construct(tcx, dep_kind, &key);
let dep_node_index = tcx.dep_graph.with_feed_task(dep_node, tcx, &value, hasher);
cache.complete(key, erased, dep_node_index);
}
}
}

// Each of these queries corresponds to a function pointer field in the
// `Providers` struct for requesting a value of that type, and a method
// on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way
Expand Down Expand Up @@ -694,10 +724,6 @@ mod sealed {
}
}

pub use sealed::IntoQueryParam;

use super::erase::EraseType;

#[derive(Copy, Clone, Debug, HashStable)]
pub struct CyclePlaceholder(pub ErrorGuaranteed);

Expand Down
Loading