public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Your 'Class <Protocol>' Work
@ 2004-09-27 19:35 Ziemowit Laski
  2004-09-28  9:01 ` David Ayers
  0 siblings, 1 reply; 35+ messages in thread
From: Ziemowit Laski @ 2004-09-27 19:35 UTC (permalink / raw)
  To: David Ayers; +Cc: GCC Patches

Hi David,

The ObjC++ integration work is held up at the moment :-(, so perhaps 
this would be a good
time for you to integrate your changes into mainline?  You can get it 
to work for
ObjC now, and we can revisit ObjC++ later.

What do you think?

--Zem

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-27 19:35 Your 'Class <Protocol>' Work Ziemowit Laski
@ 2004-09-28  9:01 ` David Ayers
  2004-09-28 19:52   ` David Ayers
  0 siblings, 1 reply; 35+ messages in thread
From: David Ayers @ 2004-09-28  9:01 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: GCC Patches

Ziemowit Laski wrote:
> Hi David,
> 
> The ObjC++ integration work is held up at the moment :-(, so perhaps 
> this would be a good
> time for you to integrate your changes into mainline?  You can get it to 
> work for
> ObjC now, and we can revisit ObjC++ later.
> 
> What do you think?

I'll get right to it!

Cheers,
David

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-28  9:01 ` David Ayers
@ 2004-09-28 19:52   ` David Ayers
  2004-09-28 19:56     ` Ziemowit Laski
  2004-09-28 20:04     ` David Ayers
  0 siblings, 2 replies; 35+ messages in thread
From: David Ayers @ 2004-09-28 19:52 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 583 bytes --]

David Ayers wrote:

> Ziemowit Laski wrote:
> 
>>Hi David,
>>
>>The ObjC++ integration work is held up at the moment :-(, so perhaps 
>>this would be a good
>>time for you to integrate your changes into mainline?  You can get it to 
>>work for
>>ObjC now, and we can revisit ObjC++ later.
>>

OK, this has been bubble strapped and regtested for ObjC on
i686-pc-linux-gnu after bootstrap of cvs today.  I'll run a full
bootstrap of c,objc,c++ tonight and regtest everything again tomorrow.

The patch.tar.gz contains the 4 text files in case of mailer problems.

Cheers,
David Ayers


[-- Attachment #2: ChangeLog --]
[-- Type: text/plain, Size: 0 bytes --]



[-- Attachment #3: ChangeLog.test --]
[-- Type: text/plain, Size: 0 bytes --]



[-- Attachment #4: protocol.patch --]
[-- Type: text/plain, Size: 0 bytes --]



[-- Attachment #5: class-protocol-1.m --]
[-- Type: text/plain, Size: 0 bytes --]



[-- Attachment #6: patch.tar.gz --]
[-- Type: application/x-gunzip, Size: 7307 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-28 19:52   ` David Ayers
@ 2004-09-28 19:56     ` Ziemowit Laski
  2004-09-28 20:04     ` David Ayers
  1 sibling, 0 replies; 35+ messages in thread
From: Ziemowit Laski @ 2004-09-28 19:56 UTC (permalink / raw)
  To: David Ayers; +Cc: GCC Patches


On 28 Sep 2004, at 12.03, David Ayers wrote:

> David Ayers wrote:
>
>> Ziemowit Laski wrote:
>>
>>> Hi David,
>>>
>>> The ObjC++ integration work is held up at the moment :-(, so perhaps
>>> this would be a good
>>> time for you to integrate your changes into mainline?  You can get 
>>> it to
>>> work for
>>> ObjC now, and we can revisit ObjC++ later.
>>>
>
> OK, this has been bubble strapped and regtested for ObjC on
> i686-pc-linux-gnu after bootstrap of cvs today.  I'll run a full
> bootstrap of c,objc,c++ tonight and regtest everything again tomorrow.

Thanks;  I'll take this for a spin on Darwin as well.

--Zem

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-28 19:52   ` David Ayers
  2004-09-28 19:56     ` Ziemowit Laski
@ 2004-09-28 20:04     ` David Ayers
  2004-09-28 20:13       ` Ziemowit Laski
  2004-09-29  3:27       ` Ziemowit Laski
  1 sibling, 2 replies; 35+ messages in thread
From: David Ayers @ 2004-09-28 20:04 UTC (permalink / raw)
  To: zlaski; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 309 bytes --]

David Ayers wrote:

> 
> OK, this has been bubble strapped and regtested for ObjC on
> i686-pc-linux-gnu after bootstrap of cvs today.  I'll run a full
> bootstrap of c,objc,c++ tonight and regtest everything again tomorrow.
> 

Hmm. seems the files got truncated somehow.  Let's try again...

Cheers,
David


[-- Attachment #2: ChangeLog --]
[-- Type: text/plain, Size: 1111 bytes --]

2004-09-28  David Ayers  <d.ayers@inode.at>

	* c-common.h: Remove RID_ID.
	* c-parse.in: Remove OBJECTNAME and references to RID_ID.
	(typespec_reserved_attr): Add rule for TYPENAME
	non_empty_protocolrefs.
	(yylexname) Remove special handling of RID_ID.
	* objc/objc-act.h (PROTOCOL_DECLARED_BY_ROOT): New macro.
	(IS_PROTOCOL_QUALIFIED_CLASS): Likewise.
	* objc/objc-act.c (mark_protocols_declared_by_root_class)
	(instance_prototype_of_root_protocol)
	(objc_comptypes_proto_proto): Add new functions.
	(objc_finish_interface): Register instance prototypes as class
	prototypes if the interface context is a protocol which has
	previously been referenced by a root class.
	(objc_comptypes): Handle protocol qualified class types.
	(objc_get_protocol_qualified_type): Report error for unknown types
	with protocol qualifiers.  Update documentation.
	(objc_finish_message_expr): Extend prototype search for protocol
	qualified class types.
	(start_class): Call mark_protocols_declared_by_root_class if
	processing a root class with protocol references.

	(lookup_and_install_protocols): Update documentation.


[-- Attachment #3: ChangeLog.test --]
[-- Type: text/plain, Size: 87 bytes --]

2004-09-28  David Ayers  <d.ayers@inode.at>

	* objc.dg/class-protocol-1.m: New test.


[-- Attachment #4: protocol.patch --]
[-- Type: text/plain, Size: 19135 bytes --]

Index: gcc/c-common.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.264
diff -u -r1.264 c-common.h
--- gcc/c-common.h	10 Sep 2004 23:56:18 -0000	1.264
+++ gcc/c-common.h	28 Sep 2004 18:23:00 -0000
@@ -92,7 +92,7 @@
   RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST,
 
   /* Objective-C */
-  RID_ID,          RID_AT_ENCODE,    RID_AT_END,
+  RID_AT_ENCODE,    RID_AT_END,
   RID_AT_CLASS,    RID_AT_ALIAS,     RID_AT_DEFS,
   RID_AT_PRIVATE,  RID_AT_PROTECTED, RID_AT_PUBLIC,
   RID_AT_PROTOCOL, RID_AT_SELECTOR,  
Index: gcc/c-parse.in
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-parse.in,v
retrieving revision 1.242
diff -u -r1.242 c-parse.in
--- gcc/c-parse.in	17 Sep 2004 18:17:59 -0000	1.242
+++ gcc/c-parse.in	28 Sep 2004 18:23:01 -0000
@@ -180,7 +180,7 @@
    Objective C, so that the token codes are the same in both.  */
 %token AT_INTERFACE AT_IMPLEMENTATION AT_END AT_SELECTOR AT_DEFS AT_ENCODE
 %token CLASSNAME AT_PUBLIC AT_PRIVATE AT_PROTECTED AT_PROTOCOL
-%token OBJECTNAME AT_CLASS AT_ALIAS
+%token AT_CLASS AT_ALIAS
 %token AT_THROW AT_TRY AT_CATCH AT_FINALLY AT_SYNCHRONIZED
 %token OBJC_STRING
 
@@ -261,7 +261,7 @@
 %type <ttype> selectorarg keywordnamelist keywordname objcencodeexpr
 %type <ttype> non_empty_protocolrefs protocolrefs identifier_list objcprotocolexpr
 
-%type <ttype> CLASSNAME OBJECTNAME OBJC_STRING OBJC_TYPE_QUAL
+%type <ttype> CLASSNAME OBJC_STRING OBJC_TYPE_QUAL
 
 %type <ttype> superclass objc_quals objc_qual objc_typename
 %type <itype> objc_try_catch_stmt optellipsis
@@ -474,7 +474,6 @@
 	IDENTIFIER
 	| TYPENAME
 @@ifobjc
-	| OBJECTNAME
 	| CLASSNAME
 @@end_ifobjc
 	;
@@ -1274,7 +1273,7 @@
 @@ifobjc
 	| CLASSNAME protocolrefs
 		{ $$ = objc_get_protocol_qualified_type ($1, $2); }
-	| OBJECTNAME protocolrefs
+	| TYPENAME non_empty_protocolrefs
 		{ $$ = objc_get_protocol_qualified_type ($1, $2); }
 
 /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>"
@@ -1549,10 +1548,6 @@
 		{ $$ = make_pointer_declarator ($2, $3); }
 	| TYPENAME
 		{ $$ = build_id_declarator ($1); }
-@@ifobjc
-	| OBJECTNAME
-		{ $$ = build_id_declarator ($1); }
-@@end_ifobjc
 	;
 
 /* Kinds of declarator that can appear in a parameter list
@@ -1571,10 +1566,6 @@
 		{ $$ = set_array_declarator_inner ($2, $1, false); }
 	| TYPENAME
 		{ $$ = build_id_declarator ($1); }
-@@ifobjc
-	| OBJECTNAME
-		{ $$ = build_id_declarator ($1); }
-@@end_ifobjc
 	;
 
 parm_declarator_nostarttypename:
@@ -2861,7 +2852,6 @@
 	  IDENTIFIER
 	| TYPENAME
 	| CLASSNAME
-	| OBJECTNAME
 	| reservedwords
 	;
 
@@ -3127,7 +3117,6 @@
   { "while",		RID_WHILE,	0 },
 
 @@ifobjc
-  { "id",		RID_ID,			D_OBJC },
 
   /* These objc keywords are recognized only immediately after
      an '@'.  */
@@ -3273,7 +3262,6 @@
   /* RID_STATCAST */	0,
 
   /* Objective C */
-  /* RID_ID */			OBJECTNAME,
   /* RID_AT_ENCODE */		AT_ENCODE,
   /* RID_AT_END */		AT_END,
   /* RID_AT_CLASS */		AT_CLASS,
@@ -3342,15 +3330,6 @@
       enum rid rid_code = C_RID_CODE (yylval.ttype);
 
 @@ifobjc
-      /* Turn non-typedefed refs to "id" into plain identifiers; this
-	 allows constructs like "void foo(id id);" to work.  */
-      if (rid_code == RID_ID)
-      {
-	decl = lookup_name (yylval.ttype);
-	if (decl == NULL_TREE || TREE_CODE (decl) != TYPE_DECL)
-	  return IDENTIFIER;
-      }
-
       if (!OBJC_IS_AT_KEYWORD (rid_code)
 	  && (!OBJC_IS_PQ_KEYWORD (rid_code) || objc_pq_context))
 @@end_ifobjc
@@ -3513,7 +3492,6 @@
     {
     case IDENTIFIER:
     case TYPENAME:
-    case OBJECTNAME:
     case TYPESPEC:
     case TYPE_QUAL:
     case SCSPEC:
Index: gcc/objc/objc-act.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.248
diff -u -r1.248 objc-act.c
--- gcc/objc/objc-act.c	24 Sep 2004 23:15:33 -0000	1.248
+++ gcc/objc/objc-act.c	28 Sep 2004 18:23:05 -0000
@@ -236,6 +236,8 @@
 static tree lookup_protocol (tree);
 static void check_protocol_recursively (tree, tree);
 static tree lookup_and_install_protocols (tree);
+static void mark_protocols_declared_by_root_class (tree, int);
+static tree instance_prototype_of_root_protocol (tree, tree, int);
 
 /* Type encoding.  */
 
@@ -712,6 +714,28 @@
 objc_finish_interface (void)
 {
   finish_class (objc_interface_context);
+
+  if (TREE_CODE (objc_interface_context) == PROTOCOL_INTERFACE_TYPE
+      && PROTOCOL_DECLARED_BY_ROOT (objc_interface_context))
+    {
+      tree protocol = objc_interface_context;
+      tree method_decl;
+
+      /* Since we do not have a protocol list,
+	 go ahead and register the method list directly.  */
+      for (method_decl = PROTOCOL_NST_METHODS (protocol);
+	   method_decl;
+	   method_decl = TREE_CHAIN (method_decl))
+	{
+	  add_method_to_hash_list(cls_method_hash_list,  method_decl);
+	}
+
+      /* This protocol is marked.  Now insure that that all instance
+	 prototypes of inherited protocols get registered as class
+	 methods without marking them.  */
+      mark_protocols_declared_by_root_class (PROTOCOL_LIST (protocol), 1);
+    }
+
   objc_interface_context = NULL_TREE;
 }
 
@@ -836,6 +860,84 @@
 }
 
 /* Return 1 if LHS and RHS are compatible types for assignment or
+   various other operations.  Return 0 if they are incompatible.
+   When the operation is REFLEXIVE (typically comparisons), check 
+   for compatibility in either direction; when it's not (typically 
+   assignments), don't.
+
+   This is ja helper function for objc_comptypes to be able to test 
+   two protocol qualified types of the same basic type to insure 
+   protocol conformance and to emit the necessary warnings.
+*/
+
+static inline
+int objc_comptypes_proto_proto(tree lhs, tree rhs, int reflexive)
+{
+  tree lproto, lproto_list = TYPE_PROTOCOL_LIST (lhs);
+  tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs);
+  tree p;
+
+  gcc_assert((IS_ID (lhs) && IS_ID (rhs))
+	     || (IS_CLASS (lhs) && IS_CLASS (rhs)));
+
+  if (!reflexive)
+    {
+      /* An assignment between two objects both either of type 'id <Protocol>' 
+	 or both 'Class <Protocol>; make sure the protocol on the lhs is
+	 supported by the object on the rhs.  */
+      for (lproto = lproto_list; lproto;
+	   lproto = TREE_CHAIN (lproto))
+	{
+	  p = TREE_VALUE (lproto);
+	  rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+	  if (!rproto)
+	    warning
+	      ("%s does not conform to the `%s' protocol",
+	       IS_ID(lhs) ? "object" : "class",
+	       IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+	}
+      return 1;
+    }
+  else
+    {
+      /* Obscure case - a comparison between two objects either both
+	 of type 'id <Protocol>' or both 'Class <protocol>'.  Check 
+	 that either the protocol on the lhs is supported by the object on
+	 the rhs, or viceversa.  */
+
+      /* Check if the protocol on the lhs is supported by the
+	 object on the rhs.  */
+      for (lproto = lproto_list; lproto;
+	   lproto = TREE_CHAIN (lproto))
+	{
+	  p = TREE_VALUE (lproto);
+	  rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+	  if (!rproto)
+	    {
+	      /* Check failed - check if the protocol on the rhs
+		 is supported by the object on the lhs.  */
+	      for (rproto = rproto_list; rproto;
+		   rproto = TREE_CHAIN (rproto))
+		{
+		  p = TREE_VALUE (rproto);
+		  lproto = lookup_protocol_in_reflist (lproto_list, p);
+
+		  if (!lproto)
+		    {
+		      /* This check failed too: incompatible  */
+		      return 0;
+		    }
+		}
+	      return 1;
+	    }
+	}
+      return 1;
+    }
+}
+
+/* Return 1 if LHS and RHS are compatible types for assignment or
    various other operations.  Return 0 if they are incompatible, and
    return -1 if we choose to not decide (because the types are really
    just C types, not ObjC specific ones).  When the operation is
@@ -866,76 +968,21 @@
       && TREE_CODE (rhs) == POINTER_TYPE
       && TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE)
     {
-      int lhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (lhs);
-      int rhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (rhs);
+      int lhs_is_proto_id = IS_PROTOCOL_QUALIFIED_ID (lhs);
+      int rhs_is_proto_id = IS_PROTOCOL_QUALIFIED_ID (rhs);
+      int lhs_is_proto_class = IS_PROTOCOL_QUALIFIED_CLASS (lhs);
+      int rhs_is_proto_class = IS_PROTOCOL_QUALIFIED_CLASS (rhs);
 
-      if (lhs_is_proto)
+      if (lhs_is_proto_id)
         {
 	  tree lproto, lproto_list = TYPE_PROTOCOL_LIST (lhs);
 	  tree rproto, rproto_list;
 	  tree p;
 
 	  /* <Protocol> = <Protocol>  */
-	  if (rhs_is_proto)
-	    {
-	      rproto_list = TYPE_PROTOCOL_LIST (rhs);
-
-	      if (!reflexive)
-		{
-		  /* An assignment between objects of type 'id
-		     <Protocol>'; make sure the protocol on the lhs is
-		     supported by the object on the rhs.  */
-		  for (lproto = lproto_list; lproto;
-		       lproto = TREE_CHAIN (lproto))
-		    {
-		      p = TREE_VALUE (lproto);
-		      rproto = lookup_protocol_in_reflist (rproto_list, p);
-
-		      if (!rproto)
-			warning
-			  ("object does not conform to the `%s' protocol",
-			   IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
-		    }
-		  return 1;
-		}
-	      else
-		{
-		  /* Obscure case - a comparison between two objects
-		     of type 'id <Protocol>'.  Check that either the
-		     protocol on the lhs is supported by the object on
-		     the rhs, or viceversa.  */
-
-		  /* Check if the protocol on the lhs is supported by the
-		     object on the rhs.  */
-		  for (lproto = lproto_list; lproto;
-		       lproto = TREE_CHAIN (lproto))
-		    {
-		      p = TREE_VALUE (lproto);
-		      rproto = lookup_protocol_in_reflist (rproto_list, p);
+	  if (rhs_is_proto_id)
+	    return objc_comptypes_proto_proto (lhs, rhs, reflexive);
 
-		      if (!rproto)
-			{
-			  /* Check failed - check if the protocol on the rhs
-			     is supported by the object on the lhs.  */
-			  for (rproto = rproto_list; rproto;
-			       rproto = TREE_CHAIN (rproto))
-			    {
-			      p = TREE_VALUE (rproto);
-			      lproto = lookup_protocol_in_reflist (lproto_list,
-								   p);
-
-			      if (!lproto)
-				{
-				  /* This check failed too: incompatible  */
-				  return 0;
-				}
-			    }
-			  return 1;
-			}
-		    }
-		  return 1;
-		}
-	    }
 	  /* <Protocol> = <class> *  */
 	  else if (TYPED_OBJECT (TREE_TYPE (rhs)))
 	    {
@@ -998,7 +1045,7 @@
 	  /* <Protocol> = ?? : let comptypes decide.  */
           return -1;
         }
-      else if (rhs_is_proto)
+      else if (rhs_is_proto_id)
 	{
 	  /* <class> * = <Protocol> */
 	  if (TYPED_OBJECT (TREE_TYPE (lhs)))
@@ -1078,6 +1125,46 @@
 	      return -1;
 	    }
 	}
+      else if (lhs_is_proto_class)
+	{
+	  /* Class <Protocol> = Class <Protocol>  */
+	  if (rhs_is_proto_class)
+	    return objc_comptypes_proto_proto (lhs, rhs, reflexive);
+
+	  /* Class <Protocol> = <class> *  */
+	  else if (TYPED_OBJECT (TREE_TYPE (rhs)))
+	    return 0;
+
+	  /* Class <Protocol> = Class */
+	  else if (objc_is_class_id (TREE_TYPE (rhs)))
+	    return 1;
+
+	  /* Class <Protocol> = id && Class <Protocol> = <Protocol> */
+	  else if (objc_is_object_id (TREE_TYPE (rhs)))
+	    return (rhs_is_proto_id ? 0 : 1);
+
+	  /* <Protocol> = ?? : let comptypes decide.  */
+	  else
+	    return -1;
+	}
+      else if (rhs_is_proto_class)
+	{
+	  /* <class> * = Class <Protocol> */
+	  if (TYPED_OBJECT (TREE_TYPE (lhs)))
+	    return 0;
+
+	  /* id = Class <Protocol> && <Protocol> = Class <Protocol> */
+	  else if (objc_is_object_id (TREE_TYPE (lhs)))
+	    return (lhs_is_proto_id ? 0 : 1);
+
+	  /* Class = Class <Protocol> */
+	  else if (objc_is_class_id (TREE_TYPE (lhs)))
+	    return 1;
+
+	  /* ??? = Class <Protocol> : let comptypes decide */
+	  else
+	    return -1;
+	}
       else
 	{
 	  /* Attention: we shouldn't defer to comptypes here.  One bad
@@ -1164,7 +1251,7 @@
 
 /* Construct a PROTOCOLS-qualified variant of INTERFACE, where INTERFACE may
    either name an Objective-C class, or refer to the special 'id' or 'Class'
-   types.  If INTERFACE is not a valid ObjC type, just return it unchanged.  */
+   types.  If INTERFACE is not a valid ObjC type, report error.  */
 
 tree
 objc_get_protocol_qualified_type (tree interface, tree protocols)
@@ -1180,7 +1267,7 @@
       if (type)
 	type = xref_tag (RECORD_TYPE, type);
       else
-        return interface;
+        error ("protocol qualifiers specified for non-Objective-C type");
     }
 
   if (protocols)
@@ -1222,8 +1309,10 @@
     }
 }
 
-/* Look up PROTOCOLS, and return a list of those that are found.
-   If none are found, return NULL.  */
+/* Look up PROTOCOLS, a list of identifiers, and return the list
+   of the protocol interface declarations that are found.  Invokes error
+   for each identifier for which the lookup failed.
+   If PROTOCOLS is empty, return NULL.  */
 
 static tree
 lookup_and_install_protocols (tree protocols)
@@ -1247,6 +1336,93 @@
   return return_value;
 }
 
+/* Iterates over the protocol interface list RPROTOS marking each as
+   PROTOCOL_DECLARED_BY_ROOT.  Registers the instance methods prototypes
+   of each protocol and their inherited protocols recursively as
+   potential class methods.  IGNORE should always be 0.  It is used
+   for recursive calls to insure that inherited protocols will not be
+   marked unduly.  */
+
+static void
+mark_protocols_declared_by_root_class (tree rprotos, int ignore)
+{
+  tree protocol_ch;
+  tree protocol;
+
+  for (protocol_ch = rprotos;
+       protocol_ch;
+       protocol_ch = TREE_CHAIN (protocol_ch))
+    {
+      protocol = TREE_CHECK(TREE_VALUE (protocol_ch),
+			    PROTOCOL_INTERFACE_TYPE);
+
+      /* Minor efficency check.  Expect all protocols which have
+	 been previously marked, to have had their methods registered.
+	 A protocol which itself is not declared by a root class yet
+	 is inherited by multiple root classes will have its instance
+	 methods processed redundantly, but it does not seem worth while
+	 to flag them just to avoid this.  */
+      if (!PROTOCOL_DECLARED_BY_ROOT (protocol))
+	{
+	  tree method_decl;
+
+	  for (method_decl = PROTOCOL_NST_METHODS (protocol);
+	       method_decl;
+	       method_decl = TREE_CHAIN (method_decl))
+	    {
+	      add_method_to_hash_list(cls_method_hash_list,  method_decl);
+	    }
+	}
+
+      if (!ignore)
+	PROTOCOL_DECLARED_BY_ROOT (protocol) = 1;
+
+      mark_protocols_declared_by_root_class (PROTOCOL_LIST (protocol), 1);
+    }
+}
+
+/* Searches for SELECTOR in the instance methods
+   of the protocol interface list RPROTOS.  Returns
+   the prototype only if the corresponding protocol from RPROTOS
+   is declared by any root class.  IGNORE should always be 0.
+   It is used for the recursive prototype search of inherited protocols.  */
+
+static tree
+instance_prototype_of_root_protocol (tree rprotos, tree selector, int ignore)
+{
+  tree protocol_ch;
+  tree protocol;
+  tree prototype = NULL_TREE;
+
+  /* Loop over protocol list and search for protocols
+     that declare the method as an instance method.  */
+  for (protocol_ch = rprotos;
+       protocol_ch;
+       protocol_ch = TREE_CHAIN (protocol_ch))
+    {
+      protocol = TREE_CHECK(TREE_VALUE (protocol_ch),
+			    PROTOCOL_INTERFACE_TYPE);
+
+      if (ignore || PROTOCOL_DECLARED_BY_ROOT (protocol))
+	{
+	  /* Check the protocol itself.  */
+	  prototype = lookup_method (PROTOCOL_NST_METHODS (protocol),
+				     selector);
+	  if (prototype)
+	    return prototype;
+
+	  /* Search prototypes of inherited protocols independent of mark.  */
+	  prototype
+	    = instance_prototype_of_root_protocol (PROTOCOL_LIST (protocol),
+						   selector, 1);
+	  if (prototype)
+	    return prototype;
+	}
+    }
+  return prototype;
+}
+
+
 /* Create a declaration for field NAME of a given TYPE.  */
 
 static tree
@@ -5569,14 +5745,24 @@
 	}
       else
 	{
+	  rprotos = TYPE_PROTOCOL_LIST (rtype);
 	  class_tree = objc_class_name;
 	  OBJC_SET_TYPE_NAME (rtype, class_tree);
+
+	  if (rprotos)
+	    rtype = NULL_TREE;
 	}
 
       if (rprotos)
-	method_prototype
-	  = lookup_method_in_protocol_list (rprotos, sel_name,
-					    class_tree != NULL_TREE);
+	{
+	  method_prototype
+	    = lookup_method_in_protocol_list (rprotos, sel_name,
+					      class_tree != NULL_TREE);
+	  if (!method_prototype && class_tree != NULL_TREE)
+	    method_prototype
+	      = instance_prototype_of_root_protocol(rprotos, sel_name, 0);
+	}
+
       if (!method_prototype && !rprotos)
 	method_prototype
 	  = lookup_method_in_hash_lists (sel_name,
@@ -6680,8 +6866,14 @@
         add_class (class);
 
       if (protocol_list)
-	CLASS_PROTOCOL_LIST (class)
-	  = lookup_and_install_protocols (protocol_list);
+	{
+	  CLASS_PROTOCOL_LIST (class)
+	    = lookup_and_install_protocols (protocol_list);
+
+	  if (!CLASS_SUPER_NAME (class))
+	    mark_protocols_declared_by_root_class (CLASS_PROTOCOL_LIST (class),
+						   0);
+	}
     }
 
   else if (code == CATEGORY_INTERFACE_TYPE)
@@ -6702,8 +6894,14 @@
         add_category (class_category_is_assoc_with, class);
 
       if (protocol_list)
-	CLASS_PROTOCOL_LIST (class)
-	  = lookup_and_install_protocols (protocol_list);
+	{
+	  CLASS_PROTOCOL_LIST (class)
+	    = lookup_and_install_protocols (protocol_list);
+
+	  if (!CLASS_SUPER_NAME (class_category_is_assoc_with))
+	    mark_protocols_declared_by_root_class (CLASS_PROTOCOL_LIST (class),
+						   0);
+	}
     }
 
   else if (code == CATEGORY_IMPLEMENTATION_TYPE)
Index: gcc/objc/objc-act.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/objc/objc-act.h,v
retrieving revision 1.31
diff -u -r1.31 objc-act.h
--- gcc/objc/objc-act.h	22 Sep 2004 01:13:07 -0000	1.31
+++ gcc/objc/objc-act.h	28 Sep 2004 18:23:08 -0000
@@ -37,6 +37,14 @@
 #define CLASS_LANG_SLOT_ELTS		5
 #define PROTOCOL_LANG_SLOT_ELTS		2
 
+/*
+  Objective-C usage for TREE_LANG_FLAG_?:
+
+  0: PROTOCOL_DECLARED_BY_ROOT - (valid for PROTOCOL_INTERFACE_TYPE)
+     Marks protocol declarations that are declared by root classes
+     so that instance methods are also checked for Class references.
+*/
+
 /* KEYWORD_DECL */
 #define KEYWORD_KEY_NAME(DECL) ((DECL)->decl.name)
 #define KEYWORD_ARG_NAME(DECL) ((DECL)->decl.arguments)
@@ -66,6 +74,7 @@
 #define PROTOCOL_CLS_METHODS(CLASS) ((CLASS)->type.maxval)
 #define PROTOCOL_FORWARD_DECL(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 1)
 #define PROTOCOL_DEFINED(CLASS) TREE_USED (CLASS)
+#define PROTOCOL_DECLARED_BY_ROOT(CLASS) TREE_LANG_FLAG_0 (CLASS)
 
 /* We need to distinguish TYPE_PROTOCOL_LISTs from TYPE_CONTEXTs, both of which
    are stored in the same accessor slot.  */
@@ -279,6 +288,8 @@
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == TREE_TYPE (objc_class_type))
 #define IS_PROTOCOL_QUALIFIED_ID(TYPE) \
   (IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE))
+#define IS_PROTOCOL_QUALIFIED_CLASS(TYPE) \
+  (IS_CLASS (TYPE) && TYPE_PROTOCOL_LIST (TYPE))
 #define IS_SUPER(TYPE) \
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == objc_super_template)
 

[-- Attachment #5: class-protocol-1.m --]
[-- Type: text/plain, Size: 7485 bytes --]

/* Check Class <protocol> types */
/* Author: David Ayers <d.ayers@inode.at> */
/* { dg-do compile } */

#include <objc/objc.h>
#include <objc/objc-api.h>

@protocol MyProto1
+(void)doItClass1;
-(void)doItInstance1;
@end

@protocol MyProto2
+(void)doItClass2;
-(void)doItInstance2;
@end

@interface MyClass1 <MyProto1>
{
  Class isa;
}
@end
@implementation MyClass1
+(void)doItClass1{}
-(void)doItInstance1{}
@end

@interface MyClass2 : MyClass1 <MyProto2>
@end
@implementation MyClass2
+(void)doItClass2{}
-(void)doItInstance2{}
@end

/*----------------------------------------*/

Class cls = 0;
Class <MyProto1> clsP1 = 0;
Class <MyProto2> clsP2 = 0;

void
testSimple(void)
{
  [cls doItClass1];
  [cls doItInstance1]; /* Do not warn as root Class declares this.  */
  [cls doItClass2];
  [cls doItInstance2]; /* { dg-warning "may not respond" } */

  [clsP1 doItClass1];
  [clsP1 doItInstance1]; /* Do not warn as root Class declares this.  */
  [clsP1 doItClass2];    /* { dg-warning "not implemented by protocol" } */
  [clsP1 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [clsP2 doItClass1];    /* { dg-warning "not implemented by protocol" } */
  [clsP2 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
  [clsP2 doItClass2];
  [clsP2 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass1];
  [MyClass1 doItInstance1];
  [MyClass1 doItClass2];    /* { dg-warning "may not respond to" } */
  [MyClass1 doItInstance2]; /* { dg-warning "may not respond to" } */

  [MyClass2 doItClass1];
  [MyClass2 doItInstance1];
  [MyClass2 doItClass2];
  [MyClass2 doItInstance2]; /* { dg-warning "may not respond to" } */

}

/*----------------------------------------*/
/* Protocols declared by categories */

@protocol MyProto3
+(void)doItClass3;
-(void)doItInstance3;
@end
@protocol MyProto4
+(void)doItClass4;
-(void)doItInstance4;
@end

@interface MyClass1 (Category1) <MyProto3>
@end
@interface MyClass2 (Category2) <MyProto4>
@end

void
testCategory(void)
{
  [cls doItClass3];
  [cls doItInstance3];      /* Do not warn as root Class declares this.  */
  [cls doItClass4];
  [cls doItInstance4];      /* { dg-warning "may not respond" } */

  [MyClass1 doItClass3];
  [MyClass1 doItInstance3];
  [MyClass1 doItClass4];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance4]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass3];
  [MyClass2 doItInstance3];
  [MyClass2 doItClass4];
  [MyClass2 doItInstance4]; /* { dg-warning "may not respond" } */

}

/*----------------------------------------*/
/* Inherited protocols declared by categories */

@protocol MyProto5 <MyProto1>
+(void)doItClass5;
-(void)doItInstance5;
@end

@protocol MyProto6 <MyProto2>
+(void)doItClass6;
-(void)doItInstance6;
@end

@interface MyClass1 (Category3) <MyProto5>
@end
@interface MyClass2 (Category4) <MyProto6>
@end

Class <MyProto5> clsP5 = 0;
Class <MyProto6> clsP6 = 0;

void
testCategoryInherited(void)
{
  [cls doItClass5];
  [cls doItInstance5]; /* Do not warn as root Class declares this.  */
  [cls doItClass6];
  [cls doItInstance6]; /* { dg-warning "may not respond" } */

  [clsP5 doItClass1];
  [clsP5 doItInstance1];
  [clsP5 doItClass2];    /* { dg-warning "not implemented by protocol" } */
  [clsP5 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [clsP6 doItClass1];    /* { dg-warning "not implemented by protocol" } */
  [clsP6 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
  [clsP6 doItClass2];
  [clsP6 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass5];
  [MyClass1 doItInstance5]; /* Do not warn as root Class declares this.  */
  [MyClass1 doItClass6];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance6]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass5];
  [MyClass2 doItInstance5]; /* Do not warn as root Class declares this.  */
  [MyClass2 doItClass6];
  [MyClass2 doItInstance6]; /* { dg-warning "may not respond" } */

}

/*----------------------------------------*/
/* Forward declared root protocols */

@protocol FwProto;

@interface MyClass1 (Forward) <FwProto>
@end

Class <FwProto> clsP7 = 0;

void
testForwardeDeclared1(void)
{
  [cls doItClass7];         /* { dg-warning "may not respond" } */
  [cls doItInstance7];      /* { dg-warning "may not respond" } */

  [clsP7 doItClass7];       /* { dg-warning "not implemented by protocol" } */
  [clsP7 doItInstance7];    /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass7];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance7]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass7];    /* { dg-warning "may not respond" } */
  [MyClass2 doItInstance7]; /* { dg-warning "may not respond" } */

}

@protocol FwProto
+(void)doItClass7;
-(void)doItInstance7;
@end

void
testForwardeDeclared2(void)
{
  [cls doItClass7];
  [cls doItInstance7];   /* Do not warn as root Class declares this.  */

  [clsP7 doItClass7];    
  [clsP7 doItInstance7]; /* Do not warn as root Class declares this.  */

  [MyClass1 doItClass7];
  [MyClass1 doItInstance7];

  [MyClass2 doItClass7];
  [MyClass2 doItInstance7];
}

/*----------------------------------------*/
/* Inherited non root protocols */

@protocol MyProto8
+(void)doItClass8;
-(void)doItInstance8;
@end

@protocol MyProto9 <MyProto8>
+(void)doItClass9;
-(void)doItInstance9;
@end

@interface MyClass1 (InheritedNonRoot) <MyProto9>
@end

Class <MyProto8> clsP8 = 0;
Class <MyProto9> clsP9 = 0;

void
testInheritedNonRoot(void)
{
  [cls doItClass8];
  [cls doItInstance8]; /* Do not warn as root Class declares super.  */
  [cls doItClass9];
  [cls doItInstance9]; /* Do not warn as root Class declares this.  */

  [clsP8 doItClass8];
  [clsP8 doItInstance8]; /* { dg-warning "not implemented by protocol" } */
  [clsP8 doItClass9];    /* { dg-warning "not implemented by protocol" } */
  [clsP8 doItInstance9]; /* { dg-warning "not implemented by protocol" } */

  [clsP9 doItClass8];
  [clsP9 doItInstance8];
  [clsP9 doItClass9];
  [clsP9 doItInstance9];

  [MyClass1 doItClass8];
  [MyClass1 doItInstance8]; /* Do not warn as root Class declares this.  */
  [MyClass1 doItClass9];
  [MyClass1 doItInstance9];

  [MyClass2 doItClass8];
  [MyClass2 doItInstance8]; /* Do not warn as root Class declares this.  */
  [MyClass2 doItClass9];
  [MyClass2 doItInstance9];
  
}

id obj = nil;
id <MyProto1> objP1 = nil;
id <MyProto2> objP2 = nil;

MyClass1 *mc1 = nil;
MyClass2 *mc2 = nil;

void
testComptypes(void)
{
  cls == clsP1;
  clsP1 == cls;

  cls == objP1; /* { dg-warning "lacks a cast" } */
  objP1 == cls; /* { dg-warning "lacks a cast" } */

  clsP1 == clsP5;
  clsP5 == clsP1;

  mc1 == clsP1; /* { dg-warning "lacks a cast" } */
  clsP1 == mc1; /* { dg-warning "lacks a cast" } */


  cls = clsP1; 
  clsP1 = cls;

  cls = objP1; /* { dg-warning "incompatible" } */
  objP1 = cls; /* { dg-warning "incompatible" } */

  clsP1 = clsP5;
  clsP5 = clsP1; /* { dg-warning "does not conform" } */

  mc1 = clsP1; /* { dg-warning "incompatible" } */
  clsP1 = mc1; /* { dg-warning "incompatible" } */

}

int main ()
{
  testSimple();
  testCategory();
  testCategoryInherited();
  return(0);
}

/* { dg-warning "Messages without a matching" "" { target *-*-* } 47 } */
/* { dg-warning "will be assumed to return" "" { target *-*-* } 47 } */
/* { dg-warning "as arguments" "" { target *-*-* } 47 } */

[-- Attachment #6: patch.tar.gz --]
[-- Type: application/x-gunzip, Size: 7307 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-28 20:04     ` David Ayers
@ 2004-09-28 20:13       ` Ziemowit Laski
  2004-09-28 22:12         ` d.ayers
  2004-09-29  3:27       ` Ziemowit Laski
  1 sibling, 1 reply; 35+ messages in thread
From: Ziemowit Laski @ 2004-09-28 20:13 UTC (permalink / raw)
  To: David Ayers; +Cc: gcc-patches


On 28 Sep 2004, at 12.11, David Ayers wrote:

> David Ayers wrote:
>
>>
>> OK, this has been bubble strapped and regtested for ObjC on
>> i686-pc-linux-gnu after bootstrap of cvs today.  I'll run a full
>> bootstrap of c,objc,c++ tonight and regtest everything again tomorrow.
>>
>
> Hmm. seems the files got truncated somehow.  Let's try again...

Thanks.  FYI, there is now a separate objc/ChangeLog; I'll split it off
for you.  :-)

Can you explain what/why PROTOCOL_DECLARED_BY_ROOT is?

Thanks,

--Zem

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-28 20:13       ` Ziemowit Laski
@ 2004-09-28 22:12         ` d.ayers
  2004-09-28 22:35           ` Ziemowit Laski
  0 siblings, 1 reply; 35+ messages in thread
From: d.ayers @ 2004-09-28 22:12 UTC (permalink / raw)
  To: zlaski; +Cc: David Ayers, gcc-patches

>
> On 28 Sep 2004, at 12.11, David Ayers wrote:
>
>> David Ayers wrote:
>>
>>>
>>> OK, this has been bubble strapped and regtested for ObjC on
>>> i686-pc-linux-gnu after bootstrap of cvs today.  I'll run a full
>>> bootstrap of c,objc,c++ tonight and regtest everything again
>>> tomorrow.
>>>
>>
>> Hmm. seems the files got truncated somehow.  Let's try again...
>
> Thanks.  FYI, there is now a separate objc/ChangeLog; I'll split it off
> for you.  :-)

Thanks.

> Can you explain what/why PROTOCOL_DECLARED_BY_ROOT is?
>

"A protocol declared by a root class.  Instance methods of these protocols
are also taken into accunt when searching for class methods."

Is that good enough?

Cheers,
David



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-28 22:12         ` d.ayers
@ 2004-09-28 22:35           ` Ziemowit Laski
  0 siblings, 0 replies; 35+ messages in thread
From: Ziemowit Laski @ 2004-09-28 22:35 UTC (permalink / raw)
  To: d.ayers; +Cc: gcc-patches


On 28 Sep 2004, at 13.13, d.ayers@inode.at wrote:

>>
>> On 28 Sep 2004, at 12.11, David Ayers wrote:
>>
>>> David Ayers wrote:
>>>
>>>>
>>>> OK, this has been bubble strapped and regtested for ObjC on
>>>> i686-pc-linux-gnu after bootstrap of cvs today.  I'll run a full
>>>> bootstrap of c,objc,c++ tonight and regtest everything again
>>>> tomorrow.
>>>>
>>>
>>> Hmm. seems the files got truncated somehow.  Let's try again...
>>
>> Thanks.  FYI, there is now a separate objc/ChangeLog; I'll split it 
>> off
>> for you.  :-)
>
> Thanks.
>
>> Can you explain what/why PROTOCOL_DECLARED_BY_ROOT is?
>>
>
> "A protocol declared by a root class.  Instance methods of these 
> protocols
> are also taken into accunt when searching for class methods."

OK, I got a bit confused by your naming convention. :-)  I think you 
mean
protocols that were _adopted_ by root classes, right?  Makes more sense 
now.

--Zem

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-28 20:04     ` David Ayers
  2004-09-28 20:13       ` Ziemowit Laski
@ 2004-09-29  3:27       ` Ziemowit Laski
  2004-09-29  9:12         ` Kai Henningsen
  2004-09-29 18:20         ` David Ayers
  1 sibling, 2 replies; 35+ messages in thread
From: Ziemowit Laski @ 2004-09-29  3:27 UTC (permalink / raw)
  To: David Ayers; +Cc: gcc-patches

David,

Aside from a general plea to clean up your formatting/spacing :-), I 
have a few questions/comments.

>  objc_finish_interface (void)
>  {
>    finish_class (objc_interface_context);
> +
> +  if (TREE_CODE (objc_interface_context) == PROTOCOL_INTERFACE_TYPE
> +      && PROTOCOL_DECLARED_BY_ROOT (objc_interface_context))

This threw me off earlier, so perhaps you could rename 
PROTOCOL_DECLARED_BY_ROOT to
PROTOCOL_USED_IN_ROOT_CLASS or something along those lines?

> +    {
> +      tree protocol = objc_interface_context;
> +      tree method_decl;
> +
> +      /* Since we do not have a protocol list,
> +	 go ahead and register the method list directly.  */
> +      for (method_decl = PROTOCOL_NST_METHODS (protocol);
> +	   method_decl;
> +	   method_decl = TREE_CHAIN (method_decl))
> +	{
> +	  add_method_to_hash_list(cls_method_hash_list,  method_decl);
> +	}

I suspect this is overkill, since instance methods of root classes are 
already added to cls_method_hash_list,
are they not?

> +
> +      /* This protocol is marked.  Now insure that that all instance

s/insure/ensure/ :-), although you probably just want to say that 
protocols inherited by a marked protocols are
themselves marked.

> +	 prototypes of inherited protocols get registered as class
> +	 methods without marking them.  */
> +      mark_protocols_declared_by_root_class (PROTOCOL_LIST 
> (protocol), 1);
> +    }
> +

This also seems like a good time to handle root class (and category?) 
interfaces and mark the protocols they inherit.

>    objc_interface_context = NULL_TREE;
>  }

>
> @@ -836,6 +860,84 @@
>  }
>
>  /* Return 1 if LHS and RHS are compatible types for assignment or
> +   various other operations.  Return 0 if they are incompatible.
> +   When the operation is REFLEXIVE (typically comparisons), check

s/REFLEXIVE/SYMMETRIC/; objc_comptypes() suffers from the same 
misnomer, it
just never seemed important enough to fix. :-) Actually, you probably 
won't
need objc_comptypes_proto_proto() after all (see below), but if you
could s/reflexive/symmetric/ in objc_comptypes(), that would be great.

> +   for compatibility in either direction; when it's not (typically
> +   assignments), don't.
> +
> +   This is ja helper function for objc_comptypes to be able to test
> +   two protocol qualified types of the same basic type to insure
> +   protocol conformance and to emit the necessary warnings.
> +*/
> +
> +static inline
> +int objc_comptypes_proto_proto(tree lhs, tree rhs, int reflexive)
> +{
>

> +/* Return 1 if LHS and RHS are compatible types for assignment or
>     various other operations.  Return 0 if they are incompatible, and
>     return -1 if we choose to not decide (because the types are really
>     just C types, not ObjC specific ones).  When the operation is
> @@ -866,76 +968,21 @@
>        && TREE_CODE (rhs) == POINTER_TYPE
>        && TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE)
>      {
> -      int lhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (lhs);
> -      int rhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (rhs);
> +      int lhs_is_proto_id = IS_PROTOCOL_QUALIFIED_ID (lhs);
> +      int rhs_is_proto_id = IS_PROTOCOL_QUALIFIED_ID (rhs);
> +      int lhs_is_proto_class = IS_PROTOCOL_QUALIFIED_CLASS (lhs);
> +      int rhs_is_proto_class = IS_PROTOCOL_QUALIFIED_CLASS (rhs);

I'm not sure why it is necessary to distinguish between 
IS_PROTOCOL_QUALIFIED_ID
and IS_PROTOCOL_QUALIFIED_CLASS for purposes for objc_comptypes().  In 
most
cases, the two behave identically for type comparison purposes, and in 
any places
they do not you can use IS_ID / IS_CLASS to distinguish them.  Then, 
you can
keep objc_comptypes() mostly as it is, and get rid of 
objc_comptypes_proto_proto().

> @@ -1164,7 +1251,7 @@
>
>  /* Construct a PROTOCOLS-qualified variant of INTERFACE, where 
> INTERFACE may
>     either name an Objective-C class, or refer to the special 'id' or 
> 'Class'
> -   types.  If INTERFACE is not a valid ObjC type, just return it 
> unchanged.  */
> +   types.  If INTERFACE is not a valid ObjC type, report error.  */
>
>  tree
>  objc_get_protocol_qualified_type (tree interface, tree protocols)
> @@ -1180,7 +1267,7 @@
>        if (type)
>  	type = xref_tag (RECORD_TYPE, type);
>        else
> -        return interface;
> +        error ("protocol qualifiers specified for non-Objective-C 
> type");

Thanks for the error message, but you should still return here instead 
of falling through, I think...

>      }
>
>    if (protocols)
> @@ -1222,8 +1309,10 @@
>      }
>  }
>
> -/* Look up PROTOCOLS, and return a list of those that are found.
> -   If none are found, return NULL.  */
> +/* Look up PROTOCOLS, a list of identifiers, and return the list
> +   of the protocol interface declarations that are found.  Invokes 
> error
> +   for each identifier for which the lookup failed.
> +   If PROTOCOLS is empty, return NULL.  */
>
>  static tree
>  lookup_and_install_protocols (tree protocols)
> @@ -1247,6 +1336,93 @@
>    return return_value;
>  }
>
> +/* Iterates over the protocol interface list RPROTOS marking each as
> +   PROTOCOL_DECLARED_BY_ROOT.  Registers the instance methods 
> prototypes
> +   of each protocol and their inherited protocols recursively as
> +   potential class methods.  IGNORE should always be 0.  It is used
> +   for recursive calls to insure that inherited protocols will not be
> +   marked unduly.  */
> +
> +static void
> +mark_protocols_declared_by_root_class (tree rprotos, int ignore)
> +{
> +  tree protocol_ch;
> +  tree protocol;
> +
> +  for (protocol_ch = rprotos;
> +       protocol_ch;
> +       protocol_ch = TREE_CHAIN (protocol_ch))
> +    {
> +      protocol = TREE_CHECK(TREE_VALUE (protocol_ch),
> +			    PROTOCOL_INTERFACE_TYPE);
> +
> +      /* Minor efficency check.  Expect all protocols which have
> +	 been previously marked, to have had their methods registered.

s/efficency/efficiency/.

> +	 A protocol which itself is not declared by a root class yet
> +	 is inherited by multiple root classes will have its instance

What is the difference between "declared by a root class" and 
"inherited by
a root class"?  I was assuming the two are synonymous...

> +	 methods processed redundantly, but it does not seem worth while
> +	 to flag them just to avoid this.  */
> +      if (!PROTOCOL_DECLARED_BY_ROOT (protocol))
> +	{
> +	  tree method_decl;
> +
> +	  for (method_decl = PROTOCOL_NST_METHODS (protocol);
> +	       method_decl;
> +	       method_decl = TREE_CHAIN (method_decl))
> +	    {
> +	      add_method_to_hash_list(cls_method_hash_list,  method_decl);
> +	    }
> +	}

Again, I suspect that adding these to cls_method_hash_list is redundant 
(see above).
> +
> +      if (!ignore)
> +	PROTOCOL_DECLARED_BY_ROOT (protocol) = 1;
> +
> +      mark_protocols_declared_by_root_class (PROTOCOL_LIST 
> (protocol), 1);
> +    }
> +}
> +
> +/* Searches for SELECTOR in the instance methods
> +   of the protocol interface list RPROTOS.  Returns
> +   the prototype only if the corresponding protocol from RPROTOS
> +   is declared by any root class.  IGNORE should always be 0.
> +   It is used for the recursive prototype search of inherited 
> protocols.  */
> +
> +static tree
> +instance_prototype_of_root_protocol (tree rprotos, tree selector, int 
> ignore)
> +{
> +  tree protocol_ch;
> +  tree protocol;
> +  tree prototype = NULL_TREE;
> +
> +  /* Loop over protocol list and search for protocols
> +     that declare the method as an instance method.  */
> +  for (protocol_ch = rprotos;
> +       protocol_ch;
> +       protocol_ch = TREE_CHAIN (protocol_ch))
> +    {
> +      protocol = TREE_CHECK(TREE_VALUE (protocol_ch),
> +			    PROTOCOL_INTERFACE_TYPE);
> +
> +      if (ignore || PROTOCOL_DECLARED_BY_ROOT (protocol))
> +	{
> +	  /* Check the protocol itself.  */
> +	  prototype = lookup_method (PROTOCOL_NST_METHODS (protocol),
> +				     selector);
> +	  if (prototype)
> +	    return prototype;
> +
> +	  /* Search prototypes of inherited protocols independent of mark.  
> */
> +	  prototype
> +	    = instance_prototype_of_root_protocol (PROTOCOL_LIST (protocol),
> +						   selector, 1);
> +	  if (prototype)
> +	    return prototype;
> +	}
> +    }
> +  return prototype;
> +}
> +
> +
>  /* Create a declaration for field NAME of a given TYPE.  */
>
>  static tree
> @@ -5569,14 +5745,24 @@
>  	}
>        else
>  	{
> +	  rprotos = TYPE_PROTOCOL_LIST (rtype);
>  	  class_tree = objc_class_name;
>  	  OBJC_SET_TYPE_NAME (rtype, class_tree);
> +
> +	  if (rprotos)
> +	    rtype = NULL_TREE;
>  	}
>
>        if (rprotos)
> -	method_prototype
> -	  = lookup_method_in_protocol_list (rprotos, sel_name,
> -					    class_tree != NULL_TREE);
> +	{
> +	  method_prototype
> +	    = lookup_method_in_protocol_list (rprotos, sel_name,
> +					      class_tree != NULL_TREE);
> +	  if (!method_prototype && class_tree != NULL_TREE)
> +	    method_prototype
> +	      = instance_prototype_of_root_protocol(rprotos, sel_name, 0);
> +	}
> +

Here, instead of calling (and defining!) 
instance_prototype_of_root_protocol(), perhaps you
can simply tweak lookup_method_in_protocol_list() so that if a class 
method is sought,
it can fall back to instance methods for protocols used in root classes?


>        if (!method_prototype && !rprotos)
>  	method_prototype
>  	  = lookup_method_in_hash_lists (sel_name,
> @@ -6680,8 +6866,14 @@
>          add_class (class);
>
>        if (protocol_list)
> -	CLASS_PROTOCOL_LIST (class)
> -	  = lookup_and_install_protocols (protocol_list);
> +	{
> +	  CLASS_PROTOCOL_LIST (class)
> +	    = lookup_and_install_protocols (protocol_list);
> +
> +	  if (!CLASS_SUPER_NAME (class))
> +	    mark_protocols_declared_by_root_class (CLASS_PROTOCOL_LIST 
> (class),
> +						   0);
> +	}
>      }
>
>    else if (code == CATEGORY_INTERFACE_TYPE)
> @@ -6702,8 +6894,14 @@
>          add_category (class_category_is_assoc_with, class);
>
>        if (protocol_list)
> -	CLASS_PROTOCOL_LIST (class)
> -	  = lookup_and_install_protocols (protocol_list);
> +	{
> +	  CLASS_PROTOCOL_LIST (class)
> +	    = lookup_and_install_protocols (protocol_list);
> +
> +	  if (!CLASS_SUPER_NAME (class_category_is_assoc_with))
> +	    mark_protocols_declared_by_root_class (CLASS_PROTOCOL_LIST 
> (class),
> +						   0);
> +	}
>      }
>
>    else if (code == CATEGORY_IMPLEMENTATION_TYPE)
> Index: gcc/objc/objc-act.h
> ===================================================================
> RCS file: /cvsroot/gcc/gcc/gcc/objc/objc-act.h,v
> retrieving revision 1.31
> diff -u -r1.31 objc-act.h
> --- gcc/objc/objc-act.h	22 Sep 2004 01:13:07 -0000	1.31
> +++ gcc/objc/objc-act.h	28 Sep 2004 18:23:08 -0000
> @@ -37,6 +37,14 @@
>  #define CLASS_LANG_SLOT_ELTS		5
>  #define PROTOCOL_LANG_SLOT_ELTS		2
>
> +/*
> +  Objective-C usage for TREE_LANG_FLAG_?:
> +
> +  0: PROTOCOL_DECLARED_BY_ROOT - (valid for PROTOCOL_INTERFACE_TYPE)
> +     Marks protocol declarations that are declared by root classes
> +     so that instance methods are also checked for Class references.
> +*/
> +
>  /* KEYWORD_DECL */
>  #define KEYWORD_KEY_NAME(DECL) ((DECL)->decl.name)
>  #define KEYWORD_ARG_NAME(DECL) ((DECL)->decl.arguments)
> @@ -66,6 +74,7 @@
>  #define PROTOCOL_CLS_METHODS(CLASS) ((CLASS)->type.maxval)
>  #define PROTOCOL_FORWARD_DECL(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 
> (CLASS), 1)
>  #define PROTOCOL_DEFINED(CLASS) TREE_USED (CLASS)
> +#define PROTOCOL_DECLARED_BY_ROOT(CLASS) TREE_LANG_FLAG_0 (CLASS)

Rename to PROTOCOL_USED_IN_ROOT_CLASS or some such, as suggested above.
>
>  /* We need to distinguish TYPE_PROTOCOL_LISTs from TYPE_CONTEXTs, 
> both of which
>     are stored in the same accessor slot.  */
> @@ -279,6 +288,8 @@
>    (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == TREE_TYPE 
> (objc_class_type))
>  #define IS_PROTOCOL_QUALIFIED_ID(TYPE) \
>    (IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE))
> +#define IS_PROTOCOL_QUALIFIED_CLASS(TYPE) \
> +  (IS_CLASS (TYPE) && TYPE_PROTOCOL_LIST (TYPE))

As I mentioned above, instead of adding IS_PROTOCOL_QUALIFIED_CLASS, 
I'd simply enhance IS_PROTOCOL_QUALIFIED_ID thusly:

    #define IS_PROTOCOL_QUALIFIED_ID(TYPE) \
       ((IS_ID (TYPE) || IS_CLASS (TYPE)) && TYPE_PROTOCOL_LIST (TYPE))

This should simplify the objc_comptypes() logic greatly.  Feel free to 
rename this macro to IS_PROTO_QUAL_ID_OR_CLASS
or some such if you'd like...


--Zem

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-29  3:27       ` Ziemowit Laski
@ 2004-09-29  9:12         ` Kai Henningsen
  2004-09-29 19:40           ` Ziemowit Laski
  2004-09-29 18:20         ` David Ayers
  1 sibling, 1 reply; 35+ messages in thread
From: Kai Henningsen @ 2004-09-29  9:12 UTC (permalink / raw)
  To: gcc-patches

zlaski@apple.com (Ziemowit Laski)  wrote on 28.09.04 in <EEFE950A-11AF-11D9-8A9A-000393673036@apple.com>:

> What is the difference between "declared by a root class" and
> "inherited by
> a root class"?  I was assuming the two are synonymous...

I thought if it inherited *anything*, it *wasn't* a root class pretty much  
by definition?!

MfG Kai

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-29  3:27       ` Ziemowit Laski
  2004-09-29  9:12         ` Kai Henningsen
@ 2004-09-29 18:20         ` David Ayers
  2004-09-29 21:25           ` Ziemowit Laski
  1 sibling, 1 reply; 35+ messages in thread
From: David Ayers @ 2004-09-29 18:20 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 12503 bytes --]

Ziemowit Laski wrote:

> David,
> 
> Aside from a general plea to clean up your formatting/spacing :-), I 
> have a few questions/comments.

Hello Zem,

Could you be a bit more specific on how to improve formatting spacing?
I've tried to follow the documented conventions and looking at:

http://gcc.gnu.org/ml/gcc-patches/2004-09/msg02888.html

I don't think my mailer (mozilla 1.7) has mangled anything unexpectedly.
 But maybe I just have some fundamental misunderstanding wrt to the
formating guidelines.

>> objc_finish_interface (void)
>> {
>>   finish_class (objc_interface_context);
>>+
>>+  if (TREE_CODE (objc_interface_context) == PROTOCOL_INTERFACE_TYPE
>>+      && PROTOCOL_DECLARED_BY_ROOT (objc_interface_context))
> 
> 
> This threw me off earlier, so perhaps you could rename 
> PROTOCOL_DECLARED_BY_ROOT to
> PROTOCOL_USED_IN_ROOT_CLASS or something along those lines?

Sure.  How about PROTOCOL_ADOPTED_BY_ROOT_CLASS?

>>+    {
>>+      tree protocol = objc_interface_context;
>>+      tree method_decl;
>>+
>>+      /* Since we do not have a protocol list,
>>+	 go ahead and register the method list directly.  */
>>+      for (method_decl = PROTOCOL_NST_METHODS (protocol);
>>+	   method_decl;
>>+	   method_decl = TREE_CHAIN (method_decl))
>>+	{
>>+	  add_method_to_hash_list(cls_method_hash_list,  method_decl);
>>+	}
> 
> 
> I suspect this is overkill, since instance methods of root classes are 
> already added to cls_method_hash_list,
> are they not?

Well, yes, instance methods of root classes are already in
cls_method_hash_list but generally/often the methods of adopted
protocols are not repeated in the interface declaration by convention,
which is what makes this necessary, I believe.

>>+
>>+      /* This protocol is marked.  Now insure that that all instance
> 
> 
> s/insure/ensure/ :-), although you probably just want to say that 
> protocols inherited by a marked protocols are
> themselves marked.

Actually what I meant was:

      /* This protocol is marked.  Now ensure that that all instance
         prototypes of incorporated protocols are registered as class
         methods without marking the protocols.  */

... but ... hmm ...

>>+	 prototypes of inherited protocols get registered as class
>>+	 methods without marking them.  */
>>+      mark_protocols_declared_by_root_class (PROTOCOL_LIST 
>>(protocol), 1);
>>+    }
>>+
> 
> 
> This also seems like a good time to handle root class (and category?) 
> interfaces and mark the protocols they inherit.

Agreed, this lets us keep them in one place.

> 
>>   objc_interface_context = NULL_TREE;
>> }
> 
> 
>>@@ -836,6 +860,84 @@
>> }
>>
>> /* Return 1 if LHS and RHS are compatible types for assignment or
>>+   various other operations.  Return 0 if they are incompatible.
>>+   When the operation is REFLEXIVE (typically comparisons), check
> 
> 
> s/REFLEXIVE/SYMMETRIC/; objc_comptypes() suffers from the same 
> misnomer, it
> just never seemed important enough to fix. :-)

Can I offer a follow up patch to deal with this and more "pressing"
naming issues in objc_comptypes?  Take a look at (patched) line 1057:

              if (reflexive)
                {
                  tree rname = OBJC_TYPE_NAME (TREE_TYPE (lhs));
                  tree rinter;
                  tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs);

where we use rname and later rinter for the lhs trees.

> Actually, you probably won't
> need objc_comptypes_proto_proto() after all (see below), but if you
> could s/reflexive/symmetric/ in objc_comptypes(), that would be great.

I think it be better to do this in a separate patch.  But if you think
the cleanup is appropriate for stage 3, I offer a follow up patch
dealing with these two and any other issues I find.

>>+/* Return 1 if LHS and RHS are compatible types for assignment or
>>    various other operations.  Return 0 if they are incompatible, and
>>    return -1 if we choose to not decide (because the types are really
>>    just C types, not ObjC specific ones).  When the operation is
>>@@ -866,76 +968,21 @@
>>       && TREE_CODE (rhs) == POINTER_TYPE
>>       && TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE)
>>     {
>>-      int lhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (lhs);
>>-      int rhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (rhs);
>>+      int lhs_is_proto_id = IS_PROTOCOL_QUALIFIED_ID (lhs);
>>+      int rhs_is_proto_id = IS_PROTOCOL_QUALIFIED_ID (rhs);
>>+      int lhs_is_proto_class = IS_PROTOCOL_QUALIFIED_CLASS (lhs);
>>+      int rhs_is_proto_class = IS_PROTOCOL_QUALIFIED_CLASS (rhs);
> 
> 
> I'm not sure why it is necessary to distinguish between 
> IS_PROTOCOL_QUALIFIED_ID
> and IS_PROTOCOL_QUALIFIED_CLASS for purposes for objc_comptypes().  In 
> most
> cases, the two behave identically for type comparison purposes, and in 
> any places
> they do not you can use IS_ID / IS_CLASS to distinguish them.  Then, 
> you can
> keep objc_comptypes() mostly as it is, and get rid of 
> objc_comptypes_proto_proto().

I just tried to stay in line with the existing implementation.
Actually, I'm not sure what value that macro has.  It is used only here
in comptypes and as you now need to work with IS_ID/IS_CLASS anyway we
might as well test with PROTOCOL_LIST.  So in this patch I've removed
the existing macro.

I'm not sure whether I can sensibly simplify objc_comptypes to get
rid of objc_comptypes_proto_proto, at least not without a considerable
rewrite of objc_comptypes which I'd rather not do at this stage.  But if
it's really important to you, I'll look into it.

>>@@ -1164,7 +1251,7 @@
>>
>> /* Construct a PROTOCOLS-qualified variant of INTERFACE, where 
>>INTERFACE may
>>    either name an Objective-C class, or refer to the special 'id' or 
>>'Class'
>>-   types.  If INTERFACE is not a valid ObjC type, just return it 
>>unchanged.  */
>>+   types.  If INTERFACE is not a valid ObjC type, report error.  */
>>
>> tree
>> objc_get_protocol_qualified_type (tree interface, tree protocols)
>>@@ -1180,7 +1267,7 @@
>>       if (type)
>> 	type = xref_tag (RECORD_TYPE, type);
>>       else
>>-        return interface;
>>+        error ("protocol qualifiers specified for non-Objective-C 
>>type");
> 
> 
> Thanks for the error message, but you should still return here instead 
> of falling through, I think...

Indeed!  In fact I think we should return an error_mark_node.

>>+      /* Minor efficency check.  Expect all protocols which have
>>+	 been previously marked, to have had their methods registered.
> 
> 
> s/efficency/efficiency/.

Thanks.

>>+	 A protocol which itself is not declared by a root class yet
>>+	 is inherited by multiple root classes will have its instance
> 
> 
> What is the difference between "declared by a root class" and 
> "inherited by
> a root class"?  I was assuming the two are synonymous...

Sorry, bad terminology, bad wording.  It should have read:

      /* Minor efficiency check.  Expect all protocols which have
         been previously marked, to have had their methods registered.
         A protocol which itself is not *adopted* by a root class, yet
         is *incorporated* by other protocols which are adopted by root
         classes will have its instance methods processed redundantly,
         but it does not seem worth while to flag them just to avoid
         this.  */

... but hmm again ...

>>+	 methods processed redundantly, but it does not seem worth while
>>+	 to flag them just to avoid this.  */
>>+      if (!PROTOCOL_DECLARED_BY_ROOT (protocol))
>>+	{
>>+	  tree method_decl;
>>+
>>+	  for (method_decl = PROTOCOL_NST_METHODS (protocol);
>>+	       method_decl;
>>+	       method_decl = TREE_CHAIN (method_decl))
>>+	    {
>>+	      add_method_to_hash_list(cls_method_hash_list,  method_decl);
>>+	    }
>>+	}
> 
> 
> Again, I suspect that adding these to cls_method_hash_list is redundant 
> (see above).
> 

I don't, see above :-).

>>+/* Searches for SELECTOR in the instance methods
>>+   of the protocol interface list RPROTOS.  Returns
>>+   the prototype only if the corresponding protocol from RPROTOS
>>+   is declared by any root class.  IGNORE should always be 0.
>>+   It is used for the recursive prototype search of inherited 
>>protocols.  */
>>+
>>+static tree
>>+instance_prototype_of_root_protocol (tree rprotos, tree selector, int 
>>ignore)
...
>>@@ -5569,14 +5745,24 @@
>> 	}
>>       else
>> 	{
>>+	  rprotos = TYPE_PROTOCOL_LIST (rtype);
>> 	  class_tree = objc_class_name;
>> 	  OBJC_SET_TYPE_NAME (rtype, class_tree);
>>+
>>+	  if (rprotos)
>>+	    rtype = NULL_TREE;
>> 	}
>>
>>       if (rprotos)
>>-	method_prototype
>>-	  = lookup_method_in_protocol_list (rprotos, sel_name,
>>-					    class_tree != NULL_TREE);
>>+	{
>>+	  method_prototype
>>+	    = lookup_method_in_protocol_list (rprotos, sel_name,
>>+					      class_tree != NULL_TREE);
>>+	  if (!method_prototype && class_tree != NULL_TREE)
>>+	    method_prototype
>>+	      = instance_prototype_of_root_protocol(rprotos, sel_name, 0);
>>+	}
>>+
> 
> 
> Here, instead of calling (and defining!) 
> instance_prototype_of_root_protocol(), perhaps you
> can simply tweak lookup_method_in_protocol_list() so that if a class 
> method is sought,
> it can fall back to instance methods for protocols used in root classes?

I think so.  I may have to add a parameter to handle the recursive
search with respect to incorporated protocols, but ...hmm... maybe I don't.

>>Index: gcc/objc/objc-act.h
>>===================================================================
>>RCS file: /cvsroot/gcc/gcc/gcc/objc/objc-act.h,v
>>retrieving revision 1.31
>>diff -u -r1.31 objc-act.h
>>--- gcc/objc/objc-act.h	22 Sep 2004 01:13:07 -0000	1.31
>>+++ gcc/objc/objc-act.h	28 Sep 2004 18:23:08 -0000
...
>>@@ -279,6 +288,8 @@
>>   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == TREE_TYPE 
>>(objc_class_type))
>> #define IS_PROTOCOL_QUALIFIED_ID(TYPE) \
>>   (IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE))
>>+#define IS_PROTOCOL_QUALIFIED_CLASS(TYPE) \
>>+  (IS_CLASS (TYPE) && TYPE_PROTOCOL_LIST (TYPE))
> 
> 
> As I mentioned above, instead of adding IS_PROTOCOL_QUALIFIED_CLASS, 
> I'd simply enhance IS_PROTOCOL_QUALIFIED_ID thusly:
> 
>     #define IS_PROTOCOL_QUALIFIED_ID(TYPE) \
>        ((IS_ID (TYPE) || IS_CLASS (TYPE)) && TYPE_PROTOCOL_LIST (TYPE))
> 
> This should simplify the objc_comptypes() logic greatly.  Feel free to 
> rename this macro to IS_PROTO_QUAL_ID_OR_CLASS
> or some such if you'd like...

Like I implied above, I don't think rewriting objc_comptypes at this
stage is a good idea, but if that is a prerequisite, I'll try.  But I'd
really like to do that in a follow up if possible.  Anyway I don't think
we really need any of those two macros so I removed them.

Now to my three '...hmm...'s:  I had originally decided it was a bad
idea to mark protocols, that are incorporated by protocols which were
adopted by root classes, as also being adopted by root classes.  The
issue is in the test case.  Consider:

@protocol MyProto8
+(void)doItClass8;
-(void)doItInstance8;
@end

@protocol MyProto9 <MyProto8>
+(void)doItClass9;
-(void)doItInstance9;
@end

@interface MyClass1 <MyProto9>
@end

Class <MyProto8> clsP8 = 0;

...
  [clsP8 doItInstance8]; /* { dg-warning "not implemented" } */

Now, does the fact that a root class adopts MyProto9, which incorporates
MyProto8, make MyProto8 a "root" protocol in the sense that we should
search for instance methods when sending messages to Class <Proto8> ?  I
admit this is a corner case that may not warrant the extra complexity.
This updated patch would make MyProto8 a full fledged "root" protocol.

I did add a flag to lookup_method_in_protocol_list to indicate whether
instance methods of protocols adopted by root classes should be
searched, so the caller can decide.  This is necessary as we only want
to use this feature if we actually have 'Class', not when we have a
"concrete" MyClass4 that is not a root class but implements a protocol
that is a root class of a different hierarchy:

@protocol MyProto1
@end

@interface MyClass1 <MyProto1> /* root */
@end
@interface MyClass2 : MyClass1
@end
@interface MyClass3 /* New root */
@end
@interface MyClass4 : MyClass3 <MyProto1>
@end

  [MyClass2 doItInstance1]; /* Do not warn */
...
  [MyClass4 doItInstance1]; /* { dg-warning "may not respond to" } */

So how's this?  (I'm sending this a little prematurely as the test case
may still need some new tests to catch more cases similar to the one
just mentioned, but I have to run now.)

Cheers,
David


[-- Attachment #2: ChangeLog.gcc --]
[-- Type: text/plain, Size: 258 bytes --]

2004-09-29  David Ayers  <d.ayers@inode.at>

	* c-common.h: Remove RID_ID.
	* c-parse.in: Remove OBJECTNAME and references to RID_ID.
	(typespec_reserved_attr): Add rule for TYPENAME
	non_empty_protocolrefs.
	(yylexname) Remove special handling of RID_ID.
	

[-- Attachment #3: ChangeLog.objc --]
[-- Type: text/plain, Size: 818 bytes --]

2004-09-29  David Ayers  <d.ayers@inode.at>

	* objc-act.h (PROTOCOL_ADOPTED_BY_ROOT_CLASS): New macro.
	(IS_PROTOCOL_QUALIFIED_ID): Removed macro.
	* objc-act.c (mark_protocols_adopted_by_root_class)
	(objc_comptypes_proto_proto): New functions.
	(lookup_method_in_protocol_list): Add parameter
	to indicate whether instance methods of protocols adopted
	by root classes should be searched.
	(objc_comptypes_proto_proto): Mark prototypes that have been
	adopted by root classes.
	(objc_comptypes): Handle protocol qualified 'Class' types.
	(objc_get_protocol_qualified_type): Report error for unknown types
	with protocol qualifiers.  Update documentation.
	(objc_finish_message_expr, lookup_method_static): Update callers
	of lookup_method_in_protocol_list.

	(lookup_and_install_protocols): Update documentation.
	

[-- Attachment #4: ChangeLog.test --]
[-- Type: text/plain, Size: 87 bytes --]

2004-09-29  David Ayers  <d.ayers@inode.at>

	* objc.dg/class-protocol-1.m: New test.


[-- Attachment #5: protocol.2.patch --]
[-- Type: text/plain, Size: 19401 bytes --]

Index: gcc/c-common.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.264
diff -u -r1.264 c-common.h
--- gcc/c-common.h	10 Sep 2004 23:56:18 -0000	1.264
+++ gcc/c-common.h	29 Sep 2004 16:59:00 -0000
@@ -92,7 +92,7 @@
   RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST,
 
   /* Objective-C */
-  RID_ID,          RID_AT_ENCODE,    RID_AT_END,
+  RID_AT_ENCODE,    RID_AT_END,
   RID_AT_CLASS,    RID_AT_ALIAS,     RID_AT_DEFS,
   RID_AT_PRIVATE,  RID_AT_PROTECTED, RID_AT_PUBLIC,
   RID_AT_PROTOCOL, RID_AT_SELECTOR,  
Index: gcc/c-parse.in
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-parse.in,v
retrieving revision 1.242
diff -u -r1.242 c-parse.in
--- gcc/c-parse.in	17 Sep 2004 18:17:59 -0000	1.242
+++ gcc/c-parse.in	29 Sep 2004 16:59:01 -0000
@@ -180,7 +180,7 @@
    Objective C, so that the token codes are the same in both.  */
 %token AT_INTERFACE AT_IMPLEMENTATION AT_END AT_SELECTOR AT_DEFS AT_ENCODE
 %token CLASSNAME AT_PUBLIC AT_PRIVATE AT_PROTECTED AT_PROTOCOL
-%token OBJECTNAME AT_CLASS AT_ALIAS
+%token AT_CLASS AT_ALIAS
 %token AT_THROW AT_TRY AT_CATCH AT_FINALLY AT_SYNCHRONIZED
 %token OBJC_STRING
 
@@ -261,7 +261,7 @@
 %type <ttype> selectorarg keywordnamelist keywordname objcencodeexpr
 %type <ttype> non_empty_protocolrefs protocolrefs identifier_list objcprotocolexpr
 
-%type <ttype> CLASSNAME OBJECTNAME OBJC_STRING OBJC_TYPE_QUAL
+%type <ttype> CLASSNAME OBJC_STRING OBJC_TYPE_QUAL
 
 %type <ttype> superclass objc_quals objc_qual objc_typename
 %type <itype> objc_try_catch_stmt optellipsis
@@ -474,7 +474,6 @@
 	IDENTIFIER
 	| TYPENAME
 @@ifobjc
-	| OBJECTNAME
 	| CLASSNAME
 @@end_ifobjc
 	;
@@ -1274,7 +1273,7 @@
 @@ifobjc
 	| CLASSNAME protocolrefs
 		{ $$ = objc_get_protocol_qualified_type ($1, $2); }
-	| OBJECTNAME protocolrefs
+	| TYPENAME non_empty_protocolrefs
 		{ $$ = objc_get_protocol_qualified_type ($1, $2); }
 
 /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>"
@@ -1549,10 +1548,6 @@
 		{ $$ = make_pointer_declarator ($2, $3); }
 	| TYPENAME
 		{ $$ = build_id_declarator ($1); }
-@@ifobjc
-	| OBJECTNAME
-		{ $$ = build_id_declarator ($1); }
-@@end_ifobjc
 	;
 
 /* Kinds of declarator that can appear in a parameter list
@@ -1571,10 +1566,6 @@
 		{ $$ = set_array_declarator_inner ($2, $1, false); }
 	| TYPENAME
 		{ $$ = build_id_declarator ($1); }
-@@ifobjc
-	| OBJECTNAME
-		{ $$ = build_id_declarator ($1); }
-@@end_ifobjc
 	;
 
 parm_declarator_nostarttypename:
@@ -2861,7 +2852,6 @@
 	  IDENTIFIER
 	| TYPENAME
 	| CLASSNAME
-	| OBJECTNAME
 	| reservedwords
 	;
 
@@ -3127,7 +3117,6 @@
   { "while",		RID_WHILE,	0 },
 
 @@ifobjc
-  { "id",		RID_ID,			D_OBJC },
 
   /* These objc keywords are recognized only immediately after
      an '@'.  */
@@ -3273,7 +3262,6 @@
   /* RID_STATCAST */	0,
 
   /* Objective C */
-  /* RID_ID */			OBJECTNAME,
   /* RID_AT_ENCODE */		AT_ENCODE,
   /* RID_AT_END */		AT_END,
   /* RID_AT_CLASS */		AT_CLASS,
@@ -3342,15 +3330,6 @@
       enum rid rid_code = C_RID_CODE (yylval.ttype);
 
 @@ifobjc
-      /* Turn non-typedefed refs to "id" into plain identifiers; this
-	 allows constructs like "void foo(id id);" to work.  */
-      if (rid_code == RID_ID)
-      {
-	decl = lookup_name (yylval.ttype);
-	if (decl == NULL_TREE || TREE_CODE (decl) != TYPE_DECL)
-	  return IDENTIFIER;
-      }
-
       if (!OBJC_IS_AT_KEYWORD (rid_code)
 	  && (!OBJC_IS_PQ_KEYWORD (rid_code) || objc_pq_context))
 @@end_ifobjc
@@ -3513,7 +3492,6 @@
     {
     case IDENTIFIER:
     case TYPENAME:
-    case OBJECTNAME:
     case TYPESPEC:
     case TYPE_QUAL:
     case SCSPEC:
Index: gcc/objc/objc-act.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.248
diff -u -r1.248 objc-act.c
--- gcc/objc/objc-act.c	24 Sep 2004 23:15:33 -0000	1.248
+++ gcc/objc/objc-act.c	29 Sep 2004 16:59:04 -0000
@@ -236,6 +236,7 @@
 static tree lookup_protocol (tree);
 static void check_protocol_recursively (tree, tree);
 static tree lookup_and_install_protocols (tree);
+static void mark_protocols_adopted_by_root_class (tree);
 
 /* Type encoding.  */
 
@@ -276,7 +277,7 @@
 
 /* Everything else.  */
 
-static tree lookup_method_in_protocol_list (tree, tree, int);
+static tree lookup_method_in_protocol_list (tree, tree, int, int);
 static tree lookup_protocol_in_reflist (tree, tree);
 static tree start_var_decl (tree, const char *);
 static void finish_var_decl (tree, tree);
@@ -329,6 +330,8 @@
      ATTRIBUTE_NORETURN;
 static void mark_referenced_methods (void);
 static void generate_objc_image_info (void);
+static inline int objc_comptypes_proto_proto(tree lhs, tree rhs, 
+					     int reflexive);
 
 /*** Private Interface (data) ***/
 
@@ -606,12 +609,16 @@
 }
 \f
 /* Return the first occurrence of a method declaration corresponding
-   to sel_name in rproto_list.  Search rproto_list recursively.
-   If is_class is 0, search for instance methods, otherwise for class
-   methods.  */
+   to SEL_NAME in RPROTO_LIST.  Search RPROTO_LIST recursively.
+   If IS_CLASS is 0, search for instance methods, otherwise for class
+   methods.
+   If SEARCH_ROOT_PROTOS is not 0, also search for instance methods
+   of protocols adopted by root classes when searching for class methods.
+*/
+
 static tree
 lookup_method_in_protocol_list (tree rproto_list, tree sel_name,
-				int is_class)
+				int is_class, int search_root_protos)
 {
    tree rproto, p;
    tree fnd = 0;
@@ -626,9 +633,15 @@
 				      ? PROTOCOL_CLS_METHODS (p)
 				      : PROTOCOL_NST_METHODS (p), sel_name)))
 	      ;
+	    else if (search_root_protos && is_class
+		     && PROTOCOL_ADOPTED_BY_ROOT_CLASS (p)
+		     && ((fnd = lookup_method (PROTOCOL_NST_METHODS (p),
+					       sel_name))))
+	      ;
 	    else if (PROTOCOL_LIST (p))
 	      fnd = lookup_method_in_protocol_list (PROTOCOL_LIST (p),
-						    sel_name, is_class);
+						    sel_name, is_class, 
+						    search_root_protos);
 	  }
 	else
           {
@@ -712,6 +725,39 @@
 objc_finish_interface (void)
 {
   finish_class (objc_interface_context);
+  if (TREE_CODE (objc_interface_context) == CLASS_INTERFACE_TYPE)
+    {
+      if (!CLASS_SUPER_NAME (objc_interface_context))
+	mark_protocols_adopted_by_root_class 
+	  (CLASS_PROTOCOL_LIST (objc_interface_context));
+    }
+  else if (TREE_CODE (objc_interface_context) == CATEGORY_INTERFACE_TYPE)
+    {
+      tree class = lookup_interface (CLASS_NAME (objc_interface_context));
+
+      if (!CLASS_SUPER_NAME (class))
+	mark_protocols_adopted_by_root_class 
+	  (CLASS_PROTOCOL_LIST (objc_interface_context));
+    }
+  else if (TREE_CODE (objc_interface_context) == PROTOCOL_INTERFACE_TYPE
+	   && PROTOCOL_ADOPTED_BY_ROOT_CLASS (objc_interface_context))
+    {
+      tree protocol = objc_interface_context;
+      tree method_decl;
+
+      /* Since we do not have a protocol list,
+	 go ahead and register the method list directly.  */
+      for (method_decl = PROTOCOL_NST_METHODS (protocol);
+	   method_decl;
+	   method_decl = TREE_CHAIN (method_decl))
+	{
+	  add_method_to_hash_list(cls_method_hash_list,  method_decl);
+	}
+
+      /* This protocol is marked.  Now mark all incorporated protocols.  */
+      mark_protocols_adopted_by_root_class (PROTOCOL_LIST (protocol));
+    }
+
   objc_interface_context = NULL_TREE;
 }
 
@@ -836,6 +882,84 @@
 }
 
 /* Return 1 if LHS and RHS are compatible types for assignment or
+   various other operations.  Return 0 if they are incompatible.
+   When the operation is REFLEXIVE (typically comparisons), check 
+   for compatibility in either direction; when it's not (typically 
+   assignments), don't.
+
+   This is ja helper function for objc_comptypes to be able to test 
+   two protocol qualified types of the same basic type to insure 
+   protocol conformance and to emit the necessary warnings.
+*/
+
+static inline
+int objc_comptypes_proto_proto(tree lhs, tree rhs, int reflexive)
+{
+  tree lproto, lproto_list = TYPE_PROTOCOL_LIST (lhs);
+  tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs);
+  tree p;
+
+  gcc_assert((IS_ID (lhs) && IS_ID (rhs))
+	     || (IS_CLASS (lhs) && IS_CLASS (rhs)));
+
+  if (!reflexive)
+    {
+      /* An assignment between two objects both either of type 'id <Protocol>' 
+	 or both 'Class <Protocol>; make sure the protocol on the lhs is
+	 supported by the object on the rhs.  */
+      for (lproto = lproto_list; lproto;
+	   lproto = TREE_CHAIN (lproto))
+	{
+	  p = TREE_VALUE (lproto);
+	  rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+	  if (!rproto)
+	    warning
+	      ("%s does not conform to the `%s' protocol",
+	       IS_ID(lhs) ? "object" : "class",
+	       IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+	}
+      return 1;
+    }
+  else
+    {
+      /* Obscure case - a comparison between two objects either both
+	 of type 'id <Protocol>' or both 'Class <protocol>'.  Check 
+	 that either the protocol on the lhs is supported by the object on
+	 the rhs, or viceversa.  */
+
+      /* Check if the protocol on the lhs is supported by the
+	 object on the rhs.  */
+      for (lproto = lproto_list; lproto;
+	   lproto = TREE_CHAIN (lproto))
+	{
+	  p = TREE_VALUE (lproto);
+	  rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+	  if (!rproto)
+	    {
+	      /* Check failed - check if the protocol on the rhs
+		 is supported by the object on the lhs.  */
+	      for (rproto = rproto_list; rproto;
+		   rproto = TREE_CHAIN (rproto))
+		{
+		  p = TREE_VALUE (rproto);
+		  lproto = lookup_protocol_in_reflist (lproto_list, p);
+
+		  if (!lproto)
+		    {
+		      /* This check failed too: incompatible  */
+		      return 0;
+		    }
+		}
+	      return 1;
+	    }
+	}
+      return 1;
+    }
+}
+
+/* Return 1 if LHS and RHS are compatible types for assignment or
    various other operations.  Return 0 if they are incompatible, and
    return -1 if we choose to not decide (because the types are really
    just C types, not ObjC specific ones).  When the operation is
@@ -866,76 +990,21 @@
       && TREE_CODE (rhs) == POINTER_TYPE
       && TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE)
     {
-      int lhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (lhs);
-      int rhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (rhs);
+      int lhs_is_proto_id = IS_ID (lhs) && TYPE_PROTOCOL_LIST (lhs);
+      int rhs_is_proto_id = IS_ID (rhs) && TYPE_PROTOCOL_LIST (rhs);
+      int lhs_is_proto_class = IS_CLASS (lhs) && TYPE_PROTOCOL_LIST (lhs);
+      int rhs_is_proto_class = IS_CLASS (rhs) && TYPE_PROTOCOL_LIST (rhs);
 
-      if (lhs_is_proto)
+      if (lhs_is_proto_id)
         {
 	  tree lproto, lproto_list = TYPE_PROTOCOL_LIST (lhs);
 	  tree rproto, rproto_list;
 	  tree p;
 
 	  /* <Protocol> = <Protocol>  */
-	  if (rhs_is_proto)
-	    {
-	      rproto_list = TYPE_PROTOCOL_LIST (rhs);
+	  if (rhs_is_proto_id)
+	    return objc_comptypes_proto_proto (lhs, rhs, reflexive);
 
-	      if (!reflexive)
-		{
-		  /* An assignment between objects of type 'id
-		     <Protocol>'; make sure the protocol on the lhs is
-		     supported by the object on the rhs.  */
-		  for (lproto = lproto_list; lproto;
-		       lproto = TREE_CHAIN (lproto))
-		    {
-		      p = TREE_VALUE (lproto);
-		      rproto = lookup_protocol_in_reflist (rproto_list, p);
-
-		      if (!rproto)
-			warning
-			  ("object does not conform to the `%s' protocol",
-			   IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
-		    }
-		  return 1;
-		}
-	      else
-		{
-		  /* Obscure case - a comparison between two objects
-		     of type 'id <Protocol>'.  Check that either the
-		     protocol on the lhs is supported by the object on
-		     the rhs, or viceversa.  */
-
-		  /* Check if the protocol on the lhs is supported by the
-		     object on the rhs.  */
-		  for (lproto = lproto_list; lproto;
-		       lproto = TREE_CHAIN (lproto))
-		    {
-		      p = TREE_VALUE (lproto);
-		      rproto = lookup_protocol_in_reflist (rproto_list, p);
-
-		      if (!rproto)
-			{
-			  /* Check failed - check if the protocol on the rhs
-			     is supported by the object on the lhs.  */
-			  for (rproto = rproto_list; rproto;
-			       rproto = TREE_CHAIN (rproto))
-			    {
-			      p = TREE_VALUE (rproto);
-			      lproto = lookup_protocol_in_reflist (lproto_list,
-								   p);
-
-			      if (!lproto)
-				{
-				  /* This check failed too: incompatible  */
-				  return 0;
-				}
-			    }
-			  return 1;
-			}
-		    }
-		  return 1;
-		}
-	    }
 	  /* <Protocol> = <class> *  */
 	  else if (TYPED_OBJECT (TREE_TYPE (rhs)))
 	    {
@@ -998,7 +1067,7 @@
 	  /* <Protocol> = ?? : let comptypes decide.  */
           return -1;
         }
-      else if (rhs_is_proto)
+      else if (rhs_is_proto_id)
 	{
 	  /* <class> * = <Protocol> */
 	  if (TYPED_OBJECT (TREE_TYPE (lhs)))
@@ -1078,6 +1147,46 @@
 	      return -1;
 	    }
 	}
+      else if (lhs_is_proto_class)
+	{
+	  /* Class <Protocol> = Class <Protocol>  */
+	  if (rhs_is_proto_class)
+	    return objc_comptypes_proto_proto (lhs, rhs, reflexive);
+
+	  /* Class <Protocol> = <class> *  */
+	  else if (TYPED_OBJECT (TREE_TYPE (rhs)))
+	    return 0;
+
+	  /* Class <Protocol> = Class */
+	  else if (objc_is_class_id (TREE_TYPE (rhs)))
+	    return 1;
+
+	  /* Class <Protocol> = id && Class <Protocol> = <Protocol> */
+	  else if (objc_is_object_id (TREE_TYPE (rhs)))
+	    return (rhs_is_proto_id ? 0 : 1);
+
+	  /* <Protocol> = ?? : let comptypes decide.  */
+	  else
+	    return -1;
+	}
+      else if (rhs_is_proto_class)
+	{
+	  /* <class> * = Class <Protocol> */
+	  if (TYPED_OBJECT (TREE_TYPE (lhs)))
+	    return 0;
+
+	  /* id = Class <Protocol> && <Protocol> = Class <Protocol> */
+	  else if (objc_is_object_id (TREE_TYPE (lhs)))
+	    return (lhs_is_proto_id ? 0 : 1);
+
+	  /* Class = Class <Protocol> */
+	  else if (objc_is_class_id (TREE_TYPE (lhs)))
+	    return 1;
+
+	  /* ??? = Class <Protocol> : let comptypes decide */
+	  else
+	    return -1;
+	}
       else
 	{
 	  /* Attention: we shouldn't defer to comptypes here.  One bad
@@ -1164,7 +1273,7 @@
 
 /* Construct a PROTOCOLS-qualified variant of INTERFACE, where INTERFACE may
    either name an Objective-C class, or refer to the special 'id' or 'Class'
-   types.  If INTERFACE is not a valid ObjC type, just return it unchanged.  */
+   types.  If INTERFACE is not a valid ObjC type, report error.  */
 
 tree
 objc_get_protocol_qualified_type (tree interface, tree protocols)
@@ -1180,7 +1289,10 @@
       if (type)
 	type = xref_tag (RECORD_TYPE, type);
       else
-        return interface;
+	{
+	  error ("protocol qualifiers specified for non-Objective-C type");
+	  return error_mark_node;
+	}
     }
 
   if (protocols)
@@ -1222,8 +1334,10 @@
     }
 }
 
-/* Look up PROTOCOLS, and return a list of those that are found.
-   If none are found, return NULL.  */
+/* Look up PROTOCOLS, a list of identifiers, and return the list
+   of the protocol interface declarations that are found.  Invokes error
+   for each identifier for which the lookup failed.
+   If PROTOCOLS is empty, return NULL.  */
 
 static tree
 lookup_and_install_protocols (tree protocols)
@@ -1247,6 +1361,44 @@
   return return_value;
 }
 
+/* Iterates over the protocol interface list RPROTOS marking each as
+   PROTOCOL_ADOPTED_BY_ROOT_CLASS.  Registers the instance methods 
+   prototypes of each protocol and their incorporated protocols recursively
+   as potential class methods.  */
+
+static void
+mark_protocols_adopted_by_root_class (tree rprotos)
+{
+  tree protocol_ch;
+  tree protocol;
+
+  for (protocol_ch = rprotos;
+       protocol_ch;
+       protocol_ch = TREE_CHAIN (protocol_ch))
+    {
+      protocol = TREE_CHECK(TREE_VALUE (protocol_ch),
+			    PROTOCOL_INTERFACE_TYPE);
+
+      /* Minor efficiency check.  Expect all protocols which have
+	 been previously marked, to have had their methods registered.  */
+      if (!PROTOCOL_ADOPTED_BY_ROOT_CLASS (protocol))
+	{
+	  tree method_decl;
+
+	  for (method_decl = PROTOCOL_NST_METHODS (protocol);
+	       method_decl;
+	       method_decl = TREE_CHAIN (method_decl))
+	    {
+	      add_method_to_hash_list(cls_method_hash_list,  method_decl);
+	    }
+	}
+
+      PROTOCOL_ADOPTED_BY_ROOT_CLASS (protocol) = 1;
+
+      mark_protocols_adopted_by_root_class (PROTOCOL_LIST (protocol));
+    }
+}
+
 /* Create a declaration for field NAME of a given TYPE.  */
 
 static tree
@@ -5569,14 +5721,19 @@
 	}
       else
 	{
+	  rprotos = TYPE_PROTOCOL_LIST (rtype);
 	  class_tree = objc_class_name;
 	  OBJC_SET_TYPE_NAME (rtype, class_tree);
+
+	  if (rprotos)
+	    rtype = NULL_TREE;
 	}
 
       if (rprotos)
 	method_prototype
 	  = lookup_method_in_protocol_list (rprotos, sel_name,
-					    class_tree != NULL_TREE);
+					    class_tree != NULL_TREE, 1);
+
       if (!method_prototype && !rprotos)
 	method_prototype
 	  = lookup_method_in_hash_lists (sel_name,
@@ -5631,7 +5788,7 @@
 	  if (!method_prototype && rprotos)
 	    method_prototype
 	      = lookup_method_in_protocol_list (rprotos, sel_name,
-						class_tree != NULL_TREE);
+						class_tree != NULL_TREE, 0);
 	}
       else
 	{
@@ -6062,7 +6219,8 @@
 	  if (CLASS_PROTOCOL_LIST (category))
 	    {
 	      if ((meth = (lookup_method_in_protocol_list
-			   (CLASS_PROTOCOL_LIST (category), ident, is_class))))
+			   (CLASS_PROTOCOL_LIST (category),
+			    ident, is_class, 0))))
 		return meth;
 	    }
 	}
@@ -6071,7 +6229,7 @@
       if (CLASS_PROTOCOL_LIST (inter))
 	{
 	  if ((meth = (lookup_method_in_protocol_list
-		       (CLASS_PROTOCOL_LIST (inter), ident, is_class))))
+		       (CLASS_PROTOCOL_LIST (inter), ident, is_class, 0))))
 	    return meth;
 	}
 
Index: gcc/objc/objc-act.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/objc/objc-act.h,v
retrieving revision 1.31
diff -u -r1.31 objc-act.h
--- gcc/objc/objc-act.h	22 Sep 2004 01:13:07 -0000	1.31
+++ gcc/objc/objc-act.h	29 Sep 2004 16:59:04 -0000
@@ -37,6 +37,14 @@
 #define CLASS_LANG_SLOT_ELTS		5
 #define PROTOCOL_LANG_SLOT_ELTS		2
 
+/*
+  Objective-C usage for TREE_LANG_FLAG_?:
+
+  0: PROTOCOL_ADOPTED_BY_ROOT_CLASS - (valid for PROTOCOL_INTERFACE_TYPE)
+     Marks protocol declarations that are adopted by root classes
+     so that instance methods are also checked for Class references.
+*/
+
 /* KEYWORD_DECL */
 #define KEYWORD_KEY_NAME(DECL) ((DECL)->decl.name)
 #define KEYWORD_ARG_NAME(DECL) ((DECL)->decl.arguments)
@@ -66,6 +74,7 @@
 #define PROTOCOL_CLS_METHODS(CLASS) ((CLASS)->type.maxval)
 #define PROTOCOL_FORWARD_DECL(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 1)
 #define PROTOCOL_DEFINED(CLASS) TREE_USED (CLASS)
+#define PROTOCOL_ADOPTED_BY_ROOT_CLASS(CLASS) TREE_LANG_FLAG_0 (CLASS)
 
 /* We need to distinguish TYPE_PROTOCOL_LISTs from TYPE_CONTEXTs, both of which
    are stored in the same accessor slot.  */
@@ -277,8 +286,6 @@
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == TREE_TYPE (objc_object_type))
 #define IS_CLASS(TYPE) \
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == TREE_TYPE (objc_class_type))
-#define IS_PROTOCOL_QUALIFIED_ID(TYPE) \
-  (IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE))
 #define IS_SUPER(TYPE) \
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == objc_super_template)
 

[-- Attachment #6: class-protocol-1.m --]
[-- Type: text/plain, Size: 7811 bytes --]

/* Check Class <protocol> types */
/* Author: David Ayers <d.ayers@inode.at> */
/* { dg-do compile } */

#include <objc/objc.h>
#include <objc/objc-api.h>

@protocol MyProto1
+(void)doItClass1;
-(void)doItInstance1;
@end

@protocol MyProto2
+(void)doItClass2;
-(void)doItInstance2;
@end

@interface MyClass1 <MyProto1>
{
  Class isa;
}
@end
@implementation MyClass1
+(void)doItClass1{}
-(void)doItInstance1{}
@end

@interface MyClass2 : MyClass1 <MyProto2>
@end
@implementation MyClass2
+(void)doItClass2{}
-(void)doItInstance2{}
@end

@interface MyClass3
{
  Class isa;
}
@end
@interface MyClass4 : MyClass3 <MyProto1>
@end

/*----------------------------------------*/

Class cls = 0;
Class <MyProto1> clsP1 = 0;
Class <MyProto2> clsP2 = 0;

void
testSimple(void)
{
  [cls doItClass1];
  [cls doItInstance1]; /* Do not warn as root Class declares this.  */
  [cls doItClass2];
  [cls doItInstance2]; /* { dg-warning "may not respond" } */

  [clsP1 doItClass1];
  [clsP1 doItInstance1]; /* Do not warn as root Class declares this.  */
  [clsP1 doItClass2];    /* { dg-warning "not implemented by protocol" } */
  [clsP1 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [clsP2 doItClass1];    /* { dg-warning "not implemented by protocol" } */
  [clsP2 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
  [clsP2 doItClass2];
  [clsP2 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass1];
  [MyClass1 doItInstance1];
  [MyClass1 doItClass2];    /* { dg-warning "may not respond to" } */
  [MyClass1 doItInstance2]; /* { dg-warning "may not respond to" } */

  [MyClass2 doItClass1];
  [MyClass2 doItInstance1];
  [MyClass2 doItClass2];
  [MyClass2 doItInstance2]; /* { dg-warning "may not respond to" } */

  [MyClass3 doItClass1];    /* { dg-warning "may not respond to" } */
  [MyClass3 doItInstance1]; /* { dg-warning "may not respond to" } */

  [MyClass4 doItClass1];    
  [MyClass4 doItInstance1]; /* { dg-warning "may not respond to" } */

}

/*----------------------------------------*/
/* Protocols declared by categories */

@protocol MyProto3
+(void)doItClass3;
-(void)doItInstance3;
@end
@protocol MyProto4
+(void)doItClass4;
-(void)doItInstance4;
@end

@interface MyClass1 (Category1) <MyProto3>
@end
@interface MyClass2 (Category2) <MyProto4>
@end

void
testCategory(void)
{
  [cls doItClass3];
  [cls doItInstance3];      /* Do not warn as root Class declares this.  */
  [cls doItClass4];
  [cls doItInstance4];      /* { dg-warning "may not respond" } */

  [MyClass1 doItClass3];
  [MyClass1 doItInstance3];
  [MyClass1 doItClass4];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance4]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass3];
  [MyClass2 doItInstance3];
  [MyClass2 doItClass4];
  [MyClass2 doItInstance4]; /* { dg-warning "may not respond" } */

}

/*----------------------------------------*/
/* Incorporated protocols declared by categories */

@protocol MyProto5 <MyProto1>
+(void)doItClass5;
-(void)doItInstance5;
@end

@protocol MyProto6 <MyProto2>
+(void)doItClass6;
-(void)doItInstance6;
@end

@interface MyClass1 (Category3) <MyProto5>
@end
@interface MyClass2 (Category4) <MyProto6>
@end

Class <MyProto5> clsP5 = 0;
Class <MyProto6> clsP6 = 0;

void
testCategoryIncorporated(void)
{
  [cls doItClass5];
  [cls doItInstance5]; /* Do not warn as root Class declares this.  */
  [cls doItClass6];
  [cls doItInstance6]; /* { dg-warning "may not respond" } */

  [clsP5 doItClass1];
  [clsP5 doItInstance1];
  [clsP5 doItClass2];    /* { dg-warning "not implemented by protocol" } */
  [clsP5 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [clsP6 doItClass1];    /* { dg-warning "not implemented by protocol" } */
  [clsP6 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
  [clsP6 doItClass2];
  [clsP6 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass5];
  [MyClass1 doItInstance5]; /* Do not warn as root Class declares this.  */
  [MyClass1 doItClass6];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance6]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass5];
  [MyClass2 doItInstance5]; /* Do not warn as root Class declares this.  */
  [MyClass2 doItClass6];
  [MyClass2 doItInstance6]; /* { dg-warning "may not respond" } */

}

/*----------------------------------------*/
/* Forward declared root protocols */

@protocol FwProto;

@interface MyClass1 (Forward) <FwProto>
@end

Class <FwProto> clsP7 = 0;

void
testForwardeDeclared1(void)
{
  [cls doItClass7];         /* { dg-warning "may not respond" } */
  [cls doItInstance7];      /* { dg-warning "may not respond" } */

  [clsP7 doItClass7];       /* { dg-warning "not implemented by protocol" } */
  [clsP7 doItInstance7];    /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass7];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance7]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass7];    /* { dg-warning "may not respond" } */
  [MyClass2 doItInstance7]; /* { dg-warning "may not respond" } */

}

@protocol FwProto
+(void)doItClass7;
-(void)doItInstance7;
@end

void
testForwardeDeclared2(void)
{
  [cls doItClass7];
  [cls doItInstance7];   /* Do not warn as root Class declares this.  */

  [clsP7 doItClass7];    
  [clsP7 doItInstance7]; /* Do not warn as root Class declares this.  */

  [MyClass1 doItClass7];
  [MyClass1 doItInstance7];

  [MyClass2 doItClass7];
  [MyClass2 doItInstance7];

}

/*----------------------------------------*/
/* Incorporated non root protocols */

@protocol MyProto8
+(void)doItClass8;
-(void)doItInstance8;
@end

@protocol MyProto9 <MyProto8>
+(void)doItClass9;
-(void)doItInstance9;
@end

@interface MyClass1 (IncorporatedNonRoot) <MyProto9>
@end

Class <MyProto8> clsP8 = 0;
Class <MyProto9> clsP9 = 0;

void
testIncorporatedNonRoot(void)
{
  [cls doItClass8];
  [cls doItInstance8]; /* Do not warn as root Class declares super.  */
  [cls doItClass9];
  [cls doItInstance9]; /* Do not warn as root Class declares this.  */

  [clsP8 doItClass8];
  [clsP8 doItInstance8]; /* Debatable, if a warning should be emitted.  */
  [clsP8 doItClass9];    /* { dg-warning "not implemented by protocol" } */
  [clsP8 doItInstance9]; /* { dg-warning "not implemented by protocol" } */

  [clsP9 doItClass8];
  [clsP9 doItInstance8];
  [clsP9 doItClass9];
  [clsP9 doItInstance9];

  [MyClass1 doItClass8];
  [MyClass1 doItInstance8]; /* Do not warn as root Class declares this.  */
  [MyClass1 doItClass9];
  [MyClass1 doItInstance9];

  [MyClass2 doItClass8];
  [MyClass2 doItInstance8]; /* Do not warn as root Class declares this.  */
  [MyClass2 doItClass9];
  [MyClass2 doItInstance9];
  
}

id obj = nil;
id <MyProto1> objP1 = nil;
id <MyProto2> objP2 = nil;

MyClass1 *mc1 = nil;

void
testComptypes(void)
{
  cls == clsP1;
  clsP1 == cls;

  cls == objP1; /* { dg-warning "lacks a cast" } */
  objP1 == cls; /* { dg-warning "lacks a cast" } */

  clsP1 == clsP5;
  clsP5 == clsP1;

  mc1 == clsP1; /* { dg-warning "lacks a cast" } */
  clsP1 == mc1; /* { dg-warning "lacks a cast" } */


  cls = clsP1; 
  clsP1 = cls;

  cls = objP1; /* { dg-warning "incompatible" } */
  objP1 = cls; /* { dg-warning "incompatible" } */

  clsP1 = clsP5;
  clsP5 = clsP1; /* { dg-warning "does not conform" } */

  mc1 = clsP1; /* { dg-warning "incompatible" } */
  clsP1 = mc1; /* { dg-warning "incompatible" } */

}

int main ()
{
  testSimple();
  testCategory();
  testCategoryIncorporated();
  return(0);
}

/* { dg-warning "Messages without a matching" "" { target *-*-* } 0 } */
/* { dg-warning "will be assumed to return" "" { target *-*-* } 0 } */
/* { dg-warning "as arguments" "" { target *-*-* } 0 } */


[-- Attachment #7: patch.tar.gz --]
[-- Type: application/x-gunzip, Size: 7489 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-29  9:12         ` Kai Henningsen
@ 2004-09-29 19:40           ` Ziemowit Laski
  2004-09-30  9:00             ` Kai Henningsen
  0 siblings, 1 reply; 35+ messages in thread
From: Ziemowit Laski @ 2004-09-29 19:40 UTC (permalink / raw)
  To: Kai Henningsen; +Cc: gcc-patches


On 28 Sep 2004, at 23.41, Kai Henningsen wrote:

> zlaski@apple.com (Ziemowit Laski)  wrote on 28.09.04 in 
> <EEFE950A-11AF-11D9-8A9A-000393673036@apple.com>:
>
>> What is the difference between "declared by a root class" and
>> "inherited by
>> a root class"?  I was assuming the two are synonymous...
>
> I thought if it inherited *anything*, it *wasn't* a root class pretty 
> much
> by definition?!

I used "inherited" a bit loosely; what I (and David) should have said 
is "adopted". :-)  ObjC protocols
get adopted by ObjC classes (much like Java interfaces get adopted by 
Java classes), but ObjC
classes do not declare protocols.

--Zem

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-29 18:20         ` David Ayers
@ 2004-09-29 21:25           ` Ziemowit Laski
  2004-09-30  0:01             ` d.ayers
  0 siblings, 1 reply; 35+ messages in thread
From: Ziemowit Laski @ 2004-09-29 21:25 UTC (permalink / raw)
  To: David Ayers; +Cc: gcc-patches


On 29 Sep 2004, at 10.34, David Ayers wrote:

> Ziemowit Laski wrote:
>
>> David,
>>
>> Aside from a general plea to clean up your formatting/spacing :-), I
>> have a few questions/comments.
>
> Hello Zem,
>
> Could you be a bit more specific on how to improve formatting spacing?
> I've tried to follow the documented conventions and looking at:
>
> http://gcc.gnu.org/ml/gcc-patches/2004-09/msg02888.html
>
> I don't think my mailer (mozilla 1.7) has mangled anything 
> unexpectedly.
>  But maybe I just have some fundamental misunderstanding wrt to the
> formating guidelines.

You are missing a space following opening parenths in several places, 
e.g.,

>>> +	{
>>> +	  add_method_to_hash_list(cls_method_hash_list,  method_decl);
>>> +	}

where you also have an extraneous space (or perhaps a tab?) after the 
comma.

>
>>> objc_finish_interface (void)
>>> {
>>>   finish_class (objc_interface_context);
>>> +
>>> +  if (TREE_CODE (objc_interface_context) == PROTOCOL_INTERFACE_TYPE
>>> +      && PROTOCOL_DECLARED_BY_ROOT (objc_interface_context))
>>
>>
>> This threw me off earlier, so perhaps you could rename
>> PROTOCOL_DECLARED_BY_ROOT to
>> PROTOCOL_USED_IN_ROOT_CLASS or something along those lines?
>
> Sure.  How about PROTOCOL_ADOPTED_BY_ROOT_CLASS?

Sounds good. :-)
>
>>> +    {
>>> +      tree protocol = objc_interface_context;
>>> +      tree method_decl;
>>> +
>>> +      /* Since we do not have a protocol list,
>>> +	 go ahead and register the method list directly.  */
>>> +      for (method_decl = PROTOCOL_NST_METHODS (protocol);
>>> +	   method_decl;
>>> +	   method_decl = TREE_CHAIN (method_decl))
>>> +	{
>>> +	  add_method_to_hash_list(cls_method_hash_list,  method_decl);
>>> +	}
>>
>>
>> I suspect this is overkill, since instance methods of root classes are
>> already added to cls_method_hash_list,
>> are they not?
>
> Well, yes, instance methods of root classes are already in
> cls_method_hash_list but generally/often the methods of adopted
> protocols are not repeated in the interface declaration by convention,
> which is what makes this necessary, I believe.

Ok, that's a good point.  I guess there's still overkill in that the 
instance
methods thusly added will serve as a fallback for _any_ class method 
lookup
(i.e., even if the protocol in question is not involved), but the same 
overkill
happens wrt root classes, which also happily stuff all of their 
instance methods
into cls_method_hash_list.  So yes, I think your approach is consistent.

However, this raises a different question in my mind: If protocols 
adopted by
root classes already stuff their instance methods into the global class 
method
table, do we need to do anything more than we already do to find them?  
In
other words, if I have

       @protocol Proto2
       - someMessage;
       @end

       @interface Root <Proto2>
       @end

       Class <Proto1, Proto2> obj;
         :
       [obj someMessage];

the compiler should look for +someMessage in Proto1 and Proto2 (only a 
slight
variation from the 'id <Proto1, Proto2>' case, where both -someMessage 
and
+someMessage would be sought) and then fall back to the the global class
method table (again, a slight variation from 'id <Proto1, Proto2>' where
both global tables would be examined), and therein find the -someMessage
method from Proto2.

What do you think?  Or am I missing something?

>
>>> +
>>> +      /* This protocol is marked.  Now insure that that all instance
>>
>>
>> s/insure/ensure/ :-), although you probably just want to say that
>> protocols inherited by a marked protocols are
>> themselves marked.
>
> Actually what I meant was:
>
>       /* This protocol is marked.  Now ensure that that all instance
>          prototypes of incorporated protocols are registered as class
>          methods without marking the protocols.  */

Perhaps instead of 'incorporated', we should consistently say 
'inherited'?
What do Java people say when one interface refers to another? :-)

>
> ... but ... hmm ...
>
>>> +	 prototypes of inherited protocols get registered as class
>>> +	 methods without marking them.  */
>>> +      mark_protocols_declared_by_root_class (PROTOCOL_LIST
>>> (protocol), 1);
>>> +    }
>>> +
>>
>>
>> This also seems like a good time to handle root class (and category?)
>> interfaces and mark the protocols they inherit.

Now I have to correct myself: s/inherit/adopt. :-)

>
> Agreed, this lets us keep them in one place.
>
>>
>>>   objc_interface_context = NULL_TREE;
>>> }
>>
>>
>>> @@ -836,6 +860,84 @@
>>> }
>>>
>>> /* Return 1 if LHS and RHS are compatible types for assignment or
>>> +   various other operations.  Return 0 if they are incompatible.
>>> +   When the operation is REFLEXIVE (typically comparisons), check
>>
>>
>> s/REFLEXIVE/SYMMETRIC/; objc_comptypes() suffers from the same
>> misnomer, it
>> just never seemed important enough to fix. :-)
>
> Can I offer a follow up patch to deal with this and more "pressing"
> naming issues in objc_comptypes?  Take a look at (patched) line 1057:
>
>               if (reflexive)
>                 {
>                   tree rname = OBJC_TYPE_NAME (TREE_TYPE (lhs));
>                   tree rinter;
>                   tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs);
>
> where we use rname and later rinter for the lhs trees.

>
>> Actually, you probably won't
>> need objc_comptypes_proto_proto() after all (see below), but if you
>> could s/reflexive/symmetric/ in objc_comptypes(), that would be great.
>
> I think it be better to do this in a separate patch.  But if you think
> the cleanup is appropriate for stage 3, I offer a follow up patch
> dealing with these two and any other issues I find.

Sure, let's deal with it later.  I see no reason why such cleanup would
not be appropriate for Stage 3, though folks above me on the totem pole
may obviously overrule me here if they wish. :-)

Actually, I do think objc_comptypes() needs to be seriously reworked
to remove the spaghetti, but that will have to wait for gcc 4.1 stage 
1...
>
>>> +/* Return 1 if LHS and RHS are compatible types for assignment or
>>>    various other operations.  Return 0 if they are incompatible, and
>>>    return -1 if we choose to not decide (because the types are really
>>>    just C types, not ObjC specific ones).  When the operation is
>>> @@ -866,76 +968,21 @@
>>>       && TREE_CODE (rhs) == POINTER_TYPE
>>>       && TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE)
>>>     {
>>> -      int lhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (lhs);
>>> -      int rhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (rhs);
>>> +      int lhs_is_proto_id = IS_PROTOCOL_QUALIFIED_ID (lhs);
>>> +      int rhs_is_proto_id = IS_PROTOCOL_QUALIFIED_ID (rhs);
>>> +      int lhs_is_proto_class = IS_PROTOCOL_QUALIFIED_CLASS (lhs);
>>> +      int rhs_is_proto_class = IS_PROTOCOL_QUALIFIED_CLASS (rhs);
>>
>>
>> I'm not sure why it is necessary to distinguish between
>> IS_PROTOCOL_QUALIFIED_ID
>> and IS_PROTOCOL_QUALIFIED_CLASS for purposes for objc_comptypes().  In
>> most
>> cases, the two behave identically for type comparison purposes, and in
>> any places
>> they do not you can use IS_ID / IS_CLASS to distinguish them.  Then,
>> you can
>> keep objc_comptypes() mostly as it is, and get rid of
>> objc_comptypes_proto_proto().
>
> I just tried to stay in line with the existing implementation.
> Actually, I'm not sure what value that macro has.  It is used only here
> in comptypes and as you now need to work with IS_ID/IS_CLASS anyway we
> might as well test with PROTOCOL_LIST.  So in this patch I've removed
> the existing macro.
>
> I'm not sure whether I can sensibly simplify objc_comptypes to get
> rid of objc_comptypes_proto_proto, at least not without a considerable
> rewrite of objc_comptypes which I'd rather not do at this stage.  But 
> if
> it's really important to you, I'll look into it.

Hmm... I guess my comment was motivated by the belief that 'Class 
<Proto>'
is virtually identical to 'id <Proto>' as far as type comparisons are
concerned, and the few differences (if any) could easily be 
special-cased.
Do you disagree?

Perhaps creating a routine like objc_comptypes_proto_proto() would make
sense as part of a deeper objc_comptypes() rewrite that I've alluded to
before, but right now this strikes me as unduly invasive.  For the same
reason, I would favor keeping (though possibly renaming, if you like)
the IS_PROTOCOL_QUALIFIED_ID macro and enhancing it to accept 'Class 
<Proto>'.
Longer term, perhaps killing this macro altogether is a good idea, as
you suggest.

>
>>> @@ -1164,7 +1251,7 @@
>>>
>>> /* Construct a PROTOCOLS-qualified variant of INTERFACE, where
>>> INTERFACE may
>>>    either name an Objective-C class, or refer to the special 'id' or
>>> 'Class'
>>> -   types.  If INTERFACE is not a valid ObjC type, just return it
>>> unchanged.  */
>>> +   types.  If INTERFACE is not a valid ObjC type, report error.  */
>>>
>>> tree
>>> objc_get_protocol_qualified_type (tree interface, tree protocols)
>>> @@ -1180,7 +1267,7 @@
>>>       if (type)
>>> 	type = xref_tag (RECORD_TYPE, type);
>>>       else
>>> -        return interface;
>>> +        error ("protocol qualifiers specified for non-Objective-C
>>> type");
>>
>>
>> Thanks for the error message, but you should still return here instead
>> of falling through, I think...
>
> Indeed!  In fact I think we should return an error_mark_node.
>
>>> +      /* Minor efficency check.  Expect all protocols which have
>>> +	 been previously marked, to have had their methods registered.
>>
>>
>> s/efficency/efficiency/.
>
> Thanks.
>
>>> +	 A protocol which itself is not declared by a root class yet
>>> +	 is inherited by multiple root classes will have its instance
>>
>>
>> What is the difference between "declared by a root class" and
>> "inherited by
>> a root class"?  I was assuming the two are synonymous...
>
> Sorry, bad terminology, bad wording.  It should have read:
>
>       /* Minor efficiency check.  Expect all protocols which have
>          been previously marked, to have had their methods registered.
>          A protocol which itself is not *adopted* by a root class, yet
>          is *incorporated* by other protocols which are adopted by root
>          classes will have its instance methods processed redundantly,
>          but it does not seem worth while to flag them just to avoid
>          this.  */
>
> ... but hmm again ...
>
>>> +	 methods processed redundantly, but it does not seem worth while
>>> +	 to flag them just to avoid this.  */
>>> +      if (!PROTOCOL_DECLARED_BY_ROOT (protocol))
>>> +	{
>>> +	  tree method_decl;
>>> +
>>> +	  for (method_decl = PROTOCOL_NST_METHODS (protocol);
>>> +	       method_decl;
>>> +	       method_decl = TREE_CHAIN (method_decl))
>>> +	    {
>>> +	      add_method_to_hash_list(cls_method_hash_list,  method_decl);
>>> +	    }
>>> +	}
>>
>>
>> Again, I suspect that adding these to cls_method_hash_list is 
>> redundant
>> (see above).
>>
>
> I don't, see above :-).

Agreed. :-)
>
>>> +/* Searches for SELECTOR in the instance methods
>>> +   of the protocol interface list RPROTOS.  Returns
>>> +   the prototype only if the corresponding protocol from RPROTOS
>>> +   is declared by any root class.  IGNORE should always be 0.
>>> +   It is used for the recursive prototype search of inherited
>>> protocols.  */
>>> +
>>> +static tree
>>> +instance_prototype_of_root_protocol (tree rprotos, tree selector, 
>>> int
>>> ignore)
> ...
>>> @@ -5569,14 +5745,24 @@
>>> 	}
>>>       else
>>> 	{
>>> +	  rprotos = TYPE_PROTOCOL_LIST (rtype);
>>> 	  class_tree = objc_class_name;
>>> 	  OBJC_SET_TYPE_NAME (rtype, class_tree);
>>> +
>>> +	  if (rprotos)
>>> +	    rtype = NULL_TREE;
>>> 	}
>>>
>>>       if (rprotos)
>>> -	method_prototype
>>> -	  = lookup_method_in_protocol_list (rprotos, sel_name,
>>> -					    class_tree != NULL_TREE);
>>> +	{
>>> +	  method_prototype
>>> +	    = lookup_method_in_protocol_list (rprotos, sel_name,
>>> +					      class_tree != NULL_TREE);
>>> +	  if (!method_prototype && class_tree != NULL_TREE)
>>> +	    method_prototype
>>> +	      = instance_prototype_of_root_protocol(rprotos, sel_name, 0);
>>> +	}
>>> +
>>
>>
>> Here, instead of calling (and defining!)
>> instance_prototype_of_root_protocol(), perhaps you
>> can simply tweak lookup_method_in_protocol_list() so that if a class
>> method is sought,
>> it can fall back to instance methods for protocols used in root 
>> classes?
>
> I think so.  I may have to add a parameter to handle the recursive
> search with respect to incorporated protocols, but ...hmm... maybe I 
> don't.

Actually, if my hunch above is correct (and I hope it is :-), you 
shouldn't need to modify
lookup_method_in_protocol_list() at all, and you will not need 
instance_prototype_of_root_protocol()
either since lookup_method_in_hash_lists() should find the instance 
methods for you.
Hopefully, the sole use of the PROTOCOL_ADOPTED_BY_ROOT_CLASS flag will 
henceforth be to
indicate that a protocol's instance methods were put into the global 
class method hash table.
>
>>> Index: gcc/objc/objc-act.h
>>> ===================================================================
>>> RCS file: /cvsroot/gcc/gcc/gcc/objc/objc-act.h,v
>>> retrieving revision 1.31
>>> diff -u -r1.31 objc-act.h
>>> --- gcc/objc/objc-act.h	22 Sep 2004 01:13:07 -0000	1.31
>>> +++ gcc/objc/objc-act.h	28 Sep 2004 18:23:08 -0000
> ...
>>> @@ -279,6 +288,8 @@
>>>   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == TREE_TYPE
>>> (objc_class_type))
>>> #define IS_PROTOCOL_QUALIFIED_ID(TYPE) \
>>>   (IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE))
>>> +#define IS_PROTOCOL_QUALIFIED_CLASS(TYPE) \
>>> +  (IS_CLASS (TYPE) && TYPE_PROTOCOL_LIST (TYPE))
>>
>>
>> As I mentioned above, instead of adding IS_PROTOCOL_QUALIFIED_CLASS,
>> I'd simply enhance IS_PROTOCOL_QUALIFIED_ID thusly:
>>
>>     #define IS_PROTOCOL_QUALIFIED_ID(TYPE) \
>>        ((IS_ID (TYPE) || IS_CLASS (TYPE)) && TYPE_PROTOCOL_LIST 
>> (TYPE))
>>
>> This should simplify the objc_comptypes() logic greatly.  Feel free to
>> rename this macro to IS_PROTO_QUAL_ID_OR_CLASS
>> or some such if you'd like...
>
> Like I implied above, I don't think rewriting objc_comptypes at this
> stage is a good idea, but if that is a prerequisite, I'll try.

Actually, my objection was that you perturbed objc_comptypes() _too 
much_. :-)
I absolutely agree that this is not the time for rewriting it.

> Now to my three '...hmm...'s:  I had originally decided it was a bad
> idea to mark protocols, that are incorporated by protocols which were
> adopted by root classes, as also being adopted by root classes.  The
> issue is in the test case.  Consider:
>
> @protocol MyProto8
> +(void)doItClass8;
> -(void)doItInstance8;
> @end
>
> @protocol MyProto9 <MyProto8>
> +(void)doItClass9;
> -(void)doItInstance9;
> @end
>
> @interface MyClass1 <MyProto9>
> @end
>
> Class <MyProto8> clsP8 = 0;
>
> ...
>   [clsP8 doItInstance8]; /* { dg-warning "not implemented" } */
>
> Now, does the fact that a root class adopts MyProto9, which 
> incorporates
> MyProto8, make MyProto8 a "root" protocol in the sense that we should
> search for instance methods when sending messages to Class <Proto8> ?  
> I
> admit this is a corner case that may not warrant the extra complexity.
> This updated patch would make MyProto8 a full fledged "root" protocol.

I agree; since MyProto9 is a "root protocol", then so is MyProto8, and 
so
the warning above should not be generated.  Yes, this is overkill, since
we don't know if 'clsP8' points at a 'MyClass1' or not, but this is the
same overkill as we already have with root classes themselves, as 
mentioned
above.

>
> I did add a flag to lookup_method_in_protocol_list to indicate whether
> instance methods of protocols adopted by root classes should be
> searched, so the caller can decide.  This is necessary as we only want
> to use this feature if we actually have 'Class', not when we have a
> "concrete" MyClass4 that is not a root class but implements a protocol
> that is a root class of a different hierarchy:
>
> @protocol MyProto1
> @end

You mean

   @protocol MyProto1
   -doItInstance1;
   @end

right?

>
> @interface MyClass1 <MyProto1> /* root */
> @end
> @interface MyClass2 : MyClass1
> @end
> @interface MyClass3 /* New root */
> @end
> @interface MyClass4 : MyClass3 <MyProto1>
> @end
>
>   [MyClass2 doItInstance1]; /* Do not warn */
> ...
>   [MyClass4 doItInstance1]; /* { dg-warning "may not respond to" } */
>

In this case, the lookup should be performed by lookup_method_static(), 
which I
believe already does what it should.  I agree with you that the warning 
_is_
needed in the second case, but lookup_method_static() should _not_ be 
able to
stumble upon MyProto1 while searching for +doItInstance1 in MyClass4; 
if it does
somehow find it, then I think it's buggy. :-(  So again, I don't think 
you
need to do anything beyond what's already being done to handle this 
case.

Anyway, thanks for putting up with my critique.  The c-parse.in portion 
of your
patch is right on the money, BTW.

--Zem

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-29 21:25           ` Ziemowit Laski
@ 2004-09-30  0:01             ` d.ayers
  2004-09-30  7:17               ` Ziemowit Laski
  0 siblings, 1 reply; 35+ messages in thread
From: d.ayers @ 2004-09-30  0:01 UTC (permalink / raw)
  To: zlaski; +Cc: gcc-patches

>
> On 29 Sep 2004, at 10.34, David Ayers wrote:
>
>> Ziemowit Laski wrote:
>>
>
> You are missing a space following opening parenths in several places,
> e.g.,
>
>>>> +	{
>>>> +	  add_method_to_hash_list(cls_method_hash_list,  method_decl); +	}
>
> where you also have an extraneous space (or perhaps a tab?) after the
> comma.

I believe this is just a  display issue with diff/patches.  If you apply
the patch the spacing should be correct.

>> Well, yes, instance methods of root classes are already in
>> cls_method_hash_list but generally/often the methods of adopted
>> protocols are not repeated in the interface declaration by convention,
>> which is what makes this necessary, I believe.
>
> Ok, that's a good point.  I guess there's still overkill in that the
> instance
> methods thusly added will serve as a fallback for _any_ class method
> lookup
> (i.e., even if the protocol in question is not involved), but the same
> overkill
> happens wrt root classes, which also happily stuff all of their
> instance methods
> into cls_method_hash_list.  So yes, I think your approach is consistent.

Yes, that was my intent.

> However, this raises a different question in my mind: If protocols
> adopted by
> root classes already stuff their instance methods into the global class
> method
> table, do we need to do anything more than we already do to find them?
> In
> other words, if I have
>
>        @protocol Proto2
>        - someMessage;
>        @end
>
>        @interface Root <Proto2>
>        @end
>
>        Class <Proto1, Proto2> obj;
>          :
>        [obj someMessage];
>
> the compiler should look for +someMessage in Proto1 and Proto2 (only a
> slight
> variation from the 'id <Proto1, Proto2>' case, where both -someMessage
> and
> +someMessage would be sought) and then fall back to the the global class
> method table (again, a slight variation from 'id <Proto1, Proto2>' where
> both global tables would be examined), and therein find the -someMessage
> method from Proto2.
>
> What do you think?  Or am I missing something?

I'd rather keep the search correct wrt diagnostics and really warn if

@protocol Proto3
-someMessage3;
@end
@interface Root2 <Proto3>
@end

Class <Proto1, Proto2> obj;
[obj someMessage3];

from the type information we have the object won't respond.  For code
generation we should definitely use the global prototype, but I think
that's what we are doing.

>>
>>>> +
>>>> +      /* This protocol is marked.  Now insure that that all
>>>> instance
>>>
>>>
>>> s/insure/ensure/ :-), although you probably just want to say that
>>> protocols inherited by a marked protocols are
>>> themselves marked.
>>
>> Actually what I meant was:
>>
>>       /* This protocol is marked.  Now ensure that that all instance
>>          prototypes of incorporated protocols are registered as class
>> methods without marking the protocols.  */
>
> Perhaps instead of 'incorporated', we should consistently say
> 'inherited'?

Actually "incorporated" is the term used in the "Objective-C" book.
http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/LanguageSummary/chapter_5_section_8.html
And the term "inherited" is a bit misleading.  The concept doesn't really
match protocols.

> What do Java people say when one interface refers to another? :-)

No offense, but that is irrelevant.  I'm sure I 'm not the only one that
would appreciate if Objective-C maintainers instinctively look to copy
Java for "inspiration" :-)

> Actually, I do think objc_comptypes() needs to be seriously reworked to
> remove the spaghetti, but that will have to wait for gcc 4.1 stage  1...
>>

Yes indeed, the rework is necessary, but 4.1 is a good target I believe.

>>>> +/* Return 1 if LHS and RHS are compatible types for assignment or
>>>>    various other operations.  Return 0 if they are incompatible, and
>>>> return -1 if we choose to not decide (because the types are
>>>> really just C types, not ObjC specific ones).  When the operation
>>>> is
>>>> @@ -866,76 +968,21 @@
>>>>       && TREE_CODE (rhs) == POINTER_TYPE
>>>>       && TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE)
>>>>     {
>>>> -      int lhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (lhs);
>>>> -      int rhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (rhs);
>>>> +      int lhs_is_proto_id = IS_PROTOCOL_QUALIFIED_ID (lhs);
>>>> +      int rhs_is_proto_id = IS_PROTOCOL_QUALIFIED_ID (rhs);
>>>> +      int lhs_is_proto_class = IS_PROTOCOL_QUALIFIED_CLASS (lhs); +
>>>>      int rhs_is_proto_class = IS_PROTOCOL_QUALIFIED_CLASS (rhs);
>>>
>>>
>>> I'm not sure why it is necessary to distinguish between
>>> IS_PROTOCOL_QUALIFIED_ID
>>> and IS_PROTOCOL_QUALIFIED_CLASS for purposes for objc_comptypes().
>>> In most
>>> cases, the two behave identically for type comparison purposes, and
>>> in any places
>>> they do not you can use IS_ID / IS_CLASS to distinguish them.  Then,
>>> you can
>>> keep objc_comptypes() mostly as it is, and get rid of
>>> objc_comptypes_proto_proto().
>>
>> I just tried to stay in line with the existing implementation.
>> Actually, I'm not sure what value that macro has.  It is used only
>> here in comptypes and as you now need to work with IS_ID/IS_CLASS
>> anyway we might as well test with PROTOCOL_LIST.  So in this patch
>> I've removed the existing macro.
>>
>> I'm not sure whether I can sensibly simplify objc_comptypes to get rid
>> of objc_comptypes_proto_proto, at least not without a considerable
>> rewrite of objc_comptypes which I'd rather not do at this stage.  But
>> if
>> it's really important to you, I'll look into it.
>
> Hmm... I guess my comment was motivated by the belief that 'Class
> <Proto>'
> is virtually identical to 'id <Proto>' as far as type comparisons are
> concerned, and the few differences (if any) could easily be
> special-cased.
> Do you disagree?

Well yes, I agree that they are virtually identical, which is why it was
so easy to
"write" objc_comptypes_proto_proto.  Maybe I should have mentioned that
this is a verbatim copy if the previuos handling in the "Protocol" =
"Protocol" case, plus the assertion that both parameters must either be
'id' or both be 'Class'.


> Perhaps creating a routine like objc_comptypes_proto_proto() would make
> sense as part of a deeper objc_comptypes() rewrite that I've alluded to
> before, but right now this strikes me as unduly invasive.  For the same
> reason, I would favor keeping (though possibly renaming, if you like)
> the IS_PROTOCOL_QUALIFIED_ID macro and enhancing it to accept 'Class
> <Proto>'.

Actually that was my first approach for objc_comptypes, but it doesn't buy
us much.
You are correct that for the
 IS_PROTOCOL_QUALIFIED_CLASS_OR_ID = IS_PROTOCOL_QUALIFIED_CLASS_OR_ID
we could then split into IS_CLASS = IS_CLASS and IS_ID = ID_ID cases.
But we also have to deal with the
IS_PROTOCOL_QUALIFIED_CLASS_OR_ID = <something else>
and
<something else> = IS_PROTOCOL_QUALIFIED_CLASS_OR_ID.
And then sprinkle IS_ID or IS_CLASS barnces all over the place.
I believe the current approach is a lot less intrussive, as the handling
of Class <protocol> types are 'neatly' grouped.  If you still beleive that
the other approach is better, I'll look into it tomorrow.

> Longer term, perhaps killing this macro altogether is a good idea, as
> you suggest.

OK, If you want I can re add the existing macro and do the IS_CLASS &&
PROTOCOL_LIST check.  But I'd prefer to either have both macros or none. 
The 'combined' macro is of little use in my view.

>>> Here, instead of calling (and defining!)
>>> instance_prototype_of_root_protocol(), perhaps you
>>> can simply tweak lookup_method_in_protocol_list() so that if a class
>>> method is sought,
>>> it can fall back to instance methods for protocols used in root
>>> classes?
>>
>> I think so.  I may have to add a parameter to handle the recursive
>> search with respect to incorporated protocols, but ...hmm... maybe I
>> don't.
>
> Actually, if my hunch above is correct (and I hope it is :-), you
> shouldn't need to modify
> lookup_method_in_protocol_list() at all, and you will not need
> instance_prototype_of_root_protocol()
> either since lookup_method_in_hash_lists() should find the instance
> methods for you.
> Hopefully, the sole use of the PROTOCOL_ADOPTED_BY_ROOT_CLASS flag will
> henceforth be to
> indicate that a protocol's instance methods were put into the global
> class method hash table.

I don't think it worth loosing that type information.  We need to account
for several root classes each possibly adopting different protocols.

>>> This should simplify the objc_comptypes() logic greatly.  Feel free
>>> to rename this macro to IS_PROTO_QUAL_ID_OR_CLASS
>>> or some such if you'd like...
>>
>> Like I implied above, I don't think rewriting objc_comptypes at this
>> stage is a good idea, but if that is a prerequisite, I'll try.
>
> Actually, my objection was that you perturbed objc_comptypes() _too
> much_. :-)
> I absolutely agree that this is not the time for rewriting it.

In the light that objc_comptypes_proto_proto was merely extracted from the
old implementation and that all the Class <proto> stuff is neatly grouped
together, do you still believe that perturbed objc_comptypes too muich?  I
really think that doing it differently will be a lot worse.

>> Now to my three '...hmm...'s:  I had originally decided it was a bad
>> idea to mark protocols, that are incorporated by protocols which were
>> adopted by root classes, as also being adopted by root classes.  The
>> issue is in the test case.  Consider:
>>
>> @protocol MyProto8
>> +(void)doItClass8;
>> -(void)doItInstance8;
>> @end
>>
>> @protocol MyProto9 <MyProto8>
>> +(void)doItClass9;
>> -(void)doItInstance9;
>> @end
>>
>> @interface MyClass1 <MyProto9>
>> @end
>>
>> Class <MyProto8> clsP8 = 0;
>>
>> ...
>>   [clsP8 doItInstance8]; /* { dg-warning "not implemented" } */
>>
>> Now, does the fact that a root class adopts MyProto9, which
>> incorporates
>> MyProto8, make MyProto8 a "root" protocol in the sense that we should
>> search for instance methods when sending messages to Class <Proto8> ?
>>  I
>> admit this is a corner case that may not warrant the extra complexity.
>> This updated patch would make MyProto8 a full fledged "root" protocol.
>
> I agree; since MyProto9 is a "root protocol", then so is MyProto8, and
> so
> the warning above should not be generated.  Yes, this is overkill, since
> we don't know if 'clsP8' points at a 'MyClass1' or not, but this is the
> same overkill as we already have with root classes themselves, as
> mentioned
> above.

Well just because a class conforms to MyProto8 does not mean it is a class
who's root class conforms to MyProto9 so we are being rather lax but the
case can be a bit pathalogical and the complexity not worth the trouble.

>>
>> I did add a flag to lookup_method_in_protocol_list to indicate whether
>> instance methods of protocols adopted by root classes should be
>> searched, so the caller can decide.  This is necessary as we only want
>> to use this feature if we actually have 'Class', not when we have a
>> "concrete" MyClass4 that is not a root class but implements a protocol
>> that is a root class of a different hierarchy:
>>
>> @protocol MyProto1
>> @end
>
> You mean
>
>    @protocol MyProto1
>    -doItInstance1;
>    @end
>
> right?

Indeed :-) This was from the test case.

>>
>> @interface MyClass1 <MyProto1> /* root */
>> @end
>> @interface MyClass2 : MyClass1
>> @end
>> @interface MyClass3 /* New root */
>> @end
>> @interface MyClass4 : MyClass3 <MyProto1>
>> @end
>>
>>   [MyClass2 doItInstance1]; /* Do not warn */
>> ...
>>   [MyClass4 doItInstance1]; /* { dg-warning "may not respond to" } */
>>
>
> In this case, the lookup should be performed by lookup_method_static(),
> which I
> believe already does what it should.  I agree with you that the warning
> _is_
> needed in the second case, but lookup_method_static() should _not_ be
> able to
> stumble upon MyProto1 while searching for +doItInstance1 in MyClass4;
> if it does
> somehow find it, then I think it's buggy. :-(  So again, I don't think
> you
> need to do anything beyond what's already being done to handle this
> case.

Yet lookup_method_static uses lookup_method_in_protocol_list, so that is
exactly the place where I need to tell it to act differently :-)

Cheers,
David



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-30  0:01             ` d.ayers
@ 2004-09-30  7:17               ` Ziemowit Laski
  2004-09-30 14:06                 ` David Ayers
  0 siblings, 1 reply; 35+ messages in thread
From: Ziemowit Laski @ 2004-09-30  7:17 UTC (permalink / raw)
  To: d.ayers; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 3782 bytes --]


On 29 Sep 2004, at 15.00, d.ayers@inode.at wrote:

>>
>> On 29 Sep 2004, at 10.34, David Ayers wrote:
>>
>>> Ziemowit Laski wrote:
>>>
>>
>> You are missing a space following opening parenths in several places,
>> e.g.,
>>
>>>>> +	{
>>>>> +	  add_method_to_hash_list(cls_method_hash_list,  method_decl); 
>>>>> +	}
>>
>> where you also have an extraneous space (or perhaps a tab?) after the
>> comma.
>
> I believe this is just a  display issue with diff/patches.  If you 
> apply
> the patch the spacing should be correct.

No, I don't think that patch will add the space missing between 
'add_method_to_hash_list'
and '(' in the line above.  And, you obviously have something other 
than a single space
following the ',' -- it could be a single tab, but that still should be 
changed.

>> However, this raises a different question in my mind: If protocols
>> adopted by
>> root classes already stuff their instance methods into the global 
>> class
>> method
>> table, do we need to do anything more than we already do to find them?
>> In
>> other words, if I have
>>
>>        @protocol Proto2
>>        - someMessage;
>>        @end
>>
>>        @interface Root <Proto2>
>>        @end
>>
>>        Class <Proto1, Proto2> obj;
>>          :
>>        [obj someMessage];
>>
>> the compiler should look for +someMessage in Proto1 and Proto2 (only a
>> slight
>> variation from the 'id <Proto1, Proto2>' case, where both -someMessage
>> and
>> +someMessage would be sought) and then fall back to the the global 
>> class
>> method table (again, a slight variation from 'id <Proto1, Proto2>' 
>> where
>> both global tables would be examined), and therein find the 
>> -someMessage
>> method from Proto2.
>>
>> What do you think?  Or am I missing something?
>
> I'd rather keep the search correct wrt diagnostics and really warn if
>
> @protocol Proto3
> -someMessage3;
> @end
> @interface Root2 <Proto3>
> @end
>
> Class <Proto1, Proto2> obj;
> [obj someMessage3];
>
> from the type information we have the object won't respond.

Well, I think that we ought to have behavior here that is analogous to
what would happen if we use 'id <Proto1, Proto2>' instead.  I tried
substituting 'id' for 'Class' in your example, and the compiler
spewed out

   warning: `-someMessage3' not implemented by protocol(s)

which is a somewhat narrower indictment than saying that the object
may not respond to the message at all.  Now, if we put 'Class' back
in place of 'id', I'd argue the compiler should say

   warning: `+someMessage3' not implemented by protocol(s)

since, narrowly speaking, neither Proto1 nor Proto2 provide 
+someMessage3.

Of course, I now realize that the example that I gave you _should_, in 
fact,
provide a diagnostic:

   warning: `+someMessage' not implemented by protocol(s)

even though there is a '-someMessage' that will (probably) wind up 
being used.

This, of course, leads to an even greater epiphany :-) -- messaging 'id 
<ProtoList>'
or 'Class <ProtoList>' is simpler in that it only checks if ProtoList 
provides
the method (instance method in case of 'id <ProtoList>', class method 
in case
of 'Class <ProtoList>') and if it does not, it generates a warning 
_even if_
some root class somewhere (and/or protocol thereto attached) happens to
provide such a method.

I apologize for not realizing this earlier; I kept thinking of when to
issue the warning 'Class <Proto1, Proto2> may not respond to "bar"' and 
when
to suppress it.  A brief lecture of objc-act.c now reminded me that such
a warning should _never_ be issued for receivers of type 'id' or 
'Class',
whether protocol-qualified or not.

In summation, I believe that the only necessary changes to 
objc_finish_message_expr()
are the following (I've attached it inline to preserve tabulation):


[-- Attachment #2: objc.20040929.diff.txt --]
[-- Type: text/plain, Size: 1261 bytes --]

Index: gcc/objc/objc-act.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.248
diff -u -3 -p -r1.248 objc-act.c
--- gcc/objc/objc-act.c	24 Sep 2004 23:15:33 -0000	1.248
+++ gcc/objc/objc-act.c	30 Sep 2004 01:13:57 -0000
@@ -5570,7 +5570,8 @@ objc_finish_message_expr (tree receiver,
       else
 	{
 	  class_tree = objc_class_name;
-	  OBJC_SET_TYPE_NAME (rtype, class_tree);
+	  rprotos = TYPE_PROTOCOL_LIST (rtype);
+	  rtype = NULL_TREE;
 	}
 
       if (rprotos)
@@ -5650,10 +5651,19 @@ objc_finish_message_expr (tree receiver,
 		 IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)),
 		 (class_tree ? '+' : '-'),
 		 IDENTIFIER_POINTER (sel_name));
+      /* If we are messaging an unadorned 'id' or 'Class' object,
+	 then we have failed to find _any_ instance or class method,
+	 respectively.  */
+      else if (!rprotos)
+	warning ("no `%c%s' method found",
+		 (class_tree ? '+' : '-'),
+		 IDENTIFIER_POINTER (sel_name));
+
       if (rprotos)
 	warning ("`%c%s' not implemented by protocol(s)",
 		 (class_tree ? '+' : '-'),
 		 IDENTIFIER_POINTER (sel_name));
+		 
       if (!warn_missing_methods)
 	{
 	  warning ("(Messages without a matching method signature");

[-- Attachment #3: Type: text/plain, Size: 7251 bytes --]



At this point, I'm wondering whether (1) PROTOCOL_ADOPTED_BY_ROOT_CLASS  
is needed at
all and (2) if instance methods of protocols adopted by root classes  
should be placed
in the class method hash table.  Doing so will make no difference  
whatsoever when
messaging 'Class <ProtoList>', but may help out when messaging an  
unadorned 'Class'.
What do you think?  I have yet to develop a strong opinion here... :-)

Anyway, I eagerly await your response to my messaging epiphany...

>> Perhaps instead of 'incorporated', we should consistently say
>> 'inherited'?
>
> Actually "incorporated" is the term used in the "Objective-C" book.
> http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/ 
> LanguageSummary/chapter_5_section_8.html
> And the term "inherited" is a bit misleading.  The concept doesn't  
> really
> match protocols.

Why not?  If you think of protocols as abstract interfaces, then  
"inherit" fits
the bill perfectly, I would think...  Personally, I find "incorporate"  
a bit vague,
since it could mean that you're manually repeating the method  
declarations from the
other protocol...

>
>> What do Java people say when one interface refers to another? :-)
>
> No offense, but that is irrelevant.  I'm sure I 'm not the only one  
> that
> would appreciate if Objective-C maintainers instinctively look to copy
> Java for "inspiration" :-)

You're not being constructive here.  :-(  If, as you say, the term  
"inherited"
is misleading, then it definitely _is_ interesting to see what term the  
Java-ites settled on
in order to maintain this distinction and avoid confusion.  Just as Java
"inherited" (pun intended) the notion of protocols/interfaces from  
ObjC, so
we can definitely borrow their terminology if we find it useful.
>
>> Hmm... I guess my comment was motivated by the belief that 'Class
>> <Proto>'
>> is virtually identical to 'id <Proto>' as far as type comparisons are
>> concerned, and the few differences (if any) could easily be
>> special-cased.
>> Do you disagree?
>
> Well yes, I agree that they are virtually identical, which is why it  
> was
> so easy to
> "write" objc_comptypes_proto_proto.  Maybe I should have mentioned that
> this is a verbatim copy if the previuos handling in the "Protocol" =
> "Protocol" case, plus the assertion that both parameters must either be
> 'id' or both be 'Class'.

OK, but then objc_comptypes_proto_proto() is nothing more than a  
gratuitous
rewrite of objc_comptypes(), which I thought we agreed should wait until
later... :-)
>
>
>> Perhaps creating a routine like objc_comptypes_proto_proto() would  
>> make
>> sense as part of a deeper objc_comptypes() rewrite that I've alluded  
>> to
>> before, but right now this strikes me as unduly invasive.  For the  
>> same
>> reason, I would favor keeping (though possibly renaming, if you like)
>> the IS_PROTOCOL_QUALIFIED_ID macro and enhancing it to accept 'Class
>> <Proto>'.
>
> Actually that was my first approach for objc_comptypes, but it doesn't  
> buy
> us much.

But do you need to buy anything? :-)

I'm curious... if you were just to augment the definition of  
IS_PROTOCOL_QUALIFIED_ID
to encompass 'Class <Proto>' constructs, but left objc_comptypes() in  
its original
form, which comparisons would break as a result?

>> Actually, if my hunch above is correct (and I hope it is :-), you
>> shouldn't need to modify
>> lookup_method_in_protocol_list() at all, and you will not need
>> instance_prototype_of_root_protocol()
>> either since lookup_method_in_hash_lists() should find the instance
>> methods for you.
>> Hopefully, the sole use of the PROTOCOL_ADOPTED_BY_ROOT_CLASS flag  
>> will
>> henceforth be to
>> indicate that a protocol's instance methods were put into the global
>> class method hash table.
>
> I don't think it worth loosing that type information.  We need to  
> account
> for several root classes each possibly adopting different protocols.

But lookup_method_static() has access to this information as is; see  
below.
>
>>> @protocol MyProto8
>>> +(void)doItClass8;
>>> -(void)doItInstance8;
>>> @end
>>>
>>> @protocol MyProto9 <MyProto8>
>>> +(void)doItClass9;
>>> -(void)doItInstance9;
>>> @end
>>>
>>> @interface MyClass1 <MyProto9>
>>> @end
>>>
>>> Class <MyProto8> clsP8 = 0;
>>>
>>> ...
>>>   [clsP8 doItInstance8]; /* { dg-warning "not implemented" } */
>>>
>>> Now, does the fact that a root class adopts MyProto9, which
>>> incorporates
>>> MyProto8, make MyProto8 a "root" protocol in the sense that we should
>>> search for instance methods when sending messages to Class <Proto8> ?
>>>  I
>>> admit this is a corner case that may not warrant the extra  
>>> complexity.
>>> This updated patch would make MyProto8 a full fledged "root"  
>>> protocol.
>>
>> I agree; since MyProto9 is a "root protocol", then so is MyProto8, and
>> so
>> the warning above should not be generated.  Yes, this is overkill,  
>> since
>> we don't know if 'clsP8' points at a 'MyClass1' or not, but this is  
>> the
>> same overkill as we already have with root classes themselves, as
>> mentioned
>> above.
>
> Well just because a class conforms to MyProto8 does not mean it is a  
> class
> who's root class conforms to MyProto9 so we are being rather lax but  
> the
> case can be a bit pathalogical and the complexity not worth the  
> trouble.

Yes, I humbly reverse my previous opinion; see above.

>
>>>
>>> I did add a flag to lookup_method_in_protocol_list to indicate  
>>> whether
>>> instance methods of protocols adopted by root classes should be
>>> searched, so the caller can decide.  This is necessary as we only  
>>> want
>>> to use this feature if we actually have 'Class', not when we have a
>>> "concrete" MyClass4 that is not a root class but implements a  
>>> protocol
>>> that is a root class of a different hierarchy:
>>>
>>> @protocol MyProto1
>>> @end
>>
>> You mean
>>
>>    @protocol MyProto1
>>    -doItInstance1;
>>    @end
>>
>> right?
>
> Indeed :-) This was from the test case.
>
>>>
>>> @interface MyClass1 <MyProto1> /* root */
>>> @end
>>> @interface MyClass2 : MyClass1
>>> @end
>>> @interface MyClass3 /* New root */
>>> @end
>>> @interface MyClass4 : MyClass3 <MyProto1>
>>> @end
>>>
>>>   [MyClass2 doItInstance1]; /* Do not warn */
>>> ...
>>>   [MyClass4 doItInstance1]; /* { dg-warning "may not respond to" } */
>>>
>>
>> In this case, the lookup should be performed by  
>> lookup_method_static(),
>> which I
>> believe already does what it should.  I agree with you that the  
>> warning
>> _is_
>> needed in the second case, but lookup_method_static() should _not_ be
>> able to
>> stumble upon MyProto1 while searching for +doItInstance1 in MyClass4;
>> if it does
>> somehow find it, then I think it's buggy. :-(  So again, I don't think
>> you
>> need to do anything beyond what's already being done to handle this
>> case.
>
> Yet lookup_method_static uses lookup_method_in_protocol_list, so that  
> is
> exactly the place where I need to tell it to act differently :-)

I think, though, that when lookup_method_static() reaches the top of the
hierarchy when searching for class methods, it will search for instance
methods in the root class _and_ its associated protocols as a last gasp,
no?

--Zem


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-29 19:40           ` Ziemowit Laski
@ 2004-09-30  9:00             ` Kai Henningsen
  0 siblings, 0 replies; 35+ messages in thread
From: Kai Henningsen @ 2004-09-30  9:00 UTC (permalink / raw)
  To: gcc-patches

zlaski@apple.com (Ziemowit Laski)  wrote on 29.09.04 in <F5816C3B-1244-11D9-BAE3-000393673036@apple.com>:

> On 28 Sep 2004, at 23.41, Kai Henningsen wrote:
>
> > zlaski@apple.com (Ziemowit Laski)  wrote on 28.09.04 in
> > <EEFE950A-11AF-11D9-8A9A-000393673036@apple.com>:
> >
> >> What is the difference between "declared by a root class" and
> >> "inherited by
> >> a root class"?  I was assuming the two are synonymous...
> >
> > I thought if it inherited *anything*, it *wasn't* a root class pretty
> > much
> > by definition?!
>
> I used "inherited" a bit loosely; what I (and David) should have said
> is "adopted". :-)  ObjC protocols
> get adopted by ObjC classes (much like Java interfaces get adopted by
> Java classes), but ObjC
> classes do not declare protocols.

The declare/adopt difference doesn't bother me, but inheritance - to me -  
means implementation, not just interface.

Or looking at it a different way, inheritance, in Objective C, is the hard  
part of the graph; protocols are the soft part, and categories are the  
hacky part [:-)].

MfG Kai

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-30  7:17               ` Ziemowit Laski
@ 2004-09-30 14:06                 ` David Ayers
  2004-09-30 22:33                   ` Ziemowit Laski
  0 siblings, 1 reply; 35+ messages in thread
From: David Ayers @ 2004-09-30 14:06 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc-patches

Ziemowit Laski wrote:
> On 29 Sep 2004, at 15.00, d.ayers@inode.at wrote:
> 
> 
> No, I don't think that patch will add the space missing between 
> 'add_method_to_hash_list' and '(' in the line above.  And, you
> obviously have something other than a single space following the ','
> -- it could be a single tab, but that still should be changed.

My bad.  Don't know what I was looking at/for yesterday.

>>> However, this raises a different question in my mind: If
>>> protocols adopted by root classes already stuff their instance
>>> methods into the global class method table, do we need to do
>>> anything more than we already do to find them? In other words, if
>>> I have
>>>
>>>       @protocol Proto2
>>>       - someMessage;
>>>       @end
>>>
>>>       @interface Root <Proto2>
>>>       @end
>>>
>>>       Class <Proto1, Proto2> obj;
>>>         :
>>>       [obj someMessage];
>>>
>>> the compiler should look for +someMessage in Proto1 and Proto2
>>> (only a slight variation from the 'id <Proto1, Proto2>' case,
>>> where both -someMessage and +someMessage would be sought) and
>>> then fall back to the the global class method table (again, a
>>> slight variation from 'id <Proto1, Proto2>' where both global
>>> tables would be examined), and therein find the
>>> -someMessage
>>> method from Proto2.
>>> 
>>> What do you think? Or am I missing something?
>>
>>I'd rather keep the search correct wrt diagnostics and really warn if
>>
>>@protocol Proto3
>>-someMessage3;
>>@end
>>@interface Root2 <Proto3>
>>@end
>>
>>Class <Proto1, Proto2> obj;
>>[obj someMessage3];
>>
>>from the type information we have the object won't respond.
> 
> 
> Well, I think that we ought to have behavior here that is analogous to
> what would happen if we use 'id <Proto1, Proto2>' instead.  I tried
> substituting 'id' for 'Class' in your example, and the compiler
> spewed out
> 
>    warning: `-someMessage3' not implemented by protocol(s)
> 
> which is a somewhat narrower indictment than saying that the object
> may not respond to the message at all.  Now, if we put 'Class' back
> in place of 'id', I'd argue the compiler should say
> 
>    warning: `+someMessage3' not implemented by protocol(s)
> 
> since, narrowly speaking, neither Proto1 nor Proto2 provide 
> +someMessage3.
> 
> Of course, I now realize that the example that I gave you _should_,
> in fact, provide a diagnostic:
> 
>    warning: `+someMessage' not implemented by protocol(s)
> 
> even though there is a '-someMessage' that will (probably) wind up 
> being used.
> 
> This, of course, leads to an even greater epiphany :-) -- messaging
> 'id <ProtoList>' or 'Class <ProtoList>' is simpler in that it only
> checks if ProtoList provides the method (instance method in case of
> 'id <ProtoList>', class method in case of 'Class <ProtoList>') and if
> it does not, it generates a warning _even if_ some root class
> somewhere (and/or protocol thereto attached) happens to provide such
> a method.
> 
> I apologize for not realizing this earlier; I kept thinking of when
> to issue the warning 'Class <Proto1, Proto2> may not respond to
> "bar"' and when to suppress it. A brief lecture of objc-act.c now
> reminded me that such a warning should _never_ be issued for
> receivers of type 'id' or 'Class', whether protocol-qualified or
> not.

OK, now we either have a fundamental disagreement or a fundamental
misunderstanding.  If I send a message to a protocol qualified 'id'
which is not declared by the protocol, I expect a warning.  Why else
should I bother qualifying it?  Or what do you mean with "that such a
warning should _never_ be issued for receivers of type 'id' or 'Class',
_whether protocol-qualified or not_"?

For the 'Class' case the situation a bit more hairy, due to the
semantics of instance methods in root classes.  What I'm trying to
achieve is that:

Class <NSObject> clsP1;
Class <NSCoding> clsP2;

[clsP1 retain];                 /* doesn't warn */
[clsP2 encodeWithCoder: coder]; /* warns */

Now if you are saying that you think it's OK, to warn in the +retain
case, (which is what I  understand from the second to last paragraph)
then, yes, we wouldn't need to mark root protocols at all.  But as the
correct retrieval of that prototype and the suppression of that warning
is _exactly_ what I'm trying to achieve, I have written the code to mark
those protocols and to test that mark when searching for protocols.
This is especially important when the prototypes start mismatching which
was part of the original trigger for me to do this at all.

> 
> In summation, I believe that the only necessary changes to 
> objc_finish_message_expr() are the following (I've attached it inline
> to preserve tabulation):
> 
> 
> 
> ------------------------------------------------------------------------
> 
> Index: gcc/objc/objc-act.c
> ===================================================================
> RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
> retrieving revision 1.248
> diff -u -3 -p -r1.248 objc-act.c
> --- gcc/objc/objc-act.c	24 Sep 2004 23:15:33 -0000	1.248
> +++ gcc/objc/objc-act.c	30 Sep 2004 01:13:57 -0000
> @@ -5570,7 +5570,8 @@ objc_finish_message_expr (tree receiver,
>        else
>  	{
>  	  class_tree = objc_class_name;
> -	  OBJC_SET_TYPE_NAME (rtype, class_tree);
> +	  rprotos = TYPE_PROTOCOL_LIST (rtype);
> +	  rtype = NULL_TREE;
>  	}
>  
>        if (rprotos)
> @@ -5650,10 +5651,19 @@ objc_finish_message_expr (tree receiver,
>  		 IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)),
>  		 (class_tree ? '+' : '-'),
>  		 IDENTIFIER_POINTER (sel_name));
> +      /* If we are messaging an unadorned 'id' or 'Class' object,
> +	 then we have failed to find _any_ instance or class method,
> +	 respectively.  */
> +      else if (!rprotos)
> +	warning ("no `%c%s' method found",
> +		 (class_tree ? '+' : '-'),
> +		 IDENTIFIER_POINTER (sel_name));
> +
>        if (rprotos)
>  	warning ("`%c%s' not implemented by protocol(s)",
>  		 (class_tree ? '+' : '-'),
>  		 IDENTIFIER_POINTER (sel_name));
> +		 
>        if (!warn_missing_methods)
>  	{
>  	  warning ("(Messages without a matching method signature");
> 
> 
> ------------------------------------------------------------------------

I tried it anyway and it fails to find the prototypes.  Since you have
the patch and test case maybe you can play a bit, to show me what you mean.

> At this point, I'm wondering whether (1)
> PROTOCOL_ADOPTED_BY_ROOT_CLASS is needed at all and (2) if instance
> methods of protocols adopted by root classes should be placed in the
> class method hash table. Doing so will make no difference whatsoever
> when messaging 'Class <ProtoList>', but may help out when messaging
> an unadorned 'Class'. What do you think? I have yet to develop a
> strong opinion here... :-)

As noted above, it does make a difference.  Or I'm totally missing your
point.

>>>Perhaps instead of 'incorporated', we should consistently say
>>>'inherited'?
>>
>> Actually "incorporated" is the term used in the "Objective-C" book.
>>  
>> http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/
>>  LanguageSummary/chapter_5_section_8.html And the term "inherited"
>> is a bit misleading. The concept doesn't really match protocols.
> 
> 
> Why not? If you think of protocols as abstract interfaces, then 
> "inherit" fits the bill perfectly, I would think... Personally, I
> find "incorporate" a bit vague, since it could mean that you're
> manually repeating the method declarations from the other
> protocol...

Well I'm not going to argue heavily about this.  I think "repeating the
method declarations" is exactly what it does, but then again
"inheritance" repeats instance variables, method declarations and
implementation.  There is a difference to Objective-C class inheritance
in that you can declare "multiple inheritance" wrt to protocol
declarations.  I just had the feeling that the term when applied to
protocols was causing confusion.  I'm still partial to term
"incorporated" now, but if you'd like me to revert my documentation to
speak of inheritance, I will.

BTW, :-) If you feel strongly about conceptually representing protocols
as a second set of inheritance hierarchies, then maybe we should
reconsider whether:

@protocol MyProto8
+(void)doItClass8;
-(void)doItInstance8;
@end
@protocol MyProto9 <MyProto8>
+(void)doItClass9;
-(void)doItInstance9;
@end

where MyProto9 is a "subprotocol" of MyProto8

@interface SomeRoot <MyProto9>
@end

Class <MyProto8> clsP8 = 0;

[clsP8 doItInstance8];

should warn, or not, as strictly speaking it's only the "sub protocol"
that has been declared by a root class and not MyProto8.  But like I
said the case is extreme and we save ourselves a lot of complexity by
not handling it.  I just mentioned it again to show the potential
expectation if you view protocols as (mulitple inheritance) hierarchies,
as I also did, which lead to my first implementation.

...
[sniped sly remark]
> You're not being constructive here.  :-(

Sorry, it was intended to be a little pinch, not a slap.

> If, as you say, the term "inherited" is misleading, then it
> definitely _is_ interesting to see what term the Java-ites settled on
>  in order to maintain this distinction and avoid confusion. Just as
> Java "inherited" (pun intended) the notion of protocols/interfaces
> from ObjC, so we can definitely borrow their terminology if we find
> it useful.

<joke>I do Objective-C, I don't believe in multiple inheritance.  (not
implying that Java has it) :-) Well in this case it would even be
"recursive".</joke>

No, seriously, if the Java folks have a term for this, let's hear it.

>>> Hmm... I guess my comment was motivated by the belief that 'Class
>>>  <Proto>' is virtually identical to 'id <Proto>' as far as type
>>> comparisons are concerned, and the few differences (if any) could
>>> easily be special-cased. Do you disagree?
>>
>> Well yes, I agree that they are virtually identical, which is why
>> it was so easy to "write" objc_comptypes_proto_proto. Maybe I
>> should have mentioned that this is a verbatim copy if the previuos
>> handling in the "Protocol" = "Protocol" case, plus the assertion
>> that both parameters must either be 'id' or both be 'Class'.
> 
> 
> OK, but then objc_comptypes_proto_proto() is nothing more than a 
> gratuitous rewrite of objc_comptypes(), which I thought we agreed
> should wait until later... :-)
> 

Actually, objc_comptypes_proto_proto is merely an extraction of a part
of objc_comptypes to avoid code duplication and avoid rearranging the
flow control of objc_comptypes. There is no change in the real code, it
just cut & paste and reformatted to take the nesting level into account.
 That doesn't fight my definition of a gratuitous rewrite.

> I'm curious... if you were just to augment the definition of 
> IS_PROTOCOL_QUALIFIED_ID to encompass 'Class <Proto>' constructs, but
> left objc_comptypes() in its original form, which comparisons would
> break as a result?

objc_comptypes is currently structured like:

if (lhs is pointer to structure && rhs is pointer to structure)
  {
    if (lhs is protocol qualified 'id')
      {
        if (rhs is protocol qualified 'id')
          { Handle "id <protocol> = id <protocol>" case. }
        else if (rhs is concrete class reference)
          { Handle "id <protocol> = SomeClass *" case. }
        else if (rhs is 'id')
          { Handle "id <protocol> = id" case. }
        else if (rhs is 'Class')
          { Handle "id <protocol> = Class" case. }
        else
          { Defer handling to comptypes. }
      }
    else if (rhs is protocol qualified 'id')
      {
        if (rhs is concrete class reference)
          { Handle "SomeClass * = id <protocol>" case. }
        else if (rhs is 'id')
          { Handle "id = id <protocol>" case. }
        else if (rhs is 'Class')
          { Handle "Class = id <protocol>" case. }
        else
          { Defer handling to comptypes. }
       }
     else
       { strip pointer from lhs and rhs }
  }

...
What I've done is:

if (lhs is pointer to structure && rhs is pointer to structure)
  {
    if (lhs is protocol qualified 'id')
      {
        if (rhs is protocol qualified 'id')
*         { Handle "id <protocol> = id <protocol>" case. }
        else if (rhs is concrete class reference)
          { Handle "id <protocol> = SomeClass *" case. }
        else if (rhs is 'id')
          { Handle "id <protocol> = id" case. }
        else if (rhs is 'Class')
          { Handle "id <protocol> = Class (& Class <protocol>)" case. }
        else
          { Defer handling to comptypes. }
      }
    else if (rhs is protocol qualified 'id')
      {
        if (rhs is concrete class reference)
          { Handle "SomeClass * = id <protocol>" case. }
        else if (rhs is 'id')
          { Handle "id = id <protocol>" case. }
        else if (rhs is 'Class')
          { Handle "Class (& Class <protocol>) = id <protocol> " case. }
        else
          { Defer handling to comptypes. }
      }
+   else if (lhs is protocol qualified 'Class')
+     {
+       if (rhs is protocol qualified 'Class')
+*        { Handle "Class <protocol> = Class <protocol>" case. }
+       else if (rhs is concrete class reference)
+         { Handle "Class <protocol> = SomeClass *" case. }
+       else if (rhs is 'id')
+         { Handle "Class <protocol> = id" case. }
+       else if (rhs is 'Class')
+         { Handle "Class <protocol> = Class" case. }
+       else
+         { Defer handling to comptypes. }
+     }
+   else if (rhs is protocol qualified 'Class')
+     {
+       if (rhs is concrete class reference)
+         { Handle "SomeClass * = Class <protocol>" case. }
+       else if (rhs is 'id')
+         { Handle "id = Class <protocol>" case. }
+       else if (rhs is 'Class')
+         { Handle "Class = Class <protocol>" case. }
+       else
+         { Defer handling to comptypes. }
+     }
     else
       { strip pointer from lhs and rhs }
  }

with the * being the extracted code in objc_comptypes_proto_proto.

What I /think/ you are asking me to do is:

if (lhs is pointer to structure && rhs is pointer to structure)
  {
    if (lhs is protocol qualified 'id' or 'Class')
      {
        if (rhs is protocol qualified 'id' or 'Class')
(1)       { Handle "id/Class <protocol> = id/Class <protocol>" case. }
        else if (rhs is concrete class reference)
(2)       { Handle "id/Class <protocol> = SomeClass *" case. }
        else if (rhs is 'id')
          { Handle "id/Class <protocol> = id" case. }
        else if (rhs is 'Class')
(3)       { Handle "id/Class <protocol> = Class" case. }
        else
          { Defer handling to comptypes. }
      }
    else if (rhs is protocol qualified 'id' or 'Class')
      {
        if (rhs is concrete class reference)
(4)       { Handle "SomeClass * = id/Class <protocol>" case. }
        else if (rhs is 'id')
          { Handle "id = id/Class <protocol>" case. }
        else if (rhs is 'Class')
(5)        { Handle "Class = id/Class <protocol>" case. }
        else
          { Defer handling to comptypes. }
       }
     else
       { strip pointer from lhs and rhs }
  }

(1) Here we would either have to special case:
Class <protocol> = id <protocol> (and the inverse)
to returns 0 (not compatible) without the need to checking protocol
conformance.

(2) Here we would either have to special case:
Class <protocol> = SomeClass *
To return 0 (not compatible) instead of looking for the protocol in the
class.

(3) Here we would either have to special case:
Class = id <protocol>
which returns 0 (not compatible)
Class = Class <protocol>
should return 1.

(4) Inversion of (2)
(5) Inversion of (3)

And it's this special casing that would disrupt the flow, at least IMO.

>>> Actually, if my hunch above is correct (and I hope it is :-), you
>>>  shouldn't need to modify lookup_method_in_protocol_list() at
>>> all, and you will not need instance_prototype_of_root_protocol() 
>>> either since lookup_method_in_hash_lists() should find the
>>> instance methods for you. Hopefully, the sole use of the
>>> PROTOCOL_ADOPTED_BY_ROOT_CLASS flag will henceforth be to 
>>> indicate that a protocol's instance methods were put into the
>>> global class method hash table.
>>
>> I don't think it worth loosing that type information. We need to 
>> account for several root classes each possibly adopting different
>> protocols.
> 
> 
> But lookup_method_static() has access to this information as is; see  
> below.
> 
>>>>@protocol MyProto8
>>>>+(void)doItClass8;
>>>>-(void)doItInstance8;
>>>>@end
>>>>
>>>>@protocol MyProto9 <MyProto8>
>>>>+(void)doItClass9;
>>>>-(void)doItInstance9;
>>>>@end
>>>>
>>>>@interface MyClass1 <MyProto9>
>>>>@end
>>>>
>>>>Class <MyProto8> clsP8 = 0;
>>>>
>>>>...
>>>>  [clsP8 doItInstance8]; /* { dg-warning "not implemented" } */
>>>>
>>>> Now, does the fact that a root class adopts MyProto9, which 
>>>> incorporates MyProto8, make MyProto8 a "root" protocol in the
>>>> sense that we should search for instance methods when sending
>>>> messages to Class <Proto8> ?
>>>> I admit this is a corner case that may not warrant the extra 
>>>> complexity. This updated patch would make MyProto8 a full
>>>> fledged "root" protocol.
>>>
>>> I agree; since MyProto9 is a "root protocol", then so is
>>> MyProto8, and so the warning above should not be generated. Yes,
>>> this is overkill, since we don't know if 'clsP8' points at a
>>> 'MyClass1' or not, but this is the same overkill as we already
>>> have with root classes themselves, as mentioned above.
>>
>> Well just because a class conforms to MyProto8 does not mean it is
>> a class who's root class conforms to MyProto9 so we are being
>> rather lax but the case can be a bit pathalogical and the
>> complexity not worth the trouble.
> 
> 
> Yes, I humbly reverse my previous opinion; see above.

Umm, I'm lost.  So is your opinion that MyProto "shouldn't" be a "root"
class?  Or are you just suggesting, that with the above assertion, that
marking root protocols is superfluous?  Which I hope I have shown that
it isn't, that it is in effect very important wrt to "prototype hygiene"
to quote you :-).

>>>> I did add a flag to lookup_method_in_protocol_list to indicate 
>>>> whether instance methods of protocols adopted by root classes
>>>> should be searched, so the caller can decide. This is necessary
>>>> as we only want to use this feature if we actually have
>>>> 'Class', not when we have a "concrete" MyClass4 that is not a
>>>> root class but implements a protocol that is a root class of a
>>>> different hierarchy:
>>>>
>>>>@protocol MyProto1
>>>>@end
>>>
>>>You mean
>>>
>>>   @protocol MyProto1
>>>   -doItInstance1;
>>>   @end
>>>
>>>right?
>>
>>Indeed :-) This was from the test case.
>>
>>
>>>>@interface MyClass1 <MyProto1> /* root */
>>>>@end
>>>>@interface MyClass2 : MyClass1
>>>>@end
>>>>@interface MyClass3 /* New root */
>>>>@end
>>>>@interface MyClass4 : MyClass3 <MyProto1>
>>>>@end
>>>>
>>>>  [MyClass2 doItInstance1]; /* Do not warn */
>>>>...
>>>>  [MyClass4 doItInstance1]; /* { dg-warning "may not respond to" } */
>>>>
>>>
>>> In this case, the lookup should be performed by 
>>> lookup_method_static(), which I believe already does what it
>>> should. I agree with you that the warning _is_ needed in the
>>> second case, but lookup_method_static() should _not_ be able to 
>>> stumble upon MyProto1 while searching for +doItInstance1 in
>>> MyClass4; if it does somehow find it, then I think it's buggy.
>>> :-( So again, I don't think you need to do anything beyond what's
>>> already being done to handle this case.
>>
>> Yet lookup_method_static uses lookup_method_in_protocol_list, so
>> that is exactly the place where I need to tell it to act
>> differently :-)
> 
> 
> I think, though, that when lookup_method_static() reaches the top of the
> hierarchy when searching for class methods, it will search for instance
> methods in the root class _and_ its associated protocols as a last gasp,
> no?

Exactly!  But it is _not_ supposed to look into the protocols adopted by
unrelated root classes, this what that flag suppresses here.

Cheers,
David

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-09-30 14:06                 ` David Ayers
@ 2004-09-30 22:33                   ` Ziemowit Laski
       [not found]                     ` <81.223.113.201.1096587115.wm@webmail.inode.at>
  0 siblings, 1 reply; 35+ messages in thread
From: Ziemowit Laski @ 2004-09-30 22:33 UTC (permalink / raw)
  To: David Ayers; +Cc: gcc-patches


On 30 Sep 2004, at 5.25, David Ayers wrote:

>> I apologize for not realizing this earlier; I kept thinking of when
>> to issue the warning 'Class <Proto1, Proto2> may not respond to
>> "bar"' and when to suppress it. A brief lecture of objc-act.c now
>> reminded me that such a warning should _never_ be issued for
>> receivers of type 'id' or 'Class', whether protocol-qualified or
>> not.
>
> OK, now we either have a fundamental disagreement or a fundamental
> misunderstanding.  If I send a message to a protocol qualified 'id'
> which is not declared by the protocol, I expect a warning.  Why else
> should I bother qualifying it?  Or what do you mean with "that such a
> warning should _never_ be issued for receivers of type 'id' or 'Class',
> _whether protocol-qualified or not_"?

Hopefully this is just a misunderstanding, and not even a fundamental  
one. :-)
When we say "warning", we are in fact talking about two different  
warnings:

    (1)  'Foo' may not respond to 'bar'
    (2)  'bar' not implemented by protocol(s)

In the paragraph you quoted, I was saying that warning (1) should never
be issued, but warning (2) should and is.  The distinction between these
two warnings is crucial, since they have different semantics and impose
different requirements on the implementation to produce them.  I seem to
have completely forgotten about this distinction, until my epiphany.

>
> For the 'Class' case the situation a bit more hairy, due to the
> semantics of instance methods in root classes.  What I'm trying to
> achieve is that:
>
> Class <NSObject> clsP1;
> Class <NSCoding> clsP2;
>
> [clsP1 retain];                 /* doesn't warn */

Unless the NSObject protocol realy does provide +retain, then the
compiler _should_ warn in this case.

> [clsP2 encodeWithCoder: coder]; /* warns */
>
> Now if you are saying that you think it's OK, to warn in the +retain
> case, (which is what I  understand from the second to last paragraph)
> then, yes, we wouldn't need to mark root protocols at all.

Exactly.

>   But as the
> correct retrieval of that prototype and the suppression of that warning
> is _exactly_ what I'm trying to achieve, I have written the code to  
> mark
> those protocols and to test that mark when searching for protocols.

Ok, I guess we have a disagreement after all. :-(  As you said above,
the very reason you'd want to protocol-qualify 'id' or 'Class' in the
first place is so that the compiler could warn you if you're invoking
a method _not_ listed in those protocols.  The machinery you're trying
to put in place will defeat this mechanism; why would you want to do  
this?

If you do not want to see a warning in this case, you can use either
(1) an unadorned 'Class' or (2) a concrete ObjC class (e.g., 'NSObject')
as the receiver.  In both cases, the compiler will look at instance  
methods
as a last resort.

> This is especially important when the prototypes start mismatching  
> which
> was part of the original trigger for me to do this at all.

I don't understand this last sentence at all. :-(  Can you show an
example of when "prototypes start mismatching"?  Perhaps this will help
me understand your motivation a bit better.

As you suggested, I think I will whip up a separate patch that  
incorporates
(and probably modifies) your testcases to show you what I mean.

Thanks,

--Zem

>
>>
>> In summation, I believe that the only necessary changes to
>> objc_finish_message_expr() are the following (I've attached it inline
>> to preserve tabulation):
>>
>>
>>
>> ---------------------------------------------------------------------- 
>> --
>>
>> Index: gcc/objc/objc-act.c
>> ===================================================================
>> RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
>> retrieving revision 1.248
>> diff -u -3 -p -r1.248 objc-act.c
>> --- gcc/objc/objc-act.c	24 Sep 2004 23:15:33 -0000	1.248
>> +++ gcc/objc/objc-act.c	30 Sep 2004 01:13:57 -0000
>> @@ -5570,7 +5570,8 @@ objc_finish_message_expr (tree receiver,
>>        else
>>  	{
>>  	  class_tree = objc_class_name;
>> -	  OBJC_SET_TYPE_NAME (rtype, class_tree);
>> +	  rprotos = TYPE_PROTOCOL_LIST (rtype);
>> +	  rtype = NULL_TREE;
>>  	}
>>
>>        if (rprotos)
>> @@ -5650,10 +5651,19 @@ objc_finish_message_expr (tree receiver,
>>  		 IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)),
>>  		 (class_tree ? '+' : '-'),
>>  		 IDENTIFIER_POINTER (sel_name));
>> +      /* If we are messaging an unadorned 'id' or 'Class' object,
>> +	 then we have failed to find _any_ instance or class method,
>> +	 respectively.  */
>> +      else if (!rprotos)
>> +	warning ("no `%c%s' method found",
>> +		 (class_tree ? '+' : '-'),
>> +		 IDENTIFIER_POINTER (sel_name));
>> +
>>        if (rprotos)
>>  	warning ("`%c%s' not implemented by protocol(s)",
>>  		 (class_tree ? '+' : '-'),
>>  		 IDENTIFIER_POINTER (sel_name));
>> +		
>>        if (!warn_missing_methods)
>>  	{
>>  	  warning ("(Messages without a matching method signature");
>>
>>
>> ---------------------------------------------------------------------- 
>> --
>
> I tried it anyway and it fails to find the prototypes.  Since you have
> the patch and test case maybe you can play a bit, to show me what you  
> mean.
>
>> At this point, I'm wondering whether (1)
>> PROTOCOL_ADOPTED_BY_ROOT_CLASS is needed at all and (2) if instance
>> methods of protocols adopted by root classes should be placed in the
>> class method hash table. Doing so will make no difference whatsoever
>> when messaging 'Class <ProtoList>', but may help out when messaging
>> an unadorned 'Class'. What do you think? I have yet to develop a
>> strong opinion here... :-)
>
> As noted above, it does make a difference.  Or I'm totally missing your
> point.
>
>>>> Perhaps instead of 'incorporated', we should consistently say
>>>> 'inherited'?
>>>
>>> Actually "incorporated" is the term used in the "Objective-C" book.
>>>
>>> http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/
>>>  LanguageSummary/chapter_5_section_8.html And the term "inherited"
>>> is a bit misleading. The concept doesn't really match protocols.
>>
>>
>> Why not? If you think of protocols as abstract interfaces, then
>> "inherit" fits the bill perfectly, I would think... Personally, I
>> find "incorporate" a bit vague, since it could mean that you're
>> manually repeating the method declarations from the other
>> protocol...
>
> Well I'm not going to argue heavily about this.  I think "repeating the
> method declarations" is exactly what it does, but then again
> "inheritance" repeats instance variables, method declarations and
> implementation.  There is a difference to Objective-C class inheritance
> in that you can declare "multiple inheritance" wrt to protocol
> declarations.  I just had the feeling that the term when applied to
> protocols was causing confusion.  I'm still partial to term
> "incorporated" now, but if you'd like me to revert my documentation to
> speak of inheritance, I will.
>
> BTW, :-) If you feel strongly about conceptually representing protocols
> as a second set of inheritance hierarchies, then maybe we should
> reconsider whether:
>
> @protocol MyProto8
> +(void)doItClass8;
> -(void)doItInstance8;
> @end
> @protocol MyProto9 <MyProto8>
> +(void)doItClass9;
> -(void)doItInstance9;
> @end
>
> where MyProto9 is a "subprotocol" of MyProto8
>
> @interface SomeRoot <MyProto9>
> @end
>
> Class <MyProto8> clsP8 = 0;
>
> [clsP8 doItInstance8];
>
> should warn, or not, as strictly speaking it's only the "sub protocol"
> that has been declared by a root class and not MyProto8.  But like I
> said the case is extreme and we save ourselves a lot of complexity by
> not handling it.  I just mentioned it again to show the potential
> expectation if you view protocols as (mulitple inheritance)  
> hierarchies,
> as I also did, which lead to my first implementation.
>
> ...
> [sniped sly remark]
>> You're not being constructive here.  :-(
>
> Sorry, it was intended to be a little pinch, not a slap.
>
>> If, as you say, the term "inherited" is misleading, then it
>> definitely _is_ interesting to see what term the Java-ites settled on
>>  in order to maintain this distinction and avoid confusion. Just as
>> Java "inherited" (pun intended) the notion of protocols/interfaces
>> from ObjC, so we can definitely borrow their terminology if we find
>> it useful.
>
> <joke>I do Objective-C, I don't believe in multiple inheritance.  (not
> implying that Java has it) :-) Well in this case it would even be
> "recursive".</joke>
>
> No, seriously, if the Java folks have a term for this, let's hear it.
>
>>>> Hmm... I guess my comment was motivated by the belief that 'Class
>>>>  <Proto>' is virtually identical to 'id <Proto>' as far as type
>>>> comparisons are concerned, and the few differences (if any) could
>>>> easily be special-cased. Do you disagree?
>>>
>>> Well yes, I agree that they are virtually identical, which is why
>>> it was so easy to "write" objc_comptypes_proto_proto. Maybe I
>>> should have mentioned that this is a verbatim copy if the previuos
>>> handling in the "Protocol" = "Protocol" case, plus the assertion
>>> that both parameters must either be 'id' or both be 'Class'.
>>
>>
>> OK, but then objc_comptypes_proto_proto() is nothing more than a
>> gratuitous rewrite of objc_comptypes(), which I thought we agreed
>> should wait until later... :-)
>>
>
> Actually, objc_comptypes_proto_proto is merely an extraction of a part
> of objc_comptypes to avoid code duplication and avoid rearranging the
> flow control of objc_comptypes. There is no change in the real code, it
> just cut & paste and reformatted to take the nesting level into  
> account.
>  That doesn't fight my definition of a gratuitous rewrite.
>
>> I'm curious... if you were just to augment the definition of
>> IS_PROTOCOL_QUALIFIED_ID to encompass 'Class <Proto>' constructs, but
>> left objc_comptypes() in its original form, which comparisons would
>> break as a result?
>
> objc_comptypes is currently structured like:
>
> if (lhs is pointer to structure && rhs is pointer to structure)
>   {
>     if (lhs is protocol qualified 'id')
>       {
>         if (rhs is protocol qualified 'id')
>           { Handle "id <protocol> = id <protocol>" case. }
>         else if (rhs is concrete class reference)
>           { Handle "id <protocol> = SomeClass *" case. }
>         else if (rhs is 'id')
>           { Handle "id <protocol> = id" case. }
>         else if (rhs is 'Class')
>           { Handle "id <protocol> = Class" case. }
>         else
>           { Defer handling to comptypes. }
>       }
>     else if (rhs is protocol qualified 'id')
>       {
>         if (rhs is concrete class reference)
>           { Handle "SomeClass * = id <protocol>" case. }
>         else if (rhs is 'id')
>           { Handle "id = id <protocol>" case. }
>         else if (rhs is 'Class')
>           { Handle "Class = id <protocol>" case. }
>         else
>           { Defer handling to comptypes. }
>        }
>      else
>        { strip pointer from lhs and rhs }
>   }
>
> ...
> What I've done is:
>
> if (lhs is pointer to structure && rhs is pointer to structure)
>   {
>     if (lhs is protocol qualified 'id')
>       {
>         if (rhs is protocol qualified 'id')
> *         { Handle "id <protocol> = id <protocol>" case. }
>         else if (rhs is concrete class reference)
>           { Handle "id <protocol> = SomeClass *" case. }
>         else if (rhs is 'id')
>           { Handle "id <protocol> = id" case. }
>         else if (rhs is 'Class')
>           { Handle "id <protocol> = Class (& Class <protocol>)" case. }
>         else
>           { Defer handling to comptypes. }
>       }
>     else if (rhs is protocol qualified 'id')
>       {
>         if (rhs is concrete class reference)
>           { Handle "SomeClass * = id <protocol>" case. }
>         else if (rhs is 'id')
>           { Handle "id = id <protocol>" case. }
>         else if (rhs is 'Class')
>           { Handle "Class (& Class <protocol>) = id <protocol> " case.  
> }
>         else
>           { Defer handling to comptypes. }
>       }
> +   else if (lhs is protocol qualified 'Class')
> +     {
> +       if (rhs is protocol qualified 'Class')
> +*        { Handle "Class <protocol> = Class <protocol>" case. }
> +       else if (rhs is concrete class reference)
> +         { Handle "Class <protocol> = SomeClass *" case. }
> +       else if (rhs is 'id')
> +         { Handle "Class <protocol> = id" case. }
> +       else if (rhs is 'Class')
> +         { Handle "Class <protocol> = Class" case. }
> +       else
> +         { Defer handling to comptypes. }
> +     }
> +   else if (rhs is protocol qualified 'Class')
> +     {
> +       if (rhs is concrete class reference)
> +         { Handle "SomeClass * = Class <protocol>" case. }
> +       else if (rhs is 'id')
> +         { Handle "id = Class <protocol>" case. }
> +       else if (rhs is 'Class')
> +         { Handle "Class = Class <protocol>" case. }
> +       else
> +         { Defer handling to comptypes. }
> +     }
>      else
>        { strip pointer from lhs and rhs }
>   }
>
> with the * being the extracted code in objc_comptypes_proto_proto.
>
> What I /think/ you are asking me to do is:
>
> if (lhs is pointer to structure && rhs is pointer to structure)
>   {
>     if (lhs is protocol qualified 'id' or 'Class')
>       {
>         if (rhs is protocol qualified 'id' or 'Class')
> (1)       { Handle "id/Class <protocol> = id/Class <protocol>" case. }
>         else if (rhs is concrete class reference)
> (2)       { Handle "id/Class <protocol> = SomeClass *" case. }
>         else if (rhs is 'id')
>           { Handle "id/Class <protocol> = id" case. }
>         else if (rhs is 'Class')
> (3)       { Handle "id/Class <protocol> = Class" case. }
>         else
>           { Defer handling to comptypes. }
>       }
>     else if (rhs is protocol qualified 'id' or 'Class')
>       {
>         if (rhs is concrete class reference)
> (4)       { Handle "SomeClass * = id/Class <protocol>" case. }
>         else if (rhs is 'id')
>           { Handle "id = id/Class <protocol>" case. }
>         else if (rhs is 'Class')
> (5)        { Handle "Class = id/Class <protocol>" case. }
>         else
>           { Defer handling to comptypes. }
>        }
>      else
>        { strip pointer from lhs and rhs }
>   }
>
> (1) Here we would either have to special case:
> Class <protocol> = id <protocol> (and the inverse)
> to returns 0 (not compatible) without the need to checking protocol
> conformance.
>
> (2) Here we would either have to special case:
> Class <protocol> = SomeClass *
> To return 0 (not compatible) instead of looking for the protocol in the
> class.
>
> (3) Here we would either have to special case:
> Class = id <protocol>
> which returns 0 (not compatible)
> Class = Class <protocol>
> should return 1.
>
> (4) Inversion of (2)
> (5) Inversion of (3)
>
> And it's this special casing that would disrupt the flow, at least IMO.
>
>>>> Actually, if my hunch above is correct (and I hope it is :-), you
>>>>  shouldn't need to modify lookup_method_in_protocol_list() at
>>>> all, and you will not need instance_prototype_of_root_protocol()
>>>> either since lookup_method_in_hash_lists() should find the
>>>> instance methods for you. Hopefully, the sole use of the
>>>> PROTOCOL_ADOPTED_BY_ROOT_CLASS flag will henceforth be to
>>>> indicate that a protocol's instance methods were put into the
>>>> global class method hash table.
>>>
>>> I don't think it worth loosing that type information. We need to
>>> account for several root classes each possibly adopting different
>>> protocols.
>>
>>
>> But lookup_method_static() has access to this information as is; see
>> below.
>>
>>>>> @protocol MyProto8
>>>>> +(void)doItClass8;
>>>>> -(void)doItInstance8;
>>>>> @end
>>>>>
>>>>> @protocol MyProto9 <MyProto8>
>>>>> +(void)doItClass9;
>>>>> -(void)doItInstance9;
>>>>> @end
>>>>>
>>>>> @interface MyClass1 <MyProto9>
>>>>> @end
>>>>>
>>>>> Class <MyProto8> clsP8 = 0;
>>>>>
>>>>> ...
>>>>>  [clsP8 doItInstance8]; /* { dg-warning "not implemented" } */
>>>>>
>>>>> Now, does the fact that a root class adopts MyProto9, which
>>>>> incorporates MyProto8, make MyProto8 a "root" protocol in the
>>>>> sense that we should search for instance methods when sending
>>>>> messages to Class <Proto8> ?
>>>>> I admit this is a corner case that may not warrant the extra
>>>>> complexity. This updated patch would make MyProto8 a full
>>>>> fledged "root" protocol.
>>>>
>>>> I agree; since MyProto9 is a "root protocol", then so is
>>>> MyProto8, and so the warning above should not be generated. Yes,
>>>> this is overkill, since we don't know if 'clsP8' points at a
>>>> 'MyClass1' or not, but this is the same overkill as we already
>>>> have with root classes themselves, as mentioned above.
>>>
>>> Well just because a class conforms to MyProto8 does not mean it is
>>> a class who's root class conforms to MyProto9 so we are being
>>> rather lax but the case can be a bit pathalogical and the
>>> complexity not worth the trouble.
>>
>>
>> Yes, I humbly reverse my previous opinion; see above.
>
> Umm, I'm lost.  So is your opinion that MyProto "shouldn't" be a "root"
> class?  Or are you just suggesting, that with the above assertion, that
> marking root protocols is superfluous?  Which I hope I have shown that
> it isn't, that it is in effect very important wrt to "prototype  
> hygiene"
> to quote you :-).
>
>>>>> I did add a flag to lookup_method_in_protocol_list to indicate
>>>>> whether instance methods of protocols adopted by root classes
>>>>> should be searched, so the caller can decide. This is necessary
>>>>> as we only want to use this feature if we actually have
>>>>> 'Class', not when we have a "concrete" MyClass4 that is not a
>>>>> root class but implements a protocol that is a root class of a
>>>>> different hierarchy:
>>>>>
>>>>> @protocol MyProto1
>>>>> @end
>>>>
>>>> You mean
>>>>
>>>>   @protocol MyProto1
>>>>   -doItInstance1;
>>>>   @end
>>>>
>>>> right?
>>>
>>> Indeed :-) This was from the test case.
>>>
>>>
>>>>> @interface MyClass1 <MyProto1> /* root */
>>>>> @end
>>>>> @interface MyClass2 : MyClass1
>>>>> @end
>>>>> @interface MyClass3 /* New root */
>>>>> @end
>>>>> @interface MyClass4 : MyClass3 <MyProto1>
>>>>> @end
>>>>>
>>>>>  [MyClass2 doItInstance1]; /* Do not warn */
>>>>> ...
>>>>>  [MyClass4 doItInstance1]; /* { dg-warning "may not respond to" }  
>>>>> */
>>>>>
>>>>
>>>> In this case, the lookup should be performed by
>>>> lookup_method_static(), which I believe already does what it
>>>> should. I agree with you that the warning _is_ needed in the
>>>> second case, but lookup_method_static() should _not_ be able to
>>>> stumble upon MyProto1 while searching for +doItInstance1 in
>>>> MyClass4; if it does somehow find it, then I think it's buggy.
>>>> :-( So again, I don't think you need to do anything beyond what's
>>>> already being done to handle this case.
>>>
>>> Yet lookup_method_static uses lookup_method_in_protocol_list, so
>>> that is exactly the place where I need to tell it to act
>>> differently :-)
>>
>>
>> I think, though, that when lookup_method_static() reaches the top of  
>> the
>> hierarchy when searching for class methods, it will search for  
>> instance
>> methods in the root class _and_ its associated protocols as a last  
>> gasp,
>> no?
>
> Exactly!  But it is _not_ supposed to look into the protocols adopted  
> by
> unrelated root classes, this what that flag suppresses here.
>
> Cheers,
> David
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
       [not found]                       ` <81.223.113.201.1096588159.wm@webmail.inode.at>
@ 2004-10-01  0:08                         ` Ziemowit Laski
  0 siblings, 0 replies; 35+ messages in thread
From: Ziemowit Laski @ 2004-10-01  0:08 UTC (permalink / raw)
  To: d.ayers; +Cc: gcc-patches


On 30 Sep 2004, at 16.49, d.ayers@inode.at wrote:

>>>
>>> On 30 Sep 2004, at 5.25, David Ayers wrote:
>>>
>>
>>> As you suggested, I think I will whip up a separate patch that
>>> incorporates
>>> (and probably modifies) your testcases to show you what I mean.
>>>
>>
>> Well, I was actually refering to the comptypes issue, but be my guest
>> :-)
>>
>
> Looking back, actually I wasn't.  So strike that :-)  I really need to 
> get
> to bed...

:-)  Hope you don't have to get up early :-)

--Zem

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
       [not found]                     ` <81.223.113.201.1096587115.wm@webmail.inode.at>
       [not found]                       ` <81.223.113.201.1096588159.wm@webmail.inode.at>
@ 2004-10-01  0:55                       ` Ziemowit Laski
  2004-10-01  7:47                         ` Kai Henningsen
  2004-10-01  9:02                         ` David Ayers
  1 sibling, 2 replies; 35+ messages in thread
From: Ziemowit Laski @ 2004-10-01  0:55 UTC (permalink / raw)
  To: d.ayers; +Cc: gcc-patches


On 30 Sep 2004, at 16.31, d.ayers@inode.at wrote:

> @protocol <CommonMethodNames1>
> - (const char *)name;
> - (void)set;
> - (int)compare:(id)obj;
> - (int) host
> @end
>
> @protocol <CommonMethodNames2>
> - (NSString *)name;
> - (NSSet *)set;
> - (BOOL)compare:(id)obj;
> - (NSString *)host
> @end

Oooh, that is pretty hairy. :-(  But I don't think your proposal (or 
mine,
for that matter) deals with this issue, does it?  I'm assuming that 
you're
worrying about constructions like:

   id <CommonMethodNames1, CommonMethodNames2> obj;
   Class <CommonMethodNames1, CommonMethodNames2> cls;
     :
   ... [obj name] ...
   ... [cls name] ...

I guess as things currently stand, the first call will silently pick 
CommonMethodNames1's
version of '-name'.  I think we should make the behavior here more 
consistent with
what a brute-force hash table lookup would do, namely warn about 
multiple '-name' signatures
being available (and then still pick CommonMethodNames1's).

The second call, in my opinion, should tell you that '+name'
is not implemented by protocol(s).  (This raises a separate, tangential 
issue:
protocols don't really implement things -- perhaps "not listed in 
protocol(s)"
would be better?)

> 1. emitting the diagnostics
> 2. fallback to searching for instance methods of protocol qualified
> 'Class' independent of whether it was declared by a root class to 
> select a
> prototype before falling back to the global table.

OK, let me see if I understand you.  So we do emit the "+name not 
implemented/listed by protocol(s)"
warning, and then proceed to search for "-name" in the same set of 
protocols?  I guess then you should
get an additional diagnostic about multiple signatures, just as you do 
when you message
'id <CommonMethodNames1, CommonMethodNames2>' (which needs fixing, as I 
alluded to above)?

Actually, I think this would be fine!  Let's see if other people on the 
list have opinions on the matter.

A related issue would be handling constructs like

    [MyObject<MyProto1, MyProto2> someClassMethod]

where, I guess, the order of operations would be
   (1) Look for '+someClassMethod' in Proto1 and Proto2, and report any 
conflicts; if none found,
       emit "not listed in protocol(s)" warning;
   (2) Failing that, look for '+someClassMethod' in MyObject (which may 
also locate a '-someClassMethod'
       in its root class); if none found, emit "may not respond to" 
warning;
   (3) Failing that, look for '-someClassMethod' in Proto1 and Proto2, 
and report any conflicts;
   (4) Failing that, look for '+someClassMethod' in the global hash 
table (which will also yield '-someClassMethod'
       from root classes), and report any conflicts;
   (5) Failing that, emit "cannot find method" warning and select IMP as 
the signature.

For the case

   [Class<MyProto1, MyProto2> someClassMethod]

that we've been discussing, we would simply elide step (2).

For completeness,

    [MyObject<MyProto1, MyProto2> *someInstanceMethod]

will
   (1) Look for '-someClassMethod' in Proto1 and Proto2, and report any 
conflicts; if none found,
       emit "not listed in protocol(s)" warning;
   (2) Failing that, look for '-someClassMethod' in MyObject; if none 
found, emit "may not respond to" warning;
   (3) Failing that, look for '-someClassMethod' in the global hash 
table, and report any conflicts;
   (4) Failing that, emit "cannot find method" warning and select IMP as 
the signature.

while

    [id<MyProto1, MyProto2> someInstanceMethod]

will elide step (2).  Wow, this is starting to look like a fragment of 
an early draft of a language spec, so I'll stop now
before things get out of hand. :-)  Anyway, at least some of this stuff 
should wait until gcc 4.1 stage 1...

--Zem

--------------------------------------------------------------
Ziemowit Laski                 1 Infinite Loop, MS 301-2K
Mac OS X Compiler Group        Cupertino, CA USA  95014-2083
Apple Computer, Inc.           +1.408.974.6229  Fax .5477

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-01  0:55                       ` Ziemowit Laski
@ 2004-10-01  7:47                         ` Kai Henningsen
  2004-10-01 18:03                           ` Ziemowit Laski
  2004-10-01  9:02                         ` David Ayers
  1 sibling, 1 reply; 35+ messages in thread
From: Kai Henningsen @ 2004-10-01  7:47 UTC (permalink / raw)
  To: gcc-patches

zlaski@apple.com (Ziemowit Laski)  wrote on 30.09.04 in <8AD84E9F-1344-11D9-A719-000393673036@apple.com>:

> is not implemented by protocol(s).  (This raises a separate, tangential
> issue:
> protocols don't really implement things -- perhaps "not listed in
> protocol(s)"
> would be better?)

Isn't that what C generally calls "declared"? I think where generic C  
vocabulary is sufficient, Objective C shouldn't use new terms.

MfG Kai

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-01  0:55                       ` Ziemowit Laski
  2004-10-01  7:47                         ` Kai Henningsen
@ 2004-10-01  9:02                         ` David Ayers
  2004-10-01 18:30                           ` David Ayers
  1 sibling, 1 reply; 35+ messages in thread
From: David Ayers @ 2004-10-01  9:02 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc-patches

Ziemowit Laski wrote:
> On 30 Sep 2004, at 16.31, d.ayers@inode.at wrote:
> 
> 
>>@protocol <CommonMethodNames1>
>>- (const char *)name;
>>- (void)set;
>>- (int)compare:(id)obj;
>>- (int) host
>>@end
>>
>>@protocol <CommonMethodNames2>
>>- (NSString *)name;
>>- (NSSet *)set;
>>- (BOOL)compare:(id)obj;
>>- (NSString *)host
>>@end
> 
> 
> Oooh, that is pretty hairy. :-( But I don't think your proposal (or 
> mine, for that matter) deals with this issue, does it? I'm assuming
> that you're worrying about constructions like:
> 
>    id <CommonMethodNames1, CommonMethodNames2> obj;
>    Class <CommonMethodNames1, CommonMethodNames2> cls;
>      :
>    ... [obj name] ...
>    ... [cls name] ...
> 

Umm, no. But it was late when I replied and I was rather terse.  The
case can not be handled.  It would entail associating multiple
implementations for a selector for any given class and defining a new
construct to indicate at the call site, which protocol to use.

I just want to insure that when a protocol qualified 'Class' type is
declared (usually because we can't use static typing), that the
prototype of the instance methods take precedence before the global
method lists.  I'm still not sure whether this should only be done for
protocols adopted by root classes and go through the trouble of marking
them.

>> 1. emitting the diagnostics
>> 2. fallback to searching for instance methods of protocol qualified
>>  'Class' independent of whether it was declared by a root class to 
>> select a prototype before falling back to the global table.
> 
> 
> OK, let me see if I understand you. So we do emit the "+name not 
> implemented/listed by protocol(s)" warning, and then proceed to
> search for "-name" in the same set of protocols? I guess then you
> should get an additional diagnostic about multiple signatures, just
> as you do when you message 'id <CommonMethodNames1,
> CommonMethodNames2>' (which needs fixing, as I alluded to above)?

Yes, we could emit something "+name not declared by protocol(s)" but we
should then emit something "using '-name' of protocol '%s'".  Then the
prototype search wrt finding conflicting signatures can continue to
cover all further adopted and incorporated/inherited protocols, but it
should not continue to the global prototype list.

> A related issue would be handling constructs like
> 
>     [MyObject<MyProto1, MyProto2> someClassMethod]
> 
> where, I guess, the order of operations would be
>    (1) Look for '+someClassMethod' in Proto1 and Proto2, and report any 
> conflicts; if none found,
>        emit "not listed in protocol(s)" warning;
>    (2) Failing that, look for '+someClassMethod' in MyObject (which may 
> also locate a '-someClassMethod'
>        in its root class); if none found, emit "may not respond to" 
> warning;
>    (3) Failing that, look for '-someClassMethod' in Proto1 and Proto2, 
> and report any conflicts;
>    (4) Failing that, look for '+someClassMethod' in the global hash 
> table (which will also yield '-someClassMethod'
>        from root classes), and report any conflicts;
>    (5) Failing that, emit "cannot find method" warning and select IMP as 
> the signature.
> 
> For the case
> 
>    [Class<MyProto1, MyProto2> someClassMethod]
> 
> that we've been discussing, we would simply elide step (2).
> 
> For completeness,
> 
>     [MyObject<MyProto1, MyProto2> *someInstanceMethod]
> 
> will
>    (1) Look for '-someClassMethod' in Proto1 and Proto2, and report any 
> conflicts; if none found,
>        emit "not listed in protocol(s)" warning;
>    (2) Failing that, look for '-someClassMethod' in MyObject; if none 
> found, emit "may not respond to" warning;
>    (3) Failing that, look for '-someClassMethod' in the global hash 
> table, and report any conflicts;
>    (4) Failing that, emit "cannot find method" warning and select IMP as 
> the signature.
> 
> while
> 
>     [id<MyProto1, MyProto2> someInstanceMethod]
> 
> will elide step (2).  Wow, this is starting to look like a fragment of 
> an early draft of a language spec, so I'll stop now
> before things get out of hand. :-)  Anyway, at least some of this stuff 
> should wait until gcc 4.1 stage 1...

With taking what I said above into account, I think the orders you
proposed are sane.  Let's see how far I get today.

Cheers,
David

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-01  7:47                         ` Kai Henningsen
@ 2004-10-01 18:03                           ` Ziemowit Laski
  0 siblings, 0 replies; 35+ messages in thread
From: Ziemowit Laski @ 2004-10-01 18:03 UTC (permalink / raw)
  To: Kai Henningsen; +Cc: gcc-patches


On 30 Sep 2004, at 23.39, Kai Henningsen wrote:

> zlaski@apple.com (Ziemowit Laski)  wrote on 30.09.04 in 
> <8AD84E9F-1344-11D9-A719-000393673036@apple.com>:
>
>> is not implemented by protocol(s).  (This raises a separate, 
>> tangential
>> issue:
>> protocols don't really implement things -- perhaps "not listed in
>> protocol(s)"
>> would be better?)
>
> Isn't that what C generally calls "declared"? I think where generic C
> vocabulary is sufficient, Objective C shouldn't use new terms.

I agree that "declared" makes sense here.

--Zem

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-01  9:02                         ` David Ayers
@ 2004-10-01 18:30                           ` David Ayers
  2004-10-01 20:50                             ` David Ayers
  0 siblings, 1 reply; 35+ messages in thread
From: David Ayers @ 2004-10-01 18:30 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 831 bytes --]

David Ayers wrote:

> Let's see how far I get today.
> 

OK, I actually just got this working and really have to run (I wish I
could be doing this full time :-/ )

What is different, is that it will warn that the class methods isn't
declared but will use the instance prototype, if one is found.

I hope I've also taken into account your concerns wrt.
objc_finish_message_expr (one issue was that I was hacking around a type
issue in the diagnostics).

I've still kept marking the protocols and only search protocol
prototypes of root protocols.

I also kept my structure of objc_comptypes(_proto_proto) as you hadn't
mentioned it in the last mail.

If you need more explanations, I'll have to ask you be a little patient,
and I'll try to summarize the patch again.  Otherwise, I'd be glad to
know what you think.

Cheers,
David



[-- Attachment #2: ChangeLog.gcc --]
[-- Type: text/plain, Size: 258 bytes --]

2004-09-29  David Ayers  <d.ayers@inode.at>

	* c-common.h: Remove RID_ID.
	* c-parse.in: Remove OBJECTNAME and references to RID_ID.
	(typespec_reserved_attr): Add rule for TYPENAME
	non_empty_protocolrefs.
	(yylexname) Remove special handling of RID_ID.
	

[-- Attachment #3: ChangeLog.objc --]
[-- Type: text/plain, Size: 940 bytes --]

2004-09-29  David Ayers  <d.ayers@inode.at>

	* objc-act.h (PROTOCOL_ADOPTED_BY_ROOT_CLASS): New macro.
	(IS_PROTOCOL_QUALIFIED_ID): Removed macro.
	* objc-act.c (mark_protocols_adopted_by_root_class)
	(objc_comptypes_proto_proto): New functions.
	(lookup_method_in_protocol_list): Change last parameter
	to indicate whether instance methods of protocols adopted
	by root classes should be searched and emit diagnostics.
	(objc_comptypes_proto_proto): Mark prototypes that have been
	adopted by root classes.
	(objc_comptypes): Handle protocol qualified 'Class' types.
	(objc_get_protocol_qualified_type): Report error for unknown types
	with protocol qualifiers.  Update documentation.
	(objc_finish_message_expr): Remove correct type managment for
	diagnostics.  Handle protocol qualified 'Class' types.
	(lookup_method_static): Update callers of
	lookup_method_in_protocol_list.

	(lookup_and_install_protocols): Update documentation.
	

[-- Attachment #4: ChangeLog.test --]
[-- Type: text/plain, Size: 87 bytes --]

2004-09-29  David Ayers  <d.ayers@inode.at>

	* objc.dg/class-protocol-1.m: New test.


[-- Attachment #5: protocol.3.patch --]
[-- Type: text/plain, Size: 20669 bytes --]

Index: gcc/c-common.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.264
diff -u -r1.264 c-common.h
--- gcc/c-common.h	10 Sep 2004 23:56:18 -0000	1.264
+++ gcc/c-common.h	1 Oct 2004 17:59:50 -0000
@@ -92,7 +92,7 @@
   RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST,
 
   /* Objective-C */
-  RID_ID,          RID_AT_ENCODE,    RID_AT_END,
+  RID_AT_ENCODE,    RID_AT_END,
   RID_AT_CLASS,    RID_AT_ALIAS,     RID_AT_DEFS,
   RID_AT_PRIVATE,  RID_AT_PROTECTED, RID_AT_PUBLIC,
   RID_AT_PROTOCOL, RID_AT_SELECTOR,  
Index: gcc/c-parse.in
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-parse.in,v
retrieving revision 1.242
diff -u -r1.242 c-parse.in
--- gcc/c-parse.in	17 Sep 2004 18:17:59 -0000	1.242
+++ gcc/c-parse.in	1 Oct 2004 17:59:51 -0000
@@ -180,7 +180,7 @@
    Objective C, so that the token codes are the same in both.  */
 %token AT_INTERFACE AT_IMPLEMENTATION AT_END AT_SELECTOR AT_DEFS AT_ENCODE
 %token CLASSNAME AT_PUBLIC AT_PRIVATE AT_PROTECTED AT_PROTOCOL
-%token OBJECTNAME AT_CLASS AT_ALIAS
+%token AT_CLASS AT_ALIAS
 %token AT_THROW AT_TRY AT_CATCH AT_FINALLY AT_SYNCHRONIZED
 %token OBJC_STRING
 
@@ -261,7 +261,7 @@
 %type <ttype> selectorarg keywordnamelist keywordname objcencodeexpr
 %type <ttype> non_empty_protocolrefs protocolrefs identifier_list objcprotocolexpr
 
-%type <ttype> CLASSNAME OBJECTNAME OBJC_STRING OBJC_TYPE_QUAL
+%type <ttype> CLASSNAME OBJC_STRING OBJC_TYPE_QUAL
 
 %type <ttype> superclass objc_quals objc_qual objc_typename
 %type <itype> objc_try_catch_stmt optellipsis
@@ -474,7 +474,6 @@
 	IDENTIFIER
 	| TYPENAME
 @@ifobjc
-	| OBJECTNAME
 	| CLASSNAME
 @@end_ifobjc
 	;
@@ -1274,7 +1273,7 @@
 @@ifobjc
 	| CLASSNAME protocolrefs
 		{ $$ = objc_get_protocol_qualified_type ($1, $2); }
-	| OBJECTNAME protocolrefs
+	| TYPENAME non_empty_protocolrefs
 		{ $$ = objc_get_protocol_qualified_type ($1, $2); }
 
 /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>"
@@ -1549,10 +1548,6 @@
 		{ $$ = make_pointer_declarator ($2, $3); }
 	| TYPENAME
 		{ $$ = build_id_declarator ($1); }
-@@ifobjc
-	| OBJECTNAME
-		{ $$ = build_id_declarator ($1); }
-@@end_ifobjc
 	;
 
 /* Kinds of declarator that can appear in a parameter list
@@ -1571,10 +1566,6 @@
 		{ $$ = set_array_declarator_inner ($2, $1, false); }
 	| TYPENAME
 		{ $$ = build_id_declarator ($1); }
-@@ifobjc
-	| OBJECTNAME
-		{ $$ = build_id_declarator ($1); }
-@@end_ifobjc
 	;
 
 parm_declarator_nostarttypename:
@@ -2861,7 +2852,6 @@
 	  IDENTIFIER
 	| TYPENAME
 	| CLASSNAME
-	| OBJECTNAME
 	| reservedwords
 	;
 
@@ -3127,7 +3117,6 @@
   { "while",		RID_WHILE,	0 },
 
 @@ifobjc
-  { "id",		RID_ID,			D_OBJC },
 
   /* These objc keywords are recognized only immediately after
      an '@'.  */
@@ -3273,7 +3262,6 @@
   /* RID_STATCAST */	0,
 
   /* Objective C */
-  /* RID_ID */			OBJECTNAME,
   /* RID_AT_ENCODE */		AT_ENCODE,
   /* RID_AT_END */		AT_END,
   /* RID_AT_CLASS */		AT_CLASS,
@@ -3342,15 +3330,6 @@
       enum rid rid_code = C_RID_CODE (yylval.ttype);
 
 @@ifobjc
-      /* Turn non-typedefed refs to "id" into plain identifiers; this
-	 allows constructs like "void foo(id id);" to work.  */
-      if (rid_code == RID_ID)
-      {
-	decl = lookup_name (yylval.ttype);
-	if (decl == NULL_TREE || TREE_CODE (decl) != TYPE_DECL)
-	  return IDENTIFIER;
-      }
-
       if (!OBJC_IS_AT_KEYWORD (rid_code)
 	  && (!OBJC_IS_PQ_KEYWORD (rid_code) || objc_pq_context))
 @@end_ifobjc
@@ -3513,7 +3492,6 @@
     {
     case IDENTIFIER:
     case TYPENAME:
-    case OBJECTNAME:
     case TYPESPEC:
     case TYPE_QUAL:
     case SCSPEC:
Index: gcc/objc/objc-act.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.248
diff -u -r1.248 objc-act.c
--- gcc/objc/objc-act.c	24 Sep 2004 23:15:33 -0000	1.248
+++ gcc/objc/objc-act.c	1 Oct 2004 17:59:54 -0000
@@ -236,6 +236,7 @@
 static tree lookup_protocol (tree);
 static void check_protocol_recursively (tree, tree);
 static tree lookup_and_install_protocols (tree);
+static void mark_protocols_adopted_by_root_class (tree);
 
 /* Type encoding.  */
 
@@ -329,6 +330,8 @@
      ATTRIBUTE_NORETURN;
 static void mark_referenced_methods (void);
 static void generate_objc_image_info (void);
+static inline int objc_comptypes_proto_proto(tree lhs, tree rhs, 
+					     int reflexive);
 
 /*** Private Interface (data) ***/
 
@@ -606,12 +609,16 @@
 }
 \f
 /* Return the first occurrence of a method declaration corresponding
-   to sel_name in rproto_list.  Search rproto_list recursively.
-   If is_class is 0, search for instance methods, otherwise for class
-   methods.  */
+   to SEL_NAME in RPROTO_LIST.  Search RPROTO_LIST recursively.
+   If SEARCH_OPT is 0, search only for instance methods.
+   If SEARCH_OPT is 1, search only for class methods.
+   If SEARCH_OPT is 2, first search for class methods yet continue
+   to search for instance methods if no class method was found and
+   emit diagnostics.  */
+
 static tree
 lookup_method_in_protocol_list (tree rproto_list, tree sel_name,
-				int is_class)
+				int search_opt)
 {
    tree rproto, p;
    tree fnd = 0;
@@ -622,13 +629,23 @@
 
 	if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
 	  {
-	    if ((fnd = lookup_method (is_class
+	    if ((fnd = lookup_method (search_opt
 				      ? PROTOCOL_CLS_METHODS (p)
 				      : PROTOCOL_NST_METHODS (p), sel_name)))
 	      ;
+	    else if (search_opt == 2
+		     && PROTOCOL_ADOPTED_BY_ROOT_CLASS (p)
+		     && ((fnd = lookup_method (PROTOCOL_NST_METHODS (p),
+					       sel_name))))
+	      {
+		warning ("%<+%s%> not implemented by protocol(s) "
+			 "as class method", 
+			 IDENTIFIER_POINTER (sel_name));
+		warn_with_method ("using", '-', fnd);
+	      }
 	    else if (PROTOCOL_LIST (p))
 	      fnd = lookup_method_in_protocol_list (PROTOCOL_LIST (p),
-						    sel_name, is_class);
+						    sel_name, search_opt);
 	  }
 	else
           {
@@ -712,6 +729,41 @@
 objc_finish_interface (void)
 {
   finish_class (objc_interface_context);
+  if (TREE_CODE (objc_interface_context) == CLASS_INTERFACE_TYPE
+      && CLASS_PROTOCOL_LIST (objc_interface_context))
+    {
+      if (!CLASS_SUPER_NAME (objc_interface_context))
+	mark_protocols_adopted_by_root_class 
+	  (CLASS_PROTOCOL_LIST (objc_interface_context));
+    }
+  else if (TREE_CODE (objc_interface_context) == CATEGORY_INTERFACE_TYPE
+	   && CLASS_PROTOCOL_LIST (objc_interface_context))
+    {
+      tree class = lookup_interface (CLASS_NAME (objc_interface_context));
+
+      if (!CLASS_SUPER_NAME (class))
+	mark_protocols_adopted_by_root_class 
+	  (CLASS_PROTOCOL_LIST (objc_interface_context));
+    }
+  else if (TREE_CODE (objc_interface_context) == PROTOCOL_INTERFACE_TYPE
+	   && PROTOCOL_ADOPTED_BY_ROOT_CLASS (objc_interface_context))
+    {
+      tree protocol = objc_interface_context;
+      tree method_decl;
+
+      /* Since we do not have a protocol list,
+	 go ahead and register the method list directly.  */
+      for (method_decl = PROTOCOL_NST_METHODS (protocol);
+	   method_decl;
+	   method_decl = TREE_CHAIN (method_decl))
+	{
+	  add_method_to_hash_list(cls_method_hash_list, method_decl);
+	}
+
+      /* This protocol is marked.  Now mark all incorperated protocols.  */
+      mark_protocols_adopted_by_root_class (PROTOCOL_LIST (protocol));
+    }
+
   objc_interface_context = NULL_TREE;
 }
 
@@ -836,6 +888,83 @@
 }
 
 /* Return 1 if LHS and RHS are compatible types for assignment or
+   various other operations.  Return 0 if they are incompatible.
+   When the operation is REFLEXIVE (typically comparisons), check 
+   for compatibility in either direction; when it's not (typically 
+   assignments), don't.
+
+   This is a helper function for objc_comptypes to be able to test 
+   two protocol qualified types of the same basic type to insure 
+   protocol conformance and to emit the necessary warnings.  */
+
+static inline
+int objc_comptypes_proto_proto(tree lhs, tree rhs, int reflexive)
+{
+  tree lproto, lproto_list = TYPE_PROTOCOL_LIST (lhs);
+  tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs);
+  tree p;
+
+  gcc_assert((IS_ID (lhs) && IS_ID (rhs))
+	     || (IS_CLASS (lhs) && IS_CLASS (rhs)));
+
+  if (!reflexive)
+    {
+      /* An assignment between two objects both either of type 'id <Protocol>' 
+	 or both 'Class <Protocol>; make sure the protocol on the lhs is
+	 supported by the object on the rhs.  */
+      for (lproto = lproto_list; lproto;
+	   lproto = TREE_CHAIN (lproto))
+	{
+	  p = TREE_VALUE (lproto);
+	  rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+	  if (!rproto)
+	    warning
+	      ("%s does not conform to the `%s' protocol",
+	       IS_ID(lhs) ? "object" : "class",
+	       IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+	}
+      return 1;
+    }
+  else
+    {
+      /* Obscure case - a comparison between two objects either both
+	 of type 'id <Protocol>' or both 'Class <protocol>'.  Check 
+	 that either the protocol on the lhs is supported by the object on
+	 the rhs, or viceversa.  */
+
+      /* Check if the protocol on the lhs is supported by the
+	 object on the rhs.  */
+      for (lproto = lproto_list; lproto;
+	   lproto = TREE_CHAIN (lproto))
+	{
+	  p = TREE_VALUE (lproto);
+	  rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+	  if (!rproto)
+	    {
+	      /* Check failed - check if the protocol on the rhs
+		 is supported by the object on the lhs.  */
+	      for (rproto = rproto_list; rproto;
+		   rproto = TREE_CHAIN (rproto))
+		{
+		  p = TREE_VALUE (rproto);
+		  lproto = lookup_protocol_in_reflist (lproto_list, p);
+
+		  if (!lproto)
+		    {
+		      /* This check failed too: incompatible  */
+		      return 0;
+		    }
+		}
+	      return 1;
+	    }
+	}
+      return 1;
+    }
+}
+
+/* Return 1 if LHS and RHS are compatible types for assignment or
    various other operations.  Return 0 if they are incompatible, and
    return -1 if we choose to not decide (because the types are really
    just C types, not ObjC specific ones).  When the operation is
@@ -866,76 +995,21 @@
       && TREE_CODE (rhs) == POINTER_TYPE
       && TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE)
     {
-      int lhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (lhs);
-      int rhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (rhs);
+      int lhs_is_proto_id = IS_ID (lhs) && TYPE_PROTOCOL_LIST (lhs);
+      int rhs_is_proto_id = IS_ID (rhs) && TYPE_PROTOCOL_LIST (rhs);
+      int lhs_is_proto_class = IS_CLASS (lhs) && TYPE_PROTOCOL_LIST (lhs);
+      int rhs_is_proto_class = IS_CLASS (rhs) && TYPE_PROTOCOL_LIST (rhs);
 
-      if (lhs_is_proto)
+      if (lhs_is_proto_id)
         {
 	  tree lproto, lproto_list = TYPE_PROTOCOL_LIST (lhs);
 	  tree rproto, rproto_list;
 	  tree p;
 
 	  /* <Protocol> = <Protocol>  */
-	  if (rhs_is_proto)
-	    {
-	      rproto_list = TYPE_PROTOCOL_LIST (rhs);
-
-	      if (!reflexive)
-		{
-		  /* An assignment between objects of type 'id
-		     <Protocol>'; make sure the protocol on the lhs is
-		     supported by the object on the rhs.  */
-		  for (lproto = lproto_list; lproto;
-		       lproto = TREE_CHAIN (lproto))
-		    {
-		      p = TREE_VALUE (lproto);
-		      rproto = lookup_protocol_in_reflist (rproto_list, p);
-
-		      if (!rproto)
-			warning
-			  ("object does not conform to the `%s' protocol",
-			   IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
-		    }
-		  return 1;
-		}
-	      else
-		{
-		  /* Obscure case - a comparison between two objects
-		     of type 'id <Protocol>'.  Check that either the
-		     protocol on the lhs is supported by the object on
-		     the rhs, or viceversa.  */
-
-		  /* Check if the protocol on the lhs is supported by the
-		     object on the rhs.  */
-		  for (lproto = lproto_list; lproto;
-		       lproto = TREE_CHAIN (lproto))
-		    {
-		      p = TREE_VALUE (lproto);
-		      rproto = lookup_protocol_in_reflist (rproto_list, p);
-
-		      if (!rproto)
-			{
-			  /* Check failed - check if the protocol on the rhs
-			     is supported by the object on the lhs.  */
-			  for (rproto = rproto_list; rproto;
-			       rproto = TREE_CHAIN (rproto))
-			    {
-			      p = TREE_VALUE (rproto);
-			      lproto = lookup_protocol_in_reflist (lproto_list,
-								   p);
+	  if (rhs_is_proto_id)
+	    return objc_comptypes_proto_proto (lhs, rhs, reflexive);
 
-			      if (!lproto)
-				{
-				  /* This check failed too: incompatible  */
-				  return 0;
-				}
-			    }
-			  return 1;
-			}
-		    }
-		  return 1;
-		}
-	    }
 	  /* <Protocol> = <class> *  */
 	  else if (TYPED_OBJECT (TREE_TYPE (rhs)))
 	    {
@@ -998,7 +1072,7 @@
 	  /* <Protocol> = ?? : let comptypes decide.  */
           return -1;
         }
-      else if (rhs_is_proto)
+      else if (rhs_is_proto_id)
 	{
 	  /* <class> * = <Protocol> */
 	  if (TYPED_OBJECT (TREE_TYPE (lhs)))
@@ -1078,6 +1152,46 @@
 	      return -1;
 	    }
 	}
+      else if (lhs_is_proto_class)
+	{
+	  /* Class <Protocol> = Class <Protocol>  */
+	  if (rhs_is_proto_class)
+	    return objc_comptypes_proto_proto (lhs, rhs, reflexive);
+
+	  /* Class <Protocol> = <class> *  */
+	  else if (TYPED_OBJECT (TREE_TYPE (rhs)))
+	    return 0;
+
+	  /* Class <Protocol> = Class */
+	  else if (objc_is_class_id (TREE_TYPE (rhs)))
+	    return 1;
+
+	  /* Class <Protocol> = id && Class <Protocol> = <Protocol> */
+	  else if (objc_is_object_id (TREE_TYPE (rhs)))
+	    return (rhs_is_proto_id ? 0 : 1);
+
+	  /* <Protocol> = ?? : let comptypes decide.  */
+	  else
+	    return -1;
+	}
+      else if (rhs_is_proto_class)
+	{
+	  /* <class> * = Class <Protocol> */
+	  if (TYPED_OBJECT (TREE_TYPE (lhs)))
+	    return 0;
+
+	  /* id = Class <Protocol> && <Protocol> = Class <Protocol> */
+	  else if (objc_is_object_id (TREE_TYPE (lhs)))
+	    return (lhs_is_proto_id ? 0 : 1);
+
+	  /* Class = Class <Protocol> */
+	  else if (objc_is_class_id (TREE_TYPE (lhs)))
+	    return 1;
+
+	  /* ??? = Class <Protocol> : let comptypes decide */
+	  else
+	    return -1;
+	}
       else
 	{
 	  /* Attention: we shouldn't defer to comptypes here.  One bad
@@ -1164,7 +1278,7 @@
 
 /* Construct a PROTOCOLS-qualified variant of INTERFACE, where INTERFACE may
    either name an Objective-C class, or refer to the special 'id' or 'Class'
-   types.  If INTERFACE is not a valid ObjC type, just return it unchanged.  */
+   types.  If INTERFACE is not a valid ObjC type, report error.  */
 
 tree
 objc_get_protocol_qualified_type (tree interface, tree protocols)
@@ -1180,7 +1294,10 @@
       if (type)
 	type = xref_tag (RECORD_TYPE, type);
       else
-        return interface;
+	{
+	  error ("protocol qualifiers specified for non-Objective-C type");
+	  return error_mark_node;
+	}
     }
 
   if (protocols)
@@ -1222,8 +1339,10 @@
     }
 }
 
-/* Look up PROTOCOLS, and return a list of those that are found.
-   If none are found, return NULL.  */
+/* Look up PROTOCOLS, a list of identifiers, and return the list
+   of the protocol interface declarations that are found.  Invokes error
+   for each identifier for which the lookup failed.
+   If PROTOCOLS is empty, return NULL.  */
 
 static tree
 lookup_and_install_protocols (tree protocols)
@@ -1247,6 +1366,44 @@
   return return_value;
 }
 
+/* Iterates over the protocol interface list RPROTOS marking each as
+   PROTOCOL_ADOPTED_BY_ROOT_CLASS.  Registers the instance methods 
+   prototypes of each protocol and their incorperated protocols recursively
+   as potential class methods.  */
+
+static void
+mark_protocols_adopted_by_root_class (tree rprotos)
+{
+  tree protocol_ch;
+  tree protocol;
+
+  for (protocol_ch = rprotos;
+       protocol_ch;
+       protocol_ch = TREE_CHAIN (protocol_ch))
+    {
+      protocol = TREE_CHECK(TREE_VALUE (protocol_ch),
+			    PROTOCOL_INTERFACE_TYPE);
+
+      /* Minor efficiency check.  Expect all protocols which have
+	 been previously marked, to have had their methods registered.  */
+      if (!PROTOCOL_ADOPTED_BY_ROOT_CLASS (protocol))
+	{
+	  tree method_decl;
+
+	  for (method_decl = PROTOCOL_NST_METHODS (protocol);
+	       method_decl;
+	       method_decl = TREE_CHAIN (method_decl))
+	    {
+	      add_method_to_hash_list(cls_method_hash_list, method_decl);
+	    }
+	}
+
+      PROTOCOL_ADOPTED_BY_ROOT_CLASS (protocol) = 1;
+
+      mark_protocols_adopted_by_root_class (PROTOCOL_LIST (protocol));
+    }
+}
+
 /* Create a declaration for field NAME of a given TYPE.  */
 
 static tree
@@ -5570,13 +5727,21 @@
       else
 	{
 	  class_tree = objc_class_name;
-	  OBJC_SET_TYPE_NAME (rtype, class_tree);
+	  
+	  rprotos = TYPE_PROTOCOL_LIST (rtype);
+
+	  /* We keep the rtype for 'Class' so that 
+	     instance prototypes will be searched.
+	     But a warning will be emitted.  */
+	  if (rprotos)
+	    rtype = NULL_TREE;
 	}
 
       if (rprotos)
 	method_prototype
 	  = lookup_method_in_protocol_list (rprotos, sel_name,
-					    class_tree != NULL_TREE);
+					    class_tree != NULL_TREE ? 2 : 0);
+
       if (!method_prototype && !rprotos)
 	method_prototype
 	  = lookup_method_in_hash_lists (sel_name,
@@ -5631,7 +5796,8 @@
 	  if (!method_prototype && rprotos)
 	    method_prototype
 	      = lookup_method_in_protocol_list (rprotos, sel_name,
-						class_tree != NULL_TREE);
+						class_tree != NULL_TREE 
+						? 1 : 0);
 	}
       else
 	{
@@ -5646,14 +5812,25 @@
       static bool warn_missing_methods = false;
 
       if (rtype)
-	warning ("`%s' may not respond to `%c%s'",
-		 IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)),
+	warning ("%<%s%> may not respond to `%c%s'",
+		 TREE_CODE (OBJC_TYPE_NAME (rtype)) == IDENTIFIER_NODE
+		 ? IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype))
+		 : IDENTIFIER_POINTER (DECL_NAME (OBJC_TYPE_NAME (rtype))),
 		 (class_tree ? '+' : '-'),
 		 IDENTIFIER_POINTER (sel_name));
+      /* If we are messaging an unadorned 'id' or 'Class' object,
+         then we have failed to find _any_ instance or class method,
+         respectively.  */
+      else if (!rprotos)
+        warning ("no `%c%s' method found",
+                 (class_tree ? '+' : '-'),
+                 IDENTIFIER_POINTER (sel_name));
+
       if (rprotos)
 	warning ("`%c%s' not implemented by protocol(s)",
 		 (class_tree ? '+' : '-'),
 		 IDENTIFIER_POINTER (sel_name));
+
       if (!warn_missing_methods)
 	{
 	  warning ("(Messages without a matching method signature");
@@ -6062,7 +6239,8 @@
 	  if (CLASS_PROTOCOL_LIST (category))
 	    {
 	      if ((meth = (lookup_method_in_protocol_list
-			   (CLASS_PROTOCOL_LIST (category), ident, is_class))))
+			   (CLASS_PROTOCOL_LIST (category),
+			    ident, is_class ? 1 : 0))))
 		return meth;
 	    }
 	}
@@ -6071,7 +6249,8 @@
       if (CLASS_PROTOCOL_LIST (inter))
 	{
 	  if ((meth = (lookup_method_in_protocol_list
-		       (CLASS_PROTOCOL_LIST (inter), ident, is_class))))
+		       (CLASS_PROTOCOL_LIST (inter), 
+			ident, is_class ? 1 : 0))))
 	    return meth;
 	}
 
Index: gcc/objc/objc-act.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/objc/objc-act.h,v
retrieving revision 1.31
diff -u -r1.31 objc-act.h
--- gcc/objc/objc-act.h	22 Sep 2004 01:13:07 -0000	1.31
+++ gcc/objc/objc-act.h	1 Oct 2004 17:59:55 -0000
@@ -37,6 +37,14 @@
 #define CLASS_LANG_SLOT_ELTS		5
 #define PROTOCOL_LANG_SLOT_ELTS		2
 
+/*
+  Objective-C usage for TREE_LANG_FLAG_?:
+
+  0: PROTOCOL_ADOPTED_BY_ROOT_CLASS - (valid for PROTOCOL_INTERFACE_TYPE)
+     Marks protocol declarations that are adopted by root classes
+     so that instance methods are also checked for Class references.
+*/
+
 /* KEYWORD_DECL */
 #define KEYWORD_KEY_NAME(DECL) ((DECL)->decl.name)
 #define KEYWORD_ARG_NAME(DECL) ((DECL)->decl.arguments)
@@ -66,6 +74,7 @@
 #define PROTOCOL_CLS_METHODS(CLASS) ((CLASS)->type.maxval)
 #define PROTOCOL_FORWARD_DECL(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 1)
 #define PROTOCOL_DEFINED(CLASS) TREE_USED (CLASS)
+#define PROTOCOL_ADOPTED_BY_ROOT_CLASS(CLASS) TREE_LANG_FLAG_0 (CLASS)
 
 /* We need to distinguish TYPE_PROTOCOL_LISTs from TYPE_CONTEXTs, both of which
    are stored in the same accessor slot.  */
@@ -277,8 +286,6 @@
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == TREE_TYPE (objc_object_type))
 #define IS_CLASS(TYPE) \
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == TREE_TYPE (objc_class_type))
-#define IS_PROTOCOL_QUALIFIED_ID(TYPE) \
-  (IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE))
 #define IS_SUPER(TYPE) \
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == objc_super_template)
 

[-- Attachment #6: class-protocol-1.m --]
[-- Type: text/plain, Size: 8027 bytes --]

/* Check Class <protocol> types */
/* Author: David Ayers <d.ayers@inode.at> */
/* { dg-do compile } */

#include <objc/objc.h>
#include <objc/objc-api.h>

@protocol MyProto1
+(void)doItClass1;
-(void)doItInstance1; /* { dg-warning "using" } */
@end

@protocol MyProto2
+(void)doItClass2;
-(void)doItInstance2;
@end

@interface MyClass1 <MyProto1>
{
  Class isa;
}
@end
@implementation MyClass1
+(void)doItClass1{}
-(void)doItInstance1{}
@end

@interface MyClass2 : MyClass1 <MyProto2>
@end
@implementation MyClass2
+(void)doItClass2{}
-(void)doItInstance2{}
@end

@interface MyClass3
{
  Class isa;
}
@end
@interface MyClass4 : MyClass3 <MyProto1>
@end

/*----------------------------------------*/

Class cls = 0;
Class <MyProto1> clsP1 = 0;
Class <MyProto2> clsP2 = 0;

void
testSimple(void)
{
  [cls doItClass1];
  [cls doItInstance1]; /* Do not warn as root Class declares this.  */
  [cls doItClass2];
  [cls doItInstance2]; /* { dg-warning "may not respond" } */

  [clsP1 doItClass1];
  [clsP1 doItInstance1]; /* { dg-warning "as class method" }  */
  [clsP1 doItClass2];    /* { dg-warning "not implemented by protocol" } */
  [clsP1 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [clsP2 doItClass1];    /* { dg-warning "not implemented by protocol" } */
  [clsP2 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
  [clsP2 doItClass2];
  [clsP2 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass1];
  [MyClass1 doItInstance1];
  [MyClass1 doItClass2];    /* { dg-warning "may not respond to" } */
  [MyClass1 doItInstance2]; /* { dg-warning "may not respond to" } */

  [MyClass2 doItClass1];
  [MyClass2 doItInstance1];
  [MyClass2 doItClass2];
  [MyClass2 doItInstance2]; /* { dg-warning "may not respond to" } */

  [MyClass3 doItClass1];    /* { dg-warning "may not respond to" } */
  [MyClass3 doItInstance1]; /* { dg-warning "may not respond to" } */

  [MyClass4 doItClass1];    
  [MyClass4 doItInstance1]; /* { dg-warning "may not respond to" } */

}

/*----------------------------------------*/
/* Protocols declared by categories */

@protocol MyProto3
+(void)doItClass3;
-(void)doItInstance3;
@end
@protocol MyProto4
+(void)doItClass4;
-(void)doItInstance4;
@end

@interface MyClass1 (Category1) <MyProto3>
@end
@interface MyClass2 (Category2) <MyProto4>
@end

void
testCategory(void)
{
  [cls doItClass3];
  [cls doItInstance3];      /* Do not warn as root Class declares this.  */
  [cls doItClass4];
  [cls doItInstance4];      /* { dg-warning "may not respond" } */

  [MyClass1 doItClass3];
  [MyClass1 doItInstance3];
  [MyClass1 doItClass4];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance4]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass3];
  [MyClass2 doItInstance3];
  [MyClass2 doItClass4];
  [MyClass2 doItInstance4]; /* { dg-warning "may not respond" } */

}

/*----------------------------------------*/
/* Incorperated protocols declared by categories */

@protocol MyProto5 <MyProto1>
+(void)doItClass5;
-(void)doItInstance5;
@end

@protocol MyProto6 <MyProto2>
+(void)doItClass6;
-(void)doItInstance6;
@end

@interface MyClass1 (Category3) <MyProto5>
@end
@interface MyClass2 (Category4) <MyProto6>
@end

Class <MyProto5> clsP5 = 0;
Class <MyProto6> clsP6 = 0;

void
testCategoryIncorporated(void)
{
  [cls doItClass5];
  [cls doItInstance5]; /* Do not warn as root Class declares this.  */
  [cls doItClass6];
  [cls doItInstance6]; /* { dg-warning "may not respond" } */

  [clsP5 doItClass1];
  [clsP5 doItInstance1]; /* { dg-warning "as class method" }  */
  [clsP5 doItClass2];    /* { dg-warning "not implemented by protocol" } */
  [clsP5 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [clsP6 doItClass1];    /* { dg-warning "not implemented by protocol" } */
  [clsP6 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
  [clsP6 doItClass2];
  [clsP6 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass5];
  [MyClass1 doItInstance5]; /* Do not warn as root Class declares this.  */
  [MyClass1 doItClass6];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance6]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass5];
  [MyClass2 doItInstance5]; /* Do not warn as root Class declares this.  */
  [MyClass2 doItClass6];
  [MyClass2 doItInstance6]; /* { dg-warning "may not respond" } */

}

/*----------------------------------------*/
/* Forward declared root protocols */

@protocol FwProto;

@interface MyClass1 (Forward) <FwProto>
@end

Class <FwProto> clsP7 = 0;

void
testForwardeDeclared1(void)
{
  [cls doItClass7];         /* { dg-warning "may not respond" } */
  [cls doItInstance7];      /* { dg-warning "may not respond" } */

  [clsP7 doItClass7];       /* { dg-warning "not implemented by protocol" } */
  [clsP7 doItInstance7];    /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass7];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance7]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass7];    /* { dg-warning "may not respond" } */
  [MyClass2 doItInstance7]; /* { dg-warning "may not respond" } */

}

@protocol FwProto
+(void)doItClass7;
-(void)doItInstance7; /* { dg-warning "using" } */
@end

void
testForwardeDeclared2(void)
{
  [cls doItClass7];
  [cls doItInstance7];   /* Do not warn as root Class declares this.  */

  [clsP7 doItClass7];    
  [clsP7 doItInstance7]; /* { dg-warning "as class method" } */

  [MyClass1 doItClass7];
  [MyClass1 doItInstance7];

  [MyClass2 doItClass7];
  [MyClass2 doItInstance7];

}

/*----------------------------------------*/
/* Incorperated non root protocols */

@protocol MyProto8
+(void)doItClass8;
-(void)doItInstance8; /* { dg-warning "using" } */
@end

@protocol MyProto9 <MyProto8>
+(void)doItClass9;
-(void)doItInstance9; /* { dg-warning "using" } */
@end

@interface MyClass1 (IncorporatedNonRoot) <MyProto9>
@end

Class <MyProto8> clsP8 = 0;
Class <MyProto9> clsP9 = 0;

void
testIncorporatedNonRoot(void)
{
  [cls doItClass8];
  [cls doItInstance8]; /* Do not warn as root Class declares super.  */
  [cls doItClass9];
  [cls doItInstance9]; /* Do not warn as root Class declares this.  */

  [clsP8 doItClass8];
  [clsP8 doItInstance8]; /* { dg-warning "as class method" } debatable */
  [clsP8 doItClass9];    /* { dg-warning "not implemented by protocol" } */
  [clsP8 doItInstance9]; /* { dg-warning "not implemented by protocol" } */

  [clsP9 doItClass8];
  [clsP9 doItInstance8]; /* { dg-warning "as class method" } */
  [clsP9 doItClass9];
  [clsP9 doItInstance9]; /* { dg-warning "as class method" } */

  [MyClass1 doItClass8];
  [MyClass1 doItInstance8]; /* Do not warn as root Class declares this.  */
  [MyClass1 doItClass9];
  [MyClass1 doItInstance9];

  [MyClass2 doItClass8];
  [MyClass2 doItInstance8]; /* Do not warn as root Class declares this.  */
  [MyClass2 doItClass9];
  [MyClass2 doItInstance9];
  
}

id obj = nil;
id <MyProto1> objP1 = nil;
id <MyProto2> objP2 = nil;

MyClass1 *mc1 = nil;

void
testComptypes(void)
{
  cls == clsP1;
  clsP1 == cls;

  cls == objP1; /* { dg-warning "lacks a cast" } */
  objP1 == cls; /* { dg-warning "lacks a cast" } */

  clsP1 == clsP5;
  clsP5 == clsP1;

  mc1 == clsP1; /* { dg-warning "lacks a cast" } */
  clsP1 == mc1; /* { dg-warning "lacks a cast" } */


  cls = clsP1; 
  clsP1 = cls;

  cls = objP1; /* { dg-warning "incompatible" } */
  objP1 = cls; /* { dg-warning "incompatible" } */

  clsP1 = clsP5;
  clsP5 = clsP1; /* { dg-warning "does not conform" } */

  mc1 = clsP1; /* { dg-warning "incompatible" } */
  clsP1 = mc1; /* { dg-warning "incompatible" } */

}

int main ()
{
  testSimple();
  testCategory();
  testCategoryIncorporated();
  return(0);
}

/* { dg-warning "Messages without a matching" "" { target *-*-* } 0 } */
/* { dg-warning "will be assumed to return" "" { target *-*-* } 0 } */
/* { dg-warning "as arguments" "" { target *-*-* } 0 } */


[-- Attachment #7: patch.tar.gz --]
[-- Type: application/x-gunzip, Size: 7923 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-01 18:30                           ` David Ayers
@ 2004-10-01 20:50                             ` David Ayers
  2004-10-02 17:35                               ` David Ayers
  0 siblings, 1 reply; 35+ messages in thread
From: David Ayers @ 2004-10-01 20:50 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1122 bytes --]

David Ayers wrote:
> David Ayers wrote:
> 
> 
>>Let's see how far I get today.
>>
> 
> 
> OK, I actually just got this working and really have to run (I wish I
> could be doing this full time :-/ )
> 
> What is different, is that it will warn that the class methods isn't
> declared but will use the instance prototype, if one is found.
> 
> I hope I've also taken into account your concerns wrt.
> objc_finish_message_expr (one issue was that I was hacking around a type
> issue in the diagnostics).
> 
> I've still kept marking the protocols and only search protocol
> prototypes of root protocols.
> 
> I also kept my structure of objc_comptypes(_proto_proto) as you hadn't
> mentioned it in the last mail.
> 
> If you need more explanations, I'll have to ask you be a little patient,
> and I'll try to summarize the patch again.  Otherwise, I'd be glad to
> know what you think.


*sigh*, once I got home I noticed I packed up the wrong tree :-(  Here 
is the one I meant to send.

The difference is in objc_finish_message_expr and the adapted test case 
for the "no '+selector' method found" message.

Cheers,
David


[-- Attachment #2: ChangeLog.gcc --]
[-- Type: text/plain, Size: 258 bytes --]

2004-09-29  David Ayers  <d.ayers@inode.at>

	* c-common.h: Remove RID_ID.
	* c-parse.in: Remove OBJECTNAME and references to RID_ID.
	(typespec_reserved_attr): Add rule for TYPENAME
	non_empty_protocolrefs.
	(yylexname) Remove special handling of RID_ID.
	

[-- Attachment #3: ChangeLog.objc --]
[-- Type: text/plain, Size: 940 bytes --]

2004-09-29  David Ayers  <d.ayers@inode.at>

	* objc-act.h (PROTOCOL_ADOPTED_BY_ROOT_CLASS): New macro.
	(IS_PROTOCOL_QUALIFIED_ID): Removed macro.
	* objc-act.c (mark_protocols_adopted_by_root_class)
	(objc_comptypes_proto_proto): New functions.
	(lookup_method_in_protocol_list): Change last parameter
	to indicate whether instance methods of protocols adopted
	by root classes should be searched and emit diagnostics.
	(objc_comptypes_proto_proto): Mark prototypes that have been
	adopted by root classes.
	(objc_comptypes): Handle protocol qualified 'Class' types.
	(objc_get_protocol_qualified_type): Report error for unknown types
	with protocol qualifiers.  Update documentation.
	(objc_finish_message_expr): Remove correct type managment for
	diagnostics.  Handle protocol qualified 'Class' types.
	(lookup_method_static): Update callers of
	lookup_method_in_protocol_list.

	(lookup_and_install_protocols): Update documentation.
	

[-- Attachment #4: ChangeLog.test --]
[-- Type: text/plain, Size: 87 bytes --]

2004-09-29  David Ayers  <d.ayers@inode.at>

	* objc.dg/class-protocol-1.m: New test.


[-- Attachment #5: protocol.4.patch --]
[-- Type: text/plain, Size: 20491 bytes --]

? build
? protocol.1.patch
? protocol.2.patch
? protocol.3.patch
? protocol.patch
? protocol.patchnew
? gcc/testsuite/objc.dg/class-protocol-1-tmp.m
? gcc/testsuite/objc.dg/class-protocol-1.m
Index: gcc/c-common.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.264
diff -u -r1.264 c-common.h
--- gcc/c-common.h	10 Sep 2004 23:56:18 -0000	1.264
+++ gcc/c-common.h	1 Oct 2004 20:22:32 -0000
@@ -92,7 +92,7 @@
   RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST,
 
   /* Objective-C */
-  RID_ID,          RID_AT_ENCODE,    RID_AT_END,
+  RID_AT_ENCODE,    RID_AT_END,
   RID_AT_CLASS,    RID_AT_ALIAS,     RID_AT_DEFS,
   RID_AT_PRIVATE,  RID_AT_PROTECTED, RID_AT_PUBLIC,
   RID_AT_PROTOCOL, RID_AT_SELECTOR,  
Index: gcc/c-parse.in
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/c-parse.in,v
retrieving revision 1.242
diff -u -r1.242 c-parse.in
--- gcc/c-parse.in	17 Sep 2004 18:17:59 -0000	1.242
+++ gcc/c-parse.in	1 Oct 2004 20:22:33 -0000
@@ -180,7 +180,7 @@
    Objective C, so that the token codes are the same in both.  */
 %token AT_INTERFACE AT_IMPLEMENTATION AT_END AT_SELECTOR AT_DEFS AT_ENCODE
 %token CLASSNAME AT_PUBLIC AT_PRIVATE AT_PROTECTED AT_PROTOCOL
-%token OBJECTNAME AT_CLASS AT_ALIAS
+%token AT_CLASS AT_ALIAS
 %token AT_THROW AT_TRY AT_CATCH AT_FINALLY AT_SYNCHRONIZED
 %token OBJC_STRING
 
@@ -261,7 +261,7 @@
 %type <ttype> selectorarg keywordnamelist keywordname objcencodeexpr
 %type <ttype> non_empty_protocolrefs protocolrefs identifier_list objcprotocolexpr
 
-%type <ttype> CLASSNAME OBJECTNAME OBJC_STRING OBJC_TYPE_QUAL
+%type <ttype> CLASSNAME OBJC_STRING OBJC_TYPE_QUAL
 
 %type <ttype> superclass objc_quals objc_qual objc_typename
 %type <itype> objc_try_catch_stmt optellipsis
@@ -474,7 +474,6 @@
 	IDENTIFIER
 	| TYPENAME
 @@ifobjc
-	| OBJECTNAME
 	| CLASSNAME
 @@end_ifobjc
 	;
@@ -1274,7 +1273,7 @@
 @@ifobjc
 	| CLASSNAME protocolrefs
 		{ $$ = objc_get_protocol_qualified_type ($1, $2); }
-	| OBJECTNAME protocolrefs
+	| TYPENAME non_empty_protocolrefs
 		{ $$ = objc_get_protocol_qualified_type ($1, $2); }
 
 /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>"
@@ -1549,10 +1548,6 @@
 		{ $$ = make_pointer_declarator ($2, $3); }
 	| TYPENAME
 		{ $$ = build_id_declarator ($1); }
-@@ifobjc
-	| OBJECTNAME
-		{ $$ = build_id_declarator ($1); }
-@@end_ifobjc
 	;
 
 /* Kinds of declarator that can appear in a parameter list
@@ -1571,10 +1566,6 @@
 		{ $$ = set_array_declarator_inner ($2, $1, false); }
 	| TYPENAME
 		{ $$ = build_id_declarator ($1); }
-@@ifobjc
-	| OBJECTNAME
-		{ $$ = build_id_declarator ($1); }
-@@end_ifobjc
 	;
 
 parm_declarator_nostarttypename:
@@ -2861,7 +2852,6 @@
 	  IDENTIFIER
 	| TYPENAME
 	| CLASSNAME
-	| OBJECTNAME
 	| reservedwords
 	;
 
@@ -3127,7 +3117,6 @@
   { "while",		RID_WHILE,	0 },
 
 @@ifobjc
-  { "id",		RID_ID,			D_OBJC },
 
   /* These objc keywords are recognized only immediately after
      an '@'.  */
@@ -3273,7 +3262,6 @@
   /* RID_STATCAST */	0,
 
   /* Objective C */
-  /* RID_ID */			OBJECTNAME,
   /* RID_AT_ENCODE */		AT_ENCODE,
   /* RID_AT_END */		AT_END,
   /* RID_AT_CLASS */		AT_CLASS,
@@ -3342,15 +3330,6 @@
       enum rid rid_code = C_RID_CODE (yylval.ttype);
 
 @@ifobjc
-      /* Turn non-typedefed refs to "id" into plain identifiers; this
-	 allows constructs like "void foo(id id);" to work.  */
-      if (rid_code == RID_ID)
-      {
-	decl = lookup_name (yylval.ttype);
-	if (decl == NULL_TREE || TREE_CODE (decl) != TYPE_DECL)
-	  return IDENTIFIER;
-      }
-
       if (!OBJC_IS_AT_KEYWORD (rid_code)
 	  && (!OBJC_IS_PQ_KEYWORD (rid_code) || objc_pq_context))
 @@end_ifobjc
@@ -3513,7 +3492,6 @@
     {
     case IDENTIFIER:
     case TYPENAME:
-    case OBJECTNAME:
     case TYPESPEC:
     case TYPE_QUAL:
     case SCSPEC:
Index: gcc/objc/objc-act.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.248
diff -u -r1.248 objc-act.c
--- gcc/objc/objc-act.c	24 Sep 2004 23:15:33 -0000	1.248
+++ gcc/objc/objc-act.c	1 Oct 2004 20:22:36 -0000
@@ -236,6 +236,7 @@
 static tree lookup_protocol (tree);
 static void check_protocol_recursively (tree, tree);
 static tree lookup_and_install_protocols (tree);
+static void mark_protocols_adopted_by_root_class (tree);
 
 /* Type encoding.  */
 
@@ -329,6 +330,8 @@
      ATTRIBUTE_NORETURN;
 static void mark_referenced_methods (void);
 static void generate_objc_image_info (void);
+static inline int objc_comptypes_proto_proto(tree lhs, tree rhs, 
+					     int reflexive);
 
 /*** Private Interface (data) ***/
 
@@ -606,12 +609,16 @@
 }
 \f
 /* Return the first occurrence of a method declaration corresponding
-   to sel_name in rproto_list.  Search rproto_list recursively.
-   If is_class is 0, search for instance methods, otherwise for class
-   methods.  */
+   to SEL_NAME in RPROTO_LIST.  Search RPROTO_LIST recursively.
+   If SEARCH_OPT is 0, search only for instance methods.
+   If SEARCH_OPT is 1, search only for class methods.
+   If SEARCH_OPT is 2, first search for class methods yet continue
+   to search for instance methods if no class method was found and
+   emit diagnostics.  */
+
 static tree
 lookup_method_in_protocol_list (tree rproto_list, tree sel_name,
-				int is_class)
+				int search_opt)
 {
    tree rproto, p;
    tree fnd = 0;
@@ -622,13 +629,23 @@
 
 	if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
 	  {
-	    if ((fnd = lookup_method (is_class
+	    if ((fnd = lookup_method (search_opt
 				      ? PROTOCOL_CLS_METHODS (p)
 				      : PROTOCOL_NST_METHODS (p), sel_name)))
 	      ;
+	    else if (search_opt == 2
+		     && PROTOCOL_ADOPTED_BY_ROOT_CLASS (p)
+		     && ((fnd = lookup_method (PROTOCOL_NST_METHODS (p),
+					       sel_name))))
+	      {
+		warning ("%<+%s%> not implemented by protocol(s) "
+			 "as class method", 
+			 IDENTIFIER_POINTER (sel_name));
+		warn_with_method ("using", '-', fnd);
+	      }
 	    else if (PROTOCOL_LIST (p))
 	      fnd = lookup_method_in_protocol_list (PROTOCOL_LIST (p),
-						    sel_name, is_class);
+						    sel_name, search_opt);
 	  }
 	else
           {
@@ -712,6 +729,41 @@
 objc_finish_interface (void)
 {
   finish_class (objc_interface_context);
+  if (TREE_CODE (objc_interface_context) == CLASS_INTERFACE_TYPE
+      && CLASS_PROTOCOL_LIST (objc_interface_context))
+    {
+      if (!CLASS_SUPER_NAME (objc_interface_context))
+	mark_protocols_adopted_by_root_class 
+	  (CLASS_PROTOCOL_LIST (objc_interface_context));
+    }
+  else if (TREE_CODE (objc_interface_context) == CATEGORY_INTERFACE_TYPE
+	   && CLASS_PROTOCOL_LIST (objc_interface_context))
+    {
+      tree class = lookup_interface (CLASS_NAME (objc_interface_context));
+
+      if (!CLASS_SUPER_NAME (class))
+	mark_protocols_adopted_by_root_class 
+	  (CLASS_PROTOCOL_LIST (objc_interface_context));
+    }
+  else if (TREE_CODE (objc_interface_context) == PROTOCOL_INTERFACE_TYPE
+	   && PROTOCOL_ADOPTED_BY_ROOT_CLASS (objc_interface_context))
+    {
+      tree protocol = objc_interface_context;
+      tree method_decl;
+
+      /* Since we do not have a protocol list,
+	 go ahead and register the method list directly.  */
+      for (method_decl = PROTOCOL_NST_METHODS (protocol);
+	   method_decl;
+	   method_decl = TREE_CHAIN (method_decl))
+	{
+	  add_method_to_hash_list(cls_method_hash_list, method_decl);
+	}
+
+      /* This protocol is marked.  Now mark all incorperated protocols.  */
+      mark_protocols_adopted_by_root_class (PROTOCOL_LIST (protocol));
+    }
+
   objc_interface_context = NULL_TREE;
 }
 
@@ -836,6 +888,83 @@
 }
 
 /* Return 1 if LHS and RHS are compatible types for assignment or
+   various other operations.  Return 0 if they are incompatible.
+   When the operation is REFLEXIVE (typically comparisons), check 
+   for compatibility in either direction; when it's not (typically 
+   assignments), don't.
+
+   This is a helper function for objc_comptypes to be able to test 
+   two protocol qualified types of the same basic type to insure 
+   protocol conformance and to emit the necessary warnings.  */
+
+static inline
+int objc_comptypes_proto_proto(tree lhs, tree rhs, int reflexive)
+{
+  tree lproto, lproto_list = TYPE_PROTOCOL_LIST (lhs);
+  tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs);
+  tree p;
+
+  gcc_assert((IS_ID (lhs) && IS_ID (rhs))
+	     || (IS_CLASS (lhs) && IS_CLASS (rhs)));
+
+  if (!reflexive)
+    {
+      /* An assignment between two objects both either of type 'id <Protocol>' 
+	 or both 'Class <Protocol>; make sure the protocol on the lhs is
+	 supported by the object on the rhs.  */
+      for (lproto = lproto_list; lproto;
+	   lproto = TREE_CHAIN (lproto))
+	{
+	  p = TREE_VALUE (lproto);
+	  rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+	  if (!rproto)
+	    warning
+	      ("%s does not conform to the `%s' protocol",
+	       IS_ID(lhs) ? "object" : "class",
+	       IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+	}
+      return 1;
+    }
+  else
+    {
+      /* Obscure case - a comparison between two objects either both
+	 of type 'id <Protocol>' or both 'Class <protocol>'.  Check 
+	 that either the protocol on the lhs is supported by the object on
+	 the rhs, or viceversa.  */
+
+      /* Check if the protocol on the lhs is supported by the
+	 object on the rhs.  */
+      for (lproto = lproto_list; lproto;
+	   lproto = TREE_CHAIN (lproto))
+	{
+	  p = TREE_VALUE (lproto);
+	  rproto = lookup_protocol_in_reflist (rproto_list, p);
+
+	  if (!rproto)
+	    {
+	      /* Check failed - check if the protocol on the rhs
+		 is supported by the object on the lhs.  */
+	      for (rproto = rproto_list; rproto;
+		   rproto = TREE_CHAIN (rproto))
+		{
+		  p = TREE_VALUE (rproto);
+		  lproto = lookup_protocol_in_reflist (lproto_list, p);
+
+		  if (!lproto)
+		    {
+		      /* This check failed too: incompatible  */
+		      return 0;
+		    }
+		}
+	      return 1;
+	    }
+	}
+      return 1;
+    }
+}
+
+/* Return 1 if LHS and RHS are compatible types for assignment or
    various other operations.  Return 0 if they are incompatible, and
    return -1 if we choose to not decide (because the types are really
    just C types, not ObjC specific ones).  When the operation is
@@ -866,76 +995,21 @@
       && TREE_CODE (rhs) == POINTER_TYPE
       && TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE)
     {
-      int lhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (lhs);
-      int rhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (rhs);
+      int lhs_is_proto_id = IS_ID (lhs) && TYPE_PROTOCOL_LIST (lhs);
+      int rhs_is_proto_id = IS_ID (rhs) && TYPE_PROTOCOL_LIST (rhs);
+      int lhs_is_proto_class = IS_CLASS (lhs) && TYPE_PROTOCOL_LIST (lhs);
+      int rhs_is_proto_class = IS_CLASS (rhs) && TYPE_PROTOCOL_LIST (rhs);
 
-      if (lhs_is_proto)
+      if (lhs_is_proto_id)
         {
 	  tree lproto, lproto_list = TYPE_PROTOCOL_LIST (lhs);
 	  tree rproto, rproto_list;
 	  tree p;
 
 	  /* <Protocol> = <Protocol>  */
-	  if (rhs_is_proto)
-	    {
-	      rproto_list = TYPE_PROTOCOL_LIST (rhs);
-
-	      if (!reflexive)
-		{
-		  /* An assignment between objects of type 'id
-		     <Protocol>'; make sure the protocol on the lhs is
-		     supported by the object on the rhs.  */
-		  for (lproto = lproto_list; lproto;
-		       lproto = TREE_CHAIN (lproto))
-		    {
-		      p = TREE_VALUE (lproto);
-		      rproto = lookup_protocol_in_reflist (rproto_list, p);
-
-		      if (!rproto)
-			warning
-			  ("object does not conform to the `%s' protocol",
-			   IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
-		    }
-		  return 1;
-		}
-	      else
-		{
-		  /* Obscure case - a comparison between two objects
-		     of type 'id <Protocol>'.  Check that either the
-		     protocol on the lhs is supported by the object on
-		     the rhs, or viceversa.  */
-
-		  /* Check if the protocol on the lhs is supported by the
-		     object on the rhs.  */
-		  for (lproto = lproto_list; lproto;
-		       lproto = TREE_CHAIN (lproto))
-		    {
-		      p = TREE_VALUE (lproto);
-		      rproto = lookup_protocol_in_reflist (rproto_list, p);
-
-		      if (!rproto)
-			{
-			  /* Check failed - check if the protocol on the rhs
-			     is supported by the object on the lhs.  */
-			  for (rproto = rproto_list; rproto;
-			       rproto = TREE_CHAIN (rproto))
-			    {
-			      p = TREE_VALUE (rproto);
-			      lproto = lookup_protocol_in_reflist (lproto_list,
-								   p);
+	  if (rhs_is_proto_id)
+	    return objc_comptypes_proto_proto (lhs, rhs, reflexive);
 
-			      if (!lproto)
-				{
-				  /* This check failed too: incompatible  */
-				  return 0;
-				}
-			    }
-			  return 1;
-			}
-		    }
-		  return 1;
-		}
-	    }
 	  /* <Protocol> = <class> *  */
 	  else if (TYPED_OBJECT (TREE_TYPE (rhs)))
 	    {
@@ -998,7 +1072,7 @@
 	  /* <Protocol> = ?? : let comptypes decide.  */
           return -1;
         }
-      else if (rhs_is_proto)
+      else if (rhs_is_proto_id)
 	{
 	  /* <class> * = <Protocol> */
 	  if (TYPED_OBJECT (TREE_TYPE (lhs)))
@@ -1078,6 +1152,46 @@
 	      return -1;
 	    }
 	}
+      else if (lhs_is_proto_class)
+	{
+	  /* Class <Protocol> = Class <Protocol>  */
+	  if (rhs_is_proto_class)
+	    return objc_comptypes_proto_proto (lhs, rhs, reflexive);
+
+	  /* Class <Protocol> = <class> *  */
+	  else if (TYPED_OBJECT (TREE_TYPE (rhs)))
+	    return 0;
+
+	  /* Class <Protocol> = Class */
+	  else if (objc_is_class_id (TREE_TYPE (rhs)))
+	    return 1;
+
+	  /* Class <Protocol> = id && Class <Protocol> = <Protocol> */
+	  else if (objc_is_object_id (TREE_TYPE (rhs)))
+	    return (rhs_is_proto_id ? 0 : 1);
+
+	  /* <Protocol> = ?? : let comptypes decide.  */
+	  else
+	    return -1;
+	}
+      else if (rhs_is_proto_class)
+	{
+	  /* <class> * = Class <Protocol> */
+	  if (TYPED_OBJECT (TREE_TYPE (lhs)))
+	    return 0;
+
+	  /* id = Class <Protocol> && <Protocol> = Class <Protocol> */
+	  else if (objc_is_object_id (TREE_TYPE (lhs)))
+	    return (lhs_is_proto_id ? 0 : 1);
+
+	  /* Class = Class <Protocol> */
+	  else if (objc_is_class_id (TREE_TYPE (lhs)))
+	    return 1;
+
+	  /* ??? = Class <Protocol> : let comptypes decide */
+	  else
+	    return -1;
+	}
       else
 	{
 	  /* Attention: we shouldn't defer to comptypes here.  One bad
@@ -1164,7 +1278,7 @@
 
 /* Construct a PROTOCOLS-qualified variant of INTERFACE, where INTERFACE may
    either name an Objective-C class, or refer to the special 'id' or 'Class'
-   types.  If INTERFACE is not a valid ObjC type, just return it unchanged.  */
+   types.  If INTERFACE is not a valid ObjC type, report error.  */
 
 tree
 objc_get_protocol_qualified_type (tree interface, tree protocols)
@@ -1180,7 +1294,10 @@
       if (type)
 	type = xref_tag (RECORD_TYPE, type);
       else
-        return interface;
+	{
+	  error ("protocol qualifiers specified for non-Objective-C type");
+	  return error_mark_node;
+	}
     }
 
   if (protocols)
@@ -1222,8 +1339,10 @@
     }
 }
 
-/* Look up PROTOCOLS, and return a list of those that are found.
-   If none are found, return NULL.  */
+/* Look up PROTOCOLS, a list of identifiers, and return the list
+   of the protocol interface declarations that are found.  Invokes error
+   for each identifier for which the lookup failed.
+   If PROTOCOLS is empty, return NULL.  */
 
 static tree
 lookup_and_install_protocols (tree protocols)
@@ -1247,6 +1366,44 @@
   return return_value;
 }
 
+/* Iterates over the protocol interface list RPROTOS marking each as
+   PROTOCOL_ADOPTED_BY_ROOT_CLASS.  Registers the instance methods 
+   prototypes of each protocol and their incorperated protocols recursively
+   as potential class methods.  */
+
+static void
+mark_protocols_adopted_by_root_class (tree rprotos)
+{
+  tree protocol_ch;
+  tree protocol;
+
+  for (protocol_ch = rprotos;
+       protocol_ch;
+       protocol_ch = TREE_CHAIN (protocol_ch))
+    {
+      protocol = TREE_CHECK(TREE_VALUE (protocol_ch),
+			    PROTOCOL_INTERFACE_TYPE);
+
+      /* Minor efficiency check.  Expect all protocols which have
+	 been previously marked, to have had their methods registered.  */
+      if (!PROTOCOL_ADOPTED_BY_ROOT_CLASS (protocol))
+	{
+	  tree method_decl;
+
+	  for (method_decl = PROTOCOL_NST_METHODS (protocol);
+	       method_decl;
+	       method_decl = TREE_CHAIN (method_decl))
+	    {
+	      add_method_to_hash_list(cls_method_hash_list, method_decl);
+	    }
+	}
+
+      PROTOCOL_ADOPTED_BY_ROOT_CLASS (protocol) = 1;
+
+      mark_protocols_adopted_by_root_class (PROTOCOL_LIST (protocol));
+    }
+}
+
 /* Create a declaration for field NAME of a given TYPE.  */
 
 static tree
@@ -5570,13 +5727,18 @@
       else
 	{
 	  class_tree = objc_class_name;
-	  OBJC_SET_TYPE_NAME (rtype, class_tree);
+	  
+	  rprotos = TYPE_PROTOCOL_LIST (rtype);
+	  rtype = NULL_TREE;
 	}
 
+      /* Search in protocols for 'id' and 'Class'.  */
       if (rprotos)
 	method_prototype
 	  = lookup_method_in_protocol_list (rprotos, sel_name,
-					    class_tree != NULL_TREE);
+					    class_tree != NULL_TREE ? 2 : 0);
+
+      /* Search in global tables for 'id' and 'Class'.  */
       if (!method_prototype && !rprotos)
 	method_prototype
 	  = lookup_method_in_hash_lists (sel_name,
@@ -5631,7 +5793,8 @@
 	  if (!method_prototype && rprotos)
 	    method_prototype
 	      = lookup_method_in_protocol_list (rprotos, sel_name,
-						class_tree != NULL_TREE);
+						class_tree != NULL_TREE 
+						? 1 : 0);
 	}
       else
 	{
@@ -5650,10 +5813,19 @@
 		 IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)),
 		 (class_tree ? '+' : '-'),
 		 IDENTIFIER_POINTER (sel_name));
+      /* If we are messaging an unadorned 'id' or 'Class' object,
+         then we have failed to find _any_ instance or class method,
+         respectively.  */
+      else if (!rprotos)
+        warning ("no `%c%s' method found",
+                 (class_tree ? '+' : '-'),
+                 IDENTIFIER_POINTER (sel_name));
+
       if (rprotos)
 	warning ("`%c%s' not implemented by protocol(s)",
 		 (class_tree ? '+' : '-'),
 		 IDENTIFIER_POINTER (sel_name));
+
       if (!warn_missing_methods)
 	{
 	  warning ("(Messages without a matching method signature");
@@ -6062,7 +6234,8 @@
 	  if (CLASS_PROTOCOL_LIST (category))
 	    {
 	      if ((meth = (lookup_method_in_protocol_list
-			   (CLASS_PROTOCOL_LIST (category), ident, is_class))))
+			   (CLASS_PROTOCOL_LIST (category),
+			    ident, is_class ? 1 : 0))))
 		return meth;
 	    }
 	}
@@ -6071,7 +6244,8 @@
       if (CLASS_PROTOCOL_LIST (inter))
 	{
 	  if ((meth = (lookup_method_in_protocol_list
-		       (CLASS_PROTOCOL_LIST (inter), ident, is_class))))
+		       (CLASS_PROTOCOL_LIST (inter), 
+			ident, is_class ? 1 : 0))))
 	    return meth;
 	}
 
Index: gcc/objc/objc-act.h
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/objc/objc-act.h,v
retrieving revision 1.31
diff -u -r1.31 objc-act.h
--- gcc/objc/objc-act.h	22 Sep 2004 01:13:07 -0000	1.31
+++ gcc/objc/objc-act.h	1 Oct 2004 20:22:37 -0000
@@ -37,6 +37,14 @@
 #define CLASS_LANG_SLOT_ELTS		5
 #define PROTOCOL_LANG_SLOT_ELTS		2
 
+/*
+  Objective-C usage for TREE_LANG_FLAG_?:
+
+  0: PROTOCOL_ADOPTED_BY_ROOT_CLASS - (valid for PROTOCOL_INTERFACE_TYPE)
+     Marks protocol declarations that are adopted by root classes
+     so that instance methods are also checked for Class references.
+*/
+
 /* KEYWORD_DECL */
 #define KEYWORD_KEY_NAME(DECL) ((DECL)->decl.name)
 #define KEYWORD_ARG_NAME(DECL) ((DECL)->decl.arguments)
@@ -66,6 +74,7 @@
 #define PROTOCOL_CLS_METHODS(CLASS) ((CLASS)->type.maxval)
 #define PROTOCOL_FORWARD_DECL(CLASS) TREE_VEC_ELT (TYPE_LANG_SLOT_1 (CLASS), 1)
 #define PROTOCOL_DEFINED(CLASS) TREE_USED (CLASS)
+#define PROTOCOL_ADOPTED_BY_ROOT_CLASS(CLASS) TREE_LANG_FLAG_0 (CLASS)
 
 /* We need to distinguish TYPE_PROTOCOL_LISTs from TYPE_CONTEXTs, both of which
    are stored in the same accessor slot.  */
@@ -277,8 +286,6 @@
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == TREE_TYPE (objc_object_type))
 #define IS_CLASS(TYPE) \
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == TREE_TYPE (objc_class_type))
-#define IS_PROTOCOL_QUALIFIED_ID(TYPE) \
-  (IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE))
 #define IS_SUPER(TYPE) \
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == objc_super_template)
 

[-- Attachment #6: class-protocol-1.m --]
[-- Type: text/plain, Size: 8079 bytes --]

/* Check Class <protocol> types */
/* Author: David Ayers <d.ayers@inode.at> */
/* { dg-do compile } */

#include <objc/objc.h>
#include <objc/objc-api.h>

@protocol MyProto1
+(void)doItClass1;
-(void)doItInstance1; /* { dg-warning "using" } */
@end

@protocol MyProto2
+(void)doItClass2;
-(void)doItInstance2;
@end

@interface MyClass1 <MyProto1>
{
  Class isa;
}
@end
@implementation MyClass1
+(void)doItClass1{}
-(void)doItInstance1{}
@end

@interface MyClass2 : MyClass1 <MyProto2>
@end
@implementation MyClass2
+(void)doItClass2{}
-(void)doItInstance2{}
@end

@interface MyClass3
{
  Class isa;
}
@end
@interface MyClass4 : MyClass3 <MyProto1>
@end

/*----------------------------------------*/

Class cls = 0;
Class <MyProto1> clsP1 = 0;
Class <MyProto2> clsP2 = 0;

void
testSimple(void)
{
  [cls doItClass1];
  [cls doItInstance1]; /* Do not warn as root Class declares this.  */
  [cls doItClass2];
  [cls doItInstance2]; /* { dg-warning "no .+doItInstance2. method" } */

  [clsP1 doItClass1];
  [clsP1 doItInstance1]; /* { dg-warning "as class method" }  */
  [clsP1 doItClass2];    /* { dg-warning "not implemented by protocol" } */
  [clsP1 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [clsP2 doItClass1];    /* { dg-warning "not implemented by protocol" } */
  [clsP2 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
  [clsP2 doItClass2];
  [clsP2 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass1];
  [MyClass1 doItInstance1];
  [MyClass1 doItClass2];    /* { dg-warning "may not respond to" } */
  [MyClass1 doItInstance2]; /* { dg-warning "may not respond to" } */

  [MyClass2 doItClass1];
  [MyClass2 doItInstance1];
  [MyClass2 doItClass2];
  [MyClass2 doItInstance2]; /* { dg-warning "may not respond to" } */

  [MyClass3 doItClass1];    /* { dg-warning "may not respond to" } */
  [MyClass3 doItInstance1]; /* { dg-warning "may not respond to" } */

  [MyClass4 doItClass1];    
  [MyClass4 doItInstance1]; /* { dg-warning "may not respond to" } */

}

/*----------------------------------------*/
/* Protocols declared by categories */

@protocol MyProto3
+(void)doItClass3;
-(void)doItInstance3;
@end
@protocol MyProto4
+(void)doItClass4;
-(void)doItInstance4;
@end

@interface MyClass1 (Category1) <MyProto3>
@end
@interface MyClass2 (Category2) <MyProto4>
@end

void
testCategory(void)
{
  [cls doItClass3];
  [cls doItInstance3];      /* Do not warn as root Class declares this.  */
  [cls doItClass4];
  [cls doItInstance4];      /* { dg-warning "no .+doItInstance4. method" } */

  [MyClass1 doItClass3];
  [MyClass1 doItInstance3];
  [MyClass1 doItClass4];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance4]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass3];
  [MyClass2 doItInstance3];
  [MyClass2 doItClass4];
  [MyClass2 doItInstance4]; /* { dg-warning "may not respond" } */

}

/*----------------------------------------*/
/* Incorperated protocols declared by categories */

@protocol MyProto5 <MyProto1>
+(void)doItClass5;
-(void)doItInstance5;
@end

@protocol MyProto6 <MyProto2>
+(void)doItClass6;
-(void)doItInstance6;
@end

@interface MyClass1 (Category3) <MyProto5>
@end
@interface MyClass2 (Category4) <MyProto6>
@end

Class <MyProto5> clsP5 = 0;
Class <MyProto6> clsP6 = 0;

void
testCategoryIncorporated(void)
{
  [cls doItClass5];
  [cls doItInstance5]; /* Do not warn as root Class declares this.  */
  [cls doItClass6];
  [cls doItInstance6]; /* { dg-warning "no .+doItInstance6. method" } */

  [clsP5 doItClass1];
  [clsP5 doItInstance1]; /* { dg-warning "as class method" }  */
  [clsP5 doItClass2];    /* { dg-warning "not implemented by protocol" } */
  [clsP5 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [clsP6 doItClass1];    /* { dg-warning "not implemented by protocol" } */
  [clsP6 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
  [clsP6 doItClass2];
  [clsP6 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass5];
  [MyClass1 doItInstance5]; /* Do not warn as root Class declares this.  */
  [MyClass1 doItClass6];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance6]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass5];
  [MyClass2 doItInstance5]; /* Do not warn as root Class declares this.  */
  [MyClass2 doItClass6];
  [MyClass2 doItInstance6]; /* { dg-warning "may not respond" } */

}

/*----------------------------------------*/
/* Forward declared root protocols */

@protocol FwProto;

@interface MyClass1 (Forward) <FwProto>
@end

Class <FwProto> clsP7 = 0;

void
testForwardeDeclared1(void)
{
  [cls doItClass7];         /* { dg-warning "no .+doItClass7. method" } */
  [cls doItInstance7];      /* { dg-warning "no .+doItInstance7. method" } */

  [clsP7 doItClass7];       /* { dg-warning "not implemented by protocol" } */
  [clsP7 doItInstance7];    /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass7];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance7]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass7];    /* { dg-warning "may not respond" } */
  [MyClass2 doItInstance7]; /* { dg-warning "may not respond" } */

}

@protocol FwProto
+(void)doItClass7;
-(void)doItInstance7; /* { dg-warning "using" } */
@end

void
testForwardeDeclared2(void)
{
  [cls doItClass7];
  [cls doItInstance7];   /* Do not warn as root Class declares this.  */

  [clsP7 doItClass7];    
  [clsP7 doItInstance7]; /* { dg-warning "as class method" } */

  [MyClass1 doItClass7];
  [MyClass1 doItInstance7];

  [MyClass2 doItClass7];
  [MyClass2 doItInstance7];

}

/*----------------------------------------*/
/* Incorperated non root protocols */

@protocol MyProto8
+(void)doItClass8;
-(void)doItInstance8; /* { dg-warning "using" } */
@end

@protocol MyProto9 <MyProto8>
+(void)doItClass9;
-(void)doItInstance9; /* { dg-warning "using" } */
@end

@interface MyClass1 (IncorporatedNonRoot) <MyProto9>
@end

Class <MyProto8> clsP8 = 0;
Class <MyProto9> clsP9 = 0;

void
testIncorporatedNonRoot(void)
{
  [cls doItClass8];
  [cls doItInstance8]; /* Do not warn as root Class declares super.  */
  [cls doItClass9];
  [cls doItInstance9]; /* Do not warn as root Class declares this.  */

  [clsP8 doItClass8];
  [clsP8 doItInstance8]; /* { dg-warning "as class method" } debatable */
  [clsP8 doItClass9];    /* { dg-warning "not implemented by protocol" } */
  [clsP8 doItInstance9]; /* { dg-warning "not implemented by protocol" } */

  [clsP9 doItClass8];
  [clsP9 doItInstance8]; /* { dg-warning "as class method" } */
  [clsP9 doItClass9];
  [clsP9 doItInstance9]; /* { dg-warning "as class method" } */

  [MyClass1 doItClass8];
  [MyClass1 doItInstance8]; /* Do not warn as root Class declares this.  */
  [MyClass1 doItClass9];
  [MyClass1 doItInstance9];

  [MyClass2 doItClass8];
  [MyClass2 doItInstance8]; /* Do not warn as root Class declares this.  */
  [MyClass2 doItClass9];
  [MyClass2 doItInstance9];
  
}

id obj = nil;
id <MyProto1> objP1 = nil;
id <MyProto2> objP2 = nil;

MyClass1 *mc1 = nil;

void
testComptypes(void)
{
  cls == clsP1;
  clsP1 == cls;

  cls == objP1; /* { dg-warning "lacks a cast" } */
  objP1 == cls; /* { dg-warning "lacks a cast" } */

  clsP1 == clsP5;
  clsP5 == clsP1;

  mc1 == clsP1; /* { dg-warning "lacks a cast" } */
  clsP1 == mc1; /* { dg-warning "lacks a cast" } */


  cls = clsP1; 
  clsP1 = cls;

  cls = objP1; /* { dg-warning "incompatible" } */
  objP1 = cls; /* { dg-warning "incompatible" } */

  clsP1 = clsP5;
  clsP5 = clsP1; /* { dg-warning "does not conform" } */

  mc1 = clsP1; /* { dg-warning "incompatible" } */
  clsP1 = mc1; /* { dg-warning "incompatible" } */

}

int main ()
{
  testSimple();
  testCategory();
  testCategoryIncorporated();
  return(0);
}

/* { dg-warning "Messages without a matching" "" { target *-*-* } 0 } */
/* { dg-warning "will be assumed to return" "" { target *-*-* } 0 } */
/* { dg-warning "as arguments" "" { target *-*-* } 0 } */


[-- Attachment #7: patch.tar.gz --]
[-- Type: application/x-gunzip, Size: 7949 bytes --]

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-01 20:50                             ` David Ayers
@ 2004-10-02 17:35                               ` David Ayers
  2004-10-04 19:51                                 ` Ziemowit Laski
  0 siblings, 1 reply; 35+ messages in thread
From: David Ayers @ 2004-10-02 17:35 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc-patches

David Ayers wrote:
> 
>> If you need more explanations, I'll have to ask you be a little patient,
>> and I'll try to summarize the patch again.  Otherwise, I'd be glad to
>> know what you think.

So here is the overview of this patch:

http://gcc.gnu.org/ml/gcc-patches/2004-10/msg00084.html

It implements protocol qualified 'Class' reference for Objective-C.

It changes the formal grammar by removing the 'id' keyword which was 
used for the type specifier:

  id [ protocol-reference-list ]

and changes this type specifier to:

  typedef-name [ protocol-reference-list ]

yet the code asserts that the provided typedef-name corresponds to 
either 'id' or 'Class'.  This change also allows us to remove a 
workaround for the cases that 'id' actually corresponded to a 
non-typedef identifier: (i.e. void foo (id id);)

lookup_method_protocol_in_list now takes either 0, 1 or 2 as the search 
flag.  This function searches the provided protocol list for the 
selector.  The search option 0 indicates that only instance methods are 
searched, 1 only class methods and 2 class methods and instance methods 
of protocols that have been adopted by root classes, but the class 
methods take precedence.  When the search is done with 2 it first 
searches the class methods, just like option 1, yet if none is found it 
continues to search for instance methods in protocols which have been 
marked as declared by a root class.  If a match is found, it emits the 
proposed diagnostics that the class method prototype wasn't found, yet 
it will use the instance methods prototype.  Even though there is only 
one call site which explicitly uses 2 as the search option, this 
mechanism cannot be special cased there as l_m_p_i_l calls itself 
recursively with the current search option.

-> Note: This new warning implies that protocols like <NSObject> should 
repeat their instance method declarations as class methods to avoid this 
warning.  This also implies that when root classes adopt such protocols, 
the the compiler should not warn about the class variants not being 
implemented if instance variants are.  I think we should leave this 
until after this patch though.

objc_finish_interface has been adapted to call the new 
mark_protocols_adopted_by_root_class function to mark protocols which 
will be considered by lookup_method_protocol_in_list so that the 
fallback mechanism to instance prototypes is not unduly invoked.  For 
marked protocols which where previously merely forward declared, we 
register the incorporated/inherited protocols.  We also register the 
instance methods of the marked protocol directly with the global class 
method list to avoid creating a method list merely to call 
mark_protocols_adopted_by_root_class for the current protocol.

static void
mark_protocols_adopted_by_root_class (tree rprotos)
/* Iterates over the protocol interface list RPROTOS marking each as
    PROTOCOL_ADOPTED_BY_ROOT_CLASS.  Registers the instance methods
    prototypes of each protocol and their incorporated protocols
    recursively as potential class methods.  */


-> Note: I'm aware that you mentioned that you do not believe this is 
necessary, but after considering that this will allow us to better 
differentiate the diagnostics for categories on root classes like 
NSObject, also considering that few of the "root class categories" 
currently repeat their instance methods as class methods and considering 
the maintenance and processing overhead which I find minimal, I think it 
is legitimate.  If you feel very strongly about it, I would remove this 
and do the extra lookup in lookup_method_protocol_in_list independent of 
whether a protocol is adopted by a root class.

objc_comptypes has been adapted to handle protocol qualified 'Class' 
type.  For comments about the structure of the previous and new 
implementation, may I refer you to about the middle of:

http://gcc.gnu.org/ml/gcc-patches/2004-09/msg03022.html

I hope that this shows that extracting the protocol comparison into the new:

static inline
int objc_comptypes_proto_proto(tree lhs, tree rhs, int reflexive)
  /* Return 1 if LHS and RHS are compatible types for assignment or
     various other operations.  Return 0 if they are incompatible.
     When the operation is REFLEXIVE (typically comparisons), check
     for compatibility in either direction; when it's not (typically
     assignments), don't.

     This is a helper function for objc_comptypes to be able to test
     two protocol qualified types of the same basic type to insure
     protocol conformance and to emit the necessary warnings.  */

is the least invasive approach to objc_comptypes.

-> Note: Please let me know if you agree or whether the structure I 
think you wanted is indeed what you are looking for and I'll add the 
special case handling inline.
Yet if you agree with this structure then please indicate whether you'd 
prefer me to:
a) remove the IS_PROTOCOL_QUALIFIED_ID macro
b) add a IS_PROTOCOL_QUALIFIED_CLASS macro
c) leave the IS_PROTOCOL_QUALIFIED_ID macro untouched and handle 
IS_PROTOCOL_QUALIFIED_CLASS 'inline'
d) replace IS_PROTOCOL_QUALIFIED_ID by IS_PROTOCOL_QUALIFIED_UNTYPED and 
add extra IS_ID, IS_CLASS tests 'inline'.

objc_finish_method_expr has been adapted to handle protocol qualified 
'Class' types.  As you requested, the hack to process 'Class' as a named 
class has been removed and it emits a new diagnostic "no '%c%s' method 
found" when no appropriate prototype has been found.  It calls 
lookup_method_protocol_in_list with search option '2' for protocol 
qualified 'Class' references.  The other calls to 
lookup_method_protocol_in_list have been updated to make the search flag 
explicit.

lookup_method_static has been updated to make the search flag used for 
calls to lookup_method_protocol_in_list explicit.

In some cases I've used the word 'incorporate' instead of 'inheritance' 
with respect to protocols as I'm still partial to that word now.  If you 
feel strongly about it, I will revert that.

I offer to follow up with the identifier/naming cleanup to:

s/reflexive/symmetric/g
s/implemented by protocol/declared by protocol/g
insure that lhs and rhs identifier in objc_comptypes(_proto_proto) are 
properly named.

After the branch we can go for the following issues:

- ensure that the warning "does not fully implement the '%s' protocol" 
is not emitted for class methods of a protocol in a root class when an 
instance variant is implemented.
- have digest_init call objc_comptypes to emit diagnostics.
- cleanup digest_init to respect lhs/rhs when calling comptypes.
- make protocol qualified types their own true types
- cleanup objc_comptypes as needed
- reactivate Alexander Malmberg's patch wrt tracking conflicting prototypes
- adding objc support to the pretty printer functions (well maybe this 
should be moved up to ease doing the others :-) )

How does that sound?

Cheers,
David

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-02 17:35                               ` David Ayers
@ 2004-10-04 19:51                                 ` Ziemowit Laski
  2004-10-05  3:13                                   ` Ziemowit Laski
  0 siblings, 1 reply; 35+ messages in thread
From: Ziemowit Laski @ 2004-10-04 19:51 UTC (permalink / raw)
  To: David Ayers; +Cc: gcc-patches

Hey David,

Thanks for your write-up.  I will read through it as I finalize my 
"alternative" patch, which I'm doing presently, and which I'll send to 
you along with additional comments.

Thanks for your patience :-),

--Zem

--------------------------------------------------------------
Ziemowit Laski                 1 Infinite Loop, MS 301-2K
Mac OS X Compiler Group        Cupertino, CA USA  95014-2083
Apple Computer, Inc.           +1.408.974.6229  Fax .5477

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-04 19:51                                 ` Ziemowit Laski
@ 2004-10-05  3:13                                   ` Ziemowit Laski
  2004-10-05 16:37                                     ` David Ayers
  0 siblings, 1 reply; 35+ messages in thread
From: Ziemowit Laski @ 2004-10-05  3:13 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc-patches, David Ayers

[-- Attachment #1: Type: text/plain, Size: 224 bytes --]

Took me longer than expected, but here is the alternative patch I 
promised; no ChangeLog entries for now.  It's running a bit late, so 
I'll defer my commentary until tomorrow. :-(  As always, feedback is 
welcome.

--Zem


[-- Attachment #2: objc.diff.20041004.txt --]
[-- Type: text/plain, Size: 18583 bytes --]

? gcc/testsuite/objc.dg/class-protocol-1.s
? gcc/testsuite/objc.dg/desig-init-1.s
? gcc/testsuite/objc.dg/method-5.s
? gcc/testsuite/objc.dg/method-6.s
Index: gcc/c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.265
diff -u -3 -p -r1.265 c-common.h
--- gcc/c-common.h	3 Oct 2004 20:53:00 -0000	1.265
+++ gcc/c-common.h	5 Oct 2004 02:17:28 -0000
@@ -92,7 +92,7 @@ enum rid
   RID_CONSTCAST, RID_DYNCAST, RID_REINTCAST, RID_STATCAST,
 
   /* Objective-C */
-  RID_ID,          RID_AT_ENCODE,    RID_AT_END,
+  RID_AT_ENCODE,   RID_AT_END,
   RID_AT_CLASS,    RID_AT_ALIAS,     RID_AT_DEFS,
   RID_AT_PRIVATE,  RID_AT_PROTECTED, RID_AT_PUBLIC,
   RID_AT_PROTOCOL, RID_AT_SELECTOR,  
Index: gcc/c-parse.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-parse.in,v
retrieving revision 1.244
diff -u -3 -p -r1.244 c-parse.in
--- gcc/c-parse.in	3 Oct 2004 20:53:04 -0000	1.244
+++ gcc/c-parse.in	5 Oct 2004 02:17:30 -0000
@@ -180,7 +180,7 @@ do {									\
    Objective C, so that the token codes are the same in both.  */
 %token AT_INTERFACE AT_IMPLEMENTATION AT_END AT_SELECTOR AT_DEFS AT_ENCODE
 %token CLASSNAME AT_PUBLIC AT_PRIVATE AT_PROTECTED AT_PROTOCOL
-%token OBJECTNAME AT_CLASS AT_ALIAS
+%token AT_CLASS AT_ALIAS
 %token AT_THROW AT_TRY AT_CATCH AT_FINALLY AT_SYNCHRONIZED
 %token OBJC_STRING
 
@@ -261,7 +261,7 @@ do {									\
 %type <ttype> selectorarg keywordnamelist keywordname objcencodeexpr
 %type <ttype> non_empty_protocolrefs protocolrefs identifier_list objcprotocolexpr
 
-%type <ttype> CLASSNAME OBJECTNAME OBJC_STRING OBJC_TYPE_QUAL
+%type <ttype> CLASSNAME OBJC_STRING OBJC_TYPE_QUAL
 
 %type <ttype> superclass objc_quals objc_qual objc_typename
 %type <itype> objc_try_catch_stmt optellipsis
@@ -474,7 +474,6 @@ identifier:
 	IDENTIFIER
 	| TYPENAME
 @@ifobjc
-	| OBJECTNAME
 	| CLASSNAME
 @@end_ifobjc
 	;
@@ -1279,7 +1278,7 @@ typespec_nonreserved_nonattr:
 @@ifobjc
 	| CLASSNAME protocolrefs
 		{ $$ = objc_get_protocol_qualified_type ($1, $2); }
-	| OBJECTNAME protocolrefs
+	| TYPENAME non_empty_protocolrefs
 		{ $$ = objc_get_protocol_qualified_type ($1, $2); }
 
 /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>"
@@ -1554,10 +1553,6 @@ after_type_declarator:
 		{ $$ = make_pointer_declarator ($2, $3); }
 	| TYPENAME
 		{ $$ = build_id_declarator ($1); }
-@@ifobjc
-	| OBJECTNAME
-		{ $$ = build_id_declarator ($1); }
-@@end_ifobjc
 	;
 
 /* Kinds of declarator that can appear in a parameter list
@@ -1576,10 +1571,6 @@ parm_declarator_starttypename:
 		{ $$ = set_array_declarator_inner ($2, $1, false); }
 	| TYPENAME
 		{ $$ = build_id_declarator ($1); }
-@@ifobjc
-	| OBJECTNAME
-		{ $$ = build_id_declarator ($1); }
-@@end_ifobjc
 	;
 
 parm_declarator_nostarttypename:
@@ -2866,7 +2857,6 @@ selector:
 	  IDENTIFIER
 	| TYPENAME
 	| CLASSNAME
-	| OBJECTNAME
 	| reservedwords
 	;
 
@@ -3132,7 +3122,6 @@ static const struct resword reswords[] =
   { "while",		RID_WHILE,	0 },
 
 @@ifobjc
-  { "id",		RID_ID,			D_OBJC },
 
   /* These objc keywords are recognized only immediately after
      an '@'.  */
@@ -3278,7 +3267,6 @@ static const short rid_to_yy[RID_MAX] =
   /* RID_STATCAST */	0,
 
   /* Objective C */
-  /* RID_ID */			OBJECTNAME,
   /* RID_AT_ENCODE */		AT_ENCODE,
   /* RID_AT_END */		AT_END,
   /* RID_AT_CLASS */		AT_CLASS,
@@ -3347,15 +3335,6 @@ yylexname (void)
       enum rid rid_code = C_RID_CODE (yylval.ttype);
 
 @@ifobjc
-      /* Turn non-typedefed refs to "id" into plain identifiers; this
-	 allows constructs like "void foo(id id);" to work.  */
-      if (rid_code == RID_ID)
-      {
-	decl = lookup_name (yylval.ttype);
-	if (decl == NULL_TREE || TREE_CODE (decl) != TYPE_DECL)
-	  return IDENTIFIER;
-      }
-
       if (!OBJC_IS_AT_KEYWORD (rid_code)
 	  && (!OBJC_IS_PQ_KEYWORD (rid_code) || objc_pq_context))
 @@end_ifobjc
@@ -3518,7 +3497,6 @@ yyprint (FILE *file, int yychar, YYSTYPE
     {
     case IDENTIFIER:
     case TYPENAME:
-    case OBJECTNAME:
     case TYPESPEC:
     case TYPE_QUAL:
     case SCSPEC:
Index: gcc/objc/objc-act.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.249
diff -u -3 -p -r1.249 objc-act.c
--- gcc/objc/objc-act.c	2 Oct 2004 15:56:06 -0000	1.249
+++ gcc/objc/objc-act.c	5 Oct 2004 02:17:38 -0000
@@ -866,8 +866,8 @@ objc_comptypes (tree lhs, tree rhs, int 
       && TREE_CODE (rhs) == POINTER_TYPE
       && TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE)
     {
-      int lhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (lhs);
-      int rhs_is_proto = IS_PROTOCOL_QUALIFIED_ID (rhs);
+      int lhs_is_proto = IS_PROTOCOL_QUALIFIED_UNTYPED (lhs);
+      int rhs_is_proto = IS_PROTOCOL_QUALIFIED_UNTYPED (rhs);
 
       if (lhs_is_proto)
         {
@@ -942,6 +942,10 @@ objc_comptypes (tree lhs, tree rhs, int 
 	      tree rname = OBJC_TYPE_NAME (TREE_TYPE (rhs));
 	      tree rinter;
 
+	      /* Class <Protocol> != <class> *  */
+	      if (IS_CLASS (lhs))
+		return 0;
+
 	      /* Make sure the protocol is supported by the object on
 		 the rhs.  */
 	      for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto))
@@ -985,15 +989,15 @@ objc_comptypes (tree lhs, tree rhs, int 
 		}
 	      return 1;
 	    }
-	  /* <Protocol> = id */
+	  /* id <Protocol> = id; Class <Protocol> != id */
 	  else if (objc_is_object_id (TREE_TYPE (rhs)))
 	    {
-	      return 1;
+	      return IS_ID (lhs);
 	    }
-	  /* <Protocol> = Class */
+	  /* id <Protocol> != Class; Class <Protocol> = Class */
 	  else if (objc_is_class_id (TREE_TYPE (rhs)))
 	    {
-	      return 0;
+	      return IS_CLASS (lhs);
 	    }
 	  /* <Protocol> = ?? : let comptypes decide.  */
           return -1;
@@ -1003,6 +1007,10 @@ objc_comptypes (tree lhs, tree rhs, int 
 	  /* <class> * = <Protocol> */
 	  if (TYPED_OBJECT (TREE_TYPE (lhs)))
 	    {
+	      /* <class> * != Class <Protocol> */
+	      if (IS_CLASS (rhs))
+		return 0;
+
 	      if (reflexive)
 		{
 		  tree rname = OBJC_TYPE_NAME (TREE_TYPE (lhs));
@@ -1062,15 +1070,15 @@ objc_comptypes (tree lhs, tree rhs, int 
 	      else
 		return 0;
 	    }
-	  /* id = <Protocol> */
+	  /* id = id <Protocol>; id != Class <Protocol> */
 	  else if (objc_is_object_id (TREE_TYPE (lhs)))
 	    {
-	      return 1;
+	      return IS_ID (rhs);
 	    }
-	  /* Class = <Protocol> */
+	  /* Class != id <Protocol>; Class = Class <Protocol> */
 	  else if (objc_is_class_id (TREE_TYPE (lhs)))
 	    {
-	      return 0;
+	      return IS_CLASS (rhs);
 	    }
 	  /* ??? = <Protocol> : let comptypes decide */
 	  else
@@ -5570,7 +5578,8 @@ objc_finish_message_expr (tree receiver,
       else
 	{
 	  class_tree = objc_class_name;
-	  OBJC_SET_TYPE_NAME (rtype, class_tree);
+	  rprotos = TYPE_PROTOCOL_LIST (rtype);
+	  rtype = NULL_TREE;
 	}
 
       if (rprotos)
@@ -5637,23 +5646,36 @@ objc_finish_message_expr (tree receiver,
 	{
 	  warning ("invalid receiver type `%s'",
 		   gen_type_name (orig_rtype));
-	  rtype = rprotos = NULL_TREE;
+	  rtype = error_mark_node;
+	  rprotos = NULL_TREE;
 	}
-    }	
+    }
 
   if (!method_prototype)
     {
       static bool warn_missing_methods = false;
 
-      if (rtype)
-	warning ("`%s' may not respond to `%c%s'",
-		 IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)),
-		 (class_tree ? '+' : '-'),
-		 IDENTIFIER_POINTER (sel_name));
-      if (rprotos)
-	warning ("`%c%s' not implemented by protocol(s)",
-		 (class_tree ? '+' : '-'),
-		 IDENTIFIER_POINTER (sel_name));
+      if (rtype != error_mark_node)
+	{
+	  if (rtype)
+	    warning ("`%s' may not respond to `%c%s'",
+		     IDENTIFIER_POINTER (OBJC_TYPE_NAME (rtype)),
+		     (class_tree ? '+' : '-'),
+		     IDENTIFIER_POINTER (sel_name));
+	    /* If we are messaging an unadorned 'id' or 'Class'
+	       object, then we have failed to find _any_ instance
+	       or class method, respectively.  */
+	  else if (!rprotos)
+	    warning ("no `%c%s' method found",
+		     (class_tree ? '+' : '-'),
+		     IDENTIFIER_POINTER (sel_name));
+
+	  if (rprotos)
+	    warning ("`%c%s' not implemented by protocol(s)",
+		     (class_tree ? '+' : '-'),
+		     IDENTIFIER_POINTER (sel_name));
+	}
+
       if (!warn_missing_methods)
 	{
 	  warning ("(Messages without a matching method signature");
Index: gcc/objc/objc-act.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.h,v
retrieving revision 1.31
diff -u -3 -p -r1.31 objc-act.h
--- gcc/objc/objc-act.h	22 Sep 2004 01:13:07 -0000	1.31
+++ gcc/objc/objc-act.h	5 Oct 2004 02:17:38 -0000
@@ -277,8 +277,8 @@ extern GTY(()) tree objc_global_trees[OC
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == TREE_TYPE (objc_object_type))
 #define IS_CLASS(TYPE) \
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == TREE_TYPE (objc_class_type))
-#define IS_PROTOCOL_QUALIFIED_ID(TYPE) \
-  (IS_ID (TYPE) && TYPE_PROTOCOL_LIST (TYPE))
+#define IS_PROTOCOL_QUALIFIED_UNTYPED(TYPE) \
+  ((IS_ID (TYPE) || IS_CLASS (TYPE)) && TYPE_PROTOCOL_LIST (TYPE))
 #define IS_SUPER(TYPE) \
   (POINTER_TYPE_P (TYPE) && TREE_TYPE (TYPE) == objc_super_template)
 
Index: gcc/testsuite/objc.dg/class-protocol-1.m
===================================================================
RCS file: gcc/testsuite/objc.dg/class-protocol-1.m
diff -N gcc/testsuite/objc.dg/class-protocol-1.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gcc/testsuite/objc.dg/class-protocol-1.m	5 Oct 2004 02:18:06 -0000
@@ -0,0 +1,303 @@
+/* Check Class <protocol> types */
+/* Author: David Ayers <d.ayers@inode.at> */
+/* { dg-do compile } */
+
+#include <objc/objc.h>
+#include <objc/objc-api.h>
+
+@protocol MyProto1
++(void)doItClass1;
+-(void)doItInstance1;
+@end
+
+@protocol MyProto2
++(void)doItClass2;
+-(void)doItInstance2;
+@end
+
+@interface MyClass1 <MyProto1>
+{
+  Class isa;
+}
+@end
+@implementation MyClass1
++(void)doItClass1{}
+-(void)doItInstance1{}
+@end
+
+@interface MyClass2 : MyClass1 <MyProto2>
+@end
+@implementation MyClass2
++(void)doItClass2{}
+-(void)doItInstance2{}
+@end
+
+/*----------------------------------------*/
+
+Class cls = 0;
+Class <MyProto1> clsP1 = 0;
+Class <MyProto2> clsP2 = 0;
+
+void
+testSimple(void)
+{
+  [cls doItClass1];
+  [cls doItInstance1]; /* Do not warn as root Class declares this.  */
+  [cls doItClass2];
+  [cls doItInstance2]; /* { dg-warning "no .\\+doItInstance2. method found" } */
+
+  [clsP1 doItClass1];
+  [clsP1 doItInstance1]; /* Do not warn as root Class declares this.  */
+  [clsP1 doItClass2];    /* { dg-warning "not implemented by protocol" } */
+  [clsP1 doItInstance2]; /* { dg-warning "not implemented by protocol" } */
+
+  [clsP2 doItClass1];    /* { dg-warning "not implemented by protocol" } */
+  [clsP2 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
+  [clsP2 doItClass2];
+  [clsP2 doItInstance2]; /* { dg-warning "not implemented by protocol" } */
+
+  [MyClass1 doItClass1];
+  [MyClass1 doItInstance1];
+  [MyClass1 doItClass2];    /* { dg-warning "may not respond to" } */
+  [MyClass1 doItInstance2]; /* { dg-warning "may not respond to" } */
+
+  [MyClass2 doItClass1];
+  [MyClass2 doItInstance1];
+  [MyClass2 doItClass2];
+  [MyClass2 doItInstance2]; /* { dg-warning "may not respond to" } */
+
+}
+
+/*----------------------------------------*/
+/* Protocols declared by categories */
+
+@protocol MyProto3
++(void)doItClass3;
+-(void)doItInstance3;
+@end
+@protocol MyProto4
++(void)doItClass4;
+-(void)doItInstance4;
+@end
+
+@interface MyClass1 (Category1) <MyProto3>
+@end
+@interface MyClass2 (Category2) <MyProto4>
+@end
+
+void
+testCategory(void)
+{
+  [cls doItClass3];
+  [cls doItInstance3];      /* Do not warn as root Class declares this.  */
+  [cls doItClass4];
+  [cls doItInstance4];      /* { dg-warning "no .\\+doItInstance4. method found" } */
+
+  [MyClass1 doItClass3];
+  [MyClass1 doItInstance3];
+  [MyClass1 doItClass4];    /* { dg-warning "may not respond" } */
+  [MyClass1 doItInstance4]; /* { dg-warning "may not respond" } */
+
+  [MyClass2 doItClass3];
+  [MyClass2 doItInstance3];
+  [MyClass2 doItClass4];
+  [MyClass2 doItInstance4]; /* { dg-warning "may not respond" } */
+
+}
+
+/*----------------------------------------*/
+/* Inherited protocols declared by categories */
+
+@protocol MyProto5 <MyProto1>
++(void)doItClass5;
+-(void)doItInstance5;
+@end
+
+@protocol MyProto6 <MyProto2>
++(void)doItClass6;
+-(void)doItInstance6;
+@end
+
+@interface MyClass1 (Category3) <MyProto5>
+@end
+@interface MyClass2 (Category4) <MyProto6>
+@end
+
+Class <MyProto5> clsP5 = 0;
+Class <MyProto6> clsP6 = 0;
+
+void
+testCategoryInherited(void)
+{
+  [cls doItClass5];
+  [cls doItInstance5]; /* Do not warn as root Class declares this.  */
+  [cls doItClass6];
+  [cls doItInstance6]; /* { dg-warning "no .\\+doItInstance6. method found" } */
+
+  [clsP5 doItClass1];
+  [clsP5 doItInstance1];
+  [clsP5 doItClass2];    /* { dg-warning "not implemented by protocol" } */
+  [clsP5 doItInstance2]; /* { dg-warning "not implemented by protocol" } */
+
+  [clsP6 doItClass1];    /* { dg-warning "not implemented by protocol" } */
+  [clsP6 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
+  [clsP6 doItClass2];
+  [clsP6 doItInstance2]; /* { dg-warning "not implemented by protocol" } */
+
+  [MyClass1 doItClass5];
+  [MyClass1 doItInstance5]; /* Do not warn as root Class declares this.  */
+  [MyClass1 doItClass6];    /* { dg-warning "may not respond" } */
+  [MyClass1 doItInstance6]; /* { dg-warning "may not respond" } */
+
+  [MyClass2 doItClass5];
+  [MyClass2 doItInstance5]; /* Do not warn as root Class declares this.  */
+  [MyClass2 doItClass6];
+  [MyClass2 doItInstance6]; /* { dg-warning "may not respond" } */
+
+}
+
+/*----------------------------------------*/
+/* Forward declared root protocols */
+
+@protocol FwProto;
+
+@interface MyClass1 (Forward) <FwProto>
+@end
+
+Class <FwProto> clsP7 = 0;
+
+void
+testForwardeDeclared1(void)
+{
+  [cls doItClass7];         /* { dg-warning "no .\\+doItClass7. method found" } */
+  [cls doItInstance7];      /* { dg-warning "no .\\+doItInstance7. method found" } */
+
+  [clsP7 doItClass7];       /* { dg-warning "not implemented by protocol" } */
+  [clsP7 doItInstance7];    /* { dg-warning "not implemented by protocol" } */
+
+  [MyClass1 doItClass7];    /* { dg-warning "may not respond" } */
+  [MyClass1 doItInstance7]; /* { dg-warning "may not respond" } */
+
+  [MyClass2 doItClass7];    /* { dg-warning "may not respond" } */
+  [MyClass2 doItInstance7]; /* { dg-warning "may not respond" } */
+
+}
+
+@protocol FwProto
++(void)doItClass7;
+-(void)doItInstance7;
+@end
+
+void
+testForwardeDeclared2(void)
+{
+  [cls doItClass7];
+  [cls doItInstance7];   /* Do not warn as root Class declares this.  */
+
+  [clsP7 doItClass7];    
+  [clsP7 doItInstance7]; /* Do not warn as root Class declares this.  */
+
+  [MyClass1 doItClass7];
+  [MyClass1 doItInstance7];
+
+  [MyClass2 doItClass7];
+  [MyClass2 doItInstance7];
+}
+
+/*----------------------------------------*/
+/* Inherited non root protocols */
+
+@protocol MyProto8
++(void)doItClass8;
+-(void)doItInstance8;
+@end
+
+@protocol MyProto9 <MyProto8>
++(void)doItClass9;
+-(void)doItInstance9;
+@end
+
+@interface MyClass1 (InheritedNonRoot) <MyProto9>
+@end
+
+Class <MyProto8> clsP8 = 0;
+Class <MyProto9> clsP9 = 0;
+
+void
+testInheritedNonRoot(void)
+{
+  [cls doItClass8];
+  [cls doItInstance8]; /* Do not warn as root Class declares super.  */
+  [cls doItClass9];
+  [cls doItInstance9]; /* Do not warn as root Class declares this.  */
+
+  [clsP8 doItClass8];
+  [clsP8 doItInstance8]; /* { dg-warning "not implemented by protocol" } */
+  [clsP8 doItClass9];    /* { dg-warning "not implemented by protocol" } */
+  [clsP8 doItInstance9]; /* { dg-warning "not implemented by protocol" } */
+
+  [clsP9 doItClass8];
+  [clsP9 doItInstance8]; /* { dg-warning "not implemented by protocol" } */
+  [clsP9 doItClass9];
+  [clsP9 doItInstance9]; /* { dg-warning "not implemented by protocol" } */
+
+  [MyClass1 doItClass8];
+  [MyClass1 doItInstance8]; /* Do not warn as root Class declares this.  */
+  [MyClass1 doItClass9];
+  [MyClass1 doItInstance9];
+
+  [MyClass2 doItClass8];
+  [MyClass2 doItInstance8]; /* Do not warn as root Class declares this.  */
+  [MyClass2 doItClass9];
+  [MyClass2 doItInstance9];
+  
+}
+
+id obj = nil;
+id <MyProto1> objP1 = nil;
+id <MyProto2> objP2 = nil;
+
+MyClass1 *mc1 = nil;
+MyClass2 *mc2 = nil;
+
+void
+testComptypes(void)
+{
+  cls == clsP1;
+  clsP1 == cls;
+
+  cls == objP1; /* { dg-warning "lacks a cast" } */
+  objP1 == cls; /* { dg-warning "lacks a cast" } */
+
+  clsP1 == clsP5;
+  clsP5 == clsP1;
+
+  mc1 == clsP1; /* { dg-warning "lacks a cast" } */
+  clsP1 == mc1; /* { dg-warning "lacks a cast" } */
+
+
+  cls = clsP1; 
+  clsP1 = cls;
+
+  cls = objP1; /* { dg-warning "incompatible" } */
+  objP1 = cls; /* { dg-warning "incompatible" } */
+
+  clsP1 = clsP5;
+  clsP5 = clsP1; /* { dg-warning "does not conform" } */
+
+  mc1 = clsP1; /* { dg-warning "incompatible" } */
+  clsP1 = mc1; /* { dg-warning "incompatible" } */
+
+}
+
+int main ()
+{
+  testSimple();
+  testCategory();
+  testCategoryInherited();
+  return(0);
+}
+
+/* { dg-warning "Messages without a matching" "" { target *-*-* } 47 } */
+/* { dg-warning "will be assumed to return" "" { target *-*-* } 47 } */
+/* { dg-warning "as arguments" "" { target *-*-* } 47 } */
Index: gcc/testsuite/objc.dg/method-6.m
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/objc.dg/method-6.m,v
retrieving revision 1.4
diff -u -3 -p -r1.4 method-6.m
--- gcc/testsuite/objc.dg/method-6.m	8 Sep 2004 18:48:56 -0000	1.4
+++ gcc/testsuite/objc.dg/method-6.m	5 Oct 2004 02:18:06 -0000
@@ -22,7 +22,7 @@ void foo(void) {
        /* { dg-warning "using .\\-\\(unsigned( int)?\\)port." "" { target *-*-* } 9 } */
        /* { dg-warning "also found .\\+\\(Protocol \\*\\)port." "" { target *-*-* } 14 } */
 
-  [receiver starboard];  /* { dg-warning ".Class. may not respond to .\\+starboard." } */
+  [receiver starboard];  /* { dg-warning "no .\\+starboard. method found" } */
        /* { dg-warning "Messages without a matching method signature" "" { target *-*-* } 25 } */
        /* { dg-warning "will be assumed to return .id. and accept" "" { target *-*-* } 25 } */
        /* { dg-warning ".\.\.\.. as arguments" "" { target *-*-* } 25 } */

[-- Attachment #3: Type: text/plain, Size: 1 bytes --]



^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-05  3:13                                   ` Ziemowit Laski
@ 2004-10-05 16:37                                     ` David Ayers
  2004-10-05 19:55                                       ` Ziemowit Laski
  0 siblings, 1 reply; 35+ messages in thread
From: David Ayers @ 2004-10-05 16:37 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: gcc-patches

Ziemowit Laski wrote:
> Took me longer than expected, but here is the alternative patch I 
> promised; no ChangeLog entries for now.  It's running a bit late, so 
> I'll defer my commentary until tomorrow. :-(  As always, feedback is 
> welcome.

Hello Zem,

well I guess we have different views on a gratuitous rewriting of
objc_comptypes :-), but your version seems fine.

The test case you attached fails with the patch:
Excess errors:
[...]/class-protocol-1.m:50: warning: `+doItInstance1' not implemented
by protocol(s)
[...]/class-protocol-1.m:92: warning: no `+doItInstance3' method found
[...]/class-protocol-1.m:133: warning: no `+doItInstance5' method found
[...]/class-protocol-1.m:138: warning: `+doItInstance1' not implemented
by protocol(s)
[...]/class-protocol-1.m:195: warning: no `+doItInstance7' method found
[...]/class-protocol-1.m:198: warning: `+doItInstance7' not implemented
by protocol(s)
[...]/class-protocol-1.m:230: warning: no `+doItInstance8' method found
[...]/class-protocol-1.m:232: warning: no `+doItInstance9' method found


You seem to have omitted the part which is /very/ important to me.
Please! search for instance prototypes in protocol qualified Class
references!  What is your issue with this feature?  It is very important
in my view wrt generating the right code.  I do not understand what is
bothering you about it.  I can live with doing it independent of whether
the protocol is adopted by the root class.  But please do it for those
that are.

I admit that my test cases so far haven't covered that.  So here it is:

/*----------------------------------------*/
/* Prototype mismatch  */

@protocol MyOtherProto1
+(id)doItClass1;
-(id)doItInstance1; /* { dg-warning "using" } */
@end
@interface MyOtherClass1 <MyOtherProto1>
@end

Class <MyOtherProto1> oclsP1;

void
testPrototypeMismatch(void)
{
  id tmp1 = [oclsP1 doItClass1];
  id tmp2 = [oclsP1 doItInstance1]; /* { dg-warning "as class method" } */

  [clsP1 doItClass1];
  [clsP1 doItInstance1]; /* { dg-warning "as class method" } */
}

Please insert right after testInheritedNonRoot().  At least after clsP1
is declared.  Note that this is still not perfect as it only tests
whether "someone" ever emits the "using" if the new protocol and doesn't
really match it up due to the fact that wouldn't know how to tell
dejagnu to do the right thing.  But at least we would know both where
being used.  Alternatively all three warnings could be removed if the
correct prototypes are used w/o emitting the diagnostics as your
modified test case suggests.

Some more comments below...

> Index: gcc/testsuite/objc.dg/class-protocol-1.m
> ===================================================================
> RCS file: gcc/testsuite/objc.dg/class-protocol-1.m
> diff -N gcc/testsuite/objc.dg/class-protocol-1.m
> --- /dev/null	1 Jan 1970 00:00:00 -0000
> +++ gcc/testsuite/objc.dg/class-protocol-1.m	5 Oct 2004 02:18:06 -0000
> @@ -0,0 +1,303 @@
> +/* Check Class <protocol> types */
> +/* Author: David Ayers <d.ayers@inode.at> */
> +/* { dg-do compile } */
> +
> +#include <objc/objc.h>
> +#include <objc/objc-api.h>
> +
> +@protocol MyProto1
> ++(void)doItClass1;
> +-(void)doItInstance1;
> +@end
> +
> +@protocol MyProto2
> ++(void)doItClass2;
> +-(void)doItInstance2;
> +@end
> +
> +@interface MyClass1 <MyProto1>
> +{
> +  Class isa;
> +}
> +@end
> +@implementation MyClass1
> ++(void)doItClass1{}
> +-(void)doItInstance1{}
> +@end
> +
> +@interface MyClass2 : MyClass1 <MyProto2>
> +@end
> +@implementation MyClass2
> ++(void)doItClass2{}
> +-(void)doItInstance2{}
> +@end
> +
> +/*----------------------------------------*/
> +
> +Class cls = 0;
> +Class <MyProto1> clsP1 = 0;
> +Class <MyProto2> clsP2 = 0;
> +
> +void
> +testSimple(void)
> +{
> +  [cls doItClass1];
> +  [cls doItInstance1]; /* Do not warn as root Class declares this.  */
> +  [cls doItClass2];
> +  [cls doItInstance2]; /* { dg-warning "no .\\+doItInstance2. method found" } */
> +
> +  [clsP1 doItClass1];
> +  [clsP1 doItInstance1]; /* Do not warn as root Class declares this.  */

This is failure:
[...]/class-protocol-1.m:50: warning: `+doItInstance1' not implemented
by protocol(s)
-doItInstance1 is part of MyProto1 which is adopted by the root class
MyClass1.
Not warning here is fine by but seems inconsistent with warnings below.
 And didn't you suggest a warning about not finding a class method here?

> +  [clsP1 doItClass2];    /* { dg-warning "not implemented by protocol" } */
> +  [clsP1 doItInstance2]; /* { dg-warning "not implemented by protocol" } */
> +
> +  [clsP2 doItClass1];    /* { dg-warning "not implemented by protocol" } */
> +  [clsP2 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
> +  [clsP2 doItClass2];
> +  [clsP2 doItInstance2]; /* { dg-warning "not implemented by protocol" } */
> +
> +  [MyClass1 doItClass1];
> +  [MyClass1 doItInstance1];
> +  [MyClass1 doItClass2];    /* { dg-warning "may not respond to" } */
> +  [MyClass1 doItInstance2]; /* { dg-warning "may not respond to" } */
> +
> +  [MyClass2 doItClass1];
> +  [MyClass2 doItInstance1];
> +  [MyClass2 doItClass2];
> +  [MyClass2 doItInstance2]; /* { dg-warning "may not respond to" } */
> +

Please add the tests from my last mail:
  [MyClass3 doItClass1];    /* { dg-warning "may not respond to" } */
  [MyClass3 doItInstance1]; /* { dg-warning "may not respond to" } */

  [MyClass4 doItClass1];
  [MyClass4 doItInstance1]; /* { dg-warning "may not respond to" } */

> +}
> +
> +/*----------------------------------------*/
> +/* Protocols declared by categories */
> +
> +@protocol MyProto3
> ++(void)doItClass3;
> +-(void)doItInstance3;
> +@end
> +@protocol MyProto4
> ++(void)doItClass4;
> +-(void)doItInstance4;
> +@end
> +
> +@interface MyClass1 (Category1) <MyProto3>
> +@end
> +@interface MyClass2 (Category2) <MyProto4>
> +@end
> +
> +void
> +testCategory(void)
> +{
> +  [cls doItClass3];
> +  [cls doItInstance3];      /* Do not warn as root Class declares this.  */

This is failure:
[...]/class-protocol-1.m:92: warning: no `+doItInstance3' method found

> +  [cls doItClass4];
> +  [cls doItInstance4];      /* { dg-warning "no .\\+doItInstance4. method found" } */
> +
> +  [MyClass1 doItClass3];
> +  [MyClass1 doItInstance3];
> +  [MyClass1 doItClass4];    /* { dg-warning "may not respond" } */
> +  [MyClass1 doItInstance4]; /* { dg-warning "may not respond" } */
> +
> +  [MyClass2 doItClass3];
> +  [MyClass2 doItInstance3];
> +  [MyClass2 doItClass4];
> +  [MyClass2 doItInstance4]; /* { dg-warning "may not respond" } */
> +
> +}
> +
> +/*----------------------------------------*/
> +/* Inherited protocols declared by categories */
> +
> +@protocol MyProto5 <MyProto1>
> ++(void)doItClass5;
> +-(void)doItInstance5;
> +@end
> +
> +@protocol MyProto6 <MyProto2>
> ++(void)doItClass6;
> +-(void)doItInstance6;
> +@end
> +
> +@interface MyClass1 (Category3) <MyProto5>
> +@end
> +@interface MyClass2 (Category4) <MyProto6>
> +@end
> +
> +Class <MyProto5> clsP5 = 0;
> +Class <MyProto6> clsP6 = 0;
> +
> +void
> +testCategoryInherited(void)
> +{
> +  [cls doItClass5];
> +  [cls doItInstance5]; /* Do not warn as root Class declares this.  */
This failure:
[...]/class-protocol-1.m:133: warning: no `+doItInstance5' method found
> +  [cls doItClass6];
> +  [cls doItInstance6]; /* { dg-warning "no .\\+doItInstance6. method found" } */
> +
> +  [clsP5 doItClass1];
> +  [clsP5 doItInstance1];

This is failure:
[...]/class-protocol-1.m:138: warning: `+doItInstance1' not implemented
by protocol(s)

Pretty much the same comment about doItInstance1 as above, so see below.

> +  [clsP5 doItClass2];    /* { dg-warning "not implemented by protocol" } */
> +  [clsP5 doItInstance2]; /* { dg-warning "not implemented by protocol" } */
> +
> +  [clsP6 doItClass1];    /* { dg-warning "not implemented by protocol" } */
> +  [clsP6 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
> +  [clsP6 doItClass2];
> +  [clsP6 doItInstance2]; /* { dg-warning "not implemented by protocol" } */
> +
> +  [MyClass1 doItClass5];
> +  [MyClass1 doItInstance5]; /* Do not warn as root Class declares this.  */
> +  [MyClass1 doItClass6];    /* { dg-warning "may not respond" } */
> +  [MyClass1 doItInstance6]; /* { dg-warning "may not respond" } */
> +
> +  [MyClass2 doItClass5];
> +  [MyClass2 doItInstance5]; /* Do not warn as root Class declares this.  */
> +  [MyClass2 doItClass6];
> +  [MyClass2 doItInstance6]; /* { dg-warning "may not respond" } */
> +
> +}
> +
> +/*----------------------------------------*/
> +/* Forward declared root protocols */
> +
> +@protocol FwProto;
> +
> +@interface MyClass1 (Forward) <FwProto>
> +@end
> +
> +Class <FwProto> clsP7 = 0;
> +
> +void
> +testForwardeDeclared1(void)
> +{
> +  [cls doItClass7];         /* { dg-warning "no .\\+doItClass7. method found" } */
> +  [cls doItInstance7];      /* { dg-warning "no .\\+doItInstance7. method found" } */
> +
> +  [clsP7 doItClass7];       /* { dg-warning "not implemented by protocol" } */
> +  [clsP7 doItInstance7];    /* { dg-warning "not implemented by protocol" } */
> +
> +  [MyClass1 doItClass7];    /* { dg-warning "may not respond" } */
> +  [MyClass1 doItInstance7]; /* { dg-warning "may not respond" } */
> +
> +  [MyClass2 doItClass7];    /* { dg-warning "may not respond" } */
> +  [MyClass2 doItInstance7]; /* { dg-warning "may not respond" } */
> +
> +}
> +
> +@protocol FwProto
> ++(void)doItClass7;
> +-(void)doItInstance7;
> +@end
> +
> +void
> +testForwardeDeclared2(void)
> +{
> +  [cls doItClass7];
> +  [cls doItInstance7];   /* Do not warn as root Class declares this.  */
This is failure:
[...]/class-protocol-1.m:195: warning: no `+doItInstance7' method found

> +
> +  [clsP7 doItClass7];    
> +  [clsP7 doItInstance7]; /* Do not warn as root Class declares this.  */
This is failure:
[...]/class-protocol-1.m:198: warning: `+doItInstance7' not implemented
by protocol(s)

And again, see below.

> +
> +  [MyClass1 doItClass7];
> +  [MyClass1 doItInstance7];
> +
> +  [MyClass2 doItClass7];
> +  [MyClass2 doItInstance7];
> +}
> +
> +/*----------------------------------------*/
> +/* Inherited non root protocols */
> +
> +@protocol MyProto8
> ++(void)doItClass8;
> +-(void)doItInstance8;
> +@end
> +
> +@protocol MyProto9 <MyProto8>
> ++(void)doItClass9;
> +-(void)doItInstance9;
> +@end
> +
> +@interface MyClass1 (InheritedNonRoot) <MyProto9>
> +@end
> +
> +Class <MyProto8> clsP8 = 0;
> +Class <MyProto9> clsP9 = 0;
> +
> +void
> +testInheritedNonRoot(void)
> +{
> +  [cls doItClass8];
> +  [cls doItInstance8]; /* Do not warn as root Class declares super.  */

This is failure:
[...]/class-protocol-1.m:230: warning: no `+doItInstance8' method found

> +  [cls doItClass9];
> +  [cls doItInstance9]; /* Do not warn as root Class declares this.  */
This is failure:
[...]/class-protocol-1.m:232: warning: no `+doItInstance9' method found

> +
> +  [clsP8 doItClass8];
> +  [clsP8 doItInstance8]; /* { dg-warning "not implemented by protocol" } */


This one is the debatable/pathological case:  The root class MyClass1
adopts MyProto9 which inherits MyProto8.  In that sense we have a good
guess at which prototype to use.  But I'm fine with this yet we should
add a comment the test case.

> +  [clsP8 doItClass9];    /* { dg-warning "not implemented by protocol" } */
> +  [clsP8 doItInstance9]; /* { dg-warning "not implemented by protocol" } */
> +
> +  [clsP9 doItClass8];
> +  [clsP9 doItInstance8]; /* { dg-warning "not implemented by protocol" } */

Here is what I've been referring to about being inconsistent.  MyClass1
is a root class that adopts MyProto9 which inherits MyProto8 and there
for should not warn as mentioned above, or it should only warn that it
doesn't find the class method but is using the prototype of the instance
method.

> +  [clsP9 doItClass9];
> +  [clsP9 doItInstance9]; /* { dg-warning "not implemented by protocol" } */

Again, MyClass1 is a root class that adopts MyProto9 directly and should
not warn as mentioned above.

> +
> +  [MyClass1 doItClass8];
> +  [MyClass1 doItInstance8]; /* Do not warn as root Class declares this.  */
> +  [MyClass1 doItClass9];
> +  [MyClass1 doItInstance9];
> +
> +  [MyClass2 doItClass8];
> +  [MyClass2 doItInstance8]; /* Do not warn as root Class declares this.  */
> +  [MyClass2 doItClass9];
> +  [MyClass2 doItInstance9];
> +  
> +}
> +
> +id obj = nil;
> +id <MyProto1> objP1 = nil;
> +id <MyProto2> objP2 = nil;
> +
> +MyClass1 *mc1 = nil;
> +MyClass2 *mc2 = nil;
> +
> +void
> +testComptypes(void)
> +{
> +  cls == clsP1;
> +  clsP1 == cls;
> +
> +  cls == objP1; /* { dg-warning "lacks a cast" } */
> +  objP1 == cls; /* { dg-warning "lacks a cast" } */
> +
> +  clsP1 == clsP5;
> +  clsP5 == clsP1;
> +
> +  mc1 == clsP1; /* { dg-warning "lacks a cast" } */
> +  clsP1 == mc1; /* { dg-warning "lacks a cast" } */
> +
> +
> +  cls = clsP1; 
> +  clsP1 = cls;
> +
> +  cls = objP1; /* { dg-warning "incompatible" } */
> +  objP1 = cls; /* { dg-warning "incompatible" } */
> +
> +  clsP1 = clsP5;
> +  clsP5 = clsP1; /* { dg-warning "does not conform" } */
> +
> +  mc1 = clsP1; /* { dg-warning "incompatible" } */
> +  clsP1 = mc1; /* { dg-warning "incompatible" } */
> +
> +}
> +
> +int main ()
> +{
> +  testSimple();
> +  testCategory();
> +  testCategoryInherited();
> +  return(0);
> +}
> +
> +/* { dg-warning "Messages without a matching" "" { target *-*-* } 47 } */
> +/* { dg-warning "will be assumed to return" "" { target *-*-* } 47 } */
> +/* { dg-warning "as arguments" "" { target *-*-* } 47 } */

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-05 16:37                                     ` David Ayers
@ 2004-10-05 19:55                                       ` Ziemowit Laski
  2004-10-05 20:44                                         ` d.ayers
  0 siblings, 1 reply; 35+ messages in thread
From: Ziemowit Laski @ 2004-10-05 19:55 UTC (permalink / raw)
  To: David Ayers; +Cc: gcc-patches

On 5 Oct 2004, at 9.34, David Ayers wrote:

> Ziemowit Laski wrote:
>> Took me longer than expected, but here is the alternative patch I
>> promised; no ChangeLog entries for now.  It's running a bit late, so
>> I'll defer my commentary until tomorrow. :-(  As always, feedback is
>> welcome.
>
> Hello Zem,
>
> well I guess we have different views on a gratuitous rewriting of
> objc_comptypes :-), but your version seems fine.

Good to hear it. :-)
>
> The test case you attached fails with the patch:
> Excess errors:
> [...]/class-protocol-1.m:50: warning: `+doItInstance1' not implemented
> by protocol(s)
> [...]/class-protocol-1.m:92: warning: no `+doItInstance3' method found
> [...]/class-protocol-1.m:133: warning: no `+doItInstance5' method found
> [...]/class-protocol-1.m:138: warning: `+doItInstance1' not implemented
> by protocol(s)
> [...]/class-protocol-1.m:195: warning: no `+doItInstance7' method found
> [...]/class-protocol-1.m:198: warning: `+doItInstance7' not implemented
> by protocol(s)
> [...]/class-protocol-1.m:230: warning: no `+doItInstance8' method found
> [...]/class-protocol-1.m:232: warning: no `+doItInstance9' method found

I could have sworn this worked for me, but I'll check again (and also
incorporate all of the comments you had below).
>
>
> You seem to have omitted the part which is /very/ important to me.
> Please! search for instance prototypes in protocol qualified Class
> references!  What is your issue with this feature?  It is very 
> important
> in my view wrt generating the right code.  I do not understand what is
> bothering you about it.  I can live with doing it independent of 
> whether
> the protocol is adopted by the root class.  But please do it for those
> that are.

My patch was only a work in progress (hence no ChangeLogs yet), but yes,
the protocols in question should be searched for a matching instance
prototype as a fallback, and if one is found, a suitable warning should
be issued.  If that yields no result either, then we give the "not 
implemented
by protocol(s)" warning and do the unadorned 'Class' search (which will 
give
us instance methods implemented by root classes).  I will do this in the
next rev of my patch; please stay tuned.

Note also that my patch intentionally skirts the various 
cleanup/renaming issues
we've discussed; we can do those later separately.  I also realized 
that my
suggestion for renaming 'reflexive' to 'symmetric' is wrong :-(; a 
symmetric
operation is one for which ((A op B) && (B op A)), whereas 
objc_comptypes()
is really implementing ((A op B) || (B op A)).  We really should rewrite
objc_comptypes() at some point so that it behaves more like C/C++ 
comptypes().

--Zem

--------------------------------------------------------------
Ziemowit Laski                 1 Infinite Loop, MS 301-2K
Mac OS X Compiler Group        Cupertino, CA USA  95014-2083
Apple Computer, Inc.           +1.408.974.6229  Fax .5477

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-05 19:55                                       ` Ziemowit Laski
@ 2004-10-05 20:44                                         ` d.ayers
  2004-10-06 17:12                                           ` David Ayers
  0 siblings, 1 reply; 35+ messages in thread
From: d.ayers @ 2004-10-05 20:44 UTC (permalink / raw)
  To: zlaski; +Cc: David Ayers, gcc-patches

> On 5 Oct 2004, at 9.34, David Ayers wrote:
>
>> Ziemowit Laski wrote:
>>> Took me longer than expected, but here is the alternative patch I
>>> promised; no ChangeLog entries for now.  It's running a bit late, so
>>> I'll defer my commentary until tomorrow. :-(  As always, feedback is
>>> welcome.
>>
>> Hello Zem,
>>
>> well I guess we have different views on a gratuitous rewriting of
>> objc_comptypes :-), but your version seems fine.
>
> Good to hear it. :-)

Actually I have to take that back.  I just tried to have a closer look so
that I could integrate this part into my version but it seems that your
handling is incomplete.  It get's gets the:

id <proto> =/== Class <proto>

case wrong.  I have to admit that the test case was missing for that
variant (and maybe some others).  I'll try to come up with a more complete
comptypes tests.  But for now simply add:

  clsP1 == objP1; /* { dg-warning "lacks a cast" } */
  objP1 == clsP1; /* { dg-warning "lacks a cast" } */

  clsP1 = objP1; /* { dg-warning "incompatible" } */
  objP1 = clsP1; /* { dg-warning "incompatible" } */


>>
>
> I could have sworn this worked for me, but I'll check again (and also
> incorporate all of the comments you had below).
>>
>>
>> You seem to have omitted the part which is /very/ important to me.
>> Please! search for instance prototypes in protocol qualified Class
>> references!  What is your issue with this feature?  It is very
>> important
>> in my view wrt generating the right code.  I do not understand what is
>> bothering you about it.  I can live with doing it independent of
>> whether
>> the protocol is adopted by the root class.  But please do it for those
>> that are.
>
> My patch was only a work in progress (hence no ChangeLogs yet), but yes,
> the protocols in question should be searched for a matching instance
> prototype as a fallback, and if one is found, a suitable warning should
> be issued.  If that yields no result either, then we give the "not
> implemented
> by protocol(s)" warning and do the unadorned 'Class' search (which will
> give
> us instance methods implemented by root classes).  I will do this in the
> next rev of my patch; please stay tuned.

I would really suggest you work from my last patch and strip what ever you
deem necessary.  We can take a closer look at getting objc_comptypes more
compact and nuking objc_comptypes_proto_proto after the branch.

> Note also that my patch intentionally skirts the various
> cleanup/renaming issues
> we've discussed; we can do those later separately.  I also realized

Indeed.

> that my
> suggestion for renaming 'reflexive' to 'symmetric' is wrong :-(; a
> symmetric
> operation is one for which ((A op B) && (B op A)), whereas
> objc_comptypes()
> is really implementing ((A op B) || (B op A)).  We really should rewrite
> objc_comptypes() at some point so that it behaves more like C/C++
> comptypes().

I was wondering about that also, but the naming is tangantial so I'm not
worried about it.  I am worried about code generation (using the correct
prototypes).

Cheers,
David Ayers




^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-05 20:44                                         ` d.ayers
@ 2004-10-06 17:12                                           ` David Ayers
  2004-10-11 21:57                                             ` Ziemowit Laski
  0 siblings, 1 reply; 35+ messages in thread
From: David Ayers @ 2004-10-06 17:12 UTC (permalink / raw)
  To: zlaski; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1060 bytes --]

d.ayers@inode.at wrote:

>>On 5 Oct 2004, at 9.34, David Ayers wrote:
>>
>>
>>>Ziemowit Laski wrote:
>>>
>>>>Took me longer than expected, but here is the alternative patch I
>>>>promised; no ChangeLog entries for now.  It's running a bit late, so
>>>>I'll defer my commentary until tomorrow. :-(  As always, feedback is
>>>>welcome.
>>>
>>>Hello Zem,
>>>
>>>well I guess we have different views on a gratuitous rewriting of
>>>objc_comptypes :-), but your version seems fine.
>>
>>Good to hear it. :-)
> 
> 
> Actually I have to take that back.  I just tried to have a closer look so
> that I could integrate this part into my version but it seems that your
> handling is incomplete.  It get's gets the:
> 
> id <proto> =/== Class <proto>
> 
> case wrong.  I have to admit that the test case was missing for that
> variant (and maybe some others).  I'll try to come up with a more complete
> comptypes tests. 
> 

OK this test case includes parts of comp-types-* but should be a good to
catch most (all?) of the branches we are interested in.

Cheers,
David


[-- Attachment #2: class-protocol-1.m --]
[-- Type: text/plain, Size: 11749 bytes --]

/* Check Class <protocol> types */
/* Author: David Ayers <d.ayers@inode.at> */
/* { dg-do compile } */

#include <objc/objc.h>
#include <objc/objc-api.h>

@protocol MyProto1
+(void)doItClass1;
-(void)doItInstance1; /* { dg-warning "using" } */
@end

@protocol MyProto2
+(void)doItClass2;
-(void)doItInstance2;
@end

@interface MyClass1 <MyProto1>
{
  Class isa;
}
@end
@implementation MyClass1
+(void)doItClass1{}
-(void)doItInstance1{}
@end

@interface MyClass2 : MyClass1 <MyProto2>
@end
@implementation MyClass2
+(void)doItClass2{}
-(void)doItInstance2{}
@end

@interface MyClass3
{
  Class isa;
}
@end
@interface MyClass4 : MyClass3 <MyProto1>
@end

/*----------------------------------------*/

Class cls = 0;
Class <MyProto1> clsP1 = 0;
Class <MyProto2> clsP2 = 0;

void
testSimple(void)
{
  [cls doItClass1];
  [cls doItInstance1]; /* Do not warn as root Class declares this.  */
  [cls doItClass2];
  [cls doItInstance2]; /* { dg-warning "no .+doItInstance2. method" } */

  [clsP1 doItClass1];
  [clsP1 doItInstance1]; /* { dg-warning "as class method" }  */
  [clsP1 doItClass2];    /* { dg-warning "not implemented by protocol" } */
  [clsP1 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [clsP2 doItClass1];    /* { dg-warning "not implemented by protocol" } */
  [clsP2 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
  [clsP2 doItClass2];
  [clsP2 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass1];
  [MyClass1 doItInstance1];
  [MyClass1 doItClass2];    /* { dg-warning "may not respond to" } */
  [MyClass1 doItInstance2]; /* { dg-warning "may not respond to" } */

  [MyClass2 doItClass1];
  [MyClass2 doItInstance1];
  [MyClass2 doItClass2];
  [MyClass2 doItInstance2]; /* { dg-warning "may not respond to" } */

  [MyClass3 doItClass1];    /* { dg-warning "may not respond to" } */
  [MyClass3 doItInstance1]; /* { dg-warning "may not respond to" } */

  [MyClass4 doItClass1];    
  [MyClass4 doItInstance1]; /* { dg-warning "may not respond to" } */

}

/*----------------------------------------*/
/* Protocols declared by categories */

@protocol MyProto3
+(void)doItClass3;
-(void)doItInstance3;
@end
@protocol MyProto4
+(void)doItClass4;
-(void)doItInstance4;
@end

@interface MyClass1 (Category1) <MyProto3>
@end
@interface MyClass2 (Category2) <MyProto4>
@end

void
testCategory(void)
{
  [cls doItClass3];
  [cls doItInstance3];      /* Do not warn as root Class declares this.  */
  [cls doItClass4];
  [cls doItInstance4];      /* { dg-warning "no .+doItInstance4. method" } */

  [MyClass1 doItClass3];
  [MyClass1 doItInstance3];
  [MyClass1 doItClass4];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance4]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass3];
  [MyClass2 doItInstance3];
  [MyClass2 doItClass4];
  [MyClass2 doItInstance4]; /* { dg-warning "may not respond" } */

}

/*----------------------------------------*/
/* Incorperated protocols declared by categories */

@protocol MyProto5 <MyProto1>
+(void)doItClass5;
-(void)doItInstance5;
@end

@protocol MyProto6 <MyProto2>
+(void)doItClass6;
-(void)doItInstance6;
@end

@interface MyClass1 (Category3) <MyProto5>
@end
@interface MyClass2 (Category4) <MyProto6>
@end

Class <MyProto5> clsP5 = 0;
Class <MyProto6> clsP6 = 0;

void
testCategoryIncorporated(void)
{
  [cls doItClass5];
  [cls doItInstance5]; /* Do not warn as root Class declares this.  */
  [cls doItClass6];
  [cls doItInstance6]; /* { dg-warning "no .+doItInstance6. method" } */

  [clsP5 doItClass1];
  [clsP5 doItInstance1]; /* { dg-warning "as class method" }  */
  [clsP5 doItClass2];    /* { dg-warning "not implemented by protocol" } */
  [clsP5 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [clsP6 doItClass1];    /* { dg-warning "not implemented by protocol" } */
  [clsP6 doItInstance1]; /* { dg-warning "not implemented by protocol" } */
  [clsP6 doItClass2];
  [clsP6 doItInstance2]; /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass5];
  [MyClass1 doItInstance5]; /* Do not warn as root Class declares this.  */
  [MyClass1 doItClass6];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance6]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass5];
  [MyClass2 doItInstance5]; /* Do not warn as root Class declares this.  */
  [MyClass2 doItClass6];
  [MyClass2 doItInstance6]; /* { dg-warning "may not respond" } */

}

/*----------------------------------------*/
/* Forward declared root protocols */

@protocol FwProto;

@interface MyClass1 (Forward) <FwProto>
@end

Class <FwProto> clsP7 = 0;

void
testForwardeDeclared1(void)
{
  [cls doItClass7];         /* { dg-warning "no .+doItClass7. method" } */
  [cls doItInstance7];      /* { dg-warning "no .+doItInstance7. method" } */

  [clsP7 doItClass7];       /* { dg-warning "not implemented by protocol" } */
  [clsP7 doItInstance7];    /* { dg-warning "not implemented by protocol" } */

  [MyClass1 doItClass7];    /* { dg-warning "may not respond" } */
  [MyClass1 doItInstance7]; /* { dg-warning "may not respond" } */

  [MyClass2 doItClass7];    /* { dg-warning "may not respond" } */
  [MyClass2 doItInstance7]; /* { dg-warning "may not respond" } */

}

@protocol FwProto
+(void)doItClass7;
-(void)doItInstance7; /* { dg-warning "using" } */
@end

void
testForwardeDeclared2(void)
{
  [cls doItClass7];
  [cls doItInstance7];   /* Do not warn as root Class declares this.  */

  [clsP7 doItClass7];    
  [clsP7 doItInstance7]; /* { dg-warning "as class method" } */

  [MyClass1 doItClass7];
  [MyClass1 doItInstance7];

  [MyClass2 doItClass7];
  [MyClass2 doItInstance7];

}

/*----------------------------------------*/
/* Incorperated non root protocols */

@protocol MyProto8
+(void)doItClass8;
-(void)doItInstance8; /* { dg-warning "using" } */
@end

@protocol MyProto9 <MyProto8>
+(void)doItClass9;
-(void)doItInstance9; /* { dg-warning "using" } */
@end

@interface MyClass1 (IncorporatedNonRoot) <MyProto9>
@end

Class <MyProto8> clsP8 = 0;
Class <MyProto9> clsP9 = 0;

void
testIncorporatedNonRoot(void)
{
  [cls doItClass8];
  [cls doItInstance8]; /* Do not warn as root Class declares super.  */
  [cls doItClass9];
  [cls doItInstance9]; /* Do not warn as root Class declares this.  */

  [clsP8 doItClass8];
  [clsP8 doItInstance8]; /* { dg-warning "as class method" } debatable */
  [clsP8 doItClass9];    /* { dg-warning "not implemented by protocol" } */
  [clsP8 doItInstance9]; /* { dg-warning "not implemented by protocol" } */

  [clsP9 doItClass8];
  [clsP9 doItInstance8]; /* { dg-warning "as class method" } */
  [clsP9 doItClass9];
  [clsP9 doItInstance9]; /* { dg-warning "as class method" } */

  [MyClass1 doItClass8];
  [MyClass1 doItInstance8]; /* Do not warn as root Class declares this.  */
  [MyClass1 doItClass9];
  [MyClass1 doItInstance9];

  [MyClass2 doItClass8];
  [MyClass2 doItInstance8]; /* Do not warn as root Class declares this.  */
  [MyClass2 doItClass9];
  [MyClass2 doItInstance9];
  
}

/*----------------------------------------*/
/* Prototype mismatch  */

@protocol MyOtherProto1
+(id)doItClass1;
-(id)doItInstance1; /* { dg-warning "using" } */
@end
@interface MyOtherClass1 <MyOtherProto1>
@end

Class <MyOtherProto1> oclsP1;

void
testPrototypeMismatch(void)
{
  id tmp1 = [oclsP1 doItClass1];
  id tmp2 = [oclsP1 doItInstance1]; /* { dg-warning "as class method" } */

  [clsP1 doItClass1];
  [clsP1 doItInstance1]; /* { dg-warning "as class method" } */
}

id obj = nil;
id <MyProto1> objP1 = nil;
id <MyProto2> objP2 = nil;
id <MyProto5> objP5 = nil;
int num = 0;
void *ptr = 0;

MyClass1 *mc1 = nil;

void
testComptypes(void)
{
  { /* id <protocol>, id <protocol> : Shouldn't be part of this test. */
    objP1 == objP2;  /* { dg-warning "lacks a cast" } */
    objP2 == objP1;  /* { dg-warning "lacks a cast" } */

    objP1 == objP5;
    objP5 == objP1;
  }
  { /* id <protocol>, SomeClass * : Shouldn't be part of this test. */
    mc1 == objP1;
    objP1 == mc1;
    
    mc1 == objP2; /* { dg-warning "does not implement" } */
    objP2 == mc1; /* { dg-warning "does not implement" } */
  }
  { /* id <protocol>, id : Shouldn't be part of this test. */
    obj == objP1;
    objP1 == obj;
  }
  { /* id <protocol>, Class : Shouldn't be part of this test. */
    cls == objP1; /* { dg-warning "lacks a cast" } */
    objP1 == cls; /* { dg-warning "lacks a cast" } */
  }
  { /* id <protocol>, non-ObjC : Shouldn't be part of this test. */
    num == objP1; /* { dg-warning "between pointer" } */
    objP1 == num; /* { dg-warning "between pointer" } */

    ptr == objP1;
    objP1 == ptr;
  }
  { /* Class <protocol>, Class <protocol> */
    clsP1 == clsP2; /* { dg-warning "lacks a cast" } */
    clsP2 == clsP1; /* { dg-warning "lacks a cast" } */

    clsP1 == clsP5;
    clsP5 == clsP1;
  }
  { /* Class <protocol>, SomeClass * */
    mc1 == clsP1; /* { dg-warning "lacks a cast" } */
    clsP1 == mc1; /* { dg-warning "lacks a cast" } */
  }
  { /* Class <protocol>, id */
    obj == clsP1;
    clsP1 == obj;
  }
  { /* Class <protocol>, Class */
    cls == clsP1;
    clsP1 == cls;
  }
  { /* Class <protocol>, non-ObjC */
    num == clsP1; /* { dg-warning "between pointer" } */
    clsP1 == num; /* { dg-warning "between pointer" } */

    ptr == clsP1;
    clsP1 == ptr;
  }
  { /* Class <protocol>, id <protocol> */
    clsP1 == objP1; /* { dg-warning "lacks a cast" } */
    objP1 == clsP1; /* { dg-warning "lacks a cast" } */
  }

  { /* id <protocol>, id <protocol> : Shouldn't be part of this test. */
    objP1 = objP2; /* { dg-warning "does not conform" } */
    objP2 = objP1; /* { dg-warning "does not conform" } */

    objP1 = objP5;
    objP5 = objP1; /* { dg-warning "does not conform" } */
  }
  { /* id <protocol>, SomeClass * : Shouldn't be part of this test. */
    mc1 = objP1; /* { dg-warning "incompatible" } Bogus ? */
    objP1 = mc1;
    
    mc1 = objP2; /* { dg-warning "incompatible" } */
    objP2 = mc1; /* { dg-warning "does not implement" } */
  }
  { /* id <protocol>, id : Shouldn't be part of this test. */
    obj = objP1;
    objP1 = obj;
  }
  { /* id <protocol>, Class : Shouldn't be part of this test. */
    cls = objP1; /* { dg-warning "incompatible" } */
    objP1 = cls; /* { dg-warning "incompatible" } */
  }
  { /* id <protocol>, non-ObjC : Shouldn't be part of this test. */
    num = objP1; /* { dg-warning "makes integer" } */
    objP1 = num; /* { dg-warning "makes pointer" } */

    ptr = objP1;
    objP1 = ptr;
  }
  { /* Class <protocol>, Class <protocol> */
    clsP1 = clsP2; /* { dg-warning "does not conform" } */
    clsP2 = clsP1; /* { dg-warning "does not conform" } */

    clsP1 = clsP5;
    clsP5 = clsP1; /* { dg-warning "does not conform" } */
  }
  { /* Class <protocol>, SomeClass * */
    mc1 = clsP1; /* { dg-warning "incompatible" } */
    clsP1 = mc1; /* { dg-warning "incompatible" } */
  }
  { /* Class <protocol>, id */
    obj = clsP1;
    clsP1 = obj;
  }
  { /* Class <protocol>, Class */
    cls = clsP1;
    clsP1 = cls;
  }
  { /* Class <protocol>, non-ObjC */
    num = clsP1; /* { dg-warning "makes integer" } */
    clsP1 = num; /* { dg-warning "makes pointer" } */

    ptr = clsP1;
    clsP1 = ptr;
  }
  { /* Class <protocol>, id <protocol> */
    clsP1 = objP1; /* { dg-warning "incompatible" } */
    objP1 = clsP1; /* { dg-warning "incompatible" } */
  }
}

int main ()
{
  testSimple();
  testCategory();
  testCategoryIncorporated();
  return(0);
}

/* { dg-warning "Messages without a matching" "" { target *-*-* } 0 } */
/* { dg-warning "will be assumed to return" "" { target *-*-* } 0 } */
/* { dg-warning "as arguments" "" { target *-*-* } 0 } */


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-06 17:12                                           ` David Ayers
@ 2004-10-11 21:57                                             ` Ziemowit Laski
  2004-10-12 16:40                                               ` David Ayers
  0 siblings, 1 reply; 35+ messages in thread
From: Ziemowit Laski @ 2004-10-11 21:57 UTC (permalink / raw)
  To: David Ayers, GCC Patches

[-- Attachment #1: Type: text/plain, Size: 2568 bytes --]

David, et al,

Sorry for the delay.  Attached please find a patch (_with_ ChangeLogs, 
this time) that
addresses some of the concerns you raised.

I say "some" because the compiler will still warn that "no `+foo' 
method found" in
some situations where you probably think it shouldn't (see 
class-protocol-1.m).  The
reason that I left things in this state is that I'd like to attack 
these superfluous
messages with a separate patch that enhances how protocols get used for 
message
lookup.  Because these enhancements will affect cases other than just 
'Class <Protocol>',
they deserve a separate e-mail thread and discussion, which I will 
start forthwith.

For now, though, it would be great if you could take the current patch 
for a spin.

Thanks,

--Zem

[gcc/ChangeLog]
2004-10-11  David Ayers  <d.ayers@inode.at>

	* c-common.h: Remove RID_ID.
	* c-parse.in: Remove OBJECTNAME and references to RID_ID.
	(typespec_reserved_attr): Add rule for TYPENAME
	non_empty_protocolrefs.
	(yylexname): Remove special handling of RID_ID.

[gcc/objc/ChangeLog]
2004-10-11  Ziemowit Laski  <zlaski@apple.com>
	    David Ayers  <d.ayers@inode.at>

	* objc-act.c (objc_comptypes): Use IS_PROTOCOL_QUALIFIED_UNTYPED
	instead of IS_PROTOCOL_QUALIFIED_ID; add comparisons for:
	'Class <Protocol> != id <Protocol>'; 'Class <Protocol> != <class> *';
	'Class <Protocol> != id'; 'Class <Protocol> = Class'.
	(objc_is_id): Add test for 'super'.
	(objc_finish_message_expr): Allow for messaging of 'Class <Proto>'
	receivers; if class methods are not found in protocol lists, search
	for instance methods therein and warn if one is found.  Look in
	global hash tables for suitable method as a last resort when messaging
	'id <Proto>', 'Class <Proto>' and invalid receiver types.
	* objc-act.h (IS_PROTOCOL_QUALIFIED_ID): Rename to
	IS_PROTOCOL_QUALIFIED_UNTYPED and allow for 'Class <Proto>' in
	addition to 'id <Proto>'.

[gcc/testsuite/ChangeLog]
2004-10-11  David Ayers  <d.ayers@inode.at>
	    Ziemowit Laski  <zlaski@apple.com>

	* objc.dg/call-super-2.m: Add messages to 'Class <Proto>'; update
	diagnostics when messaging 'id <Proto>'.
	* objc.dg/class-protocol-1.m: New test.
	* objc.dg/desig-init-1.m: Add message to an invalid receiver using
	a non-existent method signature.
	* objc.dg/method-5.m, objc.dg/method-6.m, objc.dg/proto-hier-1.m:
	Update diagnostics when messaging with non-existent method signature.
	* objc.dg/proto-lossage-1.m, objc.dg/proto-lossage-4.m: Messages to
	invalid receivers are now resolved as if messaging 'id'; remove
	extraneous diagnostics.


[-- Attachment #2: objc.20041011.diff.gz --]
[-- Type: application/x-gzip, Size: 7363 bytes --]

[-- Attachment #3: Type: text/plain, Size: 242 bytes --]



--------------------------------------------------------------
Ziemowit Laski                 1 Infinite Loop, MS 301-2K
Mac OS X Compiler Group        Cupertino, CA USA  95014-2083
Apple Computer, Inc.           +1.408.974.6229  Fax .5477

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-11 21:57                                             ` Ziemowit Laski
@ 2004-10-12 16:40                                               ` David Ayers
  2004-10-12 19:14                                                 ` Ziemowit Laski
  0 siblings, 1 reply; 35+ messages in thread
From: David Ayers @ 2004-10-12 16:40 UTC (permalink / raw)
  To: Ziemowit Laski; +Cc: GCC Patches

Ziemowit Laski wrote:

> I say "some" because the compiler will still warn that "no `+foo' 
> method found" in some situations where you probably think it
> shouldn't (see class-protocol-1.m). The reason that I left things in
> this state is that I'd like to attack these superfluous messages with
> a separate patch that enhances how protocols get used for message 
> lookup. Because these enhancements will affect cases other than just 
> 'Class <Protocol>', they deserve a separate e-mail thread and
> discussion, which I will start forthwith.

This is not an issue of "superfluous messages", it is a code gen issue.
 All other cases where the instance methods of root classes are
concerned already handle this correctly.  I fail to see why this needs
to be separated from the patch, in fact I find the patch incomplete (if
not broken) if it fails to handle these cases.  By "handle" I mean using
the correct prototype.  I have an opinion on emitting "superfluous
messages", but I can compromise either way on that.  I do expect the
compiler to use the prototype of the instance methods of those
protocols.  At least for protocols which are adopted by root classes, as
I'd compromise not to mark protocols and always use the instance
prototypes.  --- OK.  I'm going in circles.  Please let me know if I
haven't made myself clear yet and I'll try again.  But I think you
simply seem to be ignoring the importance of this issue looking at it
like a "nice to have".  I strongly disagree.

> 
> For now, though, it would be great if you could take the current patch 
> for a spin.
> 

I will have a look at it as soon as time permits.

Cheers,
David

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: Your 'Class <Protocol>' Work
  2004-10-12 16:40                                               ` David Ayers
@ 2004-10-12 19:14                                                 ` Ziemowit Laski
  0 siblings, 0 replies; 35+ messages in thread
From: Ziemowit Laski @ 2004-10-12 19:14 UTC (permalink / raw)
  To: David Ayers; +Cc: GCC Patches

On 12 Oct 2004, at 9.37, David Ayers wrote:

> Ziemowit Laski wrote:
>
>> I say "some" because the compiler will still warn that "no `+foo'
>> method found" in some situations where you probably think it
>> shouldn't (see class-protocol-1.m). The reason that I left things in
>> this state is that I'd like to attack these superfluous messages with
>> a separate patch that enhances how protocols get used for message
>> lookup. Because these enhancements will affect cases other than just
>> 'Class <Protocol>', they deserve a separate e-mail thread and
>> discussion, which I will start forthwith.
>
> This is not an issue of "superfluous messages", it is a code gen issue.
>  All other cases where the instance methods of root classes are
> concerned already handle this correctly.  I fail to see why this needs
> to be separated from the patch, in fact I find the patch incomplete (if
> not broken) if it fails to handle these cases.  By "handle" I mean 
> using
> the correct prototype.

With my most recent patch, messaging 'Class <ProtoList>' will first 
search
for a class method in ProtoList, then for an instance method in 
ProtoList,
and finally perform an unadorned 'Class' lookup.  If neither a class nor
an instance method is found in ProtoList, then I think the 'Class' (or,
similarly, 'id') lookup _should_ look in the hash table, at which point
no prototype chosen is any more "correct" than any other in the hash 
table.
Of course, if multiple prototypes are found, the compiler will warn and
tell you which one it is using.

> I do expect the
> compiler to use the prototype of the instance methods of those
> protocols.

It does that.

>   At least for protocols which are adopted by root classes, as
> I'd compromise not to mark protocols and always use the instance
> prototypes.  --- OK.  I'm going in circles.  Please let me know if I
> haven't made myself clear yet and I'll try again.  But I think you
> simply seem to be ignoring the importance of this issue looking at it
> like a "nice to have".  I strongly disagree.

I must say that I strongly disagree with the notion of "root 
protocols". :-(
Under that scheme, if a class method lookup in ProtoList (for a 'Class 
<ProtoList>'
receiver), then we look for instance methods in ProtoList, but only for 
those
protocols that were adopted by some root class, right?  So, at the 
message send
site, the user will have to remember which protocols have been adopted 
(directly
or indirectly!) by root classes and which have not in order to 
understand how
the compiler will select that particular method signature.  I find such
lack of determinism (at least from the end-user's viewpoint) 
objectionable.

Furthermore, I thought that you agreed that it was an acceptable 
compromise
to look at instance methods in all protocols in ProtoList (and warn 
appropriately)
if a class method is not found, which is what my current patch does.  
Why is
it that you now find this objectionable?

--Zem
--------------------------------------------------------------
Ziemowit Laski                 1 Infinite Loop, MS 301-2K
Mac OS X Compiler Group        Cupertino, CA USA  95014-2083
Apple Computer, Inc.           +1.408.974.6229  Fax .5477

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2004-10-12 19:14 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-09-27 19:35 Your 'Class <Protocol>' Work Ziemowit Laski
2004-09-28  9:01 ` David Ayers
2004-09-28 19:52   ` David Ayers
2004-09-28 19:56     ` Ziemowit Laski
2004-09-28 20:04     ` David Ayers
2004-09-28 20:13       ` Ziemowit Laski
2004-09-28 22:12         ` d.ayers
2004-09-28 22:35           ` Ziemowit Laski
2004-09-29  3:27       ` Ziemowit Laski
2004-09-29  9:12         ` Kai Henningsen
2004-09-29 19:40           ` Ziemowit Laski
2004-09-30  9:00             ` Kai Henningsen
2004-09-29 18:20         ` David Ayers
2004-09-29 21:25           ` Ziemowit Laski
2004-09-30  0:01             ` d.ayers
2004-09-30  7:17               ` Ziemowit Laski
2004-09-30 14:06                 ` David Ayers
2004-09-30 22:33                   ` Ziemowit Laski
     [not found]                     ` <81.223.113.201.1096587115.wm@webmail.inode.at>
     [not found]                       ` <81.223.113.201.1096588159.wm@webmail.inode.at>
2004-10-01  0:08                         ` Ziemowit Laski
2004-10-01  0:55                       ` Ziemowit Laski
2004-10-01  7:47                         ` Kai Henningsen
2004-10-01 18:03                           ` Ziemowit Laski
2004-10-01  9:02                         ` David Ayers
2004-10-01 18:30                           ` David Ayers
2004-10-01 20:50                             ` David Ayers
2004-10-02 17:35                               ` David Ayers
2004-10-04 19:51                                 ` Ziemowit Laski
2004-10-05  3:13                                   ` Ziemowit Laski
2004-10-05 16:37                                     ` David Ayers
2004-10-05 19:55                                       ` Ziemowit Laski
2004-10-05 20:44                                         ` d.ayers
2004-10-06 17:12                                           ` David Ayers
2004-10-11 21:57                                             ` Ziemowit Laski
2004-10-12 16:40                                               ` David Ayers
2004-10-12 19:14                                                 ` Ziemowit Laski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).