OSDN Git Service

Merge branch 'trunk' of git://gcc.gnu.org/git/gcc into rework
[pf3gnuchains/gcc-fork.git] / gcc / cp / parser.c
index 8ea805d..ab533f4 100644 (file)
@@ -31,11 +31,11 @@ along with GCC; see the file COPYING3.  If not see
 #include "decl.h"
 #include "flags.h"
 #include "diagnostic-core.h"
-#include "toplev.h"
 #include "output.h"
 #include "target.h"
 #include "cgraph.h"
 #include "c-family/c-common.h"
+#include "c-family/c-objc.h"
 #include "plugin.h"
 
 \f
@@ -502,6 +502,29 @@ cp_lexer_token_at (cp_lexer *lexer ATTRIBUTE_UNUSED, cp_token_position pos)
   return pos;
 }
 
+static inline void
+cp_lexer_set_token_position (cp_lexer *lexer, cp_token_position pos)
+{
+  lexer->next_token = cp_lexer_token_at (lexer, pos);
+}
+
+static inline cp_token_position
+cp_lexer_previous_token_position (cp_lexer *lexer)
+{
+  if (lexer->next_token == &eof_token)
+    return lexer->last_token - 1;
+  else
+    return cp_lexer_token_position (lexer, true);
+}
+
+static inline cp_token *
+cp_lexer_previous_token (cp_lexer *lexer)
+{
+  cp_token_position tp = cp_lexer_previous_token_position (lexer);
+
+  return cp_lexer_token_at (lexer, tp);
+}
+
 /* nonzero if we are presently saving tokens.  */
 
 static inline int
@@ -1334,7 +1357,10 @@ enum
   CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES = 0x2,
   /* When parsing a type-specifier, do not try to parse a class-specifier
      or enum-specifier.  */
-  CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS = 0x4
+  CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS = 0x4,
+  /* When parsing a decl-specifier-seq, only allow type-specifier or
+     constexpr.  */
+  CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR = 0x8
 };
 
 /* This type is used for parameters and variables which hold
@@ -2098,13 +2124,13 @@ static tree cp_parser_objc_statement
   (cp_parser *);
 static bool cp_parser_objc_valid_prefix_attributes
   (cp_parser *, tree *);
-static void cp_parser_objc_at_property 
+static void cp_parser_objc_at_property_declaration 
   (cp_parser *) ;
 static void cp_parser_objc_at_synthesize_declaration 
   (cp_parser *) ;
 static void cp_parser_objc_at_dynamic_declaration
   (cp_parser *) ;
-static void cp_parser_objc_property_decl 
+static tree cp_parser_objc_struct_declaration
   (cp_parser *) ;
 
 /* Utility Routines */
@@ -2695,8 +2721,11 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser,
           template <typename T> struct B : public A<T> { X x; };
 
         The user should have said "typename A<T>::X".  */
