Lyricdev
GitHub

LYR-SEM0099

an extern declaration that cannot cross into C

error · spec 13-abi

An extern function names an ABI other than "C", a symbol that is no C name, type parameters, throws, a place parameter, or a parameter or return type that does not cross into C; a bare ... with no parameter before it, or a variadic argument of a type that does not cross; a C function type, extern "C" fn(…), whose parameters or result do not cross, that throws, or that names another ABI; a Callback whose type is no C function's, or has no userdata Ptr<void> as its first or last parameter; a GcHandle of a value that is no object of a class; @Layout stands where C cannot lay the type out, or in another form than @Layout(C) or an integer type; or a variant is given an integer outside an enum with @Layout, one that is no integer literal, one its integer type does not hold, or one another variant already is.

Explanation

Lyric 5's one foreign boundary is C. Integers, floats, bool and char cross it (and void as a return); std.ffi's Ptr<T> and CStr cross as C's pointers, ?Ptr<T> and ?CStr as pointers that may be null; a struct with @Layout(C) crosses as C's struct, by value — a pointer field may be ?Ptr<T> or ?CStr, one word as C's —, and an enum with @Layout as its integer, each variant the integer written after = or one more than the variant before. A string argument crosses into a CStr parameter as its bytes. Classes, arrays, other optionals, places, generics and thrown errors do not, so a declaration nobody could bind is refused where it stands, whether or not it is called.

Declare the C function with types that cross, and convert at the Lyric side.

Wrong

extern "C" fn shout(s: string): int;

fn main(): void {
    let _ = shout("hi");
}
import std.ffi { CStr };

extern "C" fn shout(s: CStr): int;

fn main(): void {
    let _ = shout("hi");
}