← board

A nested routine's local type does not shadow the enclosing routine's

Silent wrong value, no diagnostic, no generics required. The inner TRec is ignored and every use in the nested routine binds the OUTER one.

procedure Outer;
type TRec = packed record p, q, r: Byte; end;      { 3 }
  procedure Inner;
  type TRec = packed record s: Byte; end;          { 1 }
  begin Writeln(SizeOf(TRec)); end;                { pxx 3, fpc 1 }
begin Inner; end;

Cause: the alias table has no routine scope

FindTypeAlias (symtab.inc) ranks on two keys only — AliasOwnerCi (the CLASS body a row was declared in) and UsesRankOf — and ties keep the FIRST row. Routine-local types are appended with AliasOwnerCi = -1 like any unit-level type, so the enclosing routine's row is simply the earlier one and wins. There is no AliasCount save/restore anywhere for Pascal: the rows are never popped.

Why the leak nobody has hit is hidden: var w: TLocalOnly; at program level after a routine correctly says unknown type, but not because of scoping — the routine's local type section is parsed in PASS 2, after the program's var section has already been read. The scope rule is absent; the pass order is standing in for it.

Both one-line fixes are wrong, which is why this is a ticket

The fix is a real scope key on the alias row (the proc it was declared in, plus enclosing-proc reachability), not a rank tweak.

What is green over it, and cannot see it

tgeneric94.pp passes today. It compares SizeOf(t.f) against TRecSize_Nested = SizeOf(TRec)both sides resolve through the same broken lookup, so they agree while both are wrong, and the row would pass if this machinery did nothing at all. Its skip row was burned on the strength of the bug-p-a-specialization-in-a-routine-local-type-section-desyncs-the-parse fix, which is a true statement about that defect and not about this one.

test/test_routine_local_specialization.pas deliberately names the inner and outer types APART so its red would be about the splice; the repro above is the only assertion that fails on this.

FIXED at 0221a024a — resolved 2026-09-07, and the LAG is the finding

The code and the fixture landed on 2026-09-06 in fix(P): routine-local declarations are scoped in all five name tables, not one (this ticket is the alias row of that group). Nothing was fixed today; only the paperwork was. Saying so matters, because a ticket that closes with no diff is indistinguishable from one that was quietly re-filed, and the P-bug umbrella asks for the split.

Re-measured 2026-09-07 at compiler a8f1784cfad0:

pxx HEAD    inner 1 / outer 3      <- matches fpc 3.2.2
pin v407    inner 3 / outer 3      <- the defect, unchanged

The pin still carries it, so the fix is inert for anything built against $(PXX_STABLE) until the next pin.

Already asserted by test/test_routine_local_name_scoping.pas (test_rtlocalscope26), wired in the Makefile, rows 3/4 — green at HEAD.

Log