3.2 KiB
§99 — The narrow-param wall is a DEF-side problem with a ZERO-blast-radius fix: convert the definition to K&R (Phase 29 SESSION-22, func_80175AB8 + func_80175DA8)
§92 said these two need "the §17a-1 caller pair, NOT a bare conform". The diagnosis was right —
conforming the fleet's void f(s32) declarations to the byte-true void f(s16) narrows the
parameter, changing argument promotion at every call site, so the callers emit different code
(§92 measured exactly that: PLUMBING before the conform, DIFF after). But the prescribed remedy
was the expensive one. The actual fix touches no declaration at all:
void func_80175AB8(param_1) /* K&R: the narrow param PROMOTES to int (C89 6.3.2.2), */
s16 param_1; /* so this is ALREADY compatible with the fleet's `s32` */
{ /* prototype — while still emitting the narrow-param codegen. */
That is §43 applied to the definition side instead of the declaration side. Cost: a draft-only
edit (T0, zero blast radius) versus a 524-site fleet conform. Both banked, d19c9580,
R22 140/140 — 57,822 templated instructions for two draft-local rewrites.
The law: when the byte-true signature has a NARROW scalar parameter and the fleet declares it wide, do NOT move the declarations. Move the DEFINITION to K&R and let C's promotion rule make the existing prototype correct. Conform only when the disagreement is a POINTER shape (caller-neutral, §85) or an arity/return change.
Two reconcile_tu bugs found underneath, one introduced while fixing the other
(a) It was blind to BLOCK-SCOPE declarations. split_statements is depth-0 by design, so for
a draft whose body is one function definition it returns exactly ONE statement and every declaration
inside is invisible — and §8d (scope_data_externs) deliberately demotes the data externs to block
scope. C still requires a block-scope extern to agree with a file-scope declaration in scope, so
the conflict is real: the tool printed reconciled: 0 draft(s), 0 data symbol(s); coverage defects: 0
for a draft cc1 then rejected with conflicting types for D_8011F7BC. Fixed by descending one level.
(b) DESCENDING INTO ANY { CORRUPTS STRUCTS — a bug I introduced with (a) and caught by diffing
the tool's own output against its input. Struct MEMBERS parse as declarations and get "conformed":
- u32 code; /* 0x04 */ -> typedef void (*code)(unsigned short*);
- p->code = *(u32 *)src; -> p->(*(u32 *)&code) = *(u32 *)src;
Guard: descend only into a FUNCTION body (a parameter list before the brace, and not a
typedef|struct|union|enum head).
(c) And it exposed a LATENT one: _cast_sub's regex matched a bare identifier, so it rewrote
member accesses as if they were the global. Broken since the tool was written; only reachable
once block-scope descent started finding such names. Guard: (?<![.\w])(?<!->).
Process note worth keeping: (b) was caught because the transform's output was diffed against its input before the result was trusted — not by a gate. The byte-gate would have reported PLUMBING and told me nothing about why, and the corrupted draft looked plausible.