OSDN Git Service

In gcc/:
authornicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 10 Dec 2010 09:38:52 +0000 (09:38 +0000)
committernicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 10 Dec 2010 09:38:52 +0000 (09:38 +0000)
2010-12-10  Nicola Pero  <nicola.pero@meta-innovation.com>

* c-parser.c (c_parser_objc_class_definition): Recognize
Objective-C 2.0 class extensions.

In gcc/cp/:
2010-12-10  Nicola Pero  <nicola.pero@meta-innovation.com>

* parser.c (cp_parser_objc_superclass_or_category): Recognize
Objective-C 2.0 class extensions.  Added iface_p and
is_class_extension arguments.
(cp_parser_objc_class_interface): Updated call to
cp_parser_objc_superclass_or_category.
(cp_parser_objc_class_implementation): Same change.

In gcc/objc/:
2010-12-10  Nicola Pero  <nicola.pero@meta-innovation.com>

* objc-act.c (objc_in_class_extension): New.
(objc_start_category_interface): If -fobjc-std=objc1
was specified, produce an error if a class extension is used.
(objc_finish_interface): Reset objc_in_class_extension to false.
(objc_add_property_declaration): Allow a class extension to extend
readonly properties in the main @interface to be readwrite.
(start_class): Added code to deal with class extensions.  In that
case, return the existing interface after adding any additional
protocols to it and setting objc_in_class_extension to true.
(continue_class): If in a class extension, do not generate the
instance variable template.

In gcc/testsuite/:
2010-12-10  Nicola Pero  <nicola.pero@meta-innovation.com>

* objc.dg/class-extension-1.m: New.
* objc.dg/class-extension-2.m: New.
* objc.dg/class-extension-3.m: New.
* objc.dg/property/at-property-26.m: New.
* objc.dg/property/at-property-27.m: New.
* objc.dg/property/at-property-28.m: New.
* obj-c++.dg/class-extension-1.mm: New.
* obj-c++.dg/class-extension-2.mm: New.
* obj-c++.dg/class-extension-3.mm: New.
* obj-c++.dg/property/at-property-26.mm: New.
* obj-c++.dg/property/at-property-27.mm: New.
* obj-c++.dg/property/at-property-28.mm: New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@167680 138bc75d-0d04-0410-961f-82ee72b054a4

19 files changed:
gcc/ChangeLog
gcc/c-parser.c
gcc/cp/ChangeLog
gcc/cp/parser.c
gcc/objc/ChangeLog
gcc/objc/objc-act.c
gcc/testsuite/ChangeLog
gcc/testsuite/obj-c++.dg/class-extension-1.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/class-extension-2.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/class-extension-3.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/property/at-property-26.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/property/at-property-27.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/property/at-property-28.mm [new file with mode: 0644]
gcc/testsuite/objc.dg/class-extension-1.m [new file with mode: 0644]
gcc/testsuite/objc.dg/class-extension-2.m [new file with mode: 0644]
gcc/testsuite/objc.dg/class-extension-3.m [new file with mode: 0644]
gcc/testsuite/objc.dg/property/at-property-26.m [new file with mode: 0644]
gcc/testsuite/objc.dg/property/at-property-27.m [new file with mode: 0644]
gcc/testsuite/objc.dg/property/at-property-28.m [new file with mode: 0644]

index 2dd440c..66ece2c 100644 (file)
@@ -1,3 +1,8 @@
+2010-12-10  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       * c-parser.c (c_parser_objc_class_definition): Recognize
+       Objective-C 2.0 class extensions.
+
 2010-12-10  Iain Sandoe <iains@gcc.gnu.org>
 
        * config/darwin.c: Remove c-tree.h and c-lang.h
index 6faaacf..8238506 100644 (file)
@@ -6743,6 +6743,8 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
        objc-class-instance-variables[opt]
      @interface identifier ( identifier ) objc-protocol-refs[opt]
        objc-methodprotolist @end
+     @interface identifier ( ) objc-protocol-refs[opt]
+       objc-methodprotolist @end
      @implementation identifier ( identifier )
 
    objc-superclass:
