Open-Source Wikis

/

Rust

/

How to contribute

/

Debugging

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

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

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

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

The 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 = 2

This 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-libs and #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.

Debugging – Rust wiki | Factory