From 9df0cd29dd0cb62ccc4808cdd39cc706f92fb59b Mon Sep 17 00:00:00 2001 From: Drew T <50529377+Druthulu@users.noreply.github.com> Date: Thu, 3 Sep 2026 20:17:57 -0600 Subject: [PATCH] =?UTF-8?q?docs(cookbook):=20=C2=A7481=20conflicting=20typ?= =?UTF-8?q?es=20is=20a=20SAME-SCOPE=20error;=20across=20scopes=20it=20degr?= =?UTF-8?q?ades=20to=20a=20warning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The escape hatch for the declaration-conflict class the reconcile/sync ladder cannot reach — two anonymous struct typedefs in one TU are never compatible in C89, so no duplicate spelling works, but block scope turns the error into the warning the build already emits elsewhere. From main:func_8001FC08 (400 ins), whose body was solved in S76 and had never banked because nobody asked why. --- docs/matching-cookbook.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md index 7d249c549..11014322c 100644 --- a/docs/matching-cookbook.md +++ b/docs/matching-cookbook.md @@ -35862,3 +35862,34 @@ than the real one.** Same shape as §478: a consumer that reads a draft and emit what the gate actually does to that draft, or it will route real work to the wrong lane and invent work that does not exist. When a static class and the gate disagree, **gate one and believe the bytes** — it costs one build. + +#### §481 ★★★ — `conflicting types` IS A SAME-SCOPE ERROR; ACROSS SCOPES IT IS ONLY A WARNING (P31 S77, `main:func_8001FC08`, 400 ins) + +**The law, and it is the escape hatch for most of the declaration-conflict class.** gcc-2.7.2 raises +`conflicting types for X` as a hard ERROR only when the two declarations are in the SAME scope. +Across scopes it degrades to `type mismatch with previous external decl` — a **WARNING**, which the +build already emits elsewhere (the unmodified TU emits exactly that for `func_80012E0C`). So a draft +whose spelling cannot be reconciled with the TU's does not need reconciling: **move the offending +`extern` to BLOCK scope and the error becomes a warning.** + +**Measured.** `func_8001FC08`'s body was solved in S76 and had never banked, and nobody had asked +why. Spliced into `src/800.c` it produced 3 hard cc1 errors (rc=33 against a baseline rc=0): its +file-scope `typedef … MTX_80020248` plus `extern MTX_80020248 D_80074818[]/D_80075018[]` collide with +the TU's own copies fifteen lines BELOW the `INCLUDE_ASM`. **Two anonymous struct typedefs in one TU +are never compatible in C89**, so no duplicate spelling could ever have worked — the usual +"adopt the TU's spelling" lever is structurally unavailable here. Renaming the struct to +`MTX_8001FC08` and demoting the two externs to block scope gives **rc=0, +4 warnings, 0 errors**, and +the whole-TU `.text` is byte-identical to the all-`INCLUDE_ASM` build. No `src/` hoist, no other +function shifted. + +**Why this generalises.** The session's dominant bank-blocker is a declaration disagreement, and the +existing ladder answers it by making the two declarations AGREE (`sync_tu_decls` copies the TU's +spelling; `reconcile_tu` casts at the use site). §481 adds the case those cannot reach: when the two +spellings are *incompatible by construction* — anonymous structs, or a type the TU declares below the +splice point — you do not need agreement at all, only different scopes. It is also the mechanism +behind §8d's scope-demote lever, stated as the general rule rather than one tool's trick. + +**Verification standard this came with (law 1c, worth copying):** 26 `jal` + 16 HI16/LO16 relocations +identical in name AND order, all 16 internal `j` destinations decoded and compared (the §195-D blind +spot), and the four `D_1F800020` words identified as splat FALSE-symbolisation of `lui $s1,0x1F80` + +an `rm++` increment — ROM `3C111F80`/`26310020`, emitted identically.