OSDN Git Service

In gcc/objc/:
authornicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 2 Jun 2011 18:54:32 +0000 (18:54 +0000)
committernicola <nicola@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 2 Jun 2011 18:54:32 +0000 (18:54 +0000)
2011-06-02  Nicola Pero  <nicola.pero@meta-innovation.com>

PR objc/48539
* objc-act.c (objc_finish_message_expr): Warn if messaging a class
that was only declared using @class without an @interface.  Warn
if messaging an instance of a class that was only declared using
@class without an @interface, unless the receiver was also typed
with a protocol list.

In gcc/testsuite/:
2011-06-02  Nicola Pero  <nicola.pero@meta-innovation.com>

PR objc/48539
* objc.dg/method-5.m: Updated.
* objc.dg/method-19.m: Updated.
* objc.dg/method-lookup-1.m: New.
* obj-c++.dg/method-6.mm: Updated.
* obj-c++.dg/method-7.mm: Updated.
* obj-c++.dg/method-lookup-1.mm: New.

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

gcc/objc/ChangeLog
gcc/objc/objc-act.c
gcc/testsuite/ChangeLog
gcc/testsuite/obj-c++.dg/method-6.mm
gcc/testsuite/obj-c++.dg/method-7.mm
gcc/testsuite/obj-c++.dg/method-lookup-1.mm [new file with mode: 0644]
gcc/testsuite/objc.dg/method-19.m
gcc/testsuite/objc.dg/method-5.m
gcc/testsuite/objc.dg/method-lookup-1.m [new file with mode: 0644]

index c52fcc3..50c80b5 100644 (file)
@@ -1,3 +1,12 @@
+2011-06-02  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       PR objc/48539
+       * objc-act.c (objc_finish_message_expr): Warn if messaging a class
+       that was only declared using @class without an @interface.  Warn
+       if messaging an instance of a class that was only declared using
+       @class without an @interface, unless the receiver was also typed
+       with a protocol list.
+
 2011-06-01  Nicola Pero  <nicola.pero@meta-innovation.com>
 
        * objc-act.c (objc_decl_method_attributes): Implement nonnull
index be65a53..e7acb7f 100644 (file)
@@ -5432,15 +5432,21 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params,
      from the implementation context).  */
   rtype = receiver;
   while (TREE_CODE (rtype) == COMPOUND_EXPR
-             || TREE_CODE (rtype) == MODIFY_EXPR
-             || CONVERT_EXPR_P (rtype)
-             || TREE_CODE (rtype) == COMPONENT_REF)
+        || TREE_CODE (rtype) == MODIFY_EXPR
+        || CONVERT_EXPR_P (rtype)
+        || TREE_CODE (rtype) == COMPONENT_REF)
     rtype = TREE_OPERAND (rtype, 0);
 
+  /* self is 1 if this is a message to self, 0 otherwise  */
   self = (rtype == self_decl);
+
+  /* super is 1 if this is a message to super, 0 otherwise.  */
   super = (rtype == UOBJC_SUPER_decl);
+
+  /* rtype is the type of the receiver.  */
   rtype = TREE_TYPE (receiver);
 
+  /* have_cast is 1 if the receiver is casted.  */
   have_cast = (TREE_CODE (receiver) == NOP_EXPR
               || (TREE_CODE (receiver) == COMPOUND_EXPR
                   && !IS_SUPER (rtype)));
