OSDN Git Service

* doc/tm.texi.in (HANDLE_SYSV_PRAGMA,
[pf3gnuchains/gcc-fork.git] / gcc / cp / parser.c
index d9cc727..3ed0579 100644 (file)
@@ -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
@@ -2097,7 +2123,15 @@ static void cp_parser_objc_declaration
 static tree cp_parser_objc_statement
   (cp_parser *);
 static bool cp_parser_objc_valid_prefix_attributes
-  (cp_parser* parser, tree *attrib);
+  (cp_parser *, tree *);
+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 tree cp_parser_objc_struct_declaration
+  (cp_parser *) ;
 
 /* Utility Routines */
 
@@ -2687,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;
 
@@ -3803,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.  */
@@ -3893,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);
@@ -7161,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"
@@ -7180,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;
@@ -7354,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 ();
     }
@@ -8294,10 +8353,13 @@ cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr)
     {
       cp_token *token = cp_lexer_peek_token (parser->lexer);
 
-      /* If we're looking at a `}', then we've run out of statements.  */
+      /* If we are looking at a `}', then we have run out of
+        statements; the same is true if we have reached the end
+        of file, or have stumbled upon a stray '@end'.  */
       if (token->type == CPP_CLOSE_BRACE
          || token->type == CPP_EOF
-         || token->type == CPP_PRAGMA_EOL)
+         || token->type == CPP_PRAGMA_EOL
+         || (token->type == CPP_KEYWORD && token->keyword == RID_AT_END))
        break;
       
       /* If we are in a compound statement and find 'else' then
@@ -8498,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);
@@ -8507,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.  */
@@ -8762,8 +8826,10 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
   TREE_USED (range_temp) = 1;
   DECL_ARTIFICIAL (range_temp) = 1;
   pushdecl (range_temp);
-  finish_expr_stmt (cp_build_modify_expr (range_temp, INIT_EXPR, range_expr,
-                                         tf_warning_or_error));
+  cp_finish_decl (range_temp, range_expr,
+                 /*is_constant_init*/false, NULL_TREE,
+                 LOOKUP_ONLYCONVERTING);
+
   range_temp = convert_from_reference (range_temp);
 
   if (TREE_CODE (TREE_TYPE (range_temp)) == ARRAY_TYPE)
@@ -8813,16 +8879,18 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr)
   TREE_USED (begin) = 1;
   DECL_ARTIFICIAL (begin) = 1;
   pushdecl (begin);
-  finish_expr_stmt (cp_build_modify_expr (begin, INIT_EXPR, begin_expr,
-                                         tf_warning_or_error));
+  cp_finish_decl (begin, begin_expr,
+                 /*is_constant_init*/false, NULL_TREE,
+                 LOOKUP_ONLYCONVERTING);
+
   end = build_decl (input_location, VAR_DECL,
                    get_identifier ("__for_end"), iter_type);
   TREE_USED (end) = 1;
   DECL_ARTIFICIAL (end) = 1;
   pushdecl (end);
-
-  finish_expr_stmt (cp_build_modify_expr (end, INIT_EXPR, end_expr,
-                                         tf_warning_or_error));
+  cp_finish_decl (end, end_expr,
+                 /*is_constant_init*/false, NULL_TREE,
+                 LOOKUP_ONLYCONVERTING);
 
   finish_for_init_stmt (statement);
 
@@ -9836,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
@@ -11011,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;
@@ -11029,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);
        }
 
@@ -12216,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
@@ -12738,15 +12825,15 @@ 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.  */
-      if (c_dialect_objc ()
+      /* 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)))
        {
          tree protos = cp_parser_objc_protocol_refs_opt (parser);
@@ -12760,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);
     }
@@ -12840,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,
@@ -12905,17 +13003,17 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
       cp_lexer_consume_token (parser->lexer);
       /* Remember that it's an enumeration type.  */
       tag_type = enum_type;
-      /* Parse the optional `struct' or `class' key (for C++0x scoped
-         enums).  */
+      /* Issue a warning if the `struct' or `class' key (for C++0x scoped
+        enums) is used here.  */
       if (cp_lexer_next_token_is_keyword (parser->lexer, RID_CLASS)
-          || cp_lexer_next_token_is_keyword (parser->lexer, RID_STRUCT))
-        {
-          if (cxx_dialect == cxx98)
-            maybe_warn_cpp0x (CPP0X_SCOPED_ENUMS);
-
-          /* Consume the `struct' or `class'.  */
-          cp_lexer_consume_token (parser->lexer);
-        }
+         || cp_lexer_next_token_is_keyword (parser->lexer, RID_STRUCT))
+       {
+           pedwarn (input_location, 0, "elaborated-type-specifier "
+                     "for a scoped enum must not use the %<%D%> keyword",
+                     cp_lexer_peek_token (parser->lexer)->u.value);
+         /* Consume the `struct' or `class' and parse it anyway.  */
+         cp_lexer_consume_token (parser->lexer);
+       }
       /* Parse the attributes.  */
       attributes = cp_parser_attributes_opt (parser);
     }