-      if (processing_template_decl && current_class_type
-         && TYPE_BINFO (current_class_type))
+      if (cxx_dialect < cxx0x && id == ridpointers[(int)RID_CONSTEXPR])
+       inform (location, "C++0x %<constexpr%> only available with "
+               "-std=c++0x or -std=gnu++0x");
+      else if (processing_template_decl && current_class_type
+              && TYPE_BINFO (current_class_type))
        {
          tree b;
 
@@ -3811,6 +3840,7 @@ cp_parser_primary_expression (cp_parser *parser,
        case RID_IS_STD_LAYOUT:
        case RID_IS_TRIVIAL:
        case RID_IS_UNION:
+       case RID_IS_LITERAL_TYPE:
          return cp_parser_trait_expr (parser, token->keyword);
 
        /* Objective-C++ expressions.  */
@@ -3901,6 +3931,22 @@ cp_parser_primary_expression (cp_parser *parser,
            if (ambiguous_decls)
              return error_mark_node;
 
+           /* In Objective-C++, we may have an Objective-C 2.0
+              dot-syntax for classes here.  */
+           if (c_dialect_objc ()
+               && cp_lexer_peek_token (parser->lexer)->type == CPP_DOT
+               && TREE_CODE (decl) == TYPE_DECL
+               && objc_is_class_name (decl))
+             {
+               tree component;
+               cp_lexer_consume_token (parser->lexer);
+               component = cp_parser_identifier (parser);
+               if (component == error_mark_node)
+                 return error_mark_node;
+
+               return objc_build_class_component_ref (id_expression, component);
+             }
+
            /* In Objective-C++, an instance variable (ivar) may be preferred
               to whatever cp_parser_lookup_name() found.  */
            decl = objc_lookup_ivar (decl, id_expression);
@@ -7169,7 +7215,8 @@ cp_parser_constant_expression (cp_parser* parser,
   saved_non_integral_constant_expression_p = parser->non_integral_constant_expression_p;
   /* We are now parsing a constant-expression.  */
   parser->integral_constant_expression_p = true;
-  parser->allow_non_integral_constant_expression_p = allow_non_constant_p;
+  parser->allow_non_integral_constant_expression_p
+    = (allow_non_constant_p || cxx_dialect >= cxx0x);
   parser->non_integral_constant_expression_p = false;
   /* Although the grammar says "conditional-expression", we parse an
      "assignment-expression", which also permits "throw-expression"
@@ -7188,7 +7235,8 @@ cp_parser_constant_expression (cp_parser* parser,
     = saved_allow_non_integral_constant_expression_p;
   if (allow_non_constant_p)
     *non_constant_p = parser->non_integral_constant_expression_p;
-  else if (parser->non_integral_constant_expression_p)
+  else if (parser->non_integral_constant_expression_p
+          && cxx_dialect < cxx0x)
     expression = error_mark_node;
   parser->non_integral_constant_expression_p
     = saved_non_integral_constant_expression_p;
@@ -7362,6 +7410,9 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
     case RID_IS_UNION:
       kind = CPTK_IS_UNION;
       break;
+    case RID_IS_LITERAL_TYPE:
+      kind = CPTK_IS_LITERAL_TYPE;
+      break;
     default:
       gcc_unreachable ();
     }
@@ -8509,6 +8560,7 @@ cp_parser_condition (cp_parser* parser)
 {
   cp_decl_specifier_seq type_specifiers;
   const char *saved_message;
+  int declares_class_or_enum;
 
   /* Try the declaration first.  */
   cp_parser_parse_tentatively (parser);
@@ -8518,9 +8570,10 @@ cp_parser_condition (cp_parser* parser)
   parser->type_definition_forbidden_message
     = G_("types may not be defined in conditions");
   /* Parse the type-specifier-seq.  */
-  cp_parser_type_specifier_seq (parser, /*is_declaration==*/true,
-                               /*is_trailing_return=*/false,
-                               &type_specifiers);
+  cp_parser_decl_specifier_seq (parser,
+                               CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR,
+                               &type_specifiers,
+                               &declares_class_or_enum);
   /* Restore the saved message.  */
   parser->type_definition_forbidden_message = saved_message;
   /* If all is well, we might be looking at a declaration.  */
@@ -9851,6 +9904,11 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
          break;
        }
 
+      if (found_decl_spec
+         && (flags & CP_PARSER_FLAGS_ONLY_TYPE_OR_CONSTEXPR)
+         && token->keyword != RID_CONSTEXPR)
+       error ("decl-specifier invalid in condition");
+
       /* Constructors are a special case.  The `S' in `S()' is not a
         decl-specifier; it is the beginning of the declarator.  */
       constructor_p
@@ -11026,6 +11084,13 @@ cp_parser_template_parameter_list (cp_parser* parser)
   tree parameter_list = NULL_TREE;
 
   begin_template_parm_list ();
+
+  /* The loop below parses the template parms.  We first need to know
+     the total number of template parms to be able to compute proper
+     canonical types of each dependent type. So after the loop, when
+     we know the total number of template parms,
+     end_template_parm_list computes the proper canonical types and
+     fixes up the dependent types accordingly.  */
   while (true)
     {
       tree parameter;
@@ -11044,11 +11109,11 @@ cp_parser_template_parameter_list (cp_parser* parser)
                                                parm_loc,
                                                parameter,
                                                is_non_type,
-                                                is_parameter_pack);
+                                               is_parameter_pack,
+                                               0);
       else
        {
          tree err_parm = build_tree_list (parameter, parameter);
-         TREE_VALUE (err_parm) = error_mark_node;
          parameter_list = chainon (parameter_list, err_parm);
        }
 
@@ -12231,6 +12296,13 @@ cp_parser_explicit_instantiation (cp_parser* parser)
                                                       decl_specifiers.type_location);
       if (declarator != cp_error_declarator)
        {
+         if (decl_specifiers.specs[(int)ds_inline])
+           permerror (input_location, "explicit instantiation shall not use"
+                      " %<inline%> specifier");
+         if (decl_specifiers.specs[(int)ds_constexpr])
+           permerror (input_location, "explicit instantiation shall not use"
+                      " %<constexpr%> specifier");
+
          decl = grokdeclarator (declarator, &decl_specifiers,
                                 NORMAL, 0, &decl_specifiers.attributes);
          /* Turn access control back on for names used during
@@ -12753,14 +12825,14 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       return error_mark_node;
     }
 
-  /* There is no valid C++ program where a non-template type is
-     followed by a "<".  That usually indicates that the user thought
-     that the type was a template.  */
   if (type && type != error_mark_node)
     {
-      /* As a last-ditch effort, see if TYPE is an Objective-C type.
-        If it is, then the '<'...'>' enclose protocol names rather than
-        template arguments, and so everything is fine.  */
+      /* See if TYPE is an Objective-C type, and if so, parse and
+        accept any protocol references following it.  Do this before
+        the cp_parser_check_for_invalid_template_id() call, because
+        Objective-C types can be followed by '<...>' which would
+        enclose protocol names rather than template arguments, and so
+        everything is fine.  */
       if (c_dialect_objc () && !parser->scope
          && (objc_is_id (type) || objc_is_class_name (type)))
        {
@@ -12775,6 +12847,9 @@ cp_parser_simple_type_specifier (cp_parser* parser,
          return qual_type;
        }
 
+      /* There is no valid C++ program where a non-template type is
+        followed by a "<".  That usually indicates that the user
+        thought that the type was a template.  */
       cp_parser_check_for_invalid_template_id (parser, TREE_TYPE (type),
                                               token->location);
     }
@@ -12855,9 +12930,17 @@ cp_parser_nonclass_name (cp_parser* parser)
       if (type)
        type_decl = TYPE_NAME (type);
     }
-  
+
   /* Issue an error if we did not find a type-name.  */
-  if (TREE_CODE (type_decl) != TYPE_DECL)
+  if (TREE_CODE (type_decl) != TYPE_DECL
+      /* In Objective-C, we have the complication that class names are
+        normally type names and start declarations (eg, the
+        "NSObject" in "NSObject *object;"), but can be used in an
+        Objective-C 2.0 dot-syntax (as in "NSObject.version") which
+        is an expression.  So, a classname followed by a dot is not a
+        valid type-name.  */
+      || (objc_is_class_name (TREE_TYPE (type_decl))
+         && cp_lexer_peek_token (parser->lexer)->type == CPP_DOT))
     {
       if (!cp_parser_simulate_error (parser))
        cp_parser_name_lookup_error (parser, identifier, type_decl,
@@ -13755,10 +13838,8 @@ cp_parser_namespace_definition (cp_parser* parser)
   /* Parse the body of the namespace.  */
   cp_parser_namespace_body (parser);
 
-#ifdef HANDLE_PRAGMA_VISIBILITY
   if (has_visibility)
     pop_visibility (1);
-#endif
 
   /* Finish the namespace.  */
   pop_namespace ();
@@ -14951,8 +15032,8 @@ cp_parser_direct_declarator (cp_parser* parser,
                = cp_parser_constant_expression (parser,
                                                 /*allow_non_constant=*/true,
                                                 &non_constant_p);
-             if (!non_constant_p)
-               bounds = fold_non_dependent_expr (bounds);
+             if (!non_constant_p || cxx_dialect >= cxx0x)
+               /* OK */;
              /* Normally, the array bound must be an integral constant
                 expression.  However, as an extension, we allow VLAs
                 in function scopes as long as they aren't part of a
@@ -16245,15 +16326,37 @@ cp_parser_function_body (cp_parser *parser)
 static bool
 cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser)
 {
-  tree body;
+  tree body, list;
   bool ctor_initializer_p;
+  const bool check_body_p =
+     DECL_CONSTRUCTOR_P (current_function_decl)
+     && DECL_DECLARED_CONSTEXPR_P (current_function_decl);
+  tree last = NULL;
 
   /* Begin the function body.  */
   body = begin_function_body ();
   /* Parse the optional ctor-initializer.  */
   ctor_initializer_p = cp_parser_ctor_initializer_opt (parser);
+
+  /* If we're parsing a constexpr constructor definition, we need
+     to check that the constructor body is indeed empty.  However,
+     before we get to cp_parser_function_body lot of junk has been
+     generated, so we can't just check that we have an empty block.
+     Rather we take a snapshot of the outermost block, and check whether
+     cp_parser_function_body changed its state.  */
+  if (check_body_p)
+    {
+      list = body;
+      if (TREE_CODE (list) == BIND_EXPR)
+       list = BIND_EXPR_BODY (list);
+      if (TREE_CODE (list) == STATEMENT_LIST
+         && STATEMENT_LIST_TAIL (list) != NULL)
+       last = STATEMENT_LIST_TAIL (list)->stmt;
+    }
   /* Parse the function-body.  */
   cp_parser_function_body (parser);
+  if (check_body_p)
+    check_constexpr_ctor_body (last, list);
   /* Finish the function body.  */
   finish_function_body (body);
 
@@ -16356,7 +16459,15 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
                                        /*allow_non_constant_p=*/true,
                                        non_constant_p);
       if (!*non_constant_p)
-       initializer = fold_non_dependent_expr (initializer);
+       {
+         /* We only want to fold if this is really a constant
+            expression.  FIXME Actually, we don't want to fold here, but in
+            cp_finish_decl.  */
+         tree folded = fold_non_dependent_expr (initializer);
+         folded = maybe_constant_value (folded);
+         if (TREE_CONSTANT (folded))
+           initializer = folded;
+       }
     }
   else
     initializer = cp_parser_braced_list (parser, non_constant_p);
@@ -16645,7 +16756,12 @@ cp_parser_class_name (cp_parser *parser,
     }
   else if (TREE_CODE (decl) != TYPE_DECL
           || TREE_TYPE (decl) == error_mark_node
-          || !MAYBE_CLASS_TYPE_P (TREE_TYPE (decl)))
+          || !MAYBE_CLASS_TYPE_P (TREE_TYPE (decl))
+          /* In Objective-C 2.0, a classname followed by '.' starts a
+             dot-syntax expression, and it's not a type-name.  */
+          || (c_dialect_objc ()
+              && cp_lexer_peek_token (parser->lexer)->type == CPP_DOT 
+              && objc_is_class_name (decl)))
     decl = error_mark_node;
 
   if (decl == error_mark_node)
@@ -16752,6 +16868,100 @@ cp_parser_class_specifier (cp_parser* parser)
     type = finish_struct (type, attributes);
   if (nested_name_specifier_p)
     pop_inner_scope (old_scope, scope);
+
+  /* We've finished a type definition.  Check for the common syntax
+     error of forgetting a semicolon after the definition.  We need to
+     be careful, as we can't just check for not-a-semicolon and be done
+     with it; the user might have typed:
+
+     class X { } c = ...;
+     class X { } *p = ...;
+
+     and so forth.  Instead, enumerate all the possible tokens that
+     might follow this production; if we don't see one of them, then
+     complain and silently insert the semicolon.  */
+  {
+    cp_token *token = cp_lexer_peek_token (parser->lexer);
+    bool want_semicolon = true;
+
+    switch (token->type)
+      {
+      case CPP_NAME:
+      case CPP_SEMICOLON:
+      case CPP_MULT:
+      case CPP_AND:
+      case CPP_OPEN_PAREN:
+      case CPP_CLOSE_PAREN:
+      case CPP_COMMA:
+        want_semicolon = false;
+        break;
+
+        /* While it's legal for type qualifiers and storage class
+           specifiers to follow type definitions in the grammar, only
+           compiler testsuites contain code like that.  Assume that if
+           we see such code, then what we're really seeing is a case
+           like:
+
+           class X { }
+           const <type> var = ...;
+
+           or
+
+           class Y { }
+           static <type> func (...) ...
+
+           i.e. the qualifier or specifier applies to the next
+           declaration.  To do so, however, we need to look ahead one
+           more token to see if *that* token is a type specifier.
+
+          This code could be improved to handle:
+
+          class Z { }
+          static const <type> var = ...;  */
+      case CPP_KEYWORD:
+       if (keyword_is_storage_class_specifier (token->keyword)
+           || keyword_is_type_qualifier (token->keyword))
+         {
+           cp_token *lookahead = cp_lexer_peek_nth_token (parser->lexer, 2);
+
+           if (lookahead->type == CPP_KEYWORD
+               && !keyword_begins_type_specifier (lookahead->keyword))
+             want_semicolon = false;
+           else if (lookahead->type == CPP_NAME)
+             /* Handling user-defined types here would be nice, but
+                very tricky.  */
+             want_semicolon = false;
+         }
+       break;
+      default:
+       break;
+      }
+
+    if (want_semicolon)
+      {
+       cp_token_position prev
+         = cp_lexer_previous_token_position (parser->lexer);
+       cp_token *prev_token = cp_lexer_token_at (parser->lexer, prev);
+       location_t loc = prev_token->location;
+
+       if (CLASSTYPE_DECLARED_CLASS (type))
+         error_at (loc, "expected %<;%> after class definition");
+       else if (TREE_CODE (type) == RECORD_TYPE)
+         error_at (loc, "expected %<;%> after struct definition");
+       else if (TREE_CODE (type) == UNION_TYPE)
+         error_at (loc, "expected %<;%> after union definition");
+       else
+         gcc_unreachable ();
+
+       /* Unget one token and smash it to look as though we encountered
+          a semicolon in the input stream.  */
+       cp_lexer_set_token_position (parser->lexer, prev);
+       token = cp_lexer_peek_token (parser->lexer);
+       token->type = CPP_SEMICOLON;
+       token->keyword = RID_MAX;
+      }
+  }
+
   /* If this class is not itself within the scope of another class,
      then we need to parse the bodies of all of the queued function
      definitions.  Note that the queued functions defined in a class
@@ -17526,6 +17736,8 @@ cp_parser_member_declaration (cp_parser* parser)
     }
   else
     {
+      bool assume_semicolon = false;
+
       /* See if these declarations will be friends.  */
       friend_p = cp_parser_friend_p (&decl_specifiers);
 
@@ -17719,11 +17931,18 @@ cp_parser_member_declaration (cp_parser* parser)
          else if (cp_lexer_next_token_is_not (parser->lexer,
                                               CPP_SEMICOLON))
            {
-             cp_parser_error (parser, "expected %<;%>");
-             /* Skip tokens until we find a `;'.  */
-             cp_parser_skip_to_end_of_statement (parser);
+             /* The next token might be a ways away from where the
+                actual semicolon is missing.  Find the previous token
+                and use that for our error position.  */
+             cp_token *token = cp_lexer_previous_token (parser->lexer);
+             error_at (token->location,
+                       "expected %<;%> at end of member declaration");
 
-             break;
+             /* Assume that the user meant to provide a semicolon.  If
+                we were to cp_parser_skip_to_end_of_statement, we might
+                skip to a semicolon inside a member function definition
+                and issue nonsensical error messages.  */
+             assume_semicolon = true;
            }
 
          if (decl)
@@ -17735,6 +17954,9 @@ cp_parser_member_declaration (cp_parser* parser)
              if (TREE_CODE (decl) == FUNCTION_DECL)
                cp_parser_save_default_args (parser, decl);
            }
+
+         if (assume_semicolon)
+           return;
        }
     }
 
