Files
BFM-decomp/cookbook/C0463.md
T

1.7 KiB

§415 ★★ — A FILE-SCOPE DECL MAKES gcc-2.7.2 MERGE THE TU'S LATER BLOCK-SCOPE EXTERNS INTO IT (P31 S71; byte-proven ov_SC04_011/func_80180B24, 215 ins)

The trap. Adding a file-scope extern for a callee is the reflex fix when a draft's declaration is missing. On a TU that declares that same callee at BLOCK scope further down, it is the thing that breaks the build — and the error names the DEFINITION, not your decl.

ov_SC04_011_jr_8017D494.c declares func_80183BD0 at block scope twice (l.5019, l.5156, both (u8 *)) and DEFINES it as void func_80183BD0(s32) around l.7238. Put ANY file-scope declaration of it at l.4883 and pushdecl's different_binding_level path merges those later block-scope externs into the global one; the merged global then conflicts with the definition. Declare it at BLOCK scope, like its neighbours, and the TU compiles.

Companion, same function: a draft's file-scope extern s32 D_80126B58 collides with the TU's block-scope u8 D_80126B58[] (l.7968) — resolved with the house __asm__ alias rather than by changing either spelling.

The rule of thumb this makes explicit: match the TU's own binding LEVEL, not just its type. §376/§378 are about the declaration's TYPE agreeing with the definition; this is the orthogonal axis, and it is invisible to match_one for the usual reason — it compiles the function alone.

Method note worth copying. The agent proved both claims by splicing a scratch copy of the whole TU and running the Makefile's own cpp+cc1 recipe on it, comparing diagnostics against an unmodified base — a negative control on the TU, not on the function. That is the right instrument for any "does my declaration break this TU" question.