OSDN Git Service

In gcc/c-family/:
[pf3gnuchains/gcc-fork.git] / gcc / objc / objc-act.c
index 0e32c23..f75fa75 100644 (file)
@@ -46,7 +46,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "toplev.h"
 #include "ggc.h"
 #include "debug.h"
-#include "target.h"
+#include "c-family/c-target.h"
 #include "diagnostic-core.h"
 #include "intl.h"
 #include "cgraph.h"
@@ -147,7 +147,6 @@ static void objc_gen_property_data (tree, tree);
 static void objc_synthesize_getter (tree, tree, tree);
 static void objc_synthesize_setter (tree, tree, tree);
 static char *objc_build_property_setter_name (tree);
-static int match_proto_with_proto (tree, tree, int);
 static tree lookup_property (tree, tree);
 static tree lookup_property_in_list (tree, tree);
 static tree lookup_property_in_protocol_list (tree, tree);
@@ -330,8 +329,9 @@ generate_struct_by_value_array (void)
   int aggregate_in_mem[32];
   int found = 0;
 
-  /* ??? as an example, m64/ppc/Darwin can pass up to 8*long+13*double in regs.
-     Presumably no platform passes 32 byte structures in a register.  */
+  /* Presumably no platform passes 32 byte structures in a register.  */
+  /* ??? As an example, m64/ppc/Darwin can pass up to 8*long+13*double
+     in registers.  */
   for (i = 1; i < 32; i++)
     {
       char buffer[5];
@@ -379,8 +379,24 @@ objc_init (void)
 #endif
     return false;
 
+  /* print_struct_values is triggered by -print-runtime-info (used
+     when building libobjc, with an empty file as input).  It does not
+     require any ObjC setup, and it never returns.
+
+     -fcompare-debug is used to check the compiler output; we are
+     executed twice, once with flag_compare_debug set, and once with
+     it not set.  If the flag is used together with
+     -print-runtime-info, we want to print the runtime info only once,
+     else it would be output in duplicate.  So we check
+     flag_compare_debug to output it in only one of the invocations.
+
+     As a side effect, this also that means -fcompare-debug
+     -print-runtime-info will run the compiler twice, and compare the
+     generated assembler file; the first time the compiler exits
+     immediately (producing no file), and the second time it compiles
+     an empty file.  This checks, as a side effect, that compiling an
+     empty file produces no assembler output.  */
   if (print_struct_values && !flag_compare_debug)
-    /* This routine does not require any ObjC set-up and never returns.  */
     generate_struct_by_value_array ();
 
   /* Set up stuff used by FE parser and all runtimes.  */
@@ -449,6 +465,8 @@ objc_write_global_declarations (void)
      and code if only checking syntax, or if generating a PCH file.  */
   if (!flag_syntax_only && !pch_file)
     {
+      location_t saved_location;
+
       /* If gen_declaration desired, open the output file.  */
       if (flag_gen_declaration)
        {
@@ -458,8 +476,24 @@ objc_write_global_declarations (void)
            fatal_error ("can%'t open %s: %m", dumpname);
          free (dumpname);
        }
+
+      /* Set the input location to BUILTINS_LOCATION.  This is good
+        for error messages, in case any is generated while producing
+        the metadata, but it also silences warnings that would be
+        produced when compiling with -Wpadded in case when padding is
+        automatically added to the built-in runtime data structure
+        declarations.  We know about this padding, and it is fine; we
+        don't want users to see any warnings about it if they use
+        -Wpadded.  */
+      saved_location = input_location;
+      input_location = BUILTINS_LOCATION;
+
       /* Compute and emit the meta-data tables for this runtime.  */
       (*runtime.generate_metadata) ();
+
+      /* Restore the original location, just in case it mattered.  */
+      input_location = saved_location;
+
       /* ... and then close any declaration file we opened.  */
       if (gen_declaration_file)
        fclose (gen_declaration_file);
@@ -1773,49 +1807,71 @@ objc_maybe_build_modify_expr (tree lhs, tree rhs)
       to get these to work with very little effort, we build a
       compound statement which does the setter call (to set the
       property to 'rhs'), but which can also be evaluated returning
-      the 'rhs'.  So, we want to create the following:
+      the 'rhs'.  If the 'rhs' has no side effects, we can simply
+      evaluate it twice, building
+
+      ([object setProperty: rhs]; rhs)
+
+      If it has side effects, we put it in a temporary variable first,
+      so we create the following:
 
       (temp = rhs; [object setProperty: temp]; temp)
+
+      setter_argument is rhs in the first case, and temp in the second
+      case.
       */
-      tree temp_variable_decl, bind;
+      tree setter_argument;
+
       /* s1, s2 and s3 are the tree statements that we need in the
         compound expression.  */
       tree s1, s2, s3, compound_expr;
+
+      if (TREE_SIDE_EFFECTS (rhs))
+       {
+         tree bind;
       
-      /* TODO: If 'rhs' is a constant, we could maybe do without the
-        'temp' variable ? */
-
-      /* Declare __objc_property_temp in a local bind.  */
-      temp_variable_decl = objc_create_temporary_var (TREE_TYPE (rhs), "__objc_property_temp");
-      DECL_SOURCE_LOCATION (temp_variable_decl) = input_location;
-      bind = build3 (BIND_EXPR, void_type_node, temp_variable_decl, NULL, NULL);
-      SET_EXPR_LOCATION (bind, input_location);
-      TREE_SIDE_EFFECTS (bind) = 1;
-      add_stmt (bind);
+         /* Declare __objc_property_temp in a local bind.  */
+         setter_argument = objc_create_temporary_var (TREE_TYPE (rhs), "__objc_property_temp");
+         DECL_SOURCE_LOCATION (setter_argument) = input_location;
+         bind = build3 (BIND_EXPR, void_type_node, setter_argument, NULL, NULL);
+         SET_EXPR_LOCATION (bind, input_location);
+         TREE_SIDE_EFFECTS (bind) = 1;
+         add_stmt (bind);
+
+         /* s1: x = rhs */
+         s1 = build_modify_expr (input_location, setter_argument, NULL_TREE,
+                                 NOP_EXPR,
+                                 input_location, rhs, NULL_TREE);
+         SET_EXPR_LOCATION (s1, input_location);
+       }
+      else
+       {
+         /* No s1.  */
+         setter_argument = rhs;
+         s1 = NULL_TREE;
+       }
       
       /* Now build the compound statement.  */
-      
-      /* s1: __objc_property_temp = rhs */
-      s1 = build_modify_expr (input_location, temp_variable_decl, NULL_TREE,
-                             NOP_EXPR,
-                             input_location, rhs, NULL_TREE);
-      SET_EXPR_LOCATION (s1, input_location);
   
-      /* s2: [object setProperty: __objc_property_temp] */
-      s2 = objc_build_setter_call (lhs, temp_variable_decl);
-
-      /* This happens if building the setter failed because the property
-        is readonly.  */
+      /* s2: [object setProperty: x] */
+      s2 = objc_build_setter_call (lhs, setter_argument);
+      
+      /* This happens if building the setter failed because the
+        property is readonly.  */
       if (s2 == error_mark_node)
        return error_mark_node;
 
       SET_EXPR_LOCATION (s2, input_location);
   
-      /* s3: __objc_property_temp */
-      s3 = convert (TREE_TYPE (lhs), temp_variable_decl);
+      /* s3: x */
+      s3 = convert (TREE_TYPE (lhs), setter_argument);
 
-      /* Now build the compound statement (s1, s2, s3) */
-      compound_expr = build_compound_expr (input_location, build_compound_expr (input_location, s1, s2), s3);
+      /* Now build the compound statement (s1, s2, s3) or (s2, s3) as
+        appropriate.  */
+      if (s1)
+       compound_expr = build_compound_expr (input_location, build_compound_expr (input_location, s1, s2), s3);
+      else
+       compound_expr = build_compound_expr (input_location, s2, s3);   
 
       /* Without this, with -Wall you get a 'valued computed is not
         used' every time there is a "object.property = x" where the
@@ -2897,7 +2953,7 @@ synth_module_prologue (void)
 
   /* Forward-declare '@interface Protocol'.  */
   type = get_identifier (PROTOCOL_OBJECT_CLASS_NAME);
-  objc_declare_class (tree_cons (NULL_TREE, type, NULL_TREE));
+  objc_declare_class (type);
   objc_protocol_type = build_pointer_type (xref_tag (RECORD_TYPE, type));
 
   /* Declare receiver type used for dispatching messages to 'super'.  */
@@ -2929,7 +2985,7 @@ synth_module_prologue (void)
   if (!constant_string_class_name)
     constant_string_class_name = runtime.default_constant_string_class_name;
   constant_string_id = get_identifier (constant_string_class_name);
-  objc_declare_class (tree_cons (NULL_TREE, constant_string_id, NULL_TREE));
+  objc_declare_class (constant_string_id);
 
   /* Pre-build the following entities - for speed/convenience.  */
   self_id = get_identifier ("self");
@@ -3304,48 +3360,42 @@ objc_declare_alias (tree alias_ident, tree class_ident)
 }
 
 void
-objc_declare_class (tree ident_list)
+objc_declare_class (tree identifier)
 {
-  tree list;
 #ifdef OBJCPLUS
   if (current_namespace != global_namespace) {
     error ("Objective-C declarations may only appear in global scope");
   }
 #endif /* OBJCPLUS */
 
-  for (list = ident_list; list; list = TREE_CHAIN (list))
+  if (! objc_is_class_name (identifier))
     {
-      tree ident = TREE_VALUE (list);
-
-      if (! objc_is_class_name (ident))
+      tree record = lookup_name (identifier), type = record;
+      
+      if (record)
        {
-         tree record = lookup_name (ident), type = record;
-
-         if (record)
+         if (TREE_CODE (record) == TYPE_DECL)
+           type = DECL_ORIGINAL_TYPE (record)
+             ? DECL_ORIGINAL_TYPE (record)
+             : TREE_TYPE (record);
+         
+         if (!TYPE_HAS_OBJC_INFO (type)
+             || !TYPE_OBJC_INTERFACE (type))
            {
-             if (TREE_CODE (record) == TYPE_DECL)
-               type = DECL_ORIGINAL_TYPE (record)
-                                       ? DECL_ORIGINAL_TYPE (record)
-                                       : TREE_TYPE (record);
-
-             if (!TYPE_HAS_OBJC_INFO (type)
-                 || !TYPE_OBJC_INTERFACE (type))
-               {
-                 error ("%qE redeclared as different kind of symbol",
-                        ident);
-                 error ("previous declaration of %q+D",
-                        record);
-               }
+             error ("%qE redeclared as different kind of symbol",
+                    identifier);
+             error ("previous declaration of %q+D",
+                    record);
            }
-
-         record = xref_tag (RECORD_TYPE, ident);
-         INIT_TYPE_OBJC_INFO (record);
-         /* In the case of a @class declaration, we store the ident
-            in the TYPE_OBJC_INTERFACE.  If later an @interface is
-            found, we'll replace the ident with the interface.  */
-         TYPE_OBJC_INTERFACE (record) = ident;
-         hash_class_name_enter (cls_name_hash_list, ident, NULL_TREE);
        }
+      
+      record = xref_tag (RECORD_TYPE, identifier);
+      INIT_TYPE_OBJC_INFO (record);
+      /* In the case of a @class declaration, we store the ident in
+        the TYPE_OBJC_INTERFACE.  If later an @interface is found,
+        we'll replace the ident with the interface.  */
+      TYPE_OBJC_INTERFACE (record) = identifier;
+      hash_class_name_enter (cls_name_hash_list, identifier, NULL_TREE);
     }
 }
 
@@ -3354,9 +3404,13 @@ objc_is_class_name (tree ident)
 {
   hash target;
 
-  if (ident && TREE_CODE (ident) == IDENTIFIER_NODE
-      && identifier_global_value (ident))
-    ident = identifier_global_value (ident);
+  if (ident && TREE_CODE (ident) == IDENTIFIER_NODE)
+    {
+      tree t = identifier_global_value (ident);
+      if (t)
+       ident = t;
+    }
+
   while (ident && TREE_CODE (ident) == TYPE_DECL && DECL_ORIGINAL_TYPE (ident))
     ident = OBJC_TYPE_NAME (DECL_ORIGINAL_TYPE (ident));
 
@@ -3396,9 +3450,12 @@ objc_is_class_name (tree ident)
 tree
 objc_is_id (tree type)
 {
-  if (type && TREE_CODE (type) == IDENTIFIER_NODE
-      && identifier_global_value (type))
-    type = identifier_global_value (type);
+  if (type && TREE_CODE (type) == IDENTIFIER_NODE)
+    {
+      tree t = identifier_global_value (type);
+      if (t)
+       type = t;
+    }
 
   if (type && TREE_CODE (type) == TYPE_DECL)
     type = TREE_TYPE (type);
@@ -4146,9 +4203,6 @@ build_private_template (tree klass)
       /* Copy the attributes from the class to the type.  */
       if (TREE_DEPRECATED (klass))
        TREE_DEPRECATED (record) = 1;
-
-      if (CLASS_HAS_EXCEPTION_ATTR (klass))
-       CLASS_HAS_EXCEPTION_ATTR (record) = 1;
     }
 }
 
@@ -4465,14 +4519,16 @@ mark_referenced_methods (void)
       chain = CLASS_CLS_METHODS (impent->imp_context);
       while (chain)
        {
-         cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)));
+         cgraph_mark_needed_node (
+                          cgraph_get_create_node (METHOD_DEFINITION (chain)));
          chain = DECL_CHAIN (chain);
        }
 
       chain = CLASS_NST_METHODS (impent->imp_context);
       while (chain)
        {
-         cgraph_mark_needed_node (cgraph_node (METHOD_DEFINITION (chain)));
+         cgraph_mark_needed_node (
+                          cgraph_get_create_node (METHOD_DEFINITION (chain)));
          chain = DECL_CHAIN (chain);
        }
     }
