Overview
The query system is the heart of the Rust compiler’s architecture:- 318+ queries defined in
rustc_middle::queries - Demand-driven execution - queries only run when their results are needed
- Automatic memoization - results are cached for reuse
- Dependency tracking - changes trigger recomputation of affected queries
- Incremental compilation - queries enable fine-grained incremental builds
Architecture
Core Components
rustc_middle::queries
Query definitions with key/value types and modifiers (318+ queries)
rustc_query_impl
Query system implementation, caching, and dependency tracking
Providers
Function table containing actual query implementations
TyCtxt
Main compiler context - provides access to all queries
How Queries Work
Basic Structure
Each query is defined with:Invocation
Queries are called through theTyCtxt:
- Checks the cache for existing results
- If not cached, calls the provider function
- Stores the result in the cache
- Tracks dependencies in the dependency graph
- Returns the result
Query Modifiers
Query modifiers control query behavior. From the query system documentation:desc - Description (Required)
desc - Description (Required)
Sets the human-readable description for diagnostics and profiling.The
tcx and query key are available within the block.arena_cache - Arena Allocation
arena_cache - Arena Allocation
Use an arena for in-memory caching of the query result.Results are allocated in a typed arena and share the same lifetime as the
TyCtxt.Use when: Query results contain references with 'tcx lifetimecache_on_disk_if - Disk Caching
cache_on_disk_if - Disk Caching
Cache the query result to disk if the condition evaluates to true.Enables incremental compilation by persisting results between runs.
cycle_* - Cycle Handling
cycle_* - Cycle Handling
Controls behavior when a dependency cycle is detected:
- cycle_fatal - Abort with fatal error (default)
- cycle_delay_bug - Emit delayed bug instead of aborting
- cycle_stash - Stash error for later handling
no_hash - Skip Hashing
no_hash - Skip Hashing
Do not hash the query result for incremental compilation.Instead, mark as dirty if the query is recomputed.Use when: Results are not stable across compilations
anon - Anonymous Queries
anon - Anonymous Queries
Make the query anonymous in the dependency graph (no dep node created).Use when: Query is internal and doesn’t need tracking
eval_always - Always Evaluate
eval_always - Always Evaluate
Always evaluate the query, ignoring dependencies and cached results.Use when: Query has side effects or depends on external state
depth_limit - Recursion Limit
depth_limit - Recursion Limit
Impose a recursion depth limit to prevent stack overflows.Use when: Query can recurse deeply (e.g., trait resolution)
separate_provide_extern - Separate Providers
separate_provide_extern - Separate Providers
Use separate provider functions for local and external crates.Allows different implementations for current crate vs dependencies.
feedable - External Input
feedable - External Input
Allow the query result to be “fed” from another query.Enables setting query results externally without running the provider.
Major Query Categories
The compiler has 318 queries organized by purpose:Parsing and AST (10+ queries)
AST and Parsing Queries
AST and Parsing Queries
early_lint_checks - Runs early lint checks on the ASTregistered_tools - Returns registered tool lints (clippy, rustfmt, etc.)resolutions - Returns name resolution resultsresolver_for_lowering_raw - Provides resolver data for AST loweringenv_var_os - Queries environment variables at compile timeThese queries process the raw source code and prepare for HIR generation.
HIR Queries (30+ queries)
HIR Construction and Access
HIR Construction and Access
hir_crate - Returns the complete HIR cratehir_crate_items - Returns all items in the cratehir_module_items - Returns items in a specific modulelocal_def_id_to_hir_id - Converts DefId to HirIdhir_owner_parent_q - Returns parent of HIR owneropt_hir_owner_nodes - Returns HIR nodes for an ownerhir_attr_map - Returns attribute map for HIR nodesThese queries provide access to the High-Level Intermediate Representation.
Type System Queries (80+ queries)
Type Queries
Type Queries
type_of - Computes the type of a definitiongenerics_of - Returns generic parameters of an itempredicates_of - Returns trait bounds and where clausestype_of_opaque - Computes concrete type of opaque typesitem_bounds - Returns bounds on associated typesexplicit_item_bounds - Returns explicitly written boundsconst_param_default - Returns default value for const parametersThese queries build and query the type system.
Trait and Impl Queries
Trait and Impl Queries
trait_def - Returns trait definitiontrait_impls_of - Returns all implementations of a traitimpl_trait_header - Returns trait being implementedinherent_impls - Returns inherent implementations for a typeassociated_items - Returns associated items (methods, types, consts)These queries support trait resolution and method dispatch.
MIR Queries (40+ queries)
MIR Construction and Analysis
MIR Construction and Analysis
mir_keys - Returns all items that need MIRmir_built - Builds unoptimized MIR for a functionmir_const_qualif - Checks if MIR is const-qualifiablemir_promoted - Returns promoted constants from MIRmir_borrowck - Performs borrow checkingoptimized_mir - Returns optimized MIRmir_for_ctfe - Returns MIR for compile-time function evaluationThese queries build and optimize the Mid-level IR.
Const Evaluation Queries (20+ queries)
Compile-Time Evaluation
Compile-Time Evaluation
const_eval_global_id - Evaluates a constanteval_to_allocation_raw - Evaluates to raw memory allocationeval_to_const_value_raw - Evaluates to const valueeval_to_valtree - Evaluates to value tree representationThese queries handle constant evaluation at compile time.
Analysis Queries (50+ queries)
Whole-Crate Analysis
Whole-Crate Analysis
analysis - Main analysis query (runs type checking, etc.)lint_expectations - Tracks expected lintscheck_expectations - Verifies expected lints occurredprivacy_access_levels - Computes privacy/visibilityreachable_set - Computes reachable itemsentry_fn - Finds program entry pointstability_index - Builds stability attribute indexThese queries perform whole-crate analyses.
Codegen Queries (30+ queries)
Code Generation
Code Generation
collect_and_partition_mono_items - Monomorphizationcodegen_unit - Returns items in a codegen unitis_codegened_item - Checks if item needs codegencodegen_fn_attrs - Returns codegen attributesexported_symbols - Returns symbols to exportupstream_monomorphizations - Tracks cross-crate monomorphizationsThese queries support code generation and linking.
Metadata Queries (20+ queries)
Crate Metadata
Crate Metadata
crate_name - Returns crate namecrate_hash - Returns crate hash for incremental compilationextern_crate - Returns information about external cratesnative_libraries - Returns native libraries to linkforeign_modules - Returns foreign function modulesThese queries handle metadata and cross-crate information.
Incremental Compilation Queries (15+ queries)
Incremental Compilation Support
Incremental Compilation Support
dep_graph - Dependency graph for incremental compilationfingerprint_style - How to fingerprint query resultstry_mark_green - Attempt to reuse cached resultsencode_query_results - Serialize query results to diskThese queries enable incremental compilation.
Query Execution Flow
Provider Functions
Providers implement the actual logic for queries:Query Registration
Queries are defined using therustc_queries! macro:
Location: compiler/rustc_middle/src/queries.rs (6000+ lines)
The macro generates:
- Methods on
TyCtxtfor invoking queries - Caching infrastructure
- Dependency tracking
- Query vtables
Dependency Graph
The query system maintains a dependency graph: Benefits:- Tracks which queries depend on which
- Enables incremental compilation
- Detects dependency cycles
- Provides query stack traces for debugging
Incremental Compilation
Queries enable fine-grained incremental compilation:- Hashing - Query keys and results are hashed
- Change Detection - Compare hashes from previous compilation
- Reuse - Reuse cached results if inputs haven’t changed
- Recomputation - Only recompute affected queries
Disk Caching
Queries withcache_on_disk_if persist results:
target/debug/incremental/.
Query Implementation Example
Definition
Provider Implementation
Usage
Query Debugging
Compiler Flags
-Z dump-dep-graph- Dump dependency graph-Z query-dep-graph- Print query dependency graph-Z time-passes- Show query execution time-Z self-profile- Generate detailed profiling data
Query Stack Traces
When a query panics or cycles, the compiler prints the query stack:Performance Considerations
Memoization
Memoization
Queries are memoized - results are cached and reused.Benefit: Avoid redundant computationCost: Memory to store cached results
Granularity
Granularity
Fine-grained queries (per-function) vs coarse-grained (whole-crate).Fine-grained:
- Better incremental compilation
- More cache overhead
- Less overhead
- Worse incremental compilation
Parallel Execution
Parallel Execution
Queries can be evaluated in parallel if they don’t depend on each other.The query system automatically parallelizes independent work.
Related Documentation
Compiler Passes
See how passes are implemented as queries
Compiler Crates
Learn about rustc_query_impl and rustc_middle
Further Reading: See the rustc dev guide for more details on the query system architecture.
Query System Statistics
- Total Queries: 318+
- Primary Definition File:
compiler/rustc_middle/src/queries.rs(6000+ lines) - Implementation Crate:
rustc_query_impl - Query Execution: Demand-driven with automatic memoization
- Incremental Support: Query results can be cached to disk
- Parallel Execution: Independent queries execute in parallel