2.0 KiB
§176f — THE DECLARATION FORM IS A MATCHING LEVER, SO RECONCILE TOWARD THE FORM THE MATCH NEEDS (P31 S52)
§176b/§176d treat an in-TU declaration conflict as plumbing: pick one form, cast at the use site, move on. Wave O found the case where that advice is actively wrong.
Six drafts in one TU referenced D_80078D88. Three declared it extern s32 D_80078D88;, three
extern s32 D_80078D88[]; — and one of those drafts carried a comment explaining exactly why:
with
extern s32 D_80078D88;the global load is a plain scalar at asymbol_ref, so sched1 hoisted thelui/lwabove thepkt->uv3store; declaring it as an ARRAY makes gcc-2.7.2'salias.ctreat the access as possibly-aliasing and the hoist stops.
So the declaration form is load-bearing codegen, not style. Resolve such a conflict by asking which form the MATCHES need, then converting the other drafts toward it:
- array is the stronger form — it constrains gcc more, so scalar users can adopt it for free by
indexing
D_x[0](identical bytes: verified on all three here); - the reverse is NOT free — forcing an array user to scalar can re-enable the hoist and break it.
Result: 42/42 drafts compatible, 0 dropped, where the greedy keep-first rule would have dropped 5. Every one re-verified MATCH after conversion. Wave J/K/L each lost 5–10 drafts to this rule, and those were logged as "recoverable with cast-at-use" — for a scalar/array clash the right repair is usually not a cast at all, it is converting the whole TU to the array form.
Procedure (do this before every batch gate):
- dry-run the gate; for each conflict, grep which drafts declare which form and why;
- reconcile toward the form the matches need (array > scalar; the TU's own decl wins over both);
- re-verify EVERY converted draft with
match_one— the conversion is a codegen change, so it is only free if the bytes say so; - re-run the dry run until it reports
N -> N compatible, 0 dropped.