OSDN Git Service

PR optimization/4382
[pf3gnuchains/gcc-fork.git] / gcc / objc / objc-act.c
index 3909e0c..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"
@@ -90,9 +93,6 @@ Boston, MA 02111-1307, USA.  */
 
 #include "obstack.h"
 
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-
 /* This obstack is used to accumulate the encoding of a data type.  */
 static struct obstack util_obstack;
 /* This points to the beginning of obstack contents,
@@ -131,7 +131,6 @@ static tree build_objc_method_call          PARAMS ((int, tree, tree,
 static void generate_strings                   PARAMS ((void));
 static tree get_proto_encoding                         PARAMS ((tree));
 static void build_selector_translation_table   PARAMS ((void));
-static tree build_ivar_chain                   PARAMS ((tree, int));
 
 static tree objc_add_static_instance           PARAMS ((tree, tree));
 
@@ -252,7 +251,6 @@ static tree build_typed_selector_reference          PARAMS ((tree, tree));
 static tree build_selector_reference           PARAMS ((tree));
 static tree build_class_reference_decl         PARAMS ((void));
 static void add_class_reference                        PARAMS ((tree));
-static tree objc_copy_list                     PARAMS ((tree, tree *));
 static tree build_protocol_template            PARAMS ((void));
 static tree build_descriptor_table_initializer PARAMS ((tree, tree));
 static tree build_method_prototype_list_template PARAMS ((tree, int));
@@ -295,6 +293,7 @@ static void generate_classref_translation_entry     PARAMS ((tree));
 static void handle_class_ref                   PARAMS ((tree));
 static void generate_struct_by_value_array     PARAMS ((void))
      ATTRIBUTE_NORETURN;
+static void encode_complete_bitfield           PARAMS ((int, tree, int));
 
 /*** Private Interface (data) ***/
 
@@ -313,13 +312,11 @@ static void generate_struct_by_value_array        PARAMS ((void))
 #define UTAG_METHOD_LIST       "_objc_method_list"
 #define UTAG_CATEGORY          "_objc_category"
 #define UTAG_MODULE            "_objc_module"
-#define UTAG_STATICS           "_objc_statics"
 #define UTAG_SYMTAB            "_objc_symtab"
 #define UTAG_SUPER             "_objc_super"
 #define UTAG_SELECTOR          "_objc_selector"
 
 #define UTAG_PROTOCOL          "_objc_protocol"
-#define UTAG_PROTOCOL_LIST     "_objc_protocol_list"
 #define UTAG_METHOD_PROTOTYPE  "_objc_method_prototype"
 #define UTAG_METHOD_PROTOTYPE_LIST "_objc__method_prototype_list"
 
@@ -329,8 +326,6 @@ static void generate_struct_by_value_array  PARAMS ((void))
 
 #define PROTOCOL_OBJECT_CLASS_NAME "Protocol"
 
-static const char *constant_string_class_name = NULL;
-
 static const char *TAG_GETCLASS;
 static const char *TAG_GETMETACLASS;
 static const char *TAG_MSGSEND;
@@ -341,8 +336,6 @@ static const char *default_constant_string_class_name;
 /* The OCTI_... enumeration itself is in objc/objc-act.h.  */
 tree objc_global_trees[OCTI_MAX];
 
-int objc_receiver_context;
-
 static void handle_impent                      PARAMS ((struct imp_entry *));
 
 struct imp_entry *imp_list = 0;
@@ -363,33 +356,10 @@ extern enum debug_info_type write_symbols;
 
 extern const char *dump_base_name;
 \f
-/* Generate code for GNU or NeXT runtime environment.  */
-
-#ifdef NEXT_OBJC_RUNTIME
-int flag_next_runtime = 1;
-#else
-int flag_next_runtime = 0;
-#endif
-
-int flag_typed_selectors;
-
-/* Open and close the file for outputting class declarations, if requested.  */
-
-int flag_gen_declaration = 0;
+static int flag_typed_selectors;
 
 FILE *gen_declaration_file;
 