@@ -4606,7 +4662,7 @@ build_keyword_selector (tree selector)
       strcat (buf, ":");
     }
 
-  return get_identifier (buf);
+  return get_identifier_with_length (buf, len);
 }
 
 /* Used for declarations and definitions.  */
@@ -4773,13 +4829,13 @@ objc_method_decl (enum tree_code opcode)
   return opcode == INSTANCE_METHOD_DECL || opcode == CLASS_METHOD_DECL;
 }
 
-/* Used by `build_objc_method_call' and `comp_proto_with_proto'.  Return
-   an argument list for method METH.  CONTEXT is either METHOD_DEF or
-   METHOD_REF, saying whether we are trying to define a method or call
-   one.  SUPERFLAG says this is for a send to super; this makes a
-   difference for the NeXT calling sequence in which the lookup and
-   the method call are done together.  If METH is null, user-defined
-   arguments (i.e., beyond self and _cmd) shall be represented by `...'.  */
+/* Used by `build_objc_method_call'.  Return an argument list for
+   method METH.  CONTEXT is either METHOD_DEF or METHOD_REF, saying
+   whether we are trying to define a method or call one.  SUPERFLAG
+   says this is for a send to super; this makes a difference for the
+   NeXT calling sequence in which the lookup and the method call are
+   done together.  If METH is null, user-defined arguments (i.e.,
+   beyond self and _cmd) shall be represented by `...'.  */
 
 tree
 get_arg_type_list (tree meth, int context, int superflag)
