diff mbox

ObjC/ObjC++: Fix PR objc/47076 ("Protocol referenced in @interface declarations should be defined")

Message ID 054E99D3-F515-42E2-9A4D-A23C1F204744@meta-innovation.com
State New
Headers show

Commit Message

Nicola Pero Dec. 28, 2010, 4:57 p.m. UTC
This patch fixes PR objc/47076.

The main testcase is fairly clear:

@protocol Protocol;

@interface Interface <Protocol> /* { dg-warning "definition of  
protocol .Protocol. not found" } */
@end

It is important that the method definition is found, otherwise the  
compiler can't check that the class (or category)
implements all the required methods.  Apple GCC does warn there, and  
so does clang.  This patch fixes our
compiler to produce the warning too.

Ok to commit to trunk ?

Thanks

+/* TODO: I guess if MyProtocol3 is now used in an @interface, we
+   should check that all the protocols it references are defined
+   too ?  */

Comments

Mike Stump Dec. 28, 2010, 8:47 p.m. UTC | #1
On Dec 28, 2010, at 8:57 AM, Nicola Pero <nicola.pero@meta-innovation.com> wrote:
> This patch fixes PR objc/47076.

> Ok to commit to trunk ?

Ok.
diff mbox

Patch

Index: objc/ChangeLog
===================================================================
--- objc/ChangeLog      (revision 168294)
+++ objc/ChangeLog      (working copy)
@@ -1,3 +1,21 @@ 
+2010-12-28  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       PR objc/47076
+       * objc-act.c (lookup_protocol): Added 'definition_required'
+       argument.  If 'definition_required', and the protocol is not
+       defined, emit a warning.
+       (objc_declare_protocols): Updated call to lookup_protocol.
+       (start_protocol): Same change.
+       (check_protocol_recursively): Same change.
+       (objc_build_protocol_expr): Same change.
+       (lookup_and_install_protocols): Added definition_required  
argument.
+       Pass it to lookup_protocol.
+       (objc_get_protocol_qualified_type): Updated call to
+       lookup_and_install_protocols.
+       (start_class): Updated calls to lookup_and_install_protocols;  
pass
+       true to 'definition_required' to get the warnings.
+       (start_protocol): Updated calls to lookup_and_install_protocols.
+
  2010-12-28  Nicola Pero  <nicola.pero@meta-innovation.com>

         * objc-act.c (objc_start_category_interface): Produce an  
