Add a define for the ObjFW runtime ABI version.

This removes __has_feature(objc_msg_lookup_stret), as it is not required
anymore after this patch.

Patch by Jonathan Schleifer!

llvm-svn: 190791
This commit is contained in:
Benjamin Kramer 2013-09-16 16:31:49 +00:00
parent 53e622cef4
commit 4d6efbb28a
5 changed files with 24 additions and 22 deletions

View File

@ -1255,23 +1255,6 @@ Further examples of these attributes are available in the static analyzer's `lis
Query for these features with ``__has_attribute(ns_consumed)``, Query for these features with ``__has_attribute(ns_consumed)``,
``__has_attribute(ns_returns_retained)``, etc. ``__has_attribute(ns_returns_retained)``, etc.
objc_msg_lookup_stret
---------------------
Traditionally, if a runtime is used that follows the GNU Objective-C ABI, a
call to objc_msg_lookup() would be emitted for each message send, which would
return a pointer to the actual implementation of the method. However,
objc_msg_lookup() has no information at all about the method signature of the
actual method. Therefore, certain features like forwarding messages cannot be
correctly implemented for methods returning structs using objc_msg_lookup(), as
methods returning structs use a slightly different calling convention.
To work around this, Clang emits calls to objc_msg_lookup_stret() instead for
methods that return structs if the runtime supports this, allowing the runtime
to use a different forwarding handler for methods returning structs.
To check if Clang emits calls to objc_msg_lookup_stret(),
__has_feature(objc_msg_lookup_stret) can be used.
Function Overloading in C Function Overloading in C
========================= =========================

View File

@ -71,16 +71,20 @@ bool ObjCRuntime::tryParse(StringRef input) {
kind = ObjCRuntime::GCC; kind = ObjCRuntime::GCC;
} else if (runtimeName == "objfw") { } else if (runtimeName == "objfw") {
kind = ObjCRuntime::ObjFW; kind = ObjCRuntime::ObjFW;
Version = VersionTuple(0, 8);
} else { } else {
return true; return true;
} }
TheKind = kind; TheKind = kind;
if (dash != StringRef::npos) { if (dash != StringRef::npos) {
StringRef verString = input.substr(dash + 1); StringRef verString = input.substr(dash + 1);
if (Version.tryParse(verString)) if (Version.tryParse(verString))
return true; return true;
} }
if (kind == ObjCRuntime::ObjFW && Version > VersionTuple(0, 8))
Version = VersionTuple(0, 8);
return false; return false;
} }

View File

@ -408,6 +408,22 @@ static void InitializePredefinedMacros(const TargetInfo &TI,
if (LangOpts.ObjCRuntime.isNeXTFamily()) if (LangOpts.ObjCRuntime.isNeXTFamily())
Builder.defineMacro("__NEXT_RUNTIME__"); Builder.defineMacro("__NEXT_RUNTIME__");
if (LangOpts.ObjCRuntime.getKind() == ObjCRuntime::ObjFW) {
VersionTuple tuple = LangOpts.ObjCRuntime.getVersion();
unsigned minor = 0;
if (tuple.getMinor().hasValue())
minor = tuple.getMinor().getValue();
unsigned subminor = 0;
if (tuple.getSubminor().hasValue())
subminor = tuple.getSubminor().getValue();
Builder.defineMacro("__OBJFW_RUNTIME_ABI__",
Twine(tuple.getMajor() * 10000 + minor * 100 +
subminor));
}
Builder.defineMacro("IBOutlet", "__attribute__((iboutlet))"); Builder.defineMacro("IBOutlet", "__attribute__((iboutlet))");
Builder.defineMacro("IBOutletCollection(ClassName)", Builder.defineMacro("IBOutletCollection(ClassName)",
"__attribute__((iboutletcollection(ClassName)))"); "__attribute__((iboutletcollection(ClassName)))");

View File

@ -920,7 +920,6 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("objc_nonfragile_abi", LangOpts.ObjCRuntime.isNonFragile()) .Case("objc_nonfragile_abi", LangOpts.ObjCRuntime.isNonFragile())
.Case("objc_property_explicit_atomic", true) // Does clang support explicit "atomic" keyword? .Case("objc_property_explicit_atomic", true) // Does clang support explicit "atomic" keyword?
.Case("objc_weak_class", LangOpts.ObjCRuntime.hasWeakClassImport()) .Case("objc_weak_class", LangOpts.ObjCRuntime.hasWeakClassImport())
.Case("objc_msg_lookup_stret", LangOpts.ObjCRuntime.getKind() == ObjCRuntime::ObjFW)
.Case("ownership_holds", true) .Case("ownership_holds", true)
.Case("ownership_returns", true) .Case("ownership_returns", true)
.Case("ownership_takes", true) .Case("ownership_takes", true)

View File

@ -11,8 +11,8 @@ struct test {
@end @end
void test0(void) { void test0(void) {
struct test t; struct test t;
#if (defined(STRET) && __has_feature(objc_msg_lookup_stret)) || \ #if (defined(STRET) && defined(__OBJFW_RUNTIME_ABI__)) || \
(!defined(STRET) && !__has_feature(objc_msg_lookup_stret)) (!defined(STRET) && !defined(__OBJFW_RUNTIME_ABI__))
t = [Test0 test]; t = [Test0 test];
#endif #endif
(void)t; (void)t;