diff options
| author | _ov4 <ov4@ov4.org> | 2026-10-22 13:27:15 +0000 |
|---|---|---|
| committer | _ov4 <ov4@ov4.org> | 2026-10-22 13:27:15 +0000 |
| commit | 4a70e44f06e637762eec0fd875eb94b84c3f4037 (patch) | |
| tree | b2771f76e3da335276a8c3e96ce70c2cfe99e088 /lib/CodeGen/FunctionGen.cc | |
| parent | eaad9c34403f05372c1544d7ef522c847dfea0ba (diff) | |
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 <noreply@anthropic.com>
Diffstat (limited to 'lib/CodeGen/FunctionGen.cc')
| -rw-r--r-- | lib/CodeGen/FunctionGen.cc | 27 |
1 files changed, 25 insertions, 2 deletions
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; |
