cpp emitter: string-helper guards scoped per package (#189, PR B) - #220
Merged
Conversation
The emitted string helpers (schema_utf8_valid, schema_interior_null) are namespace-local, but their include guards were TU-wide — so the SECOND generated unit included into one translation unit lost its helpers and its string wire functions did not compile. The guards now carry the package name (SCHEMA_<PKG>_UTF8_VALID_DEFINED / SCHEMA_<PKG>_INTERIOR_NULL_DEFINED), following the emitFlagAppendHelper pattern already in the emitter: one copy per package per TU. C is NOT defective and stays untouched: its helpers are file-scope static with trailing-underscore names, so the TU-wide guard is exactly right there (the second unit's functions call the first emission's definition). Regression test: test/guard — two packages, both with string(N) fields, generated at build time into build/ and included into ONE translation unit (build/schema_test_guard). Red on the old emitter, green here. The bench/cpp leg-local workaround (#undef of the two guards) was already removed by #204 when the example units left the bench TU; nothing remains. Licensed by bench/LOCK's one-shot carve (owner ruling 2026-08-31, #189). Generated diff: guard lines only, cpp outputs only; wire bytes unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
gafferongames
marked this pull request as ready for review
September 1, 2026 01:03
gafferongames
added a commit
that referenced
this pull request
Sep 1, 2026
The protocol closes: PR A suspended the emitter and generated-c/cpp prefixes for exactly one licensed change, PR B (#220) landed the string-helper guard fix under the reproduction control (c/cpp rows within 2.9% of the sitting-2 reference), and this single-file edit restores the lock. One modernization against the pre-carve list: the cpp ludicrous output lives at generated/cpp/ludicrous today, already covered by the generated/cpp/ prefix, so the historical generated/cpp-ludicrous/ line (which matches nothing) is not restored. Co-authored-by: Rowan Claude <rowan@mas-bandwidth.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR B of the #189 protocol, licensed by bench/LOCK's one-shot carve (owner ruling 2026-08-31).
The defect
The C++ emitter's string helpers (
schema_utf8_valid,schema_interior_null) are emitted insidenamespace <package>but guarded by TU-wide include guards (SCHEMA_UTF8_VALID_DEFINED,SCHEMA_INTERIOR_NULL_DEFINED). Two generated units from two packages, both withstring(N)fields, in one translation unit: the first unit sets the guard, the second unit's namespace never gets its helpers, and its string wire functions do not compile.The fix
internal/codegen/cpp/utf8.goandinternal/codegen/cpp/nullscan.go: the guards now carry the package name —SCHEMA_<PKG>_UTF8_VALID_DEFINED/SCHEMA_<PKG>_INTERIOR_NULL_DEFINED— one copy per package per TU, following theemitFlagAppendHelperpattern that already did this correctly in the same emitter. Formatting conventions unchanged; the helper bodies are byte-identical.C-side verdict: NOT defective, left untouched. The C emitter's helpers are file-scope
staticwith trailing-underscore names, so the TU-wide guard is exactly right there — the second unit's functions call the first emission's definition (this is also what commit f1c0f8c recorded: "the C leg needs no guard workaround"). TheSCHEMA_WRITE_INLINE/SCHEMA_READ_INLINEmacro blocks in C++ are preprocessor macros, not namespace-local symbols — TU-wide guards are correct for them and they are untouched too.Regression test (red on main, green here)
test/guard/: two packages (alpha,beta), both withstring(15)fields, generated at build time intobuild/guard-generated/(test-only corpus — never part of the committedgenerated/tree) and included into ONE translation unit (test/guard/main.cpp, newmakelegbuild/schema_test_guard). Round-trips a string through each namespace.Red — old emitter (this branch with the two emitter files stashed back to main's state), verbatim:
Green — with the fix (
git stash pop, regenerate, rebuild):bench/cpp workaround
Already gone: the
#undef SCHEMA_UTF8_VALID_DEFINED/#undef SCHEMA_INTERIOR_NULL_DEFINEDworkaround was removed by #204 (commit 3cf6b90) when the example units left the bench TU.grep -rn "SCHEMA_UTF8_VALID_DEFINED\|SCHEMA_INTERIOR_NULL_DEFINED" bench/matches nothing today; there is nothing left to remove.Generated-diff inventory
make testgreen (all nine legs);make generated-currentprintsgenerated/ tree is current. The regeneration diff is exactly the guard lines — 6 lines in each of 4 generated files (plus the same 6 in their 3 text-golden mirrors), nothing else:generated/cpp/ClausesWire.h,generated/cpp/JoinsWire.h,generated/cpp/WireWire.h(packageexample):#ifndef/#define/#endif // SCHEMA_UTF8_VALID_DEFINED→SCHEMA_EXAMPLE_UTF8_VALID_DEFINED#ifndef/#define/#endif // SCHEMA_INTERIOR_NULL_DEFINED→SCHEMA_EXAMPLE_INTERIOR_NULL_DEFINEDgenerated/bench/cpp/BenchWire.h(packagebench): same six lines →SCHEMA_BENCH_*testdata/golden/cpp/{ClausesWire.h,JoinsWire.h,WireWire.h}: text mirrors of the abovetestdata/wirechanged (git diff main -- testdata/wireis empty). Ludicrous corpora carry no strings, so no helper emissions there.Reproduction control (bench/LOCK control 2)
The frozen shapes' c/cpp rows re-run in-sitting on this branch (bench/run.sh --only cpp, --only c, Release O3, quiet box) against the sitting-2 reference
bench/results/2026-09-01-sitting2-arm64-macbook.csv(medians, msgs/sec):All rows within ±2.9% of the reference — inside the ~5% band. The control CSVs went to scratch files; nothing under
bench/results/is touched.Wire bytes
Byte-unchanged everywhere: the change is include-guard text in C++ headers only — zero effect on any emitted codec logic, and the wire goldens under
testdata/wireare untouched, byte for byte.PR C (the single-file bench/LOCK prefix restoration) follows once this merges, per the protocol.
🤖 Generated with Claude Code