merge: reconcile upstream through 19813544 (16 C/C++ resolution fixes)

Merged
BO
8h ago
+6218-125

fork/consolidated now contains upstream main through 19813544 (16 C and C++ resolution fixes). C++ calls through iterators, subscripts, front()/back()/at(), macro-defined methods, explicit specializations and overloaded free functions now link to the method C++ calls, and a C call reaches the function its own file can see. On nlohmann/json this drops 940 call links that all pointed, wrongly, at one test file's using json alias.

The fork resolves references in the Rust kernel, so upstream's TypeScript resolver files stay deleted (name-matcher.ts, cpp-includers.ts, cpp-macro-visibility.ts, cpp-namespaces.ts, cpp-type-aliases.ts, and the new c-feature-variants.ts). Their upstream versions were the specification for the native ports below. Extraction follows upstream as written: c-cpp.ts, cpp-brace-scopes.ts, the new cpp-macro-methods.ts, and the parse-worker and tree-sitter changes. The kernel's C++ naming takes upstream's explicit-specialization names (ccpp/names.rs).

Upstream PRs

  • #2567 qualified receiver type never reaches a class that only shares its last name: ported natively (c0d14580). Two of its assertions are kept unlinked (02892a99): a member whose type a template argument decides, and a receiver another function declares. In both, upstream matches by name alone.
  • #2568 alias of a global-scope type: ported natively (c0d14580). A namespace alias is looked up in the caller's include closure, and of a file's alternative aliases the first wins.
  • #2569 receiver type written from the global scope: ported natively (c0d14580).
  • #2573 receiver declared as a class template's member type: ported natively (dcad03ba).
  • #2576 -> on a declared container iterator: ported natively (77fc74d7). The RunAll assertion is kept unlinked (69dd1bd4), because the element is written only by the class template's own operator*.
  • #2579 auto local holding a library container's iterator: ported natively (77fc74d7).
  • #2598 dereferenced iterator or pointer: ported natively (77fc74d7).
  • #2601 member of the pair a map's iterator points at: ported natively (77fc74d7). The Rep::Get assertion is kept unlinked (69dd1bd4), because p.first is a T* the template writes.
  • #2602 element read by subscript: ported natively (77fc74d7).
  • #2605 macro-defined methods: the extraction merged as written. The resolver now reads the return type, parameters and deleted state from the macro expansion (543a705a).
  • #2609 explicit specializations named after their template: the names come from ccpp/names.rs at the merge. The resolver picks the specialization a call's template arguments name in the new resolve/cpp_specializations.rs (d2905a86). The callback synthesizer reads the same arguments through src/resolution/cpp-specializations.ts.
  • #2612 overloaded free functions: ported natively (39907fc3).
  • #2613 C call reaches the function its own file can see: ported natively (87808361). This adds the C branch of overload selection and treats statics of included sources as visible. A standard header is never matched by the end of its path.
  • #2615 C header definition for a flag nothing sets: ported natively in the new resolve/c_feature_variants.rs (aa7f5db5), with three-valued #if evaluation.
  • #2616 front()/back()/at()/get()/value() results: ported natively (77fc74d7).
  • #2618 overloads alike but for const: ported natively (568c0695). Four existing fork assertions now expect what upstream's specs give (c59f3b9f):
    • two subscript-result dump overloads;
    • overload_unread left unlinked;
    • leveldb's Drop reaching Slice::remove_prefix through value_type;
    • Flush reaching Cache::reset through element access.

Conflicts. Eight files conflicted:

  • The deleted resolver files stay deleted.
  • src/index.ts keeps the fork's version.
  • The synthesizer imports cppSpecializationArguments from the new src/resolution/cpp-specializations.ts.
  • ccpp/names.rs takes upstream's naming.
  • CHANGELOG.md was rebuilt with scripts/changelog-reconcile.mjs.

Verification, on this head (d2905a86 code; f494cb6a adds only README and CHANGELOG)

  • Upstream's 16 new test files and the other C/C++ test files: 67 of 67 files, 617 of 617 tests.
  • Full suite: 742 files, 9,221 tests pass (39 skipped). stderr has no Native stack trace and no Worker exited unexpectedly.
  • npx tsc, npm run check:agent-docs (AGENTS.md 12,800 of 32,768 bytes) and cargo clippy --release --lib -- -D warnings are clean.
  • Golden dumps: UPDATE_GOLDEN=1 rewrote no .dump file (8 of 8 pass, no diff).
  • Precision gate (eval:precision), base a5f14290 against this head:
