In gcc/objc/: 2010-12-30 Nicola Pero <nicola.pero@meta-innovation.com>
authorNicola Pero <nicola.pero@meta-innovation.com>
Thu, 30 Dec 2010 18:26:56 +0000 (18:26 +0000)
committerNicola Pero <nicola@gcc.gnu.org>
Thu, 30 Dec 2010 18:26:56 +0000 (18:26 +0000)
In gcc/objc/:
2010-12-30  Nicola Pero  <nicola.pero@meta-innovation.com>

* objc-act.c (objc_add_method): When emitting an error because a
method with the same name but conflicting types is found in the
same class or category interface, print a note with the location
of the original method.  Also, improved the error message to
clearly state that the conflict is due to conflicting types, and
produce it for protocols as well.  Emit an error if two identical
methods are declared in a protocol, but one is @required and the
other one is @optional.  When

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

* objc.dg/class-extension-3.m: Updated.
* objc.dg/method-1.m: Updated.
* objc.dg/method-conflict-1.m: New.
* objc.dg/method-conflict-2.m: New.
* obj-c++.dg/class-extension-3.mm: Updated.
* obj-c++.dg/method-8.mm: Updated.
* obj-c++.dg/method-conflict-1.mm: New.
* obj-c++.dg/method-conflict-2.mm: New.

From-SVN: r168350

gcc/objc/ChangeLog
gcc/objc/objc-act.c
gcc/testsuite/ChangeLog
gcc/testsuite/obj-c++.dg/class-extension-3.mm
gcc/testsuite/obj-c++.dg/method-8.mm
gcc/testsuite/obj-c++.dg/method-conflict-1.mm [new file with mode: 0644]
gcc/testsuite/obj-c++.dg/method-conflict-2.mm [new file with mode: 0644]
gcc/testsuite/objc.dg/class-extension-3.m
gcc/testsuite/objc.dg/method-1.m
gcc/testsuite/objc.dg/method-conflict-1.m [new file with mode: 0644]
gcc/testsuite/objc.dg/method-conflict-2.m [new file with mode: 0644]

index b717a946d0511a4f51d34fa2846e32a575aa13ef..43ef65d6ec9fda2bbacf40fb1ad66d212e049c5e 100644 (file)
@@ -1,4 +1,15 @@
-2010-12-30  Nicola Pero  <nicola@nicola.brainstorm.co.uk>
+2010-12-30  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       * objc-act.c (objc_add_method): When emitting an error because a
+       method with the same name but conflicting types is found in the
+       same class or category interface, print a note with the location
+       of the original method.  Also, improved the error message to
+       clearly state that the conflict is due to conflicting types, and
+       produce it for protocols as well.  Emit an error if two identical
+       methods are declared in a protocol, but one is @required and the
+       other one is @optional.  When
+
+2010-12-30  Nicola Pero  <nicola.pero@meta-innovation.com>
 
        * objc-act.c (start_class): Warn when a class attribute is
        ignored.
