Skip to main content
The Rust compiler processes code through a series of transformation passes, converting source code into executable binaries. Each pass performs specific analyses or transformations.

Compilation Pipeline Overview

Early Passes

Lexing and Parsing

Location: rustc_interface::passes::parseThe first major pass that converts source code into an Abstract Syntax Tree (AST).Process:
  1. Creates a parser from file or string input
  2. Tokenizes the source code (lexing)
  3. Parses tokens into AST nodes
  4. Injects command-line attributes into the crate
Input: Raw source code (Input::File or Input::Str)Output: ast::CrateError Handling: Parse errors are emitted immediately and cause compilation to abort.
Location: rustc_interface::passes::pre_expansion_lintRuns lints on the AST before macro expansion. These lints check for issues that should be caught early.Timing: Before macro expansionInput: AST nodes, attributes, featuresLints Checked: Built-in pre-expansion lints from rustc_lint::BuiltinCombinedPreExpansionLintPass

Macro Processing

Location: rustc_interface::passes::configure_and_expandRuns the “early phases” of compilation: cfg processing, syntax expansion, and name resolution.Major Steps:
  1. Crate Injection - Injects standard library imports
  2. Macro Expansion - Expands all macros recursively
  3. Test Harness - Injects test harness if --test is specified
  4. AST Validation - Validates the expanded AST
  5. Proc Macro Harness - Injects procedural macro runtime
  6. Name Resolution - Resolves all names and paths
Configuration:
  • Respects recursion limits
  • Handles cfg attributes
  • Processes feature gates
Input: Unexpanded ast::Crate, ResolverOutput: Fully expanded ast::Crate with all macros expanded
Timing: Within configure_and_expandThe core macro expansion pass that:
  • Expands declarative macros (macro_rules!)
  • Calls procedural macros
  • Expands built-in macros like println!, derive, etc.
  • Handles macro imports and exports
Recursion Limit: Configurable via #![recursion_limit] attribute

Analysis Passes

HIR Construction and Analysis

Location: rustc_interface::passes::resolver_for_lowering_rawQuery: resolver_for_lowering_rawPrepares resolution data needed for AST lowering to HIR.Output:
  • ResolverAstLowering - Resolution tables for lowering
  • Expanded ast::Crate
  • ResolverGlobalCtxt - Global resolution context
Query: hir_crateLowers the expanded AST into High-Level Intermediate Representation (HIR).Performed by: rustc_ast_loweringTransformations:
  • Desugars complex syntax into simpler forms
  • Converts for loops to loop + match
  • Expands question mark operator (?)
  • Normalizes closure syntax
Output: Crate<'tcx> - The HIR crate
Location: rustc_interface::passes::early_lint_checksQuery: early_lint_checksRuns lints that operate on the fully expanded AST and early HIR.Timing: After expansion, before type checking

Type Checking and Inference

Queries: type_of, generics_of, predicates_ofCollects type signatures from all items in the crate.Process:
  1. Collect types from item signatures
  2. Build generic parameter lists
  3. Collect trait bounds and where clauses
  4. Validate type well-formedness
Primary Crate: rustc_hir_typeckQueries: Per-function type checking queriesPerforms type inference and checking for function bodies.Major Components:
  • Expression type checking
  • Pattern type checking
  • Method resolution
  • Operator overload resolution
  • Type coercion
  • Closure signature inference
Algorithm: Uses unification-based type inference with constraints
Primary Crate: rustc_trait_selectionResolves trait implementations and validates trait bounds.Operations:
  • Trait selection (finding applicable impls)
  • Projection (resolving associated types)
  • Method candidate resolution
  • Impl overlap checking
  • Coherence checking

MIR Passes

Query: mir_builtPrimary Crate: rustc_mir_buildBuilds MIR (Mid-level Intermediate Representation) from THIR (Typed HIR).Steps:
  1. Lower HIR to THIR (adds type information)
  2. Build MIR control flow graph
  3. Generate MIR for match expressions
  4. Insert drop glue
Output: mir::Body<'tcx> - Unoptimized MIR
Primary Crate: rustc_borrowckQueries: mir_borrowckValidates memory safety through borrow checking.Checks:
  • Validates borrows don’t outlive referenced data
  • Ensures no simultaneous mutable and immutable borrows
  • Prevents use-after-move
  • Validates initialization before use