@@ -5450,7 +5456,10 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params,
     should_call_super_dealloc = 0;
 
   /* If the receiver is a class object, retrieve the corresponding
-     @interface, if one exists. */
+     @interface, if one exists.  class_tree is the class name
+     identifier, or NULL_TREE if this is not a class method or the
+     class name could not be determined (as in the case "Class c; [c
+     method];").  */
   class_tree = receiver_is_class_object (receiver, self, super);
 
   /* Now determine the receiver type (if an explicit cast has not been
@@ -5458,7 +5467,27 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params,
   if (!have_cast)
     {
       if (class_tree)
-       rtype = lookup_interface (class_tree);
+       {
+         /* We are here when we have no cast, and we have a class
+            name.  So, this is a plain method to a class object, as
+            in [NSObject alloc].  Find the interface corresponding to
+            the class name.  */
+         rtype = lookup_interface (class_tree);
+
+         if (rtype == NULL_TREE)
+           {
+             /* If 'rtype' is NULL_TREE at this point it means that
+                we have seen no @interface corresponding to that
+                class name, only a @class declaration.  So, we have a
+                class name (class_tree) but no actual details of the
+                class methods.  We won't be able to check that the
+                class responds to the method, and we will have to
+                guess the method prototype.  Emit a warning, then
+                keep going (this will use any method with a matching
+                name, as if the receiver was of type 'Class').  */
+             warning (0, "@interface of class %qE not found", class_tree);
+           }
+       }
       /* Handle `self' and `super'.  */
       else if (super)
        {
@@ -5474,28 +5503,41 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params,
        rtype = lookup_interface (CLASS_NAME (implementation_template));
     }
 
-  /* If receiver is of type `id' or `Class' (or if the @interface for a
-     class is not visible), we shall be satisfied with the existence of
-     any instance or class method. */
   if (objc_is_id (rtype))
     {
+      /* The receiver is of type 'id' or 'Class' (with or without some
+        protocols attached to it).  */
+
+      /* We set class_tree to the identifier for 'Class' if this is a
+        class method, and to NULL_TREE if not.  */
       class_tree = (IS_CLASS (rtype) ? objc_class_name : NULL_TREE);
+      
+      /* 'rprotos' is the list of protocols that the receiver
+        supports.  */
       rprotos = (TYPE_HAS_OBJC_INFO (TREE_TYPE (rtype))
                 ? TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rtype))
                 : NULL_TREE);
+
+      /* We have no information on the type, and we set it to
+        NULL_TREE.  */
       rtype = NULL_TREE;
 
