Const Evaluation
Const evaluation (CTFE — Compile-Time Function Evaluation) is the compiler phase in which rustc's internal MIR interpreter evaluates constant expressions during compilation and embeds the resulting values directly into the compiled binary or type definitions.
Contexts That Trigger Guaranteed Compile-Time Evaluation
In Rust, an expression is guaranteed to be evaluated at compile time only when it appears in a const context:
| Const Context | Syntax Example | Evaluated At |
|---|---|---|
const item |
const MAX_CONNECTIONS: usize = 1024 * 4; |
Compile time (when referenced) |
static / static mut item |
static HEADER: [u8; 4] = [0x89, b'P', b'N', b'G']; |
Compile time |
| Array length expression | let buf: [u8; 16 * 8]; |
Compile time |
Array repeat initializer ([const { ... }; N]) |
let slots: [Option<String>; 8] = [const { None }; 8]; |
Compile time |
| Enum discriminant value | enum Tag { First = 1 << 3 } |
Compile time |
| Const generic argument | Matrix::<f32, { 2 + 2 }, 4> |
Compile time |
Inline const { ... } block |
let table = const { build_crc_table() }; |
Compile time |
Pattern const { ... } block |
match x { const { 10 * 2 } => ... } |
Compile time |
How the Const Evaluator Works (Miri Engine Inside rustc)
During compilation, rustc lowers const contexts to Mid-level Intermediate Representation (MIR) and executes them inside the same abstract-machine interpreter engine that powers Miri:
Source Code (`const TABLE: [u16; 256] = compute_table();`)
|
v
MIR Lowering
|
v
Compile-Time MIR Interpreter (CTFE)
+-- Executes loops, branches, and `const fn` calls deterministically
+-- Rejects integer overflow, out-of-bounds indexing, or UB as a COMPILE ERROR
+-- Serializes final `[u16; 256]` bytes directly into `.rodata` binary section!
Compile-Time Error Detection During Const Evaluation
Unlike runtime execution where integer overflow in --release wraps and out-of-bounds indexing panics at runtime, any arithmetic overflow, division by zero, out-of-bounds array access, or panic!() encountered in a const context fails compilation immediately with error E0080:
// ❌ does not compile
const ITEMS: [u32; 3] = [10, 20, 30];
const OUT_OF_BOUNDS: u32 = ITEMS[5];
fn main() {}
error[E0080]: evaluation of constant value failed
--> src/main.rs:3:28
|
3 | const OUT_OF_BOUNDS: u32 = ITEMS[5];
| ^^^^^^^^ index out of bounds: the length is 3 but the index is 5
Generating a Lookup Table at Compile Time
By computing lookup tables in a const item, the binary starts up with the table already precomputed in read-only memory (0 CPU cycles spent at startup):
const fn generate_popcount_table() -> [u8; 256] {
let mut table = [0_u8; 256];
let mut i = 0;
while i < 256 {
table[i] = (i as u8).count_ones() as u8;
i += 1;
}
table
}
static POPCOUNT_TABLE: [u8; 256] = generate_popcount_table();
fn main() {
println!("popcount(0b0000_0000) = {}", POPCOUNT_TABLE[0b0000_0000]);
println!("popcount(0b1010_0101) = {}", POPCOUNT_TABLE[0b1010_0101]);
println!("popcount(0b1111_1111) = {}", POPCOUNT_TABLE[0b1111_1111]);
}
popcount(0b0000_0000) = 0
popcount(0b1010_0101) = 4
popcount(0b1111_1111) = 8