boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

commit 231ff72e8f0ade010834887bf0fe0b197a096a19
parent 53e1036601af2a4c60b08c58b3018f4aa634fe8d
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Mon, 27 Apr 2026 02:49:26 -0700

cc/cg: &arr yields T(*)[N] per strict C

cg-take-addr previously special-cased arr ctype to produce ptr-to-elem
(T*), which made &arr + 1 advance by sizeof(T) instead of
sizeof(T[N]). Programs relying on the one-past-end idiom got a
one-element offset.

Drop the special case: &arr now yields ptr-to-arr (T(*)[N]) like
every other lvalue. Array-to-pointer decay still happens on use via
cg-decay-array (already wired in cg-load), so existing fixtures that
assigned &arr to T*-typed variables through a cast keep working — the
numeric address is unchanged, only the static type differs, and
explicit casts relabel.

Lock-in: tests/cc-parse/80-addr-array.c — ((int*)(&arr+1)) - arr
should be 3 for arr[3] (one past end). Was 1 under the deviation.

cc-* green on aarch64 (48 + 67 + 1). All-arch sweep at 651 PASS / 0
FAIL midway through (mid cc-cg amd64); no regressions.

Diffstat:
Mcc/cg.scm | 11+++++------
Atests/cc-parse/80-addr-array.c | 19+++++++++++++++++++
Atests/cc-parse/80-addr-array.expected-exit | 1+
3 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/cc/cg.scm b/cc/cg.scm @@ -574,12 +574,11 @@ (define (cg-take-addr cg) (let* ((p (cg-pop cg)) (ty (opnd-type p)) - ;; &arr yields T*, not (T[N])*. Result type is ptr-to-elem - ;; for arrays so subsequent pointer arithmetic scales by - ;; element size, not by array size. - (pty (cond ((eq? (ctype-kind ty) 'arr) - (%ctype 'ptr 8 8 (car (ctype-ext ty)))) - (else (%ctype 'ptr 8 8 ty))))) + ;; &arr yields T(*)[N] per strict C. Pointer arithmetic on + ;; the result scales by sizeof(T[N]) (the whole array), so + ;; &arr + 1 is one-past-end. Array-to-pointer decay happens + ;; on use via cg-decay-array, not at the & operator. + (pty (%ctype 'ptr 8 8 ty))) (cond ((not (opnd-lval? p)) (die #f "cg-take-addr: not an lvalue")) diff --git a/tests/cc-parse/80-addr-array.c b/tests/cc-parse/80-addr-array.c @@ -0,0 +1,19 @@ +/* Strict-C semantic: &arr yields T(*)[N], not T*. + * + * The numeric address is the same either way; the difference is + * static type, which determines pointer-arithmetic stride. + * + * strict C: &arr + 1 advances by sizeof(T[N]) -> one-past-end + * deviation: &arr + 1 advances by sizeof(T) -> arr[1] + * + * Discriminator: ((int*)(&arr + 1)) - arr should be N (one past end). + * + * Locked-in expectation: 3 (for arr[3]). + */ + +int arr[3] = { 10, 20, 30 }; + +int main(void) { + int *p = (int *)(&arr + 1); + return p - arr; +} diff --git a/tests/cc-parse/80-addr-array.expected-exit b/tests/cc-parse/80-addr-array.expected-exit @@ -0,0 +1 @@ +3