@@ -4964,14 +5020,13 @@ objc_message_selector (void)
    (*(<abstract_decl>(*)())_msgSuper)(receiver, selTransTbl[n], ...);  */
 
 tree
-objc_build_message_expr (tree mess)
+objc_build_message_expr (tree receiver, tree message_args)
 {
-  tree receiver = TREE_PURPOSE (mess);
   tree sel_name;
 #ifdef OBJCPLUS
-  tree args = TREE_PURPOSE (TREE_VALUE (mess));
+  tree args = TREE_PURPOSE (message_args);
 #else
-  tree args = TREE_VALUE (mess);
+  tree args = message_args;
 #endif
   tree method_params = NULL_TREE;
 
@@ -4995,7 +5050,7 @@ objc_build_message_expr (tree mess)
   /* Build the parameter list to give to the method.  */
   if (TREE_CODE (args) == TREE_LIST)
 #ifdef OBJCPLUS
-    method_params = chainon (args, TREE_VALUE (TREE_VALUE (mess)));
+    method_params = chainon (args, TREE_VALUE (message_args));
 #else
     {
       tree chain = args, prev = NULL_TREE;
@@ -5868,6 +5923,69 @@ add_category (tree klass, tree category)
     }
 }
 
+#ifndef OBJCPLUS
+/* A flexible array member is a C99 extension where you can use
+   "type[]" at the end of a struct to mean a variable-length array.
+
+   In Objective-C, instance variables are fundamentally members of a
+   struct, but the struct can always be extended by subclassing; hence
+   we need to detect and forbid all instance variables declared using
+   flexible array members.
+
+   No check for this is needed in Objective-C++, since C++ does not
+   have flexible array members.  */
+
+/* Determine whether TYPE is a structure with a flexible array member,
+   a union containing such a structure (possibly recursively) or an
+   array of such structures or unions.  These are all invalid as
+   instance variable.  */
+static bool
+flexible_array_type_p (tree type)
+{
+  tree x;
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+      x = TYPE_FIELDS (type);
+      if (x == NULL_TREE)
+       return false;
+      while (DECL_CHAIN (x) != NULL_TREE)
+       x = DECL_CHAIN (x);
+      if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
+         && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
+         && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
+         && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE)
+       return true;
+      return false;
+    case UNION_TYPE:
+      for (x = TYPE_FIELDS (type); x != NULL_TREE; x = DECL_CHAIN (x))
+       {
+         if (flexible_array_type_p (TREE_TYPE (x)))
+           return true;
+       }
+      return false;
+    /* Note that we also check for arrays of something that uses a flexible array member.  */
+    case ARRAY_TYPE:
+      if (flexible_array_type_p (TREE_TYPE (type)))
+       return true;
+      return false;
+    default:
+    return false;
+  }
+}
+#endif
+
+/* Produce a printable version of an ivar name.  This is only used
+   inside add_instance_variable.  */
+static const char *
+printable_ivar_name (tree field_decl)
+{
+  if (DECL_NAME (field_decl))
+    return identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (field_decl)));
+  else
+    return _("<unnamed>");
+}
+
 /* Called after parsing each instance variable declaration. Necessary to
    preserve typedefs and implement public/private...
 
@@ -5878,15 +5996,12 @@ add_instance_variable (tree klass, objc_ivar_visibility_kind visibility,
                       tree field_decl)
 {
   tree field_type = TREE_TYPE (field_decl);
-  const char *ivar_name = DECL_NAME (field_decl)
-                         ? identifier_to_locale (IDENTIFIER_POINTER (DECL_NAME (field_decl)))
-                         : _("<unnamed>");
 
 #ifdef OBJCPLUS
   if (TREE_CODE (field_type) == REFERENCE_TYPE)
     {
       error ("illegal reference type specified for instance variable %qs",
-            ivar_name);
+            printable_ivar_name (field_decl));
       /* Return class as is without adding this ivar.  */
       return klass;
     }
