This guide covers the essentials of developing the Rust compiler itself, from understanding its architecture to building and testing your changes.
Compiler Architecture
The Rust compiler is organized into multiple crates, each handling specific compilation phases:
rustc_driver Orchestrates the compilation process and knits together code from other crates
rustc_ast Abstract Syntax Tree representation and parsing
rustc_hir High-level Intermediate Representation after AST lowering
rustc_middle Core type system and middle-stage representations
rustc_codegen_* Code generation backends (LLVM, Cranelift, GCC)
rustc_borrowck Borrow checker implementation
Setting Up Your Development Environment
Clone the repository
git clone https://github.com/rust-lang/rust.git
cd rust
Configure your build
Create a config.toml file in the root directory: ./configure
# Or use the setup wizard
./x.py setup
Development Profile
Library Profile
Performance Profile
profile = "compiler"
[ llvm ]
download-ci-llvm = true
[ rust ]
debug = true
debug-assertions = true
incremental = true
profile = "library"
[ llvm ]
download-ci-llvm = true
[ rust ]
download-rustc = "if-unchanged"
profile = "codegen"
[ llvm ]
download-ci-llvm = false
assertions = false
[ rust ]
debug = false
optimize = true
Build the compiler
# Build stage 1 compiler (recommended for development)
./x.py build --stage 1
# Build stage 2 compiler (for testing compiler changes)
./x.py build --stage 2
Stage 1 is usually sufficient for most development work. Stage 2 is needed when you’re modifying the compiler itself and need to test those changes.
Bootstrap Build System
The Rust compiler uses a multi-stage bootstrap process:
Stage 0 (Beta Compiler)
↓ builds
Stage 1 (Your Changes)
↓ builds
Stage 2 (Self-hosting)
Build Stages Explained
Stage 0 - Bootstrap Compiler
The stage 0 compiler is downloaded from Rust’s CI. This is a pre-built stable or beta compiler used to bootstrap your build. Location: build/x86_64-unknown-linux-gnu/stage0/
Stage 1 is built using the stage 0 compiler. This includes your changes and is suitable for most development work. Location: build/x86_64-unknown-linux-gnu/stage1/Use case: Testing library changes, running the compiler with your modifications
Stage 2 is built using the stage 1 compiler. This ensures your compiler can compile itself. Location: build/x86_64-unknown-linux-gnu/stage2/Use case: Validating compiler changes, running the full test suite
Common Build Commands
Using x.py
The x.py script is the main entry point for building and testing:
Build Commands
Check Commands
Test Commands
Other Commands
# Build the compiler
./x.py build --stage 1
# Build specific components
./x.py build library/std
./x.py build compiler/rustc_driver
# Build with verbose output
./x.py build --stage 1 -v
# Build for a specific target
./x.py build --target x86_64-unknown-linux-gnu
Directory Structure
rust/
├── compiler/ # Compiler crates
│ ├── rustc_driver/ # Main driver
│ ├── rustc_ast/ # Abstract Syntax Tree
│ ├── rustc_hir/ # High-level IR
│ ├── rustc_middle/ # Type system, MIR
│ ├── rustc_borrowck/ # Borrow checker
│ ├── rustc_codegen_llvm/ # LLVM backend
│ ├── rustc_codegen_ssa/ # Shared codegen
│ └── ... # 70+ compiler crates
├── library/ # Standard library
│ ├── std/ # Standard library
│ ├── core/ # Core library (no_std)
│ ├── alloc/ # Allocation and collections
│ └── test/ # Test framework
├── src/
│ ├── bootstrap/ # Build system
│ └── tools/ # Associated tools
├── tests/ # Compiler test suites
│ ├── ui/ # Compile-fail tests
│ ├── run-make/ # Integration tests
│ ├── codegen-llvm/ # Code generation tests
│ └── debuginfo/ # Debug info tests
└── build/ # Build output
Working with Compiler Crates
Adding a New Compiler Crate
Create the crate directory
mkdir compiler/rustc_my_feature
cd compiler/rustc_my_feature
Create Cargo.toml
[ package ]
name = "rustc_my_feature"
version = "0.0.0"
edition = "2024"
[ dependencies ]
rustc_middle = { path = "../rustc_middle" }
rustc_span = { path = "../rustc_span" }
Add to the workspace
Update the root Cargo.toml to include your new crate in the workspace members.
Use in other crates
Add your crate as a dependency in other compiler crates that need it.
Compilation Phases
Understanding the compilation pipeline helps when working on specific components:
Lexing & Parsing
Source code → Tokens → AST Handled by rustc_lexer and rustc_parse
Name Resolution
Resolve names and imports Handled by rustc_resolve
AST Lowering
AST → HIR (High-level IR) Handled by rustc_ast_lowering
Type Checking
Verify types, trait resolution Handled by rustc_hir_analysis
MIR Building
HIR → MIR (Mid-level IR) Handled by rustc_mir_build
MIR Optimization
Optimize MIR Handled by rustc_mir_transform
Borrow Checking
Verify memory safety Handled by rustc_borrowck
Code Generation
MIR → LLVM IR → Machine Code Handled by rustc_codegen_llvm, rustc_codegen_ssa
Configuration Options
Important build.toml Settings
LLVM Options
Rust Options
Build Options
[ llvm ]
# Download pre-built LLVM (recommended)
download-ci-llvm = true
# Enable LLVM assertions (debugging)
assertions = true
# LLVM targets to build
targets = "X86;ARM;AArch64"
# Use ninja for faster builds
ninja = true
[ rust ]
# Enable debug info
debuginfo-level = 1
# Enable debug assertions
debug-assertions = true
# Enable incremental compilation
incremental = true
# Codegen backends
codegen-backends = [ "llvm" , "cranelift" ]
# Channel (dev, nightly, beta, stable)
channel = "dev"
[ build ]
# Number of parallel jobs
jobs = 8
# Build documentation
docs = true
# Verbose output
verbose = 1
# Build extended tools
extended = true
tools = [ "cargo" , "rustfmt" , "clippy" ]
Development Workflow
Typical Development Cycle
Make your changes to compiler crates
Quick check with ./x.py check
Build stage 1 with ./x.py build --stage 1
Run targeted tests with ./x.py test tests/ui/my-feature
Run full test suite before submitting
Always run ./x.py test before submitting a PR to catch any regressions.
Speeding Up Development
Use --keep-stage ./x.py build --stage 1 --keep-stage 0
Avoid rebuilding earlier stages
Use check instead of build Skip code generation for faster iteration
Download pre-built artifacts Set download-ci-llvm = true and download-rustc = "if-unchanged"
Incremental compilation [ rust ]
incremental = true
Compiler Queries
The Rust compiler uses a query-based architecture for on-demand computation:
// Example query definition
rustc_queries! {
query type_of ( key : DefId ) -> Ty <' tcx > {
desc { "computing type of `{}`" , key }
}
}
Key Concepts
Queries are cached, on-demand computations
Incremental compilation tracks query dependencies
Query results are memoized between compilations
Defined in rustc_middle/src/query/mod.rs
Resources
Rustc Dev Guide Comprehensive guide to compiler internals
Zulip Chat Get help from the compiler team
Forge Infrastructure and process documentation
GitHub Issues Track bugs and feature requests
Next Steps
Library Development Learn about developing the standard library
Debugging Debug compiler issues and crashes
Profiling Profile and optimize compiler performance