From 4a70e44f06e637762eec0fd875eb94b84c3f4037 Mon Sep 17 00:00:00 2001 From: _ov4 Date: Thu, 22 Oct 2026 13:27:15 +0000 Subject: feat(codegen): accept pointers to C-struct records in EXTERN signatures A TYPE record whose fields are all C types, C structs or pointer types to C structs now crosses the EXTERN "C" boundary through a pointer type. Records by value are rejected for now, and a pointer to a record with a non-C field names that field. Co-Authored-By: Claude Opus 5.5 --- lib/CodeGen/FunctionGen.cc | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'lib/CodeGen/FunctionGen.cc') diff --git a/lib/CodeGen/FunctionGen.cc b/lib/CodeGen/FunctionGen.cc index 04f6a84..1cbf19f 100644 --- a/lib/CodeGen/FunctionGen.cc +++ b/lib/CodeGen/FunctionGen.cc @@ -298,6 +298,26 @@ bool FunctionGen::emitExternPrototype(PrototypeAST *Proto) { return Info->CSigned ? Attribute::SExt : Attribute::ZExt; }; + // Records cross the C boundary only as C structs, for now through a + // pointer type. What names the parameter or return type in diagnostics. + auto CheckRecord = [&](const TypeInfo *Info, const std::string &What) { + const TypeInfo *Record = Info->Kind == TypeKind::Pointer + ? Types.resolve(Info->Pointer.PointeeTypeName) : Info; + if (!Record || !Record->isRecord() || Record->IsClass) return true; + std::string Why; + if (!Types.isCStruct(Record, &Why)) { + reportError("%s uses record %s, which is not a C struct: %s", What.c_str(), + Record->Name.c_str(), Why.c_str()); + return false; + } + if (Record == Info) { + reportError("%s cannot be record %s by value; use a pointer type to it", What.c_str(), + Record->Name.c_str()); + return false; + } + return true; + }; + FuncSig Sig; Sig.OwnerUnit = CurrentUnit; Sig.Name = Name; @@ -317,7 +337,9 @@ bool FunctionGen::emitExternPrototype(PrototypeAST *Proto) { reportError("Unknown type %s", P.TypeName.c_str()); return false; } - if (!Info->isC() || Info->isVoid()) { + if (!CheckRecord(Info, "EXTERN parameter " + std::to_string(I + 1) + " of " + Name)) + return false; + if (!Types.isExternType(Info)) { reportError("EXTERN parameter %zu of %s must be a non-void C type (got %s)", I + 1, Name.c_str(), P.TypeName.c_str()); return false; @@ -337,7 +359,8 @@ bool FunctionGen::emitExternPrototype(PrototypeAST *Proto) { reportError("Unknown type %s", Proto->getReturnType().c_str()); return false; } - if (!Info->isC() || Info->isVoid()) { + if (!CheckRecord(Info, "The return type of EXTERN_FUNCTION " + Name)) return false; + if (!Types.isExternType(Info)) { reportError("EXTERN_FUNCTION %s must return a non-void C type (got %s)", Name.c_str(), Proto->getReturnType().c_str()); return false; -- cgit v1.3.1-4-g156e