Skip to content

fix(c): a function that writes a macro before a block still uses the macro - #3172

Merged
colbymchenry merged 1 commit into
mainfrom
claude/fix-c-macro-statements
Nov 1, 2026
Merged

colbymchenry merged 1 commit into
mainfrom
claude/fix-c-macro-statements

Conversation

@colbymchenry

Copy link
Copy Markdown
Owner

Summary

A function that writes a macro before a block, or with no ; after it, counts as using the macro again. This closes regression 4 of the comparison with 1.6.2 (TEST_CONTEXT("…") { on redis) and rocksdb's XXH_ASSERT references.

First of a stack of four. The base of this PR is main.

Root cause

cbd9817 (#1736) taught the statement-macro blank to take names in capitals, so that ATOMIC_BLOCK(x) { stops reading as a K&R function. The blank takes the whole call, name included. The function no longer named the macro, so its value reference went too: 10 on redis, 16 on rocksdb.

The fix

In a statement of a function body the name stays, as name;, in the bytes the call took. Anywhere else a ; would be the error the blank avoids, so the call goes whole as before:

  • in an initializer, a struct or enum body, another macro's arguments, or the rest of an expression;
  • as the body of an if, for, else or do, where it would part the block from its else or while.

cStatementLines reads which lines those are from the file's code, once, and only for a file that has such a macro. The change is length-preserving and in the preParse, so the kernel gets the same bytes and needs no change.

The arguments stay blanked. A macro's can be types, which a call would not parse, and no call or reference lost against 1.6.2 on redis or rocksdb was in one. Lowercase iterator macros take the same path, so nk_foreach in glfw's nuklear.h counts as used too.

Validation

Windows 11, main 4499d00.

Tests. 7 of the 9 new tests fail on main and all pass. 11 mutations each fail a test. Three older tests that said the name goes now say it stays (extraction.test.ts, cpp-raw-string-preparse-1505.test.ts).

A/B against main.

Repo Language Result
redis C the 10 back, nothing lost or moved by this commit
rocksdb C++ and C 15 of the 16 back on the same functions, 2 phantom nodes with 4 calls back, 20 spilled locals gone
glfw C +1, nk_convert really uses nk_foreach
jq, betaflight C nothing from this commit
leveldb, gin, flask controls identical

The 16th XXH_ASSERT sat on XXH3_ACCUMULATE_TEMPLATE(scalar), a K&R misreading on both arms whose body is XXH3_scalarScrambleRound, which neither arm has as a node. REG read that entry as neither arm's.

Parse errors. Over every C file of redis, jq, glfw, betaflight and linux-sub, 10,220 files: 0 worse, 0 better, error counts identical.

Kernel parity, 0 diffs. redis 639/796 (the deferrals main has), jq 66/81, glfw 69/97, rocksdb db + util 381/463, betaflight src 1177/1465.

Cost. Whole-index CPU, median of 5 interleaved rounds, base and stack built the same way: redis 23.70 to 23.84 s (+0.6%), wall 7.98 to 7.89 s. cStatementLines is 42 ms of a redis index in a profile. C preParse alone: linux-sub 6.1 to 6.6 s, redis 0.94 to 0.99 s.

Suite. 857 files passed and 6 skipped, 10,651 tests passed, 2 expected fail, 87 skipped, 4 workers, with the kernel, on the stack one clean rebase back (719ea417 on main 3bd9949). After the rebase onto 087de4c, whose hunks are apart from these: 138 files and 2,224 tests of the C, C++, Objective-C, Python and extraction suites pass on the tip.

🤖 Generated with Claude Code

…macro

Regression 4 of the comparison with 1.6.2, from cbd9817 (PR 1736). That
commit taught the statement-macro blank to take names in capitals, so that
`ATOMIC_BLOCK(x) {` stops reading as a K&R function. The blank takes the whole
call, name included, so a function no longer named the macro it uses and its
value reference went too: redis lost 10 (`TEST("…") {`, `TEST_CONTEXT`,
`TEST_DESC`) and rocksdb 16 (`XXH_ASSERT(c)`, which xxhash writes with no `;`).
A change to the macro missed those functions.

In a statement of a function body the name now stays, as `name;`, in the
bytes the call took. Anywhere else a `;` would be the error the blank avoids:
in an initializer, a struct or enum body, another macro's arguments, the rest
of an expression, or as the body of an `if`, `for`, `else` or `do`, where it
would part the block from its `else` or `while`. Those go whole, as before.
cStatementLines reads which lines those are from the file's code, once, and
only for a file with such a macro. It is length-preserving and in the
preParse, so the kernel gets the same bytes. The arguments stay blanked: a
macro's can be types, which a call would not parse, and no call or reference
lost against 1.6.2 on redis or rocksdb was in one.

Lowercase iterator macros take the same path, so `nk_foreach` in glfw's
nuklear.h now counts as used too.

Validation against main 4499d00:
- Tests: 7 of 9 fail on main, all pass. 11 mutations each fail a test. Three
  older tests now expect the name to stay.
- redis: the 10 are back, nothing lost or moved. rocksdb: 15 of the 16 are
  back on the same functions. The 16th sat on `XXH3_ACCUMULATE_TEMPLATE(scalar)`,
  a K&R misreading on both arms whose body is `XXH3_scalarScrambleRound`, which
  neither arm has as a node; REG read that entry as neither arm's. Two more
  such phantoms come back with their 4 calls, and 20 locals that had spilled
  to file scope on main are gone.
- glfw +1 (true). jq, leveldb, gin, flask and betaflight: nothing from this
  commit.
- Parse errors over every C file of redis, jq, glfw, betaflight and linux-sub,
  10,220 files: 0 worse, 0 better, error counts identical.
- Kernel parity, 0 diffs: redis 639/796 (the deferrals main has), jq 66/81,
  glfw 69/97, rocksdb db+util 381/463, betaflight src 1177/1465.
- Cost: C preParse over linux-sub 6.1 to 6.6 s, over redis 1.0 to 1.05 s.
  cStatementLines is 42 ms of a redis index's profile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@colbymchenry
colbymchenry merged commit b23c880 into main Nov 1, 2026
@colbymchenry
colbymchenry deleted the claude/fix-c-macro-statements branch November 1, 2026 05:10
bompus added a commit to bompus/codegraph that referenced this pull request Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant