SWIFT_SHARED_REFERENCE signature error

Oddly I am seeing this issue on a GitHub runner, but not locally. Perhaps it's something to do with clang versions; I can confirm that when it compiles successfully locally, <swift/bridging> is present (see guard below) and __has_attribute(swift_attr) evaluates to TRUE. Both local and runner configurations are using Swift 6.0.2 on x86_64.

Anyway, my question is: as I understand it, the the retain/release functions take a pointer to the type, not the type itself?

The code in question:

#if __has_include(<swift/bridging>)
#include <swift/bridging>
#else
#define SWIFT_SHARED_REFERENCE(_retain, _release)
#endif

struct FlutterDesktopMessenger {
  FlutterDesktopMessenger() = default;
...
} SWIFT_SHARED_REFERENCE(FlutterDesktopMessengerAddRef,
                         FlutterDesktopMessengerRelease);

typedef struct FlutterDesktopMessenger* FlutterDesktopMessengerRef;

FLUTTER_EXPORT FlutterDesktopMessengerRef
FlutterDesktopMessengerAddRef(FlutterDesktopMessengerRef messenger);
FLUTTER_EXPORT void FlutterDesktopMessengerRelease(
    FlutterDesktopMessengerRef messenger);

The error:

/__w/FlutterSwift/FlutterSwift/Sources/CxxFlutterSwift/flutter-embedded-linux/src/flutter/shell/platform/linux_embedded/flutter_elinux_state.h:50:8: error: specified retain function 'FlutterDesktopMessengerAddRef' is invalid; retain function must have exactly one argument of type 'FlutterDesktopMessenger'
48 | // Wrapper to distinguish the messenger ref from the engine ref given out
49 | // in the C API.
50 | struct FlutterDesktopMessenger {
   |        `- error: specified retain function 'FlutterDesktopMessengerAddRef' is invalid; retain function must have exactly one argument of type 'FlutterDesktopMessenger'
51 |   FlutterDesktopMessenger() = default;
52 | 
1 Like

Is your retain function of type

FLUTTER_EXPORT void FlutterDesktopMessengerAddRef(FlutterDesktopMessengerRef messenger);

Yes, pasted the prototype of both retain/release in OP.

Your retain function should be a function taking a pointer to the reference type as parameter & returning void like this

FLUTTER_EXPORT void FlutterDesktopMessengerAddRef(FlutterDesktopMessengerRef messenger);

not this

FLUTTER_EXPORT FlutterDesktopMessengerRef
FlutterDesktopMessengerAddRef(FlutterDesktopMessengerRef messenger);

Both examples above are the same?

Also note from OP:

typedef struct FlutterDesktopMessenger* FlutterDesktopMessengerRef;

Are you saying the retain/release functions should take a ref param instead of a pointer?

No they are not the same one is returning void & the other is returning a pointer to FlutterDesktopMessenger

Whoops. Gotcha. Sorry for brain fart!

It would actually be nice if the compiler would accept both, as it’s a common pattern to want to chain something to a retain, but I’ll look into that separately.

1 Like

I'll prepare a compiler PR to allow the retain function to return the same argument as the parameter, as an alternative to void.

1 Like

You can cite CFRetain as prior art for that, even!

Ha, indeed! I mean, this dates back to pre-ARC Foundation where the chaining was quite syntactically convenient in Objective-C. I remember using Foundation with Portable Distributed Objects in the mid-90s. I am old :)

My rationale in this case is that I managed to sneak in SWIFT_SHARED_REFERENCE into a third-party dependency but I very much doubt they'd accept a patch that changed the signature of their existing retain function.

1 Like

From memory returning self was rife in the pre-Foundation Objective-C days (for chaining convenience), but NeXT's advice changed when Distributed Objects was introduced: if you didn't need to return anything useful, you could avoid a half-round-trip with oneway void.

I don't so because a retain or release function should only perform retain or release operations on an already existing reference and not returning a new reference every time the retain or release functions are called

I see where you're coming from, it's a convenience (for which as @jrose points out) there is precedent in CoreFoundation and Objective-C. I'll submit a PR and the maintainers can decide whether or not to accept it.

If you think in terms of retain counts, it’s a convenience (and one that can save code size, not just a for-humans thing), if you think in terms of references-as-independent-values it’s the only signature that makes sense (like std::shared_ptr in C++ or Arc in Rust). Not returning anything is actually weirder.

NB: I am not a compiler engineer, there are probably low-hanging-fruit mistakes in this.

1 Like