← board

A multi-dim array FIELD decays with the element stride

Measured (gcc oracle)

struct A { int m[3][4]; char c[2][8]; double d[2][3]; } s;
expression gcc pxx before
(char*)(s.m+1) - (char*)s.m 16 4
(char*)(s.c+1) - (char*)s.c 8 1
(char*)(s.d+1) - (char*)s.d 24 8
int (*r)[4] = s.m + 1; r[0][2] (with s.m[1][2]=7) 7 0

The bare-array spelling of every one of these is correct and pinned by test/carr2d_decay_stride.c. The last row is the one that matters: no cast, no visible pointer arithmetic — a row pointer assigned and read back, answering a different element.

Root

IRPointerStride's AN_IDENT arm carries the C rule for rank >= 2 — a multi-dim array decays to a pointer to its ROW, so the stride is the element size times the product of the remaining dims ([[bug-c-a-multidim-array-decays-with-the-element-stride]]). Its AN_FIELD arm, one screen below in the same routine, answered RecFieldType and stopped.

RecFieldRowStride already computes exactly the needed value and ParseCPostfixTail already calls it, so the fix is four lines: for RecFieldArrNDims > 1, answer RecFieldRowStride and exit.

Why this keeps happening

The third field-arm defect found on 2026-08-29 whose array-arm twin was fixed months earlier:

the array arm got the field arm did not fixed
the ASTSLen stamp on a decayed row 10676bcc2
the product-of-remaining-spans multiplier 10676bcc2
the multi-dim ROW decay stride here

That is not bad luck; it is normalise-dont-special-case.md with three landed instances instead of a prediction. What makes it expensive is that the two arms are adjacent in the same routine — so every fix looks local and complete, and nothing in a diff shows the sibling going unedited. A reviewer sees a correct change to correct code (frank-coordinator, 2026-08-29). Put the other way: three agents did not skip the grep; the diff never gave them a reason to run it.

Two further readers are built the same way and are worse than this one — they segfault. Enumerated, with the sweep that should replace all four: [[refactor-c-one-array-shape-reader-instead-of-four-ident-field-pairs]].

Fix (DONE)

compiler/ir.inc, IRPointerStride's AN_FIELD arm: when the field is a multi-dim array, answer RecFieldRowStride and exit, exactly as the AN_IDENT arm does.

Gate — MET

Note on the commit this cites

It landed as one commit with [[refactor-c-the-partial-index-sentinel-should-not-be-a-type-tag]], not two. They were committed separately (5348f20ef, 34a72721c locally) and a contended rebase — four tools/sync.sh runs in flight at once across sibling checkouts — squashed them while resolving repeated BOARD*.md conflicts. So 72de20420's message describes only the refactor, and the fix recorded here is in it without being named by it. That is why this ticket and the refactor's cite the same sha.

Nothing was lost: verified at HEAD after the squash — make compiler/pascal26 converged, cll_array_pointer_base / cfield_partial_index_stride / carr2d_decay_stride / cptrdiff_elem_types / cfield_2d_row_decay_b62 all pass, and the int/char/double field probes still match gcc. The loss is documentary, and it is recorded here because the commit cannot be: the sha is public and tstate verdicts and resolve citations are keyed by it, so rewriting it would break more than it fixes.

Filed as tooling: [[bug-t-concurrent-sync-runs-can-squash-two-commits-into-one]].

Log