Skip to main content

2026-04-28

Discoveries

Rust Things

Quick Tip - Force types in error output:

let x = some_complex_expression();
let _: () = x;
  • Dev Guide Reference
  • Rust Playground - Includes ASM, LLVM IR, MIR, HIR as outputs.
  • Overview of Compilation Process
    1. rustc Command Line Parsing
    2. Lexical Analysis (i.e. tokenization)
    3. Parsing into AST: Macro Expansion, Name Resolution, Entry Points, Feature Gate Checking, Early Linting
    4. High Level Intermediate Representation (HIR)
    5. Type Inference - process of automatic detection of the type of an expression
    6. Mid-Level Intermediate Representation (MIR) - simplified Rust IR used for borrow checker.
    • Basic Blocks: statements, terminators, control-flow graphs
    • Locals: stack vars, arguments, local vars, temps.
    • Places: memory address expressions
    • Rvalues: expressions producing a value
    • Operands
    1. Borrow Checker - Operates on MIR
    • That all variables are initialized before they are used.
    • That you can’t move the same value twice.
    • That you can’t move a value while it is borrowed.
    • That you can’t access a place while it is mutably borrowed (except through the reference).
    • That you can’t mutate a place while it is immutably borrowed.
    1. MIR Optimizations - Pre-LLVM optimizations.
    2. Code Generation - LLVM process to generate binary.

There is a large list of "undocumented" flags you can use to drive rustc (nightly) outputs by running:

rustc +nightly -Z help

Run the following to see the rustc commands that cargo is running to build each crate.

cargo +nightly build -v

For me, one of them looked like:

/home/user/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/bin/rustc --crate-name reftests --edition=2021 src/main.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=116 --crate-type bin --emit=dep-info,link -C panic=abort -C embed-bitcode=no -C debuginfo=2 --check-cfg 'cfg(docsrs,test)' --check-cfg 'cfg(feature, values())' -C metadata=224fb19d0a7d9e0e -C extra-filename=-06c49fae36f5f61c --out-dir /opt/labs/rust/refs/target/debug/deps -C incremental=/opt/labs/rust/refs/target/debug/incremental -L dependency=/opt/labs/rust/refs/target/debug/deps --extern libc=/opt/labs/rust/refs/target/debug/deps/liblibc-48f66f96bb8290dc.rlib 

If you add a -Zunpretty= flag to the command, you can get different phases of the your rust code compilation. As seen from -Z help:

  -Z unpretty=val -- present the input source, unstable (and less-pretty) variants;
`normal`, `identified`,
`expanded`, `expanded,identified`,
`expanded,hygiene` (with internal representations),
`ast-tree` (raw AST before expansion),
`ast-tree,expanded` (raw AST after expansion),
`hir` (the HIR), `hir,identified`,
`hir,typed` (HIR with types for each node),
`hir-tree` (dump the raw HIR),
`thir-tree`, `thir-flat`,
`mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)

Changing the generated outputs from a stable rustc is accomplished with the --emit argument.

Formats:

  • --emit=type=- - emissions can be sent to STDOUT
  • --emit=type=/path/to/file - emissions can specify a dump file
  • --emit=type1=arg,type=arg - emissions types can be comma separated

Options:

--emit <TYPE>[=<FILE>]
Comma separated list of types of output for the
compiler to emit.
Each TYPE has the default FILE name:
* asm - CRATE_NAME.s
* llvm-bc - CRATE_NAME.bc
* dep-info - CRATE_NAME.d
* link - (platform and crate-type dependent)
* llvm-ir - CRATE_NAME.ll
* metadata - libCRATE_NAME.rmeta
* mir - CRATE_NAME.mir
* obj - CRATE_NAME.o
* thin-link-bitcode - CRATE_NAME.indexing.o

Trait Resolution:

RUSTC_LOG=rustc_trait_selection=info cargo build
RUSTC_LOG=rustc_trait_selection=debug cargo build