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:
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