diff mbox

=?UTF-8?Q?libobjc=20-=20more=20modern=20Objective-C=20runtime=20API=20(1?= =?UTF-8?Q?3)?=

Message ID 1287344076.283226665@192.168.2.228
State New
Headers show

Commit Message

Nicola Pero Oct. 17, 2010, 7:34 p.m. UTC
This chunk of work:

 * fixes the new libobjc headers to work with Objective-C++

 * provides tests for all libobjc API functions for Objective-C++

 * updates the documentation to explain the new libobjc API

Committed to trunk.

Thanks

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++.
diff mbox

Patch

Index: gcc/doc/objc.texi
===================================================================
--- gcc/doc/objc.texi	(revision 165594)
+++ gcc/doc/objc.texi	(working copy)
@@ -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
 * 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.
Index: gcc/ChangeLog
===================================================================
--- gcc/ChangeLog	(revision 165594)
+++ gcc/ChangeLog	(working copy)
@@ -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
Index: gcc/testsuite/ChangeLog
===================================================================
--- gcc/testsuite/ChangeLog	(revision 165594)
+++ gcc/testsuite/ChangeLog	(working copy)
@@ -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.
Index: gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/gnu-api-2-protocol.mm	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/gnu-api-2-object.mm	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/gnu-api-2-method.mm	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/gnu-api-2-objc.mm	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/gnu-api-2-ivar.mm	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/gnu-api-2-sel.mm	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/gnu-api-2-class.mm	(revision 0)
@@ -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);
+}
Index: gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm
===================================================================
--- gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm	(revision 0)
+++ gcc/testsuite/obj-c++.dg/gnu-api-2-property.mm	(revision 0)
@@ -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);
+}
Index: libobjc/ChangeLog
===================================================================
--- libobjc/ChangeLog	(revision 165594)
+++ libobjc/ChangeLog	(working copy)
@@ -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.
Index: libobjc/objc/runtime.h
===================================================================
--- libobjc/objc/runtime.h	(revision 165594)
+++ libobjc/objc/runtime.h	(working copy)
@@ -50,6 +50,10 @@  see the files COPYING3 and COPYING.RUNTIME respect
 #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_s
                                      unsigned int *align,
                                      const char **type);
 
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
 #endif
Index: libobjc/objc/message.h
===================================================================
--- libobjc/objc/message.h	(revision 165594)
+++ libobjc/objc/message.h	(working copy)
@@ -26,13 +26,13 @@  see the files COPYING3 and COPYING.RUNTIME respect
 #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.
 */