CorpusEdges beforeEdges afterChangeGraded cases
jq (C)7,7847,784identicalnone graded
nlohmann/json (C++)29,42828,803−625 (−2.1%)absent 11/11, present 7/7 held

The json call edges changed in three ways:

  • Lost: 973. 940 went to the using json alias in tests/src/fuzzer-parse_bjdata.cpp, which every test file's json call reached by name, and 23 to a test helper test in unit-noexcept.cpp. Both are wrong cross-file guesses.
  • Gained: 431. Of these, 377 are instance-method calls that the iterator, element and overload ports now type.
  • Retargeted: 66.

CHANGELOG. All of upstream's bullets are kept. Three fork changes:

  • The older copy of the C++ -> entry, which upstream's expanded entry replaces, is dropped. The fork's existing "left unlinked" wording for a class derived from a decltype(…) is kept.
  • The string-literal entry is dropped again, as at the last merge, because the fork already behaved that way.
  • One fork entry is added for the calls the native resolver leaves unlinked where upstream matches by name alone.

README rows checked:

  • The merge point is changed to 19813544.
  • "Name resolution" is still accurate.
  • The C++ typedef/using aliases row is unchanged.
  • The C++ -> smart-pointer row is unchanged.
  • The C++ auto local / chained call / data member row now also names an iterator's element and a map's key or value that a class template writes.
  • The C++ namespace aliases include-closure row is still accurate: the alias port reads only files in the caller's include closure.
  • The C++ object-creation row is unchanged.
  • "What the fork adds", "Measured results" and "What it costs" are unchanged.

Not covered.

  • The fork-vs-upstream benchmark and the CPython edge-count row ("2% fewer on CPython") were not re-measured. The C ports (#2613, #2615) may move CPython's counts, though jq's did not change.
  • I narrowed the drop of the fuzzer-alias guess to the merge commit plus 77fc74d7 (an earlier kernel build already had no edges to it), but did not isolate which change caused it.
  • No C/C++ corpus beyond jq and nlohmann/json was run.
  • The merge commit keeps upstream's 19813544 as a parent, so land it as a merge commit.

Summary by cubic

Merges upstream main through 19813544, porting 16 C/C++ resolution fixes to the fork's native Rust kernel. Upstream's TypeScript resolver files stay deleted; their behavior is reimplemented natively.

C++ calls through iterators, subscripts, container accessors, macro-defined methods, explicit specializations, and overloaded free functions now link where C++ resolves them; a C call reaches the function its own file can see. On nlohmann/json the net effect is −625 call edges (−2.1%): 940 wrong links to one test file's using json alias are gone, replaced by 377 instance-method calls that now type.

Resolver changes

  • -> on a container iterator or auto iterator, dereferences, map first/second, and element subscripts read the element's class; front()/back()/at()/top()/get()/value() name what the container holds. A map's value_type is its pair, so a call on it stays unlinked rather than reaching the key's method.
  • Explicit specializations are named after their template; a call's template arguments pick among them, and a class's own member template ends the lookup.
  • Free-function overloads now pick by argument count and type, including const-twin fits.
  • Macro-defined methods get nodes where invoked, with signature read from the expansion and default arguments their class declares inside a namespace.
  • C calls prefer the file's own function, then an included header's; a header definition compiled only by an unset flag yields to the compiled source. Standard headers never match by path tail.

Verification

  • 9,221 tests pass (39 skipped); tsc, clippy, and agent-docs clean; golden dumps unchanged.
  • Precision gate holds all graded cases: jq identical, nlohmann/json −625 edges with 18/18 graded cases held.
  • Conflicted files resolved as planned: upstream's deleted resolver files stay deleted, extraction merges as written, ccpp/names.rs takes upstream's naming, CHANGELOG rebuilt.

Summary by CodeRabbit

  • Improvements

    • C and C++ call links now better handle overloads, aliases, explicit template specializations, macro-defined methods, and visibility across source files.
    • C++ calls through containers, iterators, pointers, arrays, and accessor results resolve more accurately when their types can be determined. Ambiguous or unreadable types remain unlinked.
    • C call resolution better accounts for build flags and conditional compilation when selecting definitions.
  • Documentation

    • Updated resolution notes for C++, Go, and map key/value types.