Platform and Enemy get their real shape, and the type work 120 migrations rest on - #1378
Platform and Enemy get their real shape, and the type work 120 migrations rest on#1378andrewboudreau wants to merge 1 commit into
Conversation
…ions rest on The layout half of #1377, split out so it can be reviewed on its own. Every per-class migration is in the sibling PR; what is here is the base classes, the tooling, the two symbol renames, and the source edits those force. WHAT THIS IS * Platform's data ends at 0x31e, sizeof 0x320. Four classes derive from it directly and each places a 4-byte-aligned class member at 0x320 -- PyramidTop/Model, SwitchPillar/TextureTransformer, MovingBarSmall/ShadowModel, WallSign/MovingCylinderClsnWithPos -- each read off that class's own destructor. BowserFireSeaArena's own three s16 sit at 0x31e/0x320/0x322 so its Model lands at 0x324. One layout satisfies all five; ending at 0x324 satisfies only BowserFireSeaArena and contradicts the other four. This corrects #1374, which was mine. * Enemy derives from Actor, which is what 51 subclasses were waiting on, plus five more Enemy fields named by its subclasses and its vtable symbol. * func_020072c0 and func_02011508 become Vector3::~Vector3 and Vector3s::~Vector3s. * ModelBase::SetFile and ShadowModel::InitCylinder return int, not void. * objisolate learns the multiple-inheritance secondary vptr addend: `>= VTABLE_PREAMBLE` rather than `==`, so 44 -> 36 for ModelAnim corrects instead of being refused. The ROM names the destination independently -- _ZTV9ModelAnim 0x0208e980 against VTable_Animation_ModelAnimThunk 0x0208e9a4, differing by exactly 44 - 8. * tools/subclass_migrate.py, tools/platform_subclass.py, tools/d0_migrate.py, and the header-generation fixes behind them. WHY THESE SIX MIGRATIONS ARE HERE AND NOT IN THE SIBLING ChiefChilly, Unagi, Wiggler (D0 and D1), Goomboss and ChainChomp are migrated here because this half does not build without them, and it took the ROM link to say so rather than the compiler. Giving Vector3 a destructor stops ChiefChilly's hand-written .c files compiling; renaming func_02011508 leaves the other four referencing a symbol that no longer exists, which every file still compiles happily against and only mwldarm rejects: "Undefined : func_02011508, referenced from Wiggler::~Wiggler". Found by building, not by reading. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 1,943,084 bytes, 87.88%. eligible.py against cbd57a8: nothing lost, and the only delta is the intended rename pair -- func_020072c0 and func_02011508 out, _ZN7Vector3D1Ev and _ZN8Vector3sD1Ev in. tools suite 265 passed, 3 skipped. langmode ratchet PASS. No duplicate stems. A symbol rename drops `complete` in delinks (enroll.py preserves it by symbol name), so the two renamed entries were re-promoted with --complete-list; without that the source-built count silently falls 10,813 -> 10,810 while every gate still passes. Original work is by the author of #1377 across 37 commits; this split preserves the content, not the history. #1377's branch still carries the derivation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x
❌ PR validation — Failedrefusing to auto-validate 304 source/build-data files (cap 200) -- unusually large, please review by hand Each changed |
⏳ PR validation — ValidatingBuilding This comment is replaced with the verdict when it finishes. |
|
The tree claim checks out. Verified independently rather than taken on trust: But it does not clear the gate. The validator's threshold is 200 source/build-data files, and it counts the test merge, not the PR diff:
So both halves still refuse, and the refusal happens before the build, which means neither half has been byte-gated and the Chunking a mechanical sweep was arithmetic. Chunking this is not, because a header change and the sources it forces have to land together, so the boundaries are yours to choose rather than mine. Carry-over finding that still applies. I verified #1377's combined tree out of band -- which by the tree-hash equality above is exactly this PR plus #1379 -- and 3 files fail on relocation destinations while matching byte-for-byte: 276 of 441 verified, 162 unenrolled, those 3 failing; control of 8 equivalent on-main destructors passes under the same harness, so it is not an artifact. Detail and the two candidate readings are on #1377. |
The migration half of #1377, split from the layout work it rests on, with the D0 deleting destructors split off again on top so each PR clears the validator's 200-file cap. Stacked on #1378; the D0s are the PR above this one. 131 files. Hand-written .c destructors and methods become real C++ -- classes deriving from their actual base with typed members, in place of a flattened struct and a stand-in. Among them: DonutBlock as the worked example for the shadow-struct classes, thirty Platform subclasses unblocked by the 0x320 correction in #1378, and the array-member classes -- Wiggler's eight, Goomboss's three, ChainChomp's seven links, PathLift's Model[3], RotatingFirebar's one collision cylinder per flame. Six migrations that belong here by subject are in #1378 instead, because that half does not link without them: ChiefChilly, Unagi, Wiggler D0 and D1, Goomboss and ChainChomp all call the renamed Vector3 destructors. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. pr_linkcheck: no new WRONG or NO-REPRO. Enrollment does not move, and that is expected: a migration replaces the source of a function that was already enrolled, so the count stays while the source stops lying. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x
The migration half of #1377, split from the layout work it rests on, with the D0 deleting destructors split off again on top so each PR clears the validator's 200-file cap. Stacked on #1378; the D0s are the PR above this one. 131 files. Hand-written .c destructors and methods become real C++ -- classes deriving from their actual base with typed members, in place of a flattened struct and a stand-in. Among them: DonutBlock as the worked example for the shadow-struct classes, thirty Platform subclasses unblocked by the 0x320 correction in #1378, and the array-member classes -- Wiggler's eight, Goomboss's three, ChainChomp's seven links, PathLift's Model[3], RotatingFirebar's one collision cylinder per flame. Six migrations that belong here by subject are in #1378 instead, because that half does not link without them: ChiefChilly, Unagi, Wiggler D0 and D1, Goomboss and ChainChomp all call the renamed Vector3 destructors. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. pr_linkcheck: no new WRONG or NO-REPRO. Enrollment does not move, and that is expected: a migration replaces the source of a function that was already enrolled, so the count stays while the source stops lying. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x
The D0 half of #1379, split off so each PR clears the validator's 200-file cap. Stacked on #1379, which carries the class definitions these need. D0 is vtable slot 17 (or 1, for classes rooted below Actor): destroy, then return the object to the actor heap. Each of these was a hand-written .c file spelling out what the compiler emits anyway -- store the vtable, call the member destructors in reverse declaration order, chain to the base, call Memory::Deallocate. Declaring the class properly lets the compiler emit all of it, and the deallocation comes from the inline operator delete rather than anything in the file. Not in arm9: those D0s need an operator delete the arm9 classes do not have in scope, which is a separate problem and is not attempted here. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. Enrollment does not move: a D0 was already enrolled from its .c file, so the count stays while the source stops hand-spelling the mangled name. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x
The migration half of #1377, split from the layout work it rests on, with the D0 deleting destructors split off again on top so each PR clears the validator's 200-file cap. Stacked on #1378; the D0s are the PR above this one. 131 files. Hand-written .c destructors and methods become real C++ -- classes deriving from their actual base with typed members, in place of a flattened struct and a stand-in. Among them: DonutBlock as the worked example for the shadow-struct classes, thirty Platform subclasses unblocked by the 0x320 correction in #1378, and the array-member classes -- Wiggler's eight, Goomboss's three, ChainChomp's seven links, PathLift's Model[3], RotatingFirebar's one collision cylinder per flame. Six migrations that belong here by subject are in #1378 instead, because that half does not link without them: ChiefChilly, Unagi, Wiggler D0 and D1, Goomboss and ChainChomp all call the renamed Vector3 destructors. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. pr_linkcheck: no new WRONG or NO-REPRO. Enrollment does not move, and that is expected: a migration replaces the source of a function that was already enrolled, so the count stays while the source stops lying. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x
The D0 half of #1379, split off so each PR clears the validator's 200-file cap. Stacked on #1379, which carries the class definitions these need. D0 is vtable slot 17 (or 1, for classes rooted below Actor): destroy, then return the object to the actor heap. Each of these was a hand-written .c file spelling out what the compiler emits anyway -- store the vtable, call the member destructors in reverse declaration order, chain to the base, call Memory::Deallocate. Declaring the class properly lets the compiler emit all of it, and the deallocation comes from the inline operator delete rather than anything in the file. Not in arm9: those D0s need an operator delete the arm9 classes do not have in scope, which is a separate problem and is not attempted here. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. Enrollment does not move: a D0 was already enrolled from its .c file, so the count stays while the source stops hand-spelling the mangled name. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x
The migration half of #1377, split from the layout work it rests on, with the D0 deleting destructors split off again on top so each PR clears the validator's 200-file cap. Stacked on #1378; the D0s are the PR above this one. 131 files. Hand-written .c destructors and methods become real C++ -- classes deriving from their actual base with typed members, in place of a flattened struct and a stand-in. Among them: DonutBlock as the worked example for the shadow-struct classes, thirty Platform subclasses unblocked by the 0x320 correction in #1378, and the array-member classes -- Wiggler's eight, Goomboss's three, ChainChomp's seven links, PathLift's Model[3], RotatingFirebar's one collision cylinder per flame. Six migrations that belong here by subject are in #1378 instead, because that half does not link without them: ChiefChilly, Unagi, Wiggler D0 and D1, Goomboss and ChainChomp all call the renamed Vector3 destructors. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. pr_linkcheck: no new WRONG or NO-REPRO. Enrollment does not move, and that is expected: a migration replaces the source of a function that was already enrolled, so the count stays while the source stops lying. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x
The D0 half of #1379, split off so each PR clears the validator's 200-file cap. Stacked on #1379, which carries the class definitions these need. D0 is vtable slot 17 (or 1, for classes rooted below Actor): destroy, then return the object to the actor heap. Each of these was a hand-written .c file spelling out what the compiler emits anyway -- store the vtable, call the member destructors in reverse declaration order, chain to the base, call Memory::Deallocate. Declaring the class properly lets the compiler emit all of it, and the deallocation comes from the inline operator delete rather than anything in the file. Not in arm9: those D0s need an operator delete the arm9 classes do not have in scope, which is a separate problem and is not attempted here. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. Enrollment does not move: a D0 was already enrolled from its .c file, so the count stays while the source stops hand-spelling the mangled name. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x
The migration half of #1377, split from the layout work it rests on, with the D0 deleting destructors split off again on top so each PR clears the validator's 200-file cap. Stacked on #1378; the D0s are the PR above this one. 131 files. Hand-written .c destructors and methods become real C++ -- classes deriving from their actual base with typed members, in place of a flattened struct and a stand-in. Among them: DonutBlock as the worked example for the shadow-struct classes, thirty Platform subclasses unblocked by the 0x320 correction in #1378, and the array-member classes -- Wiggler's eight, Goomboss's three, ChainChomp's seven links, PathLift's Model[3], RotatingFirebar's one collision cylinder per flame. Six migrations that belong here by subject are in #1378 instead, because that half does not link without them: ChiefChilly, Unagi, Wiggler D0 and D1, Goomboss and ChainChomp all call the renamed Vector3 destructors. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. pr_linkcheck: no new WRONG or NO-REPRO. Enrollment does not move, and that is expected: a migration replaces the source of a function that was already enrolled, so the count stays while the source stops lying. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x
The D0 half of #1379, split off so each PR clears the validator's 200-file cap. Stacked on #1379, which carries the class definitions these need. D0 is vtable slot 17 (or 1, for classes rooted below Actor): destroy, then return the object to the actor heap. Each of these was a hand-written .c file spelling out what the compiler emits anyway -- store the vtable, call the member destructors in reverse declaration order, chain to the base, call Memory::Deallocate. Declaring the class properly lets the compiler emit all of it, and the deallocation comes from the inline operator delete rather than anything in the file. Not in arm9: those D0s need an operator delete the arm9 classes do not have in scope, which is a separate problem and is not attempted here. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. Enrollment does not move: a D0 was already enrolled from its .c file, so the count stays while the source stops hand-spelling the mangled name. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x
* 59 classes get their real base and real member types The migration half of #1377, split from the layout work it rests on, with the D0 deleting destructors split off again on top so each PR clears the validator's 200-file cap. Stacked on #1378; the D0s are the PR above this one. 131 files. Hand-written .c destructors and methods become real C++ -- classes deriving from their actual base with typed members, in place of a flattened struct and a stand-in. Among them: DonutBlock as the worked example for the shadow-struct classes, thirty Platform subclasses unblocked by the 0x320 correction in #1378, and the array-member classes -- Wiggler's eight, Goomboss's three, ChainChomp's seven links, PathLift's Model[3], RotatingFirebar's one collision cylinder per flame. Six migrations that belong here by subject are in #1378 instead, because that half does not link without them: ChiefChilly, Unagi, Wiggler D0 and D1, Goomboss and ChainChomp all call the renamed Vector3 destructors. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. pr_linkcheck: no new WRONG or NO-REPRO. Enrollment does not move, and that is expected: a migration replaces the source of a function that was already enrolled, so the count stays while the source stops lying. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x * Re-request validation against the retargeted base No content change. This PR's base moved from cpp/platform-enemy-layout to cpp/layout-headergen when the layout half was split in two, and the relay keys on head SHA -- retargeting alone does not re-submit, so the check still showed the 431-file count from the old base. This empty commit changes the head so the validator measures the 131 files this PR actually adds. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* 59 classes get their real base and real member types The migration half of #1377, split from the layout work it rests on, with the D0 deleting destructors split off again on top so each PR clears the validator's 200-file cap. Stacked on #1378; the D0s are the PR above this one. 131 files. Hand-written .c destructors and methods become real C++ -- classes deriving from their actual base with typed members, in place of a flattened struct and a stand-in. Among them: DonutBlock as the worked example for the shadow-struct classes, thirty Platform subclasses unblocked by the 0x320 correction in #1378, and the array-member classes -- Wiggler's eight, Goomboss's three, ChainChomp's seven links, PathLift's Model[3], RotatingFirebar's one collision cylinder per flame. Six migrations that belong here by subject are in #1378 instead, because that half does not link without them: ChiefChilly, Unagi, Wiggler D0 and D1, Goomboss and ChainChomp all call the renamed Vector3 destructors. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. pr_linkcheck: no new WRONG or NO-REPRO. Enrollment does not move, and that is expected: a migration replaces the source of a function that was already enrolled, so the count stays while the source stops lying. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x * Re-request validation against the retargeted base No content change. This PR's base moved from cpp/platform-enemy-layout to cpp/layout-headergen when the layout half was split in two, and the relay keys on head SHA -- retargeting alone does not re-submit, so the check still showed the 431-file count from the old base. This empty commit changes the head so the validator measures the 131 files this PR actually adds. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x * 61 deleting destructors become real C++ The D0 half of #1379, split off so each PR clears the validator's 200-file cap. Stacked on #1379, which carries the class definitions these need. D0 is vtable slot 17 (or 1, for classes rooted below Actor): destroy, then return the object to the actor heap. Each of these was a hand-written .c file spelling out what the compiler emits anyway -- store the vtable, call the member destructors in reverse declaration order, chain to the base, call Memory::Deallocate. Declaring the class properly lets the compiler emit all of it, and the deallocation comes from the inline operator delete rather than anything in the file. Not in arm9: those D0s need an operator delete the arm9 classes do not have in scope, which is a separate problem and is not attempted here. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. Enrollment does not move: a D0 was already enrolled from its .c file, so the count stays while the source stops hand-spelling the mangled name. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* 59 classes get their real base and real member types The migration half of #1377, split from the layout work it rests on, with the D0 deleting destructors split off again on top so each PR clears the validator's 200-file cap. Stacked on #1378; the D0s are the PR above this one. 131 files. Hand-written .c destructors and methods become real C++ -- classes deriving from their actual base with typed members, in place of a flattened struct and a stand-in. Among them: DonutBlock as the worked example for the shadow-struct classes, thirty Platform subclasses unblocked by the 0x320 correction in #1378, and the array-member classes -- Wiggler's eight, Goomboss's three, ChainChomp's seven links, PathLift's Model[3], RotatingFirebar's one collision cylinder per flame. Six migrations that belong here by subject are in #1378 instead, because that half does not link without them: ChiefChilly, Unagi, Wiggler D0 and D1, Goomboss and ChainChomp all call the renamed Vector3 destructors. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. pr_linkcheck: no new WRONG or NO-REPRO. Enrollment does not move, and that is expected: a migration replaces the source of a function that was already enrolled, so the count stays while the source stops lying. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x * Re-request validation against the retargeted base No content change. This PR's base moved from cpp/platform-enemy-layout to cpp/layout-headergen when the layout half was split in two, and the relay keys on head SHA -- retargeting alone does not re-submit, so the check still showed the 431-file count from the old base. This empty commit changes the head so the validator measures the 131 files this PR actually adds. Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* 59 classes get their real base and real member types The migration half of #1377, split from the layout work it rests on, with the D0 deleting destructors split off again on top so each PR clears the validator's 200-file cap. Stacked on #1378; the D0s are the PR above this one. 131 files. Hand-written .c destructors and methods become real C++ -- classes deriving from their actual base with typed members, in place of a flattened struct and a stand-in. Among them: DonutBlock as the worked example for the shadow-struct classes, thirty Platform subclasses unblocked by the 0x320 correction in #1378, and the array-member classes -- Wiggler's eight, Goomboss's three, ChainChomp's seven links, PathLift's Model[3], RotatingFirebar's one collision cylinder per flame. Six migrations that belong here by subject are in #1378 instead, because that half does not link without them: ChiefChilly, Unagi, Wiggler D0 and D1, Goomboss and ChainChomp all call the renamed Vector3 destructors. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. pr_linkcheck: no new WRONG or NO-REPRO. Enrollment does not move, and that is expected: a migration replaces the source of a function that was already enrolled, so the count stays while the source stops lying. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x * Re-request validation against the retargeted base No content change. This PR's base moved from cpp/platform-enemy-layout to cpp/layout-headergen when the layout half was split in two, and the relay keys on head SHA -- retargeting alone does not re-submit, so the check still showed the 431-file count from the old base. This empty commit changes the head so the validator measures the 131 files this PR actually adds. Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x * 61 deleting destructors become real C++ The D0 half of #1379, split off so each PR clears the validator's 200-file cap. Stacked on #1379, which carries the class definitions these need. D0 is vtable slot 17 (or 1, for classes rooted below Actor): destroy, then return the object to the actor heap. Each of these was a hand-written .c file spelling out what the compiler emits anyway -- store the vtable, call the member destructors in reverse declaration order, chain to the base, call Memory::Deallocate. Declaring the class properly lets the compiler emit all of it, and the deallocation comes from the inline operator delete rather than anything in the file. Not in arm9: those D0s need an operator delete the arm9 classes do not have in scope, which is a separate problem and is not attempted here. VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py differs from main only by the rename pair #1378 introduces. tools suite 265 passed. langmode ratchet PASS. No duplicate stems. Enrollment does not move: a D0 was already enrolled from its .c file, so the count stays while the source stops hand-spelling the mangled name. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The layout half of #1377, split out so it can be reviewed on its own. Every per-class migration is in #1377's sibling PR; what is here is the base classes, the tooling, the two symbol renames, and the source edits those force.
310 files. The other half is 253. Together they reconstruct #1377's tree exactly — same git tree hash — so nothing was dropped in the split.
What this is
Platform's data ends at0x31e, sizeof0x320. Four classes derive from it directly and each places a 4-byte-aligned class member at0x320— PyramidTop/Model, SwitchPillar/TextureTransformer, MovingBarSmall/ShadowModel, WallSign/MovingCylinderClsnWithPos— each read off that class's own destructor.BowserFireSeaArena's own threes16sit at0x31e/0x320/0x322so itsModellands at0x324. One layout satisfies all five; ending at0x324satisfies only BowserFireSeaArena and contradicts the other four. This corrects ov060: the Bowser fight becomes real C++, and D0 destructors become migratable #1374, which was mine.Enemyderives fromActor— what 51 subclasses were waiting on — plus five more Enemy fields named by its subclasses, and its vtable symbol.func_020072c0andfunc_02011508becomeVector3::~Vector3andVector3s::~Vector3s.ModelBase::SetFileandShadowModel::InitCylinderreturnint, notvoid.>= VTABLE_PREAMBLErather than==, so 44 → 36 forModelAnimcorrects instead of being refused. The ROM names the destination independently —_ZTV9ModelAnim0x0208e980againstVTable_Animation_ModelAnimThunk0x0208e9a4, differing by exactly 44 − 8.tools/subclass_migrate.py,tools/platform_subclass.py,tools/d0_migrate.py, and the header-generation fixes behind them.Why six migrations are here and not in the sibling
ChiefChilly,Unagi,Wiggler(D0 and D1),GoombossandChainChompare migrated here because this half does not build without them, and it took the ROM link to say so rather than the compiler. GivingVector3a destructor stops ChiefChilly's hand-written.cfiles compiling; renamingfunc_02011508leaves the other four referencing a symbol that no longer exists — which every file still compiles happily against, and onlymwldarmrejects:Found by building, not by reading.
Verified
rombuild.py -j16, full ROMeligible.pyvscbd57a83tools/suiteOne trap worth recording: a symbol rename drops
completein delinks, becauseenroll.pypreserves it by symbol name. The two renamed entries had to be re-promoted with--complete-list; without that the source-built count silently falls 10,813 → 10,810 while every other gate still passes.Original work is by the author of #1377 across 37 commits. This split preserves the content, not the history — #1377's branch still carries the derivation.
🤖 Generated with Claude Code
https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x