Player::CleanupResources compiles again, and it was a match all along - #1393
Merged
Conversation
The file has not compiled since it gained `#include "decl_common.h"`. That header
declares
extern void func_ov002_020bdd2c(void*);
extern void func_02073244(void*, int, int, void (*)(void*));
inside `extern "C"`, and the file then declared the same names again taking `char *`
and `(int, int, int, void (*)(void))`. Same C linkage, different parameter types, so
it is not a redeclaration but an attempt to overload a C-linkage name -- which
mwccarm rejects outright:
src/_ZN6Player16CleanupResourcesEv.cpp:17: illegal function overloading
... :18, :19, :20, :23
Errors caused tool to abort.
Nothing caught it, because the failure removes the file from every gate that could
have. A file that will not compile is not eligible, so it is not enrolled; its
delinks entry has no `complete`, so dsd hands the range to the original ROM bytes and
the build stays 106/106 without ever touching the source. It went unbuilt through
#919, #994, #1032 and #1382 -- the last of which edited it.
Fix is to declare only what decl_common.h does not. The three that remain are absent
from it; `_ZN7Vector3D1Ev` is spelled with the `this` it actually takes, which is
also what makes the `func_02073244` argument type-correct without a cast.
THE FUNCTION IS A BYTE MATCH. Once it compiles, all 0x730 bytes at 0x020e32d4 in
ov002 reproduce under the pin, with correct relocation destinations -- so this is not
a repair of a near-miss but the recovery of a match that has been sitting unreadable
in the tree. Enrolled here rather than left as rombytes.
VERIFIED
build_pin (True, '2004/b56') at 0x020e32d4, size 0x730, ov002
pr_linkcheck ok, 1 slot, correct destinations
eligible.py 10,814 / 11,162 -- main is 10,813, and the diff is this symbol alone
rombuild -j16 106/106 exact, 10,814 source-built, 0 mismatching, 87.88% -> 87.96%
Found while diagnosing why #1390's validation reported a worker error: with the
NameError in tools/pr_linkcheck.py fixed (#1392), the gate could finally grade this
file, and graded it NO-SYM. The verdict is correct and predates #1390 -- clean main
fails to compile it identically.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XxDmkQ47fWa3GB6mj8xEQe
✅ PR validation — PassedCommitted merge introduces no reconstruction or attribution regression. Full merge validation
Per-file link-check detailAll 1 changed file(s) compile to the ROM byte-for-byte with correct relocation targets.
The private worker commits a test merge, builds the stock ROM profile, compares every executable module, measures matched and source-built code, checks contributor lineage, and verifies affected relocations. The mod profile is opt-in and is not part of this merge gate. |
andrewboudreau
added a commit
that referenced
this pull request
Aug 11, 2026
…nce ratchet is unstuck (#1397) * Re-pin the unresolved-reference baseline to main The reference ratchet is stuck on main, and has been since the merges that moved it. `--update` refuses whenever `bad` is non-empty, and main's own drift lands there, so no PR can bank progress past it. The failure reproduces byte-identically on a clean `origin/main` checkout with nothing applied. Regenerated from a clean main. Ten lines change, and each is main's own state: eligible 10805 -> 10814 #1382, #1391 and #1393 all added functions. func_02057410 recorded as missing `_ll_mod`; it actually misses `_ll_udiv` and `_ull_mod`. Those are mwccarm runtime helper names -- the ROM implements them as __aeabi_uldiv / __aeabi_ulmod in ITCM at 0x01ffa9dc and 0x01ffa9e8 -- and there is no alias mechanism, so the entry is permanent rather than a to-do. _Z13func_020072c0v gone: #1382 renamed that symbol to _ZN7Vector3D1Ev. ov079 Whomp::InitResources ADDED. It is unresolvable on main today and was simply missing from the baseline. The next commit fixes half of it; the other half, func_021135d4, resolves to 15 overlays sharing base 0x021111a0, so no single name is correct. ov091 func_ov091_021339fc gone: a merged PR converted it to a hand-written asm hatch, which removes it from the candidate set. That reclassification is indistinguishable from a regression to the reason-switching guard -- which is exactly what jammed the ratchet. Its own commit, before any content, so the next commits' effect on the backlog reads as a diff against an honest starting point instead of being buried in a rewrite. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxDmkQ47fWa3GB6mj8xEQe * TextureSequence::Prepare and MaterialChanger::Prepare are static Both were declared as ordinary members and defined as forwarding (this, &model, &file). They take two arguments and no this. Four independent lines of evidence agree: - func_02046d50 and func_020470e8, the real bodies behind the two 0xc veneers, read only r0 and r1. r2 is never touched, which rules out a third argument. - the offsets r1 is read at are exactly the animation file's fields (BTP_File: 0x2, 0x4, 0x8, 0xc, 0x1c, 0x20), so r1 is the SECOND argument, not the third. - both matched implementations, src/func_02046d50.c and src/func_020470e8.c, already take two parameters. - every call site in the tree passes two. The veneer bodies are pure tail jumps (ldr ip,[pc]; bx ip), so they reproduce under either signature. That is how the wrong reading survived: the definition files never constrained it, and the callee and callers -- which do -- were not consulted. A static member mangles identically, so no symbol changes and no config moves. TextureTransformer, the third sibling, was already corrected. Its header names these two veneers as "called the same way" and notes that the old reading "cost the PC port a wrong-register hunt"; the follow-up never happened. This is it. Twenty-two call sites drop the mangled extern for the member spelling. Several of those externs were a bare `extern` on a mangled name inside a //cpp file, which mangles a second time, so removing them retires that latent defect as well. Eyerok's linkcheck improves BLIND-39 -> BLIND-35 as four call destinations become resolvable. SnowmanHead and InvisibleSecret declare the class locally rather than including TextureSequence.h: both carry `typedef int Fix12;`, which collides with the real math/Fix12.h template. The six .c callers keep the mangled extern -- C has no ::. Gates: rombuild 106/106 exact, 10,813 reproducing, 0 mismatching; eligible name list byte-identical to main at 10813; linkcheck 23 checked, 21 verified, 0 blocking; attribution 0 changed / 0 lost; port_refcheck 393 resolve; header offsets, data definitions and duplicate sources clean. Goomba::InitResources and MrI::InitResources do not reproduce -- before or after. Both fail identically on origin/main (999 and 7 words), and their compiled bytes are unchanged by this commit: 916 -> 916 and 664 -> 664, identical in both cases. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxDmkQ47fWa3GB6mj8xEQe * Whomp: the MeshColliderBase address was double-mangled _ZN5Whomp13InitResourcesEv.cpp declares _ZN16MeshColliderBase16UpdatePosAndAngs... with a bare `extern`, and that declaration sits OUTSIDE the extern "C" block above it. In a //cpp file that mangles the already-mangled name a second time, so the address taken at the func_020393d4 call points at a _Z88_ZN16... that does not exist. The byte gate cannot see this -- match.py compares relocated words as wildcards, so the function reproduces either way. check_references and prepush_linkcheck are the only gates that look at what a reference targets, and both flagged it: linkcheck goes BLIND-1 -> VERIFIED with the fix, and the function still reproduces. Found while running the gates for the Prepare change, in a file that change already touches. The other entry in the same check_references report, func_02057410's _ll_udiv/_ull_mod, is unrelated to this branch and reproduces identically on origin/main. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxDmkQ47fWa3GB6mj8xEQe * Bank the two double-mangled names this PR resolves Downward only, and both deletions are attributable to a commit above: _Z49_ZN15TextureSequence7PrepareER8BMD_FileR8BTP_Fileii resolved by making Prepare static -- the two trailing 'ii' were a shadow declaration disagreeing with the real two-argument signature. _Z88_ZN16MeshColliderBase16UpdatePosAndAngsERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_v resolved by spelling Whomp's extern the way decl_common.h does, so the already-mangled name is not mangled a second time. Nothing is added. Whomp keeps its entry for func_021135d4, which resolves to 15 overlays sharing base 0x021111a0 -- no single name is correct, so it stays. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxDmkQ47fWa3GB6mj8xEQe * Use the real headers, not local class declarations The Prepare change first spelled the call surface inline at each of the 11 call sites: struct TextureSequence { static void Prepare(BMD_File &, BTP_File &); }; That compiles and byte-matches, but it is a shadow declaration, and the langmode ratchet counts those: shadow_decls.local_body_no_include 1507 -> 1510, with nothing falling to offset it. The workflow has an escape hatch for a deliberate rise, but using it here would mean adding debt in exactly the direction the plan is draining. The headers cost nothing, so they win: shadow_decls.local_body_no_include 1507 -> 1503 (-4) A 7-point swing, and the ROM does not move -- the call is a direct bl either way. Two files needed the Fix12 shadow removed first. `typedef int Fix12;` is harmless while a file includes nothing, but the real Fix12 is a TEMPLATE, so pulling in a real header turns every use into "template argument list expected" rather than a plain redefinition. SnowmanHead and InvisibleSecret now take those extern parameters as plain int, which is what BowserFire, BowserTail, KoopaShell, LavaBubble and BabyPenguin already do. That trap is why the local-declaration route was taken in the first place; it is not specific to those two files. VERIFIED rombuild -j16: 106/106 exact, 10,814 source-built, 0 mismatching, 87.96% langmode ratchet PASS Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XxDmkQ47fWa3GB6mj8xEQe --------- Co-authored-by: Claude Opus 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.
A match that has been sitting unreadable in the tree
src/_ZN6Player16CleanupResourcesEv.cpphas not compiled since it gained#include "decl_common.h". That header declares, insideextern "C":and the file then declared the same names again taking
char *and(int, int, int, void (*)(void)). Same C linkage, different parameter types — so itis not a redeclaration but an attempt to overload a C-linkage name, which mwccarm
rejects outright:
Nothing caught it, because the failure removes the file from every gate that could
have. A file that will not compile is not eligible, so it is not enrolled; its
delinks entry carries no
complete, so dsd hands the range to the original ROM bytesand the build stays 106/106 without the source ever being touched. It went unbuilt
through #919, #994, #1032 and #1382 — the last of which edited it.
This is #1367's
NO-SYMcategory doing exactly what it was added for. It onlysurfaced now because the fan-out of #1390's header change reached the file, and
because #1392 stops the validator crashing before it can say so.
The function is a byte match
That is the real result. Once it compiles, all 0x730 bytes at
0x020e32d4inov002 reproduce under the pin with correct relocation destinations. Nothing about
the logic needed repair — only the declarations. So it is enrolled here rather than
left as rombytes, and the tree gains a function it has had all along.
The fix is to declare only what
decl_common.hdoes not. Three names remain becausethat header lacks them;
_ZN7Vector3D1Evis spelled with thethisit actuallytakes, which is also what makes the
func_02073244argument type-correct without acast.
Verified
build_pin(True, '2004/b56')— 0x020e32d4, size 0x730, ov002pr_linkcheckok, 1 slot, correct destinationseligible.pyenroll.pyrombuild -j16check_data_definitionscheck_duplicate_sourcesport_refcheckprepush_attributionWorth a follow-up
331 delink entries are unbuilt and carry no
NONMATCHINGbanner. Most will beineligible for ordinary reasons, but this file proves at least one of them was a
finished match held out of the ROM by a declaration mismatch. Sweeping them for the
same signature is a separate change; I have not measured how many are in that state
and am not claiming a number.
🤖 Generated with Claude Code
https://claude.ai/code/session_01XxDmkQ47fWa3GB6mj8xEQe