Lexing and parsing The very first thing the compiler does is take the program (in UTF-8 Unicode text) and turn it into a data format the compiler can work with more conveniently than strings. This happens in two stages: Lexing and Parsing....
Macro expansion Rust has a very powerful macro system. In the previous chapter, we saw how the parser sets aside macros to be expanded (using temporary placeholders). This chapter is about the process of expanding those macros iteratively u...
Name resolution In the previous chapters, we saw how the Abstract Syntax Tree (AST) is built with all macros expanded. We saw how doing that requires doing some name resolution to resolve imports and macro names. In this chapter, we show ho...
Attributes Attributes come in two types: inert (or built-in) and active (non-builtin). Builtin/inert attributes These attributes are defined in the compiler itself, in compiler/rustc_feature/src/builtin_attrs.rs and in the attribute parsers...
The #[test] attribute Many Rust programmers rely on a built-in attribute called #[test]. All you have to do is mark a function and include some asserts like so: #[test] fn my_test() { assert!(2+2 == 4); } When this program is compiled using...
Panicking in Rust Step 1: Invocation of the panic! macro. There are actually two panic macros - one defined in core, and one defined in std. This is due to the fact that code in core can panic. core is built before std, but we want panics t...
AST validation AST validation is a separate AST pass that visits each item in the tree and performs simple checks. This pass doesn't perform any complex analysis, type checking or name resolution. Before performing any validation, the compi...
Feature Gate Checking For the how-to steps to add, remove, rename, or stabilize feature gates, see Feature gates. Feature gates prevent usage of unstable language and library features without a nightly-only #![feature(...)] opt-in. This cha...
Lang items The compiler has certain pluggable operations; that is, functionality that isn't hard-coded into the language, but is implemented in libraries, with a special marker to tell the compiler it exists. The marker is the attribute #[l...
The HIR The HIR – "High-Level Intermediate Representation" – is the primary IR used in most of rustc. It is a compiler-friendly representation of the abstract syntax tree (AST) that is generated after parsing, macro expansion, and name reso...
AST lowering The AST lowering step converts AST to HIR. This means many structures are removed if they are irrelevant for type analysis or similar syntax-agnostic analyses. Examples of such structures include but are not limited to • Parent...
Attribute Parsing Attributes come in two types: inert (or built-in) and active (non-builtin). Inert attributes are parsed during AST lowering to the HIR, while active attributes are expanded during expansion. For more information about the...
HIR Debugging Use the -Z unpretty=hir flag to produce a human-readable representation of the HIR. For cargo projects this can be done with cargo rustc -- -Z unpretty=hir. This output is useful when you need to see at a glance how your code...
Ambig/Unambig Types and Consts Types and Consts args in the AST/HIR can be in two kinds of positions ambiguous (ambig) or unambiguous (unambig). Ambig positions are where it would be valid to parse either a type or a const, unambig position...
The THIR The THIR ("Typed High-Level Intermediate Representation"), previously called HAIR for "High-Level Abstract IR", is another IR used by rustc that is generated after type checking. It is (as of January 2024) used for MIR construction...
The MIR (Mid-level IR) MIR is Rust's Mid-level Intermediate Representation. It is constructed from HIR. MIR was introduced in RFC 1211. It is a radically simplified form of Rust that is used for certain flow-sensitive safety checks – notabl...
MIR construction The lowering of HIR to MIR occurs for the following (probably incomplete) list of items: • Function and closure bodies • Initializers of static and const items • Initializers of enum discriminants • Glue and shims of any ki...
MIR visitor The MIR visitor is a convenient tool for traversing the MIR and either looking for things or making changes to it. The visitor traits are defined in the rustc_middle::mir::visit module – there are two of them, generated via a si...
MIR queries and passes If you would like to get the MIR: • for a function - you can use the optimized_mir query (typically used by codegen) or the mir_for_ctfe query (typically used by compile time function evaluation, i.e., CTFE); • for a...
Inline assembly Overview Inline assembly in rustc mostly revolves around taking an asm! macro invocation and plumbing it through all of the compiler layers down to LLVM codegen. Throughout the various stages, an InlineAsm generally consists...