-/* Warn if multiple methods are seen for the same selector, but with
-   different argument types.  */
-
-int warn_selector = 0;
-
-/* Warn if methods required by a protocol are not implemented in the 
-   class adopting it.  When turned off, methods inherited to that
-   class are also considered implemented */
-
-int flag_warn_protocol = 1;
-
 /* Tells "encode_pointer/encode_aggregate" whether we are generating
    type descriptors for instance variables (as opposed to methods).
    Type descriptors for instance variables contain more information
@@ -397,12 +367,6 @@ int flag_warn_protocol = 1;
 
 static int generating_instance_variables = 0;
 
-/* Tells the compiler that this is a special run.  Do not perform any
-   compiling, instead we are to test some platform dependent features
-   and output a C header file with appropriate definitions.  */
-
-static int print_struct_values = 0;
-
 /* Some platforms pass small structures through registers versus
    through an invisible pointer.  Determine at what size structure is
    the transition point between the two possibilities.  */
@@ -471,6 +435,8 @@ objc_init (filename)
      const char *filename;
 {
   filename = c_objc_common_init (filename);
+  if (filename == NULL)
+    return filename;
 
   /* Force the line number back to 0; check_newline will have
      raised it to 1, which will make the builtin functions appear
@@ -530,47 +496,6 @@ finish_file ()
   if (gen_declaration_file)
     fclose (gen_declaration_file);
 }
-
-int
-objc_decode_option (argc, argv)
-     int argc;
-     char **argv;
-{
-  const char *p = argv[0];
-
-  if (!strcmp (p, "-gen-decls"))
-    flag_gen_declaration = 1;
-  else if (!strcmp (p, "-Wselector"))
-    warn_selector = 1;
-  else if (!strcmp (p, "-Wno-selector"))
-    warn_selector = 0;
-  else if (!strcmp (p, "-Wprotocol"))
-    flag_warn_protocol = 1;
-  else if (!strcmp (p, "-Wno-protocol"))
-    flag_warn_protocol = 0;
-  else if (!strcmp (p, "-fgnu-runtime"))
-    flag_next_runtime = 0;
-  else if (!strcmp (p, "-fno-next-runtime"))
-    flag_next_runtime = 0;
-  else if (!strcmp (p, "-fno-gnu-runtime"))
-    flag_next_runtime = 1;
-  else if (!strcmp (p, "-fnext-runtime"))
-    flag_next_runtime = 1;
-  else if (!strcmp (p, "-print-objc-runtime-info"))
-    print_struct_values = 1;
-#define CSTSTRCLASS "-fconstant-string-class="
-  else if (!strncmp (p, CSTSTRCLASS, sizeof(CSTSTRCLASS) - 2)) {
-    if (strlen (argv[0]) <= strlen (CSTSTRCLASS))
-      error ("no class name specified as argument to -fconstant-string-class");
-    constant_string_class_name = xstrdup(argv[0] + sizeof(CSTSTRCLASS) - 1);
-  }
-#undef CSTSTRCLASS
-  else
-    return c_decode_option (argc, argv);
-
-  return 1;
-}
-
 \f
 static tree
 define_decl (declarator, declspecs)
@@ -594,14 +519,6 @@ define_decl (declarator, declspecs)
    `a' and `b' are the same class type, or
    `a' and `b' are of class types A and B such that B is a descendant of A.  */
 
-int
-maybe_objc_comptypes (lhs, rhs, reflexive)
-     tree lhs, rhs;
-     int reflexive;
-{
-  return objc_comptypes (lhs, rhs, reflexive);
-}
-
 static tree
 lookup_method_in_protocol_list (rproto_list, sel_name, class_meth)
    tree rproto_list;
@@ -673,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)
@@ -686,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
@@ -700,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);
@@ -734,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);
@@ -748,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);
                        }
 
@@ -757,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;
@@ -822,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;
 }
 
@@ -840,13 +917,6 @@ objc_check_decl (decl)
     error_with_decl (decl, "`%s' cannot be statically allocated");
 }
 
-void
-maybe_objc_check_decl (decl)
-     tree decl;
-{
-  objc_check_decl (decl);
-}
-
 /* Implement static typing.  At this point, we know we have an interface.  */
 
 tree
@@ -861,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);
@@ -912,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);
@@ -1349,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));
@@ -1772,7 +1840,7 @@ get_objc_string_decl (ident, section)
   else
     abort ();
 