+      /* If there are any protocols, check that the method we are
+        calling appears in the protocol list.  If there are no
+        protocols, this is a message to 'id' or 'Class' and we accept
+        any method that exists.  */
       if (rprotos)
        {
-         /* If messaging 'id <Protos>' or 'Class <Proto>', first search
-            in protocols themselves for the method prototype.  */
+         /* If messaging 'id <Protos>' or 'Class <Proto>', first
+            search in protocols themselves for the method
+            prototype.  */
          method_prototype
            = lookup_method_in_protocol_list (rprotos, sel_name,
                                              class_tree != NULL_TREE);
 
-         /* If messaging 'Class <Proto>' but did not find a class method
-            prototype, search for an instance method instead, and warn
-            about having done so.  */
+         /* If messaging 'Class <Proto>' but did not find a class
+            method prototype, search for an instance method instead,
+            and warn about having done so.  */
          if (!method_prototype && !rtype && class_tree != NULL_TREE)
            {
              method_prototype
@@ -5509,6 +5551,8 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params,
     }
   else if (rtype)
     {
+      /* We have a receiver type which is more specific than 'id' or
+        'Class'.  */
       tree orig_rtype = rtype;
 
       if (TREE_CODE (rtype) == POINTER_TYPE)
@@ -5523,25 +5567,70 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params,
          rprotos = TYPE_OBJC_PROTOCOL_LIST (rtype);
          rtype = TYPE_OBJC_INTERFACE (rtype);
        }
-      /* If we could not find an @interface declaration, we must have
-        only seen a @class declaration; so, we cannot say anything
-        more intelligent about which methods the receiver will
-        understand. */
       if (!rtype || TREE_CODE (rtype) == IDENTIFIER_NODE)
        {
+         /* If we could not find an @interface declaration, we must
+            have only seen a @class declaration; so, we cannot say
+            anything more intelligent about which methods the
+            receiver will understand.  Note that this only happens
+            for instance methods; for class methods to a class where
+            we have only seen a @class declaration,
+            lookup_interface() above would have set rtype to
+            NULL_TREE.  */
+         if (rprotos)
+           {
+             /* We could not find an @interface declaration, yet, if
+                there are protocols attached to the type, we can
+                still look up the method in the protocols.  Ie, we
+                are in the following case:
+            
+                @class MyClass;
+                MyClass<MyProtocol> *x;
+                [x method];
+                
+                If 'MyProtocol' has the method 'method', we can check
+                and retrieve the method prototype.  */
+             method_prototype
+               = lookup_method_in_protocol_list (rprotos, sel_name, 0);
+
+             /* At this point, if we have found the method_prototype,
+                we are quite happy.  The details of the class are
+                irrelevant.  If we haven't found it, a warning will
+                have been produced that the method could not be found
+                in the protocol, and we won't produce further
+                warnings (please note that this means that "@class
+                MyClass; MyClass <MyProtocol> *x;" is exactly
+                equivalent to "id <MyProtocol> x", which isn't too
+                satisfactory but it's not easy to see how to do
+                better).  */
+           }
+         else
+           {
+             if (rtype)
+               {
+                 /* We could not find an @interface declaration, and
+                    there are no protocols attached to the receiver,
+                    so we can't complete the check that the receiver
+                    responds to the method, and we can't retrieve the
+                    method prototype.  But, because the receiver has
+                    a well-specified class, the programmer did want
+                    this check to be performed.  Emit a warning, then
+                    keep going as if it was an 'id'.  To remove the
+                    warning, either include an @interface for the
+                    class, or cast the receiver to 'id'.  Note that
+                    rtype is an IDENTIFIER_NODE at this point.  */
+                 warning (0, "@interface of class %qE not found", rtype);
+               }
+           }
+
          rtype = NULL_TREE;
-         /* We could not find an @interface declaration, yet Message maybe in a
-            @class's protocol. */
-         if (!method_prototype && rprotos)
-           method_prototype
-             = lookup_method_in_protocol_list (rprotos, sel_name, 0);
        }
       else if (TREE_CODE (rtype) == CLASS_INTERFACE_TYPE
          || TREE_CODE (rtype) == CLASS_IMPLEMENTATION_TYPE)
        {
-         /* We have a valid ObjC class name.  Look up the method name
-            in the published @interface for the class (and its
-            superclasses). */
+         /* We have a valid ObjC class name with an associated
+            @interface.  Look up the method name in the published
+            @interface for the class (and its superclasses).  */
          method_prototype
            = lookup_method_static (rtype, sel_name, class_tree != NULL_TREE);
 
@@ -5566,6 +5655,7 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params,
        }
       else
        {
+         /* We have a type, but it's not an Objective-C type (!).  */
          warning (0, "invalid receiver type %qs",
                   identifier_to_locale (gen_type_name (orig_rtype)));
          /* After issuing the "invalid receiver" warning, perform method
@@ -5573,11 +5663,13 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params,
          rtype = rprotos = NULL_TREE;
        }
     }
+  /* Note that rtype could also be NULL_TREE.  This happens if we are
+     messaging a class by name, but the class was only
+     forward-declared using @class.  */
 
-
-  /* For 'id' or 'Class' receivers, search in the global hash table
-     as a last resort.  For all receivers, warn if protocol searches
-     have failed.  */
+  /* For 'id' or 'Class' receivers, search in the global hash table as
+     a last resort.  For all receivers, warn if protocol searches have
+     failed.  */
   if (!method_prototype)
     {
       if (rprotos)
index 61f9f16..c6c4b06 100644 (file)
@@ -1,3 +1,13 @@
+2011-06-02  Nicola Pero  <nicola.pero@meta-innovation.com>
+
+       PR objc/48539
+       * objc.dg/method-5.m: Updated.  
+       * objc.dg/method-19.m: Updated.
+       * objc.dg/method-lookup-1.m: New.       
+       * obj-c++.dg/method-6.mm: Updated.
+       * obj-c++.dg/method-7.mm: Updated.
+       * obj-c++.dg/method-lookup-1.mm: New.   
+
 2011-06-02  DJ Delorie  <dj@redhat.com>
 
        * lib/timeout.exp (timeout): Add board_info support.
index 6c21e79..0e09922 100644 (file)
@@ -1,6 +1,5 @@
-/* The following should NOT generate "may not respond to" warnings,
-   since a forward-declared @class (instance) should be treated like a
-   'Class') ('id').  */
+/* The following should NOT generate "may not respond to" warnings, since a forward-declared
+   @class (instance) should be treated like a 'Class') ('id').  */
 
 /* { dg-do compile } */
 
@@ -9,11 +8,11 @@
 @class NotKnown;
 
 void foo(NotKnown *n) {
-  [NotKnown new];
-  [n nonexistent_method]; /* { dg-warning "no .\\-nonexistent_method. method found" } */
+  [NotKnown new];         /* { dg-warning ".interface of class .NotKnown. not found" } */
+  [n nonexistent_method]; /* { dg-warning ".interface of class .NotKnown. not found" } */
+                          /* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 12 } */
 }
 
 /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */
 /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 0 } */
 /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 0 } */
-
index e9e2d3a..85abf7d 100644 (file)
@@ -1,6 +1,5 @@
 /* Check if sending messages to "underspecified" objects is handled gracefully.  */
 /* Author: Ziemowit Laski <zlaski@apple.com>.  */
-
 /* { dg-do compile } */
 
 @class UnderSpecified;
@@ -10,10 +9,12 @@ typedef struct NotAClass {
 
 void foo(UnderSpecified *u, NotAClass *n) {
   [n nonexistent_method];    /* { dg-warning "invalid receiver type" } */
-       /* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 12 } */
+       /* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 11 } */
   [NotAClass nonexistent_method]; /* { dg-error ".NotAClass. is not an Objective\\-C class name or alias" } */
-  [u nonexistent_method]; /* { dg-warning "no .\\-nonexistent_method. method found" } */
-  [UnderSpecified nonexistent_method]; /* { dg-warning "no .\\+nonexistent_method. method found" } */
+  [u nonexistent_method];    /* { dg-warning ".interface of class .UnderSpecified. not found" } */
+                             /* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 14 } */
+  [UnderSpecified nonexistent_method]; /* { dg-warning ".interface of class .UnderSpecified. not found" } */
+                                       /* { dg-warning "no .\\+nonexistent_method. method found" "" { target *-*-* } 16 } */
 }
 
 /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/obj-c++.dg/method-lookup-1.mm b/gcc/testsuite/obj-c++.dg/method-lookup-1.mm
new file mode 100644 (file)
index 0000000..47499c3
--- /dev/null
@@ -0,0 +1,94 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, June 2011.  */
+/* { dg-do compile } */
+
+@class NotKnown;
+
+@protocol MyProtocol
++ (id) classMethod;
+- (id) instanceMethod;
+@end
+
+@protocol MyProtocol2
++ (id) classMethod2;
+- (id) instanceMethod2;
+@end
+
+void test (Class x, Class <MyProtocol> y, id w, id <MyProtocol> z, NotKnown *a, NotKnown <MyProtocol> *b)
+{
+  /* "Class x" means that "x" responds to any class methods, and may
+     also respond to instance methods because instance methods of the
+     root class are class methods.  */
+  [x classMethod]; /* No warning here.  */
+
+  [x instanceMethod]; /* No warning here.  */
+
+
+  /* "Class <MyProtocol> y" means that "y" responds to any class
+     methods specified in the protocol MyProtocol, but not to other
+     class or instance methods.  If a class method is not found, an
+     instance method from the protocol may be used instead but that is
+     suspicious and gets a warning.  */
+  [y classMethod]; /* No warning here.  */
+
+  [y instanceMethod]; /* { dg-warning "found .\\-instanceMethod. instead of .\\+instanceMethod. in protocol" } */
+
+  [y classMethod2]; /* { dg-warning ".\\+classMethod2. not found in protocol" } */
+
+  [y instanceMethod2]; /* { dg-warning ".\\+instanceMethod2. not found in protocol" } */
+
+
+  /* If a class is specified by name, the @interface must be available
+     to check what it responds to.  */
+  [NotKnown classMethod]; /* { dg-warning ".interface of class .NotKnown. not found" } */
+
+
+  /* "id w" means that "w" responds to anything, both class and
+     instance methods.  */
+  [w instanceMethod]; /* No warning here.  */
+
+  [w instanceMethod2]; /* No warning here.  */
+
+  [w classMethod]; /* No warning here.  */
+
+  [w classMethod2]; /* No warning here.  */
+
+
+  /* "id <MyProtocol> z" means that "z" responds to any instance
+     methods in the protocol, but not class methods.  To select class
+     methods, you use "Class <MyProtocol> z".  */
+  [z instanceMethod]; /* No warning here.  */
+
+  [z instanceMethod2]; /* { dg-warning ".\\-instanceMethod2. not found in protocol" } */
+
+  [z classMethod];     /* { dg-warning ".\\-classMethod. not found in protocol" } */
+
+  [z classMethod2];    /* { dg-warning ".\\-classMethod2. not found in protocol" } */
+
+
+  /* "NotKnown *a" means that "a" is an instance of NotKnown.  Since
+     the programmer explicitly specified the class name, it must be
+     because they expect the compiler to do type-checking; the
+     @interface must be available to do this check, otherwise the
+     compiler does not know what "a" responds to.  */
+  [a instanceMethod];  /* { dg-warning ".interface of class .NotKnown. not found" } */
+
+  /* But, if you cast it to "id", then you're disabling type-checking
+     and the warnings should go away.  */
+  [(id)a instanceMethod]; /* No warning here.  */
+
+
+  /* "NotKnown <MyProtocol> *b" means that "a" is an instance of
+     NotKnown, and also implements protocol <MyProtocol>.  If you send
+     a message that is part of the protocol, then the compiler can do
+     type-checking and all is fine.  */
+  [b instanceMethod];
+
+  /* But if you send a message that is not part of the protocol, then
+     you'll get a warning that the method can not be found in the
+     protocol.  */
+  [b instanceMethod2]; /* { dg-warning ".\\-instanceMethod2. not found in protocol" } */ 
+
+  /* But, if you cast it to "id", then you're disabling type-checking
+     and the warnings should go away.  */
+  [(id)b instanceMethod2]; /* No warning here.  */
+}
index 362d558..0e09922 100644 (file)
@@ -8,8 +8,9 @@
 @class NotKnown;
 
 void foo(NotKnown *n) {
-  [NotKnown new];
-  [n nonexistent_method]; /* { dg-warning "no .\\-nonexistent_method. method found" } */
+  [NotKnown new];         /* { dg-warning ".interface of class .NotKnown. not found" } */
+  [n nonexistent_method]; /* { dg-warning ".interface of class .NotKnown. not found" } */
+                          /* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 12 } */
 }
 
 /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */
index 9fa8cb6..85abf7d 100644 (file)
@@ -11,8 +11,10 @@ void foo(UnderSpecified *u, NotAClass *n) {
   [n nonexistent_method];    /* { dg-warning "invalid receiver type" } */
        /* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 11 } */
   [NotAClass nonexistent_method]; /* { dg-error ".NotAClass. is not an Objective\\-C class name or alias" } */
-  [u nonexistent_method]; /* { dg-warning "no .\\-nonexistent_method. method found" } */
-  [UnderSpecified nonexistent_method]; /* { dg-warning "no .\\+nonexistent_method. method found" } */
+  [u nonexistent_method];    /* { dg-warning ".interface of class .UnderSpecified. not found" } */
+                             /* { dg-warning "no .\\-nonexistent_method. method found" "" { target *-*-* } 14 } */
+  [UnderSpecified nonexistent_method]; /* { dg-warning ".interface of class .UnderSpecified. not found" } */
+                                       /* { dg-warning "no .\\+nonexistent_method. method found" "" { target *-*-* } 16 } */
 }
 
 /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 0 } */
diff --git a/gcc/testsuite/objc.dg/method-lookup-1.m b/gcc/testsuite/objc.dg/method-lookup-1.m
new file mode 100644 (file)
index 0000000..47499c3
--- /dev/null
@@ -0,0 +1,94 @@
+/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, June 2011.  */
+/* { dg-do compile } */
+
+@class NotKnown;
+
+@protocol MyProtocol
++ (id) classMethod;
+- (id) instanceMethod;
+@end
+
+@protocol MyProtocol2
++ (id) classMethod2;
+- (id) instanceMethod2;
+@end
+
+void test (Class x, Class <MyProtocol> y, id w, id <MyProtocol> z, NotKnown *a, NotKnown <MyProtocol> *b)
+{
+  /* "Class x" means that "x" responds to any class methods, and may
+     also respond to instance methods because instance methods of the
+     root class are class methods.  */
+  [x classMethod]; /* No warning here.  */
+
+  [x instanceMethod]; /* No warning here.  */
+
+
+  /* "Class <MyProtocol> y" means that "y" responds to any class
+     methods specified in the protocol MyProtocol, but not to other
+     class or instance methods.  If a class method is not found, an
+     instance method from the protocol may be used instead but that is
+     suspicious and gets a warning.  */
+  [y classMethod]; /* No warning here.  */
+
+  [y instanceMethod]; /* { dg-warning "found .\\-instanceMethod. instead of .\\+instanceMethod. in protocol" } */
+
+  [y classMethod2]; /* { dg-warning ".\\+classMethod2. not found in protocol" } */
+
+  [y instanceMethod2]; /* { dg-warning ".\\+instanceMethod2. not found in protocol" } */
+
+
+  /* If a class is specified by name, the @interface must be available
+     to check what it responds to.  */
+  [NotKnown classMethod]; /* { dg-warning ".interface of class .NotKnown. not found" } */
+
+
+  /* "id w" means that "w" responds to anything, both class and
+     instance methods.  */
+  [w instanceMethod]; /* No warning here.  */
+
+  [w instanceMethod2]; /* No warning here.  */
+
+  [w classMethod]; /* No warning here.  */
+
+  [w classMethod2]; /* No warning here.  */
+
+
+  /* "id <MyProtocol> z" means that "z" responds to any instance
+     methods in the protocol, but not class methods.  To select class
+     methods, you use "Class <MyProtocol> z".  */
+  [z instanceMethod]; /* No warning here.  */
+
+  [z instanceMethod2]; /* { dg-warning ".\\-instanceMethod2. not found in protocol" } */
+
+  [z classMethod];     /* { dg-warning ".\\-classMethod. not found in protocol" } */
+
+  [z classMethod2];    /* { dg-warning ".\\-classMethod2. not found in protocol" } */
+
+
+  /* "NotKnown *a" means that "a" is an instance of NotKnown.  Since
+     the programmer explicitly specified the class name, it must be
+     because they expect the compiler to do type-checking; the
+     @interface must be available to do this check, otherwise the
+     compiler does not know what "a" responds to.  */
+  [a instanceMethod];  /* { dg-warning ".interface of class .NotKnown. not found" } */
+
+  /* But, if you cast it to "id", then you're disabling type-checking
+     and the warnings should go away.  */
+  [(id)a instanceMethod]; /* No warning here.  */
+
+
+  /* "NotKnown <MyProtocol> *b" means that "a" is an instance of
+     NotKnown, and also implements protocol <MyProtocol>.  If you send
+     a message that is part of the protocol, then the compiler can do
+     type-checking and all is fine.  */
+  [b instanceMethod];
+
+  /* But if you send a message that is not part of the protocol, then
+     you'll get a warning that the method can not be found in the
+     protocol.  */
+  [b instanceMethod2]; /* { dg-warning ".\\-instanceMethod2. not found in protocol" } */ 
+
+  /* But, if you cast it to "id", then you're disabling type-checking
+     and the warnings should go away.  */
+  [(id)b instanceMethod2]; /* No warning here.  */
+}