OSDN Git Service

PR target/47935
[pf3gnuchains/gcc-fork.git] / gcc / c-parser.c
index e4efd38..69ce2e5 100644 (file)
@@ -1,6 +1,6 @@
 /* Parser for C and Objective-C.
    Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
 
    Parser actions based on the old Bison parser; structure somewhat
@@ -50,9 +50,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-tree.h"
 #include "flags.h"
 #include "output.h"
-#include "toplev.h"
 #include "ggc.h"
 #include "c-family/c-common.h"
+#include "c-family/c-objc.h"
 #include "vec.h"
 #include "target.h"
 #include "cgraph.h"
@@ -253,8 +253,7 @@ c_lex_one_token (c_parser *parser, c_token *token)
                /* We found an Objective-C "pq" keyword (in, out,
                   inout, bycopy, byref, oneway).  They need special
                   care because the interpretation depends on the
-                  context.
-                */
+                  context.  */
                if (parser->objc_pq_context)
                  {
                    token->type = CPP_KEYWORD;
@@ -275,21 +274,19 @@ c_lex_one_token (c_parser *parser, c_token *token)
                       you can't use 'in' as the name of the running
                       variable in a C for loop.  We could potentially
                       try to add code here to disambiguate, but it
-                      seems a reasonable limitation.
-                   */
+                      seems a reasonable limitation.  */
                    token->type = CPP_KEYWORD;
                    token->keyword = rid_code;
                    break;
                  }
                /* Else, "pq" keywords outside of the "pq" context are
                   not keywords, and we fall through to the code for
-                  normal tokens.
-               */
+                  normal tokens.  */
              }
            else if (c_dialect_objc () && OBJC_IS_PATTR_KEYWORD (rid_code))
              {
-               /* We found an Objective-C "property attribute" keyword 
-                  (readonly, copies, getter, setter, ivar). These are 
+               /* We found an Objective-C "property attribute"
+                  keyword (getter, setter, readonly, etc). These are
                   only valid in the property context.  */
                if (parser->objc_property_attr_context)
                  {
@@ -310,8 +307,7 @@ c_lex_one_token (c_parser *parser, c_token *token)
                   protected, public, try, catch, throw) without a
                   preceding '@' sign.  Do nothing and fall through to
                   the code for normal tokens (in C++ we would still
-                  consider the CXX ones keywords, but not in C).
-               */
+                  consider the CXX ones keywords, but not in C).  */
                ;
              }
            else
@@ -433,6 +429,22 @@ c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword)
   return c_parser_peek_token (parser)->keyword == keyword;
 }
 
+/* Return a pointer to the next-but-one token from PARSER, reading it
+   in if necessary.  The next token is already read in.  */
+
+static c_token *
+c_parser_peek_2nd_token (c_parser *parser)
+{
+  if (parser->tokens_avail >= 2)
+    return &parser->tokens[1];
+  gcc_assert (parser->tokens_avail == 1);
+  gcc_assert (parser->tokens[0].type != CPP_EOF);
+  gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL);
+  c_lex_one_token (parser, &parser->tokens[1]);
+  parser->tokens_avail = 2;
+  return &parser->tokens[1];
+}
+
 /* Return true if TOKEN can start a type name,
    false otherwise.  */
 static bool
@@ -497,13 +509,87 @@ c_token_starts_typename (c_token *token)
     }
 }
 
+enum c_lookahead_kind {
+  /* Always treat unknown identifiers as typenames.  */
+  cla_prefer_type,
+
+  /* Could be parsing a nonabstract declarator.  Only treat an identifier
+     as a typename if followed by another identifier or a star.  */
+  cla_nonabstract_decl,
+
+  /* Never treat identifiers as typenames.  */
+  cla_prefer_id
+};
+
 /* Return true if the next token from PARSER can start a type name,
+   false otherwise.  LA specifies how to do lookahead in order to
+   detect unknown type names.  If unsure, pick CLA_PREFER_ID.  */
+
+static inline bool
+c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la)
+{
+  c_token *token = c_parser_peek_token (parser);
+  if (c_token_starts_typename (token))
+    return true;
+
+  /* Try a bit harder to detect an unknown typename.  */
+  if (la != cla_prefer_id
+      && token->type == CPP_NAME
+      && token->id_kind == C_ID_ID
+
+      /* Do not try too hard when we could have "object in array".  */
+      && !parser->objc_could_be_foreach_context
+
+      && (la == cla_prefer_type
+         || c_parser_peek_2nd_token (parser)->type == CPP_NAME
+         || c_parser_peek_2nd_token (parser)->type == CPP_MULT)
+
+      /* Only unknown identifiers.  */
+      && !lookup_name (token->value))
+    return true;
+
+  return false;
+}
+
+/* Return true if TOKEN is a type qualifier, false otherwise.  */
+static bool
+c_token_is_qualifier (c_token *token)
+{
+  switch (token->type)
+    {
+    case CPP_NAME:
+      switch (token->id_kind)
+       {
+       case C_ID_ADDRSPACE:
+         return true;
+       default:
+         return false;
+       }
+    case CPP_KEYWORD:
+      switch (token->keyword)
+       {
+       case RID_CONST:
+       case RID_VOLATILE:
+       case RID_RESTRICT:
+       case RID_ATTRIBUTE:
+         return true;
+       default:
+         return false;
+       }
+    case CPP_LESS:
+      return false;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Return true if the next token from PARSER is a type qualifier,
    false otherwise.  */
 static inline bool
-c_parser_next_token_starts_typename (c_parser *parser)
+c_parser_next_token_is_qualifier (c_parser *parser)
 {
   c_token *token = c_parser_peek_token (parser);
-  return c_token_starts_typename (token);
+  return c_token_is_qualifier (token);
 }
 
 /* Return true if TOKEN can start declaration specifiers, false
@@ -590,40 +676,54 @@ c_token_starts_declaration (c_token *token)
     return false;
 }
 
-static c_token *c_parser_peek_2nd_token (c_parser *parser);
-
 /* Return true if the next token from PARSER can start declaration
    specifiers, false otherwise.  */
 static inline bool
 c_parser_next_token_starts_declspecs (c_parser *parser)
 {
   c_token *token = c_parser_peek_token (parser);
+
+  /* In Objective-C, a classname normally starts a declspecs unless it
+     is immediately followed by a dot.  In that case, it is the
+     Objective-C 2.0 "dot-syntax" for class objects, ie, calls the
+     setter/getter on the class.  c_token_starts_declspecs() can't
+     differentiate between the two cases because it only checks the
+     current token, so we have a special check here.  */
+  if (c_dialect_objc () 
+      && token->type == CPP_NAME
+      && token->id_kind == C_ID_CLASSNAME 
+      && c_parser_peek_2nd_token (parser)->type == CPP_DOT)
+    return false;
+
   return c_token_starts_declspecs (token);
 }
 
-/* Return true if the next token from PARSER can start declaration
+/* Return true if the next tokens from PARSER can start declaration
    specifiers or a static assertion, false otherwise.  */
 static inline bool
-c_parser_next_token_starts_declaration (c_parser *parser)
+c_parser_next_tokens_start_declaration (c_parser *parser)
 {
   c_token *token = c_parser_peek_token (parser);
-  return c_token_starts_declaration (token);
-}
 
-/* Return a pointer to the next-but-one token from PARSER, reading it
-   in if necessary.  The next token is already read in.  */
+  /* Same as above.  */
+  if (c_dialect_objc () 
+      && token->type == CPP_NAME
+      && token->id_kind == C_ID_CLASSNAME 
+      && c_parser_peek_2nd_token (parser)->type == CPP_DOT)
+    return false;
 
-static c_token *
-c_parser_peek_2nd_token (c_parser *parser)
-{
-  if (parser->tokens_avail >= 2)
-    return &parser->tokens[1];
-  gcc_assert (parser->tokens_avail == 1);
-  gcc_assert (parser->tokens[0].type != CPP_EOF);
-  gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL);
-  c_lex_one_token (parser, &parser->tokens[1]);
-  parser->tokens_avail = 2;
-  return &parser->tokens[1];
+  /* Labels do not start declarations.  */
+  if (token->type == CPP_NAME
+      && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+    return false;
+
+  if (c_token_starts_declaration (token))
+    return true;
+
+  if (c_parser_next_tokens_start_typename (parser, cla_nonabstract_decl))
+    return true;
+
+  return false;
 }
 
 /* Consume the next token from PARSER.  */
@@ -995,7 +1095,7 @@ static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
 static void c_parser_static_assert_declaration_no_semi (c_parser *);
 static void c_parser_static_assert_declaration (c_parser *);
 static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
-                               bool);
+                               bool, enum c_lookahead_kind);
 static struct c_typespec c_parser_enum_specifier (c_parser *);
 static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);
 static tree c_parser_struct_declaration (c_parser *);