@@ -13205,7 +13303,11 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
 /* Parse an enum-specifier.
 
    enum-specifier:
-     enum-key identifier [opt] enum-base [opt] { enumerator-list [opt] }
+     enum-head { enumerator-list [opt] }
+
+   enum-head:
+     enum-key identifier [opt] enum-base [opt]
+     enum-key nested-name-specifier identifier enum-base [opt]
 
    enum-key:
      enum
@@ -13215,6 +13317,9 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
    enum-base:   [C++0x]
      : type-specifier-seq
 
+   opaque-enum-specifier:
+     enum-key identifier enum-base [opt] ;
+
    GNU Extensions:
      enum-key attributes[opt] identifier [opt] enum-base [opt] 
        { enumerator-list [opt] }attributes[opt]
@@ -13226,11 +13331,18 @@ static tree
 cp_parser_enum_specifier (cp_parser* parser)
 {
   tree identifier;
-  tree type;
+  tree type = NULL_TREE;
+  tree prev_scope;
+  tree nested_name_specifier = NULL_TREE;
   tree attributes;
   bool scoped_enum_p = false;
   bool has_underlying_type = false;
+  bool nested_being_defined = false;
+  bool new_value_list = false;
+  bool is_new_type = false;
+  bool is_anonymous = false;
   tree underlying_type = NULL_TREE;
+  cp_token *type_start_token = NULL;
 
   /* Parse tentatively so that we can back up if we don't find a
      enum-specifier.  */
