From 0f39fc55c93bd0e9d53f42feb845524d2d9dfcd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tor=20Arne=20Vestb=C3=B8?= Date: Mon, 16 Aug 2021 17:04:08 +0200 Subject: [PATCH] Forward declare Objective-C classes as class, not typedef objc_object Forward declaring an Objective-C class in Objective-C/C++ mode is done by using the `@class` syntax, e.g.: @class NSString; In C/C++ mode however there's no documented approach, so we chose to flatten the type down to the opaque objc_object "base class": typedef struct objc_object NSString; As it turns out, when Objective-C classes are used as arguments or return types in C++, the signature they produce is equal to what it would have been if the type was a normal class. For example: void foo(NSString *) -> __Z3fooP8NSString The is due to @class in Objective-C++ just being just sugar, so an NSString pointer is not treated as `struct objc_object *` but rather a pointer to a distinct type, which then gets mangled as such by LLVM's Itanium mangler in CXXNameMangler::mangleType(const ObjCObjectType *T). With our current forward declaration however, we are expecting: void foo(NSString *) -> __Z3fooP11objc_object As a consequence exported helper functions such as QString::fromNSString() are not possible to use from plain C++ right now, as it will give a linker error for the missing QString::fromNSString(objc_object*) function. And even if we did define the extra signature, it would not be possible to declare overloaded functions taking Objective-C classes, as they would all produce ambiguous overloads in C++ mode. To fix this we change the forward declaration to a plain old class, which matches the signature in both Objective-C++ and plain C++ mode, and allows overloads. This is a binary compatible change, as no client were using any of these functions from C++ anyways as they would have produced linker errors. It does have a slight source compatible break, for clients that manually forward declared classes using the old style, but that use-case is deemed fringe enough to accept, and clients can work around this by defining Q_FORWARD_DECLARE_OBJC_CLASS to their preferred format, which Qt will respect. Pick-to: 6.2 Change-Id: I04813c60a7da22379dd9de1be56cc12c53a38232 Reviewed-by: Lars Knoll --- src/corelib/global/qglobal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index e2dc919e26f..6467ba19848 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -859,7 +859,7 @@ constexpr inline QTypeTraits::Promoted qBound(const U &min, const T &val, # ifdef __OBJC__ # define Q_FORWARD_DECLARE_OBJC_CLASS(classname) @class classname # else -# define Q_FORWARD_DECLARE_OBJC_CLASS(classname) typedef struct objc_object classname +# define Q_FORWARD_DECLARE_OBJC_CLASS(classname) class classname # endif #endif #ifndef Q_FORWARD_DECLARE_CF_TYPE