mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-10-03 00:05:11 -04:00
fix(gate_main): the in-TU clash pre-check must only compare FILE-SCOPE declarations
DECL is `^\s*extern`/MULTILINE, so it matched an INDENTED extern inside a function body, and the pre-check then compared that block-scope declaration against the TU's file-scope spelling — making the checker STRICTER THAN CC1. Per cookbook §481, gcc-2.7.2 raises `conflicting types' as an ERROR only in the SAME scope; across scopes it degrades to `type mismatch with previous external decl', a WARNING the build already emits elsewhere. So a block-scope extern cannot clash, and dropping on one refuses correct work. Measured in a single gate: func_8001FC08 (400 ins — a deliberately renamed MTX_8001FC08 at block scope, which is the ONLY legal fix there because two anonymous struct typedefs in one TU are never compatible in C89) and func_8002FF0C (166 ins — a deliberate block-scope scalar shadow of D_800A46D2). 566 instructions of byte-correct body refused by a rule the compiler does not apply. _depth0() blanks brace-nested regions, string literals and comments before DECL runs, on both the TU side and the draft side. NEGATIVE CONTROL (R39): on a synthetic TU it keeps both file-scope decls and excludes the block-scope, in-string and in-comment ones; on the two real drafts it removes EXACTLY the three disputed symbols (D_80074818, D_80075018, D_800A46D2) and leaves all 23 other declarations in each untouched. R39 governs the direction: a check that discards good work is worse than one that lets a failure through, and a real conflict still surfaces via the COMPILE-conflict path plus a byte gate that cannot be fooled. R61(b).
This commit is contained in:
+47
-2
@@ -276,6 +276,51 @@ def live_text(txt):
|
||||
out.append('' if dead else ln)
|
||||
return '\n'.join(out)
|
||||
|
||||
|
||||
def _depth0(text):
|
||||
r"""`text` with every brace-nested region blanked, so DECL only sees FILE-SCOPE declarations.
|
||||
|
||||
A BLOCK-SCOPE `extern` CANNOT CLASH WITH THE TU's FILE-SCOPE ONE (P31 S77, cookbook §481).
|
||||
gcc-2.7.2 raises `conflicting types' as an ERROR only in the SAME scope; across scopes it
|
||||
degrades to `type mismatch with previous external decl' — a WARNING the build already emits
|
||||
elsewhere. DECL is `^\s*extern`/MULTILINE, so it happily matched an INDENTED extern inside a
|
||||
function body and this pre-check compared it against the TU's file-scope spelling — making the
|
||||
checker STRICTER THAN CC1 and dropping byte-correct work.
|
||||
|
||||
Measured, in one gate: `func_8001FC08` (400 ins — a deliberately renamed `MTX_8001FC08` at
|
||||
block scope, the §481 escape hatch, the ONLY legal fix because two anonymous struct typedefs in
|
||||
one TU are never compatible in C89) and `func_8002FF0C` (166 ins — a deliberate block-scope
|
||||
scalar shadow of `D_800A46D2`). 566 instructions refused by a rule the compiler does not apply.
|
||||
|
||||
R39 governs the direction of the error: a check that discards good work is worse than one that
|
||||
lets a failure through, and a real conflict still surfaces as the COMPILE-conflict path plus a
|
||||
byte gate that cannot be fooled."""
|
||||
out, depth, i, n = [], 0, 0, len(text)
|
||||
while i < n:
|
||||
c = text[i]
|
||||
if c == '/' and i + 1 < n and text[i + 1] == '/': # line comment
|
||||
j = text.find('\n', i)
|
||||
j = n if j < 0 else j
|
||||
out.append(text[i:j]); i = j; continue
|
||||
if c == '/' and i + 1 < n and text[i + 1] == '*': # block comment
|
||||
j = text.find('*/', i + 2)
|
||||
j = n if j < 0 else j + 2
|
||||
out.append(re.sub(r'[^\n]', ' ', text[i:j])); i = j; continue
|
||||
if c in '"\'': # string / char literal
|
||||
q, j = c, i + 1
|
||||
while j < n and text[j] != q:
|
||||
j += 2 if text[j] == '\\' else 1
|
||||
j = min(j + 1, n)
|
||||
out.append(re.sub(r'[^\n]', ' ', text[i:j])); i = j; continue
|
||||
if c == '{':
|
||||
depth += 1
|
||||
elif c == '}':
|
||||
depth = max(0, depth - 1)
|
||||
out.append(c if (depth == 0 or c == '\n') else ' ')
|
||||
i += 1
|
||||
return ''.join(out)
|
||||
|
||||
|
||||
def resolve_conflicts(slate):
|
||||
"""Drop drafts whose externs contradict (a) the destination TU's OWN existing declarations,
|
||||
or (b) an earlier draft landing in the SAME file.
|
||||
@@ -303,7 +348,7 @@ def resolve_conflicts(slate):
|
||||
if path not in seen_by_file:
|
||||
t = {}
|
||||
try:
|
||||
for d in DECL.findall(live_text(open(path).read())):
|
||||
for d in DECL.findall(_depth0(live_text(open(path).read()))):
|
||||
s = sym_of(d)
|
||||
if s: t[s] = typesig(d)
|
||||
except OSError:
|
||||
@@ -317,7 +362,7 @@ def resolve_conflicts(slate):
|
||||
path = st.path if st else '<unknown>'
|
||||
seen = table(path)
|
||||
body = open(e['draft']).read()
|
||||
ds = [(sym_of(d), typesig(d)) for d in DECL.findall(body)]
|
||||
ds = [(sym_of(d), typesig(d)) for d in DECL.findall(_depth0(body))]
|
||||
ds = [(s, t) for s, t in ds if s]
|
||||
# A DRAFT'S OWN DEFINITION IS A DECLARATION TOO (§20 / wave law 3, the DEF-side wall).
|
||||
# Only `extern` lines were being compared, so a draft defining `s32 func_X(...)` against a
|
||||
|
||||
Reference in New Issue
Block a user