OSDN Git Service

2011-01-14 Ben Elliston <bje@au.ibm.com>
[pf3gnuchains/gcc-fork.git] / gcc / objc / objc-act.c
index db41dca..cfbdb6f 100644 (file)
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #endif
 
 #include "c-family/c-common.h"
+#include "c-family/c-objc.h"
 #include "c-family/c-pragma.h"
 #include "c-family/c-format.h"
 #include "flags.h"
@@ -63,11 +64,6 @@ along with GCC; see the file COPYING3.  If not see
 
 static unsigned int should_call_super_dealloc = 0;
 
-/* When building Objective-C++, we need in_late_binary_op.  */
-#ifdef OBJCPLUS
-bool in_late_binary_op = false;
-#endif  /* OBJCPLUS */
-
 /* When building Objective-C++, we are not linking against the C front-end
    and so need to replicate the C tree-construction functions in some way.  */
 #ifdef OBJCPLUS
@@ -144,7 +140,7 @@ static tree get_proto_encoding (tree);
 static tree lookup_interface (tree);
 static tree objc_add_static_instance (tree, tree);
 
-static tree start_class (enum tree_code, tree, tree, tree);
+static tree start_class (enum tree_code, tree, tree, tree, tree);
 static tree continue_class (tree);
 static void finish_class (tree);
 static void start_method_def (tree);
@@ -153,7 +149,7 @@ static void objc_start_function (tree, tree, tree, tree);
 #else
 static void objc_start_function (tree, tree, tree, struct c_arg_info *);
 #endif
-static tree start_protocol (enum tree_code, tree, tree);
+static tree start_protocol (enum tree_code, tree, tree, tree);
 static tree build_method_decl (enum tree_code, tree, tree, tree, bool);
 static tree objc_add_method (tree, tree, int, bool);
 static tree add_instance_variable (tree, objc_ivar_visibility_kind, tree);
@@ -234,10 +230,10 @@ enum string_section
 static tree add_objc_string (tree, enum string_section);
 static void build_selector_table_decl (void);
 
-/* Protocol additions.  */
+/* Protocols.  */
 
-static tree lookup_protocol (tree);
-static tree lookup_and_install_protocols (tree);
+static tree lookup_protocol (tree, bool, bool);
+static tree lookup_and_install_protocols (tree, bool);
 
 /* Type encoding.  */
 
@@ -406,17 +402,20 @@ static bool objc_method_optional_flag = false;
 
 static int objc_collecting_ivars = 0;
 
+/* Flag that is set to 'true' while we are processing a class
+   extension.  Since a class extension just "reopens" the main
+   @interface, this can be used to determine if we are in the main
+   @interface, or in a class extension.  */
+static bool objc_in_class_extension = false;
+
 #define BUFSIZE                1024
 
 static char *errbuf;   /* Buffer for error diagnostics */
 
-/* Data imported from tree.c.  */
-
-extern enum debug_info_type write_symbols;
-
-/* Data imported from toplev.c.  */
+/* An array of all the local variables in the current function that
+   need to be marked as volatile.  */
+VEC(tree,gc) *local_variables_to_volatilize = NULL;
 
-extern const char *dump_base_name;
 \f
 static int flag_typed_selectors;
 
@@ -488,6 +487,33 @@ add_field_decl (tree type, const char *name, tree **chain)
   return field;
 }
 
+/* Create a temporary variable of type 'type'.  If 'name' is set, uses
+   the specified name, else use no name.  Returns the declaration of
+   the type.  The 'name' is mostly useful for debugging.
+*/
+static tree
+objc_create_temporary_var (tree type, const char *name)
+{
+  tree decl;
+
+  if (name != NULL)
+    {
+      decl = build_decl (input_location,
+                        VAR_DECL, get_identifier (name), type);
+    }
+  else
+    {
+      decl = build_decl (input_location,
+                        VAR_DECL, NULL_TREE, type);
+    }
+  TREE_USED (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_IGNORED_P (decl) = 1;
+  DECL_CONTEXT (decl) = current_function_decl;
+
+  return decl;
+}
+
 /* 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.  */
@@ -532,15 +558,7 @@ generate_struct_by_value_array (void)
       for (i = 31; i >= 0;  i--)
        if (!aggregate_in_mem[i])
          break;
-      printf ("#define OBJC_MAX_STRUCT_BY_VALUE %d\n\n", i);
-
-      /* The first member of the structure is always 0 because we don't handle
-        structures with 0 members */
-      printf ("static int struct_forward_array[] = {\n  0");
-
-      for (j = 1; j <= i; j++)
-       printf (", %d", aggregate_in_mem[j]);
-      printf ("\n};\n");
+      printf ("#define OBJC_MAX_STRUCT_BY_VALUE %d\n", i);
     }
 
   exit (0);
@@ -562,7 +580,7 @@ objc_init (void)
       register char * const dumpname = concat (dump_base_name, ".decl", NULL);
       gen_declaration_file = fopen (dumpname, "w");
       if (gen_declaration_file == 0)
-       fatal_error ("can't open %s: %m", dumpname);
+       fatal_error ("can%'t open %s: %m", dumpname);
       free (dumpname);
     }
 
@@ -600,6 +618,11 @@ objc_init (void)
   if (print_struct_values && !flag_compare_debug)
     generate_struct_by_value_array ();
 
+#ifndef OBJCPLUS
+  if (flag_objc_exceptions && !flag_objc_sjlj_exceptions)
+    using_eh_for_cleanups ();
+#endif
+
   return true;
 }
 
@@ -625,30 +648,44 @@ static tree
 lookup_method_in_protocol_list (tree rproto_list, tree sel_name,
                                int is_class)
 {
-   tree rproto, p;
-   tree fnd = 0;
+  tree rproto, p, m;
 
    for (rproto = rproto_list; rproto; rproto = TREE_CHAIN (rproto))
      {
-        p = TREE_VALUE (rproto);
+       p = TREE_VALUE (rproto);
+       m = NULL_TREE;
 
        if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
          {
-           if ((fnd = lookup_method (is_class
-                                     ? PROTOCOL_CLS_METHODS (p)
-                                     : PROTOCOL_NST_METHODS (p), sel_name)))
-             ;
-           else if (PROTOCOL_LIST (p))
-             fnd = lookup_method_in_protocol_list (PROTOCOL_LIST (p),
-                                                   sel_name, is_class);
+           /* First, search the @required protocol methods.  */
+           if (is_class)
+             m = lookup_method (PROTOCOL_CLS_METHODS (p),  sel_name);
+           else
+             m = lookup_method (PROTOCOL_NST_METHODS (p), sel_name);
+
+           if (m)
+             return m;
+
+           /* If still not found, search the @optional protocol methods.  */
+           if (is_class)
+             m = lookup_method (PROTOCOL_OPTIONAL_CLS_METHODS (p), sel_name);
+           else
+             m = lookup_method (PROTOCOL_OPTIONAL_NST_METHODS (p), sel_name);
+
+           if (m)
+             return m;
+
+           /* If still not found, search the attached protocols.  */
+           if (PROTOCOL_LIST (p))
+             m = lookup_method_in_protocol_list (PROTOCOL_LIST (p),
+                                                 sel_name, is_class);
+           if (m)
+             return m;
          }
        else
           {
            ; /* An identifier...if we could not find a protocol.  */
           }
-
-       if (fnd)
-         return fnd;
      }
 
    return 0;
@@ -692,18 +729,12 @@ void
 objc_start_class_interface (tree klass, tree super_class,
                            tree protos, tree attributes)
 {
-  if (attributes)
-    {
-      if (flag_objc1_only)
-       error_at (input_location, "class attributes are not available in Objective-C 1.0");
-      else
-       warning_at (input_location, OPT_Wattributes, 
-                   "class attributes are not available in this version"
-                   " of the compiler, (ignored)");
-    }
+  if (flag_objc1_only && attributes)
+    error_at (input_location, "class attributes are not available in Objective-C 1.0");        
+
   objc_interface_context
     = objc_ivar_context
-    = start_class (CLASS_INTERFACE_TYPE, klass, super_class, protos);
+    = start_class (CLASS_INTERFACE_TYPE, klass, super_class, protos, attributes);
   objc_ivar_visibility = OBJC_IVAR_VIS_PROTECTED;
 }
 
@@ -720,8 +751,30 @@ objc_start_category_interface (tree klass, tree categ,
                    "category attributes are not available in this version"
                    " of the compiler, (ignored)");
     }
+  if (categ == NULL_TREE)
+    {
+      if (flag_objc1_only)
+       error_at (input_location, "class extensions are not available in Objective-C 1.0");
+      else
+       {
+         /* Iterate over all the classes and categories implemented
+            up to now in this compilation unit.  */
+         struct imp_entry *t;
+
+         for (t = imp_list; t; t = t->next)
+           {
+             /* If we find a class @implementation with the same name
+                as the one we are extending, produce an error.  */
+           if (TREE_CODE (t->imp_context) == CLASS_IMPLEMENTATION_TYPE
+               && IDENTIFIER_POINTER (CLASS_NAME (t->imp_context)) == IDENTIFIER_POINTER (klass))
+             error_at (input_location, 
+                       "class extension for class %qE declared after its %<@implementation%>",
+                       klass);
+           }
+       }
+    }
   objc_interface_context
-    = start_class (CATEGORY_INTERFACE_TYPE, klass, categ, protos);
+    = start_class (CATEGORY_INTERFACE_TYPE, klass, categ, protos, NULL_TREE);
   objc_ivar_chain
     = continue_class (objc_interface_context);
 }
@@ -729,17 +782,11 @@ objc_start_category_interface (tree klass, tree categ,
 void
 objc_start_protocol (tree name, tree protos, tree attributes)
 {
-  if (attributes)
-    {
-      if (flag_objc1_only)
-       error_at (input_location, "protocol attributes are not available in Objective-C 1.0");  
-      else
-       warning_at (input_location, OPT_Wattributes, 
-                   "protocol attributes are not available in this version"
-                   " of the compiler, (ignored)");
-    }
+  if (flag_objc1_only && attributes)
+    error_at (input_location, "protocol attributes are not available in Objective-C 1.0");     
+
   objc_interface_context
-    = start_protocol (PROTOCOL_INTERFACE_TYPE, name, protos);
+    = start_protocol (PROTOCOL_INTERFACE_TYPE, name, protos, attributes);
   objc_method_optional_flag = false;
 }
 
@@ -756,6 +803,7 @@ objc_finish_interface (void)
   finish_class (objc_interface_context);
   objc_interface_context = NULL_TREE;
   objc_method_optional_flag = false;
+  objc_in_class_extension = false;
 }
 
 void
@@ -763,7 +811,8 @@ objc_start_class_implementation (tree klass, tree super_class)
 {
   objc_implementation_context
     = objc_ivar_context
-    = start_class (CLASS_IMPLEMENTATION_TYPE, klass, super_class, NULL_TREE);
+    = start_class (CLASS_IMPLEMENTATION_TYPE, klass, super_class, NULL_TREE,
+                  NULL_TREE);
   objc_ivar_visibility = OBJC_IVAR_VIS_PROTECTED;
 }
 
@@ -771,7 +820,8 @@ void
 objc_start_category_implementation (tree klass, tree categ)
 {
   objc_implementation_context
-    = start_class (CATEGORY_IMPLEMENTATION_TYPE, klass, categ, NULL_TREE);
+    = start_class (CATEGORY_IMPLEMENTATION_TYPE, klass, categ, NULL_TREE,
+                  NULL_TREE);
   objc_ivar_chain
     = continue_class (objc_implementation_context);
 }
@@ -818,13 +868,21 @@ void
 objc_set_method_opt (bool optional)
 {
   if (flag_objc1_only)
-    error_at (input_location, "@optional/@required are not available in Objective-C 1.0");     
+    {
+      if (optional)
+       error_at (input_location, "%<@optional%> is not available in Objective-C 1.0"); 
+      else
+       error_at (input_location, "%<@required%> is not available in Objective-C 1.0"); 
+    }
 
   objc_method_optional_flag = optional;
   if (!objc_interface_context 
       || TREE_CODE (objc_interface_context) != PROTOCOL_INTERFACE_TYPE)
     {
-      error ("@optional/@required is allowed in @protocol context only.");
+      if (optional)
+       error ("%<@optional%> is allowed in @protocol context only");
+      else
+       error ("%<@required%> is allowed in @protocol context only");
       objc_method_optional_flag = false;
     }
 }
@@ -928,6 +986,7 @@ objc_add_property_declaration (location_t location, tree decl,
      is readwrite).  */
   bool property_readonly = false;
   objc_property_assign_semantics property_assign_semantics = OBJC_PROPERTY_ASSIGN;
+  bool property_extension_in_class_extension = false;
 
   if (flag_objc1_only)
     error_at (input_location, "%<@property%> is not available in Objective-C 1.0");