@@ -18092,7 +18314,7 @@ cp_parser_exception_specification_opt (cp_parser* parser)
   /* Enable this once a lot of code has transitioned to noexcept?  */
   if (cxx_dialect == cxx0x && !in_system_header)
     warning (OPT_Wdeprecated, "dynamic exception specifications are "
-            "deprecated in C++0x; use %<noexcept%> instead.");
+            "deprecated in C++0x; use %<noexcept%> instead");
 #endif
 
   /* Consume the `throw'.  */
@@ -21852,7 +22074,7 @@ cp_parser_objc_interstitial_code (cp_parser* parser)
   else if (token->type == CPP_OPEN_BRACE || token->type == CPP_CLOSE_BRACE)
     {
       cp_lexer_consume_token (parser->lexer);
-      error ("stray `%s' between Objective-C++ methods",
+      error ("stray %qs between Objective-C++ methods",
             token->type == CPP_OPEN_BRACE ? "{" : "}");
     }
   /* Finally, try to parse a block-declaration, or a function-definition.  */
@@ -21930,7 +22152,7 @@ cp_parser_objc_method_prototype_list (cp_parser* parser)
          cp_parser_consume_semicolon_at_end_of_statement (parser);
        }
       else if (token->keyword == RID_AT_PROPERTY)