@@ -13247,7 +13359,7 @@ cp_parser_enum_specifier (cp_parser* parser)
   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_CLASS)
       || cp_lexer_next_token_is_keyword (parser->lexer, RID_STRUCT))
     {
-      if (cxx_dialect == cxx98)
+      if (cxx_dialect < cxx0x)
         maybe_warn_cpp0x (CPP0X_SCOPED_ENUMS);
 
       /* Consume the `struct' or `class' token.  */
@@ -13258,10 +13370,65 @@ cp_parser_enum_specifier (cp_parser* parser)
 
   attributes = cp_parser_attributes_opt (parser);
 
-  if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
-    identifier = cp_parser_identifier (parser);
+  /* Clear the qualification.  */
+  parser->scope = NULL_TREE;
+  parser->qualifying_scope = NULL_TREE;
+  parser->object_scope = NULL_TREE;
+
+  /* Figure out in what scope the declaration is being placed.  */
+  prev_scope = current_scope ();
+
+  type_start_token = cp_lexer_peek_token (parser->lexer);
+
+  push_deferring_access_checks (dk_no_check);
+  nested_name_specifier
+      = cp_parser_nested_name_specifier_opt (parser,
+                                            /*typename_keyword_p=*/true,
+                                            /*check_dependency_p=*/false,
+                                            /*type_p=*/false,
+                                            /*is_declaration=*/false);
+
+  if (nested_name_specifier)
+    {
+      tree name;
+
+      identifier = cp_parser_identifier (parser);
+      name =  cp_parser_lookup_name (parser, identifier,
+                                    enum_type,
+                                    /*is_template=*/false,
+                                    /*is_namespace=*/false,
+                                    /*check_dependency=*/true,
+                                    /*ambiguous_decls=*/NULL,
+                                    input_location);
+      if (name)
+       {
+         type = TREE_TYPE (name);
+         if (TREE_CODE (type) == TYPENAME_TYPE)
+           {
+             /* Are template enums allowed in ISO? */
+             if (template_parm_scope_p ())
+               pedwarn (type_start_token->location, OPT_pedantic,
+                        "%qD is an enumeration template", name);
+             /* ignore a typename reference, for it will be solved by name
+                in start_enum.  */
+             type = NULL_TREE;
+           }
+       }
+      else
+       error_at (type_start_token->location,
+                 "%qD is not an enumerator-name", identifier);
+    }
   else
-    identifier = make_anon_name ();
+    {
+      if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+       identifier = cp_parser_identifier (parser);
+      else
+       {
+         identifier = make_anon_name ();
+         is_anonymous = true;
+       }
+    }
+  pop_deferring_access_checks ();
 
   /* Check for the `:' that denotes a specified underlying type in C++0x.
      Note that a ':' could also indicate a bitfield width, however.  */
@@ -13281,7 +13448,7 @@ cp_parser_enum_specifier (cp_parser* parser)
       if (!cp_parser_parse_definitely (parser))
        return NULL_TREE;
 
-      if (cxx_dialect == cxx98)
+      if (cxx_dialect < cxx0x)
         maybe_warn_cpp0x (CPP0X_SCOPED_ENUMS);
 
       has_underlying_type = true;
@@ -13299,14 +13466,39 @@ cp_parser_enum_specifier (cp_parser* parser)
   /* Look for the `{' but don't consume it yet.  */
   if (!cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
     {
-      cp_parser_error (parser, "expected %<{%>");
-      if (has_underlying_type)
-       return NULL_TREE;
+      if (cxx_dialect < cxx0x || (!scoped_enum_p && !underlying_type))
+       {
+         cp_parser_error (parser, "expected %<{%>");
+         if (has_underlying_type)
+           return NULL_TREE;
+       }
+      /* An opaque-enum-specifier must have a ';' here.  */
+      if ((scoped_enum_p || underlying_type)
+         && cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+       {
+         cp_parser_error (parser, "expected %<;%> or %<{%>");
+         if (has_underlying_type)
+           return NULL_TREE;
+       }
     }
 
   if (!has_underlying_type && !cp_parser_parse_definitely (parser))
     return NULL_TREE;
 
+  if (nested_name_specifier)
+    {
+      if (CLASS_TYPE_P (nested_name_specifier))
+       {
+         nested_being_defined = TYPE_BEING_DEFINED (nested_name_specifier);
+         TYPE_BEING_DEFINED (nested_name_specifier) = 1;
+         push_scope (nested_name_specifier);
+       }
+      else if (TREE_CODE (nested_name_specifier) == NAMESPACE_DECL)
+       {
+         push_nested_namespace (nested_name_specifier);
+       }
+    }
+
   /* Issue an error message if type-definitions are forbidden here.  */
   if (!cp_parser_check_type_definition (parser))
     type = error_mark_node;
@@ -13314,23 +13506,89 @@ cp_parser_enum_specifier (cp_parser* parser)
     /* Create the new type.  We do this before consuming the opening
        brace so the enum will be recorded as being on the line of its
        tag (or the 'enum' keyword, if there is no tag).  */
-    type = start_enum (identifier, underlying_type, scoped_enum_p);
-  
-  /* Consume the opening brace.  */
-  cp_lexer_consume_token (parser->lexer);
+    type = start_enum (identifier, type, underlying_type,
+                      scoped_enum_p, &is_new_type);
 
-  if (type == error_mark_node)
+  /* If the next token is not '{' it is an opaque-enum-specifier or an
+     elaborated-type-specifier.  */
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
     {
-      cp_parser_skip_to_end_of_block_or_statement (parser);
-      return error_mark_node;
-    }
+      if (nested_name_specifier)
+       {
+         /* The following catches invalid code such as:
+            enum class S<int>::E { A, B, C }; */
+         if (!processing_specialization
+             && CLASS_TYPE_P (nested_name_specifier)
+             && CLASSTYPE_USE_TEMPLATE (nested_name_specifier))
+           error_at (type_start_token->location, "cannot add an enumerator "
+                     "list to a template instantiation");
+
+         /* If that scope does not contain the scope in which the
+            class was originally declared, the program is invalid.  */
+         if (prev_scope && !is_ancestor (prev_scope, nested_name_specifier))
+           {
+             if (at_namespace_scope_p ())
+               error_at (type_start_token->location,
+                         "declaration of %qD in namespace %qD which does not "
+                         "enclose %qD",
+                         type, prev_scope, nested_name_specifier);
+             else
+               error_at (type_start_token->location,
+                         "declaration of %qD in %qD which does not enclose %qD",
+                         type, prev_scope, nested_name_specifier);
+             type = error_mark_node;
+           }
+       }
 
-  /* If the next token is not '}', then there are some enumerators.  */
-  if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
-    cp_parser_enumerator_list (parser, type);
+      if (scoped_enum_p)
+       begin_scope (sk_scoped_enum, type);
 
-  /* Consume the final '}'.  */
-  cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
+      /* Consume the opening brace.  */
+      cp_lexer_consume_token (parser->lexer);
+
+      if (type == error_mark_node)
+       ; /* Nothing to add */
+      else if (OPAQUE_ENUM_P (type)
+              || (cxx_dialect > cxx98 && processing_specialization))
+       {
+         new_value_list = true;
+         SET_OPAQUE_ENUM_P (type, false);
+         DECL_SOURCE_LOCATION (TYPE_NAME (type)) = type_start_token->location;
+       }
+      else
+       {
+         error_at (type_start_token->location, "multiple definition of %q#T", type);
+         error_at (DECL_SOURCE_LOCATION (TYPE_MAIN_DECL (type)),
+                   "previous definition here");
+         type = error_mark_node;
+       }
+
+      if (type == error_mark_node)
+       cp_parser_skip_to_end_of_block_or_statement (parser);
+      /* If the next token is not '}', then there are some enumerators.  */
+      else if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
+       cp_parser_enumerator_list (parser, type);
+
+      /* Consume the final '}'.  */
+      cp_parser_require (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE);
+
+      if (scoped_enum_p)
+       finish_scope ();
+    }
+  else
+    {
+      /* If a ';' follows, then it is an opaque-enum-specifier
+       and additional restrictions apply.  */
+      if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+       {
+         if (is_anonymous)
+           error_at (type_start_token->location,
+                     "opaque-enum-specifier without name");
+         else if (nested_name_specifier)
+           error_at (type_start_token->location,
+                     "opaque-enum-specifier must use a simple identifier");
+       }
+    }
 
   /* Look for trailing attributes to apply to this enumeration, and
      apply them if appropriate.  */
@@ -13344,8 +13602,26 @@ cp_parser_enum_specifier (cp_parser* parser)
     }
 
   /* Finish up the enumeration.  */
-  finish_enum (type);
+  if (type != error_mark_node)
+    {
+      if (new_value_list)
+       finish_enum_value_list (type);
+      if (is_new_type)
+       finish_enum (type);
+    }
 
+  if (nested_name_specifier)
+    {
+      if (CLASS_TYPE_P (nested_name_specifier))
+       {
+         TYPE_BEING_DEFINED (nested_name_specifier) = nested_being_defined;
+         pop_scope (nested_name_specifier);
+       }
+      else if (TREE_CODE (nested_name_specifier) == NAMESPACE_DECL)
+       {
+         pop_nested_namespace (nested_name_specifier);
+       }
+    }
   return type;
 }
 