@@ -951,8 +1010,7 @@ objc_add_property_declaration (location_t location, tree decl,
 
   if (parsed_property_readonly && parsed_property_setter_ident)
     {
-      /* Maybe this should be an error ?  The Apple documentation says it is a warning.  */
-      warning_at (location, 0, "%<readonly%> attribute conflicts with %<setter%> attribute");
+      error_at (location, "%<readonly%> attribute conflicts with %<setter%> attribute");
       property_readonly = false;
     }
 
@@ -992,16 +1050,43 @@ objc_add_property_declaration (location_t location, tree decl,
   /* At this point we know that we are either in an interface, a
      category, or a protocol.  */
 
-  /* Check that the property does not have an initial value specified.
-     This should never happen as the parser doesn't allow this, but
-     it's just in case.  */
-  if (DECL_INITIAL (decl))
+  /* We expect a FIELD_DECL from the parser.  Make sure we didn't get
+     something else, as that would confuse the checks below.  */
+  if (TREE_CODE (decl) != FIELD_DECL)
+    {
+      error_at (location, "invalid property declaration");
+      return;      
+    }
+
+  /* Do some spot-checks for the most obvious invalid types.  */
+
+  if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
     {
-      error_at (location, "property can not have an initial value");
+      error_at (location, "property can not be an array");
       return;
     }
 
-  /* TODO: Check that the property type is an Objective-C object or a "POD".  */
+  /* The C++/ObjC++ parser seems to reject the ':' for a bitfield when
+     parsing, while the C/ObjC parser accepts it and gives us a
+     FIELD_DECL with a DECL_INITIAL set.  So we use the DECL_INITIAL
+     to check for a bitfield when doing ObjC.  */
+#ifndef OBJCPLUS
+  if (DECL_INITIAL (decl))
+    {
+      /* A @property is not an actual variable, but it is a way to
+        describe a pair of accessor methods, so its type (which is
+        the type of the return value of the getter and the first
+        argument of the setter) can't be a bitfield (as return values
+        and arguments of functions can not be bitfields).  The
+        underlying instance variable could be a bitfield, but that is
+        a different matter.  */
+      error_at (location, "property can not be a bit-field");
+      return;      
+    }
+#endif
+
+  /* TODO: Check that the property type is an Objective-C object or a
+     "POD".  */
 
   /* Implement -Wproperty-assign-default (which is enabled by default).  */
   if (warn_property_assign_default
@@ -1075,60 +1160,80 @@ objc_add_property_declaration (location_t location, tree decl,
 
   /* Check for duplicate property declarations.  We first check the
      immediate context for a property with the same name.  Any such
-     declarations are an error.  */
+     declarations are an error, unless this is a class extension and
+     we are extending a property from readonly to readwrite.  */
   for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x))
     {
       if (PROPERTY_NAME (x) == DECL_NAME (decl))
        {
-         location_t original_location = DECL_SOURCE_LOCATION (x);
-         
-         error_at (location, "redeclaration of property %qD", decl);
-
-         if (original_location != UNKNOWN_LOCATION)
-           inform (original_location, "originally specified here");
-         return;
-      }
+         if (objc_in_class_extension
+             && property_readonly == 0
+             && PROPERTY_READONLY (x) == 1)
+           {
+             /* This is a class extension, and we are extending an
+                existing readonly property to a readwrite one.
+                That's fine.  :-) */
+             property_extension_in_class_extension = true;
+             break;
+           }
+         else
+           {
+             location_t original_location = DECL_SOURCE_LOCATION (x);
+             
+             error_at (location, "redeclaration of property %qD", decl);
+             
+             if (original_location != UNKNOWN_LOCATION)
+               inform (original_location, "originally specified here");
+             return;
+           }
+       }
     }
 
-  /* We now need to check for existing property declarations (in the
-     superclass, other categories or protocols) and check that the new
-     declaration is not in conflict with existing ones.  */
+  /* If x is not NULL_TREE, we must be in a class extension and we're
+     extending a readonly property.  In that case, no point in
+     searching for another declaration.  */
+  if (x == NULL_TREE)
+    {
+      /* We now need to check for existing property declarations (in
+        the superclass, other categories or protocols) and check that
+        the new declaration is not in conflict with existing
+        ones.  */
 
-  /* Search for a previous, existing declaration of a property with
-     the same name in superclasses, protocols etc.  If one is found,
-     it will be in the 'x' variable.  */
-  x = NULL_TREE;
+      /* Search for a previous, existing declaration of a property
+        with the same name in superclasses, protocols etc.  If one is
+        found, it will be in the 'x' variable.  */
 
-  /* Note that, for simplicity, the following may search again the
-     local context.  That's Ok as nothing will be found (else we'd
-     have thrown an error above); it's only a little inefficient, but
-     the code is simpler.  */
-  switch (TREE_CODE (objc_interface_context))
-    {
-    case CLASS_INTERFACE_TYPE:
-      /* Look up the property in the current @interface (which will
-        find nothing), then its protocols and categories and
-        superclasses.  */
-      x = lookup_property (objc_interface_context, DECL_NAME (decl));
-      break;
-    case CATEGORY_INTERFACE_TYPE:
-      /* Look up the property in the main @interface, then protocols
-        and categories (one of them is ours, and will find nothing)
-        and superclasses.  */
-      x = lookup_property (lookup_interface (CLASS_NAME (objc_interface_context)),
-                          DECL_NAME (decl));
-      break;
-    case PROTOCOL_INTERFACE_TYPE:
-      /* Looks up the property in any protocols attached to the
-        current protocol.  */
-      if (PROTOCOL_LIST (objc_interface_context))
+      /* Note that, for simplicity, the following may search again the
+        local context.  That's Ok as nothing will be found (else we'd
+        have thrown an error above); it's only a little inefficient,
+        but the code is simpler.  */
+      switch (TREE_CODE (objc_interface_context))
        {
-         x = lookup_property_in_protocol_list (PROTOCOL_LIST (objc_interface_context),
-                                               DECL_NAME (decl));
+       case CLASS_INTERFACE_TYPE:
+         /* Look up the property in the current @interface (which
+            will find nothing), then its protocols and categories and
+            superclasses.  */
+         x = lookup_property (objc_interface_context, DECL_NAME (decl));
+         break;
+       case CATEGORY_INTERFACE_TYPE:
+         /* Look up the property in the main @interface, then
+            protocols and categories (one of them is ours, and will
+            find nothing) and superclasses.  */
+         x = lookup_property (lookup_interface (CLASS_NAME (objc_interface_context)),
+                              DECL_NAME (decl));
+         break;
+       case PROTOCOL_INTERFACE_TYPE:
+         /* Looks up the property in any protocols attached to the
+            current protocol.  */
+         if (PROTOCOL_LIST (objc_interface_context))
+           {
+             x = lookup_property_in_protocol_list (PROTOCOL_LIST (objc_interface_context),
+                                                   DECL_NAME (decl));
+           }
+         break;
+       default:
+         gcc_unreachable ();
        }
-      break;
-    default:
-      gcc_unreachable ();
     }
 
   if (x != NULL_TREE)
@@ -1136,10 +1241,11 @@ objc_add_property_declaration (location_t location, tree decl,
       /* An existing property was found; check that it has the same
         types, or it is compatible.  */
       location_t original_location = DECL_SOURCE_LOCATION (x);
-         
+
       if (PROPERTY_NONATOMIC (x) != parsed_property_nonatomic)
        {
-         error_at (location, "'nonatomic' attribute of property %qD conflicts with previous declaration", decl);
+         warning_at (location, 0,
+                     "'nonatomic' attribute of property %qD conflicts with previous declaration", decl);
       
          if (original_location != UNKNOWN_LOCATION)
            inform (original_location, "originally specified here");
@@ -1148,7 +1254,8 @@ objc_add_property_declaration (location_t location, tree decl,
 
       if (PROPERTY_GETTER_NAME (x) != parsed_property_getter_ident)
        {
-         error_at (location, "'getter' attribute of property %qD conflicts with previous declaration", decl);
+         warning_at (location, 0,
+                     "'getter' attribute of property %qD conflicts with previous declaration", decl);
       
          if (original_location != UNKNOWN_LOCATION)
            inform (original_location, "originally specified here");
@@ -1160,7 +1267,8 @@ objc_add_property_declaration (location_t location, tree decl,
        {
          if (PROPERTY_SETTER_NAME (x) != parsed_property_setter_ident)
            {
-             error_at (location, "'setter' attribute of property %qD conflicts with previous declaration", decl);
+             warning_at (location, 0,
+                         "'setter' attribute of property %qD conflicts with previous declaration", decl);
              
              if (original_location != UNKNOWN_LOCATION)
                inform (original_location, "originally specified here");
@@ -1170,7 +1278,8 @@ objc_add_property_declaration (location_t location, tree decl,
 
       if (PROPERTY_ASSIGN_SEMANTICS (x) != property_assign_semantics)
        {
-         error_at (location, "assign semantics attributes of property %qD conflict with previous declaration", decl);
+         warning_at (location, 0,
+                     "assign semantics attributes of property %qD conflict with previous declaration", decl);
       
          if (original_location != UNKNOWN_LOCATION)
            inform (original_location, "originally specified here");
@@ -1180,29 +1289,60 @@ objc_add_property_declaration (location_t location, tree decl,
       /* It's ok to have a readonly property that becomes a readwrite, but not vice versa.  */
       if (PROPERTY_READONLY (x) == 0  &&  property_readonly == 1)
        {
-         error_at (location, "'readonly' attribute of property %qD conflicts with previous declaration", decl);
+         warning_at (location, 0,
+                     "'readonly' attribute of property %qD conflicts with previous declaration", decl);
       
          if (original_location != UNKNOWN_LOCATION)
            inform (original_location, "originally specified here");
          return;
        }
 
-      if (property_readonly)
-       {
-         /* If the property is readonly, it is Ok if the property
-            type is a specialization of the previously declared one.
-            Eg, the superclass returns 'NSArray' while the subclass
-            returns 'NSMutableArray'.  */
-         
-         /* TODO: Check that the types are the same, or more specialized.  */
-         ;
+      /* We now check that the new and old property declarations have
+        the same types (or compatible one).  In the Objective-C
+        tradition of loose type checking, we do type-checking but
+        only generate warnings (not errors) if they do not match.
+        For non-readonly properties, the types must match exactly;
+        for readonly properties, it is allowed to use a "more
+        specialized" type in the new property declaration.  Eg, the
+        superclass has a getter returning (NSArray *) and the
+        subclass a getter returning (NSMutableArray *).  The object's
+        getter returns an (NSMutableArray *); but if you cast the
+        object to the superclass, which is allowed, you'd still
+        expect the getter to return an (NSArray *), which works since
+        an (NSMutableArray *) is an (NSArray *) too.  So, the set of
+        objects belonging to the type of the new @property should be
+        a subset of the set of objects belonging to the type of the
+        old @property.  This is what "specialization" means.  And the
+        reason it only applies to readonly properties is that for a
+        readwrite property the setter would have the opposite
+        requirement - ie that the superclass type is more specialized
+        then the subclass one; hence the only way to satisfy both
+        constraints is that the types match.  */
+
+      /* If the types are not the same in the C sense, we warn ...  */
+      if (!comptypes (TREE_TYPE (x), TREE_TYPE (decl))
+         /* ... unless the property is readonly, in which case we
+            allow a new, more specialized, declaration.  */
+         && (!property_readonly 
+             || !objc_compare_types (TREE_TYPE (x),
+                                     TREE_TYPE (decl), -5, NULL_TREE)))
+       {
+         warning_at (location, 0,
+                     "type of property %qD conflicts with previous declaration", decl);
+         if (original_location != UNKNOWN_LOCATION)
+           inform (original_location, "originally specified here");
+         return;
        }
-      else
-       {
-         /* Else, the types must match exactly.  */
 
-         /* TODO: Check that property types are identical.  */
-         ;
+      /* If we are in a class extension and we're extending a readonly
+        property in the main @interface, we'll just update the
+        existing property with the readwrite flag and potentially the
+        new setter name.  */
+      if (property_extension_in_class_extension)
+       {
+         PROPERTY_READONLY (x) = 0;
+         PROPERTY_SETTER_NAME (x) = parsed_property_setter_ident;
+         return;
        }
     }
 
@@ -1224,6 +1364,13 @@ objc_add_property_declaration (location_t location, tree decl,
   PROPERTY_IVAR_NAME (property_decl) = NULL_TREE;
   PROPERTY_DYNAMIC (property_decl) = 0;
 
+  /* Remember the fact that the property was found in the @optional
+     section in a @protocol, or not.  */
+  if (objc_method_optional_flag)
+    PROPERTY_OPTIONAL (property_decl) = 1;
+  else
+    PROPERTY_OPTIONAL (property_decl) = 0;
+
   /* Note that PROPERTY_GETTER_NAME is always set for all
      PROPERTY_DECLs, and PROPERTY_SETTER_NAME is always set for all
      PROPERTY_DECLs where PROPERTY_READONLY == 0.  Any time we deal
@@ -1241,18 +1388,22 @@ objc_add_property_declaration (location_t location, tree decl,
    in the implementation, and failing that, the protocol list)
    provided for a 'setter' or 'getter' for 'component' with default
    names (ie, if 'component' is "name", then search for "name" and
-   "setName:").  If any is found, then create an artificial property
-   that uses them.  Return NULL_TREE if 'getter' or 'setter' could not
-   be found.  */
+   "setName:").  It is also possible to specify a different
+   'getter_name' (this is used for @optional readonly properties).  If
+   any is found, then create an artificial property that uses them.
+   Return NULL_TREE if 'getter' or 'setter' could not be found.  */
 static tree
 maybe_make_artificial_property_decl (tree interface, tree implementation, 
-                                    tree protocol_list, tree component, bool is_class)
+                                    tree protocol_list, tree component, bool is_class,
+                                    tree getter_name)
 {
-  tree getter_name = component;
   tree setter_name = get_identifier (objc_build_property_setter_name (component));
   tree getter = NULL_TREE;
   tree setter = NULL_TREE;
 
+  if (getter_name == NULL_TREE)
+    getter_name = component;
+
   /* First, check the @interface and all superclasses.  */
   if (interface)
     {
@@ -1317,7 +1468,7 @@ maybe_make_artificial_property_decl (tree interface, tree implementation,
       DECL_SOURCE_LOCATION (property_decl) = input_location;
       TREE_DEPRECATED (property_decl) = 0;
       DECL_ARTIFICIAL (property_decl) = 1;
-             
+
       /* Add property-specific information.  Note that one of
         PROPERTY_GETTER_NAME or PROPERTY_SETTER_NAME may refer to a
         non-existing method; this will generate an error when the
@@ -1332,6 +1483,7 @@ maybe_make_artificial_property_decl (tree interface, tree implementation,
       PROPERTY_ASSIGN_SEMANTICS (property_decl) = 0;
       PROPERTY_IVAR_NAME (property_decl) = NULL_TREE;
       PROPERTY_DYNAMIC (property_decl) = 0;
+      PROPERTY_OPTIONAL (property_decl) = 0;
 
       if (!getter)
        PROPERTY_HAS_NO_GETTER (property_decl) = 1;
@@ -1412,7 +1564,7 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
                 properties.  */
              if (!IS_CLASS (rtype))
                x = lookup_property_in_protocol_list (rprotos, property_ident);
-             
+
              if (x == NULL_TREE)
                {
                  /* Ok, no property.  Maybe it was an
@@ -1424,7 +1576,25 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
                                                           NULL_TREE,
                                                           rprotos, 
                                                           property_ident,
-                                                          IS_CLASS (rtype));
+                                                          IS_CLASS (rtype),
+                                                          NULL_TREE);
+               }
+             else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x))
+               {
+                 /* This is a special, complicated case.  If the
+                    property is optional, and is read-only, then the
+                    property is always used for reading, but an
+                    eventual existing non-property setter can be used
+                    for writing.  We create an artificial property
+                    decl copying the getter from the optional
+                    property, and looking up the setter in the
+                    interface.  */
+                 x = maybe_make_artificial_property_decl (NULL_TREE,
+                                                          NULL_TREE,
+                                                          rprotos,
+                                                          property_ident,
+                                                          false,
+                                                          PROPERTY_GETTER_NAME (x));             
                }
            }
        }
@@ -1440,23 +1610,15 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
                 || TREE_CODE (t) == COMPONENT_REF)
            t = TREE_OPERAND (t, 0);
          
-         if (t == UOBJC_SUPER_decl)
-           {
-             /* TODO: Check if this is correct also for 'super' in categories.  */
-             interface_type = lookup_interface (CLASS_SUPER_NAME (implementation_template));
-           }
+         if (t == UOBJC_SUPER_decl)    
+           interface_type = lookup_interface (CLASS_SUPER_NAME (implementation_template));
          else if (t == self_decl)
            interface_type = lookup_interface (CLASS_NAME (implementation_template));
 
-         /* TODO: Protocols.  */
-
          if (interface_type)
            {
              if (TREE_CODE (objc_method_context) != CLASS_METHOD_DECL)
-               {
-                 x = lookup_property (interface_type, property_ident);
-                 /* TODO: Protocols.  */
-               }
+               x = lookup_property (interface_type, property_ident);
        
              if (x == NULL_TREE)
                {
@@ -1471,12 +1633,25 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
                  if (t == self_decl)
                    implementation = objc_implementation_context;
                  
-                 /* TODO: Protocols.  */
-
                  x = maybe_make_artificial_property_decl 
                    (interface_type, implementation, NULL_TREE,
                     property_ident,
-                    (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL));
+                    (TREE_CODE (objc_method_context) == CLASS_METHOD_DECL),
+                    NULL_TREE);
+               }
+             else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x))
+               {
+                 tree implementation = NULL_TREE;
+                 
+                 if (t == self_decl)
+                   implementation = objc_implementation_context;
+                 
+                 x = maybe_make_artificial_property_decl (interface_type,
+                                                          implementation,
+                                                          NULL_TREE,
+                                                          property_ident,
+                                                          false,
+                                                          PROPERTY_GETTER_NAME (x));             
                }
            }
        }
@@ -1541,18 +1716,34 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
                                                           implementation,
                                                           protocol_list, 
                                                           property_ident,
-                                                          IS_CLASS (rtype));
+                                                          IS_CLASS (rtype),
+                                                          NULL_TREE);
                }
+             else if (PROPERTY_OPTIONAL (x) && PROPERTY_READONLY (x))
+               {
+                 tree implementation = NULL_TREE;
+
+                 if (objc_implementation_context
+                     && CLASS_NAME (objc_implementation_context) 
+                     == OBJC_TYPE_NAME (interface_type))
+                   implementation = objc_implementation_context;
+                 
+                 x = maybe_make_artificial_property_decl (interface_type,
+                                                          implementation,
+                                                          protocol_list,
+                                                          property_ident,
+                                                          false,
+                                                          PROPERTY_GETTER_NAME (x));             
+               }             
            }
        }
     }
 
-  /* TODO: Fix compiling super.accessor.  */
-
   if (x)
     {
       tree expression;
       tree getter_call;
+      tree deprecated_method_prototype = NULL_TREE;
 
       /* We have an additional nasty problem here; if this
         PROPERTY_REF needs to become a 'getter', then the conversion
@@ -1580,14 +1771,16 @@ objc_maybe_build_component_ref (tree object, tree property_ident)
       if (PROPERTY_HAS_NO_GETTER (x))
        getter_call = NULL_TREE;
       else
-       getter_call = objc_finish_message_expr (object,
-                                               PROPERTY_GETTER_NAME (x),
-                                               NULL_TREE);
-
-      if (TREE_DEPRECATED (x))
-       warn_deprecated_use (x, NULL_TREE);
-
-      expression = build3 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call);
+       getter_call = objc_finish_message_expr
+         (object, PROPERTY_GETTER_NAME (x), NULL_TREE,
+          /* Disable the immediate deprecation warning if the getter
+             is deprecated, but record the fact that the getter is
+             deprecated by setting PROPERTY_REF_DEPRECATED_GETTER to
+             the method prototype.  */
+          &deprecated_method_prototype);
+
+      expression = build4 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call,
+                          deprecated_method_prototype);
       SET_EXPR_LOCATION (expression, input_location);
       TREE_SIDE_EFFECTS (expression) = 1;
       
@@ -1635,26 +1828,31 @@ objc_build_class_component_ref (tree class_name, tree property_ident)
       error_at (input_location, "could not find interface for class %qE", class_name); 
       return error_mark_node;
     }
