boot2

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

commit 632c4d8ec06b73f40521e0d8eca6db45250bee49
parent 75c2bc723023f8c895930d2c4855045d9eb8ed41
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sun, 26 Apr 2026 22:39:46 -0700

cc/parse: per-arg cast-or-promote in parse-call-args (§G.1, §K.5)

parse-call-args now inspects the callee's fn type:
- fixed-arg index: emits cg-cast to the declared param type, so an
  out-of-range int gets narrowed before the call (§K.5).
- variadic-arg index: emits cg-promote (§G.1) for default integer
  promotion of rank-below-int args.

call-fn-type peeks the vstack top to recover the callee's ctype,
walking through one ptr-to-fn level for function-pointer calls.

Diffstat:
Mcc/parse.scm | 61++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Atests/cc-parse/67-vararg-call.c | 22++++++++++++++++++++++
Atests/cc-parse/67-vararg-call.expected-exit | 1+
Atests/cc-parse/74-call-narrow.c | 6++++++
Atests/cc-parse/74-call-narrow.expected-exit | 1+
5 files changed, 84 insertions(+), 7 deletions(-)

diff --git a/cc/parse.scm b/cc/parse.scm @@ -906,7 +906,8 @@ (cg-push-deref (ps-cg ps)) (lp)) ((eq? v 'lparen) (advance ps) (rval-not-fn! ps) - (let ((n (parse-call-args ps))) + (let* ((fn-ty (call-fn-type (ps-cg ps))) + (n (parse-call-args ps fn-ty))) (expect-punct ps 'rparen) (cg-call (ps-cg ps) n #t) (lp))) @@ -936,15 +937,61 @@ (cg-assign (ps-cg ps)) (lp)) (else #t)))))))) -(define (parse-call-args ps) +;; call-fn-type cg -> ctype-or-#f +;; The function operand sits at the top of the vstack when +;; parse-call-args runs (just after rval-not-fn!). Its type may be +;; `fn` directly (named callee) or `ptr -> fn` (function pointer). +;; Returns the underlying `fn` ctype, or #f if the operand isn't +;; recognizably callable (callsite still works — no per-arg cast). +(define (call-fn-type cg) + (let* ((tp (cg-top cg))) + (cond + ((not tp) #f) + (else + (let* ((ty (opnd-type tp)) + (k (ctype-kind ty))) + (cond + ((eq? k 'fn) ty) + ((eq? k 'ptr) + (let ((pe (ctype-ext ty))) + (cond ((and pe (eq? (ctype-kind pe) 'fn)) pe) + (else #f)))) + (else #f))))))) + +;; param-types-of fn-ty -> (params variadic?) with a #f fallback. +(define (call-fn-param-info fn-ty) + (cond + ((not fn-ty) (cons '() #f)) + (else + (let ((ext (ctype-ext fn-ty))) + (cons (cadr ext) (car (cddr ext))))))) + +;; parse-call-args ps fn-ty -> arg-count +;; Casts each fixed arg to the declared param type (CC.md §K.5). +;; For variadic args (index >= named-arg count, when variadic? = #t) +;; applies cg-promote (CC.md §G.1). +(define (parse-call-args ps fn-ty) (cond ((at-punct? ps 'rparen) 0) (else - (let lp ((n 0)) - (parse-expr-bp ps 4) (rval! ps) - (let ((m (+ n 1))) - (cond ((at-punct? ps 'comma) (advance ps) (lp m)) - (else m))))))) + (let* ((info (call-fn-param-info fn-ty)) + (params (car info)) + (var? (cdr info)) + (nfix (length params))) + (let lp ((n 0) (rem params)) + (parse-expr-bp ps 4) (rval! ps) + (cond + ;; Fixed-arg: cast to declared param type. param entry shape + ;; is (name . ctype) per cg-fn-begin's contract. + ((not (null? rem)) + (cg-cast (ps-cg ps) (cdr (car rem)))) + ;; Variadic position (n >= nfix and var? is true): promote. + (var? + (cg-promote (ps-cg ps)))) + (let ((m (+ n 1)) + (rest (if (null? rem) '() (cdr rem)))) + (cond ((at-punct? ps 'comma) (advance ps) (lp m rest)) + (else m)))))))) (define (parse-primary ps) (let ((t (peek ps))) diff --git a/tests/cc-parse/67-vararg-call.c b/tests/cc-parse/67-vararg-call.c @@ -0,0 +1,22 @@ +/* §G.1 — variadic call: caller default-promotes args. + * + * Declares sum3 as (int n, ...). Defines a same-ABI sum3 that takes + * three ints. Calls sum3(1, c, s) where c is signed char = -3 and s + * is short = 100. Per default-promote rules, c and s are promoted to + * int before the call, so the callee's a1/a2 hold -3 and 100 with + * full 32-bit sign-extension. + * + * Result: 1 + (-3) + 100 = 98. + */ + +int sum3(int n, ...); + +int main(void) { + signed char c; short s; + c = -3; s = 100; + return sum3(1, c, s); /* 1 + (-3) + 100 = 98 */ +} + +int sum3(int n, int a, int b) { + return n + a + b; +} diff --git a/tests/cc-parse/67-vararg-call.expected-exit b/tests/cc-parse/67-vararg-call.expected-exit @@ -0,0 +1 @@ +98 diff --git a/tests/cc-parse/74-call-narrow.c b/tests/cc-parse/74-call-narrow.c @@ -0,0 +1,6 @@ +/* §K.5 — fixed-arg call argument is cast to declared param type. + * The callee declares (unsigned char x). Caller passes 258. The cast + * happens at the call site: 258 & 0xff = 2, so f returns 2. */ +int f(unsigned char x) { return x; } + +int main(void) { return f(258); } diff --git a/tests/cc-parse/74-call-narrow.expected-exit b/tests/cc-parse/74-call-narrow.expected-exit @@ -0,0 +1 @@ +2