@@ -1074,14 +1174,14 @@ static void c_parser_objc_methodproto (c_parser *);
 static tree c_parser_objc_method_decl (c_parser *, bool, tree *);
 static tree c_parser_objc_type_name (c_parser *);
 static tree c_parser_objc_protocol_refs (c_parser *);
-static void c_parser_objc_try_catch_statement (c_parser *);
+static void c_parser_objc_try_catch_finally_statement (c_parser *);
 static void c_parser_objc_synchronized_statement (c_parser *);
 static tree c_parser_objc_selector (c_parser *);
 static tree c_parser_objc_selector_arg (c_parser *);
 static tree c_parser_objc_receiver (c_parser *);
 static tree c_parser_objc_message_args (c_parser *);
 static tree c_parser_objc_keywordexpr (c_parser *);
-static void c_parser_objc_at_property (c_parser *) ;
+static void c_parser_objc_at_property_declaration (c_parser *);
 static void c_parser_objc_at_synthesize_declaration (c_parser *);
 static void c_parser_objc_at_dynamic_declaration (c_parser *);
 static bool c_parser_objc_diagnose_bad_element_prefix
@@ -1185,7 +1285,7 @@ c_parser_external_declaration (c_parser *parser)
          break;
        case RID_AT_PROPERTY:
          gcc_assert (c_dialect_objc ());
-         c_parser_objc_at_property (parser);
+         c_parser_objc_at_property_declaration (parser);
          break;
        case RID_AT_SYNTHESIZE:
          gcc_assert (c_dialect_objc ());
@@ -1324,7 +1424,27 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       return;
     }
   specs = build_null_declspecs ();
-  c_parser_declspecs (parser, specs, true, true, start_attr_ok);
+
+  /* Try to detect an unknown type name when we have "A B" or "A *B".  */
+  if (c_parser_peek_token (parser)->type == CPP_NAME
+      && c_parser_peek_token (parser)->id_kind == C_ID_ID
+      && (c_parser_peek_2nd_token (parser)->type == CPP_NAME
+          || c_parser_peek_2nd_token (parser)->type == CPP_MULT)
+      && (!nested || !lookup_name (c_parser_peek_token (parser)->value)))
+    {
+      error_at (here, "unknown type name %qE",
+                c_parser_peek_token (parser)->value);
+
+      /* Parse declspecs normally to get a correct pointer type, but avoid
+         a further "fails to be a type name" error.  Refuse nested functions
+         since it is not how the user likely wants us to recover.  */
+      c_parser_peek_token (parser)->type = CPP_KEYWORD;
+      c_parser_peek_token (parser)->keyword = RID_VOID;
+      c_parser_peek_token (parser)->value = error_mark_node;
+      fndef_ok = !nested;
+    }
+
+  c_parser_declspecs (parser, specs, true, true, start_attr_ok, cla_nonabstract_decl);
   if (parser->error)
     {
       c_parser_skip_to_end_of_block_or_statement (parser);
@@ -1349,6 +1469,19 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
       c_parser_consume_token (parser);
       return;
     }
+
+  /* Provide better error recovery.  Note that a type name here is usually
+     better diagnosed as a redeclaration.  */
+  if (empty_ok
+      && specs->typespec_kind == ctsk_tagdef
+      && c_parser_next_token_starts_declspecs (parser)
+      && !c_parser_next_token_is (parser, CPP_NAME))
+    {
+      c_parser_error (parser, "expected %<;%>, identifier or %<(%>");
+      parser->error = false;
+      shadow_tag_warned (specs, 1);
+      return;
+    }
   else if (c_dialect_objc ())
     {
       /* Prefix attributes are an error on method decls.  */
@@ -1418,8 +1551,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
        case RID_AT_PROPERTY:
          if (specs->attrs)
            {
-             c_parser_error (parser, 
-                             "attributes may not be specified before" );
+             c_parser_error (parser, "unexpected attribute");
              specs->attrs = NULL;
            }
          break;
@@ -1441,7 +1573,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
         should diagnose if there were no declaration specifiers) or a
         function definition (in which case the diagnostic for
         implicit int suffices).  */