+  else
+    {
+      if (TREE_DEPRECATED (rtype))
+       warning (OPT_Wdeprecated_declarations, "class %qE is deprecated", class_name);    
+    }
 
   x = maybe_make_artificial_property_decl (rtype, NULL_TREE, NULL_TREE,
                                           property_ident,
-                                          true);
+                                          true, NULL_TREE);
   
   if (x)
     {
       tree expression;
       tree getter_call;
+      tree deprecated_method_prototype = NULL_TREE;
 
       if (PROPERTY_HAS_NO_GETTER (x))
        getter_call = NULL_TREE;
       else
-       getter_call = objc_finish_message_expr (object,
-                                               PROPERTY_GETTER_NAME (x),
-                                               NULL_TREE);
-      if (TREE_DEPRECATED (x))
-       warn_deprecated_use (x, NULL_TREE);
+       getter_call = objc_finish_message_expr
+         (object, PROPERTY_GETTER_NAME (x), NULL_TREE,
+          &deprecated_method_prototype);
 
-      expression = build3 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call);
+      expression = build4 (PROPERTY_REF, TREE_TYPE(x), object, x, getter_call,
+                          deprecated_method_prototype);
       SET_EXPR_LOCATION (expression, input_location);
       TREE_SIDE_EFFECTS (expression) = 1;
 
@@ -1683,6 +1881,42 @@ objc_is_property_ref (tree node)
     return false;
 }
 
+/* This function builds a setter call for a PROPERTY_REF (real, for a
+   declared property, or artificial, for a dot-syntax accessor which
+   is not corresponding to a property).  'lhs' must be a PROPERTY_REF
+   (the caller must check this beforehand).  'rhs' is the value to
+   assign to the property.  A plain setter call is returned, or
+   error_mark_node if the property is readonly.  */
+
+static tree
+objc_build_setter_call (tree lhs, tree rhs)
+{
+  tree object_expr = PROPERTY_REF_OBJECT (lhs);
+  tree property_decl = PROPERTY_REF_PROPERTY_DECL (lhs);
+  
+  if (PROPERTY_READONLY (property_decl))
+    {
+      error ("readonly property can not be set");        
+      return error_mark_node;
+    }
+  else
+    {
+      tree setter_argument = build_tree_list (NULL_TREE, rhs);
+      tree setter;
+      
+      /* TODO: Check that the setter return type is 'void'.  */
+
+      /* TODO: Decay arguments in C.  */
+      setter = objc_finish_message_expr (object_expr, 
+                                        PROPERTY_SETTER_NAME (property_decl),
+                                        setter_argument, NULL);
+      return setter;
+    }
+
+  /* Unreachable, but the compiler may not realize.  */
+  return error_mark_node;
+}
+
 /* This hook routine is called when a MODIFY_EXPR is being built.  We
    check what is being modified; if it is a PROPERTY_REF, we need to
    generate a 'setter' function call for the property.  If this is not
@@ -1702,32 +1936,193 @@ objc_maybe_build_modify_expr (tree lhs, tree rhs)
 {
   if (lhs && TREE_CODE (lhs) == PROPERTY_REF)
     {
-      tree object_expr = PROPERTY_REF_OBJECT (lhs);
-      tree property_decl = PROPERTY_REF_PROPERTY_DECL (lhs);
+      /* Building a simple call to the setter method would work for cases such as
 
-      if (PROPERTY_READONLY (property_decl))
-       {
-         error ("readonly property can not be set");     
-         return error_mark_node;
-       }
-      else
-       {
-         tree setter_argument = build_tree_list (NULL_TREE, rhs);
-         tree setter;
+      object.count = 1;
 
-         /* TODO: Check that the setter return type is 'void'.  */
+      but wouldn't work for cases such as
 
-         /* TODO: Decay argument in C.  */
-         setter = objc_finish_message_expr (object_expr, 
-                                            PROPERTY_SETTER_NAME (property_decl),
-                                            setter_argument);
-         return setter;
-       }
+      count = object2.count = 1;
+
+      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:
+
+      (temp = rhs; [object setProperty: temp]; temp)
+      */
+      tree temp_variable_decl, bind;
+      /* s1, s2 and s3 are the tree statements that we need in the
+        compound expression.  */
+      tree s1, s2, s3, compound_expr;
+      
+      /* 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);
+      
+      /* 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.  */
+      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);
+
+      /* Now build the compound statement (s1, s2, s3) */
+      compound_expr = build_compound_expr (input_location, build_compound_expr (input_location, s1, s2), s3);
+
+      /* Without this, with -Wall you get a 'valued computed is not
+        used' every time there is a "object.property = x" where the
+        value of the resulting MODIFY_EXPR is not used.  That is
+        correct (maybe a more sophisticated implementation could
+        avoid generating the compound expression if not needed), but
+        we need to turn it off.  */
+      TREE_NO_WARNING (compound_expr) = 1;
+      return compound_expr;
     }
   else
     return NULL_TREE;
 }
 
+/* This hook is called by the frontend when one of the four unary
+   expressions PREINCREMENT_EXPR, POSTINCREMENT_EXPR,
+   PREDECREMENT_EXPR and POSTDECREMENT_EXPR is being built with an
+   argument which is a PROPERTY_REF.  For example, this happens if you have
+
+   object.count++;
+
+   where 'count' is a property.  We need to use the 'getter' and
+   'setter' for the property in an appropriate way to build the
+   appropriate expression.  'code' is the code for the expression (one
+   of the four mentioned above); 'argument' is the PROPERTY_REF, and
+   'increment' is how much we need to add or subtract.  */   
+tree
+objc_build_incr_expr_for_property_ref (location_t location,
+                                      enum tree_code code, 
+                                      tree argument, tree increment)
+{
+  /* Here are the expressions that we want to build:
+
+     For PREINCREMENT_EXPR / PREDECREMENT_EXPR:
+    (temp = [object property] +/- increment, [object setProperty: temp], temp)
+    
+    For POSTINCREMENT_EXPR / POSTECREMENT_EXPR:
+    (temp = [object property], [object setProperty: temp +/- increment], temp) */
+  
+  tree temp_variable_decl, bind;
+  /* s1, s2 and s3 are the tree statements that we need in the
+     compound expression.  */
+  tree s1, s2, s3, compound_expr;
+  
+  /* Safety check.  */
+  if (!argument || TREE_CODE (argument) != PROPERTY_REF)
+    return error_mark_node;
+
+  /* Declare __objc_property_temp in a local bind.  */
+  temp_variable_decl = objc_create_temporary_var (TREE_TYPE (argument), "__objc_property_temp");
+  DECL_SOURCE_LOCATION (temp_variable_decl) = location;
+  bind = build3 (BIND_EXPR, void_type_node, temp_variable_decl, NULL, NULL);
+  SET_EXPR_LOCATION (bind, location);
+  TREE_SIDE_EFFECTS (bind) = 1;
+  add_stmt (bind);
+  
+  /* Now build the compound statement.  */
+  
+  /* Note that the 'getter' is generated at gimplify time; at this
+     time, we can simply put the property_ref (ie, argument) wherever
+     we want the getter ultimately to be.  */
+  
+  /* s1: __objc_property_temp = [object property] <+/- increment> */
+  switch (code)
+    {
+    case PREINCREMENT_EXPR:     
+      /* __objc_property_temp = [object property] + increment */
+      s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE,
+                             NOP_EXPR,
+                             location, build2 (PLUS_EXPR, TREE_TYPE (argument), 
+                                               argument, increment), NULL_TREE);
+      break;
+    case PREDECREMENT_EXPR:
+      /* __objc_property_temp = [object property] - increment */
+      s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE,
+                             NOP_EXPR,
+                             location, build2 (MINUS_EXPR, TREE_TYPE (argument), 
+                                               argument, increment), NULL_TREE);
+      break;
+    case POSTINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      /* __objc_property_temp = [object property] */
+      s1 = build_modify_expr (location, temp_variable_decl, NULL_TREE,
+                             NOP_EXPR,
+                             location, argument, NULL_TREE);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  
+  /* s2: [object setProperty: __objc_property_temp <+/- increment>] */
+  switch (code)
+    {
+    case PREINCREMENT_EXPR:     
+    case PREDECREMENT_EXPR:
+      /* [object setProperty: __objc_property_temp] */
+      s2 = objc_build_setter_call (argument, temp_variable_decl);
+      break;
+    case POSTINCREMENT_EXPR:
+      /* [object setProperty: __objc_property_temp + increment] */
+      s2 = objc_build_setter_call (argument,
+                                  build2 (PLUS_EXPR, TREE_TYPE (argument), 
+                                          temp_variable_decl, increment));
+      break;
+    case POSTDECREMENT_EXPR:
+      /* [object setProperty: __objc_property_temp - increment] */
+      s2 = objc_build_setter_call (argument,
+                                  build2 (MINUS_EXPR, TREE_TYPE (argument), 
+                                          temp_variable_decl, increment));
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  /* 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, location); 
+  
+  /* s3: __objc_property_temp */
+  s3 = convert (TREE_TYPE (argument), temp_variable_decl);
+  
+  /* Now build the compound statement (s1, s2, s3) */
+  compound_expr = build_compound_expr (location, build_compound_expr (location, s1, s2), s3);
+
+  /* Prevent C++ from warning with -Wall that "right operand of comma
+     operator has no effect".  */
+  TREE_NO_WARNING (compound_expr) = 1;
+  return compound_expr;
+}
+
 tree
 objc_build_method_signature (bool is_class_method, tree rettype, tree selector,
                             tree optparms, bool ellipsis)
@@ -1875,32 +2270,54 @@ objc_build_struct (tree klass, tree fields, tree super_name)
       fields = base;
     }
 
-  /* NB: Calling finish_struct() may cause type TYPE_LANG_SPECIFIC fields
-     in all variants of this RECORD_TYPE to be clobbered, but it is therein
-     that we store protocol conformance info (e.g., 'NSObject <MyProtocol>').
-     Hence, we must squirrel away the ObjC-specific information before calling
+  /* NB: Calling finish_struct() may cause type TYPE_OBJC_INFO
+     information in all variants of this RECORD_TYPE to be destroyed
+     (this is because the C frontend manipulates TYPE_LANG_SPECIFIC
+     for something else and then will change all variants to use the
+     same resulting TYPE_LANG_SPECIFIC, ignoring the fact that we use
+     it for ObjC protocols and that such propagation will make all
+     variants use the same objc_info), but it is therein that we store
+     protocol conformance info (e.g., 'NSObject <MyProtocol>').
+     Hence, we must save the ObjC-specific information before calling
      finish_struct(), and then reinstate it afterwards.  */
 
-  for (t = TYPE_NEXT_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t))
+  for (t = TYPE_MAIN_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t))
     {
-      if (!TYPE_HAS_OBJC_INFO (t))
-       {
-         INIT_TYPE_OBJC_INFO (t);
-         TYPE_OBJC_INTERFACE (t) = klass;
-       }
+      INIT_TYPE_OBJC_INFO (t);
       VEC_safe_push (tree, heap, objc_info, TYPE_OBJC_INFO (t));
     }
 
-  /* Point the struct at its related Objective-C class.  */
-  INIT_TYPE_OBJC_INFO (s);
-  TYPE_OBJC_INTERFACE (s) = klass;
-
   s = objc_finish_struct (s, fields);
 
