Skip to main content
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

1

Clone the repository

git clone https://github.com/rust-lang/rust.git
cd rust
2

Configure your build

Create a config.toml file in the root directory:
./configure
# Or use the setup wizard
./x.py setup
profile = "compiler"

[llvm]
download-ci-llvm = true

[rust]
debug = true
debug-assertions = true
incremental = true
3

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

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 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

1

Create the crate directory

mkdir compiler/rustc_my_feature
cd compiler/rustc_my_feature
2

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" }
3

Add to the workspace

Update the root Cargo.toml to include your new crate in the workspace members.
4

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:
1

Lexing & Parsing

Source code → Tokens → ASTHandled by rustc_lexer and rustc_parse
2

Name Resolution

Resolve names and importsHandled by rustc_resolve
3

AST Lowering

AST → HIR (High-level IR)Handled by rustc_ast_lowering
4

Type Checking

Verify types, trait resolutionHandled by rustc_hir_analysis
5

MIR Building

HIR → MIR (Mid-level IR)Handled by rustc_mir_build
6

MIR Optimization

Optimize MIRHandled by rustc_mir_transform
7

Borrow Checking

Verify memory safetyHandled by rustc_borrowck
8

Code Generation

MIR → LLVM IR → Machine CodeHandled by rustc_codegen_llvm, rustc_codegen_ssa

Configuration Options

Important build.toml Settings

[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

Development Workflow

Typical Development Cycle

  1. Make your changes to compiler crates
  2. Quick check with ./x.py check
  3. Build stage 1 with ./x.py build --stage 1
  4. Run targeted tests with ./x.py test tests/ui/my-feature
  5. 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

./x.py check
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

Build docs developers (and LLMs) love