@@ -5896,11 +6011,34 @@ add_instance_variable (tree klass, objc_ivar_visibility_kind visibility,
       || TYPE_SIZE (field_type) == error_mark_node)
       /* 'type[0]' is allowed, but 'type[]' is not! */
     {
-      error ("instance variable %qs has unknown size", ivar_name);
+      error ("instance variable %qs has unknown size",
+            printable_ivar_name (field_decl));
       /* Return class as is without adding this ivar.  */
       return klass;
     }
 
+#ifndef OBJCPLUS
+  /* Also, in C reject a struct with a flexible array member.  Ie,
+
+       struct A { int x; int[] y; };
+
+       @interface X
+       {
+         struct A instance_variable;
+       }
+       @end
+
+       is not valid because if the class is subclassed, we wouldn't be able
+       to calculate the offset of the next instance variable.  */
+  if (flexible_array_type_p (field_type))
+    {
+      error ("instance variable %qs uses flexible array member",
+            printable_ivar_name (field_decl));
+      /* Return class as is without adding this ivar.  */
+      return klass;      
+    }
+#endif
+
 #ifdef OBJCPLUS
   /* Check if the ivar being added has a non-POD C++ type.   If so, we will
      need to either (1) warn the user about it or (2) generate suitable
@@ -5942,7 +6080,7 @@ add_instance_variable (tree klass, objc_ivar_visibility_kind visibility,
              error ("type %qE has virtual member functions", type_name);
              error ("illegal aggregate type %qE specified "
                     "for instance variable %qs",
-                    type_name, ivar_name);
+                    type_name, printable_ivar_name (field_decl));
              /* Return class as is without adding this ivar.  */
              return klass;
            }