index a0a7a095eb424c6ba74dfa0c7907da8f366bd6e3..ec7fea59dd3334c3d69a491d751bc2ae319af5b4 100644 (file)
@@ -8898,22 +8898,69 @@ add_method_to_hash_list (hash *hash_list, tree method)
 static tree
 objc_add_method (tree klass, tree method, int is_class, bool is_optional)
 {
-  tree mth;
+  tree existing_method = NULL_TREE;
 
-  /* @optional methods are added to protocol's OPTIONAL list.  Note
-     that this disables checking that the methods are implemented by
-     classes implementing the protocol, since these checks only use
-     the CLASS_CLS_METHODS and CLASS_NST_METHODS.  */
-  if (is_optional)
+  /* The first thing we do is look up the method in the list of
+     methods already defined in the interface (or implementation).  */
+  if (is_class)
+    existing_method = lookup_method (CLASS_CLS_METHODS (klass), method);
+  else
+    existing_method = lookup_method (CLASS_NST_METHODS (klass), method);
+
+  /* In the case of protocols, we have a second list of methods to
+     consider, the list of optional ones.  */
+  if (TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE)
     {
-      gcc_assert (TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE);
-      if (!(mth = lookup_method (is_class
-                               ? PROTOCOL_OPTIONAL_CLS_METHODS (klass)
-                               : PROTOCOL_OPTIONAL_NST_METHODS (klass), 
-                                                               method)))
+      /* @required methods are added to the protocol's normal list.
+        @optional methods are added to the protocol's OPTIONAL lists.
+        Note that adding the methods to the optional lists disables
+        checking that the methods are implemented by classes
+        implementing the protocol, since these checks only use the
+        CLASS_CLS_METHODS and CLASS_NST_METHODS.  */
+
+      /* First of all, if the method to add is @optional, and we found
+        it already existing as @required, emit an error.  */
+      if (is_optional && existing_method)
+       {
+         error ("method %<%c%E%> declared %<@optional%> and %<@required%> at the same time",
+                (is_class ? '+' : '-'),
+                METHOD_SEL_NAME (existing_method));
+         inform (DECL_SOURCE_LOCATION (existing_method),
+                 "previous declaration of %<%c%E%> as %<@required%>",
+                 (is_class ? '+' : '-'),
+                 METHOD_SEL_NAME (existing_method));
+       }
+
+      /* Now check the list of @optional methods if we didn't find the
+        method in the @required list.  */
+      if (!existing_method)
        {
          if (is_class)
+           existing_method = lookup_method (PROTOCOL_OPTIONAL_CLS_METHODS (klass), method);
+         else
+           existing_method = lookup_method (PROTOCOL_OPTIONAL_NST_METHODS (klass), method);
+         
+         if (!is_optional && existing_method)
            {
+             error ("method %<%c%E%> declared %<@optional%> and %<@required%> at the same time",
+                    (is_class ? '+' : '-'),
+                    METHOD_SEL_NAME (existing_method));
+             inform (DECL_SOURCE_LOCATION (existing_method),
+                     "previous declaration of %<%c%E%> as %<@optional%>",
+                     (is_class ? '+' : '-'),
+                     METHOD_SEL_NAME (existing_method));
+           }
+       }
+    }
+
+  /* If the method didn't exist already, add it.  */
+  if (!existing_method)
+    {
+      if (is_optional)
+       {
+         if (is_class)
+           {
+             /* Put the method on the list in reverse order.  */
              TREE_CHAIN (method) = PROTOCOL_OPTIONAL_CLS_METHODS (klass);
              PROTOCOL_OPTIONAL_CLS_METHODS (klass) = method;
            }
@@ -8923,36 +8970,50 @@ objc_add_method (tree klass, tree method, int is_class, bool is_optional)
              PROTOCOL_OPTIONAL_NST_METHODS (klass) = method;
            }
        }
-    }
-  else if (!(mth = lookup_method (is_class
-                            ? CLASS_CLS_METHODS (klass)
-                            : CLASS_NST_METHODS (klass), method)))
-    {
-      /* put method on list in reverse order */
-      if (is_class)
-       {
-         DECL_CHAIN (method) = CLASS_CLS_METHODS (klass);
-         CLASS_CLS_METHODS (klass) = method;
-       }
       else
        {
-         DECL_CHAIN (method) = CLASS_NST_METHODS (klass);
-         CLASS_NST_METHODS (klass) = method;
+         if (is_class)
+           {
+             DECL_CHAIN (method) = CLASS_CLS_METHODS (klass);
+             CLASS_CLS_METHODS (klass) = method;
+           }
+         else
+           {
+             DECL_CHAIN (method) = CLASS_NST_METHODS (klass);
+             CLASS_NST_METHODS (klass) = method;
+           }
        }
     }
   else
     {
-      /* When processing an @interface for a class or category, give hard
-        errors on methods with identical selectors but differing argument
-        and/or return types. We do not do this for @implementations, because
-        C/C++ will do it for us (i.e., there will be duplicate function
-        definition errors).  */
+      /* The method was already defined.  Check that the types match
+        for an @interface for a class or category, or for a
+        @protocol.  Give hard errors on methods with identical
+        selectors but differing argument and/or return types.  We do
+        not do this for @implementations, because C/C++ will do it
+        for us (i.e., there will be duplicate function definition
+        errors).  */
       if ((TREE_CODE (klass) == CLASS_INTERFACE_TYPE
-          || TREE_CODE (klass) == CATEGORY_INTERFACE_TYPE)
-         && !comp_proto_with_proto (method, mth, 1))
-       error ("duplicate declaration of method %<%c%E%>",
-               is_class ? '+' : '-',
-               METHOD_SEL_NAME (mth));
+          || TREE_CODE (klass) == CATEGORY_INTERFACE_TYPE
+          /* Starting with GCC 4.6, we emit the same error for
+             protocols too.  The situation is identical to
+             @interfaces as there is no possible meaningful reason
+             for defining the same method with different signatures
+             in the very same @protocol.  If that was allowed,
+             whenever the protocol is used (both at compile and run
+             time) there wouldn't be any meaningful way to decide
+             which of the two method signatures should be used.  */
+          || TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE)
+         && !comp_proto_with_proto (method, existing_method, 1))
+       {
+         error ("duplicate declaration of method %<%c%E%> with conflicting types",
+                (is_class ? '+' : '-'),
+                METHOD_SEL_NAME (existing_method));
+         inform (DECL_SOURCE_LOCATION (existing_method),
+                 "previous declaration of %<%c%E%>",
+                 (is_class ? '+' : '-'),
+                 METHOD_SEL_NAME (existing_method));
+       }
     }
 
   if (is_class)