-  for (i = 0, t = TYPE_NEXT_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t), i++)
+  for (i = 0, t = TYPE_MAIN_VARIANT (s); t; t = TYPE_NEXT_VARIANT (t), i++)
     {
+      /* We now want to restore the different TYPE_OBJC_INFO, but we
+        have the additional problem that the C frontend doesn't just
+        copy TYPE_LANG_SPECIFIC from one variant to the other; it
+        actually makes all of them the *same* TYPE_LANG_SPECIFIC.  As
+        we need a different TYPE_OBJC_INFO for each (and
+        TYPE_OBJC_INFO is a field in TYPE_LANG_SPECIFIC), we need to
+        make a copy of each TYPE_LANG_SPECIFIC before we modify
+        TYPE_OBJC_INFO.  */
+      if (TYPE_LANG_SPECIFIC (t))
+       {
+         /* Create a copy of TYPE_LANG_SPECIFIC.  */
+         struct lang_type *old_lang_type = TYPE_LANG_SPECIFIC (t);
+         ALLOC_OBJC_TYPE_LANG_SPECIFIC (t);
+         memcpy (TYPE_LANG_SPECIFIC (t), old_lang_type,
+                 SIZEOF_OBJC_TYPE_LANG_SPECIFIC);
+       }
+      else
+       {
+         /* Just create a new one.  */
+         ALLOC_OBJC_TYPE_LANG_SPECIFIC (t);
+       }
+      /* Replace TYPE_OBJC_INFO with the saved one.  This restores any
+        protocol information that may have been associated with the
+        type.  */
       TYPE_OBJC_INFO (t) = VEC_index (tree, objc_info, i);
-      /* Replace the IDENTIFIER_NODE with an actual @interface.  */
+      /* Replace the IDENTIFIER_NODE with an actual @interface now
+        that we have it.  */
       TYPE_OBJC_INTERFACE (t) = klass;
     }
   VEC_free (tree, heap, objc_info);
@@ -1914,61 +2331,6 @@ objc_build_struct (tree klass, tree fields, tree super_name)
   return s;
 }
 
-/* Build a type differing from TYPE only in that TYPE_VOLATILE is set.
-   Unlike tree.c:build_qualified_type(), preserve TYPE_LANG_SPECIFIC in the
-   process.  */
-static tree
-objc_build_volatilized_type (tree type)
-{
-  tree t;
-
-  /* Check if we have not constructed the desired variant already.  */
-  for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-    {
-      /* The type qualifiers must (obviously) match up.  */
-      if (!TYPE_VOLATILE (t)
-         || (TYPE_READONLY (t) != TYPE_READONLY (type))
-         || (TYPE_RESTRICT (t) != TYPE_RESTRICT (type)))
-       continue;
-
-      /* For pointer types, the pointees (and hence their TYPE_LANG_SPECIFIC
-        info, if any) must match up.  */
-      if (POINTER_TYPE_P (t)
-         && (TREE_TYPE (t) != TREE_TYPE (type)))
-       continue;
-
-      /* Only match up the types which were previously volatilized in similar fashion and not
-        because they were declared as such. */
-      if (!lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (t)))
-       continue;
-
-      /* Everything matches up!  */
-      return t;
-    }
-
-  /* Ok, we could not re-use any of the pre-existing variants.  Create
-     a new one.  */
-  t = build_variant_type_copy (type);
-  TYPE_VOLATILE (t) = 1;
-
-  TYPE_ATTRIBUTES (t) = merge_attributes (TYPE_ATTRIBUTES (type),
-                                         tree_cons (get_identifier ("objc_volatilized"),
-                                         NULL_TREE,
-                                         NULL_TREE));
-  if (TREE_CODE (t) == ARRAY_TYPE)
-    TREE_TYPE (t) = objc_build_volatilized_type (TREE_TYPE (t));
-
-  /* Set up the canonical type information. */
-  if (TYPE_STRUCTURAL_EQUALITY_P (type))
-    SET_TYPE_STRUCTURAL_EQUALITY (t);
-  else if (TYPE_CANONICAL (type) != type)
-    TYPE_CANONICAL (t) = objc_build_volatilized_type (TYPE_CANONICAL (type));
-  else
-    TYPE_CANONICAL (t) = t;
-
-  return t;
-}
-
 /* Mark DECL as being 'volatile' for purposes of Darwin
    _setjmp()/_longjmp() exception handling.  Called from
    objc_mark_locals_volatile().  */
@@ -1981,17 +2343,44 @@ objc_volatilize_decl (tree decl)
       && (TREE_CODE (decl) == VAR_DECL
          || TREE_CODE (decl) == PARM_DECL))
     {
-      tree t = TREE_TYPE (decl);
+      if (local_variables_to_volatilize == NULL)
+       local_variables_to_volatilize = VEC_alloc (tree, gc, 8);
 
-      t = objc_build_volatilized_type (t);
+      VEC_safe_push (tree, gc, local_variables_to_volatilize, decl);
+    }
+}
 
-      TREE_TYPE (decl) = t;
-      TREE_THIS_VOLATILE (decl) = 1;
-      TREE_SIDE_EFFECTS (decl) = 1;
-      DECL_REGISTER (decl) = 0;
+/* Called when parsing of a function completes; if any local variables
+   in the function were marked as variables to volatilize, change them
+   to volatile.  We do this at the end of the function when the
+   warnings about discarding 'volatile' have already been produced.
+   We are making the variables as volatile just to force the compiler
+   to preserve them between setjmp/longjmp, but we don't want warnings
+   for them as they aren't really volatile.  */
+void
+objc_finish_function (void)
+{
+  /* If there are any local variables to volatilize, volatilize them.  */
+  if (local_variables_to_volatilize)
+    {
+      int i;
+      tree decl;
+      FOR_EACH_VEC_ELT (tree, local_variables_to_volatilize, i, decl)
+       {
+         tree t = TREE_TYPE (decl);
+
+         t = build_qualified_type (t, TYPE_QUALS (t) | TYPE_QUAL_VOLATILE);
+         TREE_TYPE (decl) = t;
+         TREE_THIS_VOLATILE (decl) = 1;
+         TREE_SIDE_EFFECTS (decl) = 1;
+         DECL_REGISTER (decl) = 0;
 #ifndef OBJCPLUS
-      C_DECL_REGISTER (decl) = 0;
+         C_DECL_REGISTER (decl) = 0;
 #endif
+       }
+
+      /* Now we delete the vector.  This sets it to NULL as well.  */
+      VEC_free (tree, gc, local_variables_to_volatilize);
     }
 }
 
@@ -2124,8 +2513,8 @@ objc_common_type (tree type1, tree type2)
    returning 'true', this routine may issue warnings related to, e.g.,
    protocol conformance.  When returning 'false', the routine must
    produce absolutely no warnings; the C or C++ front-end will do so
-   instead, if needed.  If either LTYP or RTYP is not an Objective-C type,
-   the routine must return 'false'.
+   instead, if needed.  If either LTYP or RTYP is not an Objective-C
+   type, the routine must return 'false'.
 
    The ARGNO parameter is encoded as follows:
      >= 1      Parameter number (CALLEE contains function being called);
@@ -2133,8 +2522,11 @@ objc_common_type (tree type1, tree type2)
      -1                Assignment;
      -2                Initialization;
      -3                Comparison (LTYP and RTYP may match in either direction);
-     -4                Silent comparison (for C++ overload resolution).
-  */
+     -4                Silent comparison (for C++ overload resolution);
+     -5                Silent "specialization" comparison for RTYP to be a "specialization" 
+                of LTYP (a specialization means that RTYP is LTYP plus some constraints, 
+                so that each object of type RTYP is also of type LTYP).  This is used
+                when comparing property types.  */
 
 bool
 objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
@@ -2219,11 +2611,24 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
   if (rcls && TREE_CODE (rcls) == IDENTIFIER_NODE)
     rcls = NULL_TREE;
 
-  /* If either type is an unqualified 'id', we're done.  */
-  if ((!lproto && objc_is_object_id (ltyp))
-      || (!rproto && objc_is_object_id (rtyp)))
-    return true;
-
+  /* If either type is an unqualified 'id', we're done.  This is because
+     an 'id' can be assigned to or from any type with no warnings.  */
+  if (argno != -5)
+    {
+      if ((!lproto && objc_is_object_id (ltyp))
+         || (!rproto && objc_is_object_id (rtyp)))
+       return true;
+    }
+  else
+    {
+      /* For property checks, though, an 'id' is considered the most
+        general type of object, hence if you try to specialize an
+        'NSArray *' (ltyp) property with an 'id' (rtyp) one, we need
+        to warn.  */
+      if (!lproto && objc_is_object_id (ltyp))
+       return true;
+    }
+  
   pointers_compatible = (TYPE_MAIN_VARIANT (ltyp) == TYPE_MAIN_VARIANT (rtyp));
 
   /* If the underlying types are the same, and at most one of them has
@@ -2239,13 +2644,22 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
   else
     {
       if (!pointers_compatible)
-       pointers_compatible
-         = (objc_is_object_id (ltyp) || objc_is_object_id (rtyp));
+       {
+         /* Again, if any of the two is an 'id', we're satisfied,
+            unless we're comparing properties, in which case only an
+            'id' on the left-hand side (old property) is good
+            enough.  */
+         if (argno != -5)
+           pointers_compatible
+             = (objc_is_object_id (ltyp) || objc_is_object_id (rtyp));
+         else
+           pointers_compatible = objc_is_object_id (ltyp);         
+       }
 
       if (!pointers_compatible)
        pointers_compatible = DERIVED_FROM_P (ltyp, rtyp);
 
-      if (!pointers_compatible && argno <= -3)
+      if (!pointers_compatible && (argno == -3 || argno == -4))
        pointers_compatible = DERIVED_FROM_P (rtyp, ltyp);
     }
 
@@ -2271,6 +2685,7 @@ objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
         ObjC-specific.  */
       switch (argno)
        {
+       case -5:
        case -4:
          return false;
 
@@ -2322,24 +2737,6 @@ objc_have_common_type (tree ltyp, tree rtyp, int argno, tree callee)
   return false;
 }
 
-/* Check if LTYP and RTYP have the same type qualifiers.  If either type
-   lives in the volatilized hash table, ignore the 'volatile' bit when
-   making the comparison.  */
-
-bool
-objc_type_quals_match (tree ltyp, tree rtyp)
-{
-  int lquals = TYPE_QUALS (ltyp), rquals = TYPE_QUALS (rtyp);
-
-  if (lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (ltyp)))
-    lquals &= ~TYPE_QUAL_VOLATILE;
-
-  if (lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (rtyp)))
-    rquals &= ~TYPE_QUAL_VOLATILE;
-
-  return (lquals == rquals);
-}
-
 #ifndef OBJCPLUS
 /* Determine if CHILD is derived from PARENT.  The routine assumes that
    both parameters are RECORD_TYPEs, and is non-reflexive.  */
@@ -2459,19 +2856,12 @@ objc_check_global_decl (tree decl)
     error ("redeclaration of Objective-C class %qs", IDENTIFIER_POINTER (id));
 }
 
-/* Return a non-volatalized version of TYPE. */
-
-tree
-objc_non_volatilized_type (tree type)
-{
-  if (lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (type)))
-    type = build_qualified_type (type, (TYPE_QUALS (type) & ~TYPE_QUAL_VOLATILE));
-  return type;
-}
-
-/* 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.  */
+/* 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.  This function is often called when
+   PROTOCOLS is NULL_TREE, in which case we simply look up the
+   appropriate INTERFACE.  */
 
 tree
 objc_get_protocol_qualified_type (tree interface, tree protocols)
@@ -2497,7 +2887,22 @@ objc_get_protocol_qualified_type (tree interface, tree protocols)
                  : xref_tag (RECORD_TYPE, type));
        }
       else
-        return interface;
+       {
+         /* This case happens when we are given an 'interface' which
+            is not a valid class name.  For example if a typedef was
+            used, and 'interface' really is the identifier of the
+            typedef, but when you resolve it you don't get an
+            Objective-C class, but something else, such as 'int'.
+            This is an error; protocols make no sense unless you use
+            them with Objective-C objects.  */
+         error_at (input_location, "only Objective-C object types can be qualified with a protocol");
+
+         /* Try to recover.  Ignore the invalid class name, and treat
+            the object as an 'id' to silence further warnings about
+            the class.  */
+         type = objc_object_type;
+         is_ptr = true;
+       }
     }
 
   if (protocols)
@@ -2521,7 +2926,8 @@ objc_get_protocol_qualified_type (tree interface, tree protocols)
 
       /* Look up protocols and install in lang specific list.  */
       DUP_TYPE_OBJC_INFO (type, TYPE_MAIN_VARIANT (type));
-      TYPE_OBJC_PROTOCOL_LIST (type) = lookup_and_install_protocols (protocols);
+      TYPE_OBJC_PROTOCOL_LIST (type) = lookup_and_install_protocols
+       (protocols, /* definition_required */ false);
 
       /* For RECORD_TYPEs, point to the @interface; for 'id' and 'Class',
         return the pointer to the new pointee variant.  */
@@ -2549,7 +2955,8 @@ check_protocol_recursively (tree proto, tree list)
       tree pp = TREE_VALUE (p);
 
       if (TREE_CODE (pp) == IDENTIFIER_NODE)
-       pp = lookup_protocol (pp);
+       pp = lookup_protocol (pp, /* warn if deprecated */ false,
+                             /* definition_required */ false);
 
       if (pp == proto)
        fatal_error ("protocol %qE has circular dependency",
@@ -2559,11 +2966,15 @@ check_protocol_recursively (tree proto, tree list)
     }
 }
 
-/* Look up PROTOCOLS, and return a list of those that are found.
-   If none are found, return NULL.  */
-
+/* Look up PROTOCOLS, and return a list of those that are found.  If
+   none are found, return NULL.  Note that this function will emit a
+   warning if a protocol is found and is deprecated.  If
+   'definition_required', then warn if the protocol is found but is
+   not defined (ie, if we only saw a forward-declaration of the
+   protocol (as in "@protocol NSObject;") not a real definition with
+   the list of methods).  */
 static tree
