commit 0ca5b9881732695ee428b3551659bd9512643549
parent f462972eb40f81e1508ef135a24a8692309ca16f
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sun, 26 Apr 2026 22:46:42 -0700
docs/CC-PUNCHLIST: mark §B + §C + §H + §K.1 as green
Updates each item with the fixture filenames and a short note on
the implementation choice. Replaces the §B "Pick one fix" preamble
with the chosen design (cg-dup + cg-postinc/postdec) and the §H
preamble with the cg-ifelse-merge contract.
Diffstat:
| M | docs/CC-PUNCHLIST.md | | | 148 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
1 file changed, 78 insertions(+), 70 deletions(-)
diff --git a/docs/CC-PUNCHLIST.md b/docs/CC-PUNCHLIST.md
@@ -91,56 +91,59 @@ upstream of nearly everything else. Land this first.
### B. Lvalue mechanics
-`cg-take-addr` does not preserve the original lval, so any operation
-that needs to *use* an lvalue twice (compound assign, inc/dec) is
-broken. Pick one fix and document it in
-[CC-CONTRACTS §4.1](CC-CONTRACTS.md#41-parsers-responsibilities) row
-"`lhs += rhs`":
-
-- (a) `cg-take-addr` leaves `[orig-lval, ptr-rval]`; or
-- (b) introduce `cg-dup` (duplicate top vstack entry).
-
-- [ ] **Pre-`++` / pre-`--`**
- - cg: `cc-cg/NN-preinc.scm` — `int x = 5; ++x; return x;` → exit 6.
- - parse: `cc-parse/NN-preinc.c`
- - Needs: lhs preservation per above.
-
-- [ ] **Post-`++` / post-`--` returns old value**
- - cg: `cc-cg/NN-postinc.scm` — `int x=5; int y=x++; return x*10+y;`
+Picked **(b) `cg-dup`** — duplicate the top vstack entry, used for
+compound assign and pre-inc/dec to keep the lhs lval available across
+its own load. Post-inc/dec use a dedicated `cg-postinc` / `cg-postdec`
+primitive to capture the old rval before the store. See
+[CC-CONTRACTS §4.1](CC-CONTRACTS.md#41-parsers-responsibilities).
+
+- [x] **Pre-`++` / pre-`--`**
+ - cg: `cc-cg/21-preinc.scm` — `int x = 5; ++x; return x;` → exit 6.
+ - parse: `cc-parse/21-preinc.c`
+ - Done: parser dups lhs lval, loads, +1, assigns; pops result.
+
+- [x] **Post-`++` / post-`--` returns old value**
+ - cg: `cc-cg/22-postinc.scm` — `int x=5; int y=x++; return x*10+y;`
→ exit 65.
- - parse: `cc-parse/NN-postinc.c`
- - Needs: `cg-postinc` / `cg-postdec`, or parser uses `cg-dup` to
- keep the old rval before the store.
-
-- [ ] **Compound assignment on simple lval (`+= -= *= /= %= <<= >>= &= ^= |=`)**
- - cg: `cc-cg/NN-cmpd-simple.scm` — `int x=7; x+=3; return x;` → exit 10.
- - parse: `cc-parse/NN-cmpd-simple.c` — one fixture per op family is
- fine; the cg primitives are shared.
- - Needs: same lhs preservation; existing parser sequence (take-addr,
- push-deref, load, rhs, arith-conv, binop, assign) works once
- preservation is in.
-
-- [ ] **Compound assignment through pointer**
- - cg: `cc-cg/NN-cmpd-ptr.scm` — `int x=7; int *p=&x; *p+=3; return x;`
- - parse: `cc-parse/NN-cmpd-ptr.c`
- - Needs: validates the indirect-slot path in `cg-assign`.
-
-- [ ] **`*p++` walking an array**
- - cg: `cc-cg/NN-deref-postinc.scm` — sums a 3-element array.
- - parse: `cc-parse/NN-deref-postinc.c`
- - Needs: composes B above with pointer arithmetic scaling.
+ - parse: `cc-parse/22-postinc.c`
+ - Done: `cg-postinc` / `cg-postdec` primitives composed of two
+ dup+load passes — one to capture the old rval (which lives in a
+ never-reused spill slot), one to compute the +1/-1 store.
+
+- [x] **Compound assignment on simple lval (`+= -= *= /= %= <<= >>= &= ^= |=`)**
+ - cg: `cc-cg/23-cmpd-simple.scm` — `int x=7; x+=3; return x;` → exit 10.
+ - parse: `cc-parse/23-cmpd-simple.c` — one of every op family.
+ - Done: parser uses `cg-dup` + `cg-load` + rhs + arith-conv + binop +
+ assign; the `cg-take-addr`/`cg-push-deref` indirection is gone.
+
+- [x] **Compound assignment through pointer**
+ - cg: `cc-cg/24-cmpd-ptr.scm` — `int x=7; int *p=&x; *p+=3; return x;`
+ - parse: `cc-parse/24-cmpd-ptr.c`
+ - Done: same parser sequence; `cg-push-deref`'s indirect-slot lval
+ composes correctly with `cg-dup` + `cg-assign`.
+
+- [x] **`*p++` walking an array**
+ - cg: `cc-cg/25-deref-postinc.scm` — walks a 3-element span via *p++.
+ - parse: `cc-parse/25-deref-postinc.c`
+ - Done: composes B.2 (post-inc on a ptr lval; pointer scaling falls
+ out of `cg-binop add`'s ptr branch) with `*p` deref. Also fixed
+ `cg-arith-conv` to skip the relabel when one operand is ptr/arr
+ so `cg-binop` still sees a ptr/int pair (previously it saw both
+ sides relabelled to ptr and skipped the scaling).
### C. `sizeof`
-- [ ] **`sizeof e` returns the type's actual size**
- - parse: `cc-parse/NN-sizeof-expr.c` — `int x; return sizeof x;` → 4.
- - Needs: parser peeks `(opnd-type (cg-top …))`, computes size, pops,
- pushes `imm u64 size`. Today returns 8 always
- (`parse.scm` line ~836).
+- [x] **`sizeof e` returns the type's actual size**
+ - parse: `cc-parse/26-sizeof-expr.c` — `int x; return sizeof x;` → 4.
+ - Done: parser peeks `(opnd-type (cg-top …))`, takes its
+ `ctype-size`, pops, pushes `imm u64 size`. Both forms
+ (`sizeof e` and `sizeof(e)`) updated.
-- [ ] **`sizeof` over struct, array, pointer, char**
- - parse: `cc-parse/NN-sizeof-types.c` — sum of representative sizes
- against a known integer.
+- [x] **`sizeof` over struct, array, pointer, char**
+ - parse: `cc-parse/27-sizeof-types.c` — sum of `char`, `short`,
+ `int`, `long`, `int*`, `int[5]`, `struct S{int a; int b;}` → 51.
+ - Done: the type form already returned `ctype-size ty`; this
+ fixture just locks the answer in.
### D. Aggregates
@@ -273,26 +276,31 @@ accepts an init bv but is never given one.
### H. Conditionals as values
-`cg-ifelse` is correct for `if`-statements (thunks push nothing) but
-leaks two opnds when both thunks push (ternary, `&&`, `||`). The fix
-is a result-merging primitive: caller pre-allocates the result slot,
-both branches store into it, vstack ends with one frame opnd.
-
-- [ ] **Ternary `?:` leaves exactly one rval**
- - cg: `cc-cg/NN-ternary.scm` — `int x = c ? 1 : 2; return x;` → exit 1.
- - parse: `cc-parse/NN-ternary.c`
- - Needs: result-merging primitive (`cg-ifelse-merge` or similar);
- parser passes the result type, cg allocates the slot.
-
-- [ ] **`&&` short-circuit leaves exactly one i32 rval**
- - cg: `cc-cg/NN-land.scm`
- - parse: `cc-parse/NN-land.c`
- - Needs: same merging primitive; result type is `%t-i32`
- irrespective of operands.
-
-- [ ] **`||` short-circuit leaves exactly one i32 rval**
- - cg: `cc-cg/NN-lor.scm`
- - parse: `cc-parse/NN-lor.c`
+Added `cg-ifelse-merge`: caller pre-allocates the result slot, each
+thunk pushes one rval that is then loaded and stored into the slot,
+and the slot's frame rval is left on the vstack. The merged result
+type is taken from the first thunk's pushed type — parser is
+responsible for arranging compatible types in the two branches.
+
+- [x] **Ternary `?:` leaves exactly one rval**
+ - cg: `cc-cg/28-ternary.scm` — `c ? 7 : 9` with c=1 → exit 7.
+ - parse: `cc-parse/28-ternary.c`
+ - Done: parser swaps `cg-ifelse` for `cg-ifelse-merge` in the
+ `qmark` arm of `parse-binary-rhs`; both branches push their
+ parsed rval directly.
+
+- [x] **`&&` short-circuit leaves exactly one i32 rval**
+ - cg: `cc-cg/29-land.scm`
+ - parse: `cc-parse/29-land.c`
+ - Done: parser injects `cg-cast %t-bool` then `cg-cast %t-i32` on
+ the rhs side so the merged result is i32 ∈ {0,1}; the else-arm
+ pushes `%t-i32 0`.
+
+- [x] **`||` short-circuit leaves exactly one i32 rval**
+ - cg: `cc-cg/30-lor.scm`
+ - parse: `cc-parse/30-lor.c`
+ - Done: mirrors §H.2 with the bool-cast on the else-arm and a
+ constant `%t-i32 1` in the then-arm.
### I. Storage classes
@@ -323,12 +331,12 @@ both branches store into it, vstack ends with one frame opnd.
### K. Expressions and conversions
-- [ ] **Comma operator (`a, b` as expression)**
- - parse: `cc-parse/NN-comma.c` — `int a; int b; (a=1, b=2); return a + b*10;`
+- [x] **Comma operator (`a, b` as expression)**
+ - parse: `cc-parse/31-comma.c` — `int a; int b; (a=1, b=2); return a + b*10;`
→ exit 21.
- - Needs: add `comma` to `%binop-bp` at lowest precedence, left-assoc.
- Handler discards lhs (`cg-pop`) before evaluating rhs. tcc.c uses
- this in `for` headers.
+ - Done: added `(comma . (1 . 2))` to `%binop-bp` (left-assoc, below
+ `assign`'s 4/3 so `parse-call-args ps 4` still won't slurp it as a
+ call separator); handler `cg-pop`s the lhs and evaluates the rhs.
- [ ] **Function-pointer call**
- cg: `cc-cg/NN-fnptr-call.scm` — push a fn-typed sym, spill to a