-      declarator = c_parser_declarator (parser, specs->type_seen_p,
+      declarator = c_parser_declarator (parser, 
+                                       specs->typespec_kind != ctsk_none,
                                        C_DTR_NORMAL, &dummy);
       if (declarator == NULL)
        {
@@ -1807,10 +1940,15 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser)
 
 static void
 c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
-                   bool scspec_ok, bool typespec_ok, bool start_attr_ok)
+                   bool scspec_ok, bool typespec_ok, bool start_attr_ok,
+                   enum c_lookahead_kind la)
 {
   bool attrs_ok = start_attr_ok;
-  bool seen_type = specs->type_seen_p;
+  bool seen_type = specs->typespec_kind != ctsk_none;
+
+  if (!typespec_ok)
+    gcc_assert (la == cla_prefer_id);
+
   while (c_parser_next_token_is (parser, CPP_NAME)
         || c_parser_next_token_is (parser, CPP_KEYWORD)
         || (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS)))
@@ -1818,6 +1956,16 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
       struct c_typespec t;
       tree attrs;
       location_t loc = c_parser_peek_token (parser)->location;
+
+      /* If we cannot accept a type, exit if the next token must start
+        one.  Also, if we already have seen a tagged definition,
+        a typename would be an error anyway and likely the user
+        has simply forgotten a semicolon, so we exit.  */
+      if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef)
+         && c_parser_next_tokens_start_typename (parser, la)
+         && !c_parser_next_token_is_qualifier (parser))
+       break;
+
       if (c_parser_next_token_is (parser, CPP_NAME))
        {
          tree value = c_parser_peek_token (parser)->value;
@@ -1833,25 +1981,34 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
              continue;
            }
 
-         /* This finishes the specifiers unless a type name is OK, it
-            is declared as a type name and a type name hasn't yet
-            been seen.  */
-         if (!typespec_ok || seen_type
-             || (kind != C_ID_TYPENAME && kind != C_ID_CLASSNAME))
+         gcc_assert (!c_parser_next_token_is_qualifier (parser));
+
+         /* If we cannot accept a type, and the next token must start one,
+            exit.  Do the same if we already have seen a tagged definition,
+            since it would be an error anyway and likely the user has simply
+            forgotten a semicolon.  */
+         if (seen_type || !c_parser_next_tokens_start_typename (parser, la))
            break;
+
+         /* Now at an unknown typename (C_ID_ID), a C_ID_TYPENAME or
+            a C_ID_CLASSNAME.  */
          c_parser_consume_token (parser);
          seen_type = true;
          attrs_ok = true;
-         if (kind == C_ID_TYPENAME
-             && (!c_dialect_objc ()
-                 || c_parser_next_token_is_not (parser, CPP_LESS)))
+         if (kind == C_ID_ID)
+           {
+             error ("unknown type name %qE", value);
+             t.kind = ctsk_typedef;
+             t.spec = error_mark_node;
+           }
+         else if (kind == C_ID_TYPENAME
+                  && (!c_dialect_objc ()
+                      || c_parser_next_token_is_not (parser, CPP_LESS)))
            {
              t.kind = ctsk_typedef;
              /* For a typedef name, record the meaning, not the name.
                 In case of 'foo foo, bar;'.  */
              t.spec = lookup_name (value);
-             t.expr = NULL_TREE;
-             t.expr_const_operands = true;
            }
          else
            {
@@ -1861,9 +2018,9 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
              if (c_parser_next_token_is (parser, CPP_LESS))
                proto = c_parser_objc_protocol_refs (parser);
              t.spec = objc_get_protocol_qualified_type (value, proto);
-             t.expr = NULL_TREE;
-             t.expr_const_operands = true;
            }
+         t.expr = NULL_TREE;
+         t.expr_const_operands = true;
          declspecs_add_type (loc, specs, t);
          continue;
        }
@@ -2279,12 +2436,17 @@ c_parser_struct_or_union_specifier (c_parser *parser)
              if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
                pedwarn (c_parser_peek_token (parser)->location, 0,
                         "no semicolon at end of struct or union");
-             else
+             else if (parser->error
+                      || !c_parser_next_token_starts_declspecs (parser))
                {
                  c_parser_error (parser, "expected %<;%>");
                  c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
                  break;
                }
+
+             /* If we come here, we have already emitted an error
+                for an expected `;', identifier or `(', and we also
+                recovered already.  Go on with the next field. */
            }
        }
       postfix_attrs = c_parser_attributes (parser);
@@ -2365,7 +2527,7 @@ c_parser_struct_declaration (c_parser *parser)
     }
   specs = build_null_declspecs ();
   decl_loc = c_parser_peek_token (parser)->location;
-  c_parser_declspecs (parser, specs, false, true, true);
+  c_parser_declspecs (parser, specs, false, true, true, cla_nonabstract_decl);
   if (parser->error)
     return NULL_TREE;
   if (!specs->declspecs_seen_p)
@@ -2374,10 +2536,11 @@ c_parser_struct_declaration (c_parser *parser)
       return NULL_TREE;
     }
   finish_declspecs (specs);
-  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON)
+      || c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
     {
       tree ret;
-      if (!specs->type_seen_p)
+      if (specs->typespec_kind == ctsk_none)
        {
          pedwarn (decl_loc, OPT_pedantic,
                   "ISO C forbids member declarations with no members");
@@ -2399,6 +2562,19 @@ c_parser_struct_declaration (c_parser *parser)
        }
       return ret;
     }
+
+  /* Provide better error recovery.  Note that a type name here is valid,
+     and will be treated as a field name.  */
+  if (specs->typespec_kind == ctsk_tagdef
+      && TREE_CODE (specs->type) != ENUMERAL_TYPE
+      && c_parser_next_token_starts_declspecs (parser)
+      && !c_parser_next_token_is (parser, CPP_NAME))
+    {
+      c_parser_error (parser, "expected %<;%>, identifier or %<(%>");
+      parser->error = false;
+      return NULL_TREE;
+    }
+
   pending_xref_error ();
   prefix_attrs = specs->attrs;
   all_prefix_attrs = prefix_attrs;
@@ -2412,7 +2588,8 @@ c_parser_struct_declaration (c_parser *parser)
       if (c_parser_next_token_is (parser, CPP_COLON))
        declarator = build_id_declarator (NULL_TREE);
       else