index a14d4160c67c17366003815743624edf987d0595..681c27ef6793760436606446ce909e5d5e1e34ee 100644 (file)
@@ -1,3 +1,14 @@
+2010-12-30  Nicola Pero  <nicola.pero@meta-innovation.com>
+       
+       * objc.dg/class-extension-3.m: Updated.
+       * objc.dg/method-1.m: Updated.
+       * objc.dg/method-conflict-1.m: New.
+       * objc.dg/method-conflict-2.m: New.     
+       * obj-c++.dg/class-extension-3.mm: Updated.
+       * obj-c++.dg/method-8.mm: Updated.
+       * obj-c++.dg/method-conflict-1.mm: New.
+       * obj-c++.dg/method-conflict-2.mm: New. 
+       
 2010-12-30  Joseph Myers  <joseph@codesourcery.com>
 
        PR c/46889
index 8feb5c9b6f20142ce1e47bdf89582986ecc08620..1d9d11b684e817b02809b102234d22ec840130db 100644 (file)
@@ -10,7 +10,7 @@
   Class isa;
   int count;
 }
-- (int) test;
+- (int) test;        /* { dg-warning "previous declaration" } */
 @property int count; /* { dg-warning "originally specified here" } */
 @end
 
index 310437a00235a842c669ea97b189e82c38222f91..11ec1751bb963c5d98c946fb1e7052880a7db06b 100644 (file)
@@ -2,12 +2,12 @@
 /* { dg-do compile } */
 
 @interface class1
-- (int) meth1;
+- (int) meth1;   /* { dg-error "previous declaration" } */
 - (void) meth1;  /* { dg-error "duplicate declaration of method .\\-meth1." } */
 @end
 
 @interface class2
-+ (void) meth1;
++ (void) meth1; /* { dg-error "previous declaration" } */
 + (int) meth1;  /* { dg-error "duplicate declaration of method .\\+meth1." } */
 @end
 
diff --git a/gcc/testsuite/obj-c++.dg/method-conflict-1.mm b/gcc/testsuite/obj-c++.dg/method-conflict-1.mm
new file mode 100644 (file)
index 0000000..9073125
--- /dev/null
@@ -0,0 +1,26 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+/* Test that you can not declare two methods, in the same protocol,
+   with the same name but conflicting method signatures.  */
+
+@protocol MyProtocol
++ (int) method1: (int)x;   /* { dg-error "previous declaration" } */
++ (float) method1: (int)x; /* { dg-error "duplicate declaration of method .\\+method1." } */
+
+- (int) method2: (int)x;   /* { dg-error "previous declaration" } */
+- (int) method2: (float)x; /* { dg-error "duplicate declaration of method .\\-method2." } */
+
+@optional
++ (int *) method3: (int)x;    /* { dg-error "previous declaration" } */
++ (int *) method3: (int **)x; /* { dg-error "duplicate declaration of method .\\+method3." } */
+
+- (id) method4: (id)x;   /* { dg-error "previous declaration" } */
+- (void) method4: (id)x; /* { dg-error "duplicate declaration of method .\\-method4." } */
+@end
+
+/* We don't test conflicting types between @required and @optional
+   methods, as that is tested in method-conflict-2.  */
+
diff --git a/gcc/testsuite/obj-c++.dg/method-conflict-2.mm b/gcc/testsuite/obj-c++.dg/method-conflict-2.mm
new file mode 100644 (file)
index 0000000..ad6023d
--- /dev/null
@@ -0,0 +1,34 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+/* Test that you can not declare two methods, in the same protocol,
+   with the same name and method signature, but one as @required and
+   once as @optional.  */
+
+/* First, @required conflicting with @optional.  */
+@protocol MyProtocol
+
+@optional
++ (void) method1: (id)x; /* { dg-error "previous declaration" } */
+- (id) method2: (long)x; /* { dg-error "previous declaration" } */
+
+@required
++ (void) method1: (id)x; /* { dg-error "declared .@optional. and .@required. at the same time" } */
+- (id) method2: (long)x; /* { dg-error "declared .@optional. and .@required. at the same time" } */
+
+@end
+
+/* Second, @optional conflicting with @required.  */
+@protocol MyProtocol2
+
+@required
++ (void) method3: (Class)x; /* { dg-error "previous declaration" } */
+- (id *) method4: (long)x;  /* { dg-error "previous declaration" } */
+
+@optional
++ (void) method3: (Class)x; /* { dg-error "declared .@optional. and .@required. at the same time" } */
+- (id *) method4: (long)x;  /* { dg-error "declared .@optional. and .@required. at the same time" } */
+
+@end
index 9564bf022cb583b25e940df211f11549990b758f..69e5705396989b4a739eed05f065f61c86664777 100644 (file)
@@ -10,7 +10,7 @@
   Class isa;
   int count;
 }