@@ -7725,9 +7863,8 @@ lookup_protocol (tree ident, bool warn_if_deprecated, bool definition_required)
    they are already declared or defined, the function has no effect.  */
 
 void
-objc_declare_protocols (tree names, tree attributes)
+objc_declare_protocol (tree name, tree attributes)
 {
-  tree list;
   bool deprecated = false;
 
 #ifdef OBJCPLUS
@@ -7752,29 +7889,25 @@ objc_declare_protocols (tree names, tree attributes)
        }
     }
 
-  for (list = names; list; list = TREE_CHAIN (list))
+  if (lookup_protocol (name, /* warn if deprecated */ false,
+                      /* definition_required */ false) == NULL_TREE)
     {
-      tree name = TREE_VALUE (list);
-
-      if (lookup_protocol (name, /* warn if deprecated */ false,
-                          /* definition_required */ false) == NULL_TREE)
+      tree protocol = make_node (PROTOCOL_INTERFACE_TYPE);
+      
+      TYPE_LANG_SLOT_1 (protocol)
+       = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS);
+      PROTOCOL_NAME (protocol) = name;
+      PROTOCOL_LIST (protocol) = NULL_TREE;
+      add_protocol (protocol);
+      PROTOCOL_DEFINED (protocol) = 0;
+      PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
+      
+      if (attributes)
        {
-         tree protocol = make_node (PROTOCOL_INTERFACE_TYPE);
-
-         TYPE_LANG_SLOT_1 (protocol)
-           = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS);
-         PROTOCOL_NAME (protocol) = name;
-         PROTOCOL_LIST (protocol) = NULL_TREE;
-         add_protocol (protocol);
-         PROTOCOL_DEFINED (protocol) = 0;
-         PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
-         
-         if (attributes)
-           {
-             TYPE_ATTRIBUTES (protocol) = attributes;
-             if (deprecated)
-               TREE_DEPRECATED (protocol) = 1;
-           }
+         /* TODO: Do we need to store the attributes here ? */
+         TYPE_ATTRIBUTES (protocol) = attributes;
+         if (deprecated)
+           TREE_DEPRECATED (protocol) = 1;
        }
     }
 }