-       cp_parser_objc_at_property (parser);
+       cp_parser_objc_at_property_declaration (parser);
       else if (token->keyword == RID_ATTRIBUTE 
               && cp_parser_objc_method_maybe_bad_prefix_attributes(parser))
        warning_at (cp_lexer_peek_token (parser->lexer)->location, 
@@ -21997,8 +22219,10 @@ cp_parser_objc_method_definition_list (cp_parser* parser)
              objc_finish_method_definition (meth);
            }
        }
+      /* The following case will be removed once @synthesize is
+        completely implemented.  */
       else if (token->keyword == RID_AT_PROPERTY)
-       cp_parser_objc_at_property (parser);
+       cp_parser_objc_at_property_declaration (parser);
       else if (token->keyword == RID_AT_SYNTHESIZE)
        cp_parser_objc_at_synthesize_declaration (parser);
       else if (token->keyword == RID_AT_DYNAMIC)
@@ -22051,6 +22275,28 @@ cp_parser_objc_class_ivars (cp_parser* parser)
                                    CP_PARSER_FLAGS_OPTIONAL,
                                    &declspecs,
                                    &decl_class_or_enum_p);
+
+      /* auto, register, static, extern, mutable.  */
+      if (declspecs.storage_class != sc_none)
+       {
+         cp_parser_error (parser, "invalid type for instance variable");         
+         declspecs.storage_class = sc_none;
+       }
+
+      /* __thread.  */
+      if (declspecs.specs[(int) ds_thread])
+       {
+         cp_parser_error (parser, "invalid type for instance variable");
+         declspecs.specs[(int) ds_thread] = 0;
+       }
+      
+      /* typedef.  */
+      if (declspecs.specs[(int) ds_typedef])
+       {
+         cp_parser_error (parser, "invalid type for instance variable");
+         declspecs.specs[(int) ds_typedef] = 0;
+       }
+
       prefix_attributes = declspecs.attributes;
       declspecs.attributes = NULL_TREE;
 
