OSDN Git Service

PR optimization/4382
[pf3gnuchains/gcc-fork.git] / gcc / objc / objc-act.c
index 6b4d76c..3a5de01 100644 (file)
@@ -1,22 +1,22 @@
 /* Implement classes and message passing for Objective C.
-   Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002
-   Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1994, 1995, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003 Free Software Foundation, Inc.
    Contributed by Steve Naroff.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
+GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2, or (at your option)
 any later version.
 
-GNU CC is distributed in the hope that it will be useful,
+GCC is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
+along with GCC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
@@ -41,6 +41,8 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "rtl.h"
 #include "expr.h"
@@ -54,6 +56,7 @@ Boston, MA 02111-1307, USA.  */
 #include "output.h"
 #include "toplev.h"
 #include "ggc.h"
+#include "varray.h"
 #include "debug.h"
 #include "target.h"
 #include "diagnostic.h"
@@ -587,10 +590,24 @@ lookup_protocol_in_reflist (rproto_list, lproto)
   return 0;
 }
 
-/* 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.  When the operation
-   is REFLEXIVE, check for compatibility in either direction.  */
+/* 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
+   REFLEXIVE (typically comparisons), check for compatibility in
+   either direction; when it's not (typically assignments), don't.
+
+   This function is called in two cases: when both lhs and rhs are
+   pointers to records (in which case we check protocols too), and
+   when both lhs and rhs are records (in which case we check class
+   inheritance only).
+
+   Warnings about classes/protocols not implementing a protocol are
+   emitted here (multiple of those warnings might be emitted for a
+   single line!); generic warnings about incompatible assignments and
+   lacks of casts in comparisons are/must be emitted by the caller if
+   we return 0.
+*/
 
 int
 objc_comptypes (lhs, rhs, reflexive)
@@ -600,6 +617,8 @@ objc_comptypes (lhs, rhs, reflexive)
 {
   /* New clause for protocols.  */
 
+  /* Here we manage the case of a POINTER_TYPE = POINTER_TYPE.  We only
+     manage the ObjC ones, and leave the rest to the C code.  */
   if (TREE_CODE (lhs) == POINTER_TYPE
       && TREE_CODE (TREE_TYPE (lhs)) == RECORD_TYPE
       && TREE_CODE (rhs) == POINTER_TYPE
@@ -614,29 +633,75 @@ objc_comptypes (lhs, rhs, reflexive)
          tree rproto, rproto_list;
          tree p;
 
+         /* <Protocol> = <Protocol>  */
          if (rhs_is_proto)
            {
              rproto_list = TYPE_PROTOCOL_LIST (rhs);
-
-             /* Make sure the protocol is supported by the object
-                on the rhs.  */
-             for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto))
+             
+             if (!reflexive)
                {
-                 p = TREE_VALUE (lproto);
-                 rproto = lookup_protocol_in_reflist (rproto_list, p);
+                 /* 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)));
+                     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)))
            {
              tree rname = TYPE_NAME (TREE_TYPE (rhs));
              tree rinter;
 
-             /* Make sure the protocol is supported by the object
-                on the rhs.  */
+             /* Make sure the protocol is supported by the object on
+                the rhs.  */
              for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto))
                {
                  p = TREE_VALUE (lproto);
@@ -648,13 +713,16 @@ objc_comptypes (lhs, rhs, reflexive)
                      tree cat;
 
                      rproto_list = CLASS_PROTOCOL_LIST (rinter);
-                     /* If the underlying ObjC class does not have
-                        protocols attached to it, perhaps there are
-                        "one-off" protocols attached to the rhs?
-                        E.g., 'id<MyProt> foo;'.  */
-                     if (!rproto_list)
-                       rproto_list = TYPE_PROTOCOL_LIST (TREE_TYPE (rhs));
                      rproto = lookup_protocol_in_reflist (rproto_list, p);
+                     /* If the underlying ObjC class does not have
+                        the protocol we're looking for, check for "one-off"
+                        protocols (e.g., `NSObject<MyProt> *foo;') attached
+                        to the rhs.  */
+                     if (!rproto)
+                       {
+                         rproto_list = TYPE_PROTOCOL_LIST (TREE_TYPE (rhs));
+                         rproto = lookup_protocol_in_reflist (rproto_list, p);
+                       }
 
                      /* Check for protocols adopted by categories.  */
                      cat = CLASS_CATEGORY_LIST (rinter);
@@ -662,7 +730,6 @@ objc_comptypes (lhs, rhs, reflexive)
                        {
                          rproto_list = CLASS_PROTOCOL_LIST (cat);
                          rproto = lookup_protocol_in_reflist (rproto_list, p);
-
                          cat = CLASS_CATEGORY_LIST (cat);
                        }
 
@@ -671,31 +738,127 @@ objc_comptypes (lhs, rhs, reflexive)
 
                  if (!rproto)
                    warning ("class `%s' does not implement the `%s' protocol",
-                            IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (rhs))),
-                            IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+                            IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (rhs))),
+                            IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
                }