@@ -6777,17 +6779,29 @@ c_parser_objc_class_definition (c_parser *parser, tree attributes)
   c_parser_consume_token (parser);
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
     {
+      /* We have a category or class extension.  */
       tree id2;
       tree proto = NULL_TREE;
       c_parser_consume_token (parser);
       if (c_parser_next_token_is_not (parser, CPP_NAME))
        {
-         c_parser_error (parser, "expected identifier");
-         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
-         return;
+         if (iface_p && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+           {
+             /* We have a class extension.  */
+             id2 = NULL_TREE;
+           }
+         else
+           {
+             c_parser_error (parser, "expected identifier or %<)%>");
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             return;
+           }
+       }
+      else
+       {
+         id2 = c_parser_peek_token (parser)->value;
+         c_parser_consume_token (parser);
        }
-      id2 = c_parser_peek_token (parser)->value;
-      c_parser_consume_token (parser);
       c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
       if (!iface_p)
        {
index 0ebc422..a78f82c 100644 (file)
@@ -1,3 +1,12 @@
+2010-12-10  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       * parser.c (cp_parser_objc_superclass_or_category): Recognize
+       Objective-C 2.0 class extensions.  Added iface_p and
+       is_class_extension arguments.
+       (cp_parser_objc_class_interface): Updated call to
+       cp_parser_objc_superclass_or_category.
+       (cp_parser_objc_class_implementation): Same change.
+       
 2010-12-09  Nathan Froyd  <froydnj@codesourcery.com>
 
        * call.c (print_conversion_rejection): Indent messages two spaces.
index ab533f4..4c8ca72 100644 (file)
@@ -22435,12 +22435,15 @@ cp_parser_objc_protocol_declaration (cp_parser* parser, tree attributes)
 /* Parse an Objective-C superclass or category.  */
 
 static void
-cp_parser_objc_superclass_or_category (cp_parser *parser, tree *super,
-                                                         tree *categ)
+cp_parser_objc_superclass_or_category (cp_parser *parser, 
+                                      bool iface_p,
+                                      tree *super,
+                                      tree *categ, bool *is_class_extension)
 {
   cp_token *next = cp_lexer_peek_token (parser->lexer);
 
   *super = *categ = NULL_TREE;
+  *is_class_extension = false;
   if (next->type == CPP_COLON)
     {
       cp_lexer_consume_token (parser->lexer);  /* Eat ':'.  */
@@ -22449,7 +22452,17 @@ cp_parser_objc_superclass_or_category (cp_parser *parser, tree *super,
   else if (next->type == CPP_OPEN_PAREN)
     {
       cp_lexer_consume_token (parser->lexer);  /* Eat '('.  */
-      *categ = cp_parser_identifier (parser);
+
+      /* If there is no category name, and this is an @interface, we
+        have a class extension.  */
+      if (iface_p && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
+       {
+         *categ = NULL_TREE;
+         *is_class_extension = true;
+       }
+      else
+       *categ = cp_parser_identifier (parser);
+
       cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
     }
 }
@@ -22460,6 +22473,7 @@ static void
 cp_parser_objc_class_interface (cp_parser* parser, tree attributes)
 {
   tree name, super, categ, protos;
+  bool is_class_extension;
 
   cp_lexer_consume_token (parser->lexer);  /* Eat '@interface'.  */
   name = cp_parser_identifier (parser);
@@ -22472,11 +22486,12 @@ cp_parser_objc_class_interface (cp_parser* parser, tree attributes)
       */
       return;
     }
-  cp_parser_objc_superclass_or_category (parser, &super, &categ);
+  cp_parser_objc_superclass_or_category (parser, true, &super, &categ,
+                                        &is_class_extension);
   protos = cp_parser_objc_protocol_refs_opt (parser);
 
   /* We have either a class or a category on our hands.  */
-  if (categ)
+  if (categ || is_class_extension)
     objc_start_category_interface (name, categ, protos, attributes);
   else
     {
@@ -22495,6 +22510,7 @@ static void
 cp_parser_objc_class_implementation (cp_parser* parser)
 {
   tree name, super, categ;
+  bool is_class_extension;
 
   cp_lexer_consume_token (parser->lexer);  /* Eat '@implementation'.  */
   name = cp_parser_identifier (parser);
@@ -22508,7 +22524,8 @@ cp_parser_objc_class_implementation (cp_parser* parser)
       */
       return;
     }
-  cp_parser_objc_superclass_or_category (parser, &super, &categ);
+  cp_parser_objc_superclass_or_category (parser, false, &super, &categ,
+                                        &is_class_extension);
 
   /* We have either a class or a category on our hands.  */
   if (categ)
index 09cc1f6..f079cb5 100644 (file)
@@ -1,3 +1,17 @@
+2010-12-10  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       * objc-act.c (objc_in_class_extension): New.
+       (objc_start_category_interface): If -fobjc-std=objc1
+       was specified, produce an error if a class extension is used.
+       (objc_finish_interface): Reset objc_in_class_extension to false.
+       (objc_add_property_declaration): Allow a class extension to extend
+       readonly properties in the main @interface to be readwrite.
+       (start_class): Added code to deal with class extensions.  In that
+       case, return the existing interface after adding any additional
+       protocols to it and setting objc_in_class_extension to true.
+       (continue_class): If in a class extension, do not generate the
+       instance variable template.
+
 2010-12-08  Nicola Pero  <nicola.pero@meta-innovation.com>
 
        * objc-act.c (objc_build_throw_stmt): Check that the argument of
index 1b815df..131ce55 100644 (file)
@@ -402,6 +402,12 @@ static bool objc_method_optional_flag = false;
 
 static int objc_collecting_ivars = 0;
 
+/* Flag that is set to 'true' while we are processing a class
+   extension.  Since a class extension just "reopens" the main
+   @interface, this can be used to determine if we are in the main
+   @interface, or in a class extension.  */
+static bool objc_in_class_extension = false;
+
 #define BUFSIZE                1024
 
 static char *errbuf;   /* Buffer for error diagnostics */
@@ -748,6 +754,11 @@ objc_start_category_interface (tree klass, tree categ,
                    "category attributes are not available in this version"
                    " of the compiler, (ignored)");
     }
+  if (categ == NULL_TREE)
+    {
+      if (flag_objc1_only)
+       error_at (input_location, "class extensions are not available in Objective-C 1.0");
+    }
   objc_interface_context
     = start_class (CATEGORY_INTERFACE_TYPE, klass, categ, protos, NULL_TREE);
   objc_ivar_chain
@@ -778,6 +789,7 @@ objc_finish_interface (void)
   finish_class (objc_interface_context);
   objc_interface_context = NULL_TREE;
   objc_method_optional_flag = false;
+  objc_in_class_extension = false;
 }
 
 void
@@ -952,6 +964,7 @@ objc_add_property_declaration (location_t location, tree decl,
      is readwrite).  */
   bool property_readonly = false;
   objc_property_assign_semantics property_assign_semantics = OBJC_PROPERTY_ASSIGN;
+  bool property_extension_in_class_extension = false;
 
   if (flag_objc1_only)
     error_at (input_location, "%<@property%> is not available in Objective-C 1.0");
@@ -1125,60 +1138,80 @@ objc_add_property_declaration (location_t location, tree decl,
 
   /* Check for duplicate property declarations.  We first check the
      immediate context for a property with the same name.  Any such
-     declarations are an error.  */
+     declarations are an error, unless this is a class extension and
+     we are extending a property from readonly to readwrite.  */
   for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x))
     {
       if (PROPERTY_NAME (x) == DECL_NAME (decl))
        {
-         location_t original_location = DECL_SOURCE_LOCATION (x);
-         
-         error_at (location, "redeclaration of property %qD", decl);
-
-         if (original_location != UNKNOWN_LOCATION)
-           inform (original_location, "originally specified here");
-         return;
-      }
+         if (objc_in_class_extension
+             && property_readonly == 0
+             && PROPERTY_READONLY (x) == 1)
+           {
+             /* This is a class extension, and we are extending an
+                existing readonly property to a readwrite one.
+                That's fine.  :-) */
+             property_extension_in_class_extension = true;
+             break;
+           }
+         else
+           {
+             location_t original_location = DECL_SOURCE_LOCATION (x);
+             
+             error_at (location, "redeclaration of property %qD", decl);
+             
+             if (original_location != UNKNOWN_LOCATION)
+               inform (original_location, "originally specified here");
+             return;
+           }
+       }
     }
 
-  /* We now need to check for existing property declarations (in the
-     superclass, other categories or protocols) and check that the new
-     declaration is not in conflict with existing ones.  */
+  /* If x is not NULL_TREE, we must be in a class extension and we're
+     extending a readonly property.  In that case, no point in
+     searching for another declaration.  */
+  if (x == NULL_TREE)
+    {
+      /* We now need to check for existing property declarations (in
+        the superclass, other categories or protocols) and check that
+        the new declaration is not in conflict with existing
+        ones.  */
 
-  /* Search for a previous, existing declaration of a property with
-     the same name in superclasses, protocols etc.  If one is found,
-     it will be in the 'x' variable.  */
-  x = NULL_TREE;
+      /* Search for a previous, existing declaration of a property
+        with the same name in superclasses, protocols etc.  If one is
+        found, it will be in the 'x' variable.  */
 
-  /* Note that, for simplicity, the following may search again the
-     local context.  That's Ok as nothing will be found (else we'd
-     have thrown an error above); it's only a little inefficient, but
-     the code is simpler.  */
-  switch (TREE_CODE (objc_interface_context))
-    {
-    case CLASS_INTERFACE_TYPE:
-      /* Look up the property in the current @interface (which will
-        find nothing), then its protocols and categories and
-        superclasses.  */
-      x = lookup_property (objc_interface_context, DECL_NAME (decl));
-      break;
-    case CATEGORY_INTERFACE_TYPE:
-      /* Look up the property in the main @interface, then protocols
-        and categories (one of them is ours, and will find nothing)
-        and superclasses.  */
-      x = lookup_property (lookup_interface (CLASS_NAME (objc_interface_context)),
-                          DECL_NAME (decl));
-      break;
-    case PROTOCOL_INTERFACE_TYPE:
-      /* Looks up the property in any protocols attached to the
-        current protocol.  */
-      if (PROTOCOL_LIST (objc_interface_context))
+      /* Note that, for simplicity, the following may search again the
+        local context.  That's Ok as nothing will be found (else we'd
+        have thrown an error above); it's only a little inefficient,
+        but the code is simpler.  */
+      switch (TREE_CODE (objc_interface_context))
        {
-         x = lookup_property_in_protocol_list (PROTOCOL_LIST (objc_interface_context),
-                                               DECL_NAME (decl));
+       case CLASS_INTERFACE_TYPE:
+         /* Look up the property in the current @interface (which
+            will find nothing), then its protocols and categories and
+            superclasses.  */
+         x = lookup_property (objc_interface_context, DECL_NAME (decl));
+         break;
+       case CATEGORY_INTERFACE_TYPE:
+         /* Look up the property in the main @interface, then
+            protocols and categories (one of them is ours, and will
+            find nothing) and superclasses.  */
+         x = lookup_property (lookup_interface (CLASS_NAME (objc_interface_context)),
+                              DECL_NAME (decl));
+         break;
+       case PROTOCOL_INTERFACE_TYPE:
+         /* Looks up the property in any protocols attached to the
+            current protocol.  */
+         if (PROTOCOL_LIST (objc_interface_context))
+           {
+             x = lookup_property_in_protocol_list (PROTOCOL_LIST (objc_interface_context),
+                                                   DECL_NAME (decl));
+           }
+         break;
+       default:
+         gcc_unreachable ();
        }
-      break;
-    default:
-      gcc_unreachable ();
     }
 
   if (x != NULL_TREE)
@@ -1278,6 +1311,17 @@ objc_add_property_declaration (location_t location, tree decl,
            inform (original_location, "originally specified here");
          return;
        }
+
+      /* If we are in a class extension and we're extending a readonly
+        property in the main @interface, we'll just update the
+        existing property with the readwrite flag and potentially the
+        new setter name.  */
+      if (property_extension_in_class_extension)
+       {
+         PROPERTY_READONLY (x) = 0;
+         PROPERTY_SETTER_NAME (x) = parsed_property_setter_ident;
+         return;
+       }
     }
 
   /* Create a PROPERTY_DECL node.  */
@@ -9417,21 +9461,24 @@ check_protocols (tree proto_list, const char *type, tree name)
     }
 }
 \f
-/* Make sure that the class CLASS_NAME is defined
-   CODE says which kind of thing CLASS_NAME ought to be.
-   It can be CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE,
-   CATEGORY_INTERFACE_TYPE, or CATEGORY_IMPLEMENTATION_TYPE.  */
-
+/* Make sure that the class CLASS_NAME is defined CODE says which kind
+   of thing CLASS_NAME ought to be.  It can be CLASS_INTERFACE_TYPE,
+   CLASS_IMPLEMENTATION_TYPE, CATEGORY_INTERFACE_TYPE, or
+   CATEGORY_IMPLEMENTATION_TYPE.  For a CATEGORY_INTERFACE_TYPE,
+   SUPER_NAME is the name of the category.  For a class extension,
+   CODE is CATEGORY_INTERFACE_TYPE and SUPER_NAME is NULL_TREE.  */
 static tree
 start_class (enum tree_code code, tree class_name, tree super_name,
             tree protocol_list, tree attributes)
 {
-  tree klass, decl;
+  tree klass = NULL_TREE;
+  tree decl;
 
 #ifdef OBJCPLUS
-  if (current_namespace != global_namespace) {
-    error ("Objective-C declarations may only appear in global scope");
-  }
+  if (current_namespace != global_namespace)
+    {
+      error ("Objective-C declarations may only appear in global scope");
+    }
 #endif /* OBJCPLUS */
 
   if (objc_implementation_context)
@@ -9442,8 +9489,14 @@ start_class (enum tree_code code, tree class_name, tree super_name,
       objc_implementation_context = NULL_TREE;
     }
 
-  klass = make_node (code);
-  TYPE_LANG_SLOT_1 (klass) = make_tree_vec (CLASS_LANG_SLOT_ELTS);
+  /* If this is a class extension, we'll be "reopening" the existing
+     CLASS_INTERFACE_TYPE, so in that case there is no need to create
+     a new node.  */
+  if (code != CATEGORY_INTERFACE_TYPE || super_name != NULL_TREE)
+    {
+      klass = make_node (code);
+      TYPE_LANG_SLOT_1 (klass) = make_tree_vec (CLASS_LANG_SLOT_ELTS);
+    }
 
   /* Check for existence of the super class, if one was specified.  Note
      that we must have seen an @interface, not just a @class.  If we
@@ -9473,9 +9526,12 @@ start_class (enum tree_code code, tree class_name, tree super_name,
        }
     }
 
-  CLASS_NAME (klass) = class_name;
-  CLASS_SUPER_NAME (klass) = super_name;
-  CLASS_CLS_METHODS (klass) = NULL_TREE;
+  if (code != CATEGORY_INTERFACE_TYPE || super_name != NULL_TREE)
+    {
+      CLASS_NAME (klass) = class_name;
+      CLASS_SUPER_NAME (klass) = super_name;
+      CLASS_CLS_METHODS (klass) = NULL_TREE;
+    }
 
   if (! objc_is_class_name (class_name)
       && (decl = lookup_name (class_name)))
@@ -9592,15 +9648,35 @@ start_class (enum tree_code code, tree class_name, tree super_name,
            if (TREE_DEPRECATED (class_category_is_assoc_with))
              warning (OPT_Wdeprecated_declarations, "class %qE is deprecated", 
                       class_name);
-           add_category (class_category_is_assoc_with, klass);
-         }
 
-       if (protocol_list)
-         CLASS_PROTOCOL_LIST (klass)
-           = lookup_and_install_protocols (protocol_list);
+           if (super_name == NULL_TREE)
+             {
+               /* This is a class extension.  Get the original
+                  interface, and continue working on it.  */
+               objc_in_class_extension = true;
+               klass = class_category_is_assoc_with;
+
+               if (protocol_list)
+                 {
+                   /* Append protocols to the original protocol
+                      list.  */
+                   CLASS_PROTOCOL_LIST (klass)
+                     = chainon (CLASS_PROTOCOL_LIST (klass),
+                                lookup_and_install_protocols (protocol_list));
+                 }
+             }
+           else
+             {
+               add_category (class_category_is_assoc_with, klass);
+               
+               if (protocol_list)
+                 CLASS_PROTOCOL_LIST (klass)
+                   = lookup_and_install_protocols (protocol_list);
+             }
+         }
       }
       break;
