Release Notes
Condensed highlights of recent releases. The authoritative, fully detailed history lives in the repository CHANGELOG.
v3.0.1 (2026-07-18) — the inheritance-ABI and Tier-2-correctness release
C++ inheritance, end to end.
- Multiple inheritance — base-class subobject offsets are extracted from
DW_TAG_inheritance, derived layouts flatten base members at their true offsets, and<Derived>_as_<Base>upcast helpers apply the static Itanium adjustment so secondary-base methods receive a correct base-relativethis. - Virtual dispatch honors overrides — virtual instance methods now dispatch through
jlcs.vcall: the thunk reads the object's vptr, indexes the slot, and calls indirectly, so a base-class wrapper invoked on a derived object reaches the override. Dispatch coordinates are class-local (an empirically pinned Itanium/DWARF fact); destructors deliberately remain direct calls for exact-class RAII semantics. - Virtual inheritance — a virtual base's offset is vtable-resident and dynamic, not static. Both DWARF parsers now decode the vbase location expression,
jlcs.type_infocarries a virtual-base table, and the wrapper emits dynamic<Derived>_as_<VBase>upcasts that read the offset through the object's vtable at runtime — the same helper is correct for every dynamic type. Diamond-proven: one shared base, override dispatch through the vbase vtable, polymorphic deletion.
Tier-2 ABI correctness (driven by the pugixml and tinyxml2 Hub packages).
- SysV small-struct classification — the thunk lowering previously forced sret for every packed struct return; native x86-64 returns ≤16-byte aligned structs in registers, so calls shifted every argument by one slot.
try_call/ffe_callnow classify MEMORY vs register class and coerce register-class structs one scalar per eightbyte, clang-style, for returns and by-value arguments. Verified against a real clang-compiled callee. - Nested packed structs — a padding-free struct nested by value inside a padded struct leaked a JLCS dialect type into LLVM struct bodies, crashing LLVM-IR translation at module load. Such members now inline as byte-identical LLVM literals.
- JIT pre-flight guard —
create_jitrefuses modules containing untranslatable types with a catchable error naming the type and op; a bad type degrades the module to "Tier 2 disabled" instead of killing the process. - Scope-RAII by-value parameters — under Itanium, a by-value parameter of a class with a non-trivial destructor is passed as a pointer to a caller-owned temporary. Thunks now copy-construct the temporary in a
jlcs.scopeand destruct it at scope exit; the old raw-bits pass was a silent miscompile. - Thunk routing — virtual instance methods were previously routed to a legacy thunk pass whose symbols the wrapper never looked up; they now flow through the standard ciface thunk pass and are callable through
invoke(). - Dialect verifiers —
jlcs.scope,jlcs.marshal_arg,jlcs.vcall, andjlcs.type_infoverify their attribute arity and element kinds at parse time; the previously known lowering crashes are now parse diagnostics.
Robustness and honesty.
- discover(force) preserves user intent — forced re-discovery no longer destroys hand-curated TOML sections (
[types].templates,[wrap].varargs/macros/shim_headers/cstring_owned); this had silently broken template-dependent fixtures for six weeks. - Depth-aware DWARF attribution — members declared after a nested type definition no longer vanish from metadata (clang interleaves nested-type DIEs mid-member-list; the parser now attributes by DIE tree depth).
- Ingest honesty pass — ingest is documented and guarded as an experimental, C-only fallback; both entry points warn that C++ API surfaces of ingested binaries are unsupported.
- Macro-shim header-collision guard — shim includes are verified to resolve inside the project/dependency tree, not to a system-installed header at a different version.
v3.0.0 (2026-07-10) — the C-generator audit release
Ownership and ABI edges of the ergonomic layer closed. Breaking changes to the generated-wrapper API (wrappers regenerate automatically via the fingerprinted cache; calling code may need updates):
- Struct-by-value convenience overloads removed — every such call was UB-adjacent (the callee saw a pointer to a temporary copy; frees and stores corrupted memory). Pass a pointer or
Refinstead. char*returns areUnion{String,Nothing}— NULL returnsnothinginstead of throwing. Ownership of malloc'd returns is declared in[wrap.cstring_owned](the wrapper frees through the declared symbol after copying); everyCstring-returning function gains a raw<name>_ptrvariant.- True variadic calls — vararg wrappers emit the
@ccallsemicolon form, so the callee is declared variadic in LLVM IR and the SysVALprotocol is correct; float varargs no longer depend on leftover register state. - Nested-member structs resolve to named fields (v2.5.8) instead of
_data::NTupleblobs, under an exact-layout proof. - Bitfield accessors assemble exact byte spans — no out-of-bounds reads/writes at struct tails; setters accept negative integers with wrapping semantics.
- Registry cache fingerprints the generator —
use()can no longer serve wrappers generated by outdated codegen; each package rebuilds once after upgrading RepliBuild. - Wrappers resolve their library sibling-first via
@__DIR__, making cached builds self-contained. - Macro shims pinned to default visibility —
[wrap.macros]survives-fvisibility=hiddenbuilds. - Misaligned small blob parameters by value now trap loudly instead of corrupting silently; unresolvable-type globals get a
_ptraccessor only.
v2.5.8 / v2.5.9 (2026-06, internal)
Never separately registered; shipped as part of v3.0.0.
- Nested-struct member resolution (C) — structs whose members are themselves structs resolve to named Julia fields under an exact-layout proof (explicit padding fields, every DWARF offset and total size reproduced) instead of opaque byte blobs. This closed a silent by-value miscompile where a small float-bearing struct's blob image classified INTEGER while the real struct traveled in XMM registers.
- ABI safety trap for residual register-class float blobs: fail closed rather than corrupt.
- Per-file IR cache correctness — the cache is keyed on a compile fingerprint in addition to
mtime, so flag/define/include changes rebuild without manual cache clearing. jlcs.vcallemit fix — the indirect-call lowering used a malformed operand-segment encoding that crashed LLVM-IR emission; rebuilt on the dedicated indirect-call builder.- Verified compatibility with system LLVM/MLIR 22.x for the dialect build.