+             return 1;
            }
-
-         /* May change...based on whether there was any mismatch */
-          return 1;
+         /* <Protocol> = id */
+         else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_object_id)
+           {
+             return 1;
+           }
+         /* <Protocol> = Class */
+         else if (TYPE_NAME (TREE_TYPE (rhs)) == objc_class_id)
+           {
+             return 0;
+           }
+         /* <Protocol> = ?? : let comptypes decide.  */
+          return -1;
         }
       else if (rhs_is_proto)
-       /* Lhs is not a protocol...warn if it is statically typed */
-       return (TYPED_OBJECT (TREE_TYPE (lhs)) != 0);
+       {
+         /* <class> * = <Protocol> */
+         if (TYPED_OBJECT (TREE_TYPE (lhs)))
+           {
+             if (reflexive)
+               {
+                 tree rname = TYPE_NAME (TREE_TYPE (lhs));
+                 tree rinter;
+                 tree rproto, rproto_list = TYPE_PROTOCOL_LIST (rhs);
+                 
+                 /* Make sure the protocol is supported by the object on
+                    the lhs.  */
+                 for (rproto = rproto_list; rproto; 
+                      rproto = TREE_CHAIN (rproto))
+                   {
+                     tree p = TREE_VALUE (rproto);
+                     tree lproto = 0;
+                     rinter = lookup_interface (rname);
 
+                     while (rinter && !lproto)
+                       {
+                         tree cat;
+
+                         tree lproto_list = CLASS_PROTOCOL_LIST (rinter);
+                         lproto = lookup_protocol_in_reflist (lproto_list, p);
+                         /* If the underlying ObjC class does not
+                            have the protocol we're looking for,
+                            check for "one-off" protocols (e.g.,
+                            `NSObject<MyProt> *foo;') attached to the
+                            lhs.  */
+                         if (!lproto)
+                           {
+                             lproto_list = TYPE_PROTOCOL_LIST 
+                               (TREE_TYPE (lhs));
+                             lproto = lookup_protocol_in_reflist 
+                               (lproto_list, p);
+                           }
+
+                         /* Check for protocols adopted by categories.  */
+                         cat = CLASS_CATEGORY_LIST (rinter);
+                         while (cat && !lproto)
+                           {
+                             lproto_list = CLASS_PROTOCOL_LIST (cat);
+                             lproto = lookup_protocol_in_reflist (lproto_list,
+                                                                  p);
+                             cat = CLASS_CATEGORY_LIST (cat);
+                           }
+                         
+                         rinter = lookup_interface (CLASS_SUPER_NAME 
+                                                    (rinter));
+                       }
+                     
+                     if (!lproto)
+                       warning ("class `%s' does not implement the `%s' protocol",
+                                IDENTIFIER_POINTER (TYPE_NAME 
+                                                    (TREE_TYPE (lhs))),
+                                IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+                   }
+                 return 1;
+               }
+             else
+               return 0;
+           }
+         /* id = <Protocol> */
+         else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_object_id)
+           {
+             return 1;
+           }
+         /* Class = <Protocol> */
+         else if (TYPE_NAME (TREE_TYPE (lhs)) == objc_class_id)
+           {
+             return 0;
+           }
+         /* ??? = <Protocol> : let comptypes decide */
+         else
+           {
+             return -1;
+           }
+       }
       else
