# Rustc Internals for HIR/MIR Analysis in fold-rust > Generated 2026-05-28. Research on rustc APIs available for fold-rust scanning. ## rustc_driver + rustc_interface fold-rust uses `rustc_driver::Callbacks` to intercept compilation: ```rust struct FoldCallbacks; impl Callbacks for FoldCallbacks { fn after_analysis<'tcx>(&mut self, _compiler: &Compiler, queries: &'tcx Queries<'tcx>) -> Compilation { queries.global_ctxt().unwrap().enter(|tcx| { // tcx: TyCtxt<'tcx> — access to all compiler state for def_id in tcx.hir().body_owners() { emit_function(tcx, sm, def_id); } }); Compilation::Continue } } ``` Key APIs: - `TyCtxt<'tcx>` — central query context: types, HIR, MIR, borrow checker - `tcx.hir()` — access HIR (High-level IR) - `tcx.optimized_mir(def_id)` — access MIR after optimizations - `tcx.typeck(def_id)` — type-checking results ## HIR (High-level IR) `rustc_hir::Expr` with `ExprKind` variants: | ExprKind | Security relevance | |----------|-------------------| | `Unary(UnOp::Deref, sub)` | Raw pointer deref — null-deref detection | | `MethodCall(segment, receiver, args)` | Method dispatch — taint tracking | | `Call(callee, args)` | Function call — interprocedural boundary | | `Binary(op, lhs, rhs)` | Arithmetic — overflow detection | | `Index(base, index)` | Array access — OOB detection | | `If(cond, then, else_opt)` | Branch — path predicate forking | | `AddrOf(..)` | Address-of — pointer tracking | | `Cast(expr, ty)` | Type cast — truncation detection | fold-rust's `DerefHunter` visitor walks HIR and matches these patterns. ## MIR (Mid-level IR) `rustc_middle::mir::Body` with `BasicBlock`s: - `StatementKind::Assign(box (place, rvalue))` — variable assignment - `StatementKind::StorageLive(local)` — variable comes into scope - `StatementKind::StorageDead(local)` — variable goes out of scope - `TerminatorKind::Call { func, args, destination, .. }` — function call - `TerminatorKind::SwitchInt { discr, targets }` — enum/switch dispatch - `TerminatorKind::Return` — function exit - `TerminatorKind::Goto { target }` — unconditional branch `Rvalue` variants: - `Use(operand)` — copy/move - `Ref(region, kind, place)` — borrow - `BinaryOp(op, box (lhs, rhs))` — arithmetic - `CheckedBinaryOp(op, box (lhs, rhs))` — checked arithmetic - `Cast(kind, operand, ty)` — type cast - `RawPtr(..)` — raw pointer creation - `Discriminant(place)` — enum discriminant ## Type System `TyKind` variants accessible via `tcx.type_of(def_id)`: - `TyKind::Int(IntTy)` — signed integers (i8, i16, i32, i64, i128, isize) - `TyKind::Uint(UintTy)` — unsigned integers (u8, u16, u32, u64, u128, usize) - `TyKind::Bool`, `TyKind::Char`, `TyKind::Float(FloatTy)` - `TyKind::Ref(region, ty, mutability)` — references - `TyKind::RawPtr(TypeAndMut { ty, mutbl })` — raw pointers - `TyKind::Adt(def, substs)` — structs, enums, unions - `TyKind::Array(ty, len)` — fixed-size arrays - `TyKind::Slice(ty)` — dynamically-sized slices - `TyKind::FnDef(def_id, substs)` — function types Bit-width queries: - `tcx.layout_of(param_env.and(ty))` → `LayoutS` with `size`, `align`, `abi` - `layout.size.bits()` → bit-width (for encoding) ## Borrow Checker `rustc_borrowck::consumers::BodyWithBorrowckFacts` provides: - `BorrowKind`: `Shared`, `Unique`, `Mut` - Loan scopes: which regions a borrow covers - Move tracking: which locals are moved fold-rust's `mir_analysis::BorrowTracker` uses this to determine which pointers are borrow-backed (safe) vs raw-pointer (potentially unsafe). ## Recommendations for fold 1. Use MIR `BasicBlock` structure for control flow in the Z3 encoder (task 120) 2. Thread `TyKind` signedness through observer hooks (done: `93439bf`) 3. Leverage `LayoutS::size` for precise bit-widths in symbolic encoding 4. Use borrow checker facts for null-deref suppression (BorrowTracker, wired in task 102)