-       declarator = c_parser_declarator (parser, specs->type_seen_p,
+       declarator = c_parser_declarator (parser,
+                                         specs->typespec_kind != ctsk_none,
                                          C_DTR_NORMAL, &dummy);
       if (declarator == NULL)
        {
@@ -2496,7 +2673,7 @@ c_parser_typeof_specifier (c_parser *parser)
       in_typeof--;
       return ret;
     }
-  if (c_parser_next_token_starts_typename (parser))
+  if (c_parser_next_tokens_start_typename (parser, cla_prefer_id))
     {
       struct c_type_name *type = c_parser_type_name (parser);
       c_inhibit_evaluation_warnings--;
@@ -2519,11 +2696,6 @@ c_parser_typeof_specifier (c_parser *parser)
        error_at (here, "%<typeof%> applied to a bit-field");
       mark_exp_read (expr.value);
       ret.spec = TREE_TYPE (expr.value);
-      if (c_dialect_objc() 
-         && ret.spec != error_mark_node
-         && lookup_attribute ("objc_volatilized", TYPE_ATTRIBUTES (ret.spec)))
-       ret.spec = build_qualified_type
-         (ret.spec, (TYPE_QUALS (ret.spec) & ~TYPE_QUAL_VOLATILE));
       was_vm = variably_modified_type_p (ret.spec, NULL_TREE);
       /* This is returned with the type so that when the type is
         evaluated, this can be evaluated.  */
@@ -2622,7 +2794,7 @@ c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
       struct c_declspecs *quals_attrs = build_null_declspecs ();
       struct c_declarator *inner;
       c_parser_consume_token (parser);
-      c_parser_declspecs (parser, quals_attrs, false, false, true);
+      c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
       inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
       if (inner == NULL)
        return NULL;
@@ -2774,12 +2946,12 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
       bool star_seen;
       tree dimen;
       c_parser_consume_token (parser);
-      c_parser_declspecs (parser, quals_attrs, false, false, true);
+      c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
       static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC);
       if (static_seen)
        c_parser_consume_token (parser);
       if (static_seen && !quals_attrs->declspecs_seen_p)
-       c_parser_declspecs (parser, quals_attrs, false, false, true);
+       c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
       if (!quals_attrs->declspecs_seen_p)
        quals_attrs = NULL;
       /* If "static" is present, there must be an array dimension.
@@ -2867,7 +3039,13 @@ c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs)
   if (id_list_ok
       && !attrs
       && c_parser_next_token_is (parser, CPP_NAME)
-      && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+      && c_parser_peek_token (parser)->id_kind == C_ID_ID
+      
+      /* Look ahead to detect typos in type names.  */
+      && c_parser_peek_2nd_token (parser)->type != CPP_NAME
+      && c_parser_peek_2nd_token (parser)->type != CPP_MULT
+      && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN
+      && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_SQUARE)
     {
       tree list = NULL_TREE, *nextp = &list;
       while (c_parser_next_token_is (parser, CPP_NAME)
@@ -3030,9 +3208,7 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs)
       if (parser->error)
        return NULL;
       c_parser_set_source_position_from_token (token);
-      if (token->type == CPP_NAME
-         && c_parser_peek_2nd_token (parser)->type != CPP_COMMA
-         && c_parser_peek_2nd_token (parser)->type != CPP_CLOSE_PAREN)
+      if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
        {
          error ("unknown type name %qE", token->value);
          parser->error = true;
@@ -3051,12 +3227,13 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs)
       declspecs_add_attrs (specs, attrs);
       attrs = NULL_TREE;
     }
-  c_parser_declspecs (parser, specs, true, true, true);
+  c_parser_declspecs (parser, specs, true, true, true, cla_nonabstract_decl);
   finish_declspecs (specs);
   pending_xref_error ();
   prefix_attrs = specs->attrs;
   specs->attrs = NULL_TREE;
