This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Your 'Class <Protocol>' Work


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


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.
	
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.
	
2004-09-29  David Ayers  <d.ayers@inode.at>

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

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 @@
 }
 
 /* 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)
 
/* 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: patch.tar.gz
Description: application/gunzip


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]