@@ -8095,19 +8228,13 @@ objc_types_share_size_and_alignment (tree type1, tree type2)
 static int
 comp_proto_with_proto (tree proto1, tree proto2, int strict)
 {
+  tree type1, type2;
+
   /* The following test is needed in case there are hashing
      collisions.  */
   if (METHOD_SEL_NAME (proto1) != METHOD_SEL_NAME (proto2))
     return 0;
 
-  return match_proto_with_proto (proto1, proto2, strict);
-}
-
-static int
-match_proto_with_proto (tree proto1, tree proto2, int strict)
-{
-  tree type1, type2;
-
   /* Compare return types.  */
   type1 = TREE_VALUE (TREE_TYPE (proto1));
   type2 = TREE_VALUE (TREE_TYPE (proto2));
@@ -8117,19 +8244,75 @@ match_proto_with_proto (tree proto1, tree proto2, int strict)
     return 0;
 
   /* Compare argument types.  */
-  for (type1 = get_arg_type_list (proto1, METHOD_REF, 0),
-       type2 = get_arg_type_list (proto2, METHOD_REF, 0);
-       type1 && type2;
-       type1 = TREE_CHAIN (type1), type2 = TREE_CHAIN (type2))
-    {
-      if (!objc_types_are_equivalent (TREE_VALUE (type1), TREE_VALUE (type2))
-         && (strict
-             || !objc_types_share_size_and_alignment (TREE_VALUE (type1),
-                                                      TREE_VALUE (type2))))
-       return 0;
-    }
 
-  return (!type1 && !type2);
+  /* The first argument (objc_object_type) is always the same, no need
+     to compare.  */
+
+  /* The second argument (objc_selector_type) is always the same, no
+     need to compare.  */
+
+  /* Compare the other arguments.  */
+  {
+    tree arg1, arg2;
+
+    /* Compare METHOD_SEL_ARGS.  */
+    for (arg1 = METHOD_SEL_ARGS (proto1), arg2 = METHOD_SEL_ARGS (proto2);
+        arg1 && arg2;
+        arg1 = DECL_CHAIN (arg1), arg2 = DECL_CHAIN (arg2))
+      {
+       type1 = TREE_VALUE (TREE_TYPE (arg1));
+       type2 = TREE_VALUE (TREE_TYPE (arg2));
+       
+       /* FIXME: Do we need to decay argument types to compare them ?  */
+       type1 = objc_decay_parm_type (type1);
+       type2 = objc_decay_parm_type (type2);
+       
+       if (!objc_types_are_equivalent (type1, type2)
+           && (strict || !objc_types_share_size_and_alignment (type1, type2)))
+         return 0;
+      }
+    
+    /* The loop ends when arg1 or arg2 are NULL.  Make sure they are
+       both NULL.  */
+    if (arg1 != arg2)
+      return 0;
+
+    /* Compare METHOD_ADD_ARGS.  */
+    if ((METHOD_ADD_ARGS (proto1) && !METHOD_ADD_ARGS (proto2))
+       || (METHOD_ADD_ARGS (proto2) && !METHOD_ADD_ARGS (proto1)))
+      return 0;
+
+    if (METHOD_ADD_ARGS (proto1))
+      {
+       for (arg1 = TREE_CHAIN (METHOD_ADD_ARGS (proto1)), arg2 = TREE_CHAIN (METHOD_ADD_ARGS (proto2));
+            arg1 && arg2;
+            arg1 = TREE_CHAIN (arg1), arg2 = TREE_CHAIN (arg2))
+         {
+           type1 = TREE_TYPE (TREE_VALUE (arg1));
+           type2 = TREE_TYPE (TREE_VALUE (arg2));
+           
+           /* FIXME: Do we need to decay argument types to compare them ?  */
+           type1 = objc_decay_parm_type (type1);
+           type2 = objc_decay_parm_type (type2);
+           
+           if (!objc_types_are_equivalent (type1, type2)
+               && (strict || !objc_types_share_size_and_alignment (type1, type2)))
+             return 0;
+         }
+      }
+    
+    /* The loop ends when arg1 or arg2 are NULL.  Make sure they are
+       both NULL.  */
+    if (arg1 != arg2)
+      return 0;
+
+    /* Compare METHOD_ADD_ARGS_ELLIPSIS_P.  */
+    if (METHOD_ADD_ARGS_ELLIPSIS_P (proto1) != METHOD_ADD_ARGS_ELLIPSIS_P (proto2))
+      return 0;
+  }
+
+  /* Success.  */
+  return 1;
 }
 
 /* This routine returns true if TYPE is a valid objc object type,
@@ -9869,27 +10052,23 @@ encode_array (tree type, int curtype, int format)
   if (an_int_cst == NULL)
     {
       /* We are trying to encode an incomplete array.  An incomplete
-        array is forbidden as part of an instance variable.  */
-      if (generating_instance_variables)
-       {
-         /* TODO: Detect this error earlier.  */
-         error ("instance variable has unknown size");
-         return;
-       }
+        array is forbidden as part of an instance variable; but it
+        may occur if the instance variable is a pointer to such an
+        array.  */
 
