diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-22 13:30:00 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-22 13:30:00 +0000 |
| commit | 90bf56f456e22dcd98458eca14e0b152a5efb179 (patch) | |
| tree | 629f46a15ea13d1d71998355f00d77d5c80052a3 | |
| parent | 4a70e44f06e637762eec0fd875eb94b84c3f4037 (diff) | |
feat(codegen): accept record pointers as variadic arguments
Pointer types to C-struct records now pass unchanged as variadic EXTERN
arguments. Pseudocode values still need a cast to a C type, and records
by value stay rejected.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | lib/CodeGen/CallGen.cc | 3 | ||||
| -rw-r--r-- | tests/i/extern-c-struct/expected.txt | 1 | ||||
| -rw-r--r-- | tests/i/extern-c-struct/lib.c | 12 | ||||
| -rw-r--r-- | tests/i/extern-c-struct/notes.md | 2 | ||||
| -rw-r--r-- | tests/i/extern-c-struct/program.cps | 4 |
5 files changed, 20 insertions, 2 deletions
diff --git a/lib/CodeGen/CallGen.cc b/lib/CodeGen/CallGen.cc index dfe89d6..b25ca12 100644 --- a/lib/CodeGen/CallGen.cc +++ b/lib/CodeGen/CallGen.cc @@ -128,7 +128,8 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature, // C values are accepted, matching the explicit-cast rule for C/pseudocode. Value *CodeGen::emitVariadicArgument(ExprAST *Expr, const std::string &Callee, size_t Position) { const TypeInfo *Info = isWholeArrayVar(Expr) ? nullptr : getExprTypeInfo(Expr); - if (!Info || !Info->isC() || Info->isVoid()) { + // Pointers to C structs pass unchanged; records by value are not supported yet. + if (!Info || Info->isRecord() || !Types->isExternType(Info)) { reportError("Variadic argument %zu to %s must be a C value; cast it to a C type", Position, Callee.c_str()); return nullptr; } diff --git a/tests/i/extern-c-struct/expected.txt b/tests/i/extern-c-struct/expected.txt index 62e50ed..dee8467 100644 --- a/tests/i/extern-c-struct/expected.txt +++ b/tests/i/extern-c-struct/expected.txt @@ -1,3 +1,4 @@ S 4.500000 5 G 0.500000 7 9 +14 diff --git a/tests/i/extern-c-struct/lib.c b/tests/i/extern-c-struct/lib.c index 39380ec..65080f1 100644 --- a/tests/i/extern-c-struct/lib.c +++ b/tests/i/extern-c-struct/lib.c @@ -1,3 +1,5 @@ +#include <stdarg.h> + struct Sample { char tag; double value; @@ -9,3 +11,13 @@ static struct Sample shared = {'G', 0.5, 7}; void scale_sample(struct Sample *s, int k) { s->value *= k; } struct Sample *shared_sample(void) { return &shared; } int shared_count(void) { return shared.count; } + +/* Each argument after n is a struct Sample *, read back with va_arg. */ +int sum_counts(int n, ...) { + va_list ap; + int total = 0; + va_start(ap, n); + for (int i = 0; i < n; ++i) total += va_arg(ap, struct Sample *)->count; + va_end(ap); + return total; +} diff --git a/tests/i/extern-c-struct/notes.md b/tests/i/extern-c-struct/notes.md index 1a0d215..519e835 100644 --- a/tests/i/extern-c-struct/notes.md +++ b/tests/i/extern-c-struct/notes.md @@ -4,4 +4,4 @@ Human review: pending. Expected output was independently traced by AI, not captu Basis: compiler extension (EXTERN "C", INCLUDE_OBJ of a user object); a record whose fields are all C types has the layout of the matching C struct. -Trace: the harness compiles `lib.c` with the host C compiler. Sample matches `struct Sample {char; double; int}`, including the padding after the char. S is 'S', 1.5, 5. scale_sample(^S, 3) multiplies the value through the pointer to 4.5 and leaves tag and count alone, so the first line is `S 4.500000 5`. shared_sample returns the address of the static struct in lib.c, initialised to 'G', 0.5, 7, giving `G 0.500000 7`. P^.Count <- 9 writes through that pointer into the C object, so shared_count() returns 9. +Trace: the harness compiles `lib.c` with the host C compiler. Sample matches `struct Sample {char; double; int}`, including the padding after the char. S is 'S', 1.5, 5. scale_sample(^S, 3) multiplies the value through the pointer to 4.5 and leaves tag and count alone, so the first line is `S 4.500000 5`. shared_sample returns the address of the static struct in lib.c, initialised to 'G', 0.5, 7, giving `G 0.500000 7`. P^.Count <- 9 writes through that pointer into the C object, so shared_count() returns 9. sum_counts receives P and Q as variadic arguments; pointers are passed unchanged and read back with va_arg(ap, struct Sample *). P points to the shared struct, whose count is now 9, and Q points to S, whose count is 5, so the last line is 9 + 5 = 14. diff --git a/tests/i/extern-c-struct/program.cps b/tests/i/extern-c-struct/program.cps index 1954d29..bcb7af4 100644 --- a/tests/i/extern-c-struct/program.cps +++ b/tests/i/extern-c-struct/program.cps @@ -9,8 +9,10 @@ TYPE PSample = ^Sample EXTERN "C" EXTERN_PROCEDURE scale_sample(PSample, C_INT) EXTERN "C" EXTERN_FUNCTION shared_sample() RETURNS PSample EXTERN "C" EXTERN_FUNCTION shared_count() RETURNS C_INT +EXTERN "C" EXTERN_FUNCTION sum_counts(C_INT, ...) RETURNS C_INT DECLARE S : Sample DECLARE P : PSample +DECLARE Q : PSample S.Tag <- (C_CHAR)'S' S.Value <- (C_DOUBLE)1.5 S.Count <- (C_INT)5 @@ -20,3 +22,5 @@ P <- shared_sample() OUTPUT P^.Tag, " ", P^.Value, " ", P^.Count P^.Count <- (C_INT)9 OUTPUT shared_count() +Q <- ^S +OUTPUT sum_counts((C_INT)2, P, Q) |