-lookup_and_install_protocols (tree protocols)
+lookup_and_install_protocols (tree protocols, bool definition_required)
 {
   tree proto;
   tree return_value = NULL_TREE;
@@ -2574,7 +2985,8 @@ lookup_and_install_protocols (tree protocols)
   for (proto = protocols; proto; proto = TREE_CHAIN (proto))
     {
       tree ident = TREE_VALUE (proto);
-      tree p = lookup_protocol (ident);
+      tree p = lookup_protocol (ident, /* warn_if_deprecated */ true,
+                               definition_required);
 
       if (p)
        return_value = chainon (return_value,
@@ -3915,7 +4327,6 @@ add_class_reference (tree ident)
 
 /* Get a class reference, creating it if necessary.  Also create the
    reference variable.  */
-
 tree
 objc_get_class_reference (tree ident)
 {
@@ -4110,6 +4521,9 @@ objc_declare_class (tree ident_list)
 
          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);
        }
@@ -4348,6 +4762,10 @@ objc_generate_write_barrier (tree lhs, enum tree_code modifycode, tree rhs)
   tree result = NULL_TREE, outer;
   int strong_cast_p = 0, outer_gc_p = 0, indirect_p = 0;
 
+  /* This function is currently only used with the next runtime with
+     garbage collection enabled (-fobjc-gc).  */
+  gcc_assert (flag_next_runtime);
+
   /* See if we have any lhs casts, and strip them out.  NB: The lvalue casts
      will have been transformed to the form '*(type *)&expr'.  */
   if (TREE_CODE (lhs) == INDIRECT_REF)
@@ -4579,32 +4997,6 @@ get_class_ivars (tree interface, bool inherited)
   return ivar_chain;
 }
 
-/* Create a temporary variable of type 'type'.  If 'name' is set, uses
-   the specified name, else use no name.  Returns the declaration of
-   the type.  The 'name' is mostly useful for debugging.
-*/
-static tree
-objc_create_temporary_var (tree type, const char *name)
-{
-  tree decl;
-
-  if (name != NULL)
-    {
-      decl = build_decl (input_location,
-                        VAR_DECL, get_identifier (name), type);
-    }
-  else
-    {
-      decl = build_decl (input_location,
-                        VAR_DECL, NULL_TREE, type);
-    }
-  TREE_USED (decl) = 1;
-  DECL_ARTIFICIAL (decl) = 1;
-  DECL_IGNORED_P (decl) = 1;
-  DECL_CONTEXT (decl) = current_function_decl;
-
-  return decl;
-}
 \f
 /* Exception handling constructs.  We begin by having the parser do most
    of the work and passing us blocks.  What we do next depends on whether
@@ -4653,17 +5045,49 @@ static GTY(()) tree objc_eh_personality_decl;
 tree
 objc_eh_runtime_type (tree type)
 {
-  return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names);
+  /* Use 'ErrorMarkNode' as class name when error_mark_node is found
+     to prevent an ICE.  Note that we know that the compiler will
+     terminate with an error and this 'ErrorMarkNode' class name will
+     never be actually used.  */
+  if (type == error_mark_node)
+    return add_objc_string (get_identifier ("ErrorMarkNode"), class_names);
+  else
+    return add_objc_string (OBJC_TYPE_NAME (TREE_TYPE (type)), class_names);
 }
 
 tree
 objc_eh_personality (void)
 {
   if (!flag_objc_sjlj_exceptions && !objc_eh_personality_decl)
-    objc_eh_personality_decl = build_personality_function ("gnu_objc");
+    objc_eh_personality_decl = build_personality_function 
+                               (flag_next_runtime
+                                               ? "objc"
+                                               : "gnu_objc");
   return objc_eh_personality_decl;
 }
-#endif
+#endif
+
+void
+objc_maybe_warn_exceptions (location_t loc)
+{
+  /* -fobjc-exceptions is required to enable Objective-C exceptions.
+     For example, on Darwin, ObjC exceptions require a sufficiently
+     recent version of the runtime, so the user must ask for them
+     explicitly.  On other platforms, at the moment -fobjc-exceptions
+     triggers -fexceptions which again is required for exceptions to
+     work.  */
+  if (!flag_objc_exceptions)
+    {
+      /* Warn only once per compilation unit.  */
+      static bool warned = false;
+
+      if (!warned)
+       {
+         error_at (loc, "%<-fobjc-exceptions%> is required to enable Objective-C exception syntax");
+         warned = true;
+       }
+    }
+}
 
 /* Build __builtin_eh_pointer, or the moral equivalent.  In the case
    of Darwin, we'll arrange for it to be initialized (and associated
@@ -4728,7 +5152,7 @@ next_sjlj_build_enter_and_setjmp (void)
   t = build_fold_addr_expr_loc (input_location, t);
 #ifdef OBJCPLUS
   /* Convert _setjmp argument to type that is expected.  */
-  if (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl)))
+  if (prototype_p (TREE_TYPE (objc_setjmp_decl)))
     t = convert (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (objc_setjmp_decl))), t);
   else
     t = convert (ptr_type_node, t);
@@ -4966,25 +5390,18 @@ objc_begin_try_stmt (location_t try_locus, tree body)
   c->end_try_locus = input_location;
   cur_try_context = c;
 
-  /* -fobjc-exceptions is required to enable Objective-C exceptions.
-     For example, on Darwin, ObjC exceptions require a sufficiently
-     recent version of the runtime, so the user must ask for them
-     explicitly.  On other platforms, at the moment -fobjc-exceptions
-     triggers -fexceptions which again is required for exceptions to
-     work.
-  */
-  if (!flag_objc_exceptions)
-    {
-      error_at (try_locus, "%<-fobjc-exceptions%> is required to enable Objective-C exception syntax");
-    }
-
+  /* Collect the list of local variables.  We'll mark them as volatile
+     at the end of compilation of this function to prevent them being
+     clobbered by setjmp/longjmp.  */
   if (flag_objc_sjlj_exceptions)
     objc_mark_locals_volatile (NULL);
 }
 
 /* Called just after parsing "@catch (parm)".  Open a binding level,
    enter DECL into the binding level, and initialize it.  Leave the
-   binding level open while the body of the compound statement is parsed.  */
+   binding level open while the body of the compound statement is
+   parsed.  If DECL is NULL_TREE, then we are compiling "@catch(...)"
+   which we compile as "@catch(id tmp_variable)".  */
 
 void
 objc_begin_catch_clause (tree decl)
@@ -4994,46 +5411,99 @@ objc_begin_catch_clause (tree decl)
   /* Begin a new scope that the entire catch clause will live in.  */
   compound = c_begin_compound_stmt (true);
 
-  /* The parser passed in a PARM_DECL, but what we really want is a VAR_DECL.  */
-  decl = build_decl (input_location,
-                    VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
-  lang_hooks.decls.pushdecl (decl);
+  /* Create the appropriate declaration for the argument.  */
+ if (decl == error_mark_node)
+   type = error_mark_node;
+ else
+   {
+     if (decl == NULL_TREE)
+       {
+        /* If @catch(...) was specified, create a temporary variable of
+           type 'id' and use it.  */
+        decl = objc_create_temporary_var (objc_object_type, "__objc_generic_catch_var");
+        DECL_SOURCE_LOCATION (decl) = input_location;
+       }
+     else
+       {
+        /* The parser passed in a PARM_DECL, but what we really want is a VAR_DECL.  */
+        decl = build_decl (input_location,
+                           VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+       }
+     lang_hooks.decls.pushdecl (decl);
 
-  /* Since a decl is required here by syntax, don't warn if its unused.  */
-  /* ??? As opposed to __attribute__((unused))?  Anyway, this appears to
-     be what the previous objc implementation did.  */
-  TREE_USED (decl) = 1;
-  DECL_READ_P (decl) = 1;
+     /* Mark the declaration as used so you never any warnings whether
+       you use the exception argument or not.  TODO: Implement a
+       -Wunused-exception-parameter flag, which would cause warnings
+       if exception parameter is not used.  */
+     TREE_USED (decl) = 1;
+     DECL_READ_P (decl) = 1;
 
-  /* Verify that the type of the catch is valid.  It must be a pointer
-     to an Objective-C class, or "id" (which is catch-all).  */
-  type = TREE_TYPE (decl);
+     type = TREE_TYPE (decl);
+   }
 
-  if (POINTER_TYPE_P (type) && objc_is_object_id (TREE_TYPE (type)))
-    type = NULL;
-  else if (!POINTER_TYPE_P (type) || !TYPED_OBJECT (TREE_TYPE (type)))
+ /* Verify that the type of the catch is valid.  It must be a pointer
+    to an Objective-C class, or "id" (which is catch-all).  */
+ if (type == error_mark_node)
+   {
+     ;/* Just keep going.  */
+   }
+ else if (!objc_type_valid_for_messaging (type, false))
     {
       error ("@catch parameter is not a known Objective-C class type");
       type = error_mark_node;
     }
-  else if (cur_try_context->catch_list)
+  else if (TYPE_HAS_OBJC_INFO (TREE_TYPE (type))
+          && TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (type)))
+    {
+      error ("@catch parameter can not be protocol-qualified");
+      type = error_mark_node;      
+    }
+  else if (objc_is_object_id (TREE_TYPE (type)))
+    type = NULL;
+  else
     {
-      /* Examine previous @catch clauses and see if we've already
-        caught the type in question.  */
-      tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
-      for (; !tsi_end_p (i); tsi_next (&i))
+      /* If 'type' was built using typedefs, we need to get rid of
+        them and get a simple pointer to the class.  */
+      bool is_typedef = false;
+      tree x = TYPE_MAIN_VARIANT (type);
+      
+      /* Skip from the pointer to the pointee.  */
+      if (TREE_CODE (x) == POINTER_TYPE)
+       x = TREE_TYPE (x);
+      
+      /* Traverse typedef aliases */
+      while (TREE_CODE (x) == RECORD_TYPE && OBJC_TYPE_NAME (x)
+            && TREE_CODE (OBJC_TYPE_NAME (x)) == TYPE_DECL
+            && DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (x)))
+       {
+         is_typedef = true;
+         x = DECL_ORIGINAL_TYPE (OBJC_TYPE_NAME (x));
+       }
+
+      /* If it was a typedef, build a pointer to the final, original
+        class.  */
+      if (is_typedef)
+       type = build_pointer_type (x);
+
+      if (cur_try_context->catch_list)
        {
-         tree stmt = tsi_stmt (i);
-         t = CATCH_TYPES (stmt);
-         if (t == error_mark_node)
-           continue;
-         if (!t || DERIVED_FROM_P (TREE_TYPE (t), TREE_TYPE (type)))
+         /* Examine previous @catch clauses and see if we've already
+            caught the type in question.  */
+         tree_stmt_iterator i = tsi_start (cur_try_context->catch_list);
+         for (; !tsi_end_p (i); tsi_next (&i))
            {
-             warning (0, "exception of type %<%T%> will be caught",
-                      TREE_TYPE (type));
-             warning_at  (EXPR_LOCATION (stmt), 0, "   by earlier handler for %<%T%>",
-                          TREE_TYPE (t ? t : objc_object_type));
-             break;
+             tree stmt = tsi_stmt (i);
+             t = CATCH_TYPES (stmt);
+             if (t == error_mark_node)
+               continue;
+             if (!t || DERIVED_FROM_P (TREE_TYPE (t), TREE_TYPE (type)))
+               {
+                 warning (0, "exception of type %<%T%> will be caught",
+                          TREE_TYPE (type));
+                 warning_at  (EXPR_LOCATION (stmt), 0, "   by earlier handler for %<%T%>",
+                              TREE_TYPE (t ? t : objc_object_type));
+                 break;
+               }
            }
        }
     }
@@ -5126,10 +5596,7 @@ objc_build_throw_stmt (location_t loc, tree throw_expr)
 {
   tree args;
 
-  if (!flag_objc_exceptions)
-    {
-      error_at (loc, "%<-fobjc-exceptions%> is required to enable Objective-C exception syntax");
-    }
+  objc_maybe_warn_exceptions (loc);
 
   if (throw_expr == NULL)
     {
@@ -5139,13 +5606,21 @@ objc_build_throw_stmt (location_t loc, tree throw_expr)
           || cur_try_context->current_catch == NULL)
        {
          error_at (loc, "%<@throw%> (rethrow) used outside of a @catch block");
-         return NULL_TREE;
+         return error_mark_node;
        }
 
       /* Otherwise the object is still sitting in the EXC_PTR_EXPR
         value that we get from the runtime.  */
       throw_expr = objc_build_exc_ptr ();
     }
+  else if (throw_expr != error_mark_node)
+    {
+      if (!objc_type_valid_for_messaging (TREE_TYPE (throw_expr), true))
+       {
+         error_at (loc, "%<@throw%> argument is not an object");
+         return error_mark_node;
+       }
+    }
 
   /* A throw is just a call to the runtime throw function with the
      object as a parameter.  */
@@ -5155,28 +5630,59 @@ objc_build_throw_stmt (location_t loc, tree throw_expr)
 }
 
 tree
-objc_build_synchronized (location_t start_locus, tree mutex, tree body)
+objc_build_synchronized (location_t start_locus, tree object_expr, tree body)
 {
-  tree args, call;
-
-  /* First lock the mutex.  */
-  mutex = save_expr (mutex);
-  args = tree_cons (NULL, mutex, NULL);
-  call = build_function_call (input_location,
-                             objc_sync_enter_decl, args);
-  SET_EXPR_LOCATION (call, start_locus);
-  add_stmt (call);
+  /* object_expr should never be NULL; but in case it is, convert it to
+     error_mark_node.  */
+  if (object_expr == NULL)
+    object_expr = error_mark_node;
 
-  /* Build the mutex unlock.  */
-  args = tree_cons (NULL, mutex, NULL);
-  call = build_function_call (input_location,
-                             objc_sync_exit_decl, args);
-  SET_EXPR_LOCATION (call, input_location);
-
-  /* Put the that and the body in a TRY_FINALLY.  */
-  objc_begin_try_stmt (start_locus, body);
-  objc_build_finally_clause (input_location, call);
-  return objc_finish_try_stmt ();
+  /* Validate object_expr.  If not valid, set it to error_mark_node.  */
+  if (object_expr != error_mark_node)
+    {
+      if (!objc_type_valid_for_messaging (TREE_TYPE (object_expr), true))
+       {
+         error_at (start_locus, "%<@synchronized%> argument is not an object");
+         object_expr = error_mark_node;
+       }
+    }
+  
+  if (object_expr == error_mark_node)
+    {
+      /* If we found an error, we simply ignore the '@synchronized'.
+        Compile the body so we can keep going with minimal
+        casualties.  */
+      return add_stmt (body);
+    }
+  else
+    {
+      tree call;
+      tree args;
+
+      /* objc_sync_enter (object_expr); */      
+      object_expr = save_expr (object_expr);
+      args = tree_cons (NULL, object_expr, NULL);
+      call = build_function_call (input_location,
+                                 objc_sync_enter_decl, args);
+      SET_EXPR_LOCATION (call, start_locus);
+      add_stmt (call);
+
+      /* Build "objc_sync_exit (object_expr);" but do not add it yet;
+        it goes inside the @finalize() clause.  */
+      args = tree_cons (NULL, object_expr, NULL);
+      call = build_function_call (input_location,
+                                 objc_sync_exit_decl, args);
+      SET_EXPR_LOCATION (call, input_location);
+
+      /* @try { body; } */
+      objc_begin_try_stmt (start_locus, body);
+      
+      /* @finally { objc_sync_exit (object_expr); } */
+      objc_build_finally_clause (input_location, call);
+      
+      /* End of try statement.  */
+      return objc_finish_try_stmt ();
+    }
 }
 
 \f
