mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #153326 - Zalathar:query-modifiers, r=nnethercote
Make `rustc_with_all_queries!` pass query modifiers as named values
This PR is a bold overhaul of how the proc-macro in `rustc_macros::query` passes query modifiers to the callback macros in `rustc_middle` and `rustc_query_impl`.
The existing approach passes modifiers as a list that looks like `[(arena_cache), (no_hash)]`. That style requires a family of helper macros (`if_arena_cache!`, `if_no_hash!`) to check for modifiers when consuming the query list.
This PR changes the proc-macro to instead pass modifiers like this:
```text
{
anon: false,
arena_cache: true,
cache_on_disk: false,
...
}
```
This style allows each of the callback macros to deconstruct the modifier list in a relatively straightforward way, by binding the true/false literals to variables like `$arena_cache:literal`.
One of the big advantages of this style is that we can write things like `#[cfg($arena_cache)]` and `#[cfg(not($arena_cache))]` to select blocks of code, eliminating the need for the `if_arena_cache!` family of helper macros.
In follow-up PRs, we can also try to take advantage of the new modifier style to pass richer information for some modifiers, such as `desc` or `cache_on_disk_if`. That could potentially make it more reasonable to get rid of the `_description_fns` and `_cache_on_disk_if_fns` modules, as proposed in https://github.com/rust-lang/rust/pull/153065.
r? nnethercote
This commit is contained in:
@@ -137,54 +137,23 @@ struct CacheOnDiskIf {
|
||||
block: Block,
|
||||
}
|
||||
|
||||
/// See `rustc_middle::query::modifiers` for documentation of each query modifier.
|
||||
struct QueryModifiers {
|
||||
/// The description of the query.
|
||||
desc: Desc,
|
||||
|
||||
/// Use this type for the in-memory cache.
|
||||
arena_cache: Option<Ident>,
|
||||
|
||||
/// Cache the query to disk if the `Block` returns true.
|
||||
cache_on_disk_if: Option<CacheOnDiskIf>,
|
||||
|
||||
/// A cycle error for this query aborting the compilation with a fatal error.
|
||||
cycle_fatal: Option<Ident>,
|
||||
|
||||
/// A cycle error results in a delay_bug call
|
||||
cycle_delay_bug: Option<Ident>,
|
||||
|
||||
/// A cycle error results in a stashed cycle error that can be unstashed and canceled later
|
||||
cycle_stash: Option<Ident>,
|
||||
|
||||
/// Don't hash the result, instead just mark a query red if it runs
|
||||
no_hash: Option<Ident>,
|
||||
|
||||
/// Generate a dep node based on the dependencies of the query
|
||||
// tidy-alphabetical-start
|
||||
anon: Option<Ident>,
|
||||
|
||||
/// Always evaluate the query, ignoring its dependencies
|
||||
eval_always: Option<Ident>,
|
||||
|
||||
/// Whether the query has a call depth limit
|
||||
arena_cache: Option<Ident>,
|
||||
cache_on_disk_if: Option<CacheOnDiskIf>,
|
||||
cycle_delay_bug: Option<Ident>,
|
||||
cycle_fatal: Option<Ident>,
|
||||
cycle_stash: Option<Ident>,
|
||||
depth_limit: Option<Ident>,
|
||||
|
||||
/// Use a separate query provider for local and extern crates
|
||||
separate_provide_extern: Option<Ident>,
|
||||
|
||||
/// Generate a `feed` method to set the query's value from another query.
|
||||
desc: Desc,
|
||||
eval_always: Option<Ident>,
|
||||
feedable: Option<Ident>,
|
||||
|
||||
/// When this query is called via `tcx.ensure_ok()`, it returns
|
||||
/// `Result<(), ErrorGuaranteed>` instead of `()`. If the query needs to
|
||||
/// be executed, and that execution returns an error, the error result is
|
||||
/// returned to the caller.
|
||||
///
|
||||
/// If execution is skipped, a synthetic `Ok(())` is returned, on the
|
||||
/// assumption that a query with all-green inputs must have succeeded.
|
||||
///
|
||||
/// Can only be applied to queries with a return value of
|
||||
/// `Result<_, ErrorGuaranteed>`.
|
||||
no_hash: Option<Ident>,
|
||||
return_result_from_ensure_ok: Option<Ident>,
|
||||
separate_provide_extern: Option<Ident>,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
|
||||
fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
|
||||
@@ -272,6 +241,68 @@ macro_rules! try_insert {
|
||||
})
|
||||
}
|
||||
|
||||
fn make_modifiers_stream(query: &Query, modifiers: &QueryModifiers) -> proc_macro2::TokenStream {
|
||||
let QueryModifiers {
|
||||
// tidy-alphabetical-start
|
||||
anon,
|
||||
arena_cache,
|
||||
cache_on_disk_if,
|
||||
cycle_delay_bug,
|
||||
cycle_fatal,
|
||||
cycle_stash,
|
||||
depth_limit,
|
||||
desc: _,
|
||||
eval_always,
|
||||
feedable,
|
||||
no_hash,
|
||||
return_result_from_ensure_ok,
|
||||
separate_provide_extern,
|
||||
// tidy-alphabetical-end
|
||||
} = modifiers;
|
||||
|
||||
let anon = anon.is_some();
|
||||
let arena_cache = arena_cache.is_some();
|
||||
let cache_on_disk = cache_on_disk_if.is_some();
|
||||
|
||||
let cycle_error_handling = if cycle_delay_bug.is_some() {
|
||||
quote! { DelayBug }
|
||||
} else if cycle_fatal.is_some() {
|
||||
quote! { Fatal }
|
||||
} else if cycle_stash.is_some() {
|
||||
quote! { Stash }
|
||||
} else {
|
||||
quote! { Error }
|
||||
};
|
||||
|
||||
let depth_limit = depth_limit.is_some();
|
||||
let eval_always = eval_always.is_some();
|
||||
let feedable = feedable.is_some();
|
||||
let no_hash = no_hash.is_some();
|
||||
let return_result_from_ensure_ok = return_result_from_ensure_ok.is_some();
|
||||
let separate_provide_extern = separate_provide_extern.is_some();
|
||||
|
||||
// Giving an input span to the modifier names in the modifier list seems
|
||||
// to give slightly more helpful errors when one of the callback macros
|
||||
// fails to parse the modifier list.
|
||||
let query_name_span = query.name.span();
|
||||
quote_spanned! {
|
||||
query_name_span =>
|
||||
// Search for (QMODLIST) to find all occurrences of this query modifier list.
|
||||
// tidy-alphabetical-start
|
||||
anon: #anon,
|
||||
arena_cache: #arena_cache,
|
||||
cache_on_disk: #cache_on_disk,
|
||||
cycle_error_handling: #cycle_error_handling,
|
||||
depth_limit: #depth_limit,
|
||||
eval_always: #eval_always,
|
||||
feedable: #feedable,
|
||||
no_hash: #no_hash,
|
||||
return_result_from_ensure_ok: #return_result_from_ensure_ok,
|
||||
separate_provide_extern: #separate_provide_extern,
|
||||
// tidy-alphabetical-end
|
||||
}
|
||||
}
|
||||
|
||||
fn doc_comment_from_desc(list: &Punctuated<Expr, token::Comma>) -> Result<Attribute> {
|
||||
use ::syn::*;
|
||||
let mut iter = list.iter();
|
||||
@@ -458,51 +489,13 @@ macro_rules! assert {
|
||||
ReturnType::Type(..) => quote! { #return_ty },
|
||||
};
|
||||
|
||||
let mut modifiers_out = vec![];
|
||||
|
||||
macro_rules! passthrough {
|
||||
( $( $modifier:ident ),+ $(,)? ) => {
|
||||
$( if let Some($modifier) = &modifiers.$modifier {
|
||||
modifiers_out.push(quote! { (#$modifier) });
|
||||
}; )+
|
||||
}
|
||||
}
|
||||
|
||||
passthrough!(
|
||||
arena_cache,
|
||||
cycle_fatal,
|
||||
cycle_delay_bug,
|
||||
cycle_stash,
|
||||
no_hash,
|
||||
anon,
|
||||
eval_always,
|
||||
feedable,
|
||||
depth_limit,
|
||||
separate_provide_extern,
|
||||
return_result_from_ensure_ok,
|
||||
);
|
||||
|
||||
// If there was a `cache_on_disk_if` modifier in the real input, pass
|
||||
// on a synthetic `(cache_on_disk)` modifier that can be inspected by
|
||||
// macro-rules macros.
|
||||
if modifiers.cache_on_disk_if.is_some() {
|
||||
modifiers_out.push(quote! { (cache_on_disk) });
|
||||
}
|
||||
|
||||
// This uses the span of the query definition for the commas,
|
||||
// which can be important if we later encounter any ambiguity
|
||||
// errors with any of the numerous macro_rules! macros that
|
||||
// we use. Using the call-site span would result in a span pointing
|
||||
// at the entire `rustc_queries!` invocation, which wouldn't
|
||||
// be very useful.
|
||||
let span = name.span();
|
||||
let modifiers_stream = quote_spanned! { span => #(#modifiers_out),* };
|
||||
let modifiers_stream = make_modifiers_stream(&query, modifiers);
|
||||
|
||||
// Add the query to the group
|
||||
query_stream.extend(quote! {
|
||||
#(#doc_comments)*
|
||||
[#modifiers_stream]
|
||||
fn #name(#key_ty) #return_ty,
|
||||
fn #name(#key_ty) #return_ty
|
||||
{ #modifiers_stream }
|
||||
});
|
||||
|
||||
if let Some(feedable) = &modifiers.feedable {
|
||||
|
||||
@@ -268,8 +268,10 @@ macro_rules! define_dep_nodes {
|
||||
queries {
|
||||
$(
|
||||
$(#[$q_attr:meta])*
|
||||
[$($modifiers:tt)*]
|
||||
fn $q_name:ident($K:ty) -> $V:ty,
|
||||
fn $q_name:ident($K:ty) -> $V:ty
|
||||
// Search for (QMODLIST) to find all occurrences of this query modifier list.
|
||||
// Query modifiers are currently not used here, so skip the whole list.
|
||||
{ $($modifiers:tt)* }
|
||||
)*
|
||||
}
|
||||
non_queries {
|
||||
|
||||
@@ -333,44 +333,6 @@ macro_rules! query_helper_param_ty {
|
||||
($K:ty) => { $K };
|
||||
}
|
||||
|
||||
// Expands to `$yes` if the `arena_cache` modifier is present, `$no` otherwise.
|
||||
macro_rules! if_arena_cache {
|
||||
([] $then:tt $no:tt) => { $no };
|
||||
([(arena_cache) $($modifiers:tt)*] $yes:tt $no:tt) => { $yes };
|
||||
([$other:tt $($modifiers:tt)*] $yes:tt $no:tt) => {
|
||||
if_arena_cache!([$($modifiers)*] $yes $no)
|
||||
};
|
||||
}
|
||||
|
||||
// Expands to `$yes` if the `separate_provide_extern` modifier is present, `$no` otherwise.
|
||||
macro_rules! if_separate_provide_extern {
|
||||
([] $then:tt $no:tt) => { $no };
|
||||
([(separate_provide_extern) $($modifiers:tt)*] $yes:tt $no:tt) => { $yes };
|
||||
([$other:tt $($modifiers:tt)*] $yes:tt $no:tt) => {
|
||||
if_separate_provide_extern!([$($modifiers)*] $yes $no)
|
||||
};
|
||||
}
|
||||
|
||||
// Expands to `$yes` if the `return_result_from_ensure_ok` modifier is present, `$no` otherwise.
|
||||
macro_rules! if_return_result_from_ensure_ok {
|
||||
([] $then:tt $no:tt) => { $no };
|
||||
([(return_result_from_ensure_ok) $($modifiers:tt)*] $yes:tt $no:tt) => { $yes };
|
||||
([$other:tt $($modifiers:tt)*] $yes:tt $no:tt) => {
|
||||
if_return_result_from_ensure_ok!([$($modifiers)*] $yes $no)
|
||||
};
|
||||
}
|
||||
|
||||
// Expands to `$item` if the `feedable` modifier is present.
|
||||
macro_rules! item_if_feedable {
|
||||
([] $($item:tt)*) => {};
|
||||
([(feedable) $($rest:tt)*] $($item:tt)*) => {
|
||||
$($item)*
|
||||
};
|
||||
([$other:tt $($modifiers:tt)*] $($item:tt)*) => {
|
||||
item_if_feedable! { [$($modifiers)*] $($item)* }
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! define_callbacks {
|
||||
(
|
||||
// You might expect the key to be `$K:ty`, but it needs to be `$($K:tt)*` so that
|
||||
@@ -378,8 +340,20 @@ macro_rules! define_callbacks {
|
||||
queries {
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
[$($modifiers:tt)*]
|
||||
fn $name:ident($($K:tt)*) -> $V:ty,
|
||||
fn $name:ident($($K:tt)*) -> $V:ty
|
||||
{
|
||||
// Search for (QMODLIST) to find all occurrences of this query modifier list.
|
||||
anon: $anon:literal,
|
||||
arena_cache: $arena_cache:literal,
|
||||
cache_on_disk: $cache_on_disk:literal,
|
||||
cycle_error_handling: $cycle_error_handling:ident,
|
||||
depth_limit: $depth_limit:literal,
|
||||
eval_always: $eval_always:literal,
|
||||
feedable: $feedable:literal,
|
||||
no_hash: $no_hash:literal,
|
||||
return_result_from_ensure_ok: $return_result_from_ensure_ok:literal,
|
||||
separate_provide_extern: $separate_provide_extern:literal,
|
||||
}
|
||||
)*
|
||||
}
|
||||
// Non-queries are unused here.
|
||||
@@ -394,20 +368,31 @@ pub mod $name {
|
||||
pub type Key<'tcx> = $($K)*;
|
||||
pub type Value<'tcx> = $V;
|
||||
|
||||
pub type LocalKey<'tcx> = if_separate_provide_extern!(
|
||||
[$($modifiers)*]
|
||||
(<Key<'tcx> as $crate::query::AsLocalQueryKey>::LocalQueryKey)
|
||||
(Key<'tcx>)
|
||||
);
|
||||
/// Key type used by provider functions in `local_providers`.
|
||||
/// This query has the `separate_provide_extern` modifier.
|
||||
#[cfg($separate_provide_extern)]
|
||||
pub type LocalKey<'tcx> =
|
||||
<Key<'tcx> as $crate::query::AsLocalQueryKey>::LocalQueryKey;
|
||||
/// Key type used by provider functions in `local_providers`.
|
||||
#[cfg(not($separate_provide_extern))]
|
||||
pub type LocalKey<'tcx> = Key<'tcx>;
|
||||
|
||||
/// This type alias specifies the type returned from query providers and the type
|
||||
/// used for decoding. For regular queries this is the declared returned type `V`,
|
||||
/// but `arena_cache` will use `<V as ArenaCached>::Provided` instead.
|
||||
pub type ProvidedValue<'tcx> = if_arena_cache!(
|
||||
[$($modifiers)*]
|
||||
(<Value<'tcx> as $crate::query::arena_cached::ArenaCached<'tcx>>::Provided)
|
||||
(Value<'tcx>)
|
||||
);
|
||||
/// Return type of the `.ensure_ok()` method for this query,
|
||||
/// which has the `return_result_from_ensure_ok` modifier.
|
||||
#[cfg($return_result_from_ensure_ok)]
|
||||
pub type EnsureOkReturnType = Result<(), rustc_errors::ErrorGuaranteed>;
|
||||
/// Return type of the `.ensure_ok()` method for this query,
|
||||
/// which does _not_ have the `return_result_from_ensure_ok` modifier.
|
||||
#[cfg(not($return_result_from_ensure_ok))]
|
||||
pub type EnsureOkReturnType = ();
|
||||
|
||||
/// Type returned from query providers and loaded from disk-cache.
|
||||
#[cfg($arena_cache)]
|
||||
pub type ProvidedValue<'tcx> =
|
||||
<Value<'tcx> as $crate::query::arena_cached::ArenaCached<'tcx>>::Provided;
|
||||
/// Type returned from query providers and loaded from disk-cache.
|
||||
#[cfg(not($arena_cache))]
|
||||
pub type ProvidedValue<'tcx> = Value<'tcx>;
|
||||
|
||||
/// This helper function takes a value returned by the query provider
|
||||
/// (or loaded from disk, or supplied by query feeding), allocates
|
||||
@@ -420,23 +405,23 @@ pub fn provided_to_erased<'tcx>(
|
||||
) -> Erased<Value<'tcx>> {
|
||||
// For queries with the `arena_cache` modifier, store the
|
||||
// provided value in an arena and get a reference to it.
|
||||
let value: Value<'tcx> = if_arena_cache!(
|
||||
[$($modifiers)*]
|
||||
{
|
||||
<Value<'tcx> as $crate::query::arena_cached::ArenaCached>::
|
||||
alloc_in_arena
|
||||
(
|
||||
tcx,
|
||||
&tcx.query_system.arenas.$name,
|
||||
provided_value,
|
||||
)
|
||||
}
|
||||
{
|
||||
// Otherwise, the provided value is the value (and `tcx` is unused).
|
||||
let _ = tcx;
|
||||
provided_value
|
||||
}
|
||||
);
|
||||
#[cfg($arena_cache)]
|
||||
let value: Value<'tcx> = {
|
||||
use $crate::query::arena_cached::ArenaCached;
|
||||
<Value<'tcx> as ArenaCached>::alloc_in_arena(
|
||||
tcx,
|
||||
&tcx.query_system.arenas.$name,
|
||||
provided_value,
|
||||
)
|
||||
};
|
||||
|
||||
// Otherwise, the provided value is the value (and `tcx` is unused).
|
||||
#[cfg(not($arena_cache))]
|
||||
let value: Value<'tcx> = {
|
||||
let _ = tcx;
|
||||
provided_value
|
||||
};
|
||||
|
||||
erase::erase_val(value)
|
||||
}
|
||||
|
||||
@@ -480,13 +465,11 @@ pub fn provided_to_erased<'tcx>(
|
||||
#[derive(Default)]
|
||||
pub struct QueryArenas<'tcx> {
|
||||
$(
|
||||
pub $name: if_arena_cache!(
|
||||
[$($modifiers)*]
|
||||
// Use the `ArenaCached` helper trait to determine the arena's value type.
|
||||
(TypedArena<<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated>)
|
||||
// No arena for this query, so the field type is `()`.
|
||||
()
|
||||
),
|
||||
// Use the `ArenaCached` helper trait to determine the arena's value type.
|
||||
#[cfg($arena_cache)]
|
||||
pub $name: TypedArena<
|
||||
<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated,
|
||||
>,
|
||||
)*
|
||||
}
|
||||
|
||||
@@ -497,16 +480,14 @@ impl<'tcx> $crate::query::TyCtxtEnsureOk<'tcx> {
|
||||
pub fn $name(
|
||||
self,
|
||||
key: query_helper_param_ty!($($K)*),
|
||||
) -> if_return_result_from_ensure_ok!(
|
||||
[$($modifiers)*]
|
||||
(Result<(), ErrorGuaranteed>)
|
||||
()
|
||||
) {
|
||||
if_return_result_from_ensure_ok!(
|
||||
[$($modifiers)*]
|
||||
(crate::query::inner::query_ensure_error_guaranteed)
|
||||
(crate::query::inner::query_ensure)
|
||||
)(
|
||||
) -> $crate::queries::$name::EnsureOkReturnType {
|
||||
|
||||
#[cfg($return_result_from_ensure_ok)]
|
||||
let ensure_fn = crate::query::inner::query_ensure_error_guaranteed;
|
||||
#[cfg(not($return_result_from_ensure_ok))]
|
||||
let ensure_fn = crate::query::inner::query_ensure;
|
||||
|
||||
ensure_fn(
|
||||
self.tcx,
|
||||
&self.tcx.query_system.query_vtables.$name,
|
||||
$crate::query::IntoQueryParam::into_query_param(key),
|
||||
@@ -560,24 +541,22 @@ pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V {
|
||||
}
|
||||
|
||||
$(
|
||||
item_if_feedable! {
|
||||
[$($modifiers)*]
|
||||
impl<'tcx, K: $crate::query::IntoQueryParam<$name::Key<'tcx>> + Copy>
|
||||
TyCtxtFeed<'tcx, K>
|
||||
{
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(self, value: $name::ProvidedValue<'tcx>) {
|
||||
let key = self.key().into_query_param();
|
||||
let erased_value = $name::provided_to_erased(self.tcx, value);
|
||||
$crate::query::inner::query_feed(
|
||||
self.tcx,
|
||||
dep_graph::DepKind::$name,
|
||||
&self.tcx.query_system.query_vtables.$name,
|
||||
key,
|
||||
erased_value,
|
||||
);
|
||||
}
|
||||
#[cfg($feedable)]
|
||||
impl<'tcx, K: $crate::query::IntoQueryParam<$name::Key<'tcx>> + Copy>
|
||||
TyCtxtFeed<'tcx, K>
|
||||
{
|
||||
$(#[$attr])*
|
||||
#[inline(always)]
|
||||
pub fn $name(self, value: $name::ProvidedValue<'tcx>) {
|
||||
let key = self.key().into_query_param();
|
||||
let erased_value = $name::provided_to_erased(self.tcx, value);
|
||||
$crate::query::inner::query_feed(
|
||||
self.tcx,
|
||||
dep_graph::DepKind::$name,
|
||||
&self.tcx.query_system.query_vtables.$name,
|
||||
key,
|
||||
erased_value,
|
||||
);
|
||||
}
|
||||
}
|
||||
)*
|
||||
@@ -602,11 +581,11 @@ pub struct Providers {
|
||||
|
||||
pub struct ExternProviders {
|
||||
$(
|
||||
pub $name: if_separate_provide_extern!(
|
||||
[$($modifiers)*]
|
||||
(for<'tcx> fn(TyCtxt<'tcx>, $name::Key<'tcx>) -> $name::ProvidedValue<'tcx>)
|
||||
()
|
||||
),
|
||||
#[cfg($separate_provide_extern)]
|
||||
pub $name: for<'tcx> fn(
|
||||
TyCtxt<'tcx>,
|
||||
$name::Key<'tcx>,
|
||||
) -> $name::ProvidedValue<'tcx>,
|
||||
)*
|
||||
}
|
||||
|
||||
@@ -626,13 +605,10 @@ impl Default for ExternProviders {
|
||||
fn default() -> Self {
|
||||
ExternProviders {
|
||||
$(
|
||||
$name: if_separate_provide_extern!(
|
||||
[$($modifiers)*]
|
||||
(|_, key| $crate::query::plumbing::default_extern_query(
|
||||
stringify!($name),
|
||||
&key
|
||||
))
|
||||
()
|
||||
#[cfg($separate_provide_extern)]
|
||||
$name: |_, key| $crate::query::plumbing::default_extern_query(
|
||||
stringify!($name),
|
||||
&key,
|
||||
),
|
||||
)*
|
||||
}
|
||||
|
||||
@@ -130,8 +130,20 @@ macro_rules! define_dep_kind_vtables {
|
||||
queries {
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
[$($modifiers:tt)*]
|
||||
fn $name:ident($K:ty) -> $V:ty,
|
||||
fn $name:ident($K:ty) -> $V:ty
|
||||
{
|
||||
// Search for (QMODLIST) to find all occurrences of this query modifier list.
|
||||
anon: $anon:literal,
|
||||
arena_cache: $arena_cache:literal,
|
||||
cache_on_disk: $cache_on_disk:literal,
|
||||
cycle_error_handling: $cycle_error_handling:ident,
|
||||
depth_limit: $depth_limit:literal,
|
||||
eval_always: $eval_always:literal,
|
||||
feedable: $feedable:literal,
|
||||
no_hash: $no_hash:literal,
|
||||
return_result_from_ensure_ok: $return_result_from_ensure_ok:literal,
|
||||
separate_provide_extern: $separate_provide_extern:literal,
|
||||
}
|
||||
)*
|
||||
}
|
||||
non_queries {
|
||||
@@ -154,9 +166,9 @@ fn $name:ident($K:ty) -> $V:ty,
|
||||
$crate::dep_kind_vtables::make_dep_kind_vtable_for_query::<
|
||||
$crate::query_impl::$name::VTableGetter,
|
||||
>(
|
||||
is_anon!([$($modifiers)*]),
|
||||
if_cache_on_disk!([$($modifiers)*] true false),
|
||||
is_eval_always!([$($modifiers)*]),
|
||||
$anon,
|
||||
$cache_on_disk,
|
||||
$eval_always,
|
||||
)
|
||||
),*
|
||||
];
|
||||
|
||||
@@ -99,125 +99,6 @@ pub(super) fn try_mark_green<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> boo
|
||||
tcx.dep_graph.try_mark_green(tcx, dep_node).is_some()
|
||||
}
|
||||
|
||||
macro_rules! cycle_error_handling {
|
||||
([]) => {{
|
||||
rustc_middle::query::CycleErrorHandling::Error
|
||||
}};
|
||||
([(cycle_fatal) $($rest:tt)*]) => {{
|
||||
rustc_middle::query::CycleErrorHandling::Fatal
|
||||
}};
|
||||
([(cycle_stash) $($rest:tt)*]) => {{
|
||||
rustc_middle::query::CycleErrorHandling::Stash
|
||||
}};
|
||||
([(cycle_delay_bug) $($rest:tt)*]) => {{
|
||||
rustc_middle::query::CycleErrorHandling::DelayBug
|
||||
}};
|
||||
([$other:tt $($modifiers:tt)*]) => {
|
||||
cycle_error_handling!([$($modifiers)*])
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_anon {
|
||||
([]) => {{
|
||||
false
|
||||
}};
|
||||
([(anon) $($rest:tt)*]) => {{
|
||||
true
|
||||
}};
|
||||
([$other:tt $($modifiers:tt)*]) => {
|
||||
is_anon!([$($modifiers)*])
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_eval_always {
|
||||
([]) => {{
|
||||
false
|
||||
}};
|
||||
([(eval_always) $($rest:tt)*]) => {{
|
||||
true
|
||||
}};
|
||||
([$other:tt $($modifiers:tt)*]) => {
|
||||
is_eval_always!([$($modifiers)*])
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_depth_limit {
|
||||
([]) => {{
|
||||
false
|
||||
}};
|
||||
([(depth_limit) $($rest:tt)*]) => {{
|
||||
true
|
||||
}};
|
||||
([$other:tt $($modifiers:tt)*]) => {
|
||||
is_depth_limit!([$($modifiers)*])
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! is_feedable {
|
||||
([]) => {{
|
||||
false
|
||||
}};
|
||||
([(feedable) $($rest:tt)*]) => {{
|
||||
true
|
||||
}};
|
||||
([$other:tt $($modifiers:tt)*]) => {
|
||||
is_feedable!([$($modifiers)*])
|
||||
};
|
||||
}
|
||||
|
||||
/// Expands to `$yes` if the `no_hash` modifier is present, or `$no` otherwise.
|
||||
macro_rules! if_no_hash {
|
||||
([] $yes:tt $no:tt) => { $no };
|
||||
([(no_hash) $($modifiers:tt)*] $yes:tt $no:tt) => { $yes };
|
||||
([$other:tt $($modifiers:tt)*] $yes:tt $no:tt) => {
|
||||
if_no_hash!([$($modifiers)*] $yes $no)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! call_provider {
|
||||
([][$tcx:expr, $name:ident, $key:expr]) => {{
|
||||
($tcx.query_system.local_providers.$name)($tcx, $key)
|
||||
}};
|
||||
([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{
|
||||
if let Some(key) = $key.as_local_key() {
|
||||
($tcx.query_system.local_providers.$name)($tcx, key)
|
||||
} else {
|
||||
($tcx.query_system.extern_providers.$name)($tcx, $key)
|
||||
}
|
||||
}};
|
||||
([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
|
||||
call_provider!([$($modifiers)*][$($args)*])
|
||||
};
|
||||
}
|
||||
|
||||
/// Expands to one of two token trees, depending on whether the current query
|
||||
/// has the `cache_on_disk_if` modifier.
|
||||
macro_rules! if_cache_on_disk {
|
||||
([] $yes:tt $no:tt) => {
|
||||
$no
|
||||
};
|
||||
// The `cache_on_disk_if` modifier generates a synthetic `(cache_on_disk)`,
|
||||
// modifier, for use by this macro and similar macros.
|
||||
([(cache_on_disk) $($rest:tt)*] $yes:tt $no:tt) => {
|
||||
$yes
|
||||
};
|
||||
([$other:tt $($modifiers:tt)*] $yes:tt $no:tt) => {
|
||||
if_cache_on_disk!([$($modifiers)*] $yes $no)
|
||||
};
|
||||
}
|
||||
|
||||
/// Conditionally expands to some token trees, if the current query has the
|
||||
/// `cache_on_disk_if` modifier.
|
||||
macro_rules! item_if_cache_on_disk {
|
||||
([] $($item:tt)*) => {};
|
||||
([(cache_on_disk) $($rest:tt)*] $($item:tt)*) => {
|
||||
$($item)*
|
||||
};
|
||||
([$other:tt $($modifiers:tt)*] $($item:tt)*) => {
|
||||
item_if_cache_on_disk! { [$($modifiers)*] $($item)* }
|
||||
};
|
||||
}
|
||||
|
||||
/// The deferred part of a deferred query stack frame.
|
||||
fn mk_query_stack_frame_extra<'tcx, Cache>(
|
||||
(tcx, vtable, key): (TyCtxt<'tcx>, &'tcx QueryVTable<'tcx, Cache>, Cache::Key),
|
||||
@@ -421,8 +302,20 @@ macro_rules! define_queries {
|
||||
queries {
|
||||
$(
|
||||
$(#[$attr:meta])*
|
||||
[$($modifiers:tt)*]
|
||||
fn $name:ident($K:ty) -> $V:ty,
|
||||
fn $name:ident($K:ty) -> $V:ty
|
||||
{
|
||||
// Search for (QMODLIST) to find all occurrences of this query modifier list.
|
||||
anon: $anon:literal,
|
||||
arena_cache: $arena_cache:literal,
|
||||
cache_on_disk: $cache_on_disk:literal,
|
||||
cycle_error_handling: $cycle_error_handling:ident,
|
||||
depth_limit: $depth_limit:literal,
|
||||
eval_always: $eval_always:literal,
|
||||
feedable: $feedable:literal,
|
||||
no_hash: $no_hash:literal,
|
||||
return_result_from_ensure_ok: $return_result_from_ensure_ok:literal,
|
||||
separate_provide_extern: $separate_provide_extern:literal,
|
||||
}
|
||||
)*
|
||||
}
|
||||
// Non-queries are unused here.
|
||||
@@ -498,7 +391,16 @@ pub(crate) fn __rust_begin_short_backtrace<'tcx>(
|
||||
let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
|
||||
|
||||
// Call the actual provider function for this query.
|
||||
let provided_value = call_provider!([$($modifiers)*][tcx, $name, key]);
|
||||
|
||||
#[cfg($separate_provide_extern)]
|
||||
let provided_value = if let Some(local_key) = key.as_local_key() {
|
||||
(tcx.query_system.local_providers.$name)(tcx, local_key)
|
||||
} else {
|
||||
(tcx.query_system.extern_providers.$name)(tcx, key)
|
||||
};
|
||||
|
||||
#[cfg(not($separate_provide_extern))]
|
||||
let provided_value = (tcx.query_system.local_providers.$name)(tcx, key);
|
||||
|
||||
rustc_middle::ty::print::with_reduced_queries!({
|
||||
tracing::trace!(?provided_value);
|
||||
@@ -515,64 +417,67 @@ pub(crate) fn make_query_vtable<'tcx>(incremental: bool)
|
||||
{
|
||||
QueryVTable {
|
||||
name: stringify!($name),
|
||||
anon: is_anon!([$($modifiers)*]),
|
||||
eval_always: is_eval_always!([$($modifiers)*]),
|
||||
depth_limit: is_depth_limit!([$($modifiers)*]),
|
||||
feedable: is_feedable!([$($modifiers)*]),
|
||||
anon: $anon,
|
||||
eval_always: $eval_always,
|
||||
depth_limit: $depth_limit,
|
||||
feedable: $feedable,
|
||||
dep_kind: dep_graph::DepKind::$name,
|
||||
cycle_error_handling: cycle_error_handling!([$($modifiers)*]),
|
||||
cycle_error_handling:
|
||||
rustc_middle::query::CycleErrorHandling::$cycle_error_handling,
|
||||
state: Default::default(),
|
||||
cache: Default::default(),
|
||||
will_cache_on_disk_for_key_fn: if_cache_on_disk!([$($modifiers)*] {
|
||||
Some(::rustc_middle::queries::_cache_on_disk_if_fns::$name)
|
||||
} {
|
||||
None
|
||||
}),
|
||||
|
||||
#[cfg($cache_on_disk)]
|
||||
will_cache_on_disk_for_key_fn:
|
||||
Some(rustc_middle::queries::_cache_on_disk_if_fns::$name),
|
||||
#[cfg(not($cache_on_disk))]
|
||||
will_cache_on_disk_for_key_fn: None,
|
||||
|
||||
call_query_method_fn: |tcx, key| {
|
||||
// Call the query method for its side-effect of loading a value
|
||||
// from disk-cache; the caller doesn't need the value.
|
||||
let _ = tcx.$name(key);
|
||||
},
|
||||
invoke_provider_fn: self::invoke_provider_fn::__rust_begin_short_backtrace,
|
||||
try_load_from_disk_fn: if_cache_on_disk!([$($modifiers)*] {
|
||||
Some(|tcx, key, prev_index, index| {
|
||||
// Check the `cache_on_disk_if` condition for this key.
|
||||
if !::rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let value: queries::$name::ProvidedValue<'tcx> =
|
||||
$crate::plumbing::try_load_from_disk(tcx, prev_index, index)?;
|
||||
#[cfg($cache_on_disk)]
|
||||
try_load_from_disk_fn: Some(|tcx, key, prev_index, index| {
|
||||
// Check the `cache_on_disk_if` condition for this key.
|
||||
if !rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Arena-alloc the value if appropriate, and erase it.
|
||||
Some(queries::$name::provided_to_erased(tcx, value))
|
||||
})
|
||||
} {
|
||||
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))
|
||||
}),
|
||||
is_loadable_from_disk_fn: if_cache_on_disk!([$($modifiers)*] {
|
||||
Some(|tcx, key, index| -> bool {
|
||||
::rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) &&
|
||||
$crate::plumbing::loadable_from_disk(tcx, index)
|
||||
})
|
||||
} {
|
||||
None
|
||||
#[cfg(not($cache_on_disk))]
|
||||
try_load_from_disk_fn: None,
|
||||
|
||||
#[cfg($cache_on_disk)]
|
||||
is_loadable_from_disk_fn: Some(|tcx, key, index| -> bool {
|
||||
rustc_middle::queries::_cache_on_disk_if_fns::$name(tcx, key) &&
|
||||
$crate::plumbing::loadable_from_disk(tcx, index)
|
||||
}),
|
||||
#[cfg(not($cache_on_disk))]
|
||||
is_loadable_from_disk_fn: None,
|
||||
|
||||
value_from_cycle_error: |tcx, cycle, guar| {
|
||||
let result: queries::$name::Value<'tcx> =
|
||||
FromCycleError::from_cycle_error(tcx, cycle, guar);
|
||||
erase::erase_val(result)
|
||||
},
|
||||
hash_value_fn: if_no_hash!(
|
||||
[$($modifiers)*]
|
||||
None
|
||||
{
|
||||
Some(|hcx, erased_value: &erase::Erased<queries::$name::Value<'tcx>>| {
|
||||
let value = erase::restore_val(*erased_value);
|
||||
rustc_middle::dep_graph::hash_result(hcx, &value)
|
||||
})
|
||||
}
|
||||
),
|
||||
|
||||
#[cfg($no_hash)]
|
||||
hash_value_fn: None,
|
||||
#[cfg(not($no_hash))]
|
||||
hash_value_fn: Some(|hcx, erased_value: &erase::Erased<queries::$name::Value<'tcx>>| {
|
||||
let value = erase::restore_val(*erased_value);
|
||||
rustc_middle::dep_graph::hash_result(hcx, &value)
|
||||
}),
|
||||
|
||||
format_value: |value| format!("{:?}", erase::restore_val::<queries::$name::Value<'tcx>>(*value)),
|
||||
description_fn: $crate::queries::_description_fns::$name,
|
||||
execute_query_fn: if incremental {
|
||||
@@ -670,8 +575,8 @@ fn encode_all_query_results<'tcx>(
|
||||
query_result_index: &mut EncodedDepNodeIndex,
|
||||
) {
|
||||
$(
|
||||
item_if_cache_on_disk! {
|
||||
[$($modifiers)*]
|
||||
#[cfg($cache_on_disk)]
|
||||
{
|
||||
$crate::plumbing::encode_query_results(
|
||||
tcx,
|
||||
&tcx.query_system.query_vtables.$name,
|
||||
|
||||
Reference in New Issue
Block a user