-      /* So the only case in which an incomplete array could occur is
-        if we are encoding the arguments or return value of a method.
-        In that case, an incomplete array argument or return value
-        (eg, -(void)display: (char[])string) is treated like a
-        pointer because that is how the compiler does the function
-        call.  A special, more complicated case, is when the
-        incomplete array is the last member of a struct (eg, if we
-        are encoding "struct { unsigned long int a;double b[];}"),
-        which is again part of a method argument/return value.  In
-        that case, we really need to communicate to the runtime that
-        there is an incomplete array (not a pointer!) there.  So, we
-        detect that special case and encode it as a zero-length
-        array.
+      /* So the only case in which an incomplete array could occur
+        (without being pointed to) is if we are encoding the
+        arguments or return value of a method.  In that case, an
+        incomplete array argument or return value (eg,
+        -(void)display: (char[])string) is treated like a pointer
+        because that is how the compiler does the function call.  A
+        special, more complicated case, is when the incomplete array
+        is the last member of a struct (eg, if we are encoding
+        "struct { unsigned long int a;double b[];}"), which is again
+        part of a method argument/return value.  In that case, we
+        really need to communicate to the runtime that there is an
+        incomplete array (not a pointer!) there.  So, we detect that
+        special case and encode it as a zero-length array.
 
         Try to detect that we are part of a struct.  We do this by
         searching for '=' in the type encoding for the current type.
@@ -10372,50 +10551,100 @@ encode_field_decl (tree field_decl, int curtype, int format)
      kPropertyGetter = 'G',
      kPropertySetter = 'S',
      kPropertyInstanceVariable = 'V',
-     kPropertyType = 't',
+     kPropertyType = 'T',
      kPropertyWeak = 'W',
-     kPropertyStrong = 'S',
+     kPropertyStrong = 'P',
      kPropertyNonAtomic = 'N'
-   };
-
-   FIXME: Update the implementation to match.  */
+   };  */
 tree
 objc_v2_encode_prop_attr (tree property)
 {
   const char *string;
   tree type = TREE_TYPE (property);
-  obstack_1grow (&util_obstack, 't');
+
+  obstack_1grow (&util_obstack, 'T');
   encode_type (type, obstack_object_size (&util_obstack),
               OBJC_ENCODE_INLINE_DEFS);
+
   if (PROPERTY_READONLY (property))
-    obstack_grow (&util_obstack, ",r", 2);
+    obstack_grow (&util_obstack, ",R", 2);
 
-  if (PROPERTY_ASSIGN_SEMANTICS (property) == OBJC_PROPERTY_COPY)
-    obstack_grow (&util_obstack, ",c", 2);
+  switch (PROPERTY_ASSIGN_SEMANTICS (property))
+    {
+    case OBJC_PROPERTY_COPY:
+      obstack_grow (&util_obstack, ",C", 2);
+      break;
+    case OBJC_PROPERTY_RETAIN:
+      obstack_grow (&util_obstack, ",&", 2);
+      break;
+    case OBJC_PROPERTY_ASSIGN:
+    default:
+      break;
+    }
 
-  if (PROPERTY_GETTER_NAME (property))
+  if (PROPERTY_DYNAMIC (property))
+    obstack_grow (&util_obstack, ",D", 2);    
+
+  if (PROPERTY_NONATOMIC (property))
+    obstack_grow (&util_obstack, ",N", 2);
+
+  /* Here we want to encode the getter name, but only if it's not the
+     standard one.  */
+  if (PROPERTY_GETTER_NAME (property) != PROPERTY_NAME (property))
     {
-      obstack_grow (&util_obstack, ",g", 2);
+      obstack_grow (&util_obstack, ",G", 2);
       string = IDENTIFIER_POINTER (PROPERTY_GETTER_NAME (property));
       obstack_grow (&util_obstack, string, strlen (string));
     }
-  if (PROPERTY_SETTER_NAME (property))
+
+  if (!PROPERTY_READONLY (property))
     {
-      obstack_grow (&util_obstack, ",s", 2);
-      string = IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (property));
-      obstack_grow (&util_obstack, string, strlen (string));
+      /* Here we want to encode the setter name, but only if it's not
+        the standard one.  */
+      tree standard_setter = get_identifier (objc_build_property_setter_name (PROPERTY_NAME (property)));
+      if (PROPERTY_SETTER_NAME (property) != standard_setter)
+       {
+         obstack_grow (&util_obstack, ",S", 2);
+         string = IDENTIFIER_POINTER (PROPERTY_SETTER_NAME (property));
+         obstack_grow (&util_obstack, string, strlen (string));
+       }
     }
