Convert the four intact-TU minigame classes to real members - #2116
Conversation
dScMgBSC_c, dScMgCard_c, dScMgMCarlo_c and dScMgMCarlo2_c are intact-object TUs: they include their own class header and carry the whole class in one file, but their virtuals were still spelled as free functions with hand-written mangled names next to the class they belong to. void _ZN13dScMgMCarlo_c13OnYoshiTryEatEi(char* c) -> void dScMgMCarlo_c::OnYoshiTryEat(int) Twenty-five members across the four files: InitResources, Behavior, Render, CleanupResources, OnYoshiTryEat, OnTurnIntoEgg, OnGroundPounded. Six bodies were missing their slot-18/slot-19 parameter entirely -- Card, MCarlo and MCarlo2 each declared OnYoshiTryEat and OnTurnIntoEgg taking only `this`. The class declares `(int)`, measured from the ROM's vtables, and an unread trailing argument costs no instruction, which is why the disagreement was invisible. The header wins; the parameter is spelled and unnamed. THE RISK THIS BATCH CARRIED, and it did not fire: a real member definition can make its TU the class's key function, and mwcc would then emit _ZTV<class> there -- bytes the config does not own. Checked directly rather than inferred, because 106/106 module fidelity is blind to vtables: dScMgBSC_c build/src/actors/dScMgBSC_c.o no vtable/RTTI emitted dScMgCard_c build/src/actors/dScMgCard_c.o no vtable/RTTI emitted dScMgMCarlo_c build/src/actors/dScMgMCarlo_c.o no vtable/RTTI emitted dScMgMCarlo2_c build/src/actors/dScMgMCarlo2_c.o no vtable/RTTI emitted None of the four classes' key functions -- the first virtual DECLARED in each header -- lives in these TUs, so no vtable moved. No delinks change: these files were already .cpp and already enrolled. NOT FIXED, flagged for a follow-up: src/actors/dScMgBSC_c.cpp carries a comment above OnYoshiTryEat claiming the body is "The DELETING DESTRUCTOR, vtable slot 17 ... the old comment here called it OnYoshiTryEat, which is slot 18 -- off by one". The body it sits above stores no vtable and calls no deallocator; it sets two flags and calls func_ov004_020b66d4. The ROM reproduces it at the OnYoshiTryEat address, so the symbol is right and the prose is stale. VERIFIED: python tools/rombuild.py -j 16 --no-rom 11,088 / 11,088 functions reproducing, 0 mismatching 106/106 modules exact, 100.000000% of compared bytes ROM data from source unchanged: 496 verified, 223 partial, 5 differ Nine static gates green, re-run after line-ending normalization. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QhhAeJwXBnfPp7B5DNjCwh
✅ PR validation — PassedCommitted merge introduces no reconstruction or attribution regression. Full merge validation
Byte-verified means the range carries Per-file link-check detailAll 4 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. |
dScMgBSC_c,dScMgCard_c,dScMgMCarlo_c,dScMgMCarlo2_care intact-object TUs — each carries a whole class in one file and includes its own header — but their virtuals were still free functions with hand-written mangled names, sitting right next to the class they belong to.25 members converted:
InitResources,Behavior,Render,CleanupResources,OnYoshiTryEat,OnTurnIntoEgg,OnGroundPounded.Six bodies were missing their parameter entirely. Card, MCarlo and MCarlo2 each declared
OnYoshiTryEatandOnTurnIntoEggtaking onlythis. The class declares(int)— measured from the ROM's vtables during the slots-18-35 campaign — and an unread trailing argument costs no instruction, which is exactly why the disagreement was invisible. Header wins; the parameter is spelled and left unnamed.The risk this batch carried, and why I checked rather than assumed
A real member definition can make its TU the class's key function, at which point mwcc emits
_ZTV<class>there — bytes the config does not own.106/106module fidelity is blind to vtables, so a green build would not have caught it. Checked the objects directly:None of the four classes' key functions — the first virtual declared in each header — lives in these TUs, so nothing moved.
ROM data from sourceis unchanged at 496 verified / 223 partial / 5 differ.No
delinks.txtchange: these files were already.cppand already enrolled.Flagged, not fixed
src/actors/dScMgBSC_c.cppcarries a comment aboveOnYoshiTryEatclaiming the body is "The DELETING DESTRUCTOR, vtable slot 17 … the old comment here called it OnYoshiTryEat, which is slot 18 — off by one". The body it sits above stores no vtable and calls no deallocator; it sets two flags and callsfunc_ov004_020b66d4. The ROM reproduces it at theOnYoshiTryEataddress, so the symbol is right and the prose is stale. Left for a follow-up rather than silently deleted — someone measured something to write that, and I would rather it be re-measured than dropped.Verified
rombuild.py -j 16 --no-rom→ 11,088/11,088 reproducing, 0 mismatching, 106/106 exact, 100.000000%. Nine static gates green, re-run after line-ending normalization.With this, every free-function body in the minigame family is now a real C++ member. Stacked on #2115.
attribution-override.