OSDN Git Service

Yet more Objective-C++...
[pf3gnuchains/gcc-fork.git] / gcc / cp / parser.c
index 5654f11..7b58840 100644 (file)
@@ -1,5 +1,6 @@
 /* C++ Parser.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004,
+   2005  Free Software Foundation, Inc.
    Written by Mark Mitchell <mark@codesourcery.com>.
 
    This file is part of GCC.
@@ -35,6 +36,7 @@
 #include "toplev.h"
 #include "output.h"
 #include "target.h"
+#include "c-common.h"
 
 \f
 /* The lexer.  */
@@ -65,7 +67,8 @@ typedef struct cp_token GTY (())
 
 /* We use a stack of token pointer for saving token sets.  */
 typedef struct cp_token *cp_token_position;
-DEF_VEC_MALLOC_P (cp_token_position);
+DEF_VEC_P (cp_token_position);
+DEF_VEC_ALLOC_P (cp_token_position,heap);
 
 static const cp_token eof_token =
 {
@@ -103,7 +106,7 @@ typedef struct cp_lexer GTY (())
      called.  The top entry is the most recent position at which we
      began saving tokens.  If the stack is non-empty, we are saving
      tokens.  */
-  VEC (cp_token_position) *GTY ((skip)) saved_tokens;
+  VEC(cp_token_position,heap) *GTY ((skip)) saved_tokens;
 
   /* True if we should output debugging information.  */
   bool debugging_p;
@@ -237,16 +240,19 @@ cp_lexer_new_main (void)
   size_t space;
   cp_token *buffer;
 
+  /* It's possible that lexing the first token will load a PCH file,
+     which is a GC collection point.  So we have to grab the first
+     token before allocating any memory.  Pragmas must not be deferred
+     as -fpch-preprocess can generate a pragma to load the PCH file in
+     the preprocessed output used by -save-temps.  */
+  cp_lexer_get_preprocessor_token (NULL, &first_token);
+
   /* Tell cpplib we want CPP_PRAGMA tokens.  */
   cpp_get_options (parse_in)->defer_pragmas = true;
 
   /* Tell c_lex not to merge string constants.  */
   c_lex_return_raw_strings = true;
 
-  /* It's possible that lexing the first token will load a PCH file,
-     which is a GC collection point.  So we have to grab the first
-     token before allocating any memory.  */
-  cp_lexer_get_preprocessor_token (NULL, &first_token);
   c_common_no_more_pch ();
 
   /* Allocate the memory.  */
@@ -256,7 +262,8 @@ cp_lexer_new_main (void)
   /* Initially we are not debugging.  */
   lexer->debugging_p = false;
 #endif /* ENABLE_CHECKING */
-  lexer->saved_tokens = VEC_alloc (cp_token_position, CP_SAVED_TOKEN_STACK);
+  lexer->saved_tokens = VEC_alloc (cp_token_position, heap,
+                                  CP_SAVED_TOKEN_STACK);
         
   /* Create the buffer.  */
   alloc = CP_LEXER_BUFFER_SIZE;
@@ -310,7 +317,8 @@ cp_lexer_new_from_tokens (cp_token_cache *cache)
   lexer->next_token = first == last ? (cp_token *)&eof_token : first;
   lexer->last_token = last;
   
-  lexer->saved_tokens = VEC_alloc (cp_token_position, CP_SAVED_TOKEN_STACK);
+  lexer->saved_tokens = VEC_alloc (cp_token_position, heap,
+                                  CP_SAVED_TOKEN_STACK);
 
 #ifdef ENABLE_CHECKING
   /* Initially we are not debugging.  */
@@ -328,7 +336,7 @@ cp_lexer_destroy (cp_lexer *lexer)
 {
   if (lexer->buffer)
     ggc_free (lexer->buffer);
-  VEC_free (cp_token_position, lexer->saved_tokens);
+  VEC_free (cp_token_position, heap, lexer->saved_tokens);
   ggc_free (lexer);
 }
 
@@ -376,8 +384,8 @@ cp_lexer_get_preprocessor_token (cp_lexer *lexer ATTRIBUTE_UNUSED ,
   static int is_extern_c = 0;
 
    /* Get a new token from the preprocessor.  */
-  token->type = c_lex_with_flags (&token->value, &token->flags);
-  token->location = input_location;
+  token->type
+    = c_lex_with_flags (&token->value, &token->location, &token->flags);
   token->in_system_header = in_system_header;
 
   /* On some systems, some header files are surrounded by an 
@@ -401,6 +409,23 @@ cp_lexer_get_preprocessor_token (cp_lexer *lexer ATTRIBUTE_UNUSED ,
         mapped to `const'.  */
       token->value = ridpointers[token->keyword];
     }
+  /* Handle Objective-C++ keywords.  */
+  else if (token->type == CPP_AT_NAME)
+    {
+      token->type = CPP_KEYWORD;
+      switch (C_RID_CODE (token->value))
+       {
+       /* Map 'class' to '@class', 'private' to '@private', etc.  */
+       case RID_CLASS: token->keyword = RID_AT_CLASS; break;
+       case RID_PRIVATE: token->keyword = RID_AT_PRIVATE; break;
+       case RID_PROTECTED: token->keyword = RID_AT_PROTECTED; break;
+       case RID_PUBLIC: token->keyword = RID_AT_PUBLIC; break;
+       case RID_THROW: token->keyword = RID_AT_THROW; break;
+       case RID_TRY: token->keyword = RID_AT_TRY; break;
+       case RID_CATCH: token->keyword = RID_AT_CATCH; break;
+       default: token->keyword = C_RID_CODE (token->value);
+       }
+    }
   else
     token->keyword = RID_MAX;
 }
@@ -617,7 +642,8 @@ cp_lexer_save_tokens (cp_lexer* lexer)
   if (cp_lexer_debugging_p (lexer))
     fprintf (cp_lexer_debug_stream, "cp_lexer: saving tokens\n");
 
-  VEC_safe_push (cp_token_position, lexer->saved_tokens, lexer->next_token);
+  VEC_safe_push (cp_token_position, heap,
+                lexer->saved_tokens, lexer->next_token);
 }
 
 /* Commit to the portion of the token stream most recently saved.  */
@@ -702,7 +728,7 @@ cp_lexer_print_token (FILE * stream, cp_token *token)
 static void
 cp_lexer_start_debugging (cp_lexer* lexer)
 {
-  ++lexer->debugging_p;
+  lexer->debugging_p = true;
 }
 
 /* Stop emitting debugging information.  */
@@ -710,7 +736,7 @@ cp_lexer_start_debugging (cp_lexer* lexer)
 static void
 cp_lexer_stop_debugging (cp_lexer* lexer)
 {
-  --lexer->debugging_p;
+  lexer->debugging_p = false;
 }
 
 #endif /* ENABLE_CHECKING */
@@ -747,8 +773,6 @@ clear_decl_specs (cp_decl_specifier_seq *decl_specs)
    Other parts of the front end that need to create entities (like
    VAR_DECLs or FUNCTION_DECLs) should do that directly.  */
 
-static cp_declarator *make_id_declarator
-  (tree);
 static cp_declarator *make_call_declarator
   (cp_declarator *, cp_parameter_declarator *, cp_cv_quals, tree);
 static cp_declarator *make_array_declarator
@@ -792,15 +816,31 @@ make_declarator (cp_declarator_kind kind)
   return declarator;
 }
 
-/* Make a declarator for a generalized identifier.  */
+/* Make a declarator for a generalized identifier.  If non-NULL, the
+   identifier is QUALIFYING_SCOPE::UNQUALIFIED_NAME; otherwise, it is
+   just UNQUALIFIED_NAME.  */
 
-cp_declarator *
-make_id_declarator (tree id)
+static cp_declarator *
+make_id_declarator (tree qualifying_scope, tree unqualified_name)
 {
   cp_declarator *declarator;
 
+  /* It is valid to write:
+
+       class C { void f(); };
+       typedef C D;
+       void D::f();
+
+     The standard is not clear about whether `typedef const C D' is
+     legal; as of 2002-09-15 the committee is considering that
+     question.  EDG 3.0 allows that syntax.  Therefore, we do as
+     well.  */
+  if (qualifying_scope && TYPE_P (qualifying_scope))
+    qualifying_scope = TYPE_MAIN_VARIANT (qualifying_scope);
+
   declarator = make_declarator (cdk_id);
-  declarator->u.id.name = id;
+  declarator->u.id.qualifying_scope = qualifying_scope;
+  declarator->u.id.unqualified_name = unqualified_name;
   declarator->u.id.sfk = sfk_none;
 
   return declarator;
@@ -1339,7 +1379,7 @@ static bool cp_parser_translation_unit
 /* Expressions [gram.expr]  */
 
 static tree cp_parser_primary_expression
-  (cp_parser *, cp_id_kind *, tree *);
+  (cp_parser *, bool, cp_id_kind *, tree *);
 static tree cp_parser_id_expression
   (cp_parser *, bool, bool, bool *, bool);
 static tree cp_parser_unqualified_id
@@ -1351,17 +1391,17 @@ static tree cp_parser_nested_name_specifier
 static tree cp_parser_class_or_namespace_name
   (cp_parser *, bool, bool, bool, bool, bool);
 static tree cp_parser_postfix_expression
-  (cp_parser *, bool);
+  (cp_parser *, bool, bool);
 static tree cp_parser_postfix_open_square_expression
   (cp_parser *, tree, bool);
 static tree cp_parser_postfix_dot_deref_expression
   (cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *);
 static tree cp_parser_parenthesized_expression_list
-  (cp_parser *, bool, bool *);
+  (cp_parser *, bool, bool, bool *);
 static void cp_parser_pseudo_destructor_name
   (cp_parser *, tree *, tree *);
 static tree cp_parser_unary_expression
-  (cp_parser *, bool);
+  (cp_parser *, bool, bool);
 static enum tree_code cp_parser_unary_operator
   (cp_token *);
 static tree cp_parser_new_expression
@@ -1379,17 +1419,17 @@ static tree cp_parser_new_initializer
 static tree cp_parser_delete_expression
   (cp_parser *);
 static tree cp_parser_cast_expression
-  (cp_parser *, bool);
+  (cp_parser *, bool, bool);
 static tree cp_parser_binary_expression
-  (cp_parser *);
+  (cp_parser *, bool);
 static tree cp_parser_question_colon_clause
   (cp_parser *, tree);
 static tree cp_parser_assignment_expression
-  (cp_parser *);
+  (cp_parser *, bool);
 static enum tree_code cp_parser_assignment_operator_opt
   (cp_parser *);
 static tree cp_parser_expression
-  (cp_parser *);
+  (cp_parser *, bool);
 static tree cp_parser_constant_expression
   (cp_parser *, bool, bool *);
 static tree cp_parser_builtin_offsetof
@@ -1492,7 +1532,7 @@ static tree cp_parser_declarator_id
 static tree cp_parser_type_id
   (cp_parser *);
 static void cp_parser_type_specifier_seq
-  (cp_parser *, cp_decl_specifier_seq *);
+  (cp_parser *, bool, cp_decl_specifier_seq *);
 static cp_parameter_declarator *cp_parser_parameter_declaration_clause
   (cp_parser *);
 static cp_parameter_declarator *cp_parser_parameter_declaration_list
@@ -1620,6 +1660,35 @@ static bool cp_parser_extension_opt
 static void cp_parser_label_declaration
   (cp_parser *);
 
+/* Objective-C++ Productions */
+
+static tree cp_parser_objc_message_receiver
+  (cp_parser *);
+static tree cp_parser_objc_message_args
+  (cp_parser *);
+static tree cp_parser_objc_message_expression
+  (cp_parser *);
+static tree cp_parser_objc_encode_expression
+  (cp_parser *);
+static tree cp_parser_objc_defs_expression 
+  (cp_parser *);
+static tree cp_parser_objc_protocol_expression
+  (cp_parser *);
+static tree cp_parser_objc_selector_expression
+  (cp_parser *);
+static tree cp_parser_objc_expression
+  (cp_parser *);
+static bool cp_parser_objc_selector_p
+  (enum cpp_ttype);
+static tree cp_parser_objc_selector
+  (cp_parser *);
+static tree cp_parser_objc_protocol_refs_opt
+  (cp_parser *);
+static void cp_parser_objc_declaration
+  (cp_parser *);
+static tree cp_parser_objc_statement
+  (cp_parser *);
+
 /* Utility Routines */
 
 static tree cp_parser_lookup_name
@@ -1769,6 +1838,16 @@ cp_parser_is_keyword (cp_token* token, enum rid keyword)
   return token->keyword == keyword;
 }
 
+/* A minimum or maximum operator has been seen.  As these are
+   deprecated, issue a warning.  */
+
+static inline void
+cp_parser_warn_min_max (void)
+{
+  if (warn_deprecated && !in_system_header)
+    warning (0, "minimum/maximum operators are deprecated");
+}
+
 /* If not parsing tentatively, issue a diagnostic of the form
       FILE:LINE: MESSAGE before TOKEN
    where TOKEN is the next token in the input stream.  MESSAGE
@@ -1784,6 +1863,12 @@ cp_parser_error (cp_parser* parser, const char* message)
       /* This diagnostic makes more sense if it is tagged to the line
         of the token we just peeked at.  */
       cp_lexer_set_source_position_from_token (token);
+      if (token->type == CPP_PRAGMA)
+       {
+         error ("%<#pragma%> is not allowed here"); 
+         cp_lexer_purge_token (parser->lexer);
+         return;
+       }
       c_parse_error (message,
                     /* Because c_parser_error does not understand
                        CPP_KEYWORD, keywords are treated like
@@ -1921,12 +2006,14 @@ cp_parser_check_for_invalid_template_id (cp_parser* parser,
 
 /* If parsing an integral constant-expression, issue an error message
    about the fact that THING appeared and return true.  Otherwise,
-   return false, marking the current expression as non-constant.  */
+   return false.  In either case, set
+   PARSER->NON_INTEGRAL_CONSTANT_EXPRESSION_P.  */ 
 
 static bool
 cp_parser_non_integral_constant_expression (cp_parser  *parser,
                                            const char *thing)
 {
+  parser->non_integral_constant_expression_p = true;
   if (parser->integral_constant_expression_p)
     {
       if (!parser->allow_non_integral_constant_expression_p)
@@ -1934,13 +2021,15 @@ cp_parser_non_integral_constant_expression (cp_parser  *parser,
          error ("%s cannot appear in a constant-expression", thing);
          return true;
        }
-      parser->non_integral_constant_expression_p = true;
     }
   return false;
 }
 
 /* Emit a diagnostic for an invalid type name.  SCOPE is the
-   qualifying scope (or NULL, if none) for ID.  */
+   qualifying scope (or NULL, if none) for ID.  This function commits
+   to the current active tentative parse, if any.  (Otherwise, the
+   problematic construct might be encountered again later, resulting
+   in duplicate error messages.)  */
 
 static void
 cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree scope, tree id)
@@ -1967,7 +2056,8 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree scope, tree id)
           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)