-- (int) test;
+- (int) test;        /* { dg-message "previous declaration" } */
 @property int count; /* { dg-message "originally specified here" } */
 @end
 
index ce2aab121293225fd8a3576f704052d8b4479a93..194c64fac4e04dcf3c6d92c4d4878d0c9fdfd476 100644 (file)
@@ -2,12 +2,12 @@
 /* { dg-do compile } */
 
 @interface class1
-- (int) meth1;
+- (int) meth1;   /* { dg-message "previous declaration" } */
 - (void) meth1;  /* { dg-error "duplicate declaration of method .\\-meth1." } */
 @end
 
 @interface class2
-+ (void) meth1;
++ (void) meth1; /* { dg-message "previous declaration" } */
 + (int) meth1;  /* { dg-error "duplicate declaration of method .\\+meth1." } */
 @end
 
diff --git a/gcc/testsuite/objc.dg/method-conflict-1.m b/gcc/testsuite/objc.dg/method-conflict-1.m
new file mode 100644 (file)
index 0000000..2cc96e4
--- /dev/null
@@ -0,0 +1,26 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+/* Test that you can not declare two methods, in the same protocol,
+   with the same name but conflicting method signatures.  */
+
+@protocol MyProtocol
++ (int) method1: (int)x;   /* { dg-message "previous declaration" } */
++ (float) method1: (int)x; /* { dg-error "duplicate declaration of method .\\+method1." } */
+
+- (int) method2: (int)x;   /* { dg-message "previous declaration" } */
+- (int) method2: (float)x; /* { dg-error "duplicate declaration of method .\\-method2." } */
+
+@optional
++ (int *) method3: (int)x;    /* { dg-message "previous declaration" } */
++ (int *) method3: (int **)x; /* { dg-error "duplicate declaration of method .\\+method3." } */
+
+- (id) method4: (id)x;   /* { dg-message "previous declaration" } */
+- (void) method4: (id)x; /* { dg-error "duplicate declaration of method .\\-method4." } */
+@end
+
+/* We don't test conflicting types between @required and @optional
+   methods, as that is tested in method-conflict-2.  */
+
diff --git a/gcc/testsuite/objc.dg/method-conflict-2.m b/gcc/testsuite/objc.dg/method-conflict-2.m
new file mode 100644 (file)
index 0000000..0b0612d
--- /dev/null
@@ -0,0 +1,34 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010.  */
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+
+/* Test that you can not declare two methods, in the same protocol,
+   with the same name and method signature, but one as @required and
+   once as @optional.  */
+
+/* First, @required conflicting with @optional.  */
+@protocol MyProtocol
+
+@optional
++ (void) method1: (id)x; /* { dg-message "previous declaration" } */
+- (id) method2: (long)x; /* { dg-message "previous declaration" } */
+
+@required
++ (void) method1: (id)x; /* { dg-error "declared .@optional. and .@required. at the same time" } */
+- (id) method2: (long)x; /* { dg-error "declared .@optional. and .@required. at the same time" } */
+
+@end
+
+/* Second, @optional conflicting with @required.  */
+@protocol MyProtocol2
+
+@required
++ (void) method3: (Class)x; /* { dg-message "previous declaration" } */
+- (id *) method4: (long)x;  /* { dg-message "previous declaration" } */
+
+@optional
++ (void) method3: (Class)x; /* { dg-error "declared .@optional. and .@required. at the same time" } */
+- (id *) method4: (long)x;  /* { dg-error "declared .@optional. and .@required. at the same time" } */
+
+@end