-  declarator = c_parser_declarator (parser, specs->type_seen_p,
+  declarator = c_parser_declarator (parser,
+                                   specs->typespec_kind != ctsk_none,
                                    C_DTR_PARM, &dummy);
   if (declarator == NULL)
     {
@@ -3257,9 +3434,12 @@ c_parser_attributes (c_parser *parser)
          /* Parse the attribute contents.  If they start with an
             identifier which is followed by a comma or close
             parenthesis, then the arguments start with that
-            identifier; otherwise they are an expression list.  */
+            identifier; otherwise they are an expression list.  
+            In objective-c the identifier may be a classname.  */
          if (c_parser_next_token_is (parser, CPP_NAME)
-             && c_parser_peek_token (parser)->id_kind == C_ID_ID
+             && (c_parser_peek_token (parser)->id_kind == C_ID_ID
+                 || (c_dialect_objc () 
+                     && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
              && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
                  || (c_parser_peek_2nd_token (parser)->type
                      == CPP_CLOSE_PAREN)))
@@ -3337,15 +3517,19 @@ c_parser_type_name (c_parser *parser)
   struct c_declarator *declarator;
   struct c_type_name *ret;
   bool dummy = false;
-  c_parser_declspecs (parser, specs, false, true, true);
+  c_parser_declspecs (parser, specs, false, true, true, cla_prefer_type);
   if (!specs->declspecs_seen_p)
     {
       c_parser_error (parser, "expected specifier-qualifier-list");
       return NULL;
     }
-  pending_xref_error ();
-  finish_declspecs (specs);
-  declarator = c_parser_declarator (parser, specs->type_seen_p,
+  if (specs->type != error_mark_node)
+    {
+      pending_xref_error ();
+      finish_declspecs (specs);
+    }
+  declarator = c_parser_declarator (parser,
+                                   specs->typespec_kind != ctsk_none,
                                    C_DTR_ABSTRACT, &dummy);
   if (declarator == NULL)
     return NULL;
@@ -3839,7 +4023,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
          c_parser_label (parser);
        }
       else if (!last_label
-              && c_parser_next_token_starts_declaration (parser))
+              && c_parser_next_tokens_start_declaration (parser))
        {
          last_label = false;
          mark_valid_location_for_stdc_pragma (false);
@@ -4001,9 +4185,7 @@ c_parser_label (c_parser *parser)
     }
   if (label)
     {
-      if (c_parser_next_token_starts_declaration (parser)
-         && !(c_parser_next_token_is (parser, CPP_NAME)
-              && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+      if (c_parser_next_tokens_start_declaration (parser))
        {
          error_at (c_parser_peek_token (parser)->location,
                    "a label can only be part of a statement and "
@@ -4220,7 +4402,7 @@ c_parser_statement_after_labels (c_parser *parser)
          break;
        case RID_AT_TRY:
          gcc_assert (c_dialect_objc ());
-         c_parser_objc_try_catch_statement (parser);
+         c_parser_objc_try_catch_finally_statement (parser);
          break;
        case RID_AT_SYNCHRONIZED:
          gcc_assert (c_dialect_objc ());
@@ -4577,7 +4759,9 @@ c_parser_for_statement (c_parser *parser)
 {
   tree block, cond, incr, save_break, save_cont, body;
   /* The following are only used when parsing an ObjC foreach statement.  */
-  tree object_expression, collection_expression;
+  tree object_expression;
+  /* Silence the bogus uninitialized warning.  */
+  tree collection_expression = NULL;
   location_t loc = c_parser_peek_token (parser)->location;
   location_t for_loc = c_parser_peek_token (parser)->location;
   bool is_foreach_statement = false;
@@ -4592,14 +4776,15 @@ c_parser_for_statement (c_parser *parser)
     {
       /* Parse the initialization declaration or expression.  */
       object_expression = error_mark_node;
+      parser->objc_could_be_foreach_context = c_dialect_objc ();
       if (c_parser_next_token_is (parser, CPP_SEMICOLON))
        {
+         parser->objc_could_be_foreach_context = false;
          c_parser_consume_token (parser);
          c_finish_expr_stmt (loc, NULL_TREE);
        }
-      else if (c_parser_next_token_starts_declaration (parser))
+      else if (c_parser_next_tokens_start_declaration (parser))
        {
-         parser->objc_could_be_foreach_context = true;
          c_parser_declaration_or_fndef (parser, true, true, true, true, true, 
                                         &object_expression);
          parser->objc_could_be_foreach_context = false;
@@ -4629,7 +4814,6 @@ c_parser_for_statement (c_parser *parser)
              int ext;
              ext = disable_extension_diagnostics ();
              c_parser_consume_token (parser);
-             parser->objc_could_be_foreach_context = true;
              c_parser_declaration_or_fndef (parser, true, true, true, true,
                                             true, &object_expression);
              parser->objc_could_be_foreach_context = false;
@@ -4653,7 +4837,6 @@ c_parser_for_statement (c_parser *parser)
        init_expr:
          {
            tree init_expression;
-           parser->objc_could_be_foreach_context = true;
            init_expression = c_parser_expression (parser).value;
            parser->objc_could_be_foreach_context = false;
            if (c_parser_next_token_is_keyword (parser, RID_IN))
@@ -4662,8 +4845,7 @@ c_parser_for_statement (c_parser *parser)
                is_foreach_statement = true;
                if (! lvalue_p (init_expression))
                  c_parser_error (parser, "invalid iterating variable in fast enumeration");
-               object_expression = c_process_expr_stmt (loc, init_expression);
-
+               object_expression = c_fully_fold (init_expression, false, NULL);
              }
            else
              {
@@ -4674,6 +4856,7 @@ c_parser_for_statement (c_parser *parser)
        }
       /* Parse the loop condition.  In the case of a foreach
         statement, there is no loop condition.  */
+      gcc_assert (!parser->objc_could_be_foreach_context);
       if (!is_foreach_statement)
        {
          if (c_parser_next_token_is (parser, CPP_SEMICOLON))
@@ -4703,7 +4886,8 @@ c_parser_for_statement (c_parser *parser)
       else
        {
          if (is_foreach_statement)
-           collection_expression = c_process_expr_stmt (loc, c_parser_expression (parser).value);
+           collection_expression = c_fully_fold (c_parser_expression (parser).value,
+                                                 false, NULL);
          else
            incr = c_process_expr_stmt (loc, c_parser_expression (parser).value);
        }
@@ -5473,7 +5657,8 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
   /* If the expression begins with a parenthesized type name, it may
      be either a cast or a compound literal; we need to see whether
      the next character is '{' to tell the difference.  If not, it is
-     an unary expression.  */
+     an unary expression.  Full detection of unknown typenames here
+     would require a 3-token lookahead.  */
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
       && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
     {
@@ -5821,6 +6006,7 @@ c_parser_alignof_expression (c_parser *parser)
      @protocol ( identifier )
      @encode ( type-name )
      objc-string-literal
+     Classname . identifier
 */
 
 static struct c_expr
@@ -5867,20 +6053,48 @@ c_parser_postfix_expression (c_parser *parser)
       c_parser_consume_token (parser);
       break;
     case CPP_NAME:
-      if (c_parser_peek_token (parser)->id_kind != C_ID_ID)
+      switch (c_parser_peek_token (parser)->id_kind)
        {
+       case C_ID_ID:
+         {
+           tree id = c_parser_peek_token (parser)->value;
+           c_parser_consume_token (parser);
+           expr.value = build_external_ref (loc, id,
+                                            (c_parser_peek_token (parser)->type
+                                             == CPP_OPEN_PAREN),
+                                            &expr.original_type);
+           break;
+         }
+       case C_ID_CLASSNAME:
+         {
+           /* Here we parse the Objective-C 2.0 Class.name dot
+              syntax.  */
+           tree class_name = c_parser_peek_token (parser)->value;
+           tree component;
+           c_parser_consume_token (parser);
+           gcc_assert (c_dialect_objc ());
+           if (!c_parser_require (parser, CPP_DOT, "expected %<.%>"))
+             {
+               expr.value = error_mark_node;
+               break;
+             }
+           if (c_parser_next_token_is_not (parser, CPP_NAME))
+             {
+               c_parser_error (parser, "expected identifier");
+               expr.value = error_mark_node;
+               break;
+             }
+           component = c_parser_peek_token (parser)->value;
+           c_parser_consume_token (parser);
+           expr.value = objc_build_class_component_ref (class_name, 
+                                                        component);
+           break;
+         }
+       default:
          c_parser_error (parser, "expected expression");
          expr.value = error_mark_node;
          break;
        }
-      {
-       tree id = c_parser_peek_token (parser)->value;
-       c_parser_consume_token (parser);
-       expr.value = build_external_ref (loc, id,
-                                        (c_parser_peek_token (parser)->type
-                                         == CPP_OPEN_PAREN),
-                                        &expr.original_type);
-      }
       break;
     case CPP_OPEN_PAREN:
       /* A parenthesized expression, statement expression or compound
@@ -6006,16 +6220,16 @@ c_parser_postfix_expression (c_parser *parser)
            }
          t1 = c_parser_type_name (parser);
          if (t1 == NULL)
-           {
-             expr.value = error_mark_node;
-             break;
-           }
+           parser->error = true;
          if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+            gcc_assert (parser->error);
+         if (parser->error)
            {
              c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
              expr.value = error_mark_node;
              break;
            }
+
          {
            tree type = groktypename (t1, NULL, NULL);
            tree offsetof_ref;
@@ -6568,6 +6782,8 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
        objc-class-instance-variables[opt]
      @interface identifier ( identifier ) objc-protocol-refs[opt]
        objc-methodprotolist @end
+     @interface identifier ( ) objc-protocol-refs[opt]
+       objc-methodprotolist @end
      @implementation identifier ( identifier )
 
    objc-superclass:
@@ -6602,17 +6818,29 @@ c_parser_objc_class_definition (c_parser *parser, tree attributes)
   c_parser_consume_token (parser);
   if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
     {
+      /* We have a category or class extension.  */
       tree id2;
       tree proto = NULL_TREE;
       c_parser_consume_token (parser);
       if (c_parser_next_token_is_not (parser, CPP_NAME))
        {
-         c_parser_error (parser, "expected identifier");
-         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
-         return;
+         if (iface_p && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+           {
+             /* We have a class extension.  */
+             id2 = NULL_TREE;
+           }
+         else
+           {
+             c_parser_error (parser, "expected identifier or %<)%>");
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             return;
+           }
+       }
+      else
+       {
+         id2 = c_parser_peek_token (parser)->value;
+         c_parser_consume_token (parser);
        }
-      id2 = c_parser_peek_token (parser)->value;
-      c_parser_consume_token (parser);
       c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
       if (!iface_p)
        {
@@ -6866,7 +7094,7 @@ c_parser_objc_protocol_definition (c_parser *parser, tree attributes)
            break;
        }
       c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
-      objc_declare_protocols (list);
+      objc_declare_protocols (list, attributes);
     }
   else
     {
@@ -6997,7 +7225,7 @@ c_parser_objc_methodprotolist (c_parser *parser)
          if (c_parser_next_token_is_keyword (parser, RID_AT_END))
            return;
          else if (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY))
-           c_parser_objc_at_property (parser);
+           c_parser_objc_at_property_declaration (parser);
          else if (c_parser_next_token_is_keyword (parser, RID_AT_OPTIONAL))
            {
              objc_set_method_opt (true);
@@ -7247,10 +7475,18 @@ c_parser_objc_type_name (c_parser *parser)
       else
        break;
     }
-  if (c_parser_next_token_starts_typename (parser))
+  if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
     type_name = c_parser_type_name (parser);
   if (type_name)
     type = groktypename (type_name, NULL, NULL);
+
+  /* If the type is unknown, and error has already been produced and
+     we need to recover from the error.  In that case, use NULL_TREE
+     for the type, as if no type had been specified; this will use the
+     default type ('id') which is good for error recovery.  */
+  if (type == error_mark_node)
+    type = NULL_TREE;
+
   return build_tree_list (quals, type);
 }
 
@@ -7288,53 +7524,98 @@ c_parser_objc_protocol_refs (c_parser *parser)
   return list;
 }
 
-/* Parse an objc-try-catch-statement.
+/* Parse an objc-try-catch-finally-statement.
 
-   objc-try-catch-statement:
+   objc-try-catch-finally-statement:
      @try compound-statement objc-catch-list[opt]
      @try compound-statement objc-catch-list[opt] @finally compound-statement
 
    objc-catch-list:
-     @catch ( parameter-declaration ) compound-statement
-     objc-catch-list @catch ( parameter-declaration ) compound-statement
-*/
+     @catch ( objc-catch-parameter-declaration ) compound-statement
+     objc-catch-list @catch ( objc-catch-parameter-declaration ) compound-statement
+
+   objc-catch-parameter-declaration:
+     parameter-declaration
+     '...'
+
+   where '...' is to be interpreted literally, that is, it means CPP_ELLIPSIS.
+
+   PS: This function is identical to cp_parser_objc_try_catch_finally_statement
+   for C++.  Keep them in sync.  */   
 
 static void
-c_parser_objc_try_catch_statement (c_parser *parser)
+c_parser_objc_try_catch_finally_statement (c_parser *parser)
 {
-  location_t loc;
+  location_t location;
   tree stmt;
+
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_TRY));
   c_parser_consume_token (parser);
-  loc = c_parser_peek_token (parser)->location;
+  location = c_parser_peek_token (parser)->location;
+  objc_maybe_warn_exceptions (location);
   stmt = c_parser_compound_statement (parser);
-  objc_begin_try_stmt (loc, stmt);
+  objc_begin_try_stmt (location, stmt);
+
   while (c_parser_next_token_is_keyword (parser, RID_AT_CATCH))
     {
       struct c_parm *parm;
+      tree parameter_declaration = error_mark_node;
+      bool seen_open_paren = false;
+
       c_parser_consume_token (parser);
       if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-       break;
-      parm = c_parser_parameter_declaration (parser, NULL_TREE);
-      if (parm == NULL)
+       seen_open_paren = true;
+      if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
        {
-         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
-         break;
+         /* We have "@catch (...)" (where the '...' are literally
+            what is in the code).  Skip the '...'.
+            parameter_declaration is set to NULL_TREE, and
+            objc_being_catch_clauses() knows that that means
+            '...'.  */
+         c_parser_consume_token (parser);
+         parameter_declaration = NULL_TREE;
        }
-      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
-      objc_begin_catch_clause (grokparm (parm));
+      else
+       {
+         /* We have "@catch (NSException *exception)" or something
+            like that.  Parse the parameter declaration.  */
+         parm = c_parser_parameter_declaration (parser, NULL_TREE);
+         if (parm == NULL)
+           parameter_declaration = error_mark_node;
+         else
+           parameter_declaration = grokparm (parm);
+       }
+      if (seen_open_paren)
+       c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      else
+       {
+         /* If there was no open parenthesis, we are recovering from
+            an error, and we are trying to figure out what mistake
+            the user has made.  */
+
+         /* If there is an immediate closing parenthesis, the user
+            probably forgot the opening one (ie, they typed "@catch
+            NSException *e)".  Parse the closing parenthesis and keep
+            going.  */
+         if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+           c_parser_consume_token (parser);
+         
+         /* If these is no immediate closing parenthesis, the user
+            probably doesn't know that parenthesis are required at
+            all (ie, they typed "@catch NSException *e").  So, just
+            forget about the closing parenthesis and keep going.  */
+       }
+      objc_begin_catch_clause (parameter_declaration);
       if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
        c_parser_compound_statement_nostart (parser);
       objc_finish_catch_clause ();
     }
   if (c_parser_next_token_is_keyword (parser, RID_AT_FINALLY))
     {
-      location_t finloc;
-      tree finstmt;
       c_parser_consume_token (parser);
-      finloc = c_parser_peek_token (parser)->location;
-      finstmt = c_parser_compound_statement (parser);
-      objc_build_finally_clause (finloc, finstmt);
+      location = c_parser_peek_token (parser)->location;
+      stmt = c_parser_compound_statement (parser);
+      objc_build_finally_clause (location, stmt);
     }
   objc_finish_try_stmt ();
 }
@@ -7353,6 +7634,7 @@ c_parser_objc_synchronized_statement (c_parser *parser)
   gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED));
   c_parser_consume_token (parser);
   loc = c_parser_peek_token (parser)->location;
+  objc_maybe_warn_exceptions (loc);
   if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
     {
       expr = c_parser_expression (parser).value;
@@ -7564,7 +7846,8 @@ static bool
 c_parser_objc_diagnose_bad_element_prefix (c_parser *parser, 
                                           struct c_declspecs *specs)
 {
-  if (!specs->declspecs_seen_p || specs->type_seen_p || specs->non_sc_seen_p)
+  if (!specs->declspecs_seen_p || specs->non_sc_seen_p
+      || specs->typespec_kind != ctsk_none)
     {
       c_parser_error (parser, 
                      "no type or storage class may be specified here,");
@@ -7574,132 +7857,190 @@ c_parser_objc_diagnose_bad_element_prefix (c_parser *parser,
   return false;
 }
 
-/* ObjC @property. */
+/* Parse an Objective-C @property declaration.  The syntax is:
 
-/* Parse a comma-separated list of property attributes.  */
+   objc-property-declaration:
+     '@property' objc-property-attributes[opt] struct-declaration ;
+
+   objc-property-attributes:
+    '(' objc-property-attribute-list ')'
+
+   objc-property-attribute-list:
+     objc-property-attribute
+     objc-property-attribute-list, objc-property-attribute
+
+   objc-property-attribute
+     'getter' = identifier
+     'setter' = identifier
+     'readonly'
+     'readwrite'
+     'assign'
+     'retain'
+     'copy'
+     'nonatomic'
+
+  For example:
+    @property NSString *name;
+    @property (readonly) id object;
+    @property (retain, nonatomic, getter=getTheName) id name;
+    @property int a, b, c;
 
+  PS: This function is identical to cp_parser_objc_at_propery_declaration
+  for C++.  Keep them in sync.  */
 static void
-c_parser_objc_property_attrlist (c_parser *parser)
-{
-  bool err = false;
-  /* Initialize to an empty list.  */
-  objc_set_property_attr (c_parser_peek_token (parser)->location,
-                         OBJC_PATTR_INIT, NULL_TREE);
+c_parser_objc_at_property_declaration (c_parser *parser)
+{
+  /* The following variables hold the attributes of the properties as
+     parsed.  They are 'false' or 'NULL_TREE' if the attribute was not
+     seen.  When we see an attribute, we set them to 'true' (if they
+     are boolean properties) or to the identifier (if they have an
+     argument, ie, for getter and setter).  Note that here we only
+     parse the list of attributes, check the syntax and accumulate the
+     attributes that we find.  objc_add_property_declaration() will
+     then process the information.  */
+  bool property_assign = false;
+  bool property_copy = false;
+  tree property_getter_ident = NULL_TREE;
+  bool property_nonatomic = false;
+  bool property_readonly = false;
+  bool property_readwrite = false;
+  bool property_retain = false;
+  tree property_setter_ident = NULL_TREE;
+
+  /* 'properties' is the list of properties that we read.  Usually a
+     single one, but maybe more (eg, in "@property int a, b, c;" there
+     are three).  */
+  tree properties;
+  location_t loc;
 
-  if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
-    return;
+  loc = c_parser_peek_token (parser)->location;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY));
 
-  /* Eat the '(' */
-  c_parser_consume_token (parser);
-  
-  /* Property attribute keywords are valid now.  */
-  parser->objc_property_attr_context = true;
-  while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)
-        && c_parser_next_token_is_not (parser, CPP_EOF)
-        && !err)
+  c_parser_consume_token (parser);  /* Eat '@property'.  */
+
+  /* Parse the optional attribute list...  */
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
     {
-      enum rid keywd;
-      location_t loc;
-      if (c_parser_peek_token (parser)->type != CPP_KEYWORD)
+      /* Eat the '(' */
+      c_parser_consume_token (parser);
+      
+      /* Property attribute keywords are valid now.  */
+      parser->objc_property_attr_context = true;
+
+      while (true)
        {
-         c_parser_error (parser, "expected a property attribute");
+         bool syntax_error = false;
+         c_token *token = c_parser_peek_token (parser);
+         enum rid keyword;
+
+         if (token->type != CPP_KEYWORD)
+           {
+             if (token->type == CPP_CLOSE_PAREN)
+               c_parser_error (parser, "expected identifier");
+             else
+               {
+                 c_parser_consume_token (parser);
+                 c_parser_error (parser, "unknown property attribute");
+               }
+             break;
+           }
+         keyword = token->keyword;
          c_parser_consume_token (parser);
-         err = true;
-         break;
-       }
-      keywd = c_parser_peek_token (parser)->keyword;
-      /* Initially, make diagnostics point to the attribute.  */
-      loc = c_parser_peek_token (parser)->location;
-      switch (keywd)
-       {
-         tree ident;
-         objc_property_attribute_kind pkind;
-         case RID_READONLY:
-           objc_set_property_attr (loc, OBJC_PATTR_READONLY, NULL_TREE);
-           break;
-         case RID_GETTER:
-         case RID_SETTER:
-         case RID_IVAR:
-           c_parser_consume_token (parser);
-           if (c_parser_next_token_is_not (parser, CPP_EQ))
-             {
-               c_parser_error (parser, 
-                 "getter/setter/ivar attribute must be followed by %<=%>");
-               err = true;
-               break;
-             }
-           c_parser_consume_token (parser); /* eat the = */
-           if (c_parser_next_token_is_not (parser, CPP_NAME))
-             {
-               c_parser_error (parser, "expected an identifier");
-               err = true;
-               break;
-             }
-           ident = c_parser_peek_token (parser)->value;
-           if (keywd == RID_SETTER)
-             {
-               pkind = OBJC_PATTR_SETTER;
-               /* Eat the identifier, and look for the following : */
-               c_parser_consume_token (parser);
-               if (c_parser_next_token_is_not (parser, CPP_COLON))
-                 {
+         switch (keyword)
+           {
+           case RID_ASSIGN:    property_assign = true;    break;
+           case RID_COPY:      property_copy = true;      break;
+           case RID_NONATOMIC: property_nonatomic = true; break;
+           case RID_READONLY:  property_readonly = true;  break;
+           case RID_READWRITE: property_readwrite = true; break;
+           case RID_RETAIN:    property_retain = true;    break;
+
+           case RID_GETTER:
+           case RID_SETTER:
+             if (c_parser_next_token_is_not (parser, CPP_EQ))
+               {
+                 if (keyword == RID_GETTER)
                    c_parser_error (parser,
-                               "setter name must be followed by %<:%>");
-                   err = true;
-                 }
-             }
-           else if (keywd == RID_GETTER)
-             pkind = OBJC_PATTR_GETTER;
-           else
-             pkind = OBJC_PATTR_IVAR;
-           
-           objc_set_property_attr (loc, pkind, ident);
-           break;
-         case RID_COPIES:
-           objc_set_property_attr (loc, OBJC_PATTR_COPIES, NULL_TREE);
+                                   "missing %<=%> (after %<getter%> attribute)");
+                 else
+                   c_parser_error (parser,
+                                   "missing %<=%> (after %<setter%> attribute)");
+                 syntax_error = true;
+                 break;
+               }
+             c_parser_consume_token (parser); /* eat the = */
+             if (c_parser_next_token_is_not (parser, CPP_NAME))
+               {
+                 c_parser_error (parser, "expected identifier");
+                 syntax_error = true;
+                 break;
+               }
+             if (keyword == RID_SETTER)
+               {
+                 if (property_setter_ident != NULL_TREE)
+                   c_parser_error (parser, "the %<setter%> attribute may only be specified once");
+                 else
+                   property_setter_ident = c_parser_peek_token (parser)->value;
+                 c_parser_consume_token (parser);
+                 if (c_parser_next_token_is_not (parser, CPP_COLON))
+                   c_parser_error (parser, "setter name must terminate with %<:%>");
+                 else
+                   c_parser_consume_token (parser);
+               }
+             else
+               {
+                 if (property_getter_ident != NULL_TREE)
+                   c_parser_error (parser, "the %<getter%> attribute may only be specified once");
+                 else
+                   property_getter_ident = c_parser_peek_token (parser)->value;
+                 c_parser_consume_token (parser);
+               }
+             break;
+           default:
+             c_parser_error (parser, "unknown property attribute");
+             syntax_error = true;
+             break;
+           }
+
+         if (syntax_error)
            break;
-         default:
-           c_parser_error (parser, "unknown property attribute");
-           err = true;
+         
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           c_parser_consume_token (parser);
+         else
            break;
        }
-      /* Eat the attribute,identifier or colon that's been used.  */
-      c_parser_consume_token (parser);
-      if (err)
-        break;
-
-      if (c_parser_next_token_is (parser, CPP_COMMA))
-       c_parser_consume_token (parser);
-      else if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
-       warning_at (c_parser_peek_token (parser)->location, 0, 
-                   "property attributes should be separated by a %<,%>");
-    }  
-  parser->objc_property_attr_context = false;
-  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
-}
-
-/* Parse property attributes and then the definition.  */
-
-static void
-c_parser_objc_at_property (c_parser *parser)
-{
-  tree props;
-  /* We should only arrive here with the property keyword.  */
-  c_parser_require_keyword (parser, RID_AT_PROPERTY, "expected %<@property%>");
-
-  /* Process the optional attribute list...  */
-  c_parser_objc_property_attrlist (parser) ;
-  /* ... and the property var decls.  */
-  props = c_parser_struct_declaration (parser);
+      parser->objc_property_attr_context = false;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  /* ... and the property declaration(s).  */
+  properties = c_parser_struct_declaration (parser);
 
-  /* Comma-separated properties are chained together in
-     reverse order; add them one by one.  */
-  props = nreverse (props);
+  if (properties == error_mark_node)
+    {
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+      parser->error = false;
+      return;
+    }
 
-  for (; props; props = TREE_CHAIN (props))
-    objc_add_property_variable (copy_node (props));
+  if (properties == NULL_TREE)
+    c_parser_error (parser, "expected identifier");
+  else
+    {
+      /* Comma-separated properties are chained together in
+        reverse order; add them one by one.  */
+      properties = nreverse (properties);
+      
+      for (; properties; properties = TREE_CHAIN (properties))
+       objc_add_property_declaration (loc, copy_node (properties),
+                                      property_readonly, property_readwrite,
+                                      property_assign, property_retain,
+                                      property_copy, property_nonatomic,
+                                      property_getter_ident, property_setter_ident);
+    }
 
   c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+  parser->error = false;
 }
 
 /* Parse an Objective-C @synthesize declaration.  The syntax is:
@@ -8772,6 +9113,9 @@ c_parser_omp_atomic (location_t loc, c_parser *parser)
          goto saw_error;
        }
 
+      /* Arrange to pass the location of the assignment operator to
+        c_finish_omp_atomic.  */
+      loc = c_parser_peek_token (parser)->location;
       c_parser_consume_token (parser);
       {
        location_t rhs_loc = c_parser_peek_token (parser)->location;
@@ -8897,7 +9241,7 @@ c_parser_omp_for_loop (location_t loc,
        goto pop_scopes;
 
       /* Parse the initialization declaration or expression.  */
-      if (c_parser_next_token_starts_declaration (parser))
+      if (c_parser_next_tokens_start_declaration (parser))
        {
          if (i > 0)
            VEC_safe_push (tree, gc, for_block, c_begin_compound_stmt (true));