aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/CallGen.cc12
-rw-r--r--tests/i/extern-c-struct/expected.txt1
-rw-r--r--tests/i/extern-c-struct/notes.md2
-rw-r--r--tests/i/extern-c-struct/program.cps1
-rw-r--r--tests/iii/extern-variadic-type/case.json4
-rw-r--r--tests/iii/extern-variadic-type/notes.md4
-rw-r--r--tests/iii/extern-variadic-type/program.cps2
7 files changed, 22 insertions, 4 deletions
diff --git a/lib/CodeGen/CallGen.cc b/lib/CodeGen/CallGen.cc
index 576520d..4631332 100644
--- a/lib/CodeGen/CallGen.cc
+++ b/lib/CodeGen/CallGen.cc
@@ -133,7 +133,10 @@ bool CodeGen::marshalCallArgs(const FuncSig &Signature,
// C structs and pointers to them pass unchanged (C11 6.5.2.2p6-7, 7.16.1.1p2).
Value *CodeGen::emitVariadicArgument(ExprAST *Expr, const std::string &Callee, size_t Position,
const TypeInfo *&Promoted) {
- const TypeInfo *Info = isWholeArrayVar(Expr) ? nullptr : getExprTypeInfo(Expr);
+ ExprAST *Target = Expr;
+ auto *Addr = dynamic_cast<AddrOfExprAST *>(Expr);
+ if (Addr) Target = Addr->getTarget();
+ const TypeInfo *Info = isWholeArrayVar(Target) ? nullptr : getExprTypeInfo(Target);
const TypeInfo *Record = Types->pointerBase(Info);
std::string Why;
if (Record && Record->isRecord() && !Record->IsClass && !Types->isCStruct(Record, &Why)) {
@@ -145,6 +148,13 @@ Value *CodeGen::emitVariadicArgument(ExprAST *Expr, const std::string &Callee, s
reportError("Variadic argument %zu to %s must be a C value; cast it to a C type", Position, Callee.c_str());
return nullptr;
}
+ // ^x of a C value or C struct is a plain pointer, like C's f(n, &x).
+ if (Addr) {
+ LValueInfo LV;
+ if (!emitLValue(Target, LV)) return nullptr;
+ Promoted = Types->resolve("C_TYPE(\"void*\")");
+ return LV.Addr;
+ }
Promoted = Info;
Value *V = emitExpr(Expr);
if (!V || Info->Kind != TypeKind::CScalar) return V;
diff --git a/tests/i/extern-c-struct/expected.txt b/tests/i/extern-c-struct/expected.txt
index 816b4e3..04931ae 100644
--- a/tests/i/extern-c-struct/expected.txt
+++ b/tests/i/extern-c-struct/expected.txt
@@ -4,3 +4,4 @@ G 0.500000 7
14
3
G 9
+14
diff --git a/tests/i/extern-c-struct/notes.md b/tests/i/extern-c-struct/notes.md
index 494c510..b32bcc1 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. 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. N starts at 1. bump(^N) receives a PInt, an int * in C, and increments N to 2. Counter matches `struct Counter {int *}`; bump_counter(^C) increments through C.Target, which points to N, giving 3. get_shared(^R) receives a struct Sample ** and stores the address of the shared struct into R, so R^ shows tag G and the count 9 written earlier: `G 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. N starts at 1. bump(^N) receives a PInt, an int * in C, and increments N to 2. Counter matches `struct Counter {int *}`; bump_counter(^C) increments through C.Target, which points to N, giving 3. get_shared(^R) receives a struct Sample ** and stores the address of the shared struct into R, so R^ shows tag G and the count 9 written earlier: `G 9`. Finally sum_counts((C_INT)2, ^S, P) passes the address of S directly, like C's `&s`, together with P: 5 + 9 = 14.
diff --git a/tests/i/extern-c-struct/program.cps b/tests/i/extern-c-struct/program.cps
index 62370d3..210e10d 100644
--- a/tests/i/extern-c-struct/program.cps
+++ b/tests/i/extern-c-struct/program.cps
@@ -43,3 +43,4 @@ CALL bump_counter(^C)
OUTPUT N
CALL get_shared(^R)
OUTPUT R^.Tag, " ", R^.Count
+OUTPUT sum_counts((C_INT)2, ^S, P)
diff --git a/tests/iii/extern-variadic-type/case.json b/tests/iii/extern-variadic-type/case.json
index 45fea44..a114299 100644
--- a/tests/iii/extern-variadic-type/case.json
+++ b/tests/iii/extern-variadic-type/case.json
@@ -3,6 +3,10 @@
{
"reason": "Variadic\\ argument\\ 2\\ to\\ printf\\ must\\ be\\ a\\ C\\ value",
"line": 5
+ },
+ {
+ "reason": "Variadic\\ argument\\ 2\\ to\\ printf\\ must\\ be\\ a\\ C\\ value",
+ "line": 7
}
]
}
diff --git a/tests/iii/extern-variadic-type/notes.md b/tests/iii/extern-variadic-type/notes.md
index 3de1d69..73456b5 100644
--- a/tests/iii/extern-variadic-type/notes.md
+++ b/tests/iii/extern-variadic-type/notes.md
@@ -1,5 +1,5 @@
# extern-variadic-type
-Compiler extension: variadic EXTERN arguments must be C values; the INTEGER literal 1 is not cast.
+Compiler extension: variadic EXTERN arguments must be C values; the INTEGER literal 1 is not cast, and ^I points to an INTEGER rather than a C value.
-Require exit 1 and the cause on the call line.
+Require exit 1 and each cause on its call line.
diff --git a/tests/iii/extern-variadic-type/program.cps b/tests/iii/extern-variadic-type/program.cps
index 23f1fe9..0a967f3 100644
--- a/tests/iii/extern-variadic-type/program.cps
+++ b/tests/iii/extern-variadic-type/program.cps
@@ -3,3 +3,5 @@ INCLUDE_OBJ "__libc"
EXTERN "C" EXTERN_FUNCTION printf(C_STRING, ...) RETURNS C_INT
DECLARE N : C_INT
N <- printf((C_STRING)"%d", 1)
+DECLARE I : INTEGER
+N <- printf((C_STRING)"%p", ^I)