-  for (; chain != 0; chain = TREE_VALUE (chain))
+  for (; chain != 0; chain = TREE_CHAIN (chain))
     if (TREE_VALUE (chain) == ident)
       return (TREE_PURPOSE (chain));
 
@@ -1962,6 +2030,32 @@ build_selector_translation_table ()
     {
       tree expr;
 
+      if (warn_selector && objc_implementation_context)
+      {
+        tree method_chain;
+        bool found = false;
+        for (method_chain = meth_var_names_chain;
+             method_chain;
+             method_chain = TREE_CHAIN (method_chain))
+          {
+            if (TREE_VALUE (method_chain) == TREE_VALUE (chain))
+              {
+                found = true;
+                break;
+              }
+          }
+        if (!found)
+          {
+            /* Adjust line number for warning message.  */
+            int save_lineno = lineno;
+            if (flag_next_runtime && TREE_PURPOSE (chain))
+              lineno = DECL_SOURCE_LINE (TREE_PURPOSE (chain));
+            warning ("creating selector for non existant method %s",
+                     IDENTIFIER_POINTER (TREE_VALUE (chain)));
+            lineno = save_lineno;
+          }
+      }
+
       expr = build_selector (TREE_VALUE (chain));
 
       if (flag_next_runtime)
@@ -2045,8 +2139,8 @@ get_proto_encoding (proto)
    identifier_node that represent the selector.  */
 
 static tree
-build_typed_selector_reference (ident, proto)
-     tree ident, proto;
+build_typed_selector_reference (ident, prototype)
+     tree ident, prototype;
 {
   tree *chain = &sel_ref_chain;
   tree expr;
@@ -2054,14 +2148,14 @@ build_typed_selector_reference (ident, proto)
 
   while (*chain)
     {
-      if (TREE_PURPOSE (*chain) == ident && TREE_VALUE (*chain) == proto)
+      if (TREE_PURPOSE (*chain) == prototype && TREE_VALUE (*chain) == ident)
        goto return_at_index;
 
       index++;
       chain = &TREE_CHAIN (*chain);
     }
 
-  *chain = tree_cons (proto, ident, NULL_TREE);
+  *chain = tree_cons (prototype, ident, NULL_TREE);
 
  return_at_index:
   expr = build_unary_op (ADDR_EXPR,
@@ -2329,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;
 {
@@ -2342,51 +2447,23 @@ lookup_interface (ident)
   return NULL_TREE;
 }
 
-static tree
-objc_copy_list (list, head)
-     tree list;
-     tree *head;
-{
-  tree newlist = NULL_TREE, tail = NULL_TREE;
-
-  while (list)
-    {
-      tail = copy_node (list);
-
-      /* The following statement fixes a bug when inheriting instance
-        variables that are declared to be bitfields. finish_struct
-        expects to find the width of the bitfield in DECL_INITIAL.  */
-      if (DECL_BIT_FIELD (tail) && DECL_INITIAL (tail) == 0)
-       DECL_INITIAL (tail) = DECL_SIZE (tail);
-
-      newlist = chainon (newlist, tail);
-      list = TREE_CHAIN (list);
-    }
-
-  *head = newlist;
-  return tail;
-}
-
-/* Used by: build_private_template, get_class_ivars, and
-   continue_class.  COPY is 1 when called from @defs.  In this case
-   copy all fields.  Otherwise don't copy leaf ivars since we rely on
-   them being side-effected exactly once by finish_struct.  */
+/* Used by: build_private_template, continue_class,
+   and for @defs constructs.  */
 
-static tree
-build_ivar_chain (interface, copy)
+tree
+get_class_ivars (interface)
      tree interface;
-     int copy;
 {
   tree my_name, super_name, ivar_chain;
 
   my_name = CLASS_NAME (interface);
   super_name = CLASS_SUPER_NAME (interface);
+  ivar_chain = CLASS_IVARS (interface);
 
-  /* Possibly copy leaf ivars.  */
-  if (copy)
-    objc_copy_list (CLASS_IVARS (interface), &ivar_chain);
-  else
-    ivar_chain = CLASS_IVARS (interface);
+  /* Save off a pristine copy of the leaf ivars (i.e, those not
+     inherited from a super class).  */
+  if (!CLASS_OWN_IVARS (interface))
+    CLASS_OWN_IVARS (interface) = copy_list (ivar_chain);
 
   while (super_name)
     {
@@ -2410,14 +2487,14 @@ build_ivar_chain (interface, copy)
       my_name = CLASS_NAME (interface);
       super_name = CLASS_SUPER_NAME (interface);
 
-      op1 = CLASS_IVARS (interface);
+      op1 = CLASS_OWN_IVARS (interface);
       if (op1)
         {
-         tree head, tail = objc_copy_list (op1, &head);
+         tree head = copy_list (op1);
 
          /* Prepend super class ivars...make a copy of the list, we
             do not want to alter the original.  */
-         TREE_CHAIN (tail) = ivar_chain;
+         chainon (head, ivar_chain);
          ivar_chain = head;
         }
     }
@@ -2444,7 +2521,7 @@ build_private_template (class)
     {
       uprivate_record = start_struct (RECORD_TYPE, CLASS_NAME (class));
 
-      ivar_context = build_ivar_chain (class, 0);
+      ivar_context = get_class_ivars (class);
 
       finish_struct (uprivate_record, ivar_context, NULL_TREE);
 
@@ -2962,6 +3039,43 @@ generate_protocol_references (plist)
     }
 }
 
+/* For each protocol which was referenced either from a @protocol()
+   expression, or because a class/category implements it (then a
+   pointer to the protocol is stored in the struct describing the
+   class/category), we create a statically allocated instance of the
+   Protocol class.  The code is written in such a way as to generate
+   as few Protocol objects as possible; we generate a unique Protocol
+   instance for each protocol, and we don't generate a Protocol
+   instance if the protocol is never referenced (either from a
+   @protocol() or from a class/category implementation).  These
+   statically allocated objects can be referred to via the static
+   (that is, private to this module) symbols _OBJC_PROTOCOL_n.
+   
+   The statically allocated Protocol objects that we generate here
+   need to be fixed up at runtime in order to be used: the 'isa'
+  pointer of the objects need to be set up to point to the 'Protocol'
+   class, as known at runtime.
+
+   The NeXT runtime fixes up all protocols at program startup time,
+   before main() is entered.  It uses a low-level trick to look up all
+   those symbols, then loops on them and fixes them up.
+
+   The GNU runtime as well fixes up all protocols before user code
+   from the module is executed; it requires pointers to those symbols
+   to be put in the objc_symtab (which is then passed as argument to
+   the function __objc_exec_class() which the compiler sets up to be
+   executed automatically when the module is loaded); setup of those
+   Protocol objects happen in two ways in the GNU runtime: all
+   Protocol objects referred to by a class or category implementation
+   are fixed up when the class/category is loaded; all Protocol
+   objects referred to by a @protocol() expression are added by the
+   compiler to the list of statically allocated instances to fixup
+   (the same list holding the statically allocated constant string
+   objects).  Because, as explained above, the compiler generates as
+   few Protocol objects as possible, some Protocol object might end up
+   being referenced multiple times when compiled with the GNU runtime,
+   and end up being fixed up multiple times at runtime inizialization.
+   But that doesn't hurt, it's just a little inefficient.  */
 static void
 generate_protocols ()
 {
@@ -3434,10 +3548,6 @@ error_with_ivar (message, decl, rawdecl)
 
 }
 
-#define USERTYPE(t) \
- (TREE_CODE (t) == RECORD_TYPE || TREE_CODE (t) == UNION_TYPE \
-  ||  TREE_CODE (t) == ENUMERAL_TYPE)
-
 static void
 check_ivars (inter, imp)
      tree inter;
@@ -4467,6 +4577,10 @@ adjust_type_for_id_default (type)
        chain;
        chain = TREE_CHAIN (chain))
     {
+      if (TYPED_OBJECT (TREE_VALUE (chain))
+          && !(TREE_VALUE (type) 
+               && TREE_CODE (TREE_VALUE (type)) == INDIRECT_REF))
+        error ("can not use an object as parameter to a method\n");
       if (!is_objc_type_qualifier (TREE_VALUE (chain)))
        return type;
     }
@@ -4737,12 +4851,12 @@ receiver_is_class_object (receiver)
    the identifier of the selector of the message.  This is
    used when printing warnings about argument mismatches.  */
 
-static tree building_objc_message_expr = 0;
+static tree current_objc_message_selector = 0;
 
 tree
-maybe_building_objc_message_expr ()
+objc_message_selector ()
 {
-  return building_objc_message_expr;
+  return current_objc_message_selector;
 }
 
 /* Construct an expression for sending a message.
@@ -4883,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);
@@ -5018,7 +5132,7 @@ finish_message_expr (receiver, sel_name, method_params)
     }
 
   /* Save the selector name for printing error messages.  */
-  building_objc_message_expr = sel_name;
+  current_objc_message_selector = sel_name;
 
   /* Build the parameters list for looking up the method.
      These are the object itself and the selector.  */
@@ -5032,7 +5146,7 @@ finish_message_expr (receiver, sel_name, method_params)
                                   receiver, self_object,
                                   selector, method_params);
 
-  building_objc_message_expr = 0;
+  current_objc_message_selector = 0;
 
   return retval;
 }