@@ -5337,6 +5843,10 @@ build_private_template (tree klass)
         can emit stabs for this struct type.  */
       if (flag_debug_only_used_symbols && TYPE_STUB_DECL (record))
        TREE_USED (TYPE_STUB_DECL (record)) = 1;
+
+      /* Copy the attributes from the class to the type.  */
+      if (TREE_DEPRECATED (klass))
+       TREE_DEPRECATED (record) = 1;
     }
 }
 \f
@@ -5512,8 +6022,9 @@ encode_method_prototype (tree method_decl)
       /* If a type size is not known, bail out.  */
       if (sz < 0)
        {
-         error ("type %q+D does not have a known size",
-                type);
+         error_at (DECL_SOURCE_LOCATION (method_decl),
+                   "type %qT does not have a known size",
+                   type);
          /* Pretend that the encoding succeeded; the compilation will
             fail nevertheless.  */
          goto finish_encoding;
@@ -7552,7 +8063,7 @@ objc_build_message_expr (tree mess)
                         method_params);
 #endif
 
-  return objc_finish_message_expr (receiver, sel_name, method_params);
+  return objc_finish_message_expr (receiver, sel_name, method_params, NULL);
 }
 
 /* Look up method SEL_NAME that would be suitable for receiver
@@ -7581,10 +8092,20 @@ lookup_method_in_hash_lists (tree sel_name, int is_class)
 /* The 'objc_finish_message_expr' routine is called from within
    'objc_build_message_expr' for non-template functions.  In the case of
    C++ template functions, it is called from 'build_expr_from_tree'
-   (in decl2.c) after RECEIVER and METHOD_PARAMS have been expanded.  */
-
+   (in decl2.c) after RECEIVER and METHOD_PARAMS have been expanded.
+
+   If the DEPRECATED_METHOD_PROTOTYPE argument is NULL, then we warn
+   if the method being used is deprecated.  If it is not NULL, instead
+   of deprecating, we set *DEPRECATED_METHOD_PROTOTYPE to the method
+   prototype that was used and is deprecated.  This is useful for
+   getter calls that are always generated when compiling dot-syntax
+   expressions, even if they may not be used.  In that case, we don't
+   want the warning immediately; we produce it (if needed) at gimplify
+   stage when we are sure that the deprecated getter is being
+   used.  */
 tree
-objc_finish_message_expr (tree receiver, tree sel_name, tree method_params)
+objc_finish_message_expr (tree receiver, tree sel_name, tree method_params,
+                         tree *deprecated_method_prototype)
 {
   tree method_prototype = NULL_TREE, rprotos = NULL_TREE, rtype;
   tree selector, retval, class_tree;
@@ -7801,7 +8322,12 @@ objc_finish_message_expr (tree receiver, tree sel_name, tree method_params)
         is often used precisely to turn off warnings associated with
         the object being of a particular class.  */
       if (TREE_DEPRECATED (method_prototype)  &&  rtype != NULL_TREE)
-       warn_deprecated_use (method_prototype, NULL_TREE);
+       {
+         if (deprecated_method_prototype)
+           *deprecated_method_prototype = method_prototype;
+         else
+           warn_deprecated_use (method_prototype, NULL_TREE);
+       }
     }
 
 
@@ -7946,7 +8472,8 @@ tree
 objc_build_protocol_expr (tree protoname)
 {
   tree expr;
-  tree p = lookup_protocol (protoname);
+  tree p = lookup_protocol (protoname, /* warn if deprecated */ true,
+                           /* definition_required */ false);
 
   if (!p)
     {
@@ -8363,19 +8890,69 @@ add_method_to_hash_list (hash *hash_list, tree method)
 static tree
 objc_add_method (tree klass, tree method, int is_class, bool is_optional)
 {
-  tree mth;
+  tree existing_method = NULL_TREE;
+
+  /* The first thing we do is look up the method in the list of
+     methods already defined in the interface (or implementation).  */
+  if (is_class)
+    existing_method = lookup_method (CLASS_CLS_METHODS (klass), method);
+  else
+    existing_method = lookup_method (CLASS_NST_METHODS (klass), method);
+
+  /* In the case of protocols, we have a second list of methods to
+     consider, the list of optional ones.  */
+  if (TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE)
+    {
+      /* @required methods are added to the protocol's normal list.
+        @optional methods are added to the protocol's OPTIONAL lists.
+        Note that adding the methods to the optional lists disables
+        checking that the methods are implemented by classes
+        implementing the protocol, since these checks only use the
+        CLASS_CLS_METHODS and CLASS_NST_METHODS.  */
+
+      /* First of all, if the method to add is @optional, and we found
+        it already existing as @required, emit an error.  */
+      if (is_optional && existing_method)
+       {
+         error ("method %<%c%E%> declared %<@optional%> and %<@required%> at the same time",
+                (is_class ? '+' : '-'),
+                METHOD_SEL_NAME (existing_method));
+         inform (DECL_SOURCE_LOCATION (existing_method),
+                 "previous declaration of %<%c%E%> as %<@required%>",
+                 (is_class ? '+' : '-'),
+                 METHOD_SEL_NAME (existing_method));
+       }
+
+      /* Now check the list of @optional methods if we didn't find the
+        method in the @required list.  */
+      if (!existing_method)
+       {
+         if (is_class)
+           existing_method = lookup_method (PROTOCOL_OPTIONAL_CLS_METHODS (klass), method);
+         else
+           existing_method = lookup_method (PROTOCOL_OPTIONAL_NST_METHODS (klass), method);
+         
+         if (!is_optional && existing_method)
+           {
+             error ("method %<%c%E%> declared %<@optional%> and %<@required%> at the same time",
+                    (is_class ? '+' : '-'),
+                    METHOD_SEL_NAME (existing_method));
+             inform (DECL_SOURCE_LOCATION (existing_method),
+                     "previous declaration of %<%c%E%> as %<@optional%>",
+                     (is_class ? '+' : '-'),
+                     METHOD_SEL_NAME (existing_method));
+           }
+       }
+    }
 
-  /* @optional methods are added to protocol's OPTIONAL list */
-  if (is_optional)
+  /* If the method didn't exist already, add it.  */
+  if (!existing_method)
     {
-      gcc_assert (TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE);
-      if (!(mth = lookup_method (is_class
-                               ? PROTOCOL_OPTIONAL_CLS_METHODS (klass)
-                               : PROTOCOL_OPTIONAL_NST_METHODS (klass), 
-                                                               method)))
+      if (is_optional)
        {
          if (is_class)
            {
+             /* Put the method on the list in reverse order.  */
              TREE_CHAIN (method) = PROTOCOL_OPTIONAL_CLS_METHODS (klass);
              PROTOCOL_OPTIONAL_CLS_METHODS (klass) = method;
            }
@@ -8385,36 +8962,50 @@ objc_add_method (tree klass, tree method, int is_class, bool is_optional)
              PROTOCOL_OPTIONAL_NST_METHODS (klass) = method;
            }
        }
-    }
-  else if (!(mth = lookup_method (is_class
-                            ? CLASS_CLS_METHODS (klass)
-                            : CLASS_NST_METHODS (klass), method)))
-    {
-      /* put method on list in reverse order */
-      if (is_class)
-       {
-         DECL_CHAIN (method) = CLASS_CLS_METHODS (klass);
-         CLASS_CLS_METHODS (klass) = method;
-       }
       else
        {
-         DECL_CHAIN (method) = CLASS_NST_METHODS (klass);
-         CLASS_NST_METHODS (klass) = method;
+         if (is_class)
+           {
+             DECL_CHAIN (method) = CLASS_CLS_METHODS (klass);
+             CLASS_CLS_METHODS (klass) = method;
+           }
+         else
+           {
+             DECL_CHAIN (method) = CLASS_NST_METHODS (klass);
+             CLASS_NST_METHODS (klass) = method;
+           }
        }
     }
   else
     {
-      /* When processing an @interface for a class or category, give hard
-        errors on methods with identical selectors but differing argument
-        and/or return types. We do not do this for @implementations, because
-        C/C++ will do it for us (i.e., there will be duplicate function
-        definition errors).  */
+      /* The method was already defined.  Check that the types match
+        for an @interface for a class or category, or for a
+        @protocol.  Give hard errors on methods with identical
+        selectors but differing argument and/or return types.  We do
+        not do this for @implementations, because C/C++ will do it
+        for us (i.e., there will be duplicate function definition
+        errors).  */
       if ((TREE_CODE (klass) == CLASS_INTERFACE_TYPE
-          || TREE_CODE (klass) == CATEGORY_INTERFACE_TYPE)
-         && !comp_proto_with_proto (method, mth, 1))
-       error ("duplicate declaration of method %<%c%E%>",
-               is_class ? '+' : '-',
-               METHOD_SEL_NAME (mth));
+          || TREE_CODE (klass) == CATEGORY_INTERFACE_TYPE
+          /* Starting with GCC 4.6, we emit the same error for
+             protocols too.  The situation is identical to
+             @interfaces as there is no possible meaningful reason
+             for defining the same method with different signatures
+             in the very same @protocol.  If that was allowed,
+             whenever the protocol is used (both at compile and run
+             time) there wouldn't be any meaningful way to decide
+             which of the two method signatures should be used.  */
+          || TREE_CODE (klass) == PROTOCOL_INTERFACE_TYPE)
+         && !comp_proto_with_proto (method, existing_method, 1))
+       {
+         error ("duplicate declaration of method %<%c%E%> with conflicting types",
+                (is_class ? '+' : '-'),
+                METHOD_SEL_NAME (existing_method));
+         inform (DECL_SOURCE_LOCATION (existing_method),
+                 "previous declaration of %<%c%E%>",
+                 (is_class ? '+' : '-'),
+                 METHOD_SEL_NAME (existing_method));
+       }
     }
 
   if (is_class)
@@ -8738,9 +9329,19 @@ check_methods (tree chain, tree implementation, int mtype)
     {
       /* If the method is associated with a dynamic property, then it
         is Ok not to have the method implementation, as it will be
-        generated dynamically at runtime.  */
-      tree property = METHOD_PROPERTY_CONTEXT (chain);
-      if (property != NULL_TREE && PROPERTY_DYNAMIC (property))
+        generated dynamically at runtime.  To decide if the method is
+        associated with a @dynamic property, we search the list of
+        @synthesize and @dynamic for this implementation, and look
+        for any @dynamic property with the same setter or getter name
+        as this method.  */
+      tree x;
+      for (x = IMPL_PROPERTY_DECL (implementation); x; x = TREE_CHAIN (x))
+       if (PROPERTY_DYNAMIC (x)
+           && (PROPERTY_GETTER_NAME (x) == METHOD_SEL_NAME (chain)
+               || PROPERTY_SETTER_NAME (x) == METHOD_SEL_NAME (chain)))
+         break;
+      
+      if (x != NULL_TREE)
        {
          chain = TREE_CHAIN (chain); /* next method...  */
          continue;
@@ -8751,6 +9352,7 @@ check_methods (tree chain, tree implementation, int mtype)
          /* If the method is a property setter/getter, we'll still
             allow it to be missing if it is implemented by
             'interface' or any of its superclasses.  */
+         tree property = METHOD_PROPERTY_CONTEXT (chain);
          if (property)
            {
              /* Note that since this is a property getter/setter, it
@@ -8864,13 +9466,21 @@ check_methods_accessible (tree chain, tree context, int mtype)
     {
       /* If the method is associated with a dynamic property, then it
         is Ok not to have the method implementation, as it will be
-        generated dynamically at runtime.  */
-      tree property = METHOD_PROPERTY_CONTEXT (chain);
-      if (property != NULL_TREE  &&  PROPERTY_DYNAMIC (property))
+        generated dynamically at runtime.  Search for any @dynamic
+        property with the same setter or getter name as this
+        method.  TODO: Use a hashtable lookup.  */
+      tree x;
+      for (x = IMPL_PROPERTY_DECL (base_context); x; x = TREE_CHAIN (x))
+       if (PROPERTY_DYNAMIC (x)
+           && (PROPERTY_GETTER_NAME (x) == METHOD_SEL_NAME (chain)
+               || PROPERTY_SETTER_NAME (x) == METHOD_SEL_NAME (chain)))
+         break;
+      
+      if (x != NULL_TREE)
        {
          chain = TREE_CHAIN (chain); /* next method...  */
          continue;
-       }
+       }       
 
       context = base_context;
       while (context)
@@ -9001,21 +9611,24 @@ check_protocols (tree proto_list, const char *type, tree name)
     }
 }
 \f
-/* Make sure that the class CLASS_NAME is defined
-   CODE says which kind of thing CLASS_NAME ought to be.
-   It can be CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE,
-   CATEGORY_INTERFACE_TYPE, or CATEGORY_IMPLEMENTATION_TYPE.  */
-
+/* Make sure that the class CLASS_NAME is defined CODE says which kind
+   of thing CLASS_NAME ought to be.  It can be CLASS_INTERFACE_TYPE,
+   CLASS_IMPLEMENTATION_TYPE, CATEGORY_INTERFACE_TYPE, or
+   CATEGORY_IMPLEMENTATION_TYPE.  For a CATEGORY_INTERFACE_TYPE,
+   SUPER_NAME is the name of the category.  For a class extension,
+   CODE is CATEGORY_INTERFACE_TYPE and SUPER_NAME is NULL_TREE.  */
 static tree
 start_class (enum tree_code code, tree class_name, tree super_name,
-            tree protocol_list)
+            tree protocol_list, tree attributes)
 {
-  tree klass, decl;
+  tree klass = NULL_TREE;
+  tree decl;
 
 #ifdef OBJCPLUS
-  if (current_namespace != global_namespace) {
-    error ("Objective-C declarations may only appear in global scope");
-  }
+  if (current_namespace != global_namespace)
+    {
+      error ("Objective-C declarations may only appear in global scope");
+    }
 #endif /* OBJCPLUS */
 
   if (objc_implementation_context)
@@ -9026,8 +9639,14 @@ start_class (enum tree_code code, tree class_name, tree super_name,
       objc_implementation_context = NULL_TREE;
     }
 
-  klass = make_node (code);
-  TYPE_LANG_SLOT_1 (klass) = make_tree_vec (CLASS_LANG_SLOT_ELTS);
+  /* If this is a class extension, we'll be "reopening" the existing
+     CLASS_INTERFACE_TYPE, so in that case there is no need to create
+     a new node.  */
+  if (code != CATEGORY_INTERFACE_TYPE || super_name != NULL_TREE)
+    {
+      klass = make_node (code);
+      TYPE_LANG_SLOT_1 (klass) = make_tree_vec (CLASS_LANG_SLOT_ELTS);
+    }
 
   /* Check for existence of the super class, if one was specified.  Note
      that we must have seen an @interface, not just a @class.  If we
@@ -9036,8 +9655,12 @@ start_class (enum tree_code code, tree class_name, tree super_name,
       && super_name)
     {
       tree super = objc_is_class_name (super_name);
+      tree super_interface = NULL_TREE;
 
-      if (!super || !lookup_interface (super))
+      if (super)
+       super_interface = lookup_interface (super);
+      
+      if (!super_interface)
        {
          error ("cannot find interface declaration for %qE, superclass of %qE",
                 super ? super : super_name,
@@ -9045,12 +9668,20 @@ start_class (enum tree_code code, tree class_name, tree super_name,
          super_name = NULL_TREE;
        }
       else
-       super_name = super;
+       {
+         if (TREE_DEPRECATED (super_interface))
+           warning (OPT_Wdeprecated_declarations, "class %qE is deprecated", 
+                    super);
+         super_name = super;
+       }
     }
 
-  CLASS_NAME (klass) = class_name;
-  CLASS_SUPER_NAME (klass) = super_name;
-  CLASS_CLS_METHODS (klass) = NULL_TREE;
+  if (code != CATEGORY_INTERFACE_TYPE || super_name != NULL_TREE)
+    {
+      CLASS_NAME (klass) = class_name;
+      CLASS_SUPER_NAME (klass) = super_name;
+      CLASS_CLS_METHODS (klass) = NULL_TREE;
+    }
 
   if (! objc_is_class_name (class_name)
       && (decl = lookup_name (class_name)))
@@ -9072,10 +9703,13 @@ start_class (enum tree_code code, tree class_name, tree super_name,
            {
              error ("reimplementation of class %qE",
                     class_name);
-             return error_mark_node;
+             /* TODO: error message saying where it was previously
+                implemented.  */
+             break;
            }
