`@convention(thin)` function pointers

Yeah, all of the existing attributes for exporting symbols to various FFI are different in very subtle ways, which I believe are the following:

  1. func f() without attributes:

    • Symbols emitted into binary: One—a normal Swift function named with the mangling of f.
    • Decls in generated header: N/A without C++ interop. With C++ interop, an inline trampoline function named module_name::f is printed that calls the Swift f.
    • Swift visibility for which decls are generated in the header: public
  2. @_silgen_name("g") func f()

    • Symbols emitted into binary: One—a normal Swift function, but named g instead of the mangling of f.
    • Decls in generated header: Same as #1.
    • Swift visibility for which decls are generated in the header: Same as #1.
  3. @_cdecl("g") func f()

    • Symbols emitted into binary: Two—a normal Swift function named with the mangling of f, and a trampoline C function g that calls f.
    • Decls in generated header: An extern "C" function declaration for the trampoline is printed. If C++ interop is enabled, a C++ inline trampoline is also printed, but it looks like it invokes the C trampoline instead of the Swift symbol? (generated header in output window)
    • Swift visibility for which decls are generated in the header: public, internal
  4. @_expose(Cxx, "g") func f()

    • Symbols emitted into binary: One—a normal Swift function named with the mangling of f.
    • Decls in generated header: N/A without C++ interop. With C++ interop, an inline trampoline function named module_name::g is printed that calls the Swift f.
    • Swift visibility for which decls are generated in the header: public
  5. @objc(g) func f() (where f is a method in a class):

    • Symbols emitted into binary: Two—a normal Swift function named with the mangling of f, and a trampoline Obj-C method named g that calls f.
    • Decls in generated header: An Objective-C method decl for the trampoline g is printed.
    • Swift visibility for which decls are generated in the header: public, internal

So I agree that there's a bit of a spectrum here; @_silgen_name affects the name of the original symbol, @_cdecl and @objc leave the original symbol alone and introduce a new one for external clients, and @_expose(Cxx, ...) only affects the generated header.

I don't think that's a reason to avoid unifying these concepts altogether (although the ship has already sailed for @objc, which is both officially supported and very widely used). If we claim that @symbolName (or whatever it's called) "defines the name that foreign languages interact with a symbol", then I think we could argue that @_cdecl and @_expose(Cxx, ...) fit that description even if C++ interop doesn't require it, and I'd feel comfortable saying that @symbolName(swift, ...) is defining the name that foreign languages (or a foreign process via dladdr) which aren't using Swift's C++ interop use to interact with a function that still uses a Swift calling convention, since those may be the only times you'd want to rename the Swift symbol. (I suppose maintaining ABI compatibility while renaming an API is another one.)

13 Likes