← board

The shape

type
  PHashItemList = ^THashItemList;                     { cclasses.pas:182 }
  THashItemList = array[0..N] of THashItem;           { :183 }
...
  with FHashList^[Index] do
    if StrIndex >= 0 then ...                         { :1274 — refused }

Ordinary Pascal, and the spelling FPC's own compiler uses.

Three voices, one cause

spelling before
p^[i].f (read or write) a value of this type has no members
with p^[i] do f with needs a record, class or interface — Integer has no members
fld^[i].f, fld a CLASS FIELD compiles, exits 0, reads 0

Same missing fact, and the third one does not announce itself. A ticket written from either of the first two would have been ranked as a diagnostic problem.

The declaration order is the discriminator and the whole argument: every failing row has an in-order twin (TArr first, PArr second) that has always worked. A declaration order changing whether a program parses is the tell the pointer-to-pointer arm of the same routine already names in its own header.

Where it was, and why the comment undersold it

ParseTypeKind's ^T arm asks FindArrayType and takes the element shape from the ArrType entry. Its comment already said:

(A FORWARD PA = ^TA ahead of TA's own declaration is not covered — the entry does not exist yet — and falls back to the old default.)

"Falls back to the old default" reads as a stride approximation. What it actually costs is AliasElemRec, and without the element record the construct is not approximated — it is refused, or silently zero.

ResolvePendingPointerAliases is the pass that exists for exactly this: it already repairs a forward pointee that is a class/record declaration, a pointer alias, or a plain type alias. A named ARRAY type lives in the ArrType table rather than the alias table, so FindTypeAlias answered -1 and no arm fired at all — the fourth pointee shape, in a routine whose other three were each added when someone hit them.

The march

Re-run under --mimic-fpc-compiler against /usr/share/fpcsrc/3.2.2/compiler:

unit before after
cutils globtype constexp version cstreams OK OK
cclasses comphook finput cfileutl cclasses.pas:1274 undefined variable (StrIndex) cclasses.pas:1561 undefined variable (prefetch)
cmsgs an object type cannot have a constructor unchanged — DECIDED, not a gap

prefetch is procedure Prefetch(const mem) — an FPC compiler intrinsic declared in systemh.inc, semantically a cache hint, so the next wall is an RTL/builtin gap and not a parser one.

Note the wall before this one was TFPCHeapStatus, closed the same day by f6ddab6ef. Two walls in one session, each revealed only by removing the one in front of it, which is the argument for walking a corpus rather than triaging a backlog.