@@ -22170,7 +22416,8 @@ cp_parser_objc_protocol_declaration (cp_parser* parser, tree attributes)
   /* Try a forward declaration first.  */
   if (tok->type == CPP_COMMA || tok->type == CPP_SEMICOLON)
     {
-      objc_declare_protocols (cp_parser_objc_identifier_list (parser));
+      objc_declare_protocols (cp_parser_objc_identifier_list (parser), 
+                             attributes);
      finish:
       cp_parser_consume_semicolon_at_end_of_statement (parser);
     }
@@ -22351,15 +22598,25 @@ cp_parser_objc_declaration (cp_parser* parser, tree attributes)
      objc-catch-clause objc-catch-clause-seq [opt]
 
    objc-catch-clause:
-     @catch ( exception-declaration ) compound-statement
+     @catch ( objc-exception-declaration ) compound-statement
 
-   objc-finally-clause
+   objc-finally-clause:
      @finally compound-statement
 
-   Returns NULL_TREE.  */
+   objc-exception-declaration:
+     parameter-declaration
+     '...'
+
+   where '...' is to be interpreted literally, that is, it means CPP_ELLIPSIS.
+
+   Returns NULL_TREE.
+
+   PS: This function is identical to c_parser_objc_try_catch_finally_statement
+   for C.  Keep them in sync.  */   
 
 static tree