@@ -5176,6 +5290,8 @@ build_protocol_reference (p)
   PROTOCOL_FORWARD_DECL (p) = decl;
 }
 
+/* This function is called by the parser when (and only when) a
+   @protocol() expression is found, in order to compile it.  */
 tree
 build_protocol_expr (protoname)
      tree protoname;
@@ -5197,9 +5313,56 @@ build_protocol_expr (protoname)
 
   TREE_TYPE (expr) = protocol_type;
 
+  /* The @protocol() expression is being compiled into a pointer to a
+     statically allocated instance of the Protocol class.  To become
+     usable at runtime, the 'isa' pointer of the instance need to be
+     fixed up at runtime by the runtime library, to point to the
+     actual 'Protocol' class.  */
+
+  /* For the GNU runtime, put the static Protocol instance in the list
+     of statically allocated instances, so that we make sure that its
+     'isa' pointer is fixed up at runtime by the GNU runtime library
+     to point to the Protocol class (at runtime, when loading the
+     module, the GNU runtime library loops on the statically allocated
+     instances (as found in the defs field in objc_symtab) and fixups
+     all the 'isa' pointers of those objects).  */
+  if (! flag_next_runtime)
+    {
+      /* This type is a struct containing the fields of a Protocol
+        object.  (Cfr. protocol_type instead is the type of a pointer
+        to such a struct).  */
+      tree protocol_struct_type = xref_tag 
+       (RECORD_TYPE, get_identifier (PROTOCOL_OBJECT_CLASS_NAME));
+      tree *chain;
+      
+      /* Look for the list of Protocol statically allocated instances
+        to fixup at runtime.  Create a new list to hold Protocol
+        statically allocated instances, if the list is not found.  At
+        present there is only another list, holding NSConstantString
+        static instances to be fixed up at runtime.  */
+      for (chain = &objc_static_instances;
+          *chain && TREE_VALUE (*chain) != protocol_struct_type;
+          chain = &TREE_CHAIN (*chain));
+      if (!*chain)
+       {
+         *chain = tree_cons (NULL_TREE, protocol_struct_type, NULL_TREE);
+         add_objc_string (TYPE_NAME (protocol_struct_type),
+                          class_names);
+       }
+      
+      /* Add this statically allocated instance to the Protocol list.  */
+      TREE_PURPOSE (*chain) = tree_cons (NULL_TREE, 
+                                        PROTOCOL_FORWARD_DECL (p),
+                                        TREE_PURPOSE (*chain));
+    }
+  
+
   return expr;
 }
 