+      if (processing_template_decl && current_class_type
+         && TYPE_BINFO (current_class_type))
        {
          tree b;
 
@@ -2012,6 +2102,7 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree scope, tree id)
       else
        gcc_unreachable ();
     }
+  cp_parser_commit_to_tentative_parse (parser);
 }
 
 /* Check for a common situation where a type-name should be present,
@@ -2608,9 +2699,16 @@ cp_parser_translation_unit (cp_parser* parser)
      ( compound-statement )
      __builtin_va_arg ( assignment-expression , type-id )
 
+   Objective-C++ Extension:
+
+   primary-expression:
+     objc-expression
+
    literal:
      __null
 
+   CAST_P is true if this primary expression is the target of a cast.
+
    Returns a representation of the expression.
 
    *IDK indicates what kind of id-expression (if any) was present.
@@ -2622,6 +2720,7 @@ cp_parser_translation_unit (cp_parser* parser)
 
 static tree
 cp_parser_primary_expression (cp_parser *parser,
+                             bool cast_p,
                              cp_id_kind *idk,
                              tree *qualifying_class)
 {
@@ -2646,6 +2745,43 @@ cp_parser_primary_expression (cp_parser *parser,
     case CPP_WCHAR:
     case CPP_NUMBER:
       token = cp_lexer_consume_token (parser->lexer);
+      /* Floating-point literals are only allowed in an integral
+        constant expression if they are cast to an integral or
+        enumeration type.  */
+      if (TREE_CODE (token->value) == REAL_CST
+         && parser->integral_constant_expression_p
+         && pedantic)
+       {
+         /* CAST_P will be set even in invalid code like "int(2.7 +
+            ...)".   Therefore, we have to check that the next token
+            is sure to end the cast.  */
+         if (cast_p)
+           {
+             cp_token *next_token;
+
+             next_token = cp_lexer_peek_token (parser->lexer);
+             if (/* The comma at the end of an
+                    enumerator-definition.  */
+                 next_token->type != CPP_COMMA
+                 /* The curly brace at the end of an enum-specifier.  */
+                 && next_token->type != CPP_CLOSE_BRACE
+                 /* The end of a statement.  */
+                 && next_token->type != CPP_SEMICOLON
+                 /* The end of the cast-expression.  */
+                 && next_token->type != CPP_CLOSE_PAREN
+                 /* The end of an array bound.  */
+                 && next_token->type != CPP_CLOSE_SQUARE)
+               cast_p = false;
+           }
+
+         /* If we are within a cast, then the constraint that the
+            cast is to an integral or enumeration type will be
+            checked at that point.  If we are not within a cast, then
+            this code is invalid.  */
+         if (!cast_p)
+           cp_parser_non_integral_constant_expression 
+             (parser, "floating-point literal");
+       }
       return token->value;
 
     case CPP_STRING:
@@ -2696,7 +2832,7 @@ cp_parser_primary_expression (cp_parser *parser,
        else
          {
            /* Parse the parenthesized expression.  */
-           expr = cp_parser_expression (parser);
+           expr = cp_parser_expression (parser, cast_p);
            /* Let the front end know that this expression was
               enclosed in parentheses. This matters in case, for
               example, the expression is of the form `A::B', since
@@ -2775,7 +2911,8 @@ cp_parser_primary_expression (cp_parser *parser,
            /* Look for the opening `('.  */
            cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
            /* Now, parse the assignment-expression.  */
-           expression = cp_parser_assignment_expression (parser);
+           expression = cp_parser_assignment_expression (parser,
+                                                         /*cast_p=*/false);
            /* Look for the `,'.  */
            cp_parser_require (parser, CPP_COMMA, "`,'");
            /* Parse the type-id.  */
@@ -2793,6 +2930,12 @@ cp_parser_primary_expression (cp_parser *parser,
        case RID_OFFSETOF:
          return cp_parser_builtin_offsetof (parser);
 
+         /* Objective-C++ expressions.  */
+       case RID_AT_ENCODE:
+       case RID_AT_PROTOCOL:
+       case RID_AT_SELECTOR:
+         return cp_parser_objc_expression (parser);
+
        default:
          cp_parser_error (parser, "expected primary-expression");
          return error_mark_node;
@@ -2841,6 +2984,11 @@ cp_parser_primary_expression (cp_parser *parser,
               been issued.  */
            if (ambiguous_p)
              return error_mark_node;
+
+           /* In Objective-C++, an instance variable (ivar) may be preferred
+              to whatever cp_parser_lookup_name() found.  */
+           decl = objc_lookup_ivar (decl, id_expression);
+
            /* If name lookup gives us a SCOPE_REF, then the
               qualifying scope was dependent.  Just propagate the
               name.  */
@@ -2891,6 +3039,11 @@ cp_parser_primary_expression (cp_parser *parser,
 
       /* Anything else is an error.  */
     default:
+      /* ...unless we have an Objective-C++ message or string literal, that is.  */
+      if (c_dialect_objc () 
+         && (token->type == CPP_OPEN_SQUARE || token->type == CPP_OBJC_STRING))
+       return cp_parser_objc_expression (parser);
+
       cp_parser_error (parser, "expected primary-expression");
       return error_mark_node;
     }
@@ -3103,6 +3256,7 @@ cp_parser_unqualified_id (cp_parser* parser,
        tree qualifying_scope;
        tree object_scope;
        tree scope;
+       bool done;
 
        /* Consume the `~' token.  */
        cp_lexer_consume_token (parser->lexer);
@@ -3159,6 +3313,8 @@ cp_parser_unqualified_id (cp_parser* parser,
 
        /* If there was an explicit qualification (S::~T), first look
           in the scope given by the qualification (i.e., S).  */
+       done = false;
+       type_decl = NULL_TREE;
        if (scope)
          {
            cp_parser_parse_tentatively (parser);
@@ -3170,10 +3326,10 @@ cp_parser_unqualified_id (cp_parser* parser,
                                              /*class_head_p=*/false,
                                              declarator_p);
            if (cp_parser_parse_definitely (parser))
-             return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+             done = true;
          }
        /* In "N::S::~S", look in "N" as well.  */
-       if (scope && qualifying_scope)
+       if (!done && scope && qualifying_scope)
          {
            cp_parser_parse_tentatively (parser);
            parser->scope = qualifying_scope;
@@ -3188,10 +3344,10 @@ cp_parser_unqualified_id (cp_parser* parser,
                                      /*class_head_p=*/false,
                                      declarator_p);
            if (cp_parser_parse_definitely (parser))
-             return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+             done = true;
          }
        /* In "p->S::~T", look in the scope given by "*p" as well.  */
-       else if (object_scope)
+       else if (!done && object_scope)
          {
            cp_parser_parse_tentatively (parser);
            parser->scope = object_scope;
@@ -3206,20 +3362,23 @@ cp_parser_unqualified_id (cp_parser* parser,
                                      /*class_head_p=*/false,
                                      declarator_p);
            if (cp_parser_parse_definitely (parser))
-             return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+             done = true;
          }
        /* Look in the surrounding context.  */
-       parser->scope = NULL_TREE;
-       parser->object_scope = NULL_TREE;
-       parser->qualifying_scope = NULL_TREE;
-       type_decl
-         = cp_parser_class_name (parser,
-                                 /*typename_keyword_p=*/false,
-                                 /*template_keyword_p=*/false,
-                                 none_type,
-                                 /*check_dependency=*/false,
-                                 /*class_head_p=*/false,
-                                 declarator_p);
+       if (!done)
+         {
+           parser->scope = NULL_TREE;
+           parser->object_scope = NULL_TREE;
+           parser->qualifying_scope = NULL_TREE;
+           type_decl
+             = cp_parser_class_name (parser,
+                                     /*typename_keyword_p=*/false,
+                                     /*template_keyword_p=*/false,
+                                     none_type,
+                                     /*check_dependency=*/false,
+                                     /*class_head_p=*/false,
+                                     declarator_p);
+         }
        /* If an error occurred, assume that the name of the
           destructor is the same as the name of the qualifying
           class.  That allows us to keep parsing after running
@@ -3235,7 +3394,8 @@ cp_parser_unqualified_id (cp_parser* parser,
           identifier in the declarator for a destructor declaration.  */
        if (declarator_p
            && !DECL_IMPLICIT_TYPEDEF_P (type_decl)
-           && !DECL_SELF_REFERENCE_P (type_decl))
+           && !DECL_SELF_REFERENCE_P (type_decl)
+           && !cp_parser_uncommitted_to_tentative_parse_p (parser))
          error ("typedef-name %qD used as destructor declarator",
                 type_decl);
 
@@ -3637,12 +3797,13 @@ cp_parser_class_or_namespace_name (cp_parser *parser,
    but they are essentially the same concept.)
 
    If ADDRESS_P is true, the postfix expression is the operand of the
-   `&' operator.
+   `&' operator.  CAST_P is true if this expression is the target of a
+   cast. 
 
    Returns a representation of the expression.  */
 
 static tree
-cp_parser_postfix_expression (cp_parser *parser, bool address_p)
+cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
 {
   cp_token *token;
   enum rid keyword;
@@ -3689,7 +3850,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
 
        /* And the expression which is being cast.  */
        cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
-       expression = cp_parser_expression (parser);
+       expression = cp_parser_expression (parser, /*cast_p=*/true);
        cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
 
        /* Only type conversions to integral or enumeration types
@@ -3762,7 +3923,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
            tree expression;
 
            /* Look for an expression.  */
-           expression = cp_parser_expression (parser);
+           expression = cp_parser_expression (parser, /*cast_p=*/false);
            /* Compute its typeid.  */
            postfix_expression = build_typeid (expression);
            /* Look for the `)' token.  */
@@ -3782,18 +3943,22 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
        bool template_p = false;
        tree id;
        tree type;
+       tree scope;
 
        /* Consume the `typename' token.  */
        cp_lexer_consume_token (parser->lexer);
        /* Look for the optional `::' operator.  */
        cp_parser_global_scope_opt (parser,
                                    /*current_scope_valid_p=*/false);
-       /* Look for the nested-name-specifier.  */
-       cp_parser_nested_name_specifier (parser,
-                                        /*typename_keyword_p=*/true,
-                                        /*check_dependency_p=*/true,
-                                        /*type_p=*/true,
-                                        /*is_declaration=*/true);
+       /* Look for the nested-name-specifier.  In case of error here,
+          consume the trailing id to avoid subsequent error messages
+          for usual cases.  */
+       scope = cp_parser_nested_name_specifier (parser,
+                                                /*typename_keyword_p=*/true,
+                                                /*check_dependency_p=*/true,
+                                                /*type_p=*/true,
+                                                /*is_declaration=*/true);
+
        /* Look for the optional `template' keyword.  */
        template_p = cp_parser_optional_template_keyword (parser);
        /* We don't know whether we're looking at a template-id or an
@@ -3806,9 +3971,13 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
        /* If that didn't work, try an identifier.  */
        if (!cp_parser_parse_definitely (parser))
          id = cp_parser_identifier (parser);
+
+       /* Don't process id if nested name specifier is invalid.  */
+       if (scope == error_mark_node)
+         return error_mark_node;
        /* If we look up a template-id in a non-dependent qualifying
           scope, there's no need to create a dependent type.  */
-       if (TREE_CODE (id) == TYPE_DECL
+       else if (TREE_CODE (id) == TYPE_DECL
            && !dependent_type_p (parser->scope))
          type = TREE_TYPE (id);
        /* Create a TYPENAME_TYPE to represent the type to which the
@@ -3894,6 +4063,7 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
 
        /* It must be a primary-expression.  */
        postfix_expression = cp_parser_primary_expression (parser,
+                                                          cast_p,
                                                           &idk,
                                                           &qualifying_class);
       }
@@ -3952,7 +4122,9 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
          {
            bool koenig_p;
            tree args = (cp_parser_parenthesized_expression_list
-                        (parser, false, /*non_constant_p=*/NULL));
+                        (parser, false, 
+                         /*cast_p=*/false,
+                         /*non_constant_p=*/NULL));
 
            if (args == error_mark_node)
              {
@@ -3962,8 +4134,9 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
 
            /* Function calls are not permitted in
               constant-expressions.  */
-           if (cp_parser_non_integral_constant_expression (parser,
-                                                           "a function call"))
+           if (! builtin_valid_in_constant_expr_p (postfix_expression)
+               && cp_parser_non_integral_constant_expression (parser,
+                                                              "a function call"))
              {
                postfix_expression = error_mark_node;
                break;
@@ -4145,7 +4318,7 @@ cp_parser_postfix_open_square_expression (cp_parser *parser,
   if (for_offsetof)
     index = cp_parser_constant_expression (parser, false, NULL);
   else
-    index = cp_parser_expression (parser);
+    index = cp_parser_expression (parser, /*cast_p=*/false);
 
   /* Look for the closing `]'.  */
   cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
@@ -4325,6 +4498,8 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
      identifier
      identifier, expression-list
 
+   CAST_P is true if this expression is the target of a cast.
+
    Returns a TREE_LIST.  The TREE_VALUE of each node is a
    representation of an assignment-expression.  Note that a TREE_LIST
    is returned even if there is only a single expression in the list.
@@ -4338,6 +4513,7 @@ cp_parser_postfix_dot_deref_expression (cp_parser *parser,
 static tree
 cp_parser_parenthesized_expression_list (cp_parser* parser,
                                         bool is_attribute_list,
+                                        bool cast_p,
                                         bool *non_constant_p)
 {
   tree expression_list = NULL_TREE;
@@ -4382,7 +4558,7 @@ cp_parser_parenthesized_expression_list (cp_parser* parser,
                  *non_constant_p = true;
              }
            else
-             expr = cp_parser_assignment_expression (parser);
+             expr = cp_parser_assignment_expression (parser, cast_p);
 
            if (fold_expr_p)
              expr = fold_non_dependent_expr (expr);
@@ -4540,12 +4716,13 @@ cp_parser_pseudo_destructor_name (cp_parser* parser,
      && identifier
 
    ADDRESS_P is true iff the unary-expression is appearing as the
-   operand of the `&' operator.
+   operand of the `&' operator.   CAST_P is true if this expression is
+   the target of a cast.
 
    Returns a representation of the expression.  */
 
 static tree
-cp_parser_unary_expression (cp_parser *parser, bool address_p)
+cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p)
 {
   cp_token *token;
   enum tree_code unary_operator;
@@ -4673,7 +4850,9 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p)
       token = cp_lexer_consume_token (parser->lexer);
       /* Parse the cast-expression.  */
       cast_expression
-       = cp_parser_cast_expression (parser, unary_operator == ADDR_EXPR);
+       = cp_parser_cast_expression (parser, 
+                                    unary_operator == ADDR_EXPR,
+                                    /*cast_p=*/false);
       /* Now, build an appropriate representation.  */
       switch (unary_operator)
        {
@@ -4712,7 +4891,7 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p)
       return expression;
     }
 
-  return cp_parser_postfix_expression (parser, address_p);
+  return cp_parser_postfix_expression (parser, address_p, cast_p);
 }
 
 /* Returns ERROR_MARK if TOKEN is not a unary-operator.  If TOKEN is a
@@ -4833,7 +5012,8 @@ cp_parser_new_placement (cp_parser* parser)
 
   /* Parse the expression-list.  */
   expression_list = (cp_parser_parenthesized_expression_list
-                    (parser, false, /*non_constant_p=*/NULL));
+                    (parser, false, /*cast_p=*/false,
+                     /*non_constant_p=*/NULL));
 
   return expression_list;
 }
@@ -4865,7 +5045,8 @@ cp_parser_new_type_id (cp_parser* parser, tree *nelts)
   parser->type_definition_forbidden_message
     = "types may not be defined in a new-type-id";
   /* Parse the type-specifier-seq.  */
-  cp_parser_type_specifier_seq (parser, &type_specifier_seq);
+  cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
+                               &type_specifier_seq);
   /* Restore the old message.  */
   parser->type_definition_forbidden_message = saved_message;
   /* Parse the new-declarator.  */
@@ -4980,7 +5161,7 @@ cp_parser_direct_new_declarator (cp_parser* parser)
       /* The first expression is not required to be constant.  */
       if (!declarator)
        {
-         expression = cp_parser_expression (parser);
+         expression = cp_parser_expression (parser, /*cast_p=*/false);
          /* The standard requires that the expression have integral
             type.  DR 74 adds enumeration types.  We believe that the
             real intent is that these expressions be handled like the
@@ -5036,7 +5217,8 @@ cp_parser_new_initializer (cp_parser* parser)
   tree expression_list;
 
   expression_list = (cp_parser_parenthesized_expression_list
-                    (parser, false, /*non_constant_p=*/NULL));
+                    (parser, false, /*cast_p=*/false,
+                     /*non_constant_p=*/NULL));
   if (!expression_list)
     expression_list = void_zero_node;
 
@@ -5095,10 +5277,14 @@ cp_parser_delete_expression (cp_parser* parser)
      unary-expression
      ( type-id ) cast-expression
 
+   ADDRESS_P is true iff the unary-expression is appearing as the
+   operand of the `&' operator.   CAST_P is true if this expression is
+   the target of a cast.
+
    Returns a representation of the expression.  */
 
 static tree
-cp_parser_cast_expression (cp_parser *parser, bool address_p)
+cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p)
 {
   /* If it's a `(', then we might be looking at a cast.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
@@ -5168,7 +5354,9 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p)
          ctor of T, but looks like a cast to function returning T
          without a dependent expression.  */
       if (!cp_parser_error_occurred (parser))
-       expr = cp_parser_simple_cast_expression (parser);
+       expr = cp_parser_cast_expression (parser, 
+                                         /*address_p=*/false,
+                                         /*cast_p=*/true);
 
       if (cp_parser_parse_definitely (parser))
        {
@@ -5177,7 +5365,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p)
              && !in_system_header
              && !VOID_TYPE_P (type)
              && current_lang_name != lang_name_c)
-           warning ("use of old-style cast");
+           warning (0, "use of old-style cast");
 
          /* Only type conversions to integral or enumeration types
             can be used in constant-expressions.  */
@@ -5198,7 +5386,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p)
 
   /* If we get here, then it's not a cast, so it must be a
      unary-expression.  */
-  return cp_parser_unary_expression (parser, address_p);
+  return cp_parser_unary_expression (parser, address_p, cast_p);
 }
 
 /* Parse a binary expression of the general form:
@@ -5268,6 +5456,8 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p)
      simple-cast-expression
      binary-expression <token> binary-expression
 
+   CAST_P is true if this expression is the target of a cast.
+
    The binops_by_token map is used to get the tree codes for each <token> type.
    binary-expressions are associated according to a precedence table.  */
 
@@ -5277,7 +5467,7 @@ cp_parser_cast_expression (cp_parser *parser, bool address_p)
    : binops_by_token[token->type].prec)
 
 static tree