@@ -13562,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 ();
@@ -14758,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
@@ -16052,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);
 
@@ -16163,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);
@@ -16452,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)
@@ -16559,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
@@ -17333,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);
 
@@ -17526,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)
@@ -17542,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;
        }
     }
 
@@ -17899,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'.  */
@@ -21090,6 +21505,12 @@ cp_parser_objc_message_args (cp_parser* parser)
       token = cp_lexer_peek_token (parser->lexer);
     }
 
+  if (sel_args == NULL_TREE && addl_args == NULL_TREE)
+    {
+      cp_parser_error (parser, "objective-c++ message argument(s) are expected");
+      return build_tree_list (error_mark_node, error_mark_node);
+    }
+
   return build_tree_list (sel_args, addl_args);
 }
 
@@ -21119,6 +21540,19 @@ cp_parser_objc_encode_expression (cp_parser* parser)
       return error_mark_node;
     }
 
+  /* This happens if we find @encode(T) (where T is a template
+     typename or something dependent on a template typename) when
+     parsing a template.  In that case, we can't compile it
+     immediately, but we rather create an AT_ENCODE_EXPR which will
+     need to be instantiated when the template is used.
+  */
+  if (dependent_type_p (type))
+    {
+      tree value = build_min (AT_ENCODE_EXPR, size_type_node, type);
+      TREE_READONLY (value) = 1;
+      return value;
+    }
+
   return objc_build_encode_expr (type);
 }
 
