rustc_queries! is a proc macro at the heart of the compiler's query system. The call to it in compiler/rustc_middle/src/queries.rs defines all the queries. It's also really complicated. Until very recently, it produced five different things as output.
macro_rules! rustc_with_all_queries { .. }
This is a higher-order macro. You can call it, passing it another macro which processes entries like this:
[(arena_cache)] fn registered_tools(()) -> & 'tcx ty::RegisteredTools,
macro_rules! rustc_feedable_queries { .. }
Another higher-order macro, very similar to rustc_with_all_queries, but only including entries for feedable queries.
This was removed in #153009, hooray.
mod _description_fns
A module containing one generated description function per query.
The body comes from the desc modifier. E.g. this modifier:
desc { "getting HIR ID of `{}`", tcx.def_path_str(key) }
gets turned into this function:
pub fn local_def_id_to_hir_id<'tcx>(tcx: TyCtxt<'tcx>, key: LocalDefId) -> String {
format!("getting HIR ID of `{}`", tcx.def_path_str(key))
}
mod _cache_on_disk_if_fns
A module containing one generated cache check function per cache_on_disk_if query.
The body comes from the cache_on_disk_if modifier, e.g. this modifier:
cache_on_disk_if { param.is_local() }
gets turned into this function:
pub fn const_param_default<'tcx>(_: TyCtxt<'tcx>, param: &crate::queries::const_param_default::Key<'tcx>) -> bool {
param.is_local()
}
mod _analyzer_hints
This is a weird module that exists purely to help rust-analyzer users find query definitions. It contains one never-executed function per query. E.g.
fn type_alias_is_lazy<'tcx>() -> bool {
let crate::query::Providers { type_alias_is_lazy: _, .. };
// These are the types in compiler/rustc_middle/src/query/modifiers.rs, just for documentation purposes.
crate::query::modifiers::desc;
crate::query::modifiers::separate_provide_extern;
loop {}
}
The exact spans on the various identifiers are very important to get right.
Summary
This one proc macro is doing a lot. It is incredibly hard to understand. I gained my understanding by println!ing the token stream and reading through things carefully. I don't know how else you could possibly understand it fully. It's clear that in the past people have modified it with only a partial understanding, leading to inconsistencies and weirdnesses, e.g. the inconsistent tcx binding syntax that was fixed in #152958.
The good news is that a lot of this functionality can be extracted from the proc macro and done instead in the declarative macros (e.g. define_callbacks!). Declarative macros are also not easy to read and understand, but they are much easier than proc macros. I think it should be possible to reduce the output from 2 macros + 3 mods down to 1 macro. (Though I'm not 100% sure about removing mod _analyzer_hints.) #153009 was a good start.
rustc_queries!is a proc macro at the heart of the compiler's query system. The call to it incompiler/rustc_middle/src/queries.rsdefines all the queries. It's also really complicated. Until very recently, it produced five different things as output.macro_rules! rustc_with_all_queries { .. }This is a higher-order macro. You can call it, passing it another macro which processes entries like this:
macro_rules! rustc_feedable_queries { .. }Another higher-order macro, very similar to
rustc_with_all_queries, but only including entries for feedable queries.This was removed in #153009, hooray.
mod _description_fnsA module containing one generated description function per query.
The body comes from the
descmodifier. E.g. this modifier:gets turned into this function:
mod _cache_on_disk_if_fnsA module containing one generated cache check function per
cache_on_disk_ifquery.The body comes from the
cache_on_disk_ifmodifier, e.g. this modifier:gets turned into this function:
mod _analyzer_hintsThis is a weird module that exists purely to help rust-analyzer users find query definitions. It contains one never-executed function per query. E.g.
The exact spans on the various identifiers are very important to get right.
Summary
This one proc macro is doing a lot. It is incredibly hard to understand. I gained my understanding by
println!ing the token stream and reading through things carefully. I don't know how else you could possibly understand it fully. It's clear that in the past people have modified it with only a partial understanding, leading to inconsistencies and weirdnesses, e.g. the inconsistenttcxbinding syntax that was fixed in #152958.The good news is that a lot of this functionality can be extracted from the proc macro and done instead in the declarative macros (e.g.
define_callbacks!). Declarative macros are also not easy to read and understand, but they are much easier than proc macros. I think it should be possible to reduce the output from 2 macros + 3 mods down to 1 macro. (Though I'm not 100% sure about removingmod _analyzer_hints.) #153009 was a good start.