-       implemented_classes = tree_cons (NULL_TREE, class_name,
-                                        implemented_classes);
+       if (chain == NULL_TREE)
+         implemented_classes = tree_cons (NULL_TREE, class_name,
+                                          implemented_classes);
       }
 
       /* Reset for multiple classes per file.  */
@@ -9127,7 +9761,25 @@ start_class (enum tree_code code, tree class_name, tree super_name,
        
       if (protocol_list)
        CLASS_PROTOCOL_LIST (klass)
-         = lookup_and_install_protocols (protocol_list);
+         = lookup_and_install_protocols (protocol_list, /* definition_required */ true);
+
+      /* Determine if 'deprecated', the only attribute we recognize
+        for classes, was used.  Ignore all other attributes for now,
+        but store them in the klass.  */
+      if (attributes)
+       {
+         tree attribute;
+         for (attribute = attributes; attribute; attribute = TREE_CHAIN (attribute))
+           {
+             tree name = TREE_PURPOSE (attribute);
+             
+             if (is_attribute_p  ("deprecated", name))
+               TREE_DEPRECATED (klass) = 1;
+             else
+               warning (OPT_Wattributes, "%qE attribute directive ignored", name);
+           }
+         TYPE_ATTRIBUTES (klass) = attributes;
+       }
       break;     
 
     case CATEGORY_INTERFACE_TYPE:
@@ -9144,14 +9796,42 @@ start_class (enum tree_code code, tree class_name, tree super_name,
            exit (FATAL_EXIT_CODE);
          }
        else
-         add_category (class_category_is_assoc_with, klass);
-       
-       if (protocol_list)
-         CLASS_PROTOCOL_LIST (klass)
-           = lookup_and_install_protocols (protocol_list);
+         {
+           if (TREE_DEPRECATED (class_category_is_assoc_with))
+             warning (OPT_Wdeprecated_declarations, "class %qE is deprecated", 
+                      class_name);
+
+           if (super_name == NULL_TREE)
+             {
+               /* This is a class extension.  Get the original
+                  interface, and continue working on it.  */
+               objc_in_class_extension = true;
+               klass = class_category_is_assoc_with;
+
+               if (protocol_list)
+                 {
+                   /* Append protocols to the original protocol
+                      list.  */
+                   CLASS_PROTOCOL_LIST (klass)
+                     = chainon (CLASS_PROTOCOL_LIST (klass),
+                                lookup_and_install_protocols
+                                (protocol_list,
+                                 /* definition_required */ true));
+                 }
+             }
+           else
+             {
+               add_category (class_category_is_assoc_with, klass);
+               
+               if (protocol_list)
+                 CLASS_PROTOCOL_LIST (klass)
+                   = lookup_and_install_protocols
+                   (protocol_list, /* definition_required */ true);
+             }
+         }
       }
       break;
-
+       
     case CATEGORY_IMPLEMENTATION_TYPE:
       /* Reset for multiple classes per file.  */
       method_slot = 0;
@@ -9224,6 +9904,8 @@ continue_class (tree klass)
       }
     case CLASS_INTERFACE_TYPE:
       {
+       if (objc_in_class_extension)
+         return NULL_TREE;
 #ifdef OBJCPLUS
        push_lang_context (lang_name_c);
 #endif /* OBJCPLUS */
@@ -9363,7 +10045,7 @@ lookup_ivar (tree interface, tree instance_variable_name)
 /* This routine synthesizes a 'getter' method.  This is only called
    for @synthesize properties.  */
 static void
-objc_synthesize_getter (tree klass, tree class_method, tree property)
+objc_synthesize_getter (tree klass, tree class_methods ATTRIBUTE_UNUSED, tree property)
 {
   location_t location = DECL_SOURCE_LOCATION (property);
   tree fn, decl;
@@ -9375,9 +10057,9 @@ objc_synthesize_getter (tree klass, tree class_method, tree property)
                     PROPERTY_GETTER_NAME (property)))
     return;
 
-  /* Find declaration of the property getter in the interface. There
-     must be one.  TODO: Search superclasses as well.  */
-  decl = lookup_method (CLASS_NST_METHODS (class_method), PROPERTY_GETTER_NAME (property));
+  /* Find declaration of the property getter in the interface (or
+     superclass, or protocol). There must be one.  */
+  decl = lookup_method_static (klass, PROPERTY_GETTER_NAME (property), 0);
 
   /* If one not declared in the interface, this condition has already
      been reported as user error (because property was not declared in
@@ -9542,7 +10224,7 @@ objc_synthesize_getter (tree klass, tree class_method, tree property)
 /* This routine synthesizes a 'setter' method.  */
 
 static void
-objc_synthesize_setter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree property)
+objc_synthesize_setter (tree klass, tree class_methods ATTRIBUTE_UNUSED, tree property)
 {
   location_t location = DECL_SOURCE_LOCATION (property);
   tree fn, decl;
@@ -9554,9 +10236,9 @@ objc_synthesize_setter (tree klass ATTRIBUTE_UNUSED, tree class_method, tree pro
                     PROPERTY_SETTER_NAME (property)))
     return;
 
-  /* Find declaration of the property setter in the interface. There
-     must be one.  TODO: Search superclasses as well.  */
-  decl = lookup_method (CLASS_NST_METHODS (class_method), PROPERTY_SETTER_NAME (property));
+  /* Find declaration of the property setter in the interface (or
+     superclass, or protocol). There must be one.  */
+  decl = lookup_method_static (klass, PROPERTY_SETTER_NAME (property), 0);
 
   /* If one not declared in the interface, this condition has already
      been reported as user error (because property was not declared in
@@ -9736,10 +10418,11 @@ objc_add_synthesize_declaration_for_property (location_t location, tree interfac
 {
   /* Find the @property declaration.  */
   tree property;
+  tree x;
 
   /* Check that synthesize or dynamic has not already been used for
      the same property.  */
-  for (property = CLASS_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property))
+  for (property = IMPL_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property))
     if (PROPERTY_NAME (property) == property_name)
       {
        location_t original_location = DECL_SOURCE_LOCATION (property);
@@ -9756,12 +10439,9 @@ objc_add_synthesize_declaration_for_property (location_t location, tree interfac
        return;
       }
 
-  /* Check that the property is declared in the interface.  */
-  /* TODO: This only check the immediate class; we need to check the
-     superclass (and categories ?) as well.  */
-  for (property = CLASS_PROPERTY_DECL (interface); property; property = TREE_CHAIN (property))
-    if (PROPERTY_NAME (property) == property_name)
-      break;
+  /* Check that the property is declared in the interface.  It could
+     also be declared in a superclass or protocol.  */
+  property = lookup_property (interface, property_name);
 
   if (!property)
     {
@@ -9785,16 +10465,97 @@ objc_add_synthesize_declaration_for_property (location_t location, tree interfac
 
   /* Check that the instance variable exists.  You can only use an
      instance variable from the same class, not one from the
-     superclass.  */
-  if (!is_ivar (CLASS_IVARS (interface), ivar_name))
-    error_at (location, "ivar %qs used by %<@synthesize%> declaration must be an existing ivar", 
-             IDENTIFIER_POINTER (property_name));
+     superclass (this makes sense as it allows us to check that an
+     instance variable is only used in one synthesized property).  */
+  {
+    tree ivar = is_ivar (CLASS_IVARS (interface), ivar_name);
+    tree type_of_ivar;
+    if (!ivar)
+      {
+       error_at (location, "ivar %qs used by %<@synthesize%> declaration must be an existing ivar", 
+                 IDENTIFIER_POINTER (property_name));
+       return;
+      }
+
+    if (DECL_BIT_FIELD_TYPE (ivar))
+      type_of_ivar = DECL_BIT_FIELD_TYPE (ivar);
+    else
+      type_of_ivar = TREE_TYPE (ivar);
+    
+    /* If the instance variable has a different C type, we throw an error ...  */
+    if (!comptypes (TREE_TYPE (property), type_of_ivar)
+       /* ... unless the property is readonly, in which case we allow
+          the instance variable to be more specialized (this means we
+          can generate the getter all right and it works).  */
+       && (!PROPERTY_READONLY (property)
+           || !objc_compare_types (TREE_TYPE (property),
+                                   type_of_ivar, -5, NULL_TREE)))
+      {
+       location_t original_location = DECL_SOURCE_LOCATION (ivar);
+       
+       error_at (location, "property %qs is using instance variable %qs of incompatible type",
+                 IDENTIFIER_POINTER (property_name),
+                 IDENTIFIER_POINTER (ivar_name));
+       
+       if (original_location != UNKNOWN_LOCATION)
+         inform (original_location, "originally specified here");
+      }
+
+    /* If the instance variable is a bitfield, the property must be
+       'assign', 'nonatomic' because the runtime getter/setter helper
+       do not work with bitfield instance variables.  */
+    if (DECL_BIT_FIELD_TYPE (ivar))
+      {
+       /* If there is an error, we return and not generate any
+          getter/setter because trying to set up the runtime
+          getter/setter helper calls with bitfields is at high risk
+          of ICE.  */
+
+       if (PROPERTY_ASSIGN_SEMANTICS (property) != OBJC_PROPERTY_ASSIGN)
+         {
+           location_t original_location = DECL_SOURCE_LOCATION (ivar);
+           
+           error_at (location, "'assign' property %qs is using bit-field instance variable %qs",
+                     IDENTIFIER_POINTER (property_name),
+                     IDENTIFIER_POINTER (ivar_name));
+       
+           if (original_location != UNKNOWN_LOCATION)
+             inform (original_location, "originally specified here");
+           return;
+         }
 
-  /* TODO: Check that the types of the instance variable and of the
-     property match.  */
+       if (!PROPERTY_NONATOMIC (property))
+         {
+           location_t original_location = DECL_SOURCE_LOCATION (ivar);
+           
+           error_at (location, "'atomic' property %qs is using bit-field instance variable %qs",
+                     IDENTIFIER_POINTER (property_name),
+                     IDENTIFIER_POINTER (ivar_name));
+           
+           if (original_location != UNKNOWN_LOCATION)
+             inform (original_location, "originally specified here");
+           return;
+         }
+      }
+  }
 
-  /* TODO: Check that no other property is using the same instance
+  /* Check that no other property is using the same instance
      variable.  */
+  for (x = IMPL_PROPERTY_DECL (objc_implementation_context); x; x = TREE_CHAIN (x))
+    if (PROPERTY_IVAR_NAME (x) == ivar_name)
+      {
+       location_t original_location = DECL_SOURCE_LOCATION (x);
+       
+       error_at (location, "property %qs is using the same instance variable as property %qs",
+                 IDENTIFIER_POINTER (property_name),
+                 IDENTIFIER_POINTER (PROPERTY_NAME (x)));
+       
+       if (original_location != UNKNOWN_LOCATION)
+         inform (original_location, "originally specified here");
+       
+       /* We keep going on.  This won't cause the compiler to fail;
+          the failure would most likely be at runtime.  */
+      }
 
   /* Note that a @synthesize (and only a @synthesize) always sets
      PROPERTY_IVAR_NAME to a non-NULL_TREE.  You can recognize a
@@ -9876,7 +10637,7 @@ objc_add_dynamic_declaration_for_property (location_t location, tree interface,
 
   /* Check that synthesize or dynamic has not already been used for
      the same property.  */
-  for (property = CLASS_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property))
+  for (property = IMPL_PROPERTY_DECL (objc_implementation_context); property; property = TREE_CHAIN (property))
     if (PROPERTY_NAME (property) == property_name)
       {
        location_t original_location = DECL_SOURCE_LOCATION (property);
@@ -9893,11 +10654,9 @@ objc_add_dynamic_declaration_for_property (location_t location, tree interface,
        return;
       }
 
-  /* Check that the property is declared in the corresponding
-     interface.  */
-  for (property = CLASS_PROPERTY_DECL (interface); property; property = TREE_CHAIN (property))
-    if (PROPERTY_NAME (property) == property_name)
-      break;
+  /* Check that the property is declared in the interface.  It could
+     also be declared in a superclass or protocol.  */
+  property = lookup_property (interface, property_name);
 
   if (!property)
     {
@@ -9907,16 +10666,6 @@ objc_add_dynamic_declaration_for_property (location_t location, tree interface,
     }
   else
     {
-      /* Mark the original PROPERTY_DECL as dynamic.  The reason is
-        that the setter and getter methods in the interface have a
-        METHOD_PROPERTY_CONTEXT that points to the original
-        PROPERTY_DECL; when we check that these methods have been
-        implemented, we need to easily find that they are associated
-        with a dynamic property.  TODO: Clean this up; maybe the
-        @property PROPERTY_DECL should contain a reference to the
-        @dynamic PROPERTY_DECL ? */
-      PROPERTY_DYNAMIC (property) = 1;
-
       /* We have to copy the property, because we want to chain it to
         the implementation context, and we want to store the source
         location of the @synthesize, not of the original
@@ -10102,7 +10851,11 @@ finish_class (tree klass)
                getter_decl = build_method_decl (INSTANCE_METHOD_DECL, 
                                                 rettype, PROPERTY_GETTER_NAME (x), 
                                                 NULL_TREE, false);
-               objc_add_method (objc_interface_context, getter_decl, false, false);
+               if (PROPERTY_OPTIONAL (x))
+                 objc_add_method (objc_interface_context, getter_decl, false, true);
+               else
+                 objc_add_method (objc_interface_context, getter_decl, false, false);
+               TREE_DEPRECATED (getter_decl) = TREE_DEPRECATED (x);
                METHOD_PROPERTY_CONTEXT (getter_decl) = x;
              }
 
@@ -10142,7 +10895,11 @@ finish_class (tree klass)
                                                     ret_type, selector,
                                                     build_tree_list (NULL_TREE, NULL_TREE),
                                                     false);
-                   objc_add_method (objc_interface_context, setter_decl, false, false);
+                   if (PROPERTY_OPTIONAL (x))
+                     objc_add_method (objc_interface_context, setter_decl, false, true);
+                   else
+                     objc_add_method (objc_interface_context, setter_decl, false, false);
+                   TREE_DEPRECATED (setter_decl) = TREE_DEPRECATED (x);
                    METHOD_PROPERTY_CONTEXT (setter_decl) = x;
                  }            
              }
@@ -10164,14 +10921,52 @@ add_protocol (tree protocol)
   return protocol_chain;
 }
 
+/* Check that a protocol is defined, and, recursively, that all
+   protocols that this protocol conforms to are defined too.  */
+static void
+check_that_protocol_is_defined (tree protocol)
+{
+  if (!PROTOCOL_DEFINED (protocol))
+    warning (0, "definition of protocol %qE not found",
+            PROTOCOL_NAME (protocol));
+
+  /* If the protocol itself conforms to other protocols, check them
+     too, recursively.  */
+  if (PROTOCOL_LIST (protocol))
+    {
+      tree p;
+
+      for (p = PROTOCOL_LIST (protocol); p; p = TREE_CHAIN (p))
+       check_that_protocol_is_defined (TREE_VALUE (p));
+    }
+}
+
+/* Looks up a protocol.  If 'warn_if_deprecated' is true, a warning is
+   emitted if the protocol is deprecated.  If 'definition_required' is
+   true, a warning is emitted if a full @protocol definition has not
+   been seen.  */
 static tree
-lookup_protocol (tree ident)
+lookup_protocol (tree ident, bool warn_if_deprecated, bool definition_required)
 {
   tree chain;
 
   for (chain = protocol_chain; chain; chain = TREE_CHAIN (chain))
     if (ident == PROTOCOL_NAME (chain))
-      return chain;
+      {
+       if (warn_if_deprecated && TREE_DEPRECATED (chain))
+         {
+           /* It would be nice to use warn_deprecated_use() here, but
+              we are using TREE_CHAIN (which is supposed to be the
+              TYPE_STUB_DECL for a TYPE) for something different.  */
+           warning (OPT_Wdeprecated_declarations, "protocol %qE is deprecated", 
+                    PROTOCOL_NAME (chain));
+         }
+
+       if (definition_required)
+         check_that_protocol_is_defined (chain);
+
+       return chain;
+      }
 
   return NULL_TREE;
 }
@@ -10180,9 +10975,10 @@ lookup_protocol (tree ident)
    they are already declared or defined, the function has no effect.  */
 
 void
-objc_declare_protocols (tree names)
+objc_declare_protocols (tree names, tree attributes)
 {
   tree list;
+  bool deprecated = false;
 
 #ifdef OBJCPLUS
   if (current_namespace != global_namespace) {
@@ -10190,11 +10986,28 @@ objc_declare_protocols (tree names)
   }
 #endif /* OBJCPLUS */
 
+  /* Determine if 'deprecated', the only attribute we recognize for
+     protocols, was used.  Ignore all other attributes.  */
+  if (attributes)
+    {
+      tree attribute;
+      for (attribute = attributes; attribute; attribute = TREE_CHAIN (attribute))
+       {
+         tree name = TREE_PURPOSE (attribute);
+         
+         if (is_attribute_p  ("deprecated", name))
+           deprecated = true;
+         else
+           warning (OPT_Wattributes, "%qE attribute directive ignored", name);
+       }
+    }
+
   for (list = names; list; list = TREE_CHAIN (list))
     {
       tree name = TREE_VALUE (list);
 
-      if (lookup_protocol (name) == NULL_TREE)
+      if (lookup_protocol (name, /* warn if deprecated */ false,
+                          /* definition_required */ false) == NULL_TREE)
        {
          tree protocol = make_node (PROTOCOL_INTERFACE_TYPE);
 
@@ -10205,14 +11018,22 @@ objc_declare_protocols (tree names)
          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;
+           }
        }
     }
 }
 
 static tree
-start_protocol (enum tree_code code, tree name, tree list)
+start_protocol (enum tree_code code, tree name, tree list, tree attributes)
 {
   tree protocol;
+  bool deprecated = false;
 
 #ifdef OBJCPLUS
   if (current_namespace != global_namespace) {
@@ -10220,7 +11041,24 @@ start_protocol (enum tree_code code, tree name, tree list)
   }
 #endif /* OBJCPLUS */
 
-  protocol = lookup_protocol (name);
+  /* Determine if 'deprecated', the only attribute we recognize for
+     protocols, was used.  Ignore all other attributes.  */
+  if (attributes)
+    {
+      tree attribute;
+      for (attribute = attributes; attribute; attribute = TREE_CHAIN (attribute))
+       {
+         tree name = TREE_PURPOSE (attribute);
+         
+         if (is_attribute_p  ("deprecated", name))
+           deprecated = true;
+         else
+           warning (OPT_Wattributes, "%qE attribute directive ignored", name);
+       }
+    }
+
+  protocol = lookup_protocol (name, /* warn_if_deprecated */ false,
+                             /* definition_required */ false);
 
   if (!protocol)
     {
@@ -10228,7 +11066,7 @@ start_protocol (enum tree_code code, tree name, tree list)
       TYPE_LANG_SLOT_1 (protocol) = make_tree_vec (PROTOCOL_LANG_SLOT_ELTS);
 
       PROTOCOL_NAME (protocol) = name;
-      PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list);
+      PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list, /* definition_required */ false);
       add_protocol (protocol);
       PROTOCOL_DEFINED (protocol) = 1;
       PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
@@ -10238,7 +11076,7 @@ start_protocol (enum tree_code code, tree name, tree list)
   else if (! PROTOCOL_DEFINED (protocol))
     {
       PROTOCOL_DEFINED (protocol) = 1;
-      PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list);
+      PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list, /* definition_required */ false);
 
       check_protocol_recursively (protocol, list);
     }
@@ -10247,6 +11085,14 @@ start_protocol (enum tree_code code, tree name, tree list)
       warning (0, "duplicate declaration for protocol %qE",
               name);
     }
+
+  if (attributes)
+    {
+      TYPE_ATTRIBUTES (protocol) = attributes;
+      if (deprecated)
+       TREE_DEPRECATED (protocol) = 1;
+    }
+
   return protocol;
 }
 
