Understanding calling conventions passing closure from Swift to C++ and calling it from C++

Hello,

I have a Swift function like

extension Anything {
  @_extern(c, "XYZPerformWithCallback")
  static func performWithCallback(_ callback: () -> Void)
}

And in C++ it is implemented like this:

// XYZ_SWIFT_CC(swift) is the Swift calling convention.
#if __has_attribute(swiftcall)
#define XYZ_SWIFT_CC_swift __attribute__((swiftcall))
#define XYZ_SWIFT_CONTEXT __attribute__((swift_context))
#else
#define XYZ_SWIFT_CC_swift
#define XYZ_SWIFT_CONTEXT
#endif

void XYZPerformWithCallback(
  void (*callback)(const void *context XYZ_SWIFT_CONTEXT) XYZ_SWIFT_CC(swift),
  const void *context
) {
  callback(context);
}

This works perfectly fine. The Swift code calls the C++ function. The C++ function calls the callback and returns control to Swift.

But when I change the Swift function to be a global function instead of a static method, the C++ code crashes when trying to invoke the callback.

My question is, what is the difference? How can I understand this?

Is the presence of the Self variable changing what gets mapped to what register? If anything, I would expect the global function to work and the static method not to.

@_extern(c) is an unsupported feature, and I would recommend against using it. The mapping of Swift calling conventions to nonstandard Clang attributes like __attribute__((swiftcall)) is also not necessarily stable or reliable. If you want to implement something in C++, I would define it in C++, and then declare it in a C++ header file and import it into Swift that way.

1 Like

I am doing it this way because it lets me pass closures with captured variables.

I am assuming that this is plain unsupported then.