error if
Index: objc/objc-act.c
===================================================================
--- objc/objc-act.c     (revision 168294)
+++ objc/objc-act.c     (working copy)
@@ -232,8 +232,8 @@  static void build_selector_table_decl (v

  /* Protocols.  */

-static tree lookup_protocol (tree, bool);
-static tree lookup_and_install_protocols (tree);
+static tree lookup_protocol (tree, bool, bool);
+static tree lookup_and_install_protocols (tree, bool);

  /* Type encoding.  */

@@ -2923,7 +2923,8 @@  objc_get_protocol_qualified_type (tree i

        /* Look up protocols and install in lang specific list.  */
        DUP_TYPE_OBJC_INFO (type, TYPE_MAIN_VARIANT (type));
-      TYPE_OBJC_PROTOCOL_LIST (type) = lookup_and_install_protocols  
(protocols);
+      TYPE_OBJC_PROTOCOL_LIST (type) = lookup_and_install_protocols
+       (protocols, /* definition_required */ false);

        /* For RECORD_TYPEs, point to the @interface; for 'id' and  
'Class',
          return the pointer to the new pointee variant.  */
@@ -2951,7 +2952,8 @@  check_protocol_recursively (tree proto,
        tree pp = TREE_VALUE (p);

        if (TREE_CODE (pp) == IDENTIFIER_NODE)
-       pp = lookup_protocol (pp, /* warn if deprecated */ false);
+       pp = lookup_protocol (pp, /* warn if deprecated */ false,
+                             /* definition_required */ false);

        if (pp == proto)
         fatal_error ("protocol %qE has circular dependency",
@@ -2963,10 +2965,13 @@  check_protocol_recursively (tree proto,

  /* Look up PROTOCOLS, and return a list of those that are found.  If
     none are found, return NULL.  Note that this function will emit a
-   warning if a protocol is found and is deprecated.  */
-
+   warning if a protocol is found and is deprecated.  If
+   'definition_required', then warn if the protocol is found but is
+   not defined (ie, if we only saw a forward-declaration of the
+   protocol (as in "@protocol NSObject;") not a real definition with
+   the list of methods).  */
  static tree
-lookup_and_install_protocols (tree protocols)
+lookup_and_install_protocols (tree protocols, bool definition_required)
  {
    tree proto;
    tree return_value = NULL_TREE;
@@ -2977,7 +2982,8 @@  lookup_and_install_protocols (tree proto
    for (proto = protocols; proto; proto = TREE_CHAIN (proto))
      {
        tree ident = TREE_VALUE (proto);
-      tree p = lookup_protocol (ident, /* warn_if_deprecated */ true);
+      tree p = lookup_protocol (ident, /* warn_if_deprecated */ true,
+                               definition_required);

        if (p)
         return_value = chainon (return_value,
@@ -8417,7 +8423,8 @@  tree
  objc_build_protocol_expr (tree protoname)
  {
    tree expr;
-  tree p = lookup_protocol (protoname, /* warn if deprecated */ true);
+  tree p = lookup_protocol (protoname, /* warn if deprecated */ true,
+                           /* definition_required */ false);

    if (!p)
      {
@@ -9644,7 +9651,7 @@  start_class (enum tree_code code, tree c

        if (protocol_list)
         CLASS_PROTOCOL_LIST (klass)
-         = lookup_and_install_protocols (protocol_list);
+         = lookup_and_install_protocols (protocol_list, /*  
definition_required */ true);

        /* Determine if 'deprecated', the only attribute we recognize
          for classes, was used.  Ignore all other attributes for now,
@@ -9695,7 +9702,9 @@  start_class (enum tree_code code, tree c
                        list.  */
                     CLASS_PROTOCOL_LIST (klass)
                       = chainon (CLASS_PROTOCOL_LIST (klass),
-                                lookup_and_install_protocols  
(protocol_list));
+                                lookup_and_install_protocols
+                                (protocol_list,
+                                 /* definition_required */ true));
                   }
               }
             else
@@ -9704,7 +9713,8 @@  start_class (enum tree_code code, tree c

                 if (protocol_list)
                   CLASS_PROTOCOL_LIST (klass)
-                   = lookup_and_install_protocols (protocol_list);
+                   = lookup_and_install_protocols
+                   (protocol_list, /* definition_required */ true);
               }
           }
        }
@@ -10798,10 +10808,12 @@  add_protocol (tree protocol)
  }

  /* Looks up a protocol.  If 'warn_if_deprecated' is true, a warning is
-   emitted if the protocol is deprecated.  */
+   emitted if the protocol is deprecated.  If 'definition_required' is
+   true, a warning is emitted if a full @protocol definition has not
+   been seen.  */

  static tree
-lookup_protocol (tree ident, bool warn_if_deprecated)
+lookup_protocol (tree ident, bool warn_if_deprecated, bool  
definition_required)
  {
    tree chain;

@@ -10817,6 +10829,10 @@  lookup_protocol (tree ident, bool warn_i
                      PROTOCOL_NAME (chain));
           }

+       if (definition_required && !PROTOCOL_DEFINED (chain))
+         warning (0, "definition of protocol %qE not found",
+                  PROTOCOL_NAME (chain));
+
         return chain;
        }

@@ -10856,7 +10872,8 @@  objc_declare_protocols (tree names, tree
      {
        tree name = TREE_VALUE (list);

-      if (lookup_protocol (name, /* warn if deprecated */ false) ==  
NULL_TREE)
+      if (lookup_protocol (name, /* warn if deprecated */ false,
+                          /* definition_required */ false) ==  
NULL_TREE)
         {
           tree protocol = make_node (PROTOCOL_INTERFACE_TYPE);

@@ -10904,7 +10921,8 @@  start_protocol (enum tree_code code, tre
         }
      }

-  protocol = lookup_protocol (name, /* warn_if_deprecated */ false);
+  protocol = lookup_protocol (name, /* warn_if_deprecated */ false,
+                             /* definition_required */ false);

    if (!protocol)
      {
@@ -10912,7 +10930,7 @@  start_protocol (enum tree_code code, tre
        TYPE_LANG_SLOT_1 (protocol) = make_tree_vec  
(PROTOCOL_LANG_SLOT_ELTS);

        PROTOCOL_NAME (protocol) = name;
-      PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list);
+      PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list, / 
* definition_required */ false);
        add_protocol (protocol);
        PROTOCOL_DEFINED (protocol) = 1;
        PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
@@ -10922,7 +10940,7 @@  start_protocol (enum tree_code code, tre
    else if (! PROTOCOL_DEFINED (protocol))
      {
        PROTOCOL_DEFINED (protocol) = 1;
-      PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list);
+      PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list, / 
* definition_required */ false);

        check_protocol_recursively (protocol, list);
      }
Index: testsuite/ChangeLog
===================================================================
--- testsuite/ChangeLog (revision 168294)
+++ testsuite/ChangeLog (working copy)
@@ -1,5 +1,15 @@ 
  2010-12-28  Nicola Pero  <nicola.pero@meta-innovation.com>

+       PR objc/47076
+       * objc.dg/protocol-forward-1.m: New.
+       * obj-c++.dg/protocol-forward-1.mm: New.
+       * objc.dg/attributes/proto-attribute-2.m: Updated.
+       * objc.dg/class-protocol-1.m: Updated.
+       * obj-c++.dg/attributes/proto-attribute-2.mm: Updated.
+       * obj-c++.dg/class-protocol-1.mm: Updated.
+
+2010-12-28  Nicola Pero  <nicola.pero@meta-innovation.com>
+
         * objc.dg/class-extension-4.m: New.
         * obj-c++.dg/class-extension-4.mm: New.

Index: testsuite/objc.dg/attributes/proto-attribute-2.m
===================================================================
--- testsuite/objc.dg/attributes/proto-attribute-2.m    (revision  
168294)
+++ testsuite/objc.dg/attributes/proto-attribute-2.m    (working copy)
@@ -13,19 +13,6 @@  __attribute__ ((deprecated))

  @protocol NonDeprecatedProtocol1;

-
-@interface Class1 <DeprecatedProtocol1> /* { dg-warning "is  
deprecated" } */
-@end
-
-@interface Class2 <NonDeprecatedProtocol1>
-@end
-
-@interface Class3 <NonDeprecatedProtocol1, DeprecatedProtocol1> /*  
{ dg-warning "is deprecated" } */
-@end
-
-@interface Class2 (Category1) <DeprecatedProtocol1> /* { dg-warning  
"is deprecated" } */
-@end
-
  void function1 (id <DeprecatedProtocol1> object); /* { dg-warning  
"is deprecated" } */
  void function2 (id <NonDeprecatedProtocol1> object);

Index: testsuite/objc.dg/class-protocol-1.m
===================================================================
--- testsuite/objc.dg/class-protocol-1.m        (revision 168294)
+++ testsuite/objc.dg/class-protocol-1.m        (working copy)
@@ -175,7 +175,7 @@  testCategoryInherited(void)

  @protocol FwProto;

-@interface MyClass1 (Forward) <FwProto>
+@interface MyClass1 (Forward) <FwProto> /* { dg-warning "definition  
of protocol .FwProto. not found" } */
  @end

  Class <FwProto> clsP7 = 0;
Index: testsuite/objc.dg/protocol-forward-1.m
===================================================================
--- testsuite/objc.dg/protocol-forward-1.m      (revision 0)
+++ testsuite/objc.dg/protocol-forward-1.m      (revision 0)
@@ -0,0 +1,30 @@ 
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>,  
December 2010.  */
+/* { dg-do compile } */
+
+/* Test that all protocols appearing in @interface declarations are
+   real (ie, we saw a full @protocol definition with list of methods),
+   and not just forward-references (ie, "@protocol NSObject;").  */
+
+#include <objc/objc.h>
+
+@protocol MyProtocol;
+
+@protocol MyProtocol2
+- (int)method2;
+@end
+
+@interface MyClass <MyProtocol> /* { dg-warning "definition of  
protocol .MyProtocol. not found" } */
+@end
+
+@interface MyClass2 <MyProtocol2> /* Ok */
+@end
+
+@interface MyClass2 (Category) <MyProtocol>  /* { dg-warning  
"definition of protocol .MyProtocol. not found" } */
+@end
+
+@protocol MyProtocol3 <MyProtocol> /* Ok */
+@end
+
+/* TODO: I guess if MyProtocol3 is now used in an @interface, we
+   should check that all the protocols it references are defined
+   too ?  */
Index: testsuite/obj-c++.dg/attributes/proto-attribute-2.mm
===================================================================
--- testsuite/obj-c++.dg/attributes/proto-attribute-2.mm         
(revision 168294)
+++ testsuite/obj-c++.dg/attributes/proto-attribute-2.mm         
(working copy)
@@ -13,19 +13,6 @@  __attribute__ ((deprecated))

  @protocol NonDeprecatedProtocol1;

-
-@interface Class1 <DeprecatedProtocol1> /* { dg-warning "is  
deprecated" } */
-@end
-
-@interface Class2 <NonDeprecatedProtocol1>
-@end
-
-@interface Class3 <NonDeprecatedProtocol1, DeprecatedProtocol1> /*  
{ dg-warning "is deprecated" } */
-@end
-
-@interface Class2 (Category1) <DeprecatedProtocol1> /* { dg-warning  
"is deprecated" } */
-@end
-
  void function1 (id <DeprecatedProtocol1> object); /* { dg-warning  
"is deprecated" } */
  void function2 (id <NonDeprecatedProtocol1> object);

Index: testsuite/obj-c++.dg/class-protocol-1.mm
===================================================================
--- testsuite/obj-c++.dg/class-protocol-1.mm    (revision 168294)
+++ testsuite/obj-c++.dg/class-protocol-1.mm    (working copy)
@@ -1,4 +1,3 @@ 
-
  /* Check Class <protocol> types */
  /* Author: David Ayers <d.ayers@inode.at> */
  /* { dg-do compile } */
@@ -176,7 +175,7 @@  testCategoryInherited(void)

  @protocol FwProto;

-@interface MyClass1 (Forward) <FwProto>
+@interface MyClass1 (Forward) <FwProto> /* { dg-warning "definition  
of protocol .FwProto. not found" } */
  @end

  Class <FwProto> clsP7 = 0;
@@ -188,9 +187,9 @@ 
    [cls doItInstance7];      /* { dg-warning "no .\\+doItInstance7.  
method found" } */

    [clsP7 doItClass7];       /* { dg-warning "not found in  
protocol" } */
-  /* { dg-warning "no .\\+doItClass7. method found" "" { target *-*- 
* } 190 } */
+  /* { dg-warning "no .\\+doItClass7. method found" "" { target *-*- 
* } 189 } */
    [clsP7 doItInstance7];    /* { dg-warning "not found in  
protocol" } */
-  /* { dg-warning "no .\\+doItInstance7. method found" "" { target *- 
*-* } 192 } */
+  /* { dg-warning "no .\\+doItInstance7. method found" "" { target *- 
*-* } 191 } */

    [MyClass1 doItClass7];    /* { dg-warning "may not respond" } */
    [MyClass1 doItInstance7]; /* { dg-warning "may not respond" } */
Index: testsuite/obj-c++.dg/protocol-forward-1.mm
===================================================================
--- testsuite/obj-c++.dg/protocol-forward-1.mm  (revision 0)
+++ testsuite/obj-c++.dg/protocol-forward-1.mm  (revision 0)
@@ -0,0 +1,30 @@ 
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>,  
December 2010.  */
+/* { dg-do compile } */
+
+/* Test that all protocols appearing in @interface declarations are
+   real (ie, we saw a full @protocol definition with list of methods),
+   and not just forward-references (ie, "@protocol NSObject;").  */
+
+#include <objc/objc.h>
+
+@protocol MyProtocol;
+
+@protocol MyProtocol2
+- (int)method2;
+@end
+
+@interface MyClass <MyProtocol> /* { dg-warning "definition of  
protocol .MyProtocol. not found" } */
+@end
+
+@interface MyClass2 <MyProtocol2> /* Ok */
+@end
+
+@interface MyClass2 (Category) <MyProtocol>  /* { dg-warning  
"definition of protocol .MyProtocol. not found" } */
+@end
+
+@protocol MyProtocol3 <MyProtocol> /* Ok */
+@end
+