+/* This function is called by the parser when a @selector() expression
+   is found, in order to compile it.  It is only called by the parser
+   and only to compile a @selector().  */
 tree
 build_selector_expr (selnamelist)
      tree selnamelist;
@@ -5215,6 +5378,32 @@ build_selector_expr (selnamelist)
   else
     abort ();
 
+  /* If we are required to check @selector() expressions as they
+     are found, check that the selector has been declared.  */
+  if (warn_undeclared_selector)
+    {
+      /* Look the selector up in the list of all known class and
+         instance methods (up to this line) to check that the selector
+         exists.  */
+      hash hsh;
+
+      /* First try with instance methods.  */
+      hsh = hash_lookup (nst_method_hash_list, selname);
+      
+      /* If not found, try with class methods.  */
+      if (!hsh)
+       {
+         hsh = hash_lookup (cls_method_hash_list, selname);
+       }
+      
+      /* If still not found, print out a warning.  */
+      if (!hsh)
+       {
+         warning ("undeclared selector `%s'", IDENTIFIER_POINTER (selname));
+       }
+    }
+  
+
   if (flag_typed_selectors)
     return build_typed_selector_reference (selname, 0);
   else
@@ -5354,6 +5543,7 @@ lookup_method (mchain, method)
     {
       if (METHOD_SEL_NAME (mchain) == key)
        return mchain;
+
       mchain = TREE_CHAIN (mchain);
     }
   return NULL_TREE;