-       /* Defer to comptypes.  */
-       return -1;
+       {
+         /* Attention: we shouldn't defer to comptypes here.  One bad
+            side effect would be that we might loose the REFLEXIVE
+            information.
+         */
+         lhs = TREE_TYPE (lhs);
+         rhs = TREE_TYPE (rhs);
+       }
     }
 
-  else if (TREE_CODE (lhs) == RECORD_TYPE && TREE_CODE (rhs) == RECORD_TYPE)
-    ; /* Fall thru.  This is the case we have been handling all along */
-  else
-    /* Defer to comptypes.  */
-    return -1;
-
-  /* `id' = `<class> *', `<class> *' = `id' */
+  if (TREE_CODE (lhs) != RECORD_TYPE || TREE_CODE (rhs) != RECORD_TYPE)
+    {
+      /* Nothing to do with ObjC - let immediately comptypes take
+        responsibility for checking.  */
+      return -1;
+    }
 
+  /* `id' = `<class> *' `<class> *' = `id': always allow it.
+     Please note that 
+     'Object *o = [[Object alloc] init]; falls
+     in the case <class> * = `id'.
+  */
   if ((TYPE_NAME (lhs) == objc_object_id && TYPED_OBJECT (rhs))
       || (TYPE_NAME (rhs) == objc_object_id && TYPED_OBJECT (lhs)))
     return 1;
@@ -736,7 +899,7 @@ objc_comptypes (lhs, rhs, reflexive)
       return 0;
     }
   else
-    /* Defer to comptypes.  */
+    /* Not an ObjC type - let comptypes do the check.  */
     return -1;
 }
 
@@ -768,7 +931,6 @@ get_static_reference (interface, protocols)
       tree t, m = TYPE_MAIN_VARIANT (type);
 
       t = copy_node (type);
-      TYPE_BINFO (t) = make_tree_vec (2);
 
       /* Add this type to the chain of variants of TYPE.  */
       TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
@@ -819,7 +981,6 @@ get_object_reference (protocols)
       tree t, m = TYPE_MAIN_VARIANT (type);
 
       t = copy_node (type);
-      TYPE_BINFO (t) = make_tree_vec (2);
 
       /* Add this type to the chain of variants of TYPE.  */
       TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (m);
@@ -1256,7 +1417,7 @@ build_constructor (type, elts)
   else
     {
       f = TYPE_FIELDS (type);
-      for (e = elts; e ; e = TREE_CHAIN (e), f = TREE_CHAIN (f))
+      for (e = elts; e && f; e = TREE_CHAIN (e), f = TREE_CHAIN (f))
        if (TREE_CODE (TREE_TYPE (f)) == POINTER_TYPE
            || TREE_CODE (TREE_TYPE (f)) == INTEGER_TYPE)
          TREE_VALUE (e) = convert (TREE_TYPE (f), TREE_VALUE (e));
@@ -2262,6 +2423,17 @@ is_class_name (ident)
 }
 
 tree
+objc_is_id (ident)
+     tree ident;
+{
+  /* NB: This function may be called before the ObjC front-end
+     has been initialized, in which case ID_TYPE will be NULL. */
+  return (id_type && ident && TYPE_P (ident) && IS_ID (ident)) 
+         ? id_type 
+         : NULL_TREE;
+}
+
+tree
 lookup_interface (ident)
      tree ident;
 {
@@ -4825,7 +4997,7 @@ finish_message_expr (receiver, sel_name, method_params)
       if (iface)
        method_prototype = lookup_instance_method_static (iface, sel_name);
 
-      if (! method_prototype && TYPE_PROTOCOL_LIST (ctype))
+      if (! method_prototype && ctype && TYPE_PROTOCOL_LIST (ctype))
        method_prototype
          = lookup_method_in_protocol_list (TYPE_PROTOCOL_LIST (ctype),
                                            sel_name, 0);