Semantic Analysis Internals
The semantic analysis stage validates the Abstract Syntax Tree, computes record memory layouts, resolves symbols, checks type conversions, and scores function overloads, implemented in src/sema/.
1. Role in the Pipeline
- Symbol Registration & Scoping: Registers struct definitions, function signatures, global variables, and type aliases across lexical and namespace scopes (
src/sema/analyze.rs). - Record Layout & Alignment: Computes struct field offsets, overall sizes, and alignment padding according to the 32-bit ILP32 target model (
src/sema/layout.rs). - Vtable Layout & Hierarchy Analysis: Analyzes single and linear inheritance hierarchies, computes base subobject offsets, identifies pure virtual methods (
= 0), and assigns vtable function pointer slots in base-prefix order. - Implicit Method Synthesis: Synthesizes default constructors, copy constructors, copy assignment operators, and destructors for structs that do not define them explicitly (
src/sema/synthesize.rs). Copy operations recursively copy base class subobjects before member fields. Dynamically instantiated template classes also synthesize cleanup methods and copy operations when member fields require non-trivial lifecycles. - Overload Resolution Ranking: Implements standard overload ranking rules to pick the best function or constructor candidate and detect ambiguous calls (
src/sema/overload.rs). Differentiates same-arity template candidates by parameter type signatures and binds out-of-class definitions using exact parameter types and constness. - Type Inference, Conversions & Qualification: Annotates expression nodes with resolved concrete types, validates assignments, arithmetic conversions, multi-level pointer
constqualification rules, null pointer constant conversions (0,0u,nullptr), and C++17 copy elision rules. - AST Desugaring: Lowers high-level syntax nodes (such as range-based
forloops insrc/sema/stmt_range_for.rs) into standard scoped primitives, synthesizing pointer and iterator bounds while preserving RAII and loop control flow. - Closure Synthesis & Lambda Desugaring: Synthesizes unique anonymous closure structs (
__lambda_N) for C++17 lambda expressions (src/sema/expr_lambda.rs), generating fields for captures, constructor initialization,operator()call signatures, return type deduction, and static__invoketrampoline methods for implicit conversion to C function pointers. - Recursive
operator->Resolution: Resolves chained member-arrow accesses recursively until a raw pointer is reached, enforcing cycle detection and receiverconstpropagation (src/sema/expr_member.rs). - List Initialization: Resolves braced initializers (
src/sema/init.rs) across direct-list, copy-list, and value-initialization contexts. Enforces C++17 narrowing rules ([dcl.init.list] p7) andexplicitconstructor rejection in copy contexts, and handles aggregate base subobjects and brace elision.
2. Key Data Structures
Sema: Central semantic state containing:structs: HashMap<String, StructLayout>: Layouts, field offsets, vtable slots, and pure virtual tracking for all defined records.functions: HashMap<String, Vec<FunctionSig>>: All registered functions and method overloads.globals: HashMap<String, Type>: Global and namespace variable types.type_aliases: HashMap<String, Type>:typedefandusingtype maps.
StructLayout:#![allow(unused)] fn main() { pub struct StructLayout { pub is_class: bool, pub has_user_declared_constructors: bool, pub base_classes: Vec<String>, pub base_offsets: Vec<(String, usize)>, pub fields: Vec<StructField>, pub size: usize, pub align: usize, pub has_vtable: bool, pub vtable_slots: Vec<String>, pub private_members: HashSet<String>, pub is_abstract: bool, pub pure_virtuals: HashSet<String>, } }FunctionSig: Signature metadata (parameters, return type,is_const,is_virtual, default arguments).OverloadCandidate: Candidate function paired with argument conversion ranks.
3. Overload Resolution Ranking
When a call expression matches multiple candidates, src/sema/overload.rs scores each parameter conversion against the provided arguments using five rank tiers:
- Exact Match: Argument type equals parameter type (or identical enum/primitive).
- Reference Binding: Binding an lvalue to
T&orconst T&. - Promotion: Numeric promotion (
char/short->int,float->double). - Standard Conversion: Derived-to-base pointer conversion, array decay, pointer qualification conversion (
T*->const T*), null pointer constant conversion (0/nullptr-> pointer /bool), pointer-to-void, or numeric widening/narrowing. - User-Defined Conversion: Implicit single-argument converting constructor.
Ambiguity Detection
If two candidates have identical rank scores across all arguments, overload resolution halts with:
file.cpp:line:col: error: call of overloaded 'func(...)' is ambiguous
Verified by tests/c_basics/functions/overload_resolution.cpp and tests/negative/ambiguous_overload_call.cpp.
4. Record Layout & Vtable Example
Given a polymorphic class hierarchy:
struct Base {
int id;
virtual void run();
};
struct Derived : public Base {
double value;
void run() override;
virtual void extra();
};
The semantic analyzer produces the following StructLayout for Derived:
size: 16 bytes (ILP32: 4 bytesvptrat offset 0, 4 bytesidat offset 4, 8 bytesvalueat offset 8).align: 8 bytes (due todoublealignment requirement).has_vtable:truevtable_slots:["Derived::run", "Derived::extra"](derivedrunreplacesBase::runat slot 0;extrais appended at slot 1).base_offsets:[("Base", 0)]