@@ -11089,9 +11935,8 @@ start_method_def (tree method)
   really_start_method (objc_method_context, parm_info);
 }
 
-/* Return 1 if TYPE1 is equivalent to TYPE2
-   for purposes of method overloading.  */
-
+/* Return 1 if TYPE1 is equivalent to TYPE2 for purposes of method
+   overloading.  */
 static int
 objc_types_are_equivalent (tree type1, tree type2)
 {
@@ -11105,6 +11950,7 @@ objc_types_are_equivalent (tree type1, tree type2)
   if (TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2))
     return 0;
 
+  /* Compare the protocol lists.  */
   type1 = (TYPE_HAS_OBJC_INFO (type1)
           ? TYPE_OBJC_PROTOCOL_LIST (type1)
           : NULL_TREE);
@@ -11112,14 +11958,34 @@ objc_types_are_equivalent (tree type1, tree type2)
           ? TYPE_OBJC_PROTOCOL_LIST (type2)
           : NULL_TREE);
 
-  if (list_length (type1) == list_length (type2))
+  /* If there are no protocols (most common case), the types are
+     identical.  */
+  if (type1 == NULL_TREE && type2 == NULL_TREE)
+    return 1;
+  
+  /* If one has protocols, and the other one hasn't, they are not
+     identical.  */
+  if ((type1 == NULL_TREE && type2 != NULL_TREE)
+      || (type1 != NULL_TREE && type2 == NULL_TREE))
+    return 0;
+  else
     {
-      for (; type2; type2 = TREE_CHAIN (type2))
-       if (!lookup_protocol_in_reflist (type1, TREE_VALUE (type2)))
+      /* Else, both have protocols, and we need to do the full
+        comparison.  It is possible that either type1 or type2
+        contain some duplicate protocols in the list, so we can't
+        even just compare list_length as a first check.  */
+      tree t;
+
+      for (t = type2; t; t = TREE_CHAIN (t))
+       if (!lookup_protocol_in_reflist (type1, TREE_VALUE (t)))
+         return 0;
+      
+      for (t = type1; t; t = TREE_CHAIN (t))
+       if (!lookup_protocol_in_reflist (type2, TREE_VALUE (t)))
          return 0;
+      
       return 1;
     }
-  return 0;
 }
 
 /* Return 1 if TYPE1 has the same size and alignment as TYPE2.  */
@@ -11840,6 +12706,22 @@ objc_demangle (const char *mangled)
 {
   char *demangled, *cp;
 
+  /* First of all, if the name is too short it can't be an Objective-C
+     mangled method name.  */
+  if (mangled[0] == '\0' || mangled[1] == '\0' || mangled[2] == '\0')
+    return NULL;
+
+  /* If the name looks like an already demangled one, return it
+     unchanged.  This should only happen on Darwin, where method names
+     are mangled differently into a pretty-print form (such as
+     '+[NSObject class]', see darwin.h).  In that case, demangling is
+     a no-op, but we need to return the demangled name if it was an
+     ObjC one, and return NULL if not.  We should be safe as no C/C++
+     function can start with "-[" or "+[".  */
+  if ((mangled[0] == '-' || mangled[0] == '+')
+      && (mangled[1] == '['))
+    return mangled;
+
   if (mangled[0] == '_' &&
       (mangled[1] == 'i' || mangled[1] == 'c') &&
       mangled[2] == '_')
@@ -12392,6 +13274,14 @@ objc_gimplify_property_ref (tree *expr_p)
       return;
     }
 
+  if (PROPERTY_REF_DEPRECATED_GETTER (*expr_p))
+    {
+      /* PROPERTY_REF_DEPRECATED_GETTER contains the method prototype
+        that is deprecated.  */
+      warn_deprecated_use (PROPERTY_REF_DEPRECATED_GETTER (*expr_p),
+                          NULL_TREE);
+    }
+
   call_exp = getter;
 #ifdef OBJCPLUS
   /* In C++, a getter which returns an aggregate value results in a
@@ -12481,8 +13371,8 @@ objc_type_valid_for_messaging (tree type, bool accept_classes)
   if (objc_is_object_id (type))
     return true;
 
-  if (accept_classes && objc_is_class_id (type))
-    return true;
+  if (objc_is_class_id (type))
+    return accept_classes;
 
   if (TYPE_HAS_OBJC_INFO (type))
     return true;
@@ -12657,13 +13547,13 @@ objc_finish_foreach_loop (location_t location, tree object_expression, tree coll
 
   if (!objc_type_valid_for_messaging (TREE_TYPE (object_expression), true))
     {
-      error ("iterating variable in fast enumeration is not an object");
+      error_at (location, "iterating variable in fast enumeration is not an object");
       return;
     }
 
   if (!objc_type_valid_for_messaging (TREE_TYPE (collection_expression), true))
     {
-      error ("collection in fast enumeration is not an object");
+      error_at (location, "collection in fast enumeration is not an object");
       return;
     }
 
@@ -12701,6 +13591,18 @@ objc_finish_foreach_loop (location_t location, tree object_expression, tree coll
   /* type object; */
   /* Done by c-parser.c.  */
 
+  /* Disable warnings that 'object' is unused.  For example the code
+
+     for (id object in collection)
+       i++;
+
+     which can be used to count how many objects there are in the
+     collection is fine and should generate no warnings even if
+     'object' is technically unused.  */
+  TREE_USED (object_expression) = 1;
+  if (DECL_P (object_expression))
+    DECL_READ_P (object_expression) = 1;
+
   /*  id __objc_foreach_collection */
   objc_foreach_collection_decl = objc_create_temporary_var (objc_object_type, "__objc_foreach_collection");
 
@@ -12725,6 +13627,8 @@ objc_finish_foreach_loop (location_t location, tree object_expression, tree coll
   t = build2 (MODIFY_EXPR, void_type_node, objc_foreach_collection_decl, collection_expression);
   SET_EXPR_LOCATION (t, location);
   append_to_statement_list (t, &BIND_EXPR_BODY (bind));
+  /* We have used 'collection_expression'.  */
+  mark_exp_read (collection_expression);
 
   /*  __objc_foreach_enum_state.state = 0; */
   t = build2 (MODIFY_EXPR, void_type_node, objc_build_component_ref (objc_foreach_enum_state_decl, 
@@ -12773,7 +13677,7 @@ objc_finish_foreach_loop (location_t location, tree object_expression, tree coll
                                 tree_cons   /* __objc_foreach_items  */
                                 (NULL_TREE, objc_foreach_items_decl,
                                  tree_cons  /* 16 */
-                                 (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))));
+                                 (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))), NULL);
 #else
   /* In C, we need to decay the __objc_foreach_items array that we are passing.  */
   {
@@ -12786,7 +13690,7 @@ objc_finish_foreach_loop (location_t location, tree object_expression, tree coll
                                   tree_cons   /* __objc_foreach_items  */
                                   (NULL_TREE, default_function_array_conversion (location, array).value,
                                    tree_cons  /* 16 */
-                                   (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))));
+                                   (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))), NULL);
   }
 #endif
   t = build2 (MODIFY_EXPR, void_type_node, objc_foreach_batchsize_decl,
@@ -12947,7 +13851,7 @@ objc_finish_foreach_loop (location_t location, tree object_expression, tree coll
                                 tree_cons   /* __objc_foreach_items  */
                                 (NULL_TREE, objc_foreach_items_decl,
                                  tree_cons  /* 16 */
-                                 (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))));
+                                 (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))), NULL);
 #else
   /* In C, we need to decay the __objc_foreach_items array that we are passing.  */
   {
@@ -12960,7 +13864,7 @@ objc_finish_foreach_loop (location_t location, tree object_expression, tree coll
                                   tree_cons   /* __objc_foreach_items  */
                                   (NULL_TREE, default_function_array_conversion (location, array).value,
                                    tree_cons  /* 16 */
-                                   (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))));
+                                   (NULL_TREE, build_int_cst (NULL_TREE, 16), NULL_TREE))), NULL);
   }
 #endif
   t = build2 (MODIFY_EXPR, void_type_node, objc_foreach_batchsize_decl,