@@ -21244,18 +21678,29 @@ cp_parser_objc_selector_expression (cp_parser* parser)
 static tree
 cp_parser_objc_identifier_list (cp_parser* parser)
 {
-  tree list = build_tree_list (NULL_TREE, cp_parser_identifier (parser));
-  cp_token *sep = cp_lexer_peek_token (parser->lexer);
+  tree identifier;
+  tree list;
+  cp_token *sep;
+
+  identifier = cp_parser_identifier (parser);
+  if (identifier == error_mark_node)
+    return error_mark_node;      
+
+  list = build_tree_list (NULL_TREE, identifier);
+  sep = cp_lexer_peek_token (parser->lexer);
 
   while (sep->type == CPP_COMMA)
     {
       cp_lexer_consume_token (parser->lexer);  /* Eat ','.  */
-      list = chainon (list,
-                     build_tree_list (NULL_TREE,
-                                      cp_parser_identifier (parser)));
+      identifier = cp_parser_identifier (parser);
+      if (identifier == error_mark_node)
+       return list;
+
+      list = chainon (list, build_tree_list (NULL_TREE,
+                                            identifier));
       sep = cp_lexer_peek_token (parser->lexer);
     }
-
+  
   return list;
 }
 
@@ -21330,13 +21775,16 @@ cp_parser_objc_visibility_spec (cp_parser* parser)
   switch (vis->keyword)
     {
     case RID_AT_PRIVATE:
-      objc_set_visibility (2);
+      objc_set_visibility (OBJC_IVAR_VIS_PRIVATE);
       break;
     case RID_AT_PROTECTED:
-      objc_set_visibility (0);
+      objc_set_visibility (OBJC_IVAR_VIS_PROTECTED);
       break;
     case RID_AT_PUBLIC:
-      objc_set_visibility (1);
+      objc_set_visibility (OBJC_IVAR_VIS_PUBLIC);
+      break;
+    case RID_AT_PACKAGE:
+      objc_set_visibility (OBJC_IVAR_VIS_PACKAGE);
       break;
     default:
       return;
@@ -21346,15 +21794,16 @@ cp_parser_objc_visibility_spec (cp_parser* parser)
   cp_lexer_consume_token (parser->lexer);
 }
 
-/* Parse an Objective-C method type.  */
+/* Parse an Objective-C method type.  Return 'true' if it is a class
+   (+) method, and 'false' if it is an instance (-) method.  */
 
-static void
+static inline bool
 cp_parser_objc_method_type (cp_parser* parser)
 {
-  objc_set_method_type
-   (cp_lexer_consume_token (parser->lexer)->type == CPP_PLUS
-    ? PLUS_EXPR
-    : MINUS_EXPR);
+  if (cp_lexer_consume_token (parser->lexer)->type == CPP_PLUS)
+    return true;
+  else
+    return false;
 }
 
 /* Parse an Objective-C protocol qualifier.  */
@@ -21482,7 +21931,12 @@ cp_parser_objc_method_keyword_params (cp_parser* parser, tree* attributes)
        }
 
       maybe_unary_selector_p = false;
-      cp_parser_require (parser, CPP_COLON, RT_COLON);
+      if (!cp_parser_require (parser, CPP_COLON, RT_COLON))
+       {
+         /* Something went quite wrong.  There should be a colon
+            here, but there is not.  Stop parsing parameters.  */
+         break;
+       }
       type_name = cp_parser_objc_typename (parser);
       /* New ObjC allows attributes on parameters too.  */
       if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
@@ -21517,6 +21971,11 @@ cp_parser_objc_method_keyword_params (cp_parser* parser, tree* attributes)
       return error_mark_node;
     }
 
+  if (params == NULL_TREE)
+    {
+      cp_parser_error (parser, "objective-c++ method declaration is expected");
+      return error_mark_node;
+    }
   return params;
 }
 
