C ABI Interop¶
Accepted
Complete for V1 scalar source semantics; unsupported-signature diagnostics remain implementation verification work.
Catalyst's first external ABI target is C. V1 keeps the interop surface small and deterministic for scalar functions. It is not a complete foreign-function interface.
Declaration Attributes¶
C ABI interop uses declaration attributes:
@export(.c)
fn scale(sample: f32, amount: f32) f32 {
return sample * amount
}
@extern(.c)
@link_name("fabsf")
const fabs: *const @callconv(.c) fn(x: f32) f32
The .c arguments are enum-like cases completed by expected-type shorthand, not strings and not local identifiers. @callconv(.c) expects CallConv.c; @export(.c) and @extern(.c) expect InteropAbi.c.
Builtin or compiler-intrinsic expression syntax is deferred. @ is committed here as attribute syntax; builtin syntax should not casually reuse it unless that tradeoff is explicitly reopened.
V1 Meaning¶
V1 separates call ABI from symbol linkage:
@callconv(.c)sets the call ABI on a function declaration or function type expression.@export(.c)exports a Catalyst free function definition as a C symbol and implies@callconv(.c).@extern(.c)binds an external C symbol as aconstvalue.@link_name("...")overrides the external symbol name for@export(.c)or@extern(.c).
For V1, @export(.c) is valid only on free function definitions with bodies:
@export(.c)
fn scale(sample: f32, amount: f32) f32 {
return sample * amount
}
It exports the definition as an external C ABI symbol, uses the C calling convention, defaults the symbol name to the Catalyst function name, and requires a C-ABI-safe parameter and return signature.
@callconv(.c) alone does not export or import anything:
@callconv(.c)
fn local_c_abi_helper(x: i32) i32 {
return x
}
This function has C call ABI but no external linkage.
C Imports¶
C function imports are source-level external symbol bindings. In Catalyst V1, they are represented as const values with function pointer type:
@extern(.c)
@link_name("fabsf")
const fabs: *const @callconv(.c) fn(x: f32) f32
@extern(.c) is valid only on const declarations in V1. For C function imports, the const type must be an explicit function pointer whose pointee function type has @callconv(.c). The pointee function signature must use V1 C-ABI-safe types.
This is invalid because @extern(.c) does not mutate the declared type:
@extern(.c)
const fabs: *const fn(x: f32) f32 // invalid
Imported function pointer consts are called with normal function pointer call syntax:
var y = fabs(-1.0)
Bodyless C-like function declarations are deferred because they would add a special declaration form:
@extern(.c)
fn fabsf(x: f32) f32 // deferred
Symbol Names¶
The default exported C symbol name is the Catalyst function name:
@export(.c)
fn scale_f32(sample: f32, amount: f32) f32 {
return sample * amount
}
exports:
Rules:
- exported names are unmangled
- default export names and default extern names must be portable ASCII C identifiers:
[_A-Za-z][_A-Za-z0-9]* @export(.c)defaults to the function name@extern(.c)defaults to the const binding name@link_name("...")sets the exact external symbol name
@link_name requires @export(.c) or @extern(.c) in V1. It is invalid with @callconv alone.
Duplicate C link names are checked within the visible linkage set:
- duplicate exported link names are hard errors
- duplicate visible imports with the same link name and same type are allowed but lintable as
interop/duplicate-import - duplicate visible imports with the same link name and incompatible types are hard errors
Visibility¶
@export(.c) controls C ABI visibility. It is separate from Catalyst module visibility.
Plain functions are internal/private to generated C by default:
fn helper(x: f32) f32 {
return x * x
}
@export(.c)
fn scale(sample: f32, amount: f32) f32 {
return helper(sample) * amount
}
The C backend direction is:
Internal symbol naming is backend-defined but must be deterministic. Future pub module visibility must not imply C export by itself.
ABI-Safe Types¶
V1 C function signatures support only the V1 scalar core types:
voidbooli32f32
Catalyst error-return types are not C-ABI-safe in V1:
@export(.c)
fn load(path: Path) Module!LoadError // invalid for v1 C export
This rejection applies to every V1 C ABI signature validation path, including @export(.c) declarations, @extern(.c) function pointer types, and function declarations or function type expressions marked with @callconv(.c). Inference may resolve first, but any resolved T!E in a C ABI signature is a hard ABI-safety error.
The C representation for T!E should be designed deliberately later, for example through explicit result structs or out-parameters. Broader ABI-safe type expansion is deferred to CEP-0007: C ABI Compound Types and Error Returns. Each type must have a deliberate ABI mapping before becoming export-safe.
ABI Inference¶
@export(.c) functions follow normal Catalyst function inference rules. The compiler should not introduce special cases that forbid inference only because a function is exported.
However, exported ABI is a public contract. First-class linting should warn when an exported C ABI signature relies on inferred parameter, return, or error facts.
Example lint:
Phase Contract¶
Attributes are parsed as source-preserved metadata. Sema resolves and evaluates the attribute provider, then validates the resulting ABI/export facts and ABI-safe signatures.
Resolved ABI, import, export, and link-name facts must be carried into SIR and IR before backend emission. The C backend consumes backend-facing facts such as:
- calling convention
- linkage status
- external symbol name
- ABI-safe lowered types
The C backend must not inspect AST attributes or rerun semantic ABI checks.
Future Decisions¶
Deferred:
- generated C headers
- named attribute arguments
- additional ABI cases beyond
.c std.cprimitive aliases and C layout profiles, tracked by CEP-0063: Representation Modes and C Layout- exported methods
- exported generic specializations
- non-function-pointer imports
- C-compatible structs, pointers, arrays, and slices, tracked by CEP-0007: C ABI Compound Types and Error Returns
- exact C representation for Catalyst error returns, tracked by CEP-0007: C ABI Compound Types and Error Returns
- full linker/visibility model