Open-Source Wikis

/

Rust

/

How to contribute

/

Patterns and conventions

rust-lang/rust

Patterns and conventions

A pragmatic guide to the conventions that recur across rust-lang/rust. The official style guide is the in-tree Rust style guide and the rustfmt config; this page captures the project-internal conventions on top.

Crate naming

  • rustc_* — internal compiler crates. Not stable, not for public consumption. Live under compiler/.
  • rustc_*_impl — the heavy implementation behind a thin facade (rustc_driver vs. rustc_driver_impl, rustc_query_system vs. rustc_query_impl). Allows incremental compilation by isolating churn.
  • Plain names (core, alloc, std, proc_macro, test) — public standard library crates. Live under library/.

File and module layout

  • Each crate has a src/lib.rs (or src/main.rs for binaries) that lists mods and pub uses.
  • The convention is pub use foo::Bar; at the lib root rather than re-exporting throughout. This keeps use rustc_middle::ty::Ty; working regardless of where Ty is implemented.
  • Submodules under src/ mirror logical structure, not alphabetical order.

// tidy-alphabetical-* markers

Many lists in this repo (workspace members, crates in dependency lists, lints in static arrays) are kept alphabetical and enforced by tidy. The marker pair:

# tidy-alphabetical-start
"compiler/rustc",
"src/build_helper",

# tidy-alphabetical-end

…tells tidy to enforce alphabetical ordering of the lines in between. Honor the markers.

Diagnostics

Compiler errors and warnings go through the rustc_errors crate. The convention is:

  1. Fluent messages — user-facing strings live in .ftl files under each crate's messages/ directory, not inline.
  2. Diagnostic structs — derive #[derive(Diagnostic)] (or Subdiagnostic, LintDiagnostic) on a struct that holds the data the message needs.
  3. Emit via tcx.dcx() or the Session — never println! an error.

Example pattern:

#[derive(Diagnostic)]
#[diag(borrowck_borrow_through_x)]
struct BorrowThroughX {
    #[primary_span]
    span: Span,
    name: Symbol,
}

tcx.dcx().emit_err(BorrowThroughX { span, name });

The corresponding .ftl entry lives in compiler/rustc_borrowck/messages.ftl.

tracing over println!

Use tracing::{debug, info, trace, warn, error} and instrumented spans (#[instrument]) for compiler logging; println! ends up in user output. See Debugging for RUSTC_LOG filter syntax.

Error handling

  • ErrorGuaranteed — a zero-sized token returned by dcx().emit_err(...). Many APIs require it as evidence that an error has been emitted before they take a fallible path. Don't construct it manually.
  • Result<T, ErrorGuaranteed> — the common return type for "this might bail with a diagnostic".
  • Delayed bugsdcx.delayed_bug(msg) records an invariant that must be flagged via a real error, but the real error happens later. Use this to assert "this code path is only reached if we already emitted an error somewhere".

TyCtxt and queries

Almost everything in the compiler reaches global state via TyCtxt. Conventions:

  • Pass tcx: TyCtxt<'tcx> rather than &TyCtxt.
  • Compute things via queries (tcx.def_kind(def_id), tcx.type_of(def_id)). Queries are memoized and form the basis of incremental compilation.
  • New queries are added in compiler/rustc_middle/src/query/mod.rs; their providers are registered in rustc_query_impl.

Lifetimes named 'tcx

The lifetime 'tcx runs through the type system: Ty<'tcx>, TyCtxt<'tcx>, Body<'tcx>. It is the lifetime of the arena allocations behind TyCtxt. When you see <'tcx> on a struct, it's almost always this.

Arena allocation

Heavy compiler data structures (types, AST nodes, MIR bodies) are arena-allocated for speed. You'll see tcx.arena.alloc(...) and per-IR arena types (tcx.hir_arena, etc.). Don't Box up these things — use the arena.

Cell types

The compiler uses several specialized cell types from rustc_data_structures:

  • OnceCell / OnceLock for write-once globals
  • FxHashMap / FxHashSet (FxHash) — faster, deterministic alternatives to HashMap
  • IndexVec<I, T> for vectors keyed by a typed integer index
  • BitSet, SparseBitMatrix for dataflow

Use these instead of std equivalents in compiler code; they're tuned for rustc's workload.

Feature gates

Unstable features go through compiler/rustc_feature/. Each unstable feature has:

  • A name (#![feature(my_feature)])
  • A tracking issue (#NNNNN)
  • A status: active, accepted, or removed
  • An entry under compiler/rustc_feature/src/unstable.rs (or stable/removed)

-Z flags work the same way but go through compiler/rustc_session/src/options.rs.

Tidy-banned patterns

A few things tidy will reject:

  • New external crates.io dependencies not in src/tools/tidy/src/extdeps.rs
  • New pub use paths that aren't either documented or marked unstable
  • Files larger than the size threshold in tidy's large_files check
  • Trailing whitespace, mixed tabs/spaces

License headers and REUSE.toml

License metadata is centralized in REUSE.toml following the REUSE specification. Most source files don't need an SPDX header — the central file declares licensing for whole directories.

Rustfmt

The repo uses an opinionated rustfmt.toml (more conservative than the rustfmt default). Run ./x fmt before pushing. Reviewers may ask for non-format-driven changes ("can you split this expression for readability") that rustfmt won't enforce.

PR titles

Prefix the PR title with the area being touched, in lowercase: borrowck: fix message ordering, bootstrap: stop downloading X twice. Tooling consumes these prefixes for changelog generation.

Cross-cutting "do not bloat" attitude

Compile time and binary size are first-class concerns:

  • Avoid adding heavy dependencies (syn and quote are only used in proc-macro code, not in rustc itself)
  • Don't derive(Debug, Clone, Hash, PartialEq, Eq) reflexively — these add code
  • Watch -Zprint-type-sizes when adding new fields to hot types like Ty, TyKind, or query keys
  • Be careful with where Self: Sized and trait-object-using indirection — devirtualization matters

These are rules of thumb the team brings up in review. Treat them as defaults, not absolutes.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Patterns and conventions – Rust wiki | Factory