← board

The wall

type
  PPHashSetItem = ^PHashSetItem;        { cclasses.pas:486 }
  PHashSetItem  = ^THashSetItem;        { :487 }
  THashSetItem  = record
    Next: PHashSetItem; Key: Pointer; KeyLength: Integer;
    HashValue: LongWord; Data: TObject;
  end;
...
  Entry := @FBucket[h and (FBucketCount-1)];
  while Assigned(Entry^) and
    not ((Entry^^.HashValue = h) and (Entry^^.KeyLength = KeyLen) and
      (CompareByte(Entry^^.Key^, Key^, KeyLen) = 0)) do
        Entry := @Entry^^.Next;         { :2909 — refused }

Measured under --mimic-fpc-compiler against /usr/share/fpcsrc/3.2.2/compiler with compiler 7c76da7cf0fa.

What does NOT reproduce it, which is the useful half

A program with those three declarations verbatim, a THashSet = class carrying FBucket: PPHashSetItem, and a Lookup whose body is the loop above (minus CompareByte) compiles and runs. So none of these is the discriminator on its own: the forward pointer-to-pointer chain, the self-referential record, the class field of PP type, @FBucket[i] indexing a pointer, Assigned(Entry^), Entry^^.field, or Entry := @Entry^^.Next.

That is worth stating plainly because it is where a reader would start, and it is a dead end. The remaining candidates are things the reduction dropped: the CompareByte(Entry^^.Key^, ...) term, TSymStr/symansistr conditionals in force under --mimic-fpc-compiler, or interference from a declaration earlier in a 3000-line unit.

Two neighbouring shapes that DO fail

Found while probing, both real, neither producing this diagnostic:

type PPI = ^PI; PI = ^TI; TI = record hv: LongWord; nx: PI; end;
var b: PPI;
  writeln(b[0]^.hv);   { "hv": a pointer has no members (dereference it with ^,
                         or the pointee type is unknown here) }

b[0]^ — indexing a pointer-to-pointer and then dereferencing the element. @b[0] followed by e^^ works, so the element's pointee is knowable and this spelling does not ask for it.

Do not confuse this with

[[bug-p-a-forward-pointer-to-a-named-array-type-loses-its-element]], which was the PREVIOUS wall on this march (cclasses.pas:1274) and is fixed. Three walls fell in one session — TFPCHeapStatus, the forward pointer-to-array, and Prefetch — each visible only once the one in front of it was gone. This is the fourth and it is the first that did not yield to a reduction.

2026-09-06 (frankS) — the "two neighbouring shapes that DO fail" section is stale

Both now compile and run, measured at d712038df with compiler 1c3ab9613b2e:

This is not a claim that the cclasses.pas:2909 wall moved. The ticket is explicit that neither shape produced that diagnostic and neither was established as the cause, so their passing says nothing about the wall itself — it only retires them as candidates and as starting points for the next reader.

The wall needs a driver under --mimic-fpc-compiler against /usr/share/fpcsrc/3.2.2/compiler, and there is no committed harness — the march is driven by hand. Not attempted here for the reason frankB banked on 2026-09-05 after retracting two march findings: "a substitute for a flag is a configuration nobody else runs, so every number it produces is unshared." This wants whoever holds the march configuration.

2026-09-09 (frankH) — closed: the wall is gone, and the bisect names why

Measured at master 3188b5c38, compiler cea180134ee7 (converged after 2 round(s); stamp removed first so nothing could answer from another tree's):

$ pascal26 --mimic-fpc-compiler -Fu/usr/share/fpcsrc/3.2.2/compiler cc.pas
ok: cc  [code=532248B ...]
$ ./cc
cc ok

where cc.pas is program cc; uses cclasses; begin WriteLn('cc ok') end. — the ticket's configuration exactly, no extra -Fu.

Controls, because "it compiles now" has three boring explanations:

Attributed: a4cbaa1de, 2026-09-06

git bisect with --term-old=broken --term-new=fixed, broken cf7101dfa (2026-09-05) → fixed 51901941e, ~10 build steps, each one rm -f compiler/.pascal26.fixedpoint then make compiler/pascal26 (exit 125 on a build failure so a tree that cannot build is skipped rather than voted):

a4cbaa1dee1cd6b450f0a1d4807e47cd2002aae8 is the first fixed commit
    fix(P): the forward-pointee alias repair ran ONCE, forward — order decided the answer

ResolvePendingPointerAliases walked the alias table once in index order, so a pointer-to-pointer row declared ABOVE its pointee copied a base still at REC_NONE and nothing revisited it. cclasses spells its chain in exactly that order (PPHashSetItem at :486, PHashSetItem at :487). That commit's own message records pin v404 refuses the three-level row outright with "dereferenced value is not a pointer" — the same diagnostic this ticket is named for. It was found and fixed from the reduction side while this ticket held the corpus side; neither knew about the other.

Why the bisect predicate was "does cclasses compile AT ALL"

Not "does the :2909 message appear". At the oldest in-range commit cf7101dfa the wall is cclasses.pas:676 unknown type: TFPCHeapStatus — walls fall in SEQUENCE in this unit, so a predicate keyed on the message answers "fixed" for every commit whose parse stops EARLIER, which is the wrong direction and reads as a clean bisect. Same inversion as [[bug-p-the-generics-corpus-wall-moved-backward-from-2729-to-224]], rejected this morning: a stopping point that moves is not the same observable as a declaration that fails.

No regression fixture from this ticket, and that is not a gap

The ticket's own reduction — the three forward declarations, the class field of PP type, the Lookup body — compiled throughout, on the day it was filed and today. A shape that never failed cannot guard anything. The guard already exists and is already wired: test/test_forward_double_pointer_alias_order.pas, landed by a4cbaa1de, asserts both fields (.a is at offset 0 and is green while the bug is live), both declaration orders, and a three-level chain. Adding a uses cclasses row would be a 3000-line fixture over a file outside the repo, guarding a defect that already has a 44-line one.

The frontier moved to cfileutl.pas:136

pascal26:136: error: unknown type: TExecuteFlags
  in: /usr/share/fpcsrc/3.2.2/compiler/cfileutl.pas

(with -Fu.../compiler/x86_64 added, or cpuinfo is not found first). This is not a parser bug: TExecuteFlags is an FPC sysutils type and pxx's RTL does not declare it anywhere — grep -rn TExecuteFlags lib/rtl/ compiler/builtin/ is empty. The default-set-after-an-open-array shape parses fine on its own (probe: two overloads, F: TEF = [], plain and array of AnsiString, compiles and prints 1 2). Filed separately.

And tail -4 manufactured a finding here, for the third time today. The truncated output showed only the :137 error, so :136 — the same type, the same line, one overload up — looked ACCEPTED, and "the plain-AnsiString arm resolves it while the open-array arm does not" is a specific, plausible, wrong diagnosis. head -20 shows both errors. The instrument did not error; it answered about the tail.

Log