@@ -21542,6 +22001,7 @@ cp_parser_objc_method_tail_params_opt (cp_parser* parser, bool *ellipsisp,
        {
          cp_lexer_consume_token (parser->lexer);  /* Eat '...'.  */
          *ellipsisp = true;
+         token = cp_lexer_peek_token (parser->lexer);
          break;
        }
 
@@ -21597,6 +22057,26 @@ cp_parser_objc_interstitial_code (cp_parser* parser)
   /* Allow stray semicolons.  */
   else if (token->type == CPP_SEMICOLON)
     cp_lexer_consume_token (parser->lexer);
+  /* Mark methods as optional or required, when building protocols.  */
+  else if (token->keyword == RID_AT_OPTIONAL)
+    {
+      cp_lexer_consume_token (parser->lexer);
+      objc_set_method_opt (true);
+    }
+  else if (token->keyword == RID_AT_REQUIRED)
+    {
+      cp_lexer_consume_token (parser->lexer);
+      objc_set_method_opt (false);
+    }
+  else if (token->keyword == RID_NAMESPACE)
+    cp_parser_namespace_definition (parser);
+  /* Other stray characters must generate errors.  */
+  else if (token->type == CPP_OPEN_BRACE || token->type == CPP_CLOSE_BRACE)
+    {
+      cp_lexer_consume_token (parser->lexer);
+      error ("stray %qs between Objective-C++ methods",
+            token->type == CPP_OPEN_BRACE ? "{" : "}");
+    }
   /* Finally, try to parse a block-declaration, or a function-definition.  */
   else
     cp_parser_block_declaration (parser, /*statement_p=*/false);
@@ -21609,8 +22089,9 @@ cp_parser_objc_method_signature (cp_parser* parser, tree* attributes)
 {
   tree rettype, kwdparms, optparms;
   bool ellipsis = false;
+  bool is_class_method;
 
-  cp_parser_objc_method_type (parser);
+  is_class_method = cp_parser_objc_method_type (parser);
   rettype = cp_parser_objc_typename (parser);
   *attributes = NULL_TREE;
   kwdparms = cp_parser_objc_method_keyword_params (parser, attributes);
@@ -21620,7 +22101,7 @@ cp_parser_objc_method_signature (cp_parser* parser, tree* attributes)
   if (optparms == error_mark_node)
     return error_mark_node;
 
-  return objc_build_method_signature (rettype, kwdparms, optparms, ellipsis);
+  return objc_build_method_signature (is_class_method, rettype, kwdparms, optparms, ellipsis);
 }
 
 static bool
@@ -21655,15 +22136,23 @@ cp_parser_objc_method_prototype_list (cp_parser* parser)
       if (token->type == CPP_PLUS || token->type == CPP_MINUS)
        {
          tree attributes, sig;
+         bool is_class_method;
+         if (token->type == CPP_PLUS)
+           is_class_method = true;
+         else
+           is_class_method = false;
          sig = cp_parser_objc_method_signature (parser, &attributes);
          if (sig == error_mark_node)
            {
              cp_parser_skip_to_end_of_block_or_statement (parser);
+             token = cp_lexer_peek_token (parser->lexer);
              continue;
            }
-         objc_add_method_declaration (sig, attributes);
+         objc_add_method_declaration (is_class_method, sig, attributes);
          cp_parser_consume_semicolon_at_end_of_statement (parser);
        }
+      else if (token->keyword == RID_AT_PROPERTY)
+       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, 
@@ -21676,7 +22165,11 @@ cp_parser_objc_method_prototype_list (cp_parser* parser)
       token = cp_lexer_peek_token (parser->lexer);
     }
 
-  cp_lexer_consume_token (parser->lexer);  /* Eat '@end'.  */
+  if (token->type != CPP_EOF)
+    cp_lexer_consume_token (parser->lexer);  /* Eat '@end'.  */
+  else
+    cp_parser_error (parser, "expected %<@end%>");
+
   objc_finish_interface ();
 }
 