-cp_parser_objc_try_catch_finally_statement (cp_parser *parser) {
+cp_parser_objc_try_catch_finally_statement (cp_parser *parser)
+{
   location_t location;
   tree stmt;
 
@@ -22373,22 +22630,60 @@ cp_parser_objc_try_catch_finally_statement (cp_parser *parser) {
 
   while (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_CATCH))
     {
-      cp_parameter_declarator *parmdecl;
-      tree parm;
+      cp_parameter_declarator *parm;
+      tree parameter_declaration = error_mark_node;
+      bool seen_open_paren = false;
 
       cp_lexer_consume_token (parser->lexer);
-      cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN);
-      parmdecl = cp_parser_parameter_declaration (parser, false, NULL);
-      parm = grokdeclarator (parmdecl->declarator,
-                            &parmdecl->decl_specifiers,
-                            PARM, /*initialized=*/0,
-                            /*attrlist=*/NULL);
-      cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
-      objc_begin_catch_clause (parm);
+      if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+       seen_open_paren = true;
+      if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+       {
+         /* 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
+            '...'.  */
+         cp_lexer_consume_token (parser->lexer);
+         parameter_declaration = NULL_TREE;
+       }
+      else
+       {
+         /* We have "@catch (NSException *exception)" or something
+            like that.  Parse the parameter declaration.  */
+         parm = cp_parser_parameter_declaration (parser, false, NULL);
+         if (parm == NULL)
+           parameter_declaration = error_mark_node;
+         else
+           parameter_declaration = grokdeclarator (parm->declarator,
+                                                   &parm->decl_specifiers,
+                                                   PARM, /*initialized=*/0,
+                                                   /*attrlist=*/NULL);
+       }
+      if (seen_open_paren)
+       cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
+      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 (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
+           cp_lexer_consume_token (parser->lexer);
+         
+         /* 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);
       cp_parser_compound_statement (parser, NULL, false);
       objc_finish_catch_clause ();
     }
-
   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_FINALLY))
     {
       cp_lexer_consume_token (parser->lexer);
@@ -22411,7 +22706,8 @@ cp_parser_objc_try_catch_finally_statement (cp_parser *parser) {
    Returns NULL_TREE.  */
 
 static tree
-cp_parser_objc_synchronized_statement (cp_parser *parser) {
+cp_parser_objc_synchronized_statement (cp_parser *parser)
+{
   location_t location;
   tree lock, stmt;
 
@@ -22438,14 +22734,15 @@ cp_parser_objc_synchronized_statement (cp_parser *parser) {
    Returns a constructed '@throw' statement.  */
 
 static tree
-cp_parser_objc_throw_statement (cp_parser *parser) {
+cp_parser_objc_throw_statement (cp_parser *parser)
+{
   tree expr = NULL_TREE;
   location_t loc = cp_lexer_peek_token (parser->lexer)->location;
 
   cp_parser_require_keyword (parser, RID_AT_THROW, RT_AT_THROW);
 
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
-    expr = cp_parser_assignment_expression (parser, false, NULL);
+    expr = cp_parser_expression (parser, /*cast_p=*/false, NULL);
 
   cp_parser_consume_semicolon_at_end_of_statement (parser);
 
@@ -22455,7 +22752,8 @@ cp_parser_objc_throw_statement (cp_parser *parser) {
 /* Parse an Objective-C statement.  */
 
 static tree
-cp_parser_objc_statement (cp_parser * parser) {
+cp_parser_objc_statement (cp_parser * parser)
+{
   /* Try to figure out what kind of declaration is present.  */
   cp_token *kwd = cp_lexer_peek_token (parser->lexer);
 
@@ -22496,144 +22794,283 @@ cp_parser_objc_valid_prefix_attributes (cp_parser* parser, tree *attrib)
   return false;  
 }
 
-/* This routine parses the propery declarations. */
+/* This routine is a minimal replacement for
+   c_parser_struct_declaration () used when parsing the list of
+   types/names or ObjC++ properties.  For example, when parsing the
+   code
 
-static void
-cp_parser_objc_property_decl (cp_parser *parser)
+   @property (readonly) int a, b, c;
+
+   this function is responsible for parsing "int a, int b, int c" and
+   returning the declarations as CHAIN of DECLs.
+
+   TODO: Share this code with cp_parser_objc_class_ivars.  It's very
+   similar parsing.  */
+static tree
+cp_parser_objc_struct_declaration (cp_parser *parser)
 {
-  int declares_class_or_enum;
+  tree decls = NULL_TREE;
   cp_decl_specifier_seq declspecs;
+  int decl_class_or_enum_p;
+  tree prefix_attributes;
 
   cp_parser_decl_specifier_seq (parser,
-                                CP_PARSER_FLAGS_NONE,
-                                &declspecs,
-                                &declares_class_or_enum);
+                               CP_PARSER_FLAGS_NONE,
+                               &declspecs,
+                               &decl_class_or_enum_p);
+
+  if (declspecs.type == error_mark_node)
+    return error_mark_node;
+
+  /* auto, register, static, extern, mutable.  */
+  if (declspecs.storage_class != sc_none)
+    {
+      cp_parser_error (parser, "invalid type for property");
+      declspecs.storage_class = sc_none;
+    }
+  
+  /* __thread.  */
+  if (declspecs.specs[(int) ds_thread])
+    {
+      cp_parser_error (parser, "invalid type for property");
+      declspecs.specs[(int) ds_thread] = 0;
+    }
+  
+  /* typedef.  */
+  if (declspecs.specs[(int) ds_typedef])
+    {
+      cp_parser_error (parser, "invalid type for property");
+      declspecs.specs[(int) ds_typedef] = 0;
+    }
+
+  prefix_attributes = declspecs.attributes;
+  declspecs.attributes = NULL_TREE;
+
   /* Keep going until we hit the `;' at the end of the declaration. */
   while (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
     {
-      tree property;
+      tree attributes, first_attribute, decl;
+      cp_declarator *declarator;
       cp_token *token;
-      cp_declarator *declarator
-       = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
-                               NULL, NULL, false);
-      property = grokdeclarator (declarator, &declspecs, NORMAL,0, NULL);
-      /* Recover from any kind of error in property declaration. */
-      if (property == error_mark_node || property == NULL_TREE)
-       return;
 
-      /* Add to property list. */
-      objc_add_property_variable (copy_node (property));
+      /* Parse the declarator.  */
+      declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+                                        NULL, NULL, false);
+
+      /* Look for attributes that apply to the ivar.  */
+      attributes = cp_parser_attributes_opt (parser);
+      /* Remember which attributes are prefix attributes and
+        which are not.  */
+      first_attribute = attributes;
+      /* Combine the attributes.  */
+      attributes = chainon (prefix_attributes, attributes);
+      
+      decl = grokfield (declarator, &declspecs,
+                       NULL_TREE, /*init_const_expr_p=*/false,
+                       NULL_TREE, attributes);
+
+      if (decl == error_mark_node || decl == NULL_TREE)
+       return error_mark_node;
+      
+      /* Reset PREFIX_ATTRIBUTES.  */
+      while (attributes && TREE_CHAIN (attributes) != first_attribute)
+       attributes = TREE_CHAIN (attributes);
+      if (attributes)
+       TREE_CHAIN (attributes) = NULL_TREE;
+
+      DECL_CHAIN (decl) = decls;
+      decls = decl;
+
       token = cp_lexer_peek_token (parser->lexer);
       if (token->type == CPP_COMMA)
        {
          cp_lexer_consume_token (parser->lexer);  /* Eat ','.  */
          continue;
        }
-      else if (token->type == CPP_EOF)
+      else
        break;
     }
-  /* Eat ';' if present, or issue an error.  */
-  cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
+  return decls;
 }
 
-/* ObjC @property. */
-/* Parse a comma-separated list of property attributes.  
-   The lexer does not recognize */
+/* Parse an Objective-C @property declaration.  The syntax is:
+
+   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
+   c_parser_objc_at_property_declaration for C.  Keep them in sync.  */
 static void 
-cp_parser_objc_property_attrlist (cp_parser *parser)
-{
-  cp_token *token;
-  /* Initialize to an empty list.  */
-  objc_set_property_attr (cp_lexer_peek_token (parser->lexer)->location,
-                         OBJC_PATTR_INIT, NULL_TREE);
+cp_parser_objc_at_property_declaration (cp_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;
 
-  /* The list is optional.  */
-  if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
-    return;
+  loc = cp_lexer_peek_token (parser->lexer)->location;
 
-  /* Eat the '('.  */
-  cp_lexer_consume_token (parser->lexer);
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@property'.  */
 
-  token = cp_lexer_peek_token (parser->lexer);
-  while (token->type != CPP_CLOSE_PAREN && token->type != CPP_EOF)
-    {
-      location_t loc = token->location;
-      tree node = cp_parser_identifier (parser);
-      if (node == ridpointers [(int) RID_READONLY])
-       objc_set_property_attr (loc, OBJC_PATTR_READONLY, NULL_TREE);
-      else if (node == ridpointers [(int) RID_GETTER]
-              || node == ridpointers [(int) RID_SETTER]
-              || node == ridpointers [(int) RID_IVAR])
+  /* Parse the optional attribute list...  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+    {
+      /* Eat the '('.  */
+      cp_lexer_consume_token (parser->lexer);
+
+      while (true)
        {
-         /* Do the getter/setter/ivar attribute. */
-         token = cp_lexer_consume_token (parser->lexer);
-         if (token->type == CPP_EQ)
+         bool syntax_error = false;
+         cp_token *token = cp_lexer_peek_token (parser->lexer);
+         enum rid keyword;
+
+         if (token->type != CPP_NAME)
+           {
+             cp_parser_error (parser, "expected identifier");
+             break;
+           }
+         keyword = C_RID_CODE (token->u.value);
+         cp_lexer_consume_token (parser->lexer);
+         switch (keyword)
            {
-             tree attr_ident = cp_parser_identifier (parser);
-             objc_property_attribute_kind pkind;
-             if (node == ridpointers [(int) RID_GETTER])
-               pkind = OBJC_PATTR_GETTER;
-             else if (node == ridpointers [(int) RID_SETTER])
+           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 (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ))
                {
-                 pkind = OBJC_PATTR_SETTER;
-                 /* Consume the ':' which must always follow the setter name. */
-                 if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
-                   cp_lexer_consume_token (parser->lexer); 
+                 cp_parser_error (parser,
+                                  "getter/setter/ivar attribute must be followed by %<=%>");
+                 syntax_error = true;
+                 break;
+               }
+             cp_lexer_consume_token (parser->lexer); /* eat the = */
+             if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME))
+               {
+                 cp_parser_error (parser, "expected identifier");
+                 syntax_error = true;
+                 break;
+               }
+             if (keyword == RID_SETTER)
+               {
+                 if (property_setter_ident != NULL_TREE)
+                   cp_parser_error (parser, "the %<setter%> attribute may only be specified once");
                  else
-                   {
-                     error_at (token->location,
-                               "setter name must be followed by %<:%>");
-                     break;
-                   }
+                   property_setter_ident = cp_lexer_peek_token (parser->lexer)->u.value;
+                 cp_lexer_consume_token (parser->lexer);
+                 if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+                   cp_parser_error (parser, "setter name must terminate with %<:%>");
+                 else
+                   cp_lexer_consume_token (parser->lexer);
+               }
+             else
+               {
+                 if (property_getter_ident != NULL_TREE)
+                   cp_parser_error (parser, "the %<getter%> attribute may only be specified once");
+                 else
+                   property_getter_ident = cp_lexer_peek_token (parser->lexer)->u.value;
+                 cp_lexer_consume_token (parser->lexer);
                }
-             else 
-               pkind = OBJC_PATTR_IVAR;
-             objc_set_property_attr (loc, pkind, attr_ident);    
-           }
-         else
-           {
-             error_at (token->location,
-               "getter/setter/ivar attribute must be followed by %<=%>");
+             break;
+           default:
+             cp_parser_error (parser, "unknown property attribute");
+             syntax_error = true;
              break;
            }
+
+         if (syntax_error)
+           break;
+         
+         if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+           cp_lexer_consume_token (parser->lexer);
+         else
+           break;
        }
-      else if (node == ridpointers [(int) RID_COPIES])
-       objc_set_property_attr (loc, OBJC_PATTR_COPIES, NULL_TREE);
-      else
+
+      if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
        {
-         error_at (token->location,"unknown property attribute");
-         break;
+         cp_parser_skip_to_closing_parenthesis (parser,
+                                                /*recovering=*/true,
+                                                /*or_comma=*/false,
+                                                /*consume_paren=*/true);
        }
-      if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
-       cp_lexer_consume_token (parser->lexer);
-      else if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
-       warning_at (token->location, 0, 
-                   "property attributes should be separated by a %<,%>");
-      token = cp_lexer_peek_token (parser->lexer);       
     }
 
-  if (token->type != CPP_CLOSE_PAREN)
-    error_at (token->location,
-             "syntax error in @property's attribute declaration");
-  else
-    /* Consume ')' */
-    cp_lexer_consume_token (parser->lexer);
-}
-
-/* This function parses a @property declaration inside an objective class
-   or its implementation. */
+  /* ... and the property declaration(s).  */
+  properties = cp_parser_objc_struct_declaration (parser);
 
-static void 
-cp_parser_objc_at_property (cp_parser *parser)
-{
-  /* Consume @property */
-  cp_lexer_consume_token (parser->lexer);
+  if (properties == error_mark_node)
+    {
+      cp_parser_skip_to_end_of_statement (parser);
+      /* If the next token is now a `;', consume it.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+       cp_lexer_consume_token (parser->lexer);
+      return;
+    }
 
-  /* Parse optional attributes list...  */
-  cp_parser_objc_property_attrlist (parser);
-  /* ... and the property declaration(s).  */
-  cp_parser_objc_property_decl (parser);
+  if (properties == NULL_TREE)
+    cp_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);
+    }
+  
+  cp_parser_consume_semicolon_at_end_of_statement (parser);
 }
 
 /* Parse an Objective-C++ @synthesize declaration.  The syntax is: