diff --git a/docs/articles.md b/docs/articles.md
index 3f39840..5fd0313 100644
--- a/docs/articles.md
+++ b/docs/articles.md
@@ -194,7 +194,7 @@ This section serves as a **technical knowledge base** containing conceptual arti
-| Compiler Engineering |
+Compiler Engineering |
What Happens When You Compile Code |
Coming Soon |
Coming Soon |
@@ -202,6 +202,15 @@ This section serves as a **technical knowledge base** containing conceptual arti
Coming Soon |
+
+| Rustc Pipeline vs C++ Compilation Pipeline |
+Article |
+Coming Soon |
+Coming Soon |
+Coming Soon |
+Coming Soon |
+
+
| Phases of a Compiler |
Coming Soon |
@@ -267,7 +276,6 @@ This section serves as a **technical knowledge base** containing conceptual arti
Coming Soon |
Coming Soon |
-
diff --git a/docs/articles/rustc-pipeline-vs-cpp-compilation-pipeline.md b/docs/articles/rustc-pipeline-vs-cpp-compilation-pipeline.md
new file mode 100644
index 0000000..011bb8f
--- /dev/null
+++ b/docs/articles/rustc-pipeline-vs-cpp-compilation-pipeline.md
@@ -0,0 +1,1270 @@
+---
+title: "Rustc Pipeline vs C++ Compilation Pipeline: A Deep Dive from Source Code to Executable"
+description: "A compiler-engineering comparison of the C++ and Rust compilation pipelines, from parsing and semantic analysis through MIR, LLVM IR, optimization, code generation, and linking."
+keywords:
+ - rustc pipeline
+ - c++ compilation pipeline
+ - clang pipeline
+ - gcc pipeline
+ - rust compiler internals
+ - clang astcontext
+ - rust mir borrow checker
+ - llvm ir generation
+ - template instantiation
+ - trait resolution
+ - monomorphization
+ - compiler engineering
+ - source to executable
+ - rust vs c++ compiler
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+# Rustc Pipeline vs C++ Compilation Pipeline: A Deep Dive from Source Code to Executable
+
+I first went down this path after watching the CUDAOxide work from NVLabs, where Rust is used in a GPU compilation flow rather than in the traditional C++-first mental model. What stood out immediately was not just the backend story, but the fact that Rust does not use C-style textual preprocessing in its core toolchain; instead, it relies on macro expansion and later lowering steps. That pushed me to lay out the full Rust pipeline next to the traditional C++ pipeline and compare the two approaches end to end.
+
+A concrete reference point is [NVLabs/cuda-oxide](https://github.com/NVlabs/cuda-oxide), which documents a Rust-to-CUDA compiler pipeline. Its README describes a layered flow of Rust MIR -> Pliron IR -> LLVM IR -> PTX, which is a good reminder that Rust compilers and Rust-based compilers can use multiple IRs in one build pipeline.
+
+## High-Level Comparison Diagram
+
+
+
+
+
+

+
+
+
+
+
+
+

+
+
+
+
+
+The two pipelines look similar at a distance because both frontends eventually lower into an IR, run optimization passes, and then rely on a backend and linker. The important difference is where each language enforces its core guarantees.
+
+For C++, the compiler mostly checks syntax and type correctness, then enforces a mix of language rules and library-level ownership patterns before handing off to the backend. For Rust, those guarantees are part of the compilation model itself: ownership, borrowing, and lifetimes are validated before code generation, and Rust often passes through multiple IRs before it ever reaches LLVM.
+
+:::note
+Both pipelines eventually reach native machine code, but the important difference is where each compiler enforces program invariants.
+:::
+
+## Key Takeaway
+
+C++ and Rust both reach native machine code, often through LLVM, but they spend compiler complexity in different places.
+
+C++ gives the programmer maximum control and uses tools like RAII, smart pointers, sanitizers, and static analysis to manage correctness.
+
+Rust moves more correctness checks into the compiler itself. Ownership, borrowing, lifetimes, and safe concurrency are validated before LLVM code generation.
+
+So the real difference is not only syntax or performance. The real difference is where safety and program invariants are enforced in the pipeline.
+
+## 1-Minute Summary
+
+- C++ spends more complexity on preprocessing, templates, and source-level flexibility.
+- Rust spends more complexity on macro expansion, name resolution, MIR, and borrow checking.
+- Both usually end up in LLVM, but Rust inserts more language-specific analysis before LLVM sees the program.
+- Safe Rust rejects many memory bugs at compile time; C++ relies more on design discipline plus tooling.
+
+## Where the compiler rejects bugs
+
+| Bug class | C++ typical detection | Rust safe-code behavior |
+|---|---|---|
+| Use-after-free | Sanitizers or code review | Rejected by borrow checking |
+| Out-of-bounds access | Sanitizers and bounds-aware APIs | Runtime checked in safe Rust, often optimized away when provable |
+| Data race | ThreadSanitizer, mutex discipline | Rejected in safe Rust |
+| Null handling | `std::optional`, checks, assertions | `Option` and pattern matching |
+| Lifetime bug | RAII and manual review | Rejected by the lifetime model |
+
+## Table of Contents
+
+1. [Why This Comparison Matters](#why-this-comparison-matters)
+2. [C++ Compilation Pipeline](#c-compilation-pipeline)
+3. [Rust Compilation Pipeline](#rust-compilation-pipeline)
+4. [Internal Compiler Structures](#internal-compiler-structures)
+5. [Ownership Analysis vs the C++ Memory Model](#ownership-analysis-vs-the-c-memory-model)
+6. [Why Rust Needs MIR](#why-rust-needs-mir)
+7. [Optimization Pipelines](#optimization-pipelines)
+8. [Error Detection and Bug Classes](#error-detection-and-bug-classes)
+9. [Real Compiler Commands](#real-compiler-commands)
+10. [LLVM IR Comparison](#llvm-ir-comparison)
+11. [Compile-Time Costs](#compile-time-costs)
+12. [Build Modes, LTO, and Binary Size](#build-modes-lto-and-binary-size)
+13. [Pipeline Stage Mapping](#pipeline-stage-mapping)
+14. [Data Structure Mapping](#data-structure-mapping)
+15. [Optimization Mapping](#optimization-mapping)
+16. [Safety Mechanism Mapping](#safety-mechanism-mapping)
+17. [Can Rust Replace C++?](#can-rust-replace-c)
+18. [References](#references)
+
+## Pipeline Comparison
+
+C++ and Rust share the same end goal, but they distribute work differently across preprocessing, parsing, semantic analysis, and IR lowering.
+
+## Why This Comparison Matters
+
+C++ and Rust are both systems programming languages that target native code, but they optimize for different engineering outcomes.
+
+C++ gives you a very low-level abstraction surface, broad platform support, and a mature ecosystem that has been refined for decades. Rust gives you comparable control over performance and memory layout, but it moves a large class of correctness checks into the compiler.
+
+That changes the shape of the toolchain:
+
+- C++ spends a lot of complexity in preprocessing, templates, semantic analysis, and backend code generation.
+- Rust spends a lot of complexity in macro expansion, trait solving, ownership analysis, MIR construction, and borrow checking.
+
+If you are a compiler engineer, the more interesting question is not which language is "better". It is where each compiler invests complexity, what invariants it proves, and how those decisions affect IR quality, optimization opportunities, compile times, and binary size.
+
+## C++ Compilation Pipeline
+
+The exact pipeline depends on the compiler. Clang uses an LLVM-based flow, while GCC uses a different middle end and backend structure. The logical phases, however, are stable enough to compare.
+
+### 1. Preprocessor
+
+The preprocessor runs before parsing. It expands macros, resolves `#include` directives, evaluates conditional compilation, and removes preprocessing directives from the translation unit.
+
+:::caution
+The C++ preprocessor is textual. The parser does not always see the same program shape that the programmer originally wrote.
+:::
+
+This stage matters because C++ is not just a language of syntax trees. It is also a language of textual substitution at the source level. The preprocessor can change the shape of the program before the parser sees it.
+
+Examples of things handled here:
+
+- `#define` and macro expansion
+- `#include` file inclusion
+- `#if`, `#ifdef`, `#ifndef`, `#elif`, `#endif`
+- pragma-style directives
+
+The main effect is that the parser works on a fully expanded translation unit. This is one reason debugging C++ templates and macros can feel indirect: the source the programmer wrote is not always the source the parser sees.
+
+### 2. Parsing
+
+Parsing converts the token stream into a structured representation of declarations, statements, and expressions.
+
+This stage checks grammar, constructs syntax nodes, and identifies the overall shape of the program. Syntax errors are usually caught here:
+
+- missing semicolons
+- mismatched braces
+- malformed declarations
+- illegal token sequences
+
+Parsing is still mostly structural. It knows that a construct looks like a function declaration or a class definition, but it does not yet know all semantic facts such as overload resolution results, access control, template argument validity, or whether a given expression can be converted to the required type.
+
+### 3. AST
+
+The Abstract Syntax Tree is the compiler's structured representation of the source program.
+
+In Clang, the AST is unusually rich. It preserves source-level information needed for diagnostics, tooling, refactoring, and code generation. It includes declarations, expressions, statements, types, and source-location metadata.
+
+Why this matters:
+
+- Diagnostics become precise because the compiler can point at the original source locations.
+- Static analysis tools can query the AST directly.
+- Code generation still has enough structure to lower source semantics into LLVM IR or another backend IR.
+
+The AST is not yet the final truth. It still mirrors source-level abstractions such as templates, classes, overload sets, and syntactic sugar.
+
+### 4. Semantic Analysis
+
+Semantic analysis, often called Sema in Clang, validates meaning rather than syntax.
+
+This is where the compiler checks things such as:
+
+- type compatibility
+- overload resolution
+- access control
+- implicit conversions
+- object lifetime rules that are expressible in the type system
+- constexpr eligibility
+- basic use of language features such as `auto`, references, and constructors
+
+Semantic analysis is also where the compiler resolves names into declarations, builds candidate sets for overloads, and determines which declarations are actually reachable in the current context.
+
+For C++, this stage becomes expensive because the language is very expressive. Overload resolution, conversion ranking, dependent names, and template-dependent semantics all interact.
+
+### 5. Template Instantiation
+
+Template instantiation is one of the defining costs of C++ compilation.
+
+Templates are not just syntax sugar. They are compile-time code generators. Every concrete instantiation of a template can produce new AST fragments, new semantic work, new overload resolution, and new backend code.
+
+That means a single template definition can expand into many specialized variants:
+
+- `std::vector`
+- `std::vector`
+- `std::vector`
+
+Each instantiation can trigger more parsing-like and semantic-like work, especially when templates depend on other templates.
+
+This is one reason large C++ codebases can become compile-time heavy even when runtime performance is excellent.
+
+### 6. Constant Evaluation
+
+C++ constant evaluation handles expressions that can be resolved at compile time.
+
+This includes:
+
+- `constexpr` variables and functions
+- compile-time branching in constant contexts
+- template metaprogramming patterns that rely on compile-time values
+
+Constant evaluation is useful for performance and correctness. It can eliminate runtime work and catch mistakes early. But it also introduces another layer of compile-time computation that the compiler must reason about.
+
+### 7. IR Generation
+
+After semantic analysis, the compiler lowers source constructs into an intermediate representation.
+
+In Clang this is typically LLVM IR. In GCC, the corresponding lowering path goes through GIMPLE and later RTL. The conceptual role is the same: preserve program meaning in a form that is more suitable for optimization and code generation than the original source tree.
+
+The IR stage matters because:
+
+- high-level control flow can be normalized
+- data-flow facts become easier to analyze
+- optimizations can be shared across languages or frontends
+
+This is the point where the frontend hands off to the middle end.
+
+### 8. LLVM or GCC Middle End
+
+The middle end is where the compiler transforms IR without committing to a specific target ISA too early.
+
+LLVM-based flows typically run passes such as:
+
+- `Mem2Reg`
+- `SROA`
+- `InstCombine`
+- `GVN`
+- `SCCP`
+- loop optimizations
+- inlining
+
+GCC uses its own SSA-based middle end and target-specific optimization machinery, but the role is similar.
+
+The middle end looks for:
+
+- dead code
+- redundant loads and stores
+- constant propagation opportunities
+- common subexpressions
+- loop-invariant code
+- better inlining decisions
+
+This is the broad optimization layer that tends to matter most for performance.
+
+### 9. Backend
+
+The backend turns optimized IR into target-specific machine code.
+
+This includes:
+
+- instruction selection
+- register allocation
+- scheduling
+- calling convention lowering
+- stack frame layout
+- branch formation
+- emission of assembly or object code
+
+This stage is target-sensitive. x86-64, AArch64, RISC-V, and GPU targets all require different instruction-selection and register-allocation decisions.
+
+### 10. Linking
+
+Linking combines object files and libraries into an executable or shared library.
+
+The linker resolves:
+
+- external symbols
+- relocation entries
+- library dependencies
+- section layout
+- final addresses
+
+Linking is not a compiler frontend concern, but it is part of the complete build pipeline. Many "compiler" performance issues only become visible at link time, especially in template-heavy or library-heavy code.
+
+## Rust Compilation Pipeline
+
+Rust's flow is similar in shape, but different in emphasis.
+
+### 1. Parsing
+
+Rust parsing converts tokens into syntax trees, but Rust source is designed to be more structurally regular than C++.
+
+The language has a smaller amount of source-level textual trickery than C++, which makes the parser's job more predictable. That does not make Rust simple; it just moves complexity away from the preprocessor and into macro expansion, type checking, and trait solving.
+
+Parsing catches:
+
+- syntactic form errors
+- malformed item declarations
+- invalid expression structure
+- many obvious grammar mistakes
+
+### 2. Macro Expansion
+
+Macro expansion is one of Rust's major preprocessing-like stages, but it is much more structured than C preprocessor substitution.
+
+:::tip
+Rust macros are preprocessing-like, but they operate on token streams rather than raw text substitution.
+:::
+
+Rust macros can generate items, expressions, patterns, and statements. They are often used for:
+
+- deriving traits
+- generating boilerplate
+- embedding domain-specific syntax
+- reducing repetition in library code
+
+This stage is not just text substitution. It operates on token streams and syntax-level constructs. That makes it more powerful than the C preprocessor and usually more analyzable.
+
+Macro expansion can also be a source of complexity because the compiler must repeatedly expand, reparse, and re-integrate generated code before later stages can reason about it.
+
+### 3. AST
+
+Rust's AST is the parsed syntax tree before most semantic normalization.
+
+It is intentionally not the final form used by analysis. The Rust compiler soon lowers it into more structured internal forms because raw syntax still contains a lot of surface sugar and expansion artifacts.
+
+### 4. Name Resolution
+
+Name resolution decides what each identifier refers to.
+
+This stage maps symbols to modules, items, functions, types, and traits. It resolves imports, paths, and visibility rules.
+
+Rust uses lexical scoping plus module-based visibility, so name resolution is a real compiler phase rather than an incidental lookup problem.
+
+It is also tightly coupled with macro expansion. Some names must be resolved before macros can be expanded correctly, and some macros produce new names that must themselves be resolved afterward.
+
+### 5. HIR
+
+HIR means High-Level Intermediate Representation.
+
+Rust lowers the AST into HIR so the compiler can work on a cleaner, more normalized representation. HIR removes many syntax-level details and makes the structure of the program easier to analyze.
+
+HIR is important because it is:
+
+- closer to the language semantics than raw AST
+- easier to traverse than expanded syntax
+- more stable for queries and diagnostics
+- a good bridge between parsing and type-driven analysis
+
+At this level, the compiler is no longer thinking in terms of tokens and surface syntax. It is thinking in terms of items, expressions, patterns, and desugared control flow.
+
+### 6. Type Checking and Type Inference
+
+Rust performs extensive type inference and type checking.
+
+Unlike C++, Rust leans on inference heavily, but it still computes strong guarantees:
+
+- the concrete type of local bindings
+- generic parameter instantiation
+- coercions between references and slices
+- lifetime relationships
+- variance and subtyping facts where relevant
+
+Type inference in Rust is not just "fill in the blanks". It is part of a larger constraint-solving process that also feeds trait selection and borrow checking.
+
+### 7. Trait Resolution
+
+Traits are Rust's mechanism for ad hoc polymorphism and generic constraints.
+
+Trait resolution decides:
+
+- which implementation applies to a given type
+- whether a trait bound is satisfied
+- which methods are available through trait methods or trait objects
+
+This stage can be expensive in generic-heavy code because it requires solving obligations across a web of types, where each crate may contribute multiple implementations.
+
+Trait resolution is one of the main reasons Rust compile times can be significant in large codebases. It is also one of the main reasons Rust generics are so expressive.
+
+### 8. MIR
+
+MIR means Mid-level Intermediate Representation.
+
+MIR is the point where Rust stops being a high-level, sugared language and becomes a control-flow graph with explicit temporaries, moves, drops, and borrow-relevant structure.
+
+MIR is one of the most important design choices in the compiler because it turns many language rules into explicit dataflow problems.
+
+### MIR CFG Example
+
+
+

+
+
+A MIR graph is the right shape for ownership analysis because it makes moves, drops, and branches explicit. That is exactly what the borrow checker needs and exactly what AST or raw HIR still hide.
+
+### 9. Borrow Checker
+
+The borrow checker validates that references follow Rust's aliasing and lifetime rules.
+
+It checks that:
+
+- mutable references are unique during their active borrow
+- immutable references do not conflict with mutation
+- references do not outlive the storage they point to
+- moves and drops obey ownership rules
+
+This is the stage that gives Rust much of its safety story. It is not a generic lifetime linter. It is a semantic analysis pass over a normalized program representation with control flow.
+
+:::important
+The borrow checker runs before LLVM code generation. Many memory-safety bugs are rejected before optimization or machine-code emission begins.
+:::
+
+### 10. MIR Optimizations
+
+Rust performs several optimization-like transformations before lowering to LLVM IR.
+
+These can include:
+
+- control-flow simplification
+- copy propagation
+- constant propagation
+- dead store elimination
+- drop elaboration and cleanup lowering
+
+The point is to reduce the work the backend has to do and to expose simpler, more canonical IR to LLVM.
+
+### 11. LLVM IR Generation
+
+After MIR, rustc lowers into LLVM IR by default.
+
+This is where Rust joins the same backend ecosystem used by Clang and many other compilers. The backend no longer cares that the source language was Rust, except through metadata, calling conventions, and aliasing properties that the frontend can encode.
+
+### 12. LLVM Backend
+
+The LLVM backend performs the target-specific work:
+
+- instruction selection
+- register allocation
+- instruction scheduling
+- prologue and epilogue insertion
+- assembly emission
+
+This stage is conceptually similar to the C++ LLVM backend path. The frontend differences are mostly gone by this point.
+
+### 13. Linking
+
+Rust can produce object files, static libraries, shared libraries, and executables, just like C++.
+
+The linker resolves symbols, brings in the standard library and dependencies, and produces the final binary.
+
+Rust linking can look different from C++ linking because of:
+
+- different default linkage choices
+- monomorphized generics increasing object size
+- panic runtime and standard library configuration
+
+But the final act is still linker resolution.
+
+## Internal Compiler Structures
+
+The best way to understand a compiler is to understand the data structures that hold its intermediate state.
+
+### Clang
+
+| Structure | Role | Why It Matters |
+|---|---|---|
+| `ASTContext` | Owns and interns core type and declaration information | Central memory arena and type factory for the AST |
+| `Decl` | Base class for declarations such as functions, variables, classes, and typedefs | Represents named entities in the source program |
+| `Stmt` | Base class for statements | Models control flow and executable constructs |
+| `Expr` | Base class for expressions | Models values, operators, calls, and conversions |
+| `Sema` | Semantic analysis engine | Resolves overloads, checks types, and enforces language rules |
+| `CodeGenModule` | Module-level code generation state | Bridges one translation unit to LLVM IR |
+| `CodeGenFunction` | Function-level code generation state | Lowers statements and expressions into LLVM IR |
+
+Clang's structure is useful because it separates source-level meaning from target lowering. `Sema` reasons about language rules, while `CodeGenModule` and `CodeGenFunction` translate the validated AST into backend-friendly IR.
+
+### rustc
+
+| Structure | Role | Why It Matters |
+|---|---|---|
+| `AST` | Raw parsed syntax tree | Captures surface syntax before heavy lowering |
+| `HIR` | High-level, desugared internal representation | Makes analysis easier and more stable |
+| `THIR` | Typed HIR used for some analyses and lowering steps | Bridges the high-level view and MIR |
+| `MIR` | Mid-level control-flow representation | Enables borrow checking, dataflow, and backend-friendly lowering |
+| `TyCtxt` | Central type-context and query entry point | Rustc's main semantic database |
+| `Query System` | Memoized, dependency-tracked computation engine | Powers incremental compilation and compiler scalability |
+| `Crate Metadata` | Serialized information about dependencies | Lets rustc reason across crate boundaries without recompiling everything |
+
+rustc is built around queries. Instead of doing all work in one giant pass, it computes facts on demand and caches them. That design is a major reason the compiler can support incremental recompilation and complex semantic reasoning at scale.
+
+## Ownership Analysis vs the C++ Memory Model
+
+This is where Rust and the C++ memory model differ in the most practical way.
+
+C++ gives you several ownership patterns, but most of them are conventions layered on top of a language that still allows raw pointers and unrestricted aliasing. Rust turns ownership into a first-class compile-time rule.
+
+### C++: Raw Pointers, Smart Pointers, RAII, Move Semantics
+
+Raw pointers are the lowest-level ownership primitive in C++.
+
+```cpp
+#include
+#include
+#include
+#include
+
+void fill(int* data, std::size_t n) {
+ for (std::size_t i = 0; i < n; ++i) {
+ data[i] = static_cast(i);
+ }
+}
+
+std::unique_ptr make_name() {
+ return std::make_unique("clang");
+}
+
+struct FileHandle {
+ explicit FileHandle(const char* path) : fp(std::fopen(path, "r")) {}
+ ~FileHandle() {
+ if (fp) std::fclose(fp);
+ }
+ FILE* fp;
+};
+
+int main() {
+ auto p1 = std::make_unique(42);
+ auto p2 = std::move(p1);
+}
+```
+
+The important ideas:
+
+- Raw pointers do not encode ownership.
+- `std::unique_ptr` encodes single ownership.
+- `std::shared_ptr` encodes reference-counted shared ownership.
+- RAII ties resource cleanup to object lifetime.
+- `std::move` does not move bytes by itself; it marks a value as eligible for move construction or move assignment.
+
+This gives you strong tools, but not a global guarantee. A programmer can still create dangling pointers, iterator invalidation bugs, data races, or lifetime errors if they step outside the safer abstractions.
+
+### Rust: Ownership, Borrowing, Lifetimes, References
+
+Rust makes ownership part of the type system and borrow checking part of compilation.
+
+```rust
+fn fill(data: &mut [i32]) {
+ for (i, slot) in data.iter_mut().enumerate() {
+ *slot = i as i32;
+ }
+}
+
+fn make_name() -> String {
+ "rustc".to_string()
+}
+
+struct FileHandle {
+ path: String,
+}
+
+impl Drop for FileHandle {
+ fn drop(&mut self) {
+ // Cleanup happens automatically when the value goes out of scope.
+ }
+}
+
+fn main() {
+ let s1 = String::from("hello");
+ let s2 = s1; // move
+ // println!("{s1}"); // compile error: s1 was moved
+
+ let mut value = 10;
+ let r1 = &value;
+ let r2 = &value;
+ // let r3 = &mut value; // not allowed while immutable borrows are live
+
+ let mut numbers = [0, 0, 0, 0];
+ fill(&mut numbers);
+ let _ = (s2, r1, r2);
+}
+```
+
+The key contrast is enforcement:
+
+- In C++, ownership is a design discipline supported by types, libraries, and programmer discipline.
+- In Rust, ownership is a compile-time contract enforced by the compiler.
+
+That does not mean Rust has no unsafe escape hatches. It does. But safe Rust makes the common path much more constrained.
+
+### The Compiler View
+
+From the compiler's perspective, the differences matter because aliasing and lifetime information are more explicit in Rust's safe code.
+
+Rust references usually let the compiler assume stronger invariants than raw pointers in C++. That can help the optimizer because the frontend can mark arguments as non-null, dereferenceable, or no-alias when justified.
+
+This is one reason Rust can often produce code as efficient as carefully written C++ while still preserving a stricter source-level safety model.
+
+## MIR, Borrow Checker, and Optimization
+
+This is the middle of the Rust story: MIR makes ownership and lifetime facts explicit enough for the borrow checker and for later optimization passes.
+
+## Why Rust Needs MIR
+
+MIR exists because AST and HIR are too high-level for several important compiler tasks.
+
+### Borrow Checking Needs Explicit Control Flow
+
+Borrow checking needs to know where values are moved, where borrows start and end, where drops happen, and how control flow actually branches.
+
+That is difficult to compute directly from syntax trees because:
+
+- AST nodes are too rich and too syntactic
+- sugar and desugaring hide real control flow
+- temporary lifetimes are implicit
+
+MIR exposes the program as a control-flow graph with explicit statements and terminators. That makes borrow analysis tractable.
+
+### NLL Needs Dataflow on a CFG
+
+Non-Lexical Lifetimes, or NLL, mean a borrow can end before the end of a lexical scope if the compiler can prove it is no longer used.
+
+This is a more precise model than old block-based lifetime checking because it follows actual use sites rather than just braces.
+
+MIR is the right substrate for NLL because it supports:
+
+- liveness analysis
+- move and drop tracking
+- region inference on a control-flow graph
+- precise borrow overlap analysis
+
+### Dataflow Analysis Needs Normalization
+
+MIR lowers many source-level constructs into explicit operations:
+
+- temporaries become visible
+- drops are explicit
+- branching structure is explicit
+- assignments and moves are explicit
+
+That makes dataflow analysis more reliable and easier to implement. The compiler no longer has to reason about too many source-level surface forms at once.
+
+### MIR Opens Optimization Opportunities
+
+MIR is not only for safety. It also helps optimization.
+
+Once the compiler has a canonical control-flow graph, it can more easily perform:
+
+- constant propagation
+- copy propagation
+- dead store elimination
+- simplification of control flow
+- cleanup of unnecessary temporaries
+
+The result is a better foundation for LLVM lowering and for compiler diagnostics.
+
+## Optimization Pipelines
+
+Rust and C++ both eventually rely on LLVM-style optimization, but Rust adds a few language-specific passes before it gets there.
+
+### LLVM Passes Commonly Seen in Both Worlds
+
+| LLVM Pass | What It Does | Why It Matters |
+|---|---|---|
+| `Mem2Reg` | Promotes stack slots to SSA registers | Removes unnecessary memory traffic |
+| `SROA` | Splits aggregates into scalar parts | Exposes more scalar optimization opportunities |
+| `InstCombine` | Simplifies instruction patterns | Canonicalizes IR and removes redundant operations |
+| `GVN` | Global value numbering | Eliminates repeated computations |
+| `SCCP` | Sparse conditional constant propagation | Resolves values and branches from compile-time facts |
+| `LoopVectorize` | Turns scalar loops into vector loops where legal | Exploits SIMD hardware |
+| `LoopUnroll` | Duplicates loop bodies to reduce branch overhead | Helps small hot loops |
+| `Inliner` | Substitutes call sites with callee bodies | Exposes more optimization opportunities |
+
+These passes are relevant to both Clang-produced code and Rust-produced code because both eventually lower into LLVM IR.
+
+### Rust-Specific MIR Optimizations
+
+| Rust MIR Pass | What It Does | Why It Matters |
+|---|---|---|
+| MIR Simplification | Normalizes the control-flow graph | Makes later analyses easier |
+| Copy Propagation | Replaces redundant copies with original values | Shrinks temporary traffic |
+| Const Propagation | Replaces values known at compile time | Reduces work before LLVM lowering |
+| Dead Store Elimination | Removes writes never observed later | Cuts unnecessary memory operations |
+
+The important point is sequencing. Rust can simplify at MIR first, then hand cleaner IR to LLVM. That can improve compile-time clarity and help LLVM do a better job.
+
+### Practical Difference
+
+In C++, the middle end sees code after templates, overload resolution, and constant evaluation have already expanded the program shape.
+
+In Rust, the middle end also sees a lot of semantic decisions, but ownership and borrowing have already been resolved in a way that makes aliasing and lifetimes more explicit.
+
+That difference often shows up in the quality of alias analysis, the availability of `noalias` style metadata, and the optimizer's confidence about reference-based code.
+
+## Error Detection and Bug Classes
+
+C++ and Rust both aim to produce fast native code, but they discover different bugs at different times.
+
+
+

+
+
+### C++: Runtime Detection with Sanitizers
+
+C++ can catch a lot of dangerous bugs with runtime tools:
+
+- ASan: AddressSanitizer
+- UBSan: UndefinedBehaviorSanitizer
+- TSan: ThreadSanitizer
+- MSan: MemorySanitizer
+
+These tools are effective, but they are still runtime tools. That means:
+
+- they must be enabled
+- they may not be enabled in production
+- they only catch what the test workload exercises
+
+Sanitizers are indispensable, but they are not the same as compile-time rejection.
+
+### Rust: Compile-Time Ownership Checks
+
+In safe Rust, the compiler checks many classes of mistakes before code generation:
+
+- use-after-free in safe code
+- double free in safe code
+- data races in safe code
+- dangling references in safe code
+- invalid aliasing of mutable and immutable borrows
+
+That is a major shift in failure mode. The bug is not "caught when tests happen to hit it". The bug is often impossible to express in safe Rust.
+
+### What Safe Rust Prevents
+
+Rust safe code prevents or strongly constrains:
+
+- dangling references
+- iterator invalidation patterns that violate borrowing
+- many null-pointer-style mistakes by using `Option`
+- many data races by constraining shared mutation
+- use-after-free from ordinary safe code
+
+### What Rust Still Does Not Prevent
+
+Rust does not magically eliminate all bugs:
+
+- logic bugs still exist
+- panics still exist
+- deadlocks still exist
+- out-of-memory still exists
+- FFI mistakes still exist
+- bugs in `unsafe` blocks still exist
+- integer overflow behavior depends on build mode and type
+- resource leaks are still possible through deliberate leaking or design errors
+
+So the correct statement is not "Rust prevents all bugs." The correct statement is that safe Rust moves a large, dangerous subset of memory bugs from runtime into compile time.
+
+### Real Bug Example
+
+A classic C++ bug is returning a reference or pointer to a local object. The code compiles, but the reference dangles after the function returns.
+
+```cpp
+const int& bad_ref() {
+ int x = 42;
+ return x; // dangling reference, undefined behavior
+}
+```
+
+The Rust equivalent is rejected in safe code instead of becoming a latent runtime bug.
+
+```rust
+fn bad_ref() -> &i32 {
+ let x = 42;
+ &x
+}
+```
+
+Rustc rejects the borrow because the returned reference would outlive `x`. That is the difference in enforcement model: C++ lets the bug compile, while safe Rust rejects it before code generation.
+
+## Where Rust Still Uses Unsafe
+
+Rust still uses `unsafe` in places where the compiler cannot prove the contract on its own or where the language needs to talk directly to raw memory and external ABIs. Common examples include:
+
+- FFI calls into C, CUDA, or operating-system APIs
+- dereferencing raw pointers
+- implementing low-level containers and allocators
+- interacting with hardware registers or memory-mapped I/O
+- maintaining performance-sensitive internal invariants in `std`
+
+`unsafe` does not mean unstructured or careless. It means the compiler is stepping aside and asking the programmer to prove the extra contract manually. That boundary is usually kept small, reviewed carefully, and wrapped by safe APIs whenever possible.
+
+```rust
+unsafe fn read_ptr(ptr: *const i32) -> i32 {
+ *ptr
+}
+```
+
+The important distinction is that safe Rust stays safe by default, but the language still gives you escape hatches for systems code.
+
+:::important
+`unsafe` does not disable Rust completely. It marks a boundary where the programmer must manually uphold rules the compiler cannot verify.
+:::
+
+## Real Compiler Commands
+
+These commands are useful when you want to see what the compiler is actually doing.
+
+| Command | What It Produces | What To Look For |
+|---|---|---|
+| `clang++ -E file.cpp` | Preprocessed source | Expanded macros, included headers, conditional compilation results |
+| `clang++ -ast-dump -fsyntax-only file.cpp` | AST dump | `FunctionDecl`, `VarDecl`, `Stmt`, `Expr`, templates, and source locations |
+| `clang++ -S -emit-llvm file.cpp -o file.ll` | LLVM IR | Lowered control flow, SSA values, function attributes, alias metadata |
+| `clang++ -ftime-trace file.cpp` | JSON timing trace | Time spent in parsing, Sema, template instantiation, and codegen |
+| `rustc -Zunpretty=hir file.rs` | Pretty-printed HIR | Desugared items and expressions after expansion and resolution |
+| `rustc -Zunpretty=mir file.rs` | MIR dump | Control-flow graph, temporaries, moves, drops, and borrow-relevant structure |
+| `cargo rustc --release -- --emit=llvm-ir` | LLVM IR file | Optimized IR after Rust lowering and LLVM middle-end preparation |
+
+### What Each Output Means
+
+- `clang++ -E` lets you inspect the translation unit after the preprocessor is done. It is the fastest way to see macro expansion and include resolution.
+- `clang++ -ast-dump -fsyntax-only` shows the compiler's structural view of the program. It is often the best debugging aid for templates, overloads, and parser misunderstandings.
+- `clang++ -S -emit-llvm` shows the LLVM IR that the frontend generated before assembly emission. This is where you can inspect attributes, inlining candidates, and loop structure.
+- `clang++ -ftime-trace` writes a Chrome-tracing-compatible JSON file that makes it obvious where compile time is being spent.
+- `rustc -Zunpretty=hir` shows the compiler's desugared high-level form. This is useful for understanding how Rust transformed macros, `for` loops, `async` sugar, and pattern matching.
+- `rustc -Zunpretty=mir` shows the simplified control-flow form used for borrow checking and many compiler analyses. It is one of the best ways to understand ownership-related compilation decisions.
+- `cargo rustc --release -- --emit=llvm-ir` emits LLVM IR for the crate, usually under `target/release/deps/`. This lets you compare Rust's lowering and optimization decisions against Clang's.
+
+:::caution
+Most `rustc -Z` options require a nightly compiler. On stable toolchains, examples may need nightly Rust or `RUSTC_BOOTSTRAP=1` for local experimentation.
+:::
+
+## Command Output Snapshots
+
+
+
+
+
+

+
+
+
+
+
+
+

+
+
+
+
+
+## What LLVM Sees After Both Frontends
+
+
+

+
+
+Both frontends hand LLVM a target-independent IR contract, but they do not hand it the same metadata or the same aliasing guarantees. Rust safe code usually gives LLVM more precise lifetime and alias information than equivalent raw-pointer-heavy C++. Clang can still attach strong facts when the source uses references, `restrict`-like conventions, or library abstractions, but the guarantees are generally less uniform.
+
+LLVM can also remove Rust bounds checks when it proves the index is in range. That is why safe Rust often still optimizes well in hot loops: the check is present in the source model, but not necessarily in the final machine code.
+
+## LLVM IR Comparison
+
+Equivalent C++ and Rust programs often converge to very similar LLVM IR once the frontend-specific work is done.
+
+:::caution
+The LLVM IR shown here is representative. Exact IR changes with compiler version, optimization level, target triple, and flags.
+:::
+
+### Example Source
+
+```cpp
+// C++
+int sum(const int* data, int n) {
+ int acc = 0;
+ for (int i = 0; i < n; ++i) {
+ acc += data[i];
+ }
+ return acc;
+}
+```
+
+```rust
+// Rust
+fn sum(data: &[i32]) -> i32 {
+ let mut acc = 0;
+ for &x in data {
+ acc += x;
+ }
+ acc
+}
+```
+
+### Representative LLVM IR Shape
+
+The exact output depends on compiler version, optimization level, and target triple, but the core shape is often similar:
+
+```llvm
+define i32 @sum(ptr nocapture noundef readonly %data, i32 %n) {
+entry:
+ br label %loop
+
+loop:
+ %i = phi i32 [ 0, %entry ], [ %i.next, %body ]
+ %acc = phi i32 [ 0, %entry ], [ %acc.next, %body ]
+ %idx = getelementptr inbounds i32, ptr %data, i32 %i
+ %val = load i32, ptr %idx, align 4
+ %acc.next = add nsw i32 %acc, %val
+ %i.next = add nuw nsw i32 %i, 1
+ %done = icmp eq i32 %i.next, %n
+ br i1 %done, label %exit, label %body
+
+body:
+ br label %loop
+
+exit:
+ ret i32 %acc
+}
+```
+
+### What Usually Differs
+
+| Aspect | C++ | Rust |
+|---|---|---|
+| Symbol names | Often mangled and compiler-specific | Also mangled, usually by Rust's scheme |
+| Aliasing metadata | Depends on references, pointers, and frontend inference | Often stronger for safe references and slices |
+| Bounds checks | Depends on source form and library API | Slice indexing may emit checks, but LLVM can remove them when it proves they are redundant |
+| Panic or exception paths | Depends on exception settings and source | Rust may include panic paths unless optimized away |
+| Provenance information | Conservative unless proven otherwise | Frontend can attach more useful facts for safe borrows |
+
+The important insight is that LLVM IR is not the whole story. Frontend guarantees shape the IR that LLVM receives. Rust often gives the backend stronger source-level guarantees in safe code, while C++ gives the programmer more freedom and more responsibility.
+
+## Compile-Time Costs
+
+Both languages can be compile-time heavy, but for different reasons.
+
+
+

+
+
+| Cost Center | C++ | Rust |
+|---|---|---|
+| Generic specialization | Template instantiation | Monomorphization |
+| Type-directed overload resolution | Heavy for advanced code | Present, but usually less template-like |
+| Constraint solving | Concepts, SFINAE, overload sets | Trait resolution and obligation solving |
+| Cross-TU reuse | Traditional object-file boundaries, plus modules/PCH where used | Query system plus crate metadata |
+| Incremental compilation | Improving with modules and build caching | Strong focus on incremental queries and crate reuse |
+
+### Cargo vs CMake/Ninja
+
+| Build flow | C++ | Rust |
+|---|---|---|
+| Dependency graph | Usually managed by CMake plus Ninja or Make | Managed by Cargo and the crate graph |
+| Unit of compilation | Translation unit | Crate |
+| Incremental state | Compiler and build-system dependent | Cargo fingerprints plus rustc query caching |
+| Linking orchestration | Build-system driven | Cargo invokes rustc and linker with crate metadata |
+
+CMake and Ninja orchestrate the compilation of object files, then the linker performs the final merge. Cargo does the same job for Rust, but it also owns dependency resolution, crate metadata flow, feature selection, and build-script execution.
+
+### Template Instantiation vs Monomorphization
+
+These are the closest analogous costs.
+
+In C++, template instantiation creates concrete code for each type combination the program uses.
+
+In Rust, monomorphization does the same thing for generics and trait-backed code.
+
+The difference is not that one specializes and the other does not. The difference is where the compiler stores and reuses the computation. Rust's query system is designed around dependency-tracked reuse, while C++ traditionally relies more on translation-unit boundaries and build-system-level caching.
+
+### Trait Resolution vs Template Metaprogramming
+
+Rust trait resolution can be expensive when many generic constraints interact.
+
+C++ template metaprogramming can also become very expensive, but the failure modes differ:
+
+- C++ often pays in instantiation depth, diagnostic complexity, and repeated work across translation units.
+- Rust often pays in trait solving, normalization, and monomorphized code generation.
+
+### Incremental Compilation
+
+Rust benefits from a compiler architecture that was designed with query caching in mind.
+
+C++ can also compile incrementally, but largely at the build-system level:
+
+- compile one translation unit at a time
+- use precompiled headers or modules where available
+- cache objects
+
+Rust does similar things at the build level, but the compiler itself is more query-driven.
+
+## Build Modes, LTO, and Binary Size
+
+Binary size is rarely determined by language alone. It is affected by optimization level, link-time optimization, panic strategy, and how much generic code gets specialized.
+
+### LTO Comparison
+
+- `clang++ -flto` keeps IR available across translation units so the linker can perform whole-program optimization.
+- `cargo build` with `lto = true` or `thinlto = true` gives Rust the same broad idea across crate boundaries.
+- `cargo build -Z build-std` is a nightly-only option that rebuilds the standard library with your selected settings, which matters for custom targets and some size-sensitive builds.
+
+### Debug vs Release Builds
+
+- Debug builds keep more checks visible, reduce aggressive inlining, and preserve easier-to-debug control flow.
+- Release builds enable more inlining, vectorization, constant folding, and bounds-check elimination opportunities.
+- In Rust, a release build can remove a surprising amount of slice checking when LLVM proves the bounds are safe.
+- In C++, release builds can also collapse abstraction overhead, but template-heavy code may still leave a large binary footprint.
+
+### Panic vs Exceptions
+
+| Aspect | C++ exceptions | Rust panics |
+|---|---|---|
+| Default intent | Recoverable error propagation in exception-enabled code | Programmer error or unrecoverable failure |
+| Unwinding | Stack unwinding if enabled | Stack unwinding or abort, depending on `panic` strategy |
+| Cost model | Runtime tables and EH machinery | Smaller by default with `panic = "abort"` |
+| Design advice | Use sparingly in low-latency paths | Do not use panic as ordinary control flow |
+
+### What Increases Size
+
+- Template instantiation in C++
+- Monomorphization in Rust
+- Inlining too aggressively
+- Static linking of large runtimes
+- Duplicate generic code across crates or translation units
+- Panic or exception support
+
+### What Reduces Size
+
+- Link-time optimization
+- Dead code elimination
+- Identical code folding
+- Smaller panic strategy in Rust, such as `panic = "abort"`
+- `-fno-exceptions` and `-fno-rtti` in C++ when acceptable
+- Carefully chosen abstraction boundaries
+
+### Practical Reality
+
+Rust can generate larger binaries than equivalent C++ in some cases, especially when the standard library is statically linked and generic code is heavily instantiated.
+
+C++ can also generate large binaries, especially with template-heavy libraries and exception support.
+
+The real question is not which language is inherently smaller. The real question is whether the build configuration and abstraction choices align with the deployment target.
+
+In performance-critical systems, code size affects:
+
+- instruction-cache pressure
+- cold-start time
+- paging behavior
+- embedded flash usage
+- distribution size
+
+So size is not a cosmetic concern. It is a real systems constraint.
+
+## Pipeline Stage Mapping
+
+| Conceptual Stage | C++ | Rust |
+|---|---|---|
+| Source ingestion | Source text | Source text |
+| Lexing / tokenization | Implicit in preprocessing and parsing | Explicit lexer before parsing |
+| Macro or textual expansion | Preprocessor | Macro expansion |
+| Syntax tree | AST | AST |
+| Early semantic checks | Sema | Name resolution and type checking |
+| Generic specialization | Template instantiation | Monomorphization |
+| High-level IR | Clang AST / GCC GIMPLE-like forms | HIR |
+| Mid-level IR | Compiler-specific middle end or LLVM IR after lowering | MIR |
+| Memory and lifetime reasoning | Mostly library discipline and diagnostics | Borrow checker on MIR |
+| Backend input | LLVM IR or GCC middle-end IR | LLVM IR |
+| Machine code generation | Target backend | LLVM backend |
+| Final assembly / executable | Assembler + linker | Assembler + linker |
+
+## Data Structure Mapping
+
+| Clang | Rustc | Role |
+|---|---|---|
+| `ASTContext` | `TyCtxt` | Global semantic context and shared compiler state |
+| `Decl` | `HIR` items | Named program entities |
+| `Stmt` | HIR/MIR statements | Executable control-flow units |
+| `Expr` | HIR expressions / THIR | Value-producing program fragments |
+| `Sema` | Name resolution + type checking + trait solving | Enforces language rules |
+| `CodeGenModule` | LLVM IR lowering context | Module-level backend bridge |
+| `CodeGenFunction` | MIR-to-LLVM lowering for a function | Function-level backend bridge |
+| Clang AST | Rust AST | Raw syntax and structure |
+| Clang semantic graph | Rust HIR / THIR / MIR | Normalized analysis-friendly representation |
+| Clang diagnostics | rustc diagnostics | User-facing compile errors and notes |
+
+## Optimization Mapping
+
+| LLVM or C++ Side | Rust Side | Common Purpose |
+|---|---|---|
+| `Mem2Reg` | MIR simplification + lowering cleanup | Move stack temporaries into SSA form |
+| `SROA` | MIR scalarization opportunities | Break aggregates into scalars |
+| `InstCombine` | LLVM `InstCombine` after Rust lowering | Fold redundant instructions |
+| `GVN` | LLVM `GVN` after Rust lowering | Remove repeated computations |
+| `SCCP` | MIR const propagation + LLVM `SCCP` | Propagate constants through CFG |
+| `LoopVectorize` | LLVM loop vectorization | Use SIMD where legal |
+| `LoopUnroll` | LLVM loop unrolling | Reduce branch overhead in hot loops |
+| `Inliner` | LLVM inlining | Expose more optimization context |
+| `Copy Propagation` | Rust MIR copy propagation | Eliminate redundant temporaries |
+| `Dead Store Elimination` | Rust MIR DSE | Remove writes never observed |
+
+The main point is that Rust does not replace LLVM optimization. It adds a frontend-specific layer that prepares stronger semantic information before LLVM sees the code.
+
+## Safety Mechanism Mapping
+
+| Concern | C++ Mechanism | Rust Mechanism |
+|---|---|---|
+| Use-after-free | Sanitizers, code review, ownership types | Borrow checker and ownership in safe code |
+| Out-of-bounds access | Sanitizers, checked APIs, careful coding | Runtime checked in safe Rust, often optimized away when provable |
+| Data race | TSan, mutex discipline, atomic discipline | `Send`, `Sync`, ownership, and borrowing rules |
+| Null handling | Raw pointers or `std::optional` | `Option` and pattern matching |
+| Uninitialized memory | MSan, careful initialization | Safe code rules and initialization guarantees |
+| Undefined behavior | Compiler warnings plus runtime tools | Smaller safe surface, `unsafe` boundaries |
+| Lifetime bugs | RAII and careful design | Lifetimes validated at compile time |
+
+Rust does not remove the need for tests, fuzzing, static analysis, or sanitizers. It changes the default failure mode so that many classes of bugs are rejected before the executable exists.
+
+## Can Rust Replace C++?
+
+:::note
+This is not a language-war question. The practical question is where Rust's compile-time guarantees reduce risk enough to justify migration cost.
+:::
+
+The honest answer is: sometimes, partially, and not universally.
+
+### Operating Systems
+
+Rust is already relevant for kernels, drivers, filesystems, and user-space system components.
+
+It can replace C++ in new subsystems where memory safety is a priority and the ecosystem is acceptable. But full replacement is hard because operating systems have:
+
+- entrenched ABIs
+- assembly-heavy paths
+- platform-specific boot and interrupt code
+- existing C and C++ codebases that are too large to rewrite wholesale
+
+### Embedded Systems
+
+Rust is a strong candidate for embedded development, especially where memory safety and predictable behavior matter.
+
+C++ remains extremely strong because of:
+
+- existing vendor support
+- mature bare-metal toolchains
+- low-level hardware abstraction libraries
+- very small runtime footprints when configured carefully
+
+In embedded, the deciding factor is often not language elegance. It is certification, ecosystem maturity, and device support.
+
+### Game Engines
+
+Game engines are a mixed case.
+
+C++ remains dominant because of:
+
+- mature engine architecture
+- extensive platform support
+- direct control over memory and performance
+- decades of toolchain and middleware integration
+
+Rust is attractive for engine subsystems, tooling, asset pipelines, networking, and safety-sensitive components. A full engine rewrite is a bigger ecosystem problem than a language problem.
+
+### Browsers
+
+Browsers are one of Rust's strongest application areas because they are huge, security-sensitive, and concurrency-heavy.
+
+Rust is a good fit for:
+
+- rendering subsystems
+- parsing and sandboxed processing
+- component isolation
+- security-sensitive infrastructure
+
+But browsers still contain enormous C++ codebases. Replacement is gradual, not absolute.
+
+### Cloud Infrastructure
+
+Rust is very competitive in cloud services and infrastructure code because:
+
+- memory safety matters
+- concurrency matters
+- binary performance matters
+- startup time and predictability matter
+
+This is one of the most realistic areas for Rust to displace C++ over time, especially in new services and security-focused components.
+
+### HPC
+
+C++ still has a major advantage in HPC because of:
+
+- entrenched libraries
+- numerical ecosystem maturity
+- decades of tuning around vectorization and MPI-style workflows
+- compiler familiarity in research and production clusters
+
+Rust can absolutely be used in HPC, but ecosystem friction is still higher than in C++.
+
+### GPU Programming
+
+GPU programming is one of the hardest areas for Rust to replace C++ in the near term.
+
+Why:
+
+- CUDA and HIP ecosystems are deeply C++-centered
+- device-side tooling is still maturing in Rust
+- vendor libraries and examples are often C++ first
+- many GPU developers depend on template-based metaprogramming and intrinsics-heavy idioms
+
+Rust is promising for host-side orchestration, safety wrappers, and some GPU experiments, but C++ still dominates the mainstream GPU programming stack.
+
+### Balanced Conclusion
+
+Rust does not replace C++ everywhere. It replaces C++ best where:
+
+- memory safety is a first-class requirement
+- ownership models are helpful rather than awkward
+- ecosystem maturity is sufficient
+- long-term maintenance cost matters
+
+C++ remains the better fit where:
+
+- legacy integration is unavoidable
+- hardware and vendor ecosystems are C++-first
+- certification or tooling already depends on C++
+- the team has a deep, mature C++ investment
+
+The engineering conclusion is not a language war. It is a portfolio decision. Use Rust where compile-time safety materially reduces risk. Keep C++ where the ecosystem, control surface, or migration cost is still the deciding factor.
+
+## References
+
+- [Clang CFE Internals Manual](https://clang.llvm.org/docs/InternalsManual.html) - Clang's internal architecture, including the lexer, parser, AST, Sema, and code generation libraries.
+- [Introduction to the Clang AST](https://clang.llvm.org/docs/IntroductionToTheClangAST.html) - Clang AST, `ASTContext`, `Decl`, `Stmt`, `Expr`, and the source-level AST model.
+- [The Rust Compiler Development Guide](https://rustc-dev-guide.rust-lang.org/) - rustc architecture, compiler queries, MIR, and implementation details.
+- [The MIR (Mid-level IR)](https://rustc-dev-guide.rust-lang.org/mir/index.html) - rustc MIR, control-flow graphs, borrow checking, and MIR lowering.
+- [Queries: demand-driven compilation](https://rustc-dev-guide.rust-lang.org/query.html) - rustc's query system and incremental compilation model.
+- [LLVM Language Reference Manual](https://llvm.org/docs/LangRef.html) - LLVM IR semantics and the contract seen by the backend.
+- [LLVM's Analysis and Transform Passes](https://llvm.org/docs/Passes.html) - LLVM optimization passes such as `mem2reg`, `sroa`, `gvn`, `instcombine`, and `sccp`.
+- [GCC Internals](https://gcc.gnu.org/onlinedocs/gccint/) - GCC's internal structure, trees, GIMPLE, RTL, and backend pipeline.
+- [The Rust Reference](https://doc.rust-lang.org/reference/) - The normative language reference for Rust syntax, semantics, and ownership rules.
+- [What is Ownership?](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html) - Rust ownership, borrowing, and move semantics from the Rust Book.
diff --git a/sidebars/site.js b/sidebars/site.js
index 6105c94..c267479 100644
--- a/sidebars/site.js
+++ b/sidebars/site.js
@@ -210,8 +210,15 @@ const site = {
'articles/where_gcc_and_clang_diverge_stencil_pass_trace',
'articles/hft_stdlib_restrictions',
'articles/language_energy_efficiency_validation',
- 'articles/rust-vs-modern-cpp-memory-safety-beyond-the-hype',
-
+ {
+ type: 'category',
+ label: 'Compiler Comparisons',
+ collapsed: false,
+ items: [
+ 'articles/rust-vs-modern-cpp-memory-safety-beyond-the-hype',
+ 'articles/rustc-pipeline-vs-cpp-compilation-pipeline',
+ ],
+ },
{
type: 'category',
label: 'Tech Blog',
diff --git a/static/img/articles/clang-ftime-trace-output.png b/static/img/articles/clang-ftime-trace-output.png
new file mode 100644
index 0000000..aa354f4
Binary files /dev/null and b/static/img/articles/clang-ftime-trace-output.png differ
diff --git a/static/img/articles/compile-time-heatmap.png b/static/img/articles/compile-time-heatmap.png
new file mode 100644
index 0000000..bc66d4a
Binary files /dev/null and b/static/img/articles/compile-time-heatmap.png differ
diff --git a/static/img/articles/compiler-safety-chart.png b/static/img/articles/compiler-safety-chart.png
new file mode 100644
index 0000000..230e1b4
Binary files /dev/null and b/static/img/articles/compiler-safety-chart.png differ
diff --git a/static/img/articles/llvm-convergence.png b/static/img/articles/llvm-convergence.png
new file mode 100644
index 0000000..ee7344a
Binary files /dev/null and b/static/img/articles/llvm-convergence.png differ
diff --git a/static/img/articles/rustc-cpp-pipeline.png b/static/img/articles/rustc-cpp-pipeline.png
new file mode 100644
index 0000000..aa35e7d
Binary files /dev/null and b/static/img/articles/rustc-cpp-pipeline.png differ
diff --git a/static/img/articles/rustc-mir-cfg.png b/static/img/articles/rustc-mir-cfg.png
new file mode 100644
index 0000000..f331eb4
Binary files /dev/null and b/static/img/articles/rustc-mir-cfg.png differ
diff --git a/static/img/articles/rustc-mir-output.png b/static/img/articles/rustc-mir-output.png
new file mode 100644
index 0000000..639b21a
Binary files /dev/null and b/static/img/articles/rustc-mir-output.png differ
diff --git a/static/img/articles/rustc-rust-pipeline.png b/static/img/articles/rustc-rust-pipeline.png
new file mode 100644
index 0000000..3cee35c
Binary files /dev/null and b/static/img/articles/rustc-rust-pipeline.png differ