@@ -21695,14 +22188,20 @@ cp_parser_objc_method_definition_list (cp_parser* parser)
        {
          cp_token *ptk;
          tree sig, attribute;
+         bool is_class_method;
+         if (token->type == CPP_PLUS)
+           is_class_method = true;
+         else
+           is_class_method = false;
          push_deferring_access_checks (dk_deferred);
          sig = cp_parser_objc_method_signature (parser, &attribute);
          if (sig == error_mark_node)
            {
              cp_parser_skip_to_end_of_block_or_statement (parser);
+             token = cp_lexer_peek_token (parser->lexer);
              continue;
            }
-         objc_start_method_definition (sig, attribute);
+         objc_start_method_definition (is_class_method, sig, attribute);
 
          /* For historical reasons, we accept an optional semicolon.  */
          if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
@@ -21715,11 +22214,19 @@ cp_parser_objc_method_definition_list (cp_parser* parser)
              perform_deferred_access_checks ();
              stop_deferring_access_checks ();
              meth = cp_parser_function_definition_after_declarator (parser,
-                                                                false);
+                                                                    false);
              pop_deferring_access_checks ();
              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_declaration (parser);
+      else if (token->keyword == RID_AT_SYNTHESIZE)
+       cp_parser_objc_at_synthesize_declaration (parser);
+      else if (token->keyword == RID_AT_DYNAMIC)
+       cp_parser_objc_at_dynamic_declaration (parser);
       else if (token->keyword == RID_ATTRIBUTE 
               && cp_parser_objc_method_maybe_bad_prefix_attributes(parser))
        warning_at (token->location, OPT_Wattributes,
@@ -21731,7 +22238,11 @@ cp_parser_objc_method_definition_list (cp_parser* parser)
       token = cp_lexer_peek_token (parser->lexer);
     }
 
-  cp_lexer_consume_token (parser->lexer);  /* Eat '@end'.  */
+  if (token->type != CPP_EOF)
+    cp_lexer_consume_token (parser->lexer);  /* Eat '@end'.  */
+  else
+    cp_parser_error (parser, "expected %<@end%>");
+
   objc_finish_implementation ();
 }
 
@@ -21748,7 +22259,8 @@ cp_parser_objc_class_ivars (cp_parser* parser)
   cp_lexer_consume_token (parser->lexer);  /* Eat '{'.  */
   token = cp_lexer_peek_token (parser->lexer);
 
-  while (token->type != CPP_CLOSE_BRACE)
+  while (token->type != CPP_CLOSE_BRACE 
+       && token->keyword != RID_AT_END && token->type != CPP_EOF)
     {
       cp_decl_specifier_seq declspecs;
       int decl_class_or_enum_p;
@@ -21763,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;
 
@@ -21847,7 +22381,14 @@ cp_parser_objc_class_ivars (cp_parser* parser)
       token = cp_lexer_peek_token (parser->lexer);
     }
 
-  cp_lexer_consume_token (parser->lexer);  /* Eat '}'.  */
+  if (token->keyword == RID_AT_END)
+    cp_parser_error (parser, "expected %<}%>");
+
+  /* Do not consume the RID_AT_END, so it will be read again as terminating
+     the @interface of @implementation.  */ 
+  if (token->keyword != RID_AT_END && token->type != CPP_EOF)
+    cp_lexer_consume_token (parser->lexer);  /* Eat '}'.  */
+    
   /* For historical reasons, we accept an optional semicolon.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
     cp_lexer_consume_token (parser->lexer);
@@ -21875,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);
     }
@@ -21921,6 +22463,15 @@ cp_parser_objc_class_interface (cp_parser* parser, tree attributes)
 
   cp_lexer_consume_token (parser->lexer);  /* Eat '@interface'.  */
   name = cp_parser_identifier (parser);
+  if (name == error_mark_node)
+    {
+      /* It's hard to recover because even if valid @interface stuff
+        is to follow, we can't compile it (or validate it) if we
+        don't even know which class it refers to.  Let's assume this
+        was a stray '@interface' token in the stream and skip it.
+      */
+      return;
+    }
   cp_parser_objc_superclass_or_category (parser, &super, &categ);
   protos = cp_parser_objc_protocol_refs_opt (parser);
 
@@ -21947,6 +22498,16 @@ cp_parser_objc_class_implementation (cp_parser* parser)
 
   cp_lexer_consume_token (parser->lexer);  /* Eat '@implementation'.  */
   name = cp_parser_identifier (parser);
+  if (name == error_mark_node)
+    {
+      /* It's hard to recover because even if valid @implementation
+        stuff is to follow, we can't compile it (or validate it) if
+        we don't even know which class it refers to.  Let's assume
+        this was a stray '@implementation' token in the stream and
+        skip it.
+      */
+      return;
+    }
   cp_parser_objc_superclass_or_category (parser, &super, &categ);
 
   /* We have either a class or a category on our hands.  */
