summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>2010-10-17 19:33:19 +0000
committernicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>2010-10-17 19:33:19 +0000
commit116d575b68536cd6caca51dc03fa067192f46002 (patch)
tree21e63a2c01fdd1ab461d151039afa15a5bfe542e
parentb54b6a4d94f53adb98061eab3b52b99af36eb69c (diff)
downloadgcc-116d575b68536cd6caca51dc03fa067192f46002.tar.gz
In gcc/:
2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com> * doc/objc.texi (GNU Objective-C runtime API): New section. (Modern GNU Objective-C runtime API): New section. (Traditional GNU Objective-C runtime API): New section. (Executing code before main): Mention that this section is specific to the GNU Objective-C runtime. (Garbage Collection): Same. In gcc/testsuite/: 2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com> * obj-c++.dg/gnu-api-2-class.mm: New. * obj-c++.dg/gnu-api-2-ivar.mm: New. * obj-c++.dg/gnu-api-2-method.mm: New. * obj-c++.dg/gnu-api-2-objc.mm: New. * obj-c++.dg/gnu-api-2-object.mm: New. * obj-c++.dg/gnu-api-2-property.mm: New. * obj-c++.dg/gnu-api-2-protocol.mm: New. * obj-c++.dg/gnu-api-2-sel.mm: New. In libobjc/: 2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com> * objc/message.h: Moved initial includes outside of extern "C". * objc/runtime.h: Add extern "C" for Objective-C++. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@165595 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/doc/objc.texi121
-rw-r--r--gcc/testsuite/ChangeLog11
-rw-r--r--gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm441
-rw-r--r--gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm80
-rw-r--r--gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm227
-rw-r--r--gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm242
-rw-r--r--gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm161
-rw-r--r--gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm65
-rw-r--r--gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm160
-rw-r--r--gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm103
-rw-r--r--libobjc/ChangeLog7
-rw-r--r--libobjc/objc/message.h6
-rw-r--r--libobjc/objc/runtime.h8
14 files changed, 1636 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 530eca6dc86..4e9cb738028 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * doc/objc.texi (GNU Objective-C runtime API): New section.
+ (Modern GNU Objective-C runtime API): New section.
+ (Traditional GNU Objective-C runtime API): New section.
+ (Executing code before main): Mention that this section is
+ specific to the GNU Objective-C runtime.
+ (Garbage Collection): Same.
+
2010-10-17 Uros Bizjak <ubizjak@gmail.com>
* c-parser.c (c_parser_for_statement): Move initialization of
diff --git a/gcc/doc/objc.texi b/gcc/doc/objc.texi
index f0fab6be827..ed5d390a84e 100644
--- a/gcc/doc/objc.texi
+++ b/gcc/doc/objc.texi
@@ -9,10 +9,11 @@
@chapter GNU Objective-C features
This document is meant to describe some of the GNU Objective-C
-features. It is not intended to teach you Objective-C, there are
+features. It is not intended to teach you Objective-C. There are
several resources on the Internet that present the language.
@menu
+* GNU Objective-C runtime API::
* Executing code before main::
* Type encoding::
* Garbage Collection::
@@ -23,9 +24,124 @@ several resources on the Internet that present the language.
* Fast enumeration::
@end menu
+@c =========================================================================
+@node GNU Objective-C runtime API
+@section GNU Objective-C runtime API
+
+This section is specific for the GNU Objective-C runtime. If you are
+using a different runtime, you can skip it.
+
+The GNU Objective-C runtime provides an API that allows you to
+interact with the Objective-C runtime system, querying the live
+runtime structures and even manipulating them. This allows you for
+example to inspect and navigate classes, methods and protocols; to
+define new classes or new methods, and even to modify existing classes
+or protocols.
+
+If you are using a ``Foundation'' library such as GNUstep-Base, this
+library will provide you with a rich set of functionality to do most
+of the inspection tasks, and you probably will only need direct access
+to the GNU Objective-C runtime API to define new classes or methods.
+
+@menu
+* Modern GNU Objective-C runtime API::
+* Traditional GNU Objective-C runtime API::
+@end menu
+
+@c =========================================================================
+@node Modern GNU Objective-C runtime API
+@subsection Modern GNU Objective-C runtime API
+
+The GNU Objective-C runtime provides an API which is similar to the
+one provided by the ``Objective-C 2.0'' Apple/NeXT Objective-C
+runtime. The API is documented in the public header files of the GNU
+Objective-C runtime:
+
+@itemize @bullet
+
+@item
+@file{objc/objc.h}: this is the basic Objective-C header file,
+defining the basic Objective-C types such as @code{id}, @code{Class}
+and @code{BOOL}. You have to include this header to do almost
+anything with Objective-C.
+
+@item
+@file{objc/runtime.h}: this header declares most of the public runtime
+API functions allowing you to inspect and manipulate the Objective-C
+runtime data structures. These functions are fairly standardized
+across Objective-C runtimes and are almost identical to the Apple/NeXT
+Objective-C runtime ones. It does not declare functions in some
+specialized areas (constructing and forwarding message invocations,
+threading) which are in the other headers below. You have to include
+@file{objc/objc.h} and @file{objc/runtime.h} to use any of the
+functions, such as @code{class_getName()}, declared in
+@file{objc/runtime.h}.
+
+@item
+@file{objc/message.h}: this header declares public functions used to
+construct, deconstruct and forward message invocations. Because
+messaging is done in quite a different way on different runtimes,
+functions in this header are specific to the GNU Objective-C runtime
+implementation.
+
+@item
+@file{objc/objc-exception.h}: this header declares some public
+functions related to Objective-C exceptions. For example functions in
+this header allow you to throw an Objective-C exception from plain
+C/C++ code.
+
+@item
+@file{objc/objc-sync.h}: this header declares some public functions
+related to the Objective-C @code{@@synchronized()} syntax, allowing
+you to emulate an Objective-C @code{@@synchronized()} block in plain
+C/C++ code.
+
+@item
+@file{objc/thr.h}: this header declares a public runtime API threading
+layer that is only provided by the GNU Objective-C runtime. It
+declares functions such as @code{objc_mutex_lock()}, which provide a
+platform-independent set of threading functions.
+
+@end itemize
+
+@c =========================================================================
+@node Traditional GNU Objective-C runtime API
+@subsection Traditional GNU Objective-C runtime API
+
+The GNU Objective-C runtime used to provide a different API, which we
+call the ``traditional'' GNU Objective-C runtime API. Functions
+belonging to this API are easy to recognize because they use a
+different naming convention, such as @code{class_get_super_class()}
+(traditional API) instead of @code{class_getSuperclass()} (modern
+API). Software using this API includes the file
+@file{objc/objc-api.h} where it is declared.
+
+The traditional API is deprecated but it is still supported in this
+release of the runtime; you can access it as usual by including
+@file{objc/objc-api.h}.
+
+If you are using the traditional API you are urged to upgrade your
+software to use the modern API because the traditional API requires
+access to private runtime internals to do anything serious with it;
+for this reason, there is no guarantee that future releases of the GNU
+Objective-C runtime library will be able to provide a fully compatible
+@file{objc/objc-api.h} as the private runtime internals change. It is
+expected that the next release will hide a number of runtime internals
+making the traditional API nominally supported but fairly useless
+beyond very simple use cases.
+
+Finally, you can not include both @file{objc/objc-api.h} and
+@file{objc/runtime.h} at the same time. The traditional and modern
+APIs unfortunately have some conflicting declarations (such as the one
+for @code{Method}) and can not be used at the same time.
+
+@c =========================================================================
@node Executing code before main
@section @code{+load}: Executing code before main
+This section is specific for the GNU Objective-C runtime. If you are
+using a different runtime, you can skip it.
+
The GNU Objective-C runtime provides a way that allows you to execute
code before the execution of the program enters the @code{main}
function. The code is executed on a per-class and a per-category basis,
@@ -480,6 +596,9 @@ of Objective-C methods.
@node Garbage Collection
@section Garbage Collection
+This section is specific for the GNU Objective-C runtime. If you are
+using a different runtime, you can skip it.
+
Support for garbage collection with the GNU runtime has been added by
using a powerful conservative garbage collector, known as the
Boehm-Demers-Weiser conservative garbage collector.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d678a0a5cd5..7004ca21102 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,14 @@
+2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
+
+ * obj-c++.dg/gnu-api-2-class.mm: New.
+ * obj-c++.dg/gnu-api-2-ivar.mm: New.
+ * obj-c++.dg/gnu-api-2-method.mm: New.
+ * obj-c++.dg/gnu-api-2-objc.mm: New.
+ * obj-c++.dg/gnu-api-2-object.mm: New.
+ * obj-c++.dg/gnu-api-2-property.mm: New.
+ * obj-c++.dg/gnu-api-2-protocol.mm: New.
+ * obj-c++.dg/gnu-api-2-sel.mm: New.
+
2010-10-17 Iain Sandoe <iains@gcc.gnu.org>
* objc.dg/fsf-package-0.m: New.
diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm
new file mode 100644
index 00000000000..d6aa827bc8d
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm
@@ -0,0 +1,441 @@
+/* Test the Modern GNU Objective-C Runtime API.
+
+ This is test 'class', covering all functions starting with 'class'. */
+
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
+
+/* To get the modern GNU Objective-C Runtime API, you include
+ objc/runtime.h. */
+#include <objc/runtime.h>
+#include <stdlib.h>
+#include <iostream>
+#include <cstring>
+
+@interface MyRootClass
+{ Class isa; }
++ alloc;
+- init;
+@end
+
+@implementation MyRootClass
++ alloc { return class_createInstance (self, 0); }
+- init { return self; }
+@end
+
+@protocol MyProtocol
+- (id) variable;
+@end
+
+@protocol MySecondProtocol
+- (id) setVariable: (id)value;
+@end
+
+@interface MySubClass : MyRootClass <MyProtocol>
+{ id variable_ivar; }
+- (void) setVariable: (id)value;
+- (id) variable;
+@end
+
+@implementation MySubClass
+- (void) setVariable: (id)value { variable_ivar = value; }
+- (id) variable { return variable_ivar; }
+@end
+
+@interface DifferentClass : MyRootClass
+- (id) myClass;
+- (id) self;
+@end
+
+@implementation DifferentClass
+- (id) myClass { return object_getClass (self); }
+- (id) self { return self; }
+@end
+
+@interface MySubClass (MySelf)
+- (id) mySelf;
+@end
+
+int main ()
+{
+ /* Functions are tested in alphabetical order. */
+
+ std::cout << "Testing class_addIvar ()...\n";
+ {
+ Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0);
+
+ if (new_class == Nil)
+ abort ();
+
+ if (! class_addIvar (new_class, "variable2_ivar", sizeof (id),
+ __alignof__ (id), @encode (id)))
+ abort ();
+
+ if (! class_addIvar (new_class, "variable3_ivar", sizeof (unsigned char),
+ __alignof__ (unsigned char), @encode (unsigned char)))
+ abort ();
+
+ if (! class_addIvar (new_class, "variable4_ivar", sizeof (unsigned long),
+ __alignof__ (unsigned long), @encode (unsigned long)))
+ abort ();
+
+ objc_registerClassPair (new_class);
+
+ {
+ MySubClass *o = [[objc_getClass ("MySubSubClass") alloc] init];
+ Ivar variable2 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable2_ivar");
+ Ivar variable3 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable3_ivar");
+ Ivar variable4 = class_getInstanceVariable (objc_getClass ("MySubSubClass"), "variable4_ivar");
+
+ if (variable2 == NULL || variable3 == NULL || variable4 == NULL)
+ abort ();
+
+ if (std::strcmp (ivar_getName (variable2), "variable2_ivar") != 0)
+ abort ();
+
+ if (std::strcmp (ivar_getName (variable3), "variable3_ivar") != 0)
+ abort ();
+
+ if (std::strcmp (ivar_getName (variable4), "variable4_ivar") != 0)
+ abort ();
+
+ {
+ unsigned char *var3 = (unsigned char *)((char *)o + ivar_getOffset (variable3));
+ unsigned long *var4 = (unsigned long *)((char *)o + ivar_getOffset (variable4));
+
+ object_setIvar (o, variable2, new_class);
+ *var3 = 230;
+ *var4 = 89000L;
+
+ if (object_getIvar (o, variable2) != new_class)
+ abort ();
+
+ if (*var3 != 230)
+ abort ();
+
+ if (*var4 != 89000L)
+ abort ();
+ }
+ }
+ }
+
+ std::cout << "Testing class_addMethod ()...\n";
+ {
+ Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MySubClass2", 0);
+ Method method1 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:));
+ Method method2 = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (variable));
+
+ if (new_class == Nil)
+ abort ();
+
+ if (! class_addIvar (new_class, "variable_ivar", sizeof (id),
+ __alignof__ (id), @encode (id)))
+ abort ();
+
+ if (! class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method1),
+ method_getTypeEncoding (method1)))
+ abort ();
+
+ if (! class_addMethod (new_class, @selector (variable), method_getImplementation (method2),
+ method_getTypeEncoding (method2)))
+ abort ();
+
+ objc_registerClassPair (new_class);
+
+ /* Now, MySubClass2 is basically the same as MySubClass! We'll
+ use the variable and setVariable: methods on it. */
+ {
+ MySubClass *o = (MySubClass *)[[objc_getClass ("MySubClass2") alloc] init];
+
+ [o setVariable: o];
+
+ if ([o variable] != o)
+ abort ();
+ }
+ }
+
+ std::cout << "Testing class_addProtocol ()...\n";
+ {
+ if (!class_addProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol)))
+ abort ();
+
+ if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol)))
+ abort ();
+
+ if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MySecondProtocol)))
+ abort ();
+ }
+
+ std::cout << "Testing class_conformsToProtocol ()...\n";
+ {
+ if (class_conformsToProtocol (objc_getClass ("MyRootClass"), @protocol (MyProtocol)))
+ abort ();
+
+ if (!class_conformsToProtocol (objc_getClass ("MySubClass"), @protocol (MyProtocol)))
+ abort ();
+ }
+
+ std::cout << "Testing class_copyIvarList ()...\n";
+ {
+ unsigned int count;
+ Ivar * list = class_copyIvarList (objc_getClass ("MySubClass"), &count);
+
+ if (count != 1)
+ abort ();
+
+ if (std::strcmp (ivar_getName (list[0]), "variable_ivar") != 0)
+ abort ();
+
+ if (list[1] != NULL)
+ abort ();
+ }
+
+ std::cout << "Testing class_copyMethodList ()...\n";
+ {
+ unsigned int count;
+ Method * list = class_copyMethodList (objc_getClass ("MySubClass"), &count);
+
+ if (count != 2)
+ abort ();
+
+ if (! ((std::strcmp (sel_getName (method_getName (list[0])), "variable") == 0
+ && std::strcmp (sel_getName (method_getName (list[1])), "setVariable:") == 0)
+ || (std::strcmp (sel_getName (method_getName (list[0])), "setVariable:") == 0
+ && std::strcmp (sel_getName (method_getName (list[1])), "variable") == 0)))
+ abort ();
+
+ if (list[2] != NULL)
+ abort ();
+ }
+
+ /* TODO: Test new ABI (when available). */
+ std::cout << "Testing class_copyPropertyList ()...\n";
+ {
+ unsigned int count;
+ Property * list = class_copyPropertyList (objc_getClass ("MySubClass"), &count);
+
+ if (count != 0 || list != NULL)
+ abort ();
+ }
+
+ std::cout << "Testing class_copyProtocolList ()...\n";
+ {
+ unsigned int count;
+ Protocol ** list = class_copyProtocolList (objc_getClass ("MySubClass"), &count);
+
+ /* Remember that we added MySecondProtocol in the test above. */
+ if (count != 2)
+ abort ();
+
+ if (! ((std::strcmp (protocol_getName (list[0]), "MyProtocol") == 0
+ && std::strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0)
+ || (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0
+ && std::strcmp (protocol_getName (list[1]), "MyProtocol") == 0)))
+ abort ();
+
+ if (list[2] != NULL)
+ abort ();
+ }
+
+ std::cout << "Testing class_createInstance ()...\n";
+ {
+ MySubClass *object = [[MySubClass alloc] init];
+
+ [object setVariable: object];
+ if ([object variable] != object)
+ abort ();
+ }
+
+ std::cout << "Testing class_getClassMethod ()...\n";
+ {
+ Method method = class_getClassMethod (objc_getClass ("MySubClass"),
+ @selector(alloc));
+
+ if (method == NULL)
+ abort ();
+
+ if (std::strcmp (sel_getName (method_getName (method)), "alloc") != 0)
+ abort ();
+
+ if (class_getClassMethod (objc_getClass ("MySubClass"),
+ @selector(variable)))
+ abort ();
+ }
+
+ std::cout << "Testing class_getClassVariable ()...\n";
+ {
+ if (class_getClassVariable (objc_getClass ("MySubClass"), "variable_ivar"))
+ abort ();
+ }
+
+ std::cout << "Testing class_getInstanceMethod ()...\n";
+ {
+ Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector(variable));
+
+ if (method == NULL)
+ abort ();
+
+ if (std::strcmp (sel_getName (method_getName (method)), "variable") != 0)
+ abort ();
+
+ if (class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector(alloc)))
+ abort ();
+ }
+
+ std::cout << "Testing class_getInstanceSize ()...\n";
+ {
+ if (class_getInstanceSize (objc_getClass ("MyRootClass")) != sizeof (struct objc_object))
+ abort ();
+ }
+
+ std::cout << "Testing class_getInstanceVariable ()...\n";
+ {
+ Ivar variable = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar");
+
+ if (variable == NULL)
+ abort ();
+
+ if (std::strcmp (ivar_getName (variable), "variable_ivar") != 0)
+ abort ();
+
+ if (class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar_no"))
+ abort ();
+ }
+
+ std::cout << "Testing class_getIvarLayout ()...\n";
+ {
+ if (class_getIvarLayout (objc_getClass ("MyRootClass")) != NULL)
+ abort ();
+ }
+
+ std::cout << "Testing class_getMethodImplementation ()...\n";
+ {
+ MySubClass *object = [[MySubClass alloc] init];
+ IMP imp = class_getMethodImplementation (objc_getClass ("MySubClass"),
+ @selector(variable));
+
+ if (imp == NULL)
+ abort ();
+
+ [object setVariable: object];
+
+ if ((*imp)(object, @selector(variable)) != object)
+ abort ();
+ }
+
+ /* This function does not exist with the GNU runtime. */
+ /* std::cout << "Testing class_getMethodImplementation_stret ()...\n"; */
+
+ std::cout << "Testing class_getName ()...\n";
+ {
+ if (std::strcmp (class_getName (objc_getClass ("MyRootClass")),
+ "MyRootClass") != 0)
+ abort ();
+ }
+
+ /* TODO: Test new ABI (when available). */
+ std::cout << "Testing class_getProperty ()...\n";
+ {
+ if (class_getProperty (objc_getClass ("MyRootClass"), "property") != NULL)
+ abort ();
+ }
+
+ std::cout << "Testing class_getSuperclass ()...\n";
+ {
+ MySubClass *object = [[MySubClass alloc] init];
+ if (class_getSuperclass (object_getClass (object)) != objc_getClass ("MyRootClass"))
+ abort ();
+ }
+
+ std::cout << "Testing class_getVersion ()...\n";
+ {
+ if (class_getVersion (objc_getClass ("MySubClass")) != 0)
+ abort ();
+ }
+
+ std::cout << "Testing class_getWeakIvarLayout ()...\n";
+ {
+ if (class_getWeakIvarLayout (objc_getClass ("MyRootClass")) != NULL)
+ abort ();
+ }
+
+ std::cout << "Testing class_isMetaClass ()...\n";
+ {
+ MySubClass *object = [[MySubClass alloc] init];
+ if (class_isMetaClass (object_getClass (object))
+ || ! class_isMetaClass (object_getClass (object_getClass (object))))
+ abort ();
+ }
+
+ std::cout << "Testing class_replaceMethod ()...\n";
+ {
+ Method new_method = class_getInstanceMethod (objc_getClass ("DifferentClass"),
+ @selector (myClass));
+ Method old_method = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (variable));
+ const char *new_types = method_getTypeEncoding (new_method);
+ IMP new_imp = method_getImplementation (new_method);
+ const char *old_types = method_getTypeEncoding (old_method);
+ IMP old_imp = class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable),
+ method_getImplementation (new_method),
+ method_getTypeEncoding (new_method));
+ MySubClass *o = [[MySubClass alloc] init];
+
+ [o setVariable: o];
+
+ /* Try the new method implementation. */
+ if ([o variable] != objc_getClass ("MySubClass"))
+ abort ();
+
+ /* Put the original method back. */
+ class_replaceMethod (objc_getClass ("MySubClass"), @selector (variable),
+ old_imp, old_types);
+
+ /* Test it's back to what it was. */
+ if ([o variable] != o)
+ abort ();
+
+ {
+ DifferentClass *o = [[DifferentClass alloc] init];
+
+ /* Finally, try adding a new method. */
+ class_replaceMethod (objc_getClass ("DifferentClass"), @selector (mySelf),
+ new_imp, new_types);
+
+ if ([(MySubClass*)o mySelf] != objc_getClass ("DifferentClass"))
+ abort ();
+ }
+ }
+
+ std::cout << "Testing class_respondsToSelector ()...\n";
+ {
+ if (! class_respondsToSelector (objc_getClass ("MySubClass"), @selector(setVariable:)))
+ abort ();
+
+ if (class_respondsToSelector (objc_getClass ("MyRootClass"), @selector(setVariable:)))
+ abort ();
+ }
+
+ /* This is not really implemented with the GNU runtime. */
+ /* std::cout << "Testing class_setIvarLayout ()...\n"; */
+
+ std::cout << "Testing class_setVersion ()...\n";
+ {
+ class_setVersion (objc_getClass ("MySubClass"), 45);
+
+ if (class_getVersion (objc_getClass ("MySubClass")) != 45)
+ abort ();
+
+ class_setVersion (objc_getClass ("MySubClass"), 46);
+
+ if (class_getVersion (objc_getClass ("MySubClass")) != 46)
+ abort ();
+ }
+
+ /* This is not really implemented with the GNU runtime. */
+ /* std::cout << "Testing class_setWeakIvarLayout ()...\n"; */
+
+ return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm
new file mode 100644
index 00000000000..a95cbac7fcc
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm
@@ -0,0 +1,80 @@
+/* Test the Modern GNU Objective-C Runtime API.
+
+ This is test 'ivar', covering all functions starting with 'ivar'. */
+
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
+
+/* To get the modern GNU Objective-C Runtime API, you include
+ objc/runtime.h. */
+#include <objc/runtime.h>
+#include <stdlib.h>
+#include <iostream>
+#include <cstring>
+
+@interface MyRootClass
+{ Class isa; }
++ alloc;
+- init;
+@end
+
+@implementation MyRootClass
++ alloc { return class_createInstance (self, 0); }
+- init { return self; }
+@end
+
+@protocol MyProtocol
+- (id) variable;
+@end
+
+@protocol MySecondProtocol
+- (id) setVariable: (id)value;
+@end
+
+@interface MySubClass : MyRootClass <MyProtocol>
+{ id variable_ivar; }
+- (void) setVariable: (id)value;
+- (id) variable;
+@end
+
+@implementation MySubClass
+- (void) setVariable: (id)value { variable_ivar = value; }
+- (id) variable { return variable_ivar; }
+@end
+
+
+int main ()
+{
+ /* Functions are tested in alphabetical order. */
+
+ std::cout << "Testing ivar_getName () ...\n";
+ {
+ Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"),
+ "variable_ivar");
+ if (strcmp (ivar_getName (ivar), "variable_ivar") != 0)
+ abort ();
+
+ ivar = class_getInstanceVariable (objc_getClass ("MySubClass"),
+ "variable");
+ if (ivar != 0)
+ abort ();
+ }
+
+ std::cout << "Testing ivar_getOffset () ...\n";
+ {
+ Ivar ivar = class_getInstanceVariable (objc_getClass ("MyRootClass"),
+ "isa");
+ if (ivar_getOffset (ivar) != 0)
+ abort ();
+ }
+
+ std::cout << "Testing ivar_getTypeEncoding () ...\n";
+ {
+ Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"),
+ "variable_ivar");
+ if (strcmp (ivar_getTypeEncoding (ivar), "@") != 0)
+ abort ();
+ }
+
+ return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm
new file mode 100644
index 00000000000..ea665052660
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm
@@ -0,0 +1,227 @@
+/* Test the Modern GNU Objective-C Runtime API.
+
+ This is test 'method', covering all functions starting with 'method'. */
+
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
+
+/* To get the modern GNU Objective-C Runtime API, you include
+ objc/runtime.h. */
+#include <objc/runtime.h>
+#include <stdlib.h>
+#include <iostream>
+#include <cstring>
+
+@interface MyRootClass
+{ Class isa; }
++ alloc;
+- init;
+@end
+
+@implementation MyRootClass
++ alloc { return class_createInstance (self, 0); }
+- init { return self; }
+@end
+
+@protocol MyProtocol
+- (id) variable;
+@end
+
+@protocol MySecondProtocol
+- (id) setVariable: (id)value;
+@end
+
+@interface MySubClass : MyRootClass <MyProtocol>
+{ id variable_ivar; }
+- (void) setVariable: (id)value;
+- (id) variable;
+- (id) constant;
+@end
+
+@implementation MySubClass
+- (void) setVariable: (id)value { variable_ivar = value; }
+- (id) variable { return variable_ivar; }
+- (id) constant { return nil; }
+@end
+
+
+int main ()
+{
+ /* Functions are tested in alphabetical order. */
+
+ std::cout <<"Testing method_copyArgumentType () ...\n";
+ {
+ Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (setVariable:));
+ char *type = method_copyArgumentType (method, 2);
+
+ if (type == NULL || type[0] != '@')
+ abort ();
+ }
+
+ std::cout << "Testing method_copyReturnType () ...\n";
+ {
+ Method method = class_getClassMethod (objc_getClass ("MyRootClass"),
+ @selector (alloc));
+ char *type = method_copyReturnType (method);
+
+ /* Check that it returns an object. */
+ if (type == NULL || type[0] != '@')
+ abort ();
+ }
+
+ std::cout << "Testing method_exchangeImplementations () ...\n";
+ {
+ Method method_a = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (variable));
+ Method method_b = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (constant));
+ MySubClass *object = [[MySubClass alloc] init];
+
+ /* Check that things work as expected before the swap. */
+ [object setVariable: object];
+
+ if ([object variable] != object || [object constant] != nil)
+ abort ();
+
+ /* Swap the methods. */
+ method_exchangeImplementations (method_a, method_b);
+
+ /* Check that behaviour has changed. */
+ if ([object variable] != nil || [object constant] != object)
+ abort ();
+
+ /* Swap the methods again. */
+ method_exchangeImplementations (method_a, method_b);
+
+ /* Check that behaviour is back to normal. */
+ if ([object variable] != object || [object constant] != nil)
+ abort ();
+ }
+
+ std::cout << "Testing method_getArgumentType () ...\n";
+ {
+ Method method = class_getInstanceMethod (objc_getClass ("MyRootClass"),
+ @selector (init));
+ char type[16];
+
+ method_getArgumentType (method, 1, type, 16);
+
+ /* Check the second argument (_cmd), which should be a SEL. */
+ if (type[0] != ':')
+ abort ();
+ }
+
+ std::cout << "Testing method_getDescription () ...\n";
+ {
+ Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (variable));
+ struct objc_method_description *description = method_getDescription (method);
+
+ if (std::strcmp (sel_getName (description->name), "variable") != 0)
+ abort ();
+
+ if (method_getDescription (NULL) != NULL)
+ abort ();
+ }
+
+ std::cout << "Testing method_getImplementation () ...\n";
+ {
+ typedef void (*set_variable_function) (id receiver, SEL _cmd, id variable);
+ Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (setVariable:));
+ set_variable_function imp;
+ MySubClass *object = [[MySubClass alloc] init];
+
+ imp = (set_variable_function)(method_getImplementation (method));
+
+ (*imp)(object, @selector (setVariable:), object);
+
+ if ([object variable] != object)
+ abort ();
+ }
+
+ std::cout << "Testing method_getName () ...\n";
+ {
+ Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (setVariable:));
+ if (std::strcmp (sel_getName (method_getName (method)), "setVariable:") != 0)
+ abort ();
+ }
+
+ std::cout << "Testing method_getNumberOfArguments () ...\n";
+ {
+ Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (setVariable:));
+ if (method_getNumberOfArguments (method) != 3)
+ abort ();
+
+ method = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (variable));
+ if (method_getNumberOfArguments (method) != 2)
+ abort ();
+ }
+
+ std::cout << "Testing method_getTypeEncoding () ...\n";
+ {
+ Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (setVariable:));
+ const char *types = method_getTypeEncoding (method);
+
+ /* Check that method type string starts with 'v' (void) */
+ if (types == NULL || types[0] != 'v')
+ abort ();
+ }
+
+ std::cout << "Testing method_getReturnType () ...\n";
+ {
+ Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (setVariable:));
+ char type[16];
+
+ method_getReturnType (method, type, 16);
+
+ if (type[0] != 'v')
+ abort ();
+
+ method_getReturnType (NULL, type, 16);
+
+ if (type[0] != 0)
+ abort ();
+ }
+
+ std::cout << "Testing method_setImplementation () ...\n";
+ {
+ Method method_a = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (variable));
+ Method method_b = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (constant));
+ IMP original_imp_a = method_getImplementation (method_a);
+ IMP original_imp_b = method_getImplementation (method_b);
+ MySubClass *object = [[MySubClass alloc] init];
+
+ /* Check that things work as expected before the swap. */
+ [object setVariable: object];
+
+ if ([object variable] != object || [object constant] != nil)
+ abort ();
+
+ /* Have 'variable' use the same implementation as 'constant'. */
+ if (method_setImplementation (method_a, original_imp_b) != original_imp_a)
+ abort ();
+
+ /* Check that behaviour has changed. */
+ if ([object variable] != nil || [object constant] != nil)
+ abort ();
+
+ /* Put the original method back. */
+ if (method_setImplementation (method_a, original_imp_a) != original_imp_b)
+ abort ();
+
+ /* Check that behaviour is back to normal. */
+ if ([object variable] != object || [object constant] != nil)
+ abort ();
+ }
+
+ return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm
new file mode 100644
index 00000000000..e9bdee8daf3
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm
@@ -0,0 +1,242 @@
+/* Test the Modern GNU Objective-C Runtime API.
+
+ This is test 'objc', covering all functions starting with 'objc'. */
+
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
+
+/* To get the modern GNU Objective-C Runtime API, you include
+ objc/runtime.h. */
+#include <objc/runtime.h>
+#include <stdlib.h>
+#include <iostream>
+#include <cstring>
+
+@interface MyRootClass
+{ Class isa; }
++ alloc;
+- init;
+@end
+
+@implementation MyRootClass
++ alloc { return class_createInstance (self, 0); }
+- init { return self; }
+@end
+
+@protocol MyProtocol
+- (id) variable;
+@end
+
+@protocol MySecondProtocol
+- (id) setVariable: (id)value;
+@end
+
+@interface MySubClass : MyRootClass <MyProtocol>
+{ id variable_ivar; }
+- (void) setVariable: (id)value;
+- (id) variable;
+@end
+
+@implementation MySubClass
+- (void) setVariable: (id)value { variable_ivar = value; }
+- (id) variable { return variable_ivar; }
+@end
+
+
+int main ()
+{
+ /* Functions are tested in alphabetical order. */
+
+ std::cout << "Testing objc_allocateClassPair ()...\n";
+ {
+ Class new_root_class = objc_allocateClassPair (Nil, "MyNewRootClass", 0);
+ Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass", 0);
+
+ /* A new root class would obviously need at least an 'isa'
+ instance variable. We don't add it so we never actually
+ instantiate an instance of the class, which wouldn't work. */
+
+ objc_registerClassPair (new_root_class);
+ objc_registerClassPair (new_class);
+
+ if (std::strcmp (class_getName (new_class), "MyNewSubClass") != 0)
+ abort ();
+
+ if (class_getSuperclass (new_class) != objc_getClass ("MyRootClass"))
+ abort ();
+
+ if (std::strcmp (class_getName (new_root_class), "MyNewRootClass") != 0)
+ abort ();
+
+ if (class_getSuperclass (new_root_class) != Nil)
+ abort ();
+
+ {
+ MySubClass *o = [[objc_getClass ("MyNewSubClass") alloc] init];
+
+ if (object_getClass (o) != objc_getClass ("MyNewSubClass"))
+ abort ();
+ }
+ }
+
+ std::cout << "Testing objc_copyProtocolList ()...\n";
+ {
+ /* Make sure both our two protocols are known to the runtime. */
+ id my_protocol = @protocol (MyProtocol);
+ id my_second_protocol = @protocol (MySecondProtocol);
+ unsigned int count;
+ Protocol ** list = objc_copyProtocolList (&count);
+
+ if (count != 2)
+ abort ();
+
+ if (! ((std::strcmp (protocol_getName (list[0]), "MyProtocol") == 0
+ && std::strcmp (protocol_getName (list[1]), "MySecondProtocol") == 0)
+ || (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") == 0
+ && std::strcmp (protocol_getName (list[1]), "MyProtocol") == 0)))
+ abort ();
+
+ if (list[2] != NULL)
+ abort ();
+ }
+
+ std::cout << "Testing objc_disposeClassPair ()...\n";
+ {
+ Method method = class_getInstanceMethod (objc_getClass ("MySubClass"), @selector (setVariable:));
+ Class new_class = objc_allocateClassPair (objc_getClass ("MyRootClass"), "MyNewSubClass", 0);
+
+ /* Add a bit of everything to the class to exercise undoing all these changes. */
+
+ /* Instance variable. */
+ class_addIvar (new_class, "my_variable", sizeof (float), __alignof__ (float), @encode (float));
+
+ /* Instance method. */
+ class_addMethod (new_class, @selector (setVariable:), method_getImplementation (method),
+ method_getTypeEncoding (method));
+
+ /* Class method. */
+ class_addMethod (object_getClass (new_class), @selector (setVariable:), method_getImplementation (method),
+ method_getTypeEncoding (method));
+
+ /* Protocol. */
+ class_addProtocol (new_class, @protocol (MyProtocol));
+
+ objc_disposeClassPair (new_class);
+ }
+
+ /* This function currently does not exist with the GNU runtime. */
+ /* std::cout << "Testing objc_duplicateClass ()...\n"; */
+
+ /* TODO - Test it when implemented in the GNU Runtime */
+ /* std::cout << "Testing objc_getAssociatedObject ()...\n"; */
+
+ std::cout << "Testing objc_getClass ()...\n";
+ {
+ if (std::strcmp (class_getName (objc_getClass ("MySubClass")),
+ "MySubClass") != 0)
+ abort ();
+ }
+
+ std::cout << "Testing objc_getClassList ()...\n";
+ {
+ Class *list;
+ int i, count, other_count;
+ count = objc_getClassList (NULL, 0);
+
+ /* count most likely will be 5, (MyRootClass, MySubClass,
+ Protocol, Object, NXConstantString). */
+ if (count < 3)
+ abort ();
+
+ list = (Class *)(malloc (sizeof (Class) * count));
+ other_count = objc_getClassList (list, count);
+
+ if (other_count != count)
+ abort ();
+
+ /* Spot-check: search for class 'MyRootClass' in the list. */
+ for (i = 0; i < count; i++)
+ {
+ if (std::strcmp (class_getName (list[i]), "MyRootClass") == 0)
+ break;
+ }
+ if (i == count)
+ abort ();
+
+ /* Spot-check: search for class 'MySubClass' in the list. */
+ for (i = 0; i < count; i++)
+ {
+ if (std::strcmp (class_getName (list[i]), "MySubClass") == 0)
+ break;
+ }
+ if (i == count)
+ abort ();
+
+ /* Spot-check: search for class 'Protocol' in the list. */
+ for (i = 0; i < count; i++)
+ {
+ if (std::strcmp (class_getName (list[i]), "Protocol") == 0)
+ break;
+ }
+ if (i == count)
+ abort ();
+ }
+
+ /* This function does not exist with the GNU runtime. */
+ /* std::cout << "Testing objc_getFutureClass ()...\n"; */
+
+ std::cout << "Testing objc_getMetaClass ()...\n";
+ {
+ if (! class_isMetaClass (objc_getMetaClass ("MyRootClass")))
+ abort ();
+ }
+
+ std::cout << "Testing objc_getProtocol ()...\n";
+ {
+ if (! protocol_isEqual (objc_getProtocol ("MyProtocol"), @protocol (MyProtocol)))
+ abort ();
+ }
+
+ std::cout << "Testing objc_getRequiredClass ()...\n";
+ {
+ if (std::strcmp (class_getName (objc_getRequiredClass ("MyRootClass")),
+ "MyRootClass") != 0)
+ abort ();
+ }
+
+ std::cout << "Testing objc_lookupClass ()...\n";
+ {
+ if (std::strcmp (class_getName (objc_lookupClass ("MyRootClass")),
+ "MyRootClass") != 0)
+ abort ();
+ }
+
+ /* This function does not exist with the GNU runtime. */
+ /* std::cout << "Testing objc_setFutureClass ()...\n"; */
+
+ std::cout << "Testing objc_registerClassPair ()...\n";
+ {
+ Class new_class = objc_allocateClassPair (objc_getClass ("MySubClass"), "MySubSubClass", 0);
+
+ class_addProtocol (new_class, @protocol (MySecondProtocol));
+
+ objc_registerClassPair (new_class);
+
+ if (std::strcmp (class_getName (new_class), "MySubSubClass") != 0)
+ abort ();
+
+ if (class_getSuperclass (new_class) != objc_getClass ("MySubClass"))
+ abort ();
+
+ if (! class_conformsToProtocol (new_class, @protocol (MySecondProtocol)))
+ abort ();
+ }
+
+ /* TODO - Test it when implemented in the GNU Runtime */
+ /* std::cout << "Testing objc_removeAssociatedObjects ()...\n"; */
+
+ /* TODO - Test it when implemented in the GNU Runtime */
+ /* std::cout << "Testing objc_setAssociatedObject ()...\n"; */
+
+ return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm
new file mode 100644
index 00000000000..2a544474d37
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm
@@ -0,0 +1,161 @@
+/* Test the Modern GNU Objective-C Runtime API.
+
+ This is test 'object', covering all functions starting with 'object'. */
+
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
+
+/* To get the modern GNU Objective-C Runtime API, you include
+ objc/runtime.h. */
+#include <objc/runtime.h>
+#include <stdlib.h>
+#include <iostream>
+#include <cstring>
+
+@interface MyRootClass
+{ Class isa; }
++ alloc;
+- init;
+@end
+
+@implementation MyRootClass
++ alloc { return class_createInstance (self, 0); }
+- init { return self; }
+@end
+
+@protocol MyProtocol
+- (id) variable;
+@end
+
+@protocol MySecondProtocol
+- (id) setVariable: (id)value;
+@end
+
+@interface MySubClass : MyRootClass <MyProtocol>
+{ id variable_ivar; }
+- (void) setVariable: (id)value;
+- (id) variable;
+@end
+
+@implementation MySubClass
+- (void) setVariable: (id)value { variable_ivar = value; }
+- (id) variable { return variable_ivar; }
+@end
+
+@interface MySubSubClass : MySubClass
+- (id) test;
+@end
+
+@implementation MySubSubClass
+- (id) test { return self; }
+@end
+
+
+
+int main ()
+{
+ /* Functions are tested in alphabetical order. */
+
+ std::cout << "Testing object_copy () ...\n";
+ {
+ MySubClass *object_a = [[MySubClass alloc] init];
+ MySubClass *object_b = object_copy (object_a, 0);
+
+ [object_b setVariable: object_a];
+ if ([object_b variable] != object_a)
+ abort ();
+ }
+
+ std::cout << "Testing object_dispose () ...\n";
+ {
+ MySubClass *object = [[MySubClass alloc] init];
+
+ object_dispose (object);
+ }
+
+ std::cout << "Testing object_getClass () ...\n";
+ {
+ MyRootClass *o = [[MySubClass alloc] init];
+
+ if (object_getClass (o) != objc_getClass ("MySubClass"))
+ abort ();
+ }
+
+ std::cout << "Testing object_getClassName () ...\n";
+ {
+ MyRootClass *o = [[MyRootClass alloc] init];
+
+ if (std::strcmp (object_getClassName (o), "MyRootClass") != 0)
+ abort ();
+ }
+
+ std::cout << "Testing object_getIndexedIvars () ...\n";
+ {
+ if (object_getIndexedIvars ([[MyRootClass alloc] init]) == NULL)
+ abort ();
+ }
+
+ std::cout << "Testing object_getInstanceVariable () ...\n";
+ {
+ MySubClass *o = [[MySubClass alloc] init];
+ id value;
+
+ [o setVariable: o];
+
+ if (object_getInstanceVariable (o, "variable_ivar", (void **)&value) == NULL)
+ abort ();
+
+ if (value != o)
+ abort ();
+ }
+
+ std::cout << "Testing object_getIvar () ...\n";
+ {
+ MySubClass *o = [[MySubClass alloc] init];
+ Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar");
+
+ [o setVariable: o];
+
+ if (object_getIvar (o, ivar) != o)
+ abort ();
+ }
+
+ std::cout << "Testing object_setClass () ...\n";
+ {
+ MySubClass *o = [[MySubClass alloc] init];
+
+ object_setClass (o, objc_getClass ("MySubSubClass"));
+
+ if ([(MySubSubClass *)o test] != o)
+ abort ();
+ }
+
+ std::cout << "Testing object_setInstanceVariable () ...\n";
+ {
+ MySubClass *o = [[MySubClass alloc] init];
+
+ [o setVariable: nil];
+
+ if (object_setInstanceVariable (o, "variable_ivar", (void *)o) == NULL)
+ abort ();
+
+ if ([o variable] != o)
+ abort ();
+ }
+
+ std::cout << "Testing object_setIvar () ...\n";
+ {
+ MySubClass *o = [[MySubClass alloc] init];
+ MySubClass *value = [[MySubClass alloc] init];
+ Ivar ivar = class_getInstanceVariable (objc_getClass ("MySubClass"), "variable_ivar");
+
+ [o setVariable: o];
+
+ object_setIvar (o, ivar, value);
+
+ if ([o variable] != value)
+ abort ();
+ }
+
+ return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm
new file mode 100644
index 00000000000..9907d4438f3
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm
@@ -0,0 +1,65 @@
+/* Test the Modern GNU Objective-C Runtime API.
+
+ This is test 'property', covering all functions starting with 'property'. */
+
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
+
+/* To get the modern GNU Objective-C Runtime API, you include
+ objc/runtime.h. */
+#include <objc/runtime.h>
+#include <stdlib.h>
+#include <iostream>
+#include <cstring>
+
+@interface MyRootClass
+{ Class isa; }
++ alloc;
+- init;
+@end
+
+@implementation MyRootClass
++ alloc { return class_createInstance (self, 0); }
+- init { return self; }
+@end
+
+@protocol MyProtocol
+- (id) variable;
+@end
+
+@protocol MySecondProtocol
+- (id) setVariable: (id)value;
+@end
+
+@interface MySubClass : MyRootClass <MyProtocol>
+{ id variable_ivar; }
+- (void) setVariable: (id)value;
+- (id) variable;
+@end
+
+@implementation MySubClass
+- (void) setVariable: (id)value { variable_ivar = value; }
+- (id) variable { return variable_ivar; }
+@end
+
+
+int main ()
+{
+ /* Functions are tested in alphabetical order. */
+
+ /* TODO: Test new ABI (when available). */
+ std::cout << "Testing property_getAttributes () ...\n";
+ {
+ if (property_getAttributes (NULL) != NULL)
+ abort ();
+ }
+
+ /* TODO: Test new ABI (when available). */
+ std::cout << "Testing property_getName () ...\n";
+ {
+ if (property_getName (NULL) != NULL)
+ abort ();
+ }
+
+ return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm
new file mode 100644
index 00000000000..1db7d766183
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm
@@ -0,0 +1,160 @@
+/* Test the Modern GNU Objective-C Runtime API.
+
+ This is test 'protocol', covering all functions starting with 'protocol'. */
+
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
+
+/* To get the modern GNU Objective-C Runtime API, you include
+ objc/runtime.h. */
+#include <objc/runtime.h>
+#include <stdlib.h>
+#include <iostream>
+#include <cstring>
+
+@interface MyRootClass
+{ Class isa; }
++ alloc;
+- init;
+@end
+
+@implementation MyRootClass
++ alloc { return class_createInstance (self, 0); }
+- init { return self; }
+@end
+
+@protocol MyProtocol
+- (id) variable;
+@end
+
+@protocol MySecondProtocol
+- (id) setVariable: (id)value;
+@end
+
+@protocol MyThirdProtocol <MySecondProtocol>
+- (id) setAnotherVariable: (id)value;
+@end
+
+@interface MySubClass : MyRootClass <MyProtocol>
+{ id variable_ivar; }
+- (void) setVariable: (id)value;
+- (id) variable;
+@end
+
+@implementation MySubClass
+- (void) setVariable: (id)value { variable_ivar = value; }
+- (id) variable { return variable_ivar; }
+@end
+
+
+int main ()
+{
+ /* Functions are tested in alphabetical order. */
+
+ std::cout << "Testing protocol_conformsToProtocol ()...\n";
+ {
+ if (!protocol_conformsToProtocol (@protocol (MyProtocol),
+ @protocol (MyProtocol)))
+ abort ();
+
+ if (!protocol_conformsToProtocol (@protocol (MyThirdProtocol),
+ @protocol (MySecondProtocol)))
+ abort ();
+
+ if (protocol_conformsToProtocol (@protocol (MyProtocol),
+ @protocol (MySecondProtocol)))
+ abort ();
+ }
+
+ std::cout << "Testing protocol_copyMethodDescriptionList ()...\n";
+ {
+ unsigned int count;
+ struct objc_method_description *list;
+
+ list = protocol_copyMethodDescriptionList (@protocol (MyThirdProtocol),
+ YES, YES, &count);
+
+ if (count != 1)
+ abort ();
+
+ if (std::strcmp (sel_getName (list[0].name), "setAnotherVariable:") != 0)
+ abort ();
+
+ if (list[1].name != NULL && list[1].types != NULL)
+ abort ();
+ }
+
+ /* TODO: Test new ABI (when available). */
+ std::cout << "Testing protocol_copyPropertyList ()...\n";
+ {
+ unsigned int count;
+ Property *list;
+
+ list = protocol_copyPropertyList (@protocol (MyProtocol), &count);
+
+ if (count != 0 || list != NULL)
+ abort ();
+ }
+
+ std::cout << "Testing protocol_copyProtocolList ()...\n";
+ {
+ unsigned int count;
+ Protocol **list;
+
+ list = protocol_copyProtocolList (@protocol (MyThirdProtocol), &count);
+
+ if (count != 1)
+ abort ();
+
+ if (std::strcmp (protocol_getName (list[0]), "MySecondProtocol") != 0)
+ abort ();
+
+ if (list[1] != NULL)
+ abort ();
+ }
+
+ std::cout << "Testing protocol_getMethodDescription ()...\n";
+ {
+ struct objc_method_description description;
+
+ description = protocol_getMethodDescription (@protocol (MySecondProtocol),
+ @selector (setVariable:),
+ YES, YES);
+ if (description.name == NULL && description.types == NULL)
+ abort ();
+
+ if (std::strcmp (sel_getName (description.name), "setVariable:") != 0)
+ abort ();
+ }
+
+ std::cout << "Testing protocol_getName ()...\n";
+ {
+ if (std::strcmp (protocol_getName (@protocol (MyProtocol)), "MyProtocol") != 0)
+ abort ();
+ }
+
+ /* TODO: Test new ABI (when available). */
+ std::cout << "Testing protocol_getProperty ()...\n";
+ {
+ Property property;
+
+ property = protocol_getProperty (objc_getProtocol ("MyProtocol"), "someProperty",
+ YES, YES);
+
+ if (property != NULL)
+ abort ();
+ }
+
+ std::cout << "Testing protocol_isEqual ()...\n";
+ {
+ if (!protocol_isEqual (@protocol (MyProtocol),
+ @protocol (MyProtocol)))
+ abort ();
+
+ if (!protocol_isEqual (@protocol (MyProtocol),
+ objc_getProtocol ("MyProtocol")))
+ abort ();
+ }
+
+ return (0);
+}
diff --git a/gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm b/gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm
new file mode 100644
index 00000000000..66cf0725c79
--- /dev/null
+++ b/gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm
@@ -0,0 +1,103 @@
+/* Test the Modern GNU Objective-C Runtime API.
+
+ This is test 'sel', covering all functions starting with 'sel'. */
+
+/* { dg-do run } */
+/* { dg-skip-if "" { *-*-* } { "-fnext-runtime" } { "" } } */
+
+/* To get the modern GNU Objective-C Runtime API, you include
+ objc/runtime.h. */
+#include <objc/runtime.h>
+#include <stdlib.h>
+#include <iostream>
+#include <cstring>
+
+@interface MyRootClass
+{ Class isa; }
++ alloc;
+- init;
+@end
+
+@implementation MyRootClass
++ alloc { return class_createInstance (self, 0); }
+- init { return self; }
+@end
+
+@protocol MyProtocol
+- (id) variable;
+@end
+
+@protocol MySecondProtocol
+- (id) setVariable: (id)value;
+@end
+
+@interface MySubClass : MyRootClass <MyProtocol>
+{ id variable_ivar; }
+- (void) setVariable: (id)value;
+- (id) variable;
+@end
+
+@implementation MySubClass
+- (void) setVariable: (id)value { variable_ivar = value; }
+- (id) variable { return variable_ivar; }
+@end
+
+
+int main ()
+{
+ /* Functions are tested in alphabetical order. */
+
+ std::cout << "Testing sel_getName () ...\n";
+ {
+ if (std::strcmp (sel_getName (@selector (variable)), "variable") != 0)
+ abort ();
+
+ if (std::strcmp (sel_getName (NULL), "<null selector>") != 0)
+ abort ();
+ }
+
+ std::cout << "Testing sel_getType () ...\n";
+ {
+ /* Get a selector from a real class, so it has interesting
+ types. */
+ Method method = class_getInstanceMethod (objc_getClass ("MySubClass"),
+ @selector (variable));
+
+ if (std::strcmp (sel_getType (method_getName (method)), method_getTypeEncoding (method)) != 0)
+ abort ();
+ }
+
+ std::cout << "Testing sel_getUid () ...\n";
+ {
+ if (std::strcmp (sel_getName (sel_getUid ("myMethod")), "myMethod") != 0)
+ abort ();
+ }
+
+ std::cout << "Testing sel_isEqual () ...\n";
+ {
+ if (! sel_isEqual (@selector (setVariable:), @selector (setVariable:)))
+ abort ();
+ }
+
+ std::cout << "Testing sel_registerName () ...\n";
+ {
+ if (std::strcmp (sel_getName (sel_registerName ("myMethod")), "myMethod") != 0)
+ abort ();
+ }
+
+ std::cout << "Testing set_registerTypedName () ...\n";
+ {
+ const char *types = method_getTypeEncoding (class_getInstanceMethod
+ (objc_getClass ("MySubClass"),
+ @selector (variable)));
+ SEL selector = sel_registerTypedName ("aMethod", types);
+
+ if (std::strcmp (sel_getName (selector), "aMethod") != 0)
+ abort ();
+
+ if (std::strcmp (sel_getType (selector), types) != 0)
+ abort ();
+ }
+
+ return (0);
+}
diff --git a/libobjc/ChangeLog b/libobjc/ChangeLog
index 6e70ac762ea..3c79186211b 100644
--- a/libobjc/ChangeLog
+++ b/libobjc/ChangeLog
@@ -1,12 +1,17 @@
2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
+ * objc/message.h: Moved initial includes outside of extern "C".
+ * objc/runtime.h: Add extern "C" for Objective-C++.
+
+2010-10-17 Nicola Pero <nicola.pero@meta-innovation.com>
+
* init.c (objc_send_load): Do not wait for NXConstantString to be
registered before executing +load. There is no point if
-fconstant-string-class=xxx is used when compiling all modules,
as is the case for almost all users.
* linking.m (__objc_linking): Do not try to forcefully link in
NXConstantString.
-
+
2010-10-16 Nicola Pero <nicola.pero@meta-innovation.com>
* objc/runtime.h: Updated comments.
diff --git a/libobjc/objc/message.h b/libobjc/objc/message.h
index f0038e714ac..b87153ea61c 100644
--- a/libobjc/objc/message.h
+++ b/libobjc/objc/message.h
@@ -26,13 +26,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#ifndef __objc_message_INCLUDE_GNU
#define __objc_message_INCLUDE_GNU
+#include "objc.h"
+#include "objc-decls.h"
+
#ifdef __cplusplus
extern "C" {
#endif
-#include "objc.h"
-#include "objc-decls.h"
-
/* This file includes declarations of the messaging functions and
types.
*/
diff --git a/libobjc/objc/runtime.h b/libobjc/objc/runtime.h
index 0b6f3dfc99b..b37eee2125b 100644
--- a/libobjc/objc/runtime.h
+++ b/libobjc/objc/runtime.h
@@ -50,6 +50,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#include "objc.h"
#include "objc-decls.h"
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
/* An 'Ivar' represents an instance variable. It holds information
about the name, type and offset of the instance variable. */
typedef struct objc_ivar *Ivar;
@@ -1042,4 +1046,8 @@ void objc_layout_structure_get_info (struct objc_struct_layout *layout,
unsigned int *align,
const char **type);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
#endif