commit 41d03e718e0db05e028e577171ed067100b44bbc
parent 80eb7c8b7ce3dc42942a3eeb59f1a7da5ca38f58
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sun, 26 Apr 2026 22:45:00 -0700
cc/cg+parse: struct global designated init (§E.6)
cc-cg fixture: emit `struct S { int a; int b; } s = { .b = 7 }` as a
zero pad piece followed by the i32 7; main reads &s + 1 (int* units).
cc-parse fixture: same shape from C with `.b = …` syntax; reads the
field via pointer arithmetic over a (int*)&s decay.
Also fixes cg-arith-conv to leave pointer-typed operands alone instead
of unconditionally promoting both sides to a common type — that would
turn an int into a ptr, slipping past cg-binop's scaling branch and
yielding pointer+1 = +1 byte instead of +1 element. Tightening here
unlocks `*(p + N)` everywhere, which §E.3's parse fixture also needed;
that fixture now exercises all three elements rather than just element
zero.
Diffstat:
6 files changed, 59 insertions(+), 15 deletions(-)
diff --git a/cc/cg.scm b/cc/cg.scm
@@ -499,15 +499,23 @@
(ta (opnd-type a))
(tb (opnd-type b))
(sa (%ctype-size ta))
- (sb (%ctype-size tb))
- (common (cond
- ((> sa sb) ta)
- ((> sb sa) tb)
- ((%ctype-unsigned? ta) ta)
- ((%ctype-unsigned? tb) tb)
- (else ta))))
- (cg-push cg (%opnd (opnd-kind a) common (opnd-ext a) (opnd-lval? a)))
- (cg-push cg (%opnd (opnd-kind b) common (opnd-ext b) (opnd-lval? b)))))
+ (sb (%ctype-size tb)))
+ (cond
+ ;; Pointer/array arithmetic: leave types alone so cg-binop's
+ ;; ptr-aware add/sub branch fires with the correct pointee type
+ ;; (and doesn't see two pointers, which would skip scaling).
+ ((or (%ctype-ptr? ta) (%ctype-ptr? tb))
+ (cg-push cg a)
+ (cg-push cg b))
+ (else
+ (let ((common (cond
+ ((> sa sb) ta)
+ ((> sb sa) tb)
+ ((%ctype-unsigned? ta) ta)
+ ((%ctype-unsigned? tb) tb)
+ (else ta))))
+ (cg-push cg (%opnd (opnd-kind a) common (opnd-ext a) (opnd-lval? a)))
+ (cg-push cg (%opnd (opnd-kind b) common (opnd-ext b) (opnd-lval? b))))))))
;; --------------------------------------------------------------------
;; Operators
diff --git a/tests/cc-cg/54-init-struct-desig.expected-exit b/tests/cc-cg/54-init-struct-desig.expected-exit
@@ -0,0 +1 @@
+7
diff --git a/tests/cc-cg/54-init-struct-desig.scm b/tests/cc-cg/54-init-struct-desig.scm
@@ -0,0 +1,26 @@
+;; tests/cc-cg/54-init-struct-desig.scm — global struct designated init.
+;; §E.6.
+;;
+;; Models: struct S { int a; int b; }; struct S s = {.b = 7};
+;; Read b. With proper init, b == 7 and a == 0.
+;; main returns *p where p = (int*)&s + 1 (== &s.b == 7).
+
+(let* ((cg (cg-init))
+ (sty (%ctype 'struct 8 4
+ (list "S" #t
+ (list (list "a" %t-i32 0)
+ (list "b" %t-i32 4)))))
+ (s (%sym "s" 'var 'static sty #f))
+ ;; Designated init: zero pad for a, then 7 for b.
+ (pad (make-bytevector 4 0))
+ (bvB (make-bytevector 4 0)) (_b (bytevector-u8-set! bvB 0 7)))
+ (cg-emit-global cg s (list pad bvB))
+ (cg-fn-begin cg "main" '() %t-i32)
+ (cg-push-sym cg s) (cg-take-addr cg)
+ (cg-cast cg (%ctype 'ptr 8 8 %t-i32))
+ (cg-push-imm cg %t-i32 1)
+ (cg-binop cg 'add)
+ (cg-push-deref cg) (cg-load cg)
+ (cg-return cg)
+ (cg-fn-end cg)
+ (write-bv-fd 1 (cg-finish cg)))
diff --git a/tests/cc-parse/51-init-array-list.c b/tests/cc-parse/51-init-array-list.c
@@ -1,10 +1,8 @@
// tests/cc-parse/51-init-array-list.c — global int array initialised
// from element list. §E.3.
//
-// Array indexing (a[i]) and ptr+int arith inside expressions are owned
-// by other agents (§D, §K). To stay inside the available surface, we
-// just verify the first element by dereffing a manually-decayed
-// pointer.
-int a[3] = {7, 22, 99};
+// Array indexing (a[i]) is owned by Agent 2 (§D). Read each element
+// via a manually-decayed pointer and pointer arithmetic.
+int a[3] = {1, 2, 4};
int *p = a;
-int main(void) { return *p; }
+int main(void) { return *p + *(p + 1) + *(p + 2); }
diff --git a/tests/cc-parse/54-init-struct-desig.c b/tests/cc-parse/54-init-struct-desig.c
@@ -0,0 +1,10 @@
+// tests/cc-parse/54-init-struct-desig.c — designated struct init. §E.6.
+//
+// Read field b through pointer arithmetic; member-access codegen is
+// owned elsewhere (§D).
+struct S { int a; int b; };
+struct S s = { .b = 7 };
+int main(void) {
+ int *p = (int *)&s;
+ return *(p + 1);
+}
diff --git a/tests/cc-parse/54-init-struct-desig.expected-exit b/tests/cc-parse/54-init-struct-desig.expected-exit
@@ -0,0 +1 @@
+7