-
+       
     case CATEGORY_IMPLEMENTATION_TYPE:
       /* Reset for multiple classes per file.  */
       method_slot = 0;
@@ -9673,6 +9749,8 @@ continue_class (tree klass)
       }
     case CLASS_INTERFACE_TYPE:
       {
+       if (objc_in_class_extension)
+         return NULL_TREE;
 #ifdef OBJCPLUS
        push_lang_context (lang_name_c);
 #endif /* OBJCPLUS */
index 2ccdde3..afba479 100644 (file)
@@ -1,3 +1,18 @@
+2010-12-10  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       * objc.dg/class-extension-1.m: New.
+       * objc.dg/class-extension-2.m: New.
+       * objc.dg/class-extension-3.m: New.
+       * objc.dg/property/at-property-26.m: New.
+       * objc.dg/property/at-property-27.m: New.
+       * objc.dg/property/at-property-28.m: New.
+       * obj-c++.dg/class-extension-1.mm: New.
+       * obj-c++.dg/class-extension-2.mm: New.
+       * obj-c++.dg/class-extension-3.mm: New.
+       * obj-c++.dg/property/at-property-26.mm: New.
+       * obj-c++.dg/property/at-property-27.mm: New.
+       * obj-c++.dg/property/at-property-28.mm: New.   
+       
 2010-12-09  John David Anglin  <dave.anglin@nrc-cnrc.gc.ca>
 
        PR target/46057
diff --git a/gcc/testsuite/obj-c++.dg/class-extension-1.mm b/gcc/testsuite/obj-c++.dg/class-extension-1.mm
new file mode 100644 (file)
index 0000000..eab59c4
--- /dev/null
@@ -0,0 +1,30 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do compile } */
+
+/* This test tests the basic of class extensions.  */
+
+#include <objc/objc.h>
+
+@interface MyObject
+{
+  Class isa;
+}
+- (int) test;
+@end
+
+@interface MyObject ()
+- (int) test2;
+- (int) test3;
+@end
+
+@implementation MyObject
+- (int) test
+{
+  return 20;
+}
+- (int) test2
+{
+  return 20;
+}
+@end /* { dg-warning "incomplete implementation of class .MyObject." } */
+     /* { dg-warning "method definition for .-test3. not found" "" { target *-*-* } 29 } */
diff --git a/gcc/testsuite/obj-c++.dg/class-extension-2.mm b/gcc/testsuite/obj-c++.dg/class-extension-2.mm
new file mode 100644 (file)
index 0000000..79b126f
--- /dev/null
@@ -0,0 +1,56 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do compile } */
+
+/* This test tests class extensions and protocols.  */
+
+#include <objc/objc.h>
+
+/* First, a simple test where a plain class has a protocol attached to
+   it in a class extension.  */
+@interface MyObject
+{
+  Class isa;
+}
+@end
+
+@protocol MyProtocol
+- (void) test;
+@end
+
+@interface MyObject () <MyProtocol>
+@end
+
+@implementation MyObject
+@end /* { dg-warning "incomplete implementation of class .MyObject." } */
+     /* { dg-warning "method definition for .-test. not found" "" { target *-*-* } 24 } */
+     /* { dg-warning "class .MyObject. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 24 } */
+
+
+
+/* Second, a more interesting test where protocols are added from the
+   main class and from two different class extensions.  */
+@interface MyObject2 : MyObject <MyProtocol>
+@end
+
+@protocol MyProtocol2
+- (void) test2;
+@end
+
+@protocol MyProtocol3
+- (void) test3;
+@end
+
+@interface MyObject2 () <MyProtocol2>
+@end
+
+@interface MyObject2 () <MyProtocol3>
+@end
+
+@implementation MyObject2
+@end /* { dg-warning "incomplete implementation of class .MyObject2." } */
+     /* { dg-warning "method definition for .-test. not found" "" { target *-*-* } 50 } */
+     /* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 50 } */
+     /* { dg-warning "method definition for .-test2. not found" "" { target *-*-* } 50 } */
+     /* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol2. protocol" "" { target *-*-* } 50 } */
+     /* { dg-warning "method definition for .-test3. not found" "" { target *-*-* } 50 } */
+     /* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol3. protocol" "" { target *-*-* } 50 } */
diff --git a/gcc/testsuite/obj-c++.dg/class-extension-3.mm b/gcc/testsuite/obj-c++.dg/class-extension-3.mm
new file mode 100644 (file)
index 0000000..8feb5c9
--- /dev/null
@@ -0,0 +1,26 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do compile } */
+
+/* This test tests warnings on class extensions.  */
+
+#include <objc/objc.h>
+
+@interface MyObject
+{
+  Class isa;
+  int count;
+}
+- (int) test;
+@property int count; /* { dg-warning "originally specified here" } */
+@end
+
+@interface MyObject ()
+- (void) test; /* { dg-error "duplicate declaration of method .-test." } */
+@end
+
+@interface MyObject ()
+@end
+
+@interface MyObject ()
+@property int count; /* { dg-error "redeclaration of property .count." } */
+@end
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-26.mm b/gcc/testsuite/obj-c++.dg/property/at-property-26.mm
new file mode 100644 (file)
index 0000000..c45757e
--- /dev/null
@@ -0,0 +1,85 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do run } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+
+/* Test @properties in class extensions.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@end
+
+@protocol count4
+/* Use a different getters/setters, so that the only way to compile
+   object.countX is to find the actual @property.  */
+@property (getter=number4, setter=setNumber4:) int count4;
+@end
+
+@interface MySubClass : MyRootClass
+{
+  int count1;
+  int count2;
+  int count3;
+  int count4;
+}
+@property (getter=number1, setter=setNumber1:) int count1;
+@end
+
+@interface MySubClass ()
+@property (getter=number2, setter=setNumber2:) int count2;
+@end
+
+@interface MySubClass ()  <count4>
+@property (getter=number3, setter=setNumber3:) int count3;
+@end
+
+@implementation MySubClass
+@synthesize count1;
+@synthesize count2;
+- (int) number3
+{
+  return count3;
+}
+- (void) setNumber3: (int)value
+{
+  count3 = value;
+}
+@synthesize count4;
+@end
+
+int main (void)
+{
+  MySubClass *object = [[MySubClass alloc] init];
+
+  object.count1 = 20;
+  if (object.count1 != 20)
+    abort ();
+
+  object.count2 = 11;
+  if (object.count2 != 11)
+    abort ();
+
+  object.count3 = 19;
+  if (object.count3 != 19)
+    abort ();
+
+  object.count4 = 74;
+  if (object.count4 != 74)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-27.mm b/gcc/testsuite/obj-c++.dg/property/at-property-27.mm
new file mode 100644 (file)
index 0000000..7278346
--- /dev/null
@@ -0,0 +1,66 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do run } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+
+/* Test overriding a readonly @property with a readwrite one in a class extension.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@end
+
+@protocol count2
+/* Use a different getters/setters, so that the only way to compile
+   object.countX is to find the actual @property.  */
+@property (readonly, getter=number2) int count2;
+@end
+
+@interface MySubClass : MyRootClass
+{
+  int count1;
+  int count2;
+}
+@property (readonly, getter=number1) int count1;
+@end
+
+@interface MySubClass ()
+@property (readwrite, getter=number1, setter=setNumber1:) int count1;
+@end
+
+@interface MySubClass ()  <count2>
+@property (readwrite, getter=number2, setter=setNumber2:) int count2;
+@end
+
+@implementation MySubClass
+@synthesize count1;
+@synthesize count2;
+@end
+
+int main (void)
+{
+  MySubClass *object = [[MySubClass alloc] init];
+
+  object.count1 = 20;
+  if (object.count1 != 20)
+    abort ();
+
+  object.count2 = 11;
+  if (object.count2 != 11)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-28.mm b/gcc/testsuite/obj-c++.dg/property/at-property-28.mm
new file mode 100644 (file)
index 0000000..23b357c
--- /dev/null
@@ -0,0 +1,29 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do compile } */
+
+/* Test errors when extending a property in a class extension.  */
+
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
+@property (readonly, retain)    id property1; /* { dg-warning "originally specified here" } */
+@property (readonly)           int property2; /* { dg-warning "originally specified here" } */
+@property (readonly, getter=y) int property3; /* { dg-warning "originally specified here" } */
+@property (readonly)           int property4; /* Ok */
+@property (readonly)           int property5; /* { dg-warning "originally specified here" } */
+@end
+
+@interface MyRootClass ()
+@property (readwrite, copy)       id property1; /* { dg-warning "assign semantics attributes of property .property1. conflict with previous declaration" } */
+@property (readwrite, nonatomic) int property2; /* { dg-warning ".nonatomic. attribute of property .property2. conflicts with previous declaration" } */
+@property (readwrite, getter=x)  int property3; /* { dg-warning ".getter. attribute of property .property3. conflicts with previous declaration" } */
+@property (readwrite)            int property4; /* Ok */
+@property (readwrite)          float property5; /* { dg-warning "type of property .property5. conflicts with previous declaration" } */
+@end
+
+
+
diff --git a/gcc/testsuite/objc.dg/class-extension-1.m b/gcc/testsuite/objc.dg/class-extension-1.m
new file mode 100644 (file)
index 0000000..eab59c4
--- /dev/null
@@ -0,0 +1,30 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do compile } */
+
+/* This test tests the basic of class extensions.  */
+
+#include <objc/objc.h>
+
+@interface MyObject
+{
+  Class isa;
+}
+- (int) test;
+@end
+
+@interface MyObject ()
+- (int) test2;
+- (int) test3;
+@end
+
+@implementation MyObject
+- (int) test
+{
+  return 20;
+}
+- (int) test2
+{
+  return 20;
+}
+@end /* { dg-warning "incomplete implementation of class .MyObject." } */
+     /* { dg-warning "method definition for .-test3. not found" "" { target *-*-* } 29 } */
diff --git a/gcc/testsuite/objc.dg/class-extension-2.m b/gcc/testsuite/objc.dg/class-extension-2.m
new file mode 100644 (file)
index 0000000..79b126f
--- /dev/null
@@ -0,0 +1,56 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do compile } */
+
+/* This test tests class extensions and protocols.  */
+
+#include <objc/objc.h>
+
+/* First, a simple test where a plain class has a protocol attached to
+   it in a class extension.  */
+@interface MyObject
+{
+  Class isa;
+}
+@end
+
+@protocol MyProtocol
+- (void) test;
+@end
+
+@interface MyObject () <MyProtocol>
+@end
+
+@implementation MyObject
+@end /* { dg-warning "incomplete implementation of class .MyObject." } */
+     /* { dg-warning "method definition for .-test. not found" "" { target *-*-* } 24 } */
+     /* { dg-warning "class .MyObject. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 24 } */
+
+
+
+/* Second, a more interesting test where protocols are added from the
+   main class and from two different class extensions.  */
+@interface MyObject2 : MyObject <MyProtocol>
+@end
+
+@protocol MyProtocol2
+- (void) test2;
+@end
+
+@protocol MyProtocol3
+- (void) test3;
+@end
+
+@interface MyObject2 () <MyProtocol2>
+@end
+
+@interface MyObject2 () <MyProtocol3>
+@end
+
+@implementation MyObject2
+@end /* { dg-warning "incomplete implementation of class .MyObject2." } */
+     /* { dg-warning "method definition for .-test. not found" "" { target *-*-* } 50 } */
+     /* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 50 } */
+     /* { dg-warning "method definition for .-test2. not found" "" { target *-*-* } 50 } */
+     /* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol2. protocol" "" { target *-*-* } 50 } */
+     /* { dg-warning "method definition for .-test3. not found" "" { target *-*-* } 50 } */
+     /* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol3. protocol" "" { target *-*-* } 50 } */
diff --git a/gcc/testsuite/objc.dg/class-extension-3.m b/gcc/testsuite/objc.dg/class-extension-3.m
new file mode 100644 (file)
index 0000000..9564bf0
--- /dev/null
@@ -0,0 +1,26 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do compile } */
+
+/* This test tests warnings on class extensions.  */
+
+#include <objc/objc.h>
+
+@interface MyObject
+{
+  Class isa;
+  int count;
+}
+- (int) test;
+@property int count; /* { dg-message "originally specified here" } */
+@end
+
+@interface MyObject ()
+- (void) test; /* { dg-error "duplicate declaration of method .-test." } */
+@end
+
+@interface MyObject ()
+@end
+
+@interface MyObject ()
+@property int count; /* { dg-error "redeclaration of property .count." } */
+@end
diff --git a/gcc/testsuite/objc.dg/property/at-property-26.m b/gcc/testsuite/objc.dg/property/at-property-26.m
new file mode 100644 (file)
index 0000000..c45757e
--- /dev/null
@@ -0,0 +1,85 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do run } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+
+/* Test @properties in class extensions.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@end
+
+@protocol count4
+/* Use a different getters/setters, so that the only way to compile
+   object.countX is to find the actual @property.  */
+@property (getter=number4, setter=setNumber4:) int count4;
+@end
+
+@interface MySubClass : MyRootClass
+{
+  int count1;
+  int count2;
+  int count3;
+  int count4;
+}
+@property (getter=number1, setter=setNumber1:) int count1;
+@end
+
+@interface MySubClass ()
+@property (getter=number2, setter=setNumber2:) int count2;
+@end
+
+@interface MySubClass ()  <count4>
+@property (getter=number3, setter=setNumber3:) int count3;
+@end
+
+@implementation MySubClass
+@synthesize count1;
+@synthesize count2;
+- (int) number3
+{
+  return count3;
+}
+- (void) setNumber3: (int)value
+{
+  count3 = value;
+}
+@synthesize count4;
+@end
+
+int main (void)
+{
+  MySubClass *object = [[MySubClass alloc] init];
+
+  object.count1 = 20;
+  if (object.count1 != 20)
+    abort ();
+
+  object.count2 = 11;
+  if (object.count2 != 11)
+    abort ();
+
+  object.count3 = 19;
+  if (object.count3 != 19)
+    abort ();
+
+  object.count4 = 74;
+  if (object.count4 != 74)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/objc.dg/property/at-property-27.m b/gcc/testsuite/objc.dg/property/at-property-27.m
new file mode 100644 (file)
index 0000000..7278346
--- /dev/null
@@ -0,0 +1,66 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do run } */
+/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
+
+/* Test overriding a readonly @property with a readwrite one in a class extension.  */
+
+#include <stdlib.h>
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
++ (id) initialize;
++ (id) alloc;
+- (id) init;
+@end
+
+@implementation MyRootClass
++ (id) initialize { return self; }
++ (id) alloc { return class_createInstance (self, 0); }
+- (id) init { return self; }
+@end
+
+@protocol count2
+/* Use a different getters/setters, so that the only way to compile
+   object.countX is to find the actual @property.  */
+@property (readonly, getter=number2) int count2;
+@end
+
+@interface MySubClass : MyRootClass
+{
+  int count1;
+  int count2;
+}
+@property (readonly, getter=number1) int count1;
+@end
+
+@interface MySubClass ()
+@property (readwrite, getter=number1, setter=setNumber1:) int count1;
+@end
+
+@interface MySubClass ()  <count2>
+@property (readwrite, getter=number2, setter=setNumber2:) int count2;
+@end
+
+@implementation MySubClass
+@synthesize count1;
+@synthesize count2;
+@end
+
+int main (void)
+{
+  MySubClass *object = [[MySubClass alloc] init];
+
+  object.count1 = 20;
+  if (object.count1 != 20)
+    abort ();
+
+  object.count2 = 11;
+  if (object.count2 != 11)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/objc.dg/property/at-property-28.m b/gcc/testsuite/objc.dg/property/at-property-28.m
new file mode 100644 (file)
index 0000000..de51224
--- /dev/null
@@ -0,0 +1,29 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do compile } */
+
+/* Test errors when extending a property in a class extension.  */
+
+#include <objc/objc.h>
+#include <objc/runtime.h>
+
+@interface MyRootClass
+{
+  Class isa;
+}
+@property (readonly, retain)    id property1; /* { dg-message "originally specified here" } */
+@property (readonly)           int property2; /* { dg-message "originally specified here" } */
+@property (readonly, getter=y) int property3; /* { dg-message "originally specified here" } */
+@property (readonly)           int property4; /* Ok */
+@property (readonly)           int property5; /* { dg-message "originally specified here" } */
+@end
+
+@interface MyRootClass ()
+@property (readwrite, copy)       id property1; /* { dg-warning "assign semantics attributes of property .property1. conflict with previous declaration" } */
+@property (readwrite, nonatomic) int property2; /* { dg-warning ".nonatomic. attribute of property .property2. conflicts with previous declaration" } */
+@property (readwrite, getter=x)  int property3; /* { dg-warning ".getter. attribute of property .property3. conflicts with previous declaration" } */
+@property (readwrite)            int property4; /* Ok */
+@property (readwrite)          float property5; /* { dg-warning "type of property .property5. conflicts with previous declaration" } */
+@end
+
+
+