@@ -5725,18 +5915,6 @@ is_public (expr, identifier)
 
   return 1;
 }
-
-/* Implement @defs (<classname>) within struct bodies.  */
-
-tree
-get_class_ivars (interface)
-     tree interface;
-{
-  /* Make sure we copy the leaf ivars in case @defs is used in a local
-     context.  Otherwise finish_struct will overwrite the layout info
-     using temporary storage.  */
-  return build_ivar_chain (interface, 1);
-}
 \f
 /* Make sure all entries in CHAIN are also in LIST.  */
 
@@ -5883,7 +6061,7 @@ check_protocol (p, type, name)
       int f1, f2;
 
       /* Ensure that all protocols have bodies!  */
-      if (flag_warn_protocol)
+      if (warn_protocol)
        {
          f1 = check_methods (PROTOCOL_CLS_METHODS (p),
                              CLASS_CLS_METHODS (objc_implementation_context),
@@ -5968,7 +6146,7 @@ start_class (code, class_name, super_name, protocol_list)
     }
 
   class = make_node (code);
-  TYPE_BINFO (class) = make_tree_vec (5);
+  TYPE_BINFO (class) = make_tree_vec (6);
 
   CLASS_NAME (class) = class_name;
   CLASS_SUPER_NAME (class) = super_name;
@@ -6158,7 +6336,7 @@ continue_class (class)
 
       if (!TYPE_FIELDS (record))
        {
-         finish_struct (record, build_ivar_chain (class, 0), NULL_TREE);
+         finish_struct (record, get_class_ivars (class), NULL_TREE);
          CLASS_STATIC_TEMPLATE (class) = record;
 
          /* Mark this record as a class template for static typing.  */
@@ -6709,7 +6887,10 @@ encode_type (type, curtype, format)
 }
 
 static void
-encode_complete_bitfield (int position, tree type, int size)
+encode_complete_bitfield (position, type, size)
+     int position;
+     tree type;
+     int size;
 {
   enum tree_code code = TREE_CODE (type);
   char buffer[40];
@@ -6779,14 +6960,14 @@ encode_field_decl (field_decl, curtype, format)
      the bitfield typing information.  */
   if (flag_next_runtime)
     {
-      if (DECL_BIT_FIELD (field_decl))
+      if (DECL_BIT_FIELD_TYPE (field_decl))
        encode_bitfield (tree_low_cst (DECL_SIZE (field_decl), 1));
       else
        encode_type (TREE_TYPE (field_decl), curtype, format);
     }
   else
     {
-      if (DECL_BIT_FIELD (field_decl))
+      if (DECL_BIT_FIELD_TYPE (field_decl))
        encode_complete_bitfield (int_bit_position (field_decl),
                                  DECL_BIT_FIELD_TYPE (field_decl),
                                  tree_low_cst (DECL_SIZE (field_decl), 1));
@@ -7146,9 +7327,13 @@ get_super_receiver ()
            {
              super_class = get_class_reference (super_name);
              if (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)
+               /* Cast the super class to 'id', since the user may not have
+                  included <objc/objc-class.h>, leaving 'struct objc_class'
+                  an incomplete type.  */
                super_class
-                 = build_component_ref (build_indirect_ref (super_class, "->"),
-                                        get_identifier ("isa"));
+                 = build_component_ref (build_indirect_ref 
+                                        (build_c_cast (id_type, super_class), "->"),
+                                         get_identifier ("isa"));
            }
          else
            {
@@ -7906,12 +8091,21 @@ gen_method_decl (method, buf)
 \f
 /* Debug info.  */
 
+
+/* Dump an @interface declaration of the supplied class CHAIN to the
+   supplied file FP.  Used to implement the -gen-decls option (which
+   prints out an @interface declaration of all classes compiled in
+   this run); potentially useful for debugging the compiler too.  */
 static void
 dump_interface (fp, chain)
      FILE *fp;
      tree chain;
 {
-  char *buf = (char *) xmalloc (256);
+  /* FIXME: A heap overflow here whenever a method (or ivar)
+     declaration is so long that it doesn't fit in the buffer.  The
+     code and all the related functions should be rewritten to avoid
+     using fixed size buffers.  */
+  char *buf = (char *) xmalloc (1024 * 10);
   const char *my_name = IDENTIFIER_POINTER (CLASS_NAME (chain));
   tree ivar_decls = CLASS_RAW_IVARS (chain);
   tree nst_methods = CLASS_NST_METHODS (chain);
@@ -7919,14 +8113,26 @@ dump_interface (fp, chain)
 
   fprintf (fp, "\n@interface %s", my_name);
 
+  /* CLASS_SUPER_NAME is used to store the superclass name for 
+     classes, and the category name for categories.  */
   if (CLASS_SUPER_NAME (chain))
     {
-      const char *super_name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (chain));
-      fprintf (fp, " : %s\n", super_name);
+      const char *name = IDENTIFIER_POINTER (CLASS_SUPER_NAME (chain));
+      
+      if (TREE_CODE (chain) == CATEGORY_IMPLEMENTATION_TYPE 
+         || TREE_CODE (chain) == CATEGORY_INTERFACE_TYPE)
+       {
+         fprintf (fp, " (%s)\n", name);
+       }
+      else
+       {
+         fprintf (fp, " : %s\n", name);
+       }
     }
   else
     fprintf (fp, "\n");
 
+  /* FIXME - the following doesn't seem to work at the moment.  */
   if (ivar_decls)
     {
       fprintf (fp, "{\n");
@@ -7950,7 +8156,8 @@ dump_interface (fp, chain)
       fprintf (fp, "+ %s;\n", gen_method_decl (cls_methods, buf));
       cls_methods = TREE_CHAIN (cls_methods);
     }
-  fprintf (fp, "\n@end");
+
+  fprintf (fp, "@end\n");
 }
 
 /* Demangle function for Objective-C */
@@ -8070,7 +8277,16 @@ finish_objc ()
 
       UOBJC_CLASS_decl = impent->class_decl;
       UOBJC_METACLASS_decl = impent->meta_decl;
-
+      
+      /* Dump the @interface of each class as we compile it, if the
+        -gen-decls option is in use.  TODO: Dump the classes in the
+         order they were found, rather than in reverse order as we
+         are doing now.  */
+      if (flag_gen_declaration)
+       {
+         dump_interface (gen_declaration_file, objc_implementation_context);
+       }
+      
       if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE)
        {
          /* all of the following reference the string pool...  */
@@ -8121,12 +8337,6 @@ finish_objc ()
 
   generate_strings ();
 
-  if (flag_gen_declaration)
-    {
-      add_class (objc_implementation_context);
-      dump_interface (gen_declaration_file, objc_implementation_context);
-    }
-
   if (warn_selector)
     {
       int slot;
@@ -8311,8 +8521,8 @@ lookup_objc_ivar (id)
 {
   tree decl;
 
-  if (objc_receiver_context && !strcmp (IDENTIFIER_POINTER (id), "super"))
-    /* we have a message to super */
+  if (objc_method_context && !strcmp (IDENTIFIER_POINTER (id), "super"))
+    /* We have a message to super.  */
     return get_super_receiver ();
   else if (objc_method_context && (decl = is_ivar (objc_ivar_chain, id)))
     {