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:

> 
> 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

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.

2004-09-28  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	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)
 
/* 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: 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]