rust-lang/rust
Debugging
Tips for hunting down compiler bugs. The deep version of this content is the Debugging the compiler chapter of the rustc-dev-guide; this page is a quick orientation.
Reproducing the bug
Start by reducing the input. The smaller the program, the faster everything else gets.
- For "rustc compiles this incorrectly", produce the smallest example that ICEs or miscompiles.
- For diagnostic regressions, the test usually already exists or can be added under
tests/ui/. - The
tests/crashes/directory is a good place to look for known ICEs that may match.
cargo-bisect-rustc bisects the regression to a single PR. For ICEs, the rustc-supplied bug-report URL in the panic output usually tells you everything bors needs.
-Z flags worth knowing
The compiler has hundreds of unstable -Z flags for diagnostics and tracing. A few of the most useful:
| Flag | What it does |
|---|---|
-Zdump-mir=all |
Dump MIR after every pass, into mir_dump/ |
-Zunpretty=hir,typed |
Print the HIR with inferred types |
-Zunpretty=mir |
Print MIR (similar to -Zdump-mir) |
-Zunpretty=thir-tree |
Print the THIR |
-Zunpretty=expanded |
Source after macro expansion |
-Zunpretty=ast-tree |
The raw AST |
-Zsave-analysis |
Emit semantic-analysis JSON (legacy; rust-analyzer does it better) |
-Zprint-type-sizes |
Print sizes for every type considered |
-Zcrate-attr=… |
Inject crate-level attributes |
-Ztime-passes |
Time each compiler pass |
-Zself-profile=DIR |
Write self-profile data; render with measureme's summarize |
-Ztreat-err-as-bug=1 |
Crash on the first error (gets you a backtrace) |
-Ztrack-diagnostics |
Print which line of rustc emitted a diagnostic |
-Zverbose-internals |
Verbose Debug for internal data structures |
A canonical workflow when investigating a type-checking bug:
RUSTC_LOG=rustc_hir_typeck=debug \
rustc -Zunpretty=hir,typed your-test.rsRUSTC_LOG is a tracing-env-filter string. Most rustc crates emit tracing events at debug and trace levels.
Backtraces and ICE reports
When rustc panics it prints something like:
note: rustc 1.NN.0-nightly (...) running on x86_64-unknown-linux-gnu
note: please make sure that you have updated to the latest nightly
note: please attach the file at `…/rustc-ice-….txt` to your bug report
query stack during panic:
#0 [check_well_formed] checking that ...
#1 [check_mod_well_formedness] checking that mod ...
end of query stackThe query stack tells you which compiler queries were running at the time. To get a Rust-level backtrace as well:
RUST_BACKTRACE=1 ./x build ... # bootstrap
RUST_BACKTRACE=1 rustc your-test.rs # the resulting toolchainOr RUST_BACKTRACE=full for raw frames including std internals.
-Ztreat-err-as-bug=1
When you have an error message but no idea where it comes from, set -Ztreat-err-as-bug=1 to make rustc panic when emitting the first error. Combined with RUST_BACKTRACE=1, this gives you a stack trace pointing at the tcx.dcx().emit_err(...) call site.
Logging
rustc uses tracing throughout. Filter via RUSTC_LOG:
RUSTC_LOG=info # everything at info+
RUSTC_LOG=rustc_borrowck=debug # one crate
RUSTC_LOG=rustc_borrowck::diagnostics=trace # one module
RUSTC_LOG=warn,rustc_hir_typeck=trace # multi-targetThe infrastructure lives in compiler/rustc_log/.
Self-profiling
For performance investigation, use -Zself-profile:
rustc -Zself-profile=. your-crate.rs
summarize summarize <events_file_prefix>This produces machine-readable timing data per query. Combined with flamegraph or Chrome's profiler import format, you get a full breakdown of where compile time went.
Debug builds of rustc
For Rust-side rust-gdb / rust-lldb debugging:
# bootstrap.toml
[rust]
debug = true
debuginfo-level = 2This makes rustc itself debuggable but slows the build (~3–5x). For production-style perf work, prefer [rust] debug-assertions-std = true and leave the compiler at release build.
Crater runs
For "did my change regress some real-world crate?", request a crater run on the PR (@craterbot run mode=...). Crater compiles every public crates.io crate against your PR and a baseline, reporting any newly broken builds.
Common ICE patterns
| Pattern in the panic message | Likely culprit |
|---|---|
delayed_bug not consumed |
Something emitted a delayed bug but never reached the point that drains them |
bound vars in const evaluatable |
Const-generic substitution issue |
assertion failed: !ty.has_infer() |
An inference variable leaked past type checking |
cycle detected when … |
The query system found a query graph cycle; usually a type-checking ordering bug |
evaluator.has_changed() on dataflow |
Borrowck/dataflow invariant break |
For each of these, the fix usually involves either preventing the bad path from being taken, or — if the path is legitimate — reporting a proper user-facing diagnostic before the assertion runs.
Asking for help
The fastest way to get unblocked is to ask in the relevant Zulip stream. For each subsystem there's a topic team:
#t-compiler/help— general compiler debugging#t-types— trait solver / inference#t-libsand#t-libs-api— library questions#t-bootstrap— build system
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.