@@ -22181,6 +22742,384 @@ cp_parser_objc_valid_prefix_attributes (cp_parser* parser, tree *attrib)
   cp_lexer_rollback_tokens (parser->lexer);
   return false;  
 }
+
+/* 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
+
+   @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)
+{
+  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,
+                               &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 attributes, first_attribute, decl;
+      cp_declarator *declarator;
+      cp_token *token;
+
+      /* 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
+       break;
+    }
+  return decls;
+}
+
+/* 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_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;
+
+  loc = cp_lexer_peek_token (parser->lexer)->location;
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@property'.  */
+
+  /* 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)
+       {
+         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)
+           {
+           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))
+               {
+                 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
+                   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);
+               }
+             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;
+       }
+
+      if (!cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN))
+       {
+         cp_parser_skip_to_closing_parenthesis (parser,
+                                                /*recovering=*/true,
+                                                /*or_comma=*/false,
+                                                /*consume_paren=*/true);
+       }
+    }
+
+  /* ... and the property declaration(s).  */
+  properties = cp_parser_objc_struct_declaration (parser);
+
+  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;
+    }
+
+  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:
+
+   objc-synthesize-declaration:
+     @synthesize objc-synthesize-identifier-list ;
+
+   objc-synthesize-identifier-list:
+     objc-synthesize-identifier
+     objc-synthesize-identifier-list, objc-synthesize-identifier
+
+   objc-synthesize-identifier
+     identifier
+     identifier = identifier
+
+  For example:
+    @synthesize MyProperty;
+    @synthesize OneProperty, AnotherProperty=MyIvar, YetAnotherProperty;
+
+  PS: This function is identical to c_parser_objc_at_synthesize_declaration
+  for C.  Keep them in sync.
+*/
+static void 
+cp_parser_objc_at_synthesize_declaration (cp_parser *parser)
+{
+  tree list = NULL_TREE;
+  location_t loc;
+  loc = cp_lexer_peek_token (parser->lexer)->location;
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@synthesize'.  */
+  while (true)
+    {
+      tree property, ivar;
+      property = cp_parser_identifier (parser);
+      if (property == error_mark_node)
+       {
+         cp_parser_consume_semicolon_at_end_of_statement (parser);
+         return;
+       }
+      if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
+       {
+         cp_lexer_consume_token (parser->lexer);
+         ivar = cp_parser_identifier (parser);
+         if (ivar == error_mark_node)
+           {
+             cp_parser_consume_semicolon_at_end_of_statement (parser);
+             return;
+           }
+       }
+      else
+       ivar = NULL_TREE;
+      list = chainon (list, build_tree_list (ivar, property));
+      if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+       cp_lexer_consume_token (parser->lexer);
+      else
+       break;
+    }
+  cp_parser_consume_semicolon_at_end_of_statement (parser);
+  objc_add_synthesize_declaration (loc, list);
+}
+
+/* Parse an Objective-C++ @dynamic declaration.  The syntax is:
+
+   objc-dynamic-declaration:
+     @dynamic identifier-list ;
+
+   For example:
+     @dynamic MyProperty;
+     @dynamic MyProperty, AnotherProperty;
+
+  PS: This function is identical to c_parser_objc_at_dynamic_declaration
+  for C.  Keep them in sync.
+*/
+static void 
+cp_parser_objc_at_dynamic_declaration (cp_parser *parser)
+{
+  tree list = NULL_TREE;
+  location_t loc;
+  loc = cp_lexer_peek_token (parser->lexer)->location;
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@dynamic'.  */
+  while (true)
+    {
+      tree property;
+      property = cp_parser_identifier (parser);
+      if (property == error_mark_node)
+       {
+         cp_parser_consume_semicolon_at_end_of_statement (parser);
+         return;
+       }
+      list = chainon (list, build_tree_list (NULL, property));
+      if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+       cp_lexer_consume_token (parser->lexer);
+      else
+       break;
+    }
+  cp_parser_consume_semicolon_at_end_of_statement (parser);
+  objc_add_dynamic_declaration (loc, list);
+}
+
 \f
 /* OpenMP 2.5 parsing routines.  */