-  if (PROPERTY_IVAR_NAME (property))
+
+  /* TODO: Encode strong ('P'), weak ('W') for garbage collection.  */
+
+  if (!PROPERTY_DYNAMIC (property))
     {
-      obstack_grow (&util_obstack, ",i", 2);
-      string = IDENTIFIER_POINTER (PROPERTY_IVAR_NAME (property));
+      obstack_grow (&util_obstack, ",V", 2);
+      if (PROPERTY_IVAR_NAME (property))
+       string = IDENTIFIER_POINTER (PROPERTY_IVAR_NAME (property));
+      else
+       string = IDENTIFIER_POINTER (PROPERTY_NAME (property));
       obstack_grow (&util_obstack, string, strlen (string));
     }
-    
-  obstack_1grow (&util_obstack, 0);    /* null terminate string */
+
+  /* NULL-terminate string.  */
+  obstack_1grow (&util_obstack, 0);
   string = XOBFINISH (&util_obstack, char *);
   obstack_free (&util_obstack, util_firstobj);
   return get_identifier (string);
 }
 
+void
+objc_common_init_ts (void)
+{
+  c_common_init_ts ();
+
+  MARK_TS_DECL_NON_COMMON (CLASS_METHOD_DECL);
+  MARK_TS_DECL_NON_COMMON (INSTANCE_METHOD_DECL);
+  MARK_TS_DECL_NON_COMMON (KEYWORD_DECL);
+  MARK_TS_DECL_NON_COMMON (PROPERTY_DECL);
+
+  MARK_TS_COMMON (CLASS_INTERFACE_TYPE);
+  MARK_TS_COMMON (PROTOCOL_INTERFACE_TYPE);
+  MARK_TS_COMMON (CLASS_IMPLEMENTATION_TYPE);
+
+  MARK_TS_TYPED (MESSAGE_SEND_EXPR);
+  MARK_TS_TYPED (PROPERTY_REF);
+}
+
 #include "gt-objc-objc-act.h"