Why 'Never' cannot be represented in C?

While developing a pure Swift minimal standard library for use in Embedded WASM, I tried to create an exit function and got the 'Never' cannot be represented in C error for __builtin_trap :

@_cdecl("exit")
func exit(_ code: Uint) -> Never {
    //...
    __builtin_trap()
}

@_extern(c, "__builtin_trap")
private func __builtin_trap() -> Never

I know that I can achieve the same result using fatalError, but I wanted to take a similar approach to what is done in other C WASM standard libraries. I just wanted to clarify why we can call a Swift function returning Never from C, but cannot do the same thing from Swift?

Is it because Never is not standardized in C? If so, why doesn't @_cdecl have the same error?

Or is it just not accounted for in the Swift compiler, and Never simply needs to be added as a C-representable type?

C can't represent Never in it's type system, it instead represents a non-returning function using _Noreturn or, more recently, the [[noreturn]] attribute. While the compiler seems to be able to import _Noreturn functions from C as () -> Never functions, it looks like no one has added the reverse transformation.

I think it works if you use @c instead of @_extern(c), but you should probably not use a name that's reserved in C.

1 Like

I meant _Noreturn and __attribute__((noreturn)) when saying "returning Never on the C side".

If I create a header with a function using _Noreturn and __attribute__((noreturn)) on the C side, this function will be automatically converted to func ...() -> Never on the Swift side. If I import a target with this C header, that would be done automatically.

I am asking about manual definition, asking about direct usage of __builtin_trap() in Swift without wrapping functions in C headers.

Also, the @c attribute does not refer to export C symbols; it represents Swift functions in C. The @c attribute is analogous to @_cdecl , not @_extern(c) as you said, and it expects a function body.

The long and short of it is that Swift doesn't really support* forward declaring C symbols in Swift. If you need a forward declared symbol, you need to import it from a header file.

Also, I don't think __builtin_trap is a function anyway, so I don't think that forward declaration would work.

* forward declared Objective-C protocols & interfaces notwithstanding.