diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 1ad9bbc3b4b30..0cac699e5b626 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -280,31 +280,21 @@ fn add_query_desc_cached_impl( let crate::query::Providers { #name: _, .. }; }; - // Find out if we should cache the query on disk - let cache = if let Some((args, expr)) = modifiers.cache.as_ref() { + // Generate a function to check whether we should cache the query to disk, for some key. + if let Some((args, expr)) = modifiers.cache.as_ref() { let tcx = args.as_ref().map(|t| quote! { #t }).unwrap_or_else(|| quote! { _ }); // expr is a `Block`, meaning that `{ #expr }` gets expanded // to `{ { stmts... } }`, which triggers the `unused_braces` lint. // we're taking `key` by reference, but some rustc types usually prefer being passed by value - quote! { + cached.extend(quote! { #[allow(unused_variables, unused_braces, rustc::pass_by_value)] #[inline] pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::query::queries::#name::Key<'tcx>) -> bool { #ra_hint #expr } - } - } else { - quote! { - // we're taking `key` by reference, but some rustc types usually prefer being passed by value - #[allow(rustc::pass_by_value)] - #[inline] - pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::query::queries::#name::Key<'tcx>) -> bool { - #ra_hint - false - } - } - }; + }); + } let (tcx, desc) = &modifiers.desc; let tcx = tcx.as_ref().map_or_else(|| quote! { _ }, |t| quote! { #t }); @@ -322,10 +312,6 @@ fn add_query_desc_cached_impl( descs.extend(quote! { #desc }); - - cached.extend(quote! { - #cache - }); } pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 0e536352563f4..f1704d5a84ee3 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -18,6 +18,18 @@ use crate::query::{ }; use crate::ty::TyCtxt; +pub type WillCacheOnDiskForKeyFn<'tcx, Key> = fn(tcx: TyCtxt<'tcx>, key: &Key) -> bool; + +pub type TryLoadFromDiskFn<'tcx, Key, Value> = fn( + tcx: TyCtxt<'tcx>, + key: &Key, + prev_index: SerializedDepNodeIndex, + index: DepNodeIndex, +) -> Option; + +pub type IsLoadableFromDiskFn<'tcx, Key> = + fn(tcx: TyCtxt<'tcx>, key: &Key, index: SerializedDepNodeIndex) -> bool; + /// Stores function pointers and other metadata for a particular query. /// /// Used indirectly by query plumbing in `rustc_query_system`, via a trait. @@ -31,18 +43,11 @@ pub struct QueryVTable<'tcx, C: QueryCache> { pub query_state: usize, // Offset of this query's cache field in the QueryCaches struct pub query_cache: usize, - pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool, + pub will_cache_on_disk_for_key_fn: Option>, pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value, pub compute: fn(tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value, - pub can_load_from_disk: bool, - pub try_load_from_disk: fn( - tcx: TyCtxt<'tcx>, - key: &C::Key, - prev_index: SerializedDepNodeIndex, - index: DepNodeIndex, - ) -> Option, - pub loadable_from_disk: - fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool, + pub try_load_from_disk_fn: Option>, + pub is_loadable_from_disk_fn: Option>, pub hash_result: HashResult, pub value_from_cycle_error: fn(tcx: TyCtxt<'tcx>, cycle_error: &CycleError, guar: ErrorGuaranteed) -> C::Value, diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index d6310b62b2759..7618893d0f23e 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -82,8 +82,8 @@ where } #[inline(always)] - fn cache_on_disk(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool { - (self.vtable.cache_on_disk)(tcx, key) + fn will_cache_on_disk_for_key(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool { + self.vtable.will_cache_on_disk_for_key_fn.map_or(false, |f| f(tcx, key)) } #[inline(always)] @@ -132,21 +132,18 @@ where prev_index: SerializedDepNodeIndex, index: DepNodeIndex, ) -> Option { - if self.vtable.can_load_from_disk { - (self.vtable.try_load_from_disk)(qcx.tcx, key, prev_index, index) - } else { - None - } + // `?` will return None immediately for queries that never cache to disk. + self.vtable.try_load_from_disk_fn?(qcx.tcx, key, prev_index, index) } #[inline] - fn loadable_from_disk( + fn is_loadable_from_disk( self, qcx: QueryCtxt<'tcx>, key: &Self::Key, index: SerializedDepNodeIndex, ) -> bool { - (self.vtable.loadable_from_disk)(qcx.tcx, key, index) + self.vtable.is_loadable_from_disk_fn.map_or(false, |f| f(qcx.tcx, key, index)) } fn value_from_cycle_error( diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 0223981fd55dc..231db14647e3a 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -400,7 +400,7 @@ pub(crate) fn encode_query_results<'a, 'tcx, Q>( assert!(query.query_state(qcx).all_inactive()); let cache = query.query_cache(qcx); cache.iter(&mut |key, value, dep_node| { - if query.cache_on_disk(qcx.tcx, key) { + if query.will_cache_on_disk_for_key(qcx.tcx, key) { let dep_node = SerializedDepNodeIndex::new(dep_node.index()); // Record position of the cache entry. @@ -449,7 +449,7 @@ where let key = Q::Key::recover(tcx, &dep_node).unwrap_or_else(|| { panic!("Failed to recover key for {:?} with hash {}", dep_node, dep_node.hash) }); - if query.cache_on_disk(tcx, &key) { + if query.will_cache_on_disk_for_key(tcx, &key) { let _ = query.execute_query(tcx, key); } } @@ -651,7 +651,11 @@ macro_rules! define_queries { cycle_error_handling: cycle_error_handling!([$($modifiers)*]), query_state: std::mem::offset_of!(QueryStates<'tcx>, $name), query_cache: std::mem::offset_of!(QueryCaches<'tcx>, $name), - cache_on_disk: |tcx, key| ::rustc_middle::query::cached::$name(tcx, key), + will_cache_on_disk_for_key_fn: should_ever_cache_on_disk!([$($modifiers)*] { + Some(::rustc_middle::query::cached::$name) + } { + None + }), execute_query: |tcx, key| erase(tcx.$name(key)), compute: |tcx, key| { #[cfg(debug_assertions)] @@ -669,37 +673,34 @@ macro_rules! define_queries { ) ) }, - can_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] true false), - try_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] { - |tcx, key, prev_index, index| { - if ::rustc_middle::query::cached::$name(tcx, key) { - let value = $crate::plumbing::try_load_from_disk::< - queries::$name::ProvidedValue<'tcx> - >( - tcx, - prev_index, - index, - ); - value.map(|value| queries::$name::provided_to_erased(tcx, value)) - } else { - None + try_load_from_disk_fn: should_ever_cache_on_disk!([$($modifiers)*] { + Some(|tcx, key, prev_index, index| { + // Check the `cache_on_disk_if` condition for this key. + if !::rustc_middle::query::cached::$name(tcx, key) { + return None; } - } + + let value: queries::$name::ProvidedValue<'tcx> = + $crate::plumbing::try_load_from_disk(tcx, prev_index, index)?; + + // Arena-alloc the value if appropriate, and erase it. + Some(queries::$name::provided_to_erased(tcx, value)) + }) } { - |_tcx, _key, _prev_index, _index| None + None + }), + is_loadable_from_disk_fn: should_ever_cache_on_disk!([$($modifiers)*] { + Some(|tcx, key, index| -> bool { + ::rustc_middle::query::cached::$name(tcx, key) && + $crate::plumbing::loadable_from_disk(tcx, index) + }) + } { + None }), value_from_cycle_error: |tcx, cycle, guar| { let result: queries::$name::Value<'tcx> = Value::from_cycle_error(tcx, cycle, guar); erase(result) }, - loadable_from_disk: |_tcx, _key, _index| { - should_ever_cache_on_disk!([$($modifiers)*] { - ::rustc_middle::query::cached::$name(_tcx, _key) && - $crate::plumbing::loadable_from_disk(_tcx, _index) - } { - false - }) - }, hash_result: hash_result!([$($modifiers)*][queries::$name::Value<'tcx>]), format_value: |value| format!("{:?}", restore::>(*value)), } diff --git a/compiler/rustc_query_system/src/query/dispatcher.rs b/compiler/rustc_query_system/src/query/dispatcher.rs index 1ca76a70364c9..dc2879b0264d9 100644 --- a/compiler/rustc_query_system/src/query/dispatcher.rs +++ b/compiler/rustc_query_system/src/query/dispatcher.rs @@ -49,7 +49,7 @@ pub trait QueryDispatcher: Copy { // Don't use this method to access query results, instead use the methods on TyCtxt fn query_cache<'a>(self, tcx: Self::Qcx) -> &'a Self::Cache; - fn cache_on_disk(self, tcx: DepContextOf, key: &Self::Key) -> bool; + fn will_cache_on_disk_for_key(self, tcx: DepContextOf, key: &Self::Key) -> bool; // Don't use this method to compute query results, instead use the methods on TyCtxt fn execute_query(self, tcx: DepContextOf, k: Self::Key) -> Self::Value; @@ -64,7 +64,7 @@ pub trait QueryDispatcher: Copy { index: DepNodeIndex, ) -> Option; - fn loadable_from_disk( + fn is_loadable_from_disk( self, qcx: Self::Qcx, key: &Self::Key, diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 7e9f83e8fe82b..f537166bdc36d 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -623,7 +623,7 @@ where // We always expect to find a cached result for things that // can be forced from `DepNode`. debug_assert!( - !query.cache_on_disk(*qcx.dep_context(), key) + !query.will_cache_on_disk_for_key(*qcx.dep_context(), key) || !qcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(), "missing on-disk cache entry for {dep_node:?}" ); @@ -631,7 +631,7 @@ where // Sanity check for the logic in `ensure`: if the node is green and the result loadable, // we should actually be able to load it. debug_assert!( - !query.loadable_from_disk(qcx, key, prev_dep_node_index), + !query.is_loadable_from_disk(qcx, key, prev_dep_node_index), "missing on-disk cache entry for loadable {dep_node:?}" ); @@ -798,7 +798,7 @@ where return (false, None); } - let loadable = query.loadable_from_disk(qcx, key, serialized_dep_node_index); + let loadable = query.is_loadable_from_disk(qcx, key, serialized_dep_node_index); (!loadable, Some(dep_node)) }