-cp_parser_binary_expression (cp_parser* parser)
+cp_parser_binary_expression (cp_parser* parser, bool cast_p)
 {
   cp_parser_expression_stack stack;
   cp_parser_expression_stack_entry *sp = &stack[0];
@@ -5288,12 +5478,15 @@ cp_parser_binary_expression (cp_parser* parser)
   bool overloaded_p;
 
   /* Parse the first expression.  */
-  lhs = cp_parser_simple_cast_expression (parser);
+  lhs = cp_parser_cast_expression (parser, /*address_p=*/false, cast_p);
 
   for (;;)
     {
       /* Get an operator token.  */
       token = cp_lexer_peek_token (parser->lexer);
+      if (token->type == CPP_MIN || token->type == CPP_MAX)
+       cp_parser_warn_min_max ();
+
       new_prec = TOKEN_PRECEDENCE (token);
 
       /* Popping an entry off the stack means we completed a subexpression:
@@ -5402,12 +5595,12 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
     expr = NULL_TREE;
   else
     /* Parse the expression.  */
-    expr = cp_parser_expression (parser);
+    expr = cp_parser_expression (parser, /*cast_p=*/false);
 
   /* The next token should be a `:'.  */
   cp_parser_require (parser, CPP_COLON, "`:'");
   /* Parse the assignment-expression.  */
-  assignment_expr = cp_parser_assignment_expression (parser);
+  assignment_expr = cp_parser_assignment_expression (parser, /*cast_p=*/false);
 
   /* Build the conditional-expression.  */
   return build_x_conditional_expr (logical_or_expr,
@@ -5422,10 +5615,12 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
      logical-or-expression assignment-operator assignment_expression
      throw-expression
 
+   CAST_P is true if this expression is the target of a cast.
+
    Returns a representation for the expression.  */
 
 static tree
-cp_parser_assignment_expression (cp_parser* parser)
+cp_parser_assignment_expression (cp_parser* parser, bool cast_p)
 {
   tree expr;
 
@@ -5438,7 +5633,7 @@ cp_parser_assignment_expression (cp_parser* parser)
   else
     {
       /* Parse the binary expressions (logical-or-expression).  */
-      expr = cp_parser_binary_expression (parser);
+      expr = cp_parser_binary_expression (parser, cast_p);
       /* If the next token is a `?' then we're actually looking at a
         conditional-expression.  */
       if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
@@ -5456,7 +5651,7 @@ cp_parser_assignment_expression (cp_parser* parser)
              tree rhs;
 
              /* Parse the right-hand side of the assignment.  */
-             rhs = cp_parser_assignment_expression (parser);
+             rhs = cp_parser_assignment_expression (parser, cast_p);
              /* An assignment may not appear in a
                 constant-expression.  */
              if (cp_parser_non_integral_constant_expression (parser,
@@ -5547,10 +5742,12 @@ cp_parser_assignment_operator_opt (cp_parser* parser)
 
     case CPP_MIN_EQ:
       op = MIN_EXPR;
+      cp_parser_warn_min_max ();
       break;
 
     case CPP_MAX_EQ:
       op = MAX_EXPR;
+      cp_parser_warn_min_max ();
       break;
 
     default:
@@ -5571,10 +5768,12 @@ cp_parser_assignment_operator_opt (cp_parser* parser)
      assignment-expression
      expression , assignment-expression
 
+   CAST_P is true if this expression is the target of a cast.
+
    Returns a representation of the expression.  */
 
 static tree
-cp_parser_expression (cp_parser* parser)
+cp_parser_expression (cp_parser* parser, bool cast_p)
 {
   tree expression = NULL_TREE;
 
@@ -5584,7 +5783,7 @@ cp_parser_expression (cp_parser* parser)
 
       /* Parse the next assignment-expression.  */
       assignment_expression
-       = cp_parser_assignment_expression (parser);
+       = cp_parser_assignment_expression (parser, cast_p);
       /* If this is the first assignment-expression, we can just
         save it away.  */
       if (!expression)
@@ -5662,14 +5861,18 @@ cp_parser_constant_expression (cp_parser* parser,
      For example, cp_parser_initializer_clauses uses this function to
      determine whether a particular assignment-expression is in fact
      constant.  */
-  expression = cp_parser_assignment_expression (parser);
+  expression = cp_parser_assignment_expression (parser, /*cast_p=*/false);
   /* Restore the old settings.  */
-  parser->integral_constant_expression_p = saved_integral_constant_expression_p;
+  parser->integral_constant_expression_p 
+    = saved_integral_constant_expression_p;
   parser->allow_non_integral_constant_expression_p
     = saved_allow_non_integral_constant_expression_p;
   if (allow_non_constant_p)
     *non_constant_p = parser->non_integral_constant_expression_p;
-  parser->non_integral_constant_expression_p = saved_non_integral_constant_expression_p;
+  else if (parser->non_integral_constant_expression_p)
+    expression = error_mark_node;
+  parser->non_integral_constant_expression_p 
+    = saved_non_integral_constant_expression_p;
 
   return expression;
 }
@@ -5819,6 +6022,15 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr)
          statement = cp_parser_jump_statement (parser);
          break;
 
+         /* Objective-C++ exception-handling constructs.  */
+       case RID_AT_TRY:
+       case RID_AT_CATCH:
+       case RID_AT_FINALLY:
+       case RID_AT_SYNCHRONIZED:
+       case RID_AT_THROW:
+         statement = cp_parser_objc_statement (parser);
+         break;
+
        case RID_TRY:
          statement = cp_parser_try_block (parser);
          break;
@@ -5980,18 +6192,16 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
   /* If the next token is a ';', then there is no expression
      statement.  */
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
-    statement = cp_parser_expression (parser);
+    statement = cp_parser_expression (parser, /*cast_p=*/false);
 
   /* Consume the final `;'.  */
   cp_parser_consume_semicolon_at_end_of_statement (parser);
 
   if (in_statement_expr
       && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
-    {
-      /* This is the final expression statement of a statement
-        expression.  */
-      statement = finish_stmt_expr_expr (statement, in_statement_expr);
-    }
+    /* This is the final expression statement of a statement
+       expression.  */
+    statement = finish_stmt_expr_expr (statement, in_statement_expr);
   else if (statement)
     statement = finish_expr_stmt (statement);
   else
@@ -6177,7 +6387,8 @@ cp_parser_condition (cp_parser* parser)
   parser->type_definition_forbidden_message
     = "types may not be defined in conditions";
   /* Parse the type-specifier-seq.  */
-  cp_parser_type_specifier_seq (parser, &type_specifiers);
+  cp_parser_type_specifier_seq (parser, /*is_condition==*/true,
+                               &type_specifiers);
   /* Restore the saved message.  */
   parser->type_definition_forbidden_message = saved_message;
   /* If all is well, we might be looking at a declaration.  */
@@ -6210,15 +6421,16 @@ cp_parser_condition (cp_parser* parser)
         for sure.  */
       if (cp_parser_parse_definitely (parser))
        {
-         bool pop_p;   
+         tree pushed_scope;    
 
          /* Create the declaration.  */
          decl = start_decl (declarator, &type_specifiers,
                             /*initialized_p=*/true,
                             attributes, /*prefix_attributes=*/NULL_TREE,
-                            &pop_p);
+                            &pushed_scope);
          /* Parse the assignment-expression.  */
-         initializer = cp_parser_assignment_expression (parser);
+         initializer = cp_parser_assignment_expression (parser,
+                                                        /*cast_p=*/false);
 
          /* Process the initializer.  */
          cp_finish_decl (decl,
@@ -6226,8 +6438,8 @@ cp_parser_condition (cp_parser* parser)
                          asm_specification,
                          LOOKUP_ONLYCONVERTING);
 
-         if (pop_p)
-           pop_scope (DECL_CONTEXT (decl));
+         if (pushed_scope)
+           pop_scope (pushed_scope);
 
          return convert_from_reference (decl);
        }
@@ -6238,7 +6450,7 @@ cp_parser_condition (cp_parser* parser)
     cp_parser_abort_tentative_parse (parser);
 
   /* Otherwise, we are looking at an expression.  */
-  return cp_parser_expression (parser);
+  return cp_parser_expression (parser, /*cast_p=*/false);
 }
 
 /* Parse an iteration-statement.
@@ -6311,7 +6523,7 @@ cp_parser_iteration_statement (cp_parser* parser)
        /* Look for the `('.  */
        cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
        /* Parse the expression.  */
-       expression = cp_parser_expression (parser);
+       expression = cp_parser_expression (parser, /*cast_p=*/false);
        /* We're done with the do-statement.  */
        finish_do_stmt (expression, statement);
        /* Look for the `)'.  */
@@ -6343,7 +6555,7 @@ cp_parser_iteration_statement (cp_parser* parser)
 
        /* If there's an expression, process it.  */
        if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
-         expression = cp_parser_expression (parser);
+         expression = cp_parser_expression (parser, /*cast_p=*/false);
        finish_for_expr (expression, statement);
        /* Look for the `)'.  */
        cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
@@ -6460,7 +6672,7 @@ cp_parser_jump_statement (cp_parser* parser)
        /* If the next token is a `;', then there is no
           expression.  */
        if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
-         expr = cp_parser_expression (parser);
+         expr = cp_parser_expression (parser, /*cast_p=*/false);
        else
          expr = NULL_TREE;
        /* Build the return-statement.  */
@@ -6480,7 +6692,7 @@ cp_parser_jump_statement (cp_parser* parser)
          /* Consume the '*' token.  */
          cp_lexer_consume_token (parser->lexer);
          /* Parse the dependent expression.  */
-         finish_goto_stmt (cp_parser_expression (parser));
+         finish_goto_stmt (cp_parser_expression (parser, /*cast_p=*/false));
        }
       else
        finish_goto_stmt (cp_parser_identifier (parser));
@@ -6721,6 +6933,9 @@ cp_parser_declaration (cp_parser* parser)
               /* An unnamed namespace definition.  */
               || token2.type == CPP_OPEN_BRACE))
     cp_parser_namespace_definition (parser);
+  /* Objective-C++ declaration/definition.  */
+  else if (c_dialect_objc () && OBJC_IS_AT_KEYWORD (token1.keyword))
+    cp_parser_objc_declaration (parser);
   /* We must have either a block declaration or a function
      definition.  */
   else
@@ -7376,7 +7591,7 @@ cp_parser_conversion_function_id (cp_parser* parser)
   tree saved_scope;
   tree saved_qualifying_scope;
   tree saved_object_scope;
-  bool pop_p = false;
+  tree pushed_scope = NULL_TREE;
 
   /* Look for the `operator' token.  */
   if (!cp_parser_require_keyword (parser, RID_OPERATOR, "`operator'"))
@@ -7401,12 +7616,12 @@ cp_parser_conversion_function_id (cp_parser* parser)
      In order to see that `I' is a type-name in the definition, we
      must be in the scope of `S'.  */
   if (saved_scope)
-    pop_p = push_scope (saved_scope);
+    pushed_scope = push_scope (saved_scope);
   /* Parse the conversion-type-id.  */
   type = cp_parser_conversion_type_id (parser);
   /* Leave the scope of the class, if any.  */
-  if (pop_p)
-    pop_scope (saved_scope);
+  if (pushed_scope)
+    pop_scope (pushed_scope);
   /* Restore the saved scope.  */
   parser->scope = saved_scope;
   parser->qualifying_scope = saved_qualifying_scope;
@@ -7435,7 +7650,8 @@ cp_parser_conversion_type_id (cp_parser* parser)
   /* Parse the attributes.  */
   attributes = cp_parser_attributes_opt (parser);
   /* Parse the type-specifiers.  */
-  cp_parser_type_specifier_seq (parser, &type_specifiers);
+  cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
+                               &type_specifiers);
   /* If that didn't work, stop.  */
   if (type_specifiers.type == error_mark_node)
     return error_mark_node;
@@ -7595,6 +7811,7 @@ cp_parser_mem_initializer (cp_parser* parser)
 
   expression_list
     = cp_parser_parenthesized_expression_list (parser, false,
+                                              /*cast_p=*/false,
                                               /*non_constant_p=*/NULL);
   if (!expression_list)
     expression_list = void_type_node;
@@ -7924,18 +8141,22 @@ cp_parser_operator (cp_parser* parser)
       /* Extensions.  */
     case CPP_MIN:
       id = ansi_opname (MIN_EXPR);
+      cp_parser_warn_min_max ();
       break;
 
     case CPP_MAX:
       id = ansi_opname (MAX_EXPR);
+      cp_parser_warn_min_max ();
       break;
 
     case CPP_MIN_EQ:
       id = ansi_assopname (MIN_EXPR);
+      cp_parser_warn_min_max ();
       break;
 
     case CPP_MAX_EQ:
       id = ansi_assopname (MAX_EXPR);
+      cp_parser_warn_min_max ();
       break;
 
     default:
@@ -7987,7 +8208,7 @@ cp_parser_template_declaration (cp_parser* parser, bool member_p)
       /* Consume the `export' token.  */
       cp_lexer_consume_token (parser->lexer);
       /* Warn that we do not support `export'.  */
-      warning ("keyword %<export%> not implemented, and will be ignored");
+      warning (0, "keyword %<export%> not implemented, and will be ignored");
     }
 
   cp_parser_template_declaration_after_export (parser, member_p);
@@ -8414,9 +8635,8 @@ cp_parser_template_id (cp_parser *parser,
      should we re-parse the token stream, we will not have to repeat
      the effort required to do the parse, nor will we issue duplicate
      error messages about problems during instantiation of the
-     template.  Do so only if parsing succeeded, otherwise we may
-     silently accept template arguments with syntax errors.  */
-  if (start_of_id && !cp_parser_error_occurred (parser))
+     template.  */
+  if (start_of_id)
     {
       cp_token *token = cp_lexer_token_at (parser->lexer, start_of_id);
       
@@ -8427,6 +8647,13 @@ cp_parser_template_id (cp_parser *parser,
       
       /* Purge all subsequent tokens.  */
       cp_lexer_purge_tokens_after (parser->lexer, start_of_id);
+
+      /* ??? Can we actually assume that, if template_id ==
+        error_mark_node, we will have issued a diagnostic to the
+        user, as opposed to simply marking the tentative parse as
+        failed?  */
+      if (cp_parser_error_occurred (parser) && template_id != error_mark_node)
+       error ("parse error in template argument list");
     }
 
   pop_deferring_access_checks ();
@@ -8591,6 +8818,8 @@ cp_parser_template_name (cp_parser* parser,
     ;
   else
     {
+      tree fn = NULL_TREE;
+
       /* The standard does not explicitly indicate whether a name that
         names a set of overloaded declarations, some of which are
         templates, is a template-name.  However, such a name should
@@ -8598,16 +8827,13 @@ cp_parser_template_name (cp_parser* parser,
         template-id for the overloaded templates.  */
       fns = BASELINK_P (decl) ? BASELINK_FUNCTIONS (decl) : decl;
       if (TREE_CODE (fns) == OVERLOAD)
-       {
-         tree fn;
+       for (fn = fns; fn; fn = OVL_NEXT (fn))
+         if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL)
+           break;
 
-         for (fn = fns; fn; fn = OVL_NEXT (fn))
-           if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL)
-             break;
-       }
-      else
+      if (!fn)
        {
-         /* Otherwise, the name does not name a template.  */
+         /* The name does not name a template.  */
          cp_parser_error (parser, "expected template-name");
          return error_mark_node;
        }
@@ -8799,6 +9025,7 @@ cp_parser_template_argument (cp_parser* parser)
     {
       cp_parser_parse_tentatively (parser);
       argument = cp_parser_primary_expression (parser,
+                                              /*cast_p=*/false,
                                               &idk,
                                               &qualifying_class);
       if (TREE_CODE (argument) != TEMPLATE_PARM_INDEX
@@ -8823,6 +9050,7 @@ cp_parser_template_argument (cp_parser* parser)
     {
       cp_parser_parse_tentatively (parser);
       argument = cp_parser_primary_expression (parser,
+                                              /*cast_p=*/false,
                                               &idk,
                                               &qualifying_class);
       if (cp_parser_error_occurred (parser)
@@ -9448,7 +9676,26 @@ cp_parser_simple_type_specifier (cp_parser* parser,
      followed by a "<".  That usually indicates that the user thought
      that the type was a template.  */
   if (type && type != error_mark_node)
-    cp_parser_check_for_invalid_template_id (parser, TREE_TYPE (type));
+    {
+      /* 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 ()
+         && (objc_is_id (type) || objc_is_class_name (type)))
+       {
+         tree protos = cp_parser_objc_protocol_refs_opt (parser);
+         tree qual_type = objc_get_protocol_qualified_type (type, protos);
+
+         /* Clobber the "unqualified" type previously entered into
+            DECL_SPECS with the new, improved protocol-qualifed version.  */
+         if (decl_specs)
+           decl_specs->type = qual_type;
+
+         return qual_type;
+       }
+
+      cp_parser_check_for_invalid_template_id (parser, TREE_TYPE (type));
+    } 
 
   return type;
 }
@@ -9466,7 +9713,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
    typedef-name:
      identifier
 
-   Returns a TYPE_DECL for the the type.  */
+   Returns a TYPE_DECL for the type.  */
 
 static tree
 cp_parser_type_name (cp_parser* parser)
@@ -9494,6 +9741,17 @@ cp_parser_type_name (cp_parser* parser)
 
       /* Look up the type-name.  */
       type_decl = cp_parser_lookup_name_simple (parser, identifier);
+
+      if (TREE_CODE (type_decl) != TYPE_DECL
+         && (objc_is_id (identifier) || objc_is_class_name (identifier)))
+       {
+         /* See if this is an Objective-C type.  */
+         tree protos = cp_parser_objc_protocol_refs_opt (parser);
+         tree type = objc_get_protocol_qualified_type (identifier, protos);
+         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)
        {
@@ -9766,7 +10024,7 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
 
          /* Warn about attributes. They are ignored.  */
          if (attributes)
-           warning ("type attributes are honored only at type definition");
+           warning (0, "type attributes are honored only at type definition");
 
          type = xref_tag (tag_type, identifier, ts,
                           parser->num_template_parameter_lists);
@@ -10154,9 +10412,7 @@ cp_parser_using_declaration (cp_parser* parser)
       if (at_class_scope_p ())
        {
          /* Create the USING_DECL.  */
-         decl = do_class_using_decl (build_nt (SCOPE_REF,
-                                               parser->scope,
-                                               identifier));
+         decl = do_class_using_decl (parser->scope, identifier);
          /* Add it to the list of members in this class.  */
          finish_member_declaration (decl);
        }
@@ -10407,7 +10663,7 @@ cp_parser_init_declarator (cp_parser* parser,
   bool is_non_constant_init;
   int ctor_dtor_or_conv_p;
   bool friend_p;
-  bool pop_p = false;
+  tree pushed_scope = NULL;
 
   /* Gather the attributes that were provided with the
      decl-specifiers.  */
@@ -10564,12 +10820,12 @@ cp_parser_init_declarator (cp_parser* parser,
        }
       decl = start_decl (declarator, decl_specifiers,
                         is_initialized, attributes, prefix_attributes,
-                        &pop_p);
+                        &pushed_scope);
     }
   else if (scope)
     /* Enter the SCOPE.  That way unqualified names appearing in the
        initializer will be looked up in SCOPE.  */
-    pop_p = push_scope (scope);
+    pushed_scope = push_scope (scope);
 
   /* Perform deferred access control checks, now that we know in which
      SCOPE the declared entity resides.  */
@@ -10613,16 +10869,16 @@ cp_parser_init_declarator (cp_parser* parser,
      attributes -- but ignores them.  */
   if (cp_parser_allow_gnu_extensions_p (parser) && is_parenthesized_init)
     if (cp_parser_attributes_opt (parser))
-      warning ("attributes after parenthesized initializer ignored");
+      warning (0, "attributes after parenthesized initializer ignored");
 
   /* For an in-class declaration, use `grokfield' to create the
      declaration.  */
   if (member_p)
     {
-      if (pop_p)
+      if (pushed_scope)
        {
-         pop_scope (scope);
-         pop_p = false;
+         pop_scope (pushed_scope);
+         pushed_scope = false;
        }
       decl = grokfield (declarator, decl_specifiers,
                        initializer, /*asmspec=*/NULL_TREE,
@@ -10644,9 +10900,9 @@ cp_parser_init_declarator (cp_parser* parser,
                         `explicit' constructor cannot be used.  */
                      ((is_parenthesized_init || !is_initialized)
                     ? 0 : LOOKUP_ONLYCONVERTING));
-      if (pop_p)
-       pop_scope (DECL_CONTEXT (decl));
     }
+  if (!friend_p && pushed_scope)
+    pop_scope (pushed_scope);
 
   /* Remember whether or not variables were initialized by
      constant-expressions.  */
@@ -10817,7 +11073,7 @@ cp_parser_direct_declarator (cp_parser* parser,
   bool saved_default_arg_ok_p = parser->default_arg_ok_p;
   bool saved_in_declarator_p = parser->in_declarator_p;
   bool first = true;
-  bool pop_p = false;
+  tree pushed_scope = NULL_TREE;
 
   while (true)
     {
@@ -10993,6 +11249,9 @@ cp_parser_direct_declarator (cp_parser* parser,
                                                 &non_constant_p);
              if (!non_constant_p)
                bounds = fold_non_dependent_expr (bounds);
+             /* Normally, the array bound must be an integral constant
+                expression.  However, as an extension, we allow VLAs
+                in function scopes.  */  
              else if (!at_function_scope_p ())
                {
                  error ("array bound is not an integer constant");
@@ -11012,33 +11271,36 @@ cp_parser_direct_declarator (cp_parser* parser,
        }
       else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
        {
-         tree id;
+         tree qualifying_scope;
+         tree unqualified_name;
 
          /* Parse a declarator-id */
          if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
            cp_parser_parse_tentatively (parser);
-         id = cp_parser_declarator_id (parser);
+         unqualified_name = cp_parser_declarator_id (parser);
+         qualifying_scope = parser->scope;
          if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
            {
              if (!cp_parser_parse_definitely (parser))
-               id = error_mark_node;
-             else if (TREE_CODE (id) != IDENTIFIER_NODE)
+               unqualified_name = error_mark_node;
+             else if (qualifying_scope
+                      || (TREE_CODE (unqualified_name) 
+                          != IDENTIFIER_NODE))
                {
                  cp_parser_error (parser, "expected unqualified-id");
-                 id = error_mark_node;
+                 unqualified_name = error_mark_node;
                }
            }
 
-         if (id == error_mark_node)
+         if (unqualified_name == error_mark_node)
            {
              declarator = cp_error_declarator;
              break;
            }
 
-         if (TREE_CODE (id) == SCOPE_REF && at_namespace_scope_p ())
+         if (qualifying_scope && at_namespace_scope_p ()
+             && TREE_CODE (qualifying_scope) == TYPENAME_TYPE)
            {
-             tree scope = TREE_OPERAND (id, 0);
-
              /* In the declaration of a member of a template class
                 outside of the class itself, the SCOPE will sometimes
                 be a TYPENAME_TYPE.  For example, given:
@@ -11055,40 +11317,31 @@ cp_parser_direct_declarator (cp_parser* parser,
                 `S<T>::R' not a type.  However, if `S' is
                 specialized, then this `i' will not be used, so there
                 is no harm in resolving the types here.  */
-             if (TREE_CODE (scope) == TYPENAME_TYPE)
-               {
-                 tree type;
-
-                 /* Resolve the TYPENAME_TYPE.  */
-                 type = resolve_typename_type (scope,
-                                                /*only_current_p=*/false);
-                 /* If that failed, the declarator is invalid.  */
-                 if (type == error_mark_node)
-                   error ("%<%T::%D%> is not a type",
-                          TYPE_CONTEXT (scope),
-                          TYPE_IDENTIFIER (scope));
-                 /* Build a new DECLARATOR.  */
-                 id = build_nt (SCOPE_REF, type, TREE_OPERAND (id, 1));
-               }
+             tree type;
+             
+             /* Resolve the TYPENAME_TYPE.  */
+             type = resolve_typename_type (qualifying_scope,
+                                           /*only_current_p=*/false);
+             /* If that failed, the declarator is invalid.  */
+             if (type == error_mark_node)
+               error ("%<%T::%D%> is not a type",
+                      TYPE_CONTEXT (qualifying_scope),
+                      TYPE_IDENTIFIER (qualifying_scope));
+             qualifying_scope = type;
            }
 
-         declarator = make_id_declarator (id);
-         if (id)
+         declarator = make_id_declarator (qualifying_scope, 
+                                          unqualified_name);
+         declarator->id_loc = token->location;
+         if (unqualified_name)
            {
              tree class_type;
-             tree unqualified_name;
 
-             if (TREE_CODE (id) == SCOPE_REF
-                 && CLASS_TYPE_P (TREE_OPERAND (id, 0)))
-               {
-                 class_type = TREE_OPERAND (id, 0);
-                 unqualified_name = TREE_OPERAND (id, 1);
-               }
+             if (qualifying_scope
+                 && CLASS_TYPE_P (qualifying_scope))
+               class_type = qualifying_scope;
              else
-               {
-                 class_type = current_class_type;
-                 unqualified_name = id;
-               }
+               class_type = current_class_type;
 
              if (class_type)
                {
@@ -11096,16 +11349,21 @@ cp_parser_direct_declarator (cp_parser* parser,
                    declarator->u.id.sfk = sfk_destructor;
                  else if (IDENTIFIER_TYPENAME_P (unqualified_name))
                    declarator->u.id.sfk = sfk_conversion;
-                 else if (constructor_name_p (unqualified_name,
-                                              class_type)
-                          || (TREE_CODE (unqualified_name) == TYPE_DECL
-                              && same_type_p (TREE_TYPE (unqualified_name),
-                                              class_type)))
+                 else if (/* There's no way to declare a constructor
+                             for an anonymous type, even if the type
+                             got a name for linkage purposes.  */
+                          !TYPE_WAS_ANONYMOUS (class_type)
+                          && (constructor_name_p (unqualified_name,
+                                                  class_type)
+                              || (TREE_CODE (unqualified_name) == TYPE_DECL
+                                  && (same_type_p 
+                                      (TREE_TYPE (unqualified_name),
+                                       class_type)))))
                    declarator->u.id.sfk = sfk_constructor;
 
                  if (ctor_dtor_or_conv_p && declarator->u.id.sfk != sfk_none)
                    *ctor_dtor_or_conv_p = -1;
-                 if (TREE_CODE (id) == SCOPE_REF
+                 if (qualifying_scope
                      && TREE_CODE (unqualified_name) == TYPE_DECL
                      && CLASSTYPE_USE_TEMPLATE (TREE_TYPE (unqualified_name)))
                    {
@@ -11124,7 +11382,7 @@ cp_parser_direct_declarator (cp_parser* parser,
          if (scope)
            /* Any names that appear after the declarator-id for a
               member are looked up in the containing scope.  */
-           pop_p = push_scope (scope);
+           pushed_scope = push_scope (scope);
          parser->in_declarator_p = true;
          if ((ctor_dtor_or_conv_p && *ctor_dtor_or_conv_p)
              || (declarator && declarator->kind == cdk_id))
@@ -11147,8 +11405,8 @@ cp_parser_direct_declarator (cp_parser* parser,
     cp_parser_error (parser, "expected declarator");
 
   /* If we entered a scope, we must exit it now.  */
-  if (pop_p)
-    pop_scope (scope);
+  if (pushed_scope)
+    pop_scope (pushed_scope);
 
   parser->default_arg_ok_p = saved_default_arg_ok_p;
   parser->in_declarator_p = saved_in_declarator_p;
@@ -11327,8 +11585,6 @@ cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
 static tree
 cp_parser_declarator_id (cp_parser* parser)
 {
-  tree id_expression;
-
   /* The expression must be an id-expression.  Assume that qualified
      names are the names of types so that:
 
@@ -11343,20 +11599,11 @@ cp_parser_declarator_id (cp_parser* parser)
        int S<T>::R<T>::i = 3;
 
      will work, too.  */
-  id_expression = cp_parser_id_expression (parser,
-                                          /*template_keyword_p=*/false,
-                                          /*check_dependency_p=*/false,
-                                          /*template_p=*/NULL,
-                                          /*declarator_p=*/true);
-  /* If the name was qualified, create a SCOPE_REF to represent
-     that.  */
-  if (parser->scope)
-    {
-      id_expression = build_nt (SCOPE_REF, parser->scope, id_expression);
-      parser->scope = NULL_TREE;
-    }
-
-  return id_expression;
+  return cp_parser_id_expression (parser,
+                                 /*template_keyword_p=*/false,
+                                 /*check_dependency_p=*/false,
+                                 /*template_p=*/NULL,
+                                 /*declarator_p=*/true);
 }
 
 /* Parse a type-id.
@@ -11373,7 +11620,8 @@ cp_parser_type_id (cp_parser* parser)
   cp_declarator *abstract_declarator;
 
   /* Parse the type-specifier-seq.  */
-  cp_parser_type_specifier_seq (parser, &type_specifier_seq);
+  cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
+                               &type_specifier_seq);
   if (type_specifier_seq.type == error_mark_node)
     return error_mark_node;
 
@@ -11401,13 +11649,18 @@ cp_parser_type_id (cp_parser* parser)
    type-specifier-seq:
      attributes type-specifier-seq [opt]
 
+   If IS_CONDITION is true, we are at the start of a "condition",
+   e.g., we've just seen "if (".
+
    Sets *TYPE_SPECIFIER_SEQ to represent the sequence.  */
 
 static void
 cp_parser_type_specifier_seq (cp_parser* parser,
+                             bool is_condition,
                              cp_decl_specifier_seq *type_specifier_seq)
 {
   bool seen_type_specifier = false;
+  cp_parser_flags flags = CP_PARSER_FLAGS_OPTIONAL;
 
   /* Clear the TYPE_SPECIFIER_SEQ.  */
   clear_decl_specs (type_specifier_seq);
@@ -11416,6 +11669,7 @@ cp_parser_type_specifier_seq (cp_parser* parser,
   while (true)
     {
       tree type_specifier;
+      bool is_cv_qualifier;
 
       /* Check for attributes first.  */
       if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
@@ -11428,25 +11682,45 @@ cp_parser_type_specifier_seq (cp_parser* parser,
 
       /* Look for the type-specifier.  */
       type_specifier = cp_parser_type_specifier (parser,
-                                                CP_PARSER_FLAGS_OPTIONAL,
+                                                flags,
                                                 type_specifier_seq,
                                                 /*is_declaration=*/false,
                                                 NULL,
-                                                NULL);
-      /* If the first type-specifier could not be found, this is not a
-        type-specifier-seq at all.  */
-      if (!seen_type_specifier && !type_specifier)
+                                                &is_cv_qualifier);
+      if (!type_specifier)
        {
-         cp_parser_error (parser, "expected type-specifier");
-         type_specifier_seq->type = error_mark_node;
-         return;
+         /* If the first type-specifier could not be found, this is not a
+            type-specifier-seq at all.  */
+         if (!seen_type_specifier)
+           {
+             cp_parser_error (parser, "expected type-specifier");
+             type_specifier_seq->type = error_mark_node;
+             return;
+           }
+         /* If subsequent type-specifiers could not be found, the
+            type-specifier-seq is complete.  */
+         break;
        }
-      /* If subsequent type-specifiers could not be found, the
-        type-specifier-seq is complete.  */
-      else if (seen_type_specifier && !type_specifier)
-       break;
 
       seen_type_specifier = true;
+      /* The standard says that a condition can be:
+
+            type-specifier-seq declarator = assignment-expression
+      
+        However, given:
+
+          struct S {};
+          if (int S = ...)
+
+         we should treat the "S" as a declarator, not as a
+         type-specifier.  The standard doesn't say that explicitly for
+         type-specifier-seq, but it does say that for
+         decl-specifier-seq in an ordinary declaration.  Perhaps it
+         would be clearer just to allow a decl-specifier-seq here, and
+         then add a semantic restriction that if any decl-specifiers
+         that are not type-specifiers appear, the program is invalid.  */
+      if (is_condition && !is_cv_qualifier)
+       flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES; 
     }
 
   return;
@@ -11584,7 +11858,10 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
 
       /* Peek at the next token.  */
       if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)
-         || cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
+         || cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)
+         /* These are for Objective-C++ */
+         || cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
+         || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
        /* The parameter-declaration-list is complete.  */
        break;
       else if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
@@ -11861,7 +12138,8 @@ cp_parser_parameter_declaration (cp_parser *parser,
            = parser->local_variables_forbidden_p;
          parser->local_variables_forbidden_p = true;
          /* Parse the assignment-expression.  */
-         default_argument = cp_parser_assignment_expression (parser);
+         default_argument 
+           = cp_parser_assignment_expression (parser, /*cast_p=*/false);
          /* Restore saved state.  */
          parser->greater_than_is_operator_p
            = saved_greater_than_is_operator_p;
@@ -11871,7 +12149,7 @@ cp_parser_parameter_declaration (cp_parser *parser,
       if (!parser->default_arg_ok_p)
        {
          if (!flag_pedantic_errors)
-           warning ("deprecated use of default argument for parameter of non-function");
+           warning (0, "deprecated use of default argument for parameter of non-function");
          else
            {
              error ("default arguments are only permitted for function parameters");
@@ -11959,6 +12237,7 @@ cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init,
     }
   else if (token->type == CPP_OPEN_PAREN)
     init = cp_parser_parenthesized_expression_list (parser, false,
+                                                   /*cast_p=*/false,
                                                    non_constant_p);
   else
     {
@@ -11994,6 +12273,9 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
 {
   tree initializer;
 
+  /* Assume the expression is constant.  */
+  *non_constant_p = false;
+
   /* If it is not a `{', then we are looking at an
      assignment-expression.  */
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
@@ -12349,8 +12631,8 @@ cp_parser_class_specifier (cp_parser* parser)
     {
       tree queue_entry;
       tree fn;
-      tree class_type;
-      bool pop_p;
+      tree class_type = NULL_TREE;
+      tree pushed_scope = NULL_TREE;
 
       /* In a first pass, parse default arguments to the functions.
         Then, in a second pass, parse the bodies of the functions.
@@ -12362,8 +12644,6 @@ cp_parser_class_specifier (cp_parser* parser)
             };
 
          */
-      class_type = NULL_TREE;
-      pop_p = false;
       for (TREE_PURPOSE (parser->unparsed_functions_queues)
             = nreverse (TREE_PURPOSE (parser->unparsed_functions_queues));
           (queue_entry = TREE_PURPOSE (parser->unparsed_functions_queues));
@@ -12375,10 +12655,10 @@ cp_parser_class_specifier (cp_parser* parser)
             take care of them now.  */
          if (class_type != TREE_PURPOSE (queue_entry))
            {
-             if (pop_p)
-               pop_scope (class_type);
+             if (pushed_scope)
+               pop_scope (pushed_scope);
              class_type = TREE_PURPOSE (queue_entry);
-             pop_p = push_scope (class_type);
+             pushed_scope = push_scope (class_type);
            }
          /* Make sure that any template parameters are in scope.  */
          maybe_begin_member_template_processing (fn);
@@ -12387,8 +12667,8 @@ cp_parser_class_specifier (cp_parser* parser)
          /* Remove any template parameters from the symbol table.  */
          maybe_end_member_template_processing ();
        }
-      if (pop_p)
-       pop_scope (class_type);
+      if (pushed_scope)
+       pop_scope (pushed_scope);
       /* Now parse the body of the functions.  */
       for (TREE_VALUE (parser->unparsed_functions_queues)
             = nreverse (TREE_VALUE (parser->unparsed_functions_queues));
@@ -12456,7 +12736,7 @@ cp_parser_class_head (cp_parser* parser,
   bool qualified_p = false;
   bool invalid_nested_name_p = false;
   bool invalid_explicit_specialization_p = false;
-  bool pop_p = false;
+  tree pushed_scope = NULL_TREE;
   unsigned num_templates;
   tree bases;
 
@@ -12674,19 +12954,12 @@ cp_parser_class_head (cp_parser* parser,
     {
       type = TREE_TYPE (id);
       maybe_process_partial_specialization (type);
+      if (nested_name_specifier)
+       pushed_scope = push_scope (nested_name_specifier);
     }
-  else if (!nested_name_specifier)
-    {
-      /* If the class was unnamed, create a dummy name.  */
-      if (!id)
-       id = make_anon_name ();
-      type = xref_tag (class_key, id, /*tag_scope=*/ts_current,
-                      parser->num_template_parameter_lists);
-    }
-  else
+  else if (nested_name_specifier)
     {
       tree class_type;
-      bool pop_p = false;
 
       /* Given:
 
@@ -12712,8 +12985,7 @@ cp_parser_class_head (cp_parser* parser,
       maybe_process_partial_specialization (TREE_TYPE (type));
       class_type = current_class_type;
       /* Enter the scope indicated by the nested-name-specifier.  */
-      if (nested_name_specifier)
-       pop_p = push_scope (nested_name_specifier);
+      pushed_scope = push_scope (nested_name_specifier);
       /* Get the canonical version of this type.  */
       type = TYPE_MAIN_DECL (TREE_TYPE (type));
       if (PROCESSING_REAL_TEMPLATE_DECL_P ()
@@ -12728,29 +13000,40 @@ cp_parser_class_head (cp_parser* parser,
        }
       
       type = TREE_TYPE (type);
-      if (nested_name_specifier)
-       {
-         *nested_name_specifier_p = true;
-         if (pop_p)
-           pop_scope (nested_name_specifier);
-       }
+      *nested_name_specifier_p = true;
+    }
+  else      /* The name is not a nested name.  */
+    {
+      /* If the class was unnamed, create a dummy name.  */
+      if (!id)
+       id = make_anon_name ();
+      type = xref_tag (class_key, id, /*tag_scope=*/ts_current,
+                      parser->num_template_parameter_lists);
     }
+
   /* Indicate whether this class was declared as a `class' or as a
      `struct'.  */
   if (TREE_CODE (type) == RECORD_TYPE)
     CLASSTYPE_DECLARED_CLASS (type) = (class_key == class_type);
   cp_parser_check_class_key (class_key, type);
 
-  /* Enter the scope containing the class; the names of base classes
-     should be looked up in that context.  For example, given:
+  /* If this type was already complete, and we see another definition,
+     that's an error.  */
+  if (type != error_mark_node && COMPLETE_TYPE_P (type))
+    {
+      error ("redefinition of %q#T", type);
+      cp_error_at ("previous definition of %q#T", type);
+      type = NULL_TREE;
+      goto done;
+    }
+
+  /* We will have entered the scope containing the class; the names of
+     base classes should be looked up in that context.  For example:
 
        struct A { struct B {}; struct C; };
        struct A::C : B {};
 
      is valid.  */
-  if (nested_name_specifier)
-    pop_p = push_scope (nested_name_specifier);
-
   bases = NULL_TREE;
 
   /* Get the list of base-classes, if there is one.  */
@@ -12760,12 +13043,12 @@ cp_parser_class_head (cp_parser* parser,
   /* Process the base classes.  */
   xref_basetypes (type, bases);
 
+ done:
   /* Leave the scope given by the nested-name-specifier.  We will
      enter the class scope itself while processing the members.  */
-  if (pop_p)
-    pop_scope (nested_name_specifier);
+  if (pushed_scope)
+    pop_scope (pushed_scope);
 
- done:
   if (invalid_explicit_specialization_p)
     {
       end_specialization ();
@@ -12921,6 +13204,22 @@ cp_parser_member_declaration (cp_parser* parser)
       return;
     }
 
+  /* Check for @defs.  */
+  if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_DEFS))
+    {
+      tree ivar, member;
+      tree ivar_chains = cp_parser_objc_defs_expression (parser);
+      ivar = ivar_chains;
+      while (ivar)
+       {
+         member = ivar;
+         ivar = TREE_CHAIN (member);
+         TREE_CHAIN (member) = NULL_TREE;
+         finish_member_declaration (member);
+       }
+      return;
+    }
+
   /* Parse the decl-specifier-seq.  */
   cp_parser_decl_specifier_seq (parser,
                                CP_PARSER_FLAGS_OPTIONAL,
@@ -13058,7 +13357,8 @@ cp_parser_member_declaration (cp_parser* parser)
 
              /* Create the bitfield declaration.  */
              decl = grokbitfield (identifier
-                                  ? make_id_declarator (identifier)
+                                  ? make_id_declarator (NULL_TREE,
+                                                        identifier)
                                   : NULL,
                                   &decl_specifiers,
                                   width);
@@ -13241,13 +13541,18 @@ cp_parser_pure_specifier (cp_parser* parser)
   if (!cp_parser_require (parser, CPP_EQ, "`='"))
     return error_mark_node;
   /* Look for the `0' token.  */
-  token = cp_parser_require (parser, CPP_NUMBER, "`0'");
-  /* Unfortunately, this will accept `0L' and `0x00' as well.  We need
-     to get information from the lexer about how the number was
-     spelled in order to fix this problem.  */
-  if (!token || !integer_zerop (token->value))
-    return error_mark_node;
+  token = cp_lexer_consume_token (parser->lexer);
+  if (token->type != CPP_NUMBER || !integer_zerop (token->value))
+    {
+      cp_parser_error (parser,
+                      "invalid pure specifier (only `= 0' is allowed)");
+      cp_parser_skip_to_end_of_statement (parser);
+      return error_mark_node;
+    }
 
+  /* FIXME: Unfortunately, this will accept `0L' and `0x00' as well.
+     We need to get information from the lexer about how the number
+     was spelled in order to fix this problem.  */
   return integer_zero_node;
 }
 
@@ -13688,7 +13993,8 @@ cp_parser_exception_declaration (cp_parser* parser)
     = "types may not be defined in exception-declarations";
 
   /* Parse the type-specifier-seq.  */
-  cp_parser_type_specifier_seq (parser, &type_specifiers);
+  cp_parser_type_specifier_seq (parser, /*is_condition=*/false,
+                               &type_specifiers);
   /* If it's a `)', then there is no declarator.  */
   if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
     declarator = NULL;
@@ -13738,7 +14044,8 @@ cp_parser_throw_expression (cp_parser* parser)
       || token->type == CPP_COLON)
     expression = NULL_TREE;
   else
-    expression = cp_parser_assignment_expression (parser);
+    expression = cp_parser_assignment_expression (parser,
+                                                 /*cast_p=*/false);
 
   return build_throw (expression);
 }
@@ -13828,7 +14135,7 @@ cp_parser_asm_operand_list (cp_parser* parser)
       /* Look for the `('.  */
       cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
       /* Parse the expression.  */
-      expression = cp_parser_expression (parser);
+      expression = cp_parser_expression (parser, /*cast_p=*/false);
       /* Look for the `)'.  */
       cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
 
@@ -13945,10 +14252,10 @@ cp_parser_attributes_opt (cp_parser* parser)
      identifier ( identifier , expression-list )
      identifier ( expression-list )
 
-   Returns a TREE_LIST.  Each node corresponds to an attribute.  THe
-   TREE_PURPOSE of each node is the identifier indicating which
-   attribute is in use.  The TREE_VALUE represents the arguments, if
-   any.  */
+   Returns a TREE_LIST, or NULL_TREE on error.  Each node corresponds
+   to an attribute.  The TREE_PURPOSE of each node is the identifier
+   indicating which attribute is in use.  The TREE_VALUE represents
+   the arguments, if any.  */
 
 static tree
 cp_parser_attribute_list (cp_parser* parser)
@@ -13966,36 +14273,39 @@ cp_parser_attribute_list (cp_parser* parser)
       /* Look for the identifier.  We also allow keywords here; for
         example `__attribute__ ((const))' is legal.  */
       token = cp_lexer_peek_token (parser->lexer);
-      if (token->type != CPP_NAME
-         && token->type != CPP_KEYWORD)
-       return error_mark_node;
-      /* Consume the token.  */
-      token = cp_lexer_consume_token (parser->lexer);
+      if (token->type == CPP_NAME
+         || token->type == CPP_KEYWORD)
+       {
+         /* Consume the token.  */
+         token = cp_lexer_consume_token (parser->lexer);
 
-      /* Save away the identifier that indicates which attribute this is.  */
-      identifier = token->value;
-      attribute = build_tree_list (identifier, NULL_TREE);
+         /* Save away the identifier that indicates which attribute
+            this is.  */ 
+         identifier = token->value;
+         attribute = build_tree_list (identifier, NULL_TREE);
 
-      /* Peek at the next token.  */
-      token = cp_lexer_peek_token (parser->lexer);
-      /* If it's an `(', then parse the attribute arguments.  */
-      if (token->type == CPP_OPEN_PAREN)
-       {
-         tree arguments;
+         /* Peek at the next token.  */
+         token = cp_lexer_peek_token (parser->lexer);
+         /* If it's an `(', then parse the attribute arguments.  */
+         if (token->type == CPP_OPEN_PAREN)
+           {
+             tree arguments;
 
-         arguments = (cp_parser_parenthesized_expression_list
-                      (parser, true, /*non_constant_p=*/NULL));
-         /* Save the identifier and arguments away.  */
-         TREE_VALUE (attribute) = arguments;
-       }
+             arguments = (cp_parser_parenthesized_expression_list
+                          (parser, true, /*cast_p=*/false, 
+                           /*non_constant_p=*/NULL));
+             /* Save the identifier and arguments away.  */
+             TREE_VALUE (attribute) = arguments;
+           }
 
-      /* Add this attribute to the list.  */
-      TREE_CHAIN (attribute) = attribute_list;
-      attribute_list = attribute;
+         /* Add this attribute to the list.  */
+         TREE_CHAIN (attribute) = attribute_list;
+         attribute_list = attribute;
 
-      /* Now, look for more attributes.  */
-      token = cp_lexer_peek_token (parser->lexer);
-      /* If the next token isn't a `,', we're done.  */
+         token = cp_lexer_peek_token (parser->lexer);
+       }
+      /* Now, look for more attributes.  If the next token isn't a
+        `,', we're done.  */
       if (token->type != CPP_COMMA)
        break;
 
@@ -14154,6 +14464,8 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
       /* If that's not a class type, there is no destructor.  */
       if (!type || !CLASS_TYPE_P (type))
        return error_mark_node;
+      if (CLASSTYPE_LAZY_DESTRUCTOR (type))
+       lazily_declare_fn (sfk_destructor, type);
       if (!CLASSTYPE_DESTRUCTORS (type))
          return error_mark_node;
       /* If it was a class type, return the destructor.  */
@@ -14205,7 +14517,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
        }
       else
        {
-         bool pop_p = false;
+         tree pushed_scope = NULL_TREE;
 
          /* If PARSER->SCOPE is a dependent type, then it must be a
             class type, and we must not be checking dependencies;
@@ -14213,16 +14525,16 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
             that PARSER->SCOPE is not considered a dependent base by
             lookup_member, we must enter the scope here.  */
          if (dependent_p)
-           pop_p = push_scope (parser->scope);
-         /* If the PARSER->SCOPE is a template specialization, it
+           pushed_scope = push_scope (parser->scope);
+         /* If the PARSER->SCOPE is a template specialization, it
             may be instantiated during name lookup.  In that case,
             errors may be issued.  Even if we rollback the current
             tentative parse, those errors are valid.  */
          decl = lookup_qualified_name (parser->scope, name, 
                                        tag_type != none_type, 
                                        /*complain=*/true);
-         if (pop_p)
-           pop_scope (parser->scope);
+         if (pushed_scope)
+           pop_scope (pushed_scope);
        }
       parser->qualifying_scope = parser->scope;
       parser->object_scope = NULL_TREE;
@@ -14262,10 +14574,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name,
     }
 
   /* If the lookup failed, let our caller know.  */
-  if (!decl
-      || decl == error_mark_node
-      || (TREE_CODE (decl) == FUNCTION_DECL
-         && DECL_ANTICIPATED (decl)))
+  if (!decl || decl == error_mark_node)
     return error_mark_node;
 
   /* If it's a TREE_LIST, the result of the lookup was ambiguous.  */
@@ -14377,13 +14686,13 @@ cp_parser_check_declarator_template_parameters (cp_parser* parser,
   switch (declarator->kind)
     {
     case cdk_id:
-      if (TREE_CODE (declarator->u.id.name) == SCOPE_REF)
+      if (declarator->u.id.qualifying_scope)
        {
          tree scope;
          tree member;
 
-         scope = TREE_OPERAND (declarator->u.id.name, 0);
-         member = TREE_OPERAND (declarator->u.id.name, 1);
+         scope = declarator->u.id.qualifying_scope;
+         member = declarator->u.id.unqualified_name;
 
          while (scope && CLASS_TYPE_P (scope))
            {
@@ -14406,10 +14715,10 @@ cp_parser_check_declarator_template_parameters (cp_parser* parser,
              scope = TYPE_CONTEXT (scope);
            }
        }
-
-      /* If the DECLARATOR has the form `X<y>' then it uses one
-        additional level of template parameters.  */
-      if (TREE_CODE (declarator->u.id.name) == TEMPLATE_ID_EXPR)
+      else if (TREE_CODE (declarator->u.id.unqualified_name) 
+              == TEMPLATE_ID_EXPR)
+       /* If the DECLARATOR has the form `X<y>' then it uses one
+          additional level of template parameters.  */
        ++num_templates;
 
       return cp_parser_check_template_parameters (parser,
@@ -14598,7 +14907,7 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
          && !cp_parser_storage_class_specifier_opt (parser))
        {
          tree type;
-         bool pop_p = false;
+         tree pushed_scope = NULL_TREE;
          unsigned saved_num_template_parameter_lists;
 
          /* Names appearing in the type-specifier should be looked up
@@ -14618,7 +14927,7 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
                      return false;
                    }
                }
-             pop_p = push_scope (type);
+             pushed_scope = push_scope (type);
            }
 
          /* Inside the constructor parameter list, surrounding
@@ -14639,8 +14948,8 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
            = saved_num_template_parameter_lists;
 
          /* Leave the scope of the class.  */
-         if (pop_p)
-           pop_scope (type);
+         if (pushed_scope)
+           pop_scope (pushed_scope);
 
          constructor_p = !cp_parser_error_occurred (parser);
        }
@@ -14961,7 +15270,8 @@ cp_parser_single_declaration (cp_parser* parser,
 static tree
 cp_parser_simple_cast_expression (cp_parser *parser)
 {
-  return cp_parser_cast_expression (parser, /*address_p=*/false);
+  return cp_parser_cast_expression (parser, /*address_p=*/false,
+                                   /*cast_p=*/false);
 }
 
 /* Parse a functional cast to TYPE.  Returns an expression
@@ -14975,6 +15285,7 @@ cp_parser_functional_cast (cp_parser* parser, tree type)
 
   expression_list
     = cp_parser_parenthesized_expression_list (parser, false,
+                                              /*cast_p=*/true,
                                               /*non_constant_p=*/NULL);
 
   cast = build_functional_cast (type, expression_list);
@@ -15166,9 +15477,10 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
       tokens = DECL_PENDING_INLINE_INFO (member_function);
       DECL_PENDING_INLINE_INFO (member_function) = NULL;
       DECL_PENDING_INLINE_P (member_function) = 0;
-      /* If this was an inline function in a local class, enter the scope
-        of the containing function.  */
-      function_scope = decl_function_context (member_function);
+      
+      /* If this is a local class, enter the scope of the containing
+        function.  */
+      function_scope = current_function_decl;
       if (function_scope)
        push_function_context_to (function_scope);
 
@@ -15258,7 +15570,8 @@ cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
       cp_parser_push_lexer_for_tokens (parser, tokens);
 
       /* Parse the assignment-expression.  */
-      TREE_PURPOSE (parm) = cp_parser_assignment_expression (parser);
+      TREE_PURPOSE (parm) = cp_parser_assignment_expression (parser,
+                                                            /*cast_p=*/false);
 
       /* If the token stream has not been completely used up, then
         there was extra junk after the end of the default
@@ -15290,6 +15603,7 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)
   tree expr = NULL_TREE;
   const char *saved_message;
   bool saved_integral_constant_expression_p;
+  bool saved_non_integral_constant_expression_p;
 
   /* Initialize FORMAT the first time we get here.  */
   if (!format)
@@ -15308,7 +15622,10 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)
 
   /* The restrictions on constant-expressions do not apply inside
      sizeof expressions.  */
-  saved_integral_constant_expression_p = parser->integral_constant_expression_p;
+  saved_integral_constant_expression_p 
+    = parser->integral_constant_expression_p;
+  saved_non_integral_constant_expression_p
+    = parser->non_integral_constant_expression_p;
   parser->integral_constant_expression_p = false;
 
   /* Do not actually evaluate the expression.  */
@@ -15353,7 +15670,8 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)
   /* If the type-id production did not work out, then we must be
      looking at the unary-expression production.  */
   if (!expr)
-    expr = cp_parser_unary_expression (parser, /*address_p=*/false);
+    expr = cp_parser_unary_expression (parser, /*address_p=*/false,
+                                      /*cast_p=*/false);
   /* Go back to evaluating expressions.  */
   --skip_evaluation;
 
@@ -15361,7 +15679,10 @@ cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)
   free ((char *) parser->type_definition_forbidden_message);
   /* And restore the old one.  */
   parser->type_definition_forbidden_message = saved_message;
-  parser->integral_constant_expression_p = saved_integral_constant_expression_p;
+  parser->integral_constant_expression_p 
+    = saved_integral_constant_expression_p;
+  parser->non_integral_constant_expression_p
+    = saved_non_integral_constant_expression_p;
 
   return expr;
 }
@@ -15860,7 +16181,1109 @@ cp_parser_allow_gnu_extensions_p (cp_parser* parser)
 {
   return parser->allow_gnu_extensions_p;
 }
+\f
+/* Objective-C++ Productions */
+
+
+/* Parse an Objective-C expression, which feeds into a primary-expression
+   above.
+
+   objc-expression:
+     objc-message-expression
+     objc-string-literal
+     objc-encode-expression
+     objc-protocol-expression
+     objc-selector-expression
+
+  Returns a tree representation of the expression.  */
+
+static tree
+cp_parser_objc_expression (cp_parser* parser)
+{
+  /* Try to figure out what kind of declaration is present.  */
+  cp_token *kwd = cp_lexer_peek_token (parser->lexer);
+
+  switch (kwd->type)
+    {
+    case CPP_OPEN_SQUARE:
+      return cp_parser_objc_message_expression (parser);
+
+    case CPP_OBJC_STRING:
+      kwd = cp_lexer_consume_token (parser->lexer);
+      return objc_build_string_object (kwd->value);
+
+    case CPP_KEYWORD:
+      switch (kwd->keyword)
+       {
+       case RID_AT_ENCODE:
+         return cp_parser_objc_encode_expression (parser);
+
+       case RID_AT_PROTOCOL:
+         return cp_parser_objc_protocol_expression (parser);
+
+       case RID_AT_SELECTOR:
+         return cp_parser_objc_selector_expression (parser);
+
+       default:
+         break;
+       }
+    default:
+      error ("misplaced `@%D' Objective-C++ construct", kwd->value);
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+    }
+
+  return error_mark_node;
+}
+
+/* Parse an Objective-C message expression.
+
+   objc-message-expression:
+     [ objc-message-receiver objc-message-args ]
 
+   Returns a representation of an Objective-C message.  */
+
+static tree
+cp_parser_objc_message_expression (cp_parser* parser)
+{
+  tree receiver, messageargs;
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '['.  */
+  receiver = cp_parser_objc_message_receiver (parser);
+  messageargs = cp_parser_objc_message_args (parser);
+  cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
+
+  return objc_build_message_expr (build_tree_list (receiver, messageargs));
+}
+
+/* Parse an objc-message-receiver.
+
+   objc-message-receiver:
+     type-name
+     expression
+
+  Returns a representation of the type or expression.  */
+
+static tree
+cp_parser_objc_message_receiver (cp_parser* parser)
+{
+  tree rcv;
+  bool class_scope_p, template_p;
+
+  /* An Objective-C message receiver may be either (1) a type
+     or (2) an expression.  */
+  cp_parser_parse_tentatively (parser);
+  rcv = cp_parser_expression (parser, false);
+
+  if (cp_parser_parse_definitely (parser))
+    return rcv;
+
+  /* Look for the optional `::' operator.  */
+  cp_parser_global_scope_opt (parser, false);
+  /* Look for the nested-name-specifier.  */
+  cp_parser_nested_name_specifier_opt (parser,
+                                      /*typename_keyword_p=*/true,
+                                      /*check_dependency_p=*/true,
+                                      /*type_p=*/true,
+                                      /*is_declaration=*/true);
+  class_scope_p = (parser->scope && TYPE_P (parser->scope));
+  template_p = class_scope_p && cp_parser_optional_template_keyword (parser);
+  /* Finally, look for the class-name.  */
+  rcv = cp_parser_class_name (parser,
+                              class_scope_p,
+                              template_p,
+                              /*type_p=*/true,
+                              /*check_dependency_p=*/true,
+                              /*class_head_p=*/false,
+                              /*is_declaration=*/true);
+
+  return objc_get_class_reference (rcv);
+}
+
+/* Parse the arguments and selectors comprising an Objective-C message.
+
+   objc-message-args:
+     objc-selector
+     objc-selector-args
+     objc-selector-args , objc-comma-args
+
+   objc-selector-args:
+     objc-selector [opt] : assignment-expression
+     objc-selector-args objc-selector [opt] : assignment-expression
+
+   objc-comma-args:
+     assignment-expression
+     objc-comma-args , assignment-expression
+
+   Returns a TREE_LIST, with TREE_PURPOSE containing a list of
+   selector arguments and TREE_VALUE containing a list of comma
+   arguments.  */
+
+static tree
+cp_parser_objc_message_args (cp_parser* parser)
+{
+  tree sel_args = NULL_TREE, addl_args = NULL_TREE;
+  bool maybe_unary_selector_p = true;
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+  while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON)
+    {
+      tree selector = NULL_TREE, arg;
+
+      if (token->type != CPP_COLON)
+       selector = cp_parser_objc_selector (parser);
+
+      /* Detect if we have a unary selector.  */
+      if (maybe_unary_selector_p
+         && cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+       return build_tree_list (selector, NULL_TREE);
+
+      maybe_unary_selector_p = false;
+      cp_parser_require (parser, CPP_COLON, "`:'");
+      arg = cp_parser_assignment_expression (parser, false);
+
+      sel_args
+       = chainon (sel_args,
+                  build_tree_list (selector, arg));
+
+      token = cp_lexer_peek_token (parser->lexer);
+    }
+
+  /* Handle non-selector arguments, if any. */
+  while (token->type == CPP_COMMA)
+    {
+      tree arg;
+
+      cp_lexer_consume_token (parser->lexer);
+      arg = cp_parser_assignment_expression (parser, false);
+
+      addl_args
+       = chainon (addl_args,
+                  build_tree_list (NULL_TREE, arg));
+
+      token = cp_lexer_peek_token (parser->lexer);
+    }
+
+  return build_tree_list (sel_args, addl_args);
+}
+
+/* Parse an Objective-C encode expression.
+
+   objc-encode-expression:
+     @encode objc-typename
+     
+   Returns an encoded representation of the type argument.  */
+
+static tree
+cp_parser_objc_encode_expression (cp_parser* parser)
+{
+  tree type;
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@encode'.  */
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+  type = complete_type (cp_parser_type_id (parser));
+  cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+  if (!type)
+    {
+      error ("`@encode' must specify a type as an argument");
+      return error_mark_node;
+    }
+
+  return objc_build_encode_expr (type);
+}
+
+/* Parse an Objective-C @defs expression.  */
+
+static tree
+cp_parser_objc_defs_expression (cp_parser *parser)
+{
+  tree name;
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@defs'.  */
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+  name = cp_parser_identifier (parser);
+  cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+  return objc_get_class_ivars (name);
+}
+
+/* Parse an Objective-C protocol expression.
+
+  objc-protocol-expression:
+    @protocol ( identifier )
+
+  Returns a representation of the protocol expression.  */
+
+static tree
+cp_parser_objc_protocol_expression (cp_parser* parser)
+{
+  tree proto;
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@protocol'.  */
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+  proto = cp_parser_identifier (parser);
+  cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+  return objc_build_protocol_expr (proto);
+}
+
+/* Parse an Objective-C selector expression.
+
+   objc-selector-expression:
+     @selector ( objc-method-signature )
+
+   objc-method-signature:
+     objc-selector
+     objc-selector-seq
+
+   objc-selector-seq:
+     objc-selector :
+     objc-selector-seq objc-selector :
+
+  Returns a representation of the method selector.  */
+
+static tree
+cp_parser_objc_selector_expression (cp_parser* parser)
+{
+  tree sel_seq = NULL_TREE;
+  bool maybe_unary_selector_p = true;
+  cp_token *token;
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@selector'.  */
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+  token = cp_lexer_peek_token (parser->lexer);
+
+  while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON)
+    {
+      tree selector = NULL_TREE;
+
+      if (token->type != CPP_COLON)
+       selector = cp_parser_objc_selector (parser);
+
+      /* Detect if we have a unary selector.  */
+      if (maybe_unary_selector_p
+         && cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+       {
+         sel_seq = selector;
+         goto finish_selector;
+       }
+
+      maybe_unary_selector_p = false;
+      cp_parser_require (parser, CPP_COLON, "`:'");
+
+      sel_seq
+       = chainon (sel_seq,
+                  build_tree_list (selector, NULL_TREE));
+
+      token = cp_lexer_peek_token (parser->lexer);
+    }
+
+ finish_selector:
+  cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+  return objc_build_selector_expr (sel_seq);
+}
+
+/* Parse a list of identifiers.
+
+   objc-identifier-list:
+     identifier
+     objc-identifier-list , identifier
+
+   Returns a TREE_LIST of identifier nodes.  */
+
+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);
+
+  while (sep->type == CPP_COMMA)
+    {
+      cp_lexer_consume_token (parser->lexer);  /* Eat ','.  */
+      list = chainon (list, 
+                     build_tree_list (NULL_TREE,
+                                      cp_parser_identifier (parser)));
+      sep = cp_lexer_peek_token (parser->lexer);
+    }
+    
+  return list;
+}
+
+/* Parse an Objective-C alias declaration.
+
+   objc-alias-declaration:
+     @compatibility_alias identifier identifier ;
+
+   This function registers the alias mapping with the Objective-C front-end.
+   It returns nothing.  */
+
+static void
+cp_parser_objc_alias_declaration (cp_parser* parser)
+{
+  tree alias, orig;
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@compatibility_alias'.  */
+  alias = cp_parser_identifier (parser);
+  orig = cp_parser_identifier (parser);
+  objc_declare_alias (alias, orig);
+  cp_parser_consume_semicolon_at_end_of_statement (parser);
+}
+
+/* Parse an Objective-C class forward-declaration.
+
+   objc-class-declaration:
+     @class objc-identifier-list ;
+
+   The function registers the forward declarations with the Objective-C
+   front-end.  It returns nothing.  */
+
+static void
+cp_parser_objc_class_declaration (cp_parser* parser)
+{
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@class'.  */
+  objc_declare_class (cp_parser_objc_identifier_list (parser));
+  cp_parser_consume_semicolon_at_end_of_statement (parser);
+}
+
+/* Parse a list of Objective-C protocol references.
+
+   objc-protocol-refs-opt:
+     objc-protocol-refs [opt]
+
+   objc-protocol-refs:
+     < objc-identifier-list >
+
+   Returns a TREE_LIST of identifiers, if any.  */
+
+static tree
+cp_parser_objc_protocol_refs_opt (cp_parser* parser)
+{
+  tree protorefs = NULL_TREE;
+
+  if(cp_lexer_next_token_is (parser->lexer, CPP_LESS))
+    {
+      cp_lexer_consume_token (parser->lexer);  /* Eat '<'.  */
+      protorefs = cp_parser_objc_identifier_list (parser);
+      cp_parser_require (parser, CPP_GREATER, "`>'");
+    }
+
+  return protorefs;
+}
+
+/* Parse a Objective-C visibility specification.  */
+
+static void
+cp_parser_objc_visibility_spec (cp_parser* parser)
+{
+  cp_token *vis = cp_lexer_peek_token (parser->lexer);
+
+  switch (vis->keyword)
+    {
+    case RID_AT_PRIVATE:
+      objc_set_visibility (2);
+      break;
+    case RID_AT_PROTECTED:
+      objc_set_visibility (0);
+      break;
+    case RID_AT_PUBLIC:
+      objc_set_visibility (1);
+      break;
+    default:
+      return;
+    }
+
+  /* Eat '@private'/'@protected'/'@public'.  */
+  cp_lexer_consume_token (parser->lexer);
+}
+
+/* Parse an Objective-C method type.  */
+
+static void
+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);
+}
+
+/* Parse an Objective-C protocol qualifier.  */
+
+static tree
+cp_parser_objc_protocol_qualifiers (cp_parser* parser)
+{
+  tree quals = NULL_TREE, node;
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+  node = token->value;
+
+  while (node && TREE_CODE (node) == IDENTIFIER_NODE
+        && (node == ridpointers [(int) RID_IN]
+            || node == ridpointers [(int) RID_OUT]
+            || node == ridpointers [(int) RID_INOUT]
+            || node == ridpointers [(int) RID_BYCOPY]
+             || node == ridpointers [(int) RID_BYREF]
+            || node == ridpointers [(int) RID_ONEWAY]))
+    {
+      quals = tree_cons (NULL_TREE, node, quals);
+      cp_lexer_consume_token (parser->lexer);
+      token = cp_lexer_peek_token (parser->lexer);
+      node = token->value;
+    }
+
+  return quals;
+}
+
+/* Parse an Objective-C typename.  */
+
+static tree
+cp_parser_objc_typename (cp_parser* parser)
+{
+  tree typename = NULL_TREE;
+
+  if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+    {
+      tree proto_quals, cp_type = NULL_TREE;
+
+      cp_lexer_consume_token (parser->lexer);  /* Eat '('.  */
+      proto_quals = cp_parser_objc_protocol_qualifiers (parser);
+
+      /* An ObjC type name may consist of just protocol qualifiers, in which
+        case the type shall default to 'id'.  */
+      if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
+       cp_type = cp_parser_type_id (parser);
+
+      cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+      typename = build_tree_list (proto_quals, cp_type);
+    }
+
+  return typename;
+}
+
+/* Check to see if TYPE refers to an Objective-C selector name.  */
+
+static bool
+cp_parser_objc_selector_p (enum cpp_ttype type)
+{
+  return (type == CPP_NAME || type == CPP_KEYWORD
+         || type == CPP_AND_AND || type == CPP_AND_EQ || type == CPP_AND
+         || type == CPP_OR || type == CPP_COMPL || type == CPP_NOT
+         || type == CPP_NOT_EQ || type == CPP_OR_OR || type == CPP_OR_EQ
+         || type == CPP_XOR || type == CPP_XOR_EQ);
+}
+
+/* Parse an Objective-C selector.  */
+
+static tree
+cp_parser_objc_selector (cp_parser* parser)
+{
+  cp_token *token = cp_lexer_consume_token (parser->lexer);
+  
+  if (!cp_parser_objc_selector_p (token->type))
+    {
+      error ("invalid Objective-C++ selector name");
+      return error_mark_node;
+    }
+
+  /* C++ operator names are allowed to appear in ObjC selectors.  */
+  switch (token->type)
+    {
+    case CPP_AND_AND: return get_identifier ("and");
+    case CPP_AND_EQ: return get_identifier ("and_eq");
+    case CPP_AND: return get_identifier ("bitand");
+    case CPP_OR: return get_identifier ("bitor");
+    case CPP_COMPL: return get_identifier ("compl");
+    case CPP_NOT: return get_identifier ("not");
+    case CPP_NOT_EQ: return get_identifier ("not_eq");
+    case CPP_OR_OR: return get_identifier ("or");
+    case CPP_OR_EQ: return get_identifier ("or_eq");
+    case CPP_XOR: return get_identifier ("xor");
+    case CPP_XOR_EQ: return get_identifier ("xor_eq");
+    default: return token->value;
+    }
+}
+
+/* Parse an Objective-C params list.  */
+
+static tree
+cp_parser_objc_method_keyword_params (cp_parser* parser)
+{
+  tree params = NULL_TREE;
+  bool maybe_unary_selector_p = true;
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+  while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON)
+    {
+      tree selector = NULL_TREE, typename, identifier;
+
+      if (token->type != CPP_COLON)
+       selector = cp_parser_objc_selector (parser);
+
+      /* Detect if we have a unary selector.  */
+      if (maybe_unary_selector_p
+         && cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
+       return selector;
+
+      maybe_unary_selector_p = false;
+      cp_parser_require (parser, CPP_COLON, "`:'");
+      typename = cp_parser_objc_typename (parser);
+      identifier = cp_parser_identifier (parser);
+
+      params
+       = chainon (params,
+                  objc_build_keyword_decl (selector, 
+                                           typename,
+                                           identifier));
+
+      token = cp_lexer_peek_token (parser->lexer);
+    }
+
+  return params;
+}
+
+/* Parse the non-keyword Objective-C params.  */
+
+static tree
+cp_parser_objc_method_tail_params_opt (cp_parser* parser, bool *ellipsisp)
+{
+  tree params = make_node (TREE_LIST);
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+  *ellipsisp = false;  /* Initially, assume no ellipsis.  */
+
+  while (token->type == CPP_COMMA)
+    {
+      cp_parameter_declarator *parmdecl;
+      tree parm;
+
+      cp_lexer_consume_token (parser->lexer);  /* Eat ','.  */
+      token = cp_lexer_peek_token (parser->lexer);
+
+      if (token->type == CPP_ELLIPSIS)
+       {
+         cp_lexer_consume_token (parser->lexer);  /* Eat '...'.  */
+         *ellipsisp = true;
+         break;
+       }
+
+      parmdecl = cp_parser_parameter_declaration (parser, false, NULL);
+      parm = grokdeclarator (parmdecl->declarator,
+                            &parmdecl->decl_specifiers,
+                            PARM, /*initialized=*/0, 
+                            /*attrlist=*/NULL);
+
+      chainon (params, build_tree_list (NULL_TREE, parm));
+      token = cp_lexer_peek_token (parser->lexer);
+    }
+
+  return params;
+}
+
+/* Parse a linkage specification, a pragma, an extra semicolon or a block.  */
+
+static void
+cp_parser_objc_interstitial_code (cp_parser* parser)
+{
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+  /* If the next token is `extern' and the following token is a string
+     literal, then we have a linkage specification.  */
+  if (token->keyword == RID_EXTERN
+      && cp_parser_is_string_literal (cp_lexer_peek_nth_token (parser->lexer, 2)))
+    cp_parser_linkage_specification (parser);
+  /* Handle #pragma, if any.  */
+  else if (token->type == CPP_PRAGMA)
+    cp_lexer_handle_pragma (parser->lexer);
+  /* Allow stray semicolons.  */
+  else if (token->type == CPP_SEMICOLON)
+    cp_lexer_consume_token (parser->lexer);
+  /* Finally, try to parse a block-declaration, or a function-definition.  */
+  else
+    cp_parser_block_declaration (parser, /*statement_p=*/false);
+}
+
+/* Parse a method signature.  */
+
+static tree
+cp_parser_objc_method_signature (cp_parser* parser)
+{
+  tree rettype, kwdparms, optparms;
+  bool ellipsis = false;
+
+  cp_parser_objc_method_type (parser);
+  rettype = cp_parser_objc_typename (parser);
+  kwdparms = cp_parser_objc_method_keyword_params (parser);
+  optparms = cp_parser_objc_method_tail_params_opt (parser, &ellipsis);
+
+  return objc_build_method_signature (rettype, kwdparms, optparms, ellipsis);
+}
+
+/* Pars an Objective-C method prototype list.  */
+
+static void
+cp_parser_objc_method_prototype_list (cp_parser* parser)
+{
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+  while (token->keyword != RID_AT_END)
+    {
+      if (token->type == CPP_PLUS || token->type == CPP_MINUS)
+       {
+         objc_add_method_declaration
+          (cp_parser_objc_method_signature (parser));
+         cp_parser_consume_semicolon_at_end_of_statement (parser);
+       }
+      else
+       /* Allow for interspersed non-ObjC++ code.  */
+       cp_parser_objc_interstitial_code (parser);
+
+      token = cp_lexer_peek_token (parser->lexer);
+    }
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@end'.  */
+  objc_finish_interface ();
+}
+
+/* Parse an Objective-C method definition list.  */
+
+static void
+cp_parser_objc_method_definition_list (cp_parser* parser)
+{
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+  while (token->keyword != RID_AT_END)
+    {
+      tree meth;
+
+      if (token->type == CPP_PLUS || token->type == CPP_MINUS)
+       {
+         push_deferring_access_checks (dk_deferred);
+         objc_start_method_definition
+          (cp_parser_objc_method_signature (parser));
+
+         /* For historical reasons, we accept an optional semicolon.  */
+         if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+           cp_lexer_consume_token (parser->lexer);
+
+         perform_deferred_access_checks ();
+         stop_deferring_access_checks ();
+         meth = cp_parser_function_definition_after_declarator (parser,
+                                                                false);
+         pop_deferring_access_checks ();
+         objc_finish_method_definition (meth);
+       }
+      else
+       /* Allow for interspersed non-ObjC++ code.  */
+       cp_parser_objc_interstitial_code (parser);
+
+      token = cp_lexer_peek_token (parser->lexer);
+    }
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@end'.  */
+  objc_finish_implementation ();
+}
+
+/* Parse Objective-C ivars.  */
+
+static void
+cp_parser_objc_class_ivars (cp_parser* parser)
+{
+  cp_token *token = cp_lexer_peek_token (parser->lexer);
+
+  if (token->type != CPP_OPEN_BRACE)
+    return;    /* No ivars specified.  */
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '{'.  */
+  token = cp_lexer_peek_token (parser->lexer);
+
+  while (token->type != CPP_CLOSE_BRACE)
+    {
+      cp_decl_specifier_seq declspecs;
+      int decl_class_or_enum_p;
+      tree prefix_attributes;
+
+      cp_parser_objc_visibility_spec (parser);
+
+      if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
+       break;
+
+      cp_parser_decl_specifier_seq (parser,
+                                   CP_PARSER_FLAGS_OPTIONAL,
+                                   &declspecs,
+                                   &decl_class_or_enum_p);
+      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 width = NULL_TREE, attributes, first_attribute, decl;
+         cp_declarator *declarator = NULL;
+         int ctor_dtor_or_conv_p;
+
+         /* Check for a (possibly unnamed) bitfield declaration.  */
+         token = cp_lexer_peek_token (parser->lexer);
+         if (token->type == CPP_COLON)
+           goto eat_colon;
+
+         if (token->type == CPP_NAME
+             && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
+                 == CPP_COLON))
+           {
+             /* Get the name of the bitfield.  */
+             declarator = make_id_declarator (NULL_TREE,
+                                              cp_parser_identifier (parser));
+
+            eat_colon:
+             cp_lexer_consume_token (parser->lexer);  /* Eat ':'.  */
+             /* Get the width of the bitfield.  */
+             width
+               = cp_parser_constant_expression (parser,
+                                                /*allow_non_constant=*/false,
+                                                NULL);
+           }
+         else
+           {
+             /* Parse the declarator.  */
+             declarator 
+               = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
+                                       &ctor_dtor_or_conv_p,
+                                       /*parenthesized_p=*/NULL,
+                                       /*member_p=*/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);
+
+         if (width)
+           {
+             /* Create the bitfield declaration.  */
+             decl = grokbitfield (declarator, &declspecs, width);
+             cplus_decl_attributes (&decl, attributes, /*flags=*/0);
+           }
+         else
+           decl = grokfield (declarator, &declspecs, NULL_TREE,
+                             NULL_TREE, attributes);
+         
+         /* Add the instance variable.  */
+         objc_add_instance_variable (decl);
+
+         /* Reset PREFIX_ATTRIBUTES.  */
+         while (attributes && TREE_CHAIN (attributes) != first_attribute)
+           attributes = TREE_CHAIN (attributes);
+         if (attributes)
+           TREE_CHAIN (attributes) = NULL_TREE;
+
+         token = cp_lexer_peek_token (parser->lexer);
+
+         if (token->type == CPP_COMMA)
+           {
+             cp_lexer_consume_token (parser->lexer);  /* Eat ','.  */
+             continue;
+           }
+         break;
+       }
+
+      cp_parser_consume_semicolon_at_end_of_statement (parser);
+      token = cp_lexer_peek_token (parser->lexer);
+    }
+
+  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);
+}
+
+/* Parse an Objective-C protocol declaration.  */
+
+static void
+cp_parser_objc_protocol_declaration (cp_parser* parser)
+{
+  tree proto, protorefs;
+  cp_token *tok;
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@protocol'.  */
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME))
+    {
+      error ("identifier expected after `@protocol'");
+      goto finish;
+    }
+
+  /* See if we have a foward declaration or a definition.  */
+  tok = cp_lexer_peek_nth_token (parser->lexer, 2);
+  
+  /* Try a forward declaration first.  */
+  if (tok->type == CPP_COMMA || tok->type == CPP_SEMICOLON)
+    {
+      objc_declare_protocols (cp_parser_objc_identifier_list (parser));
+     finish: 
+      cp_parser_consume_semicolon_at_end_of_statement (parser);
+    } 
+
+  /* Ok, we got a full-fledged definition (or at least should).  */
+  else
+    {
+      proto = cp_parser_identifier (parser);
+      protorefs = cp_parser_objc_protocol_refs_opt (parser);
+      objc_start_protocol (proto, protorefs);
+      cp_parser_objc_method_prototype_list (parser);
+    }
+}
+
+/* Parse an Objective-C superclass or category.  */
+
+static void
+cp_parser_objc_superclass_or_category (cp_parser *parser, tree *super,
+                                                         tree *categ)
+{
+  cp_token *next = cp_lexer_peek_token (parser->lexer);
+
+  *super = *categ = NULL_TREE;
+  if (next->type == CPP_COLON)
+    {
+      cp_lexer_consume_token (parser->lexer);  /* Eat ':'.  */
+      *super = cp_parser_identifier (parser);
+    }
+  else if (next->type == CPP_OPEN_PAREN)
+    {
+      cp_lexer_consume_token (parser->lexer);  /* Eat '('.  */
+      *categ = cp_parser_identifier (parser);
+      cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+    }
+}
+
+/* Parse an Objective-C class interface.  */
+
+static void
+cp_parser_objc_class_interface (cp_parser* parser)
+{
+  tree name, super, categ, protos;
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@interface'.  */
+  name = cp_parser_identifier (parser);
+  cp_parser_objc_superclass_or_category (parser, &super, &categ);
+  protos = cp_parser_objc_protocol_refs_opt (parser);
+
+  /* We have either a class or a category on our hands.  */
+  if (categ)
+    objc_start_category_interface (name, categ, protos);
+  else
+    {
+      objc_start_class_interface (name, super, protos);
+      /* Handle instance variable declarations, if any.  */
+      cp_parser_objc_class_ivars (parser);
+      objc_continue_interface ();
+    }
+
+  cp_parser_objc_method_prototype_list (parser);
+}
+
+/* Parse an Objective-C class implementation.  */
+
+static void
+cp_parser_objc_class_implementation (cp_parser* parser)
+{
+  tree name, super, categ;
+
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@implementation'.  */
+  name = cp_parser_identifier (parser);
+  cp_parser_objc_superclass_or_category (parser, &super, &categ);
+
+  /* We have either a class or a category on our hands.  */
+  if (categ)
+    objc_start_category_implementation (name, categ);
+  else
+    {
+      objc_start_class_implementation (name, super);
+      /* Handle instance variable declarations, if any.  */
+      cp_parser_objc_class_ivars (parser);
+      objc_continue_implementation ();
+    }
+
+  cp_parser_objc_method_definition_list (parser);
+}
+
+/* Consume the @end token and finish off the implementation.  */
+
+static void
+cp_parser_objc_end_implementation (cp_parser* parser)
+{
+  cp_lexer_consume_token (parser->lexer);  /* Eat '@end'.  */
+  objc_finish_implementation ();
+}
+
+/* Parse an Objective-C declaration.  */
+
+static void
+cp_parser_objc_declaration (cp_parser* parser)
+{
+  /* Try to figure out what kind of declaration is present.  */
+  cp_token *kwd = cp_lexer_peek_token (parser->lexer);
+
+  switch (kwd->keyword)
+    {
+    case RID_AT_ALIAS:
+      cp_parser_objc_alias_declaration (parser);
+      break;
+    case RID_AT_CLASS:
+      cp_parser_objc_class_declaration (parser);
+      break;
+    case RID_AT_PROTOCOL:
+      cp_parser_objc_protocol_declaration (parser);
+      break;
+    case RID_AT_INTERFACE:
+      cp_parser_objc_class_interface (parser);
+      break;
+    case RID_AT_IMPLEMENTATION:
+      cp_parser_objc_class_implementation (parser);
+      break;
+    case RID_AT_END:
+      cp_parser_objc_end_implementation (parser);
+      break;
+    default:
+      error ("misplaced `@%D' Objective-C++ construct", kwd->value);
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+    }
+}
+
+/* Parse an Objective-C try-catch-finally statement.
+
+   objc-try-catch-finally-stmt:
+     @try compound-statement objc-catch-clause-seq [opt]
+       objc-finally-clause [opt]
+
+   objc-catch-clause-seq:
+     objc-catch-clause objc-catch-clause-seq [opt]
+
+   objc-catch-clause:
+     @catch ( exception-declaration ) compound-statement
+
+   objc-finally-clause
+     @finally compound-statement
+
+   Returns NULL_TREE.  */
+
+static tree
+cp_parser_objc_try_catch_finally_statement (cp_parser *parser) {
+  location_t location;
+  tree stmt;
+
+  cp_parser_require_keyword (parser, RID_AT_TRY, "`@try'");
+  location = cp_lexer_peek_token (parser->lexer)->location;
+  /* NB: The @try block needs to be wrapped in its own STATEMENT_LIST
+     node, lest it get absorbed into the surrounding block.  */
+  stmt = push_stmt_list ();
+  cp_parser_compound_statement (parser, NULL, false);
+  objc_begin_try_stmt (location, pop_stmt_list (stmt));
+  
+  while (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_CATCH))
+    {
+      cp_parameter_declarator *parmdecl;
+      tree parm;
+
+      cp_lexer_consume_token (parser->lexer);
+      cp_parser_require (parser, CPP_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, "`)'");
+      objc_begin_catch_clause (parm);
+      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);
+      location = cp_lexer_peek_token (parser->lexer)->location;
+      /* NB: The @finally block needs to be wrapped in its own STATEMENT_LIST
+        node, lest it get absorbed into the surrounding block.  */
+      stmt = push_stmt_list ();
+      cp_parser_compound_statement (parser, NULL, false);
+      objc_build_finally_clause (location, pop_stmt_list (stmt));
+    }
+
+  return objc_finish_try_stmt ();
+}
+
+/* Parse an Objective-C synchronized statement.
+
+   objc-synchronized-stmt:
+     @synchronized ( expression ) compound-statement
+
+   Returns NULL_TREE.  */
+
+static tree
+cp_parser_objc_synchronized_statement (cp_parser *parser) {
+  location_t location;
+  tree lock, stmt;
+
+  cp_parser_require_keyword (parser, RID_AT_SYNCHRONIZED, "`@synchronized'");
+
+  location = cp_lexer_peek_token (parser->lexer)->location;
+  cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+  lock = cp_parser_expression (parser, false);
+  cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+
+  /* NB: The @synchronized block needs to be wrapped in its own STATEMENT_LIST
+     node, lest it get absorbed into the surrounding block.  */
+  stmt = push_stmt_list ();
+  cp_parser_compound_statement (parser, NULL, false);
+
+  return objc_build_synchronized (location, lock, pop_stmt_list (stmt));
+}
+
+/* Parse an Objective-C throw statement.
+
+   objc-throw-stmt:
+     @throw assignment-expression [opt] ;
+
+   Returns a constructed '@throw' statement.  */
+
+static tree
+cp_parser_objc_throw_statement (cp_parser *parser) {
+  tree expr = NULL_TREE;
+
+  cp_parser_require_keyword (parser, RID_AT_THROW, "`@throw'");
+
+  if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+    expr = cp_parser_assignment_expression (parser, false);
+
+  cp_parser_consume_semicolon_at_end_of_statement (parser);
+
+  return objc_build_throw_stmt (expr);
+}
+
+/* Parse an Objective-C statement.  */
+
+static tree
+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);
+
+  switch (kwd->keyword)
+    {
+    case RID_AT_TRY:
+      return cp_parser_objc_try_catch_finally_statement (parser);
+    case RID_AT_SYNCHRONIZED:
+      return cp_parser_objc_synchronized_statement (parser);
+    case RID_AT_THROW:
+      return cp_parser_objc_throw_statement (parser);
+    default:
+      error ("misplaced `@%D' Objective-C++ construct", kwd->value);
+      cp_parser_skip_to_end_of_block_or_statement (parser);
+    }
+
+  return error_mark_node;
+}
 \f
 /* The parser.  */