Algorithm: Dataflow analysis on MIR using polonius or NLL (Non-Lexical Lifetimes)
Primary Crate: rustc_mir_transformPerforms optimization passes on MIR.Major Optimizations:
  • Inlining - Inline small functions
  • Constant Propagation - Evaluate constants at compile time
  • Dead Code Elimination - Remove unreachable code
  • Copy Propagation - Eliminate unnecessary copies
  • Destination Propagation - Optimize memory destinations
  • Simplify CFG - Simplify control flow graph
  • InstCombine - Combine instructions
Levels: Different optimization levels run different passes

Additional Analysis Passes

Module: rustc_passes::reachableDetermines which items are reachable from entry points.Used For:
  • Dead code detection
  • Determining what to include in metadata
  • Link-time optimization decisions
Module: rustc_passes::deadQuery: Provided through rustc_passes::provideDetects unused code that can be removed or warned about.Checks:
  • Unused functions
  • Unused imports
  • Unused variables
  • Unused struct fields (private only)
Primary Crate: rustc_privacyValidates privacy rules (pub/private).Checks:
  • Private types in public signatures
  • Access to private items
  • Computes effective visibilities
Module: rustc_passes::stabilityValidates use of stable/unstable features.Checks:
  • Unstable feature gates
  • Deprecated item usage
  • Stability attribute consistency
Module: rustc_passes::entryFinds the entry point for the program (main function or custom entry point).Validates:
  • Entry point signature
  • Only one entry point exists
  • Entry point visibility

Code Generation Passes

Primary Crate: rustc_monomorphizeCreates concrete versions of generic functions for each type they’re used with.Process:
  1. Collect all generic items used
  2. Generate concrete versions with type parameters substituted
  3. Partition into codegen units
  4. Handle dynamic dispatch (trait objects)
Output: MonoItems - Concrete items ready for codegen
Query: collect_and_partition_mono_itemsDivides monomorphized items into compilation units for parallel codegen.Strategies:
  • Per-module partitioning (faster compilation)
  • Single unit (better optimization, slower compilation)
Primary Crate: rustc_codegen_llvmGenerates LLVM IR from MIR.Steps:
  1. Convert MIR to LLVM IR
  2. Apply LLVM optimizations
  3. Generate object files
Parallel: Each codegen unit is compiled in parallel
Final Phase: Links object files into final binaryProcess:
  1. Collect all object files
  2. Link with runtime libraries
  3. Apply LTO (Link-Time Optimization) if enabled
  4. Produce final executable/library

Pass Organization in Code

rustc_passes Crate

The rustc_passes crate (compiler/rustc_passes/) contains various analysis passes:
// From rustc_passes/src/lib.rs
pub mod abi_test;          // ABI testing
mod check_attr;             // Attribute validation  
mod check_export;           // Export checking
pub mod dead;               // Dead code detection
mod debugger_visualizer;    // Debugger integration
mod diagnostic_items;       // Diagnostic item collection
pub mod entry;              // Entry point detection
pub mod hir_id_validator;   // HIR ID validation
pub mod input_stats;        // Input statistics
mod lang_items;             // Language item collection
pub mod layout_test;        // Layout testing
mod lib_features;           // Library feature collection
mod reachable;              // Reachability analysis
pub mod stability;          // Stability checking
mod upvars;                 // Upvar analysis
mod weak_lang_items;        // Weak language items

Analysis Pass

The main analysis query coordinates type checking and other analyses: Location: rustc_interface::passes::analysis Query: analysis Runs:
  • Parallel type checking of all items
  • Privacy checking
  • Liveness analysis
  • Intrinsic checking
  • Variance inference
  • Other whole-crate analyses

Pass Timing and Profiling

All major passes are instrumented with timing information:
sess.time("parse_crate", || { /* parsing */ });
sess.time("macro_expand_crate", || { /* expansion */ });
sess.time("AST_validation", || { /* validation */ });
Use rustc -Z time-passes to see timing information for each pass.

Query System

Learn how passes are implemented as queries

Compiler Crates

See which crates implement which passes
Many passes are implemented as queries in the demand-driven query system. See the Query System documentation for details.

Build docs developers (and LLMs) love