]> oss.titaniummirror.com Git - msp430-gcc.git/blobdiff - gcc/c-parser.c
Imported gcc-4.4.3
[msp430-gcc.git] / gcc / c-parser.c
diff --git a/gcc/c-parser.c b/gcc/c-parser.c
new file mode 100644 (file)
index 0000000..0f047de
--- /dev/null
@@ -0,0 +1,8282 @@
+/* Parser for C and Objective-C.
+   Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009
+   Free Software Foundation, Inc.
+
+   Parser actions based on the old Bison parser; structure somewhat
+   influenced by and fragments based on the C++ parser.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* TODO:
+
+   Make sure all relevant comments, and all relevant code from all
+   actions, brought over from old parser.  Verify exact correspondence
+   of syntax accepted.
+
+   Add testcases covering every input symbol in every state in old and
+   new parsers.
+
+   Include full syntax for GNU C, including erroneous cases accepted
+   with error messages, in syntax productions in comments.
+
+   Make more diagnostics in the front end generally take an explicit
+   location rather than implicitly using input_location.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "rtl.h"
+#include "langhooks.h"
+#include "input.h"
+#include "cpplib.h"
+#include "timevar.h"
+#include "c-pragma.h"
+#include "c-tree.h"
+#include "flags.h"
+#include "output.h"
+#include "toplev.h"
+#include "ggc.h"
+#include "c-common.h"
+#include "vec.h"
+#include "target.h"
+#include "cgraph.h"
+
+\f
+/* Initialization routine for this file.  */
+
+void
+c_parse_init (void)
+{
+  /* The only initialization required is of the reserved word
+     identifiers.  */
+  unsigned int i;
+  tree id;
+  int mask = 0;
+
+  mask |= D_CXXONLY;
+  if (!flag_isoc99)
+    mask |= D_C99;
+  if (flag_no_asm)
+    {
+      mask |= D_ASM | D_EXT;
+      if (!flag_isoc99)
+       mask |= D_EXT89;
+    }
+  if (!c_dialect_objc ())
+    mask |= D_OBJC | D_CXX_OBJC;
+
+  ridpointers = GGC_CNEWVEC (tree, (int) RID_MAX);
+  for (i = 0; i < num_c_common_reswords; i++)
+    {
+      /* If a keyword is disabled, do not enter it into the table
+        and so create a canonical spelling that isn't a keyword.  */
+      if (c_common_reswords[i].disable & mask)
+       {
+         if (warn_cxx_compat
+             && (c_common_reswords[i].disable & D_CXXWARN))
+           {
+             id = get_identifier (c_common_reswords[i].word);
+             C_SET_RID_CODE (id, RID_CXX_COMPAT_WARN);
+             C_IS_RESERVED_WORD (id) = 1;
+           }
+         continue;
+       }
+
+      id = get_identifier (c_common_reswords[i].word);
+      C_SET_RID_CODE (id, c_common_reswords[i].rid);
+      C_IS_RESERVED_WORD (id) = 1;
+      ridpointers [(int) c_common_reswords[i].rid] = id;
+    }
+}
+\f
+/* The C lexer intermediates between the lexer in cpplib and c-lex.c
+   and the C parser.  Unlike the C++ lexer, the parser structure
+   stores the lexer information instead of using a separate structure.
+   Identifiers are separated into ordinary identifiers, type names,
+   keywords and some other Objective-C types of identifiers, and some
+   look-ahead is maintained.
+
+   ??? It might be a good idea to lex the whole file up front (as for
+   C++).  It would then be possible to share more of the C and C++
+   lexer code, if desired.  */
+
+/* The following local token type is used.  */
+
+/* A keyword.  */
+#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
+
+/* More information about the type of a CPP_NAME token.  */
+typedef enum c_id_kind {
+  /* An ordinary identifier.  */
+  C_ID_ID,
+  /* An identifier declared as a typedef name.  */
+  C_ID_TYPENAME,
+  /* An identifier declared as an Objective-C class name.  */
+  C_ID_CLASSNAME,
+  /* Not an identifier.  */
+  C_ID_NONE
+} c_id_kind;
+
+/* A single C token after string literal concatenation and conversion
+   of preprocessing tokens to tokens.  */
+typedef struct c_token GTY (())
+{
+  /* The kind of token.  */
+  ENUM_BITFIELD (cpp_ttype) type : 8;
+  /* If this token is a CPP_NAME, this value indicates whether also
+     declared as some kind of type.  Otherwise, it is C_ID_NONE.  */
+  ENUM_BITFIELD (c_id_kind) id_kind : 8;
+  /* If this token is a keyword, this value indicates which keyword.
+     Otherwise, this value is RID_MAX.  */
+  ENUM_BITFIELD (rid) keyword : 8;
+  /* If this token is a CPP_PRAGMA, this indicates the pragma that
+     was seen.  Otherwise it is PRAGMA_NONE.  */
+  ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
+  /* The value associated with this token, if any.  */
+  tree value;
+  /* The location at which this token was found.  */
+  location_t location;
+} c_token;
+
+/* A parser structure recording information about the state and
+   context of parsing.  Includes lexer information with up to two
+   tokens of look-ahead; more are not needed for C.  */
+typedef struct c_parser GTY(())
+{
+  /* The look-ahead tokens.  */
+  c_token tokens[2];
+  /* How many look-ahead tokens are available (0, 1 or 2).  */
+  short tokens_avail;
+  /* True if a syntax error is being recovered from; false otherwise.
+     c_parser_error sets this flag.  It should clear this flag when
+     enough tokens have been consumed to recover from the error.  */
+  BOOL_BITFIELD error : 1;
+  /* True if we're processing a pragma, and shouldn't automatically
+     consume CPP_PRAGMA_EOL.  */
+  BOOL_BITFIELD in_pragma : 1;
+  /* True if we're parsing the outermost block of an if statement.  */
+  BOOL_BITFIELD in_if_block : 1;
+  /* True if we want to lex an untranslated string.  */
+  BOOL_BITFIELD lex_untranslated_string : 1;
+  /* Objective-C specific parser/lexer information.  */
+  BOOL_BITFIELD objc_pq_context : 1;
+  /* The following flag is needed to contextualize Objective-C lexical
+     analysis.  In some cases (e.g., 'int NSObject;'), it is
+     undesirable to bind an identifier to an Objective-C class, even
+     if a class with that name exists.  */
+  BOOL_BITFIELD objc_need_raw_identifier : 1;
+} c_parser;
+
+
+/* The actual parser and external interface.  ??? Does this need to be
+   garbage-collected?  */
+
+static GTY (()) c_parser *the_parser;
+
+
+/* Read in and lex a single token, storing it in *TOKEN.  */
+
+static void
+c_lex_one_token (c_parser *parser, c_token *token)
+{
+  timevar_push (TV_LEX);
+
+  token->type = c_lex_with_flags (&token->value, &token->location, NULL,
+                                 (parser->lex_untranslated_string
+                                  ? C_LEX_STRING_NO_TRANSLATE : 0));
+  token->id_kind = C_ID_NONE;
+  token->keyword = RID_MAX;
+  token->pragma_kind = PRAGMA_NONE;
+
+  switch (token->type)
+    {
+    case CPP_NAME:
+      {
+       tree decl;
+
+       bool objc_force_identifier = parser->objc_need_raw_identifier;
+       if (c_dialect_objc ())
+         parser->objc_need_raw_identifier = false;
+
+       if (C_IS_RESERVED_WORD (token->value))
+         {
+           enum rid rid_code = C_RID_CODE (token->value);
+
+           if (rid_code == RID_CXX_COMPAT_WARN)
+             {
+               warning_at (token->location,
+                           OPT_Wc___compat,
+                           "identifier %qs conflicts with C++ keyword",
+                           IDENTIFIER_POINTER (token->value));
+             }
+           else if (c_dialect_objc ())
+             {
+               if (!objc_is_reserved_word (token->value)
+                   && (!OBJC_IS_PQ_KEYWORD (rid_code)
+                       || parser->objc_pq_context))
+                 {
+                   /* Return the canonical spelling for this keyword.  */
+                   token->value = ridpointers[(int) rid_code];
+                   token->type = CPP_KEYWORD;
+                   token->keyword = rid_code;
+                   break;
+                 }
+             }
+           else
+             {
+               token->type = CPP_KEYWORD;
+               token->keyword = rid_code;
+               break;
+             }
+         }
+
+       decl = lookup_name (token->value);
+       if (decl)
+         {
+           if (TREE_CODE (decl) == TYPE_DECL)
+             {
+               token->id_kind = C_ID_TYPENAME;
+               break;
+             }
+         }
+       else if (c_dialect_objc ())
+         {
+           tree objc_interface_decl = objc_is_class_name (token->value);
+           /* Objective-C class names are in the same namespace as
+              variables and typedefs, and hence are shadowed by local
+              declarations.  */
+           if (objc_interface_decl
+               && (global_bindings_p ()
+                   || (!objc_force_identifier && !decl)))
+             {
+               token->value = objc_interface_decl;
+               token->id_kind = C_ID_CLASSNAME;
+               break;
+             }
+         }
+        token->id_kind = C_ID_ID;
+      }
+      break;
+    case CPP_AT_NAME:
+      /* This only happens in Objective-C; it must be a keyword.  */
+      token->type = CPP_KEYWORD;
+      token->keyword = C_RID_CODE (token->value);
+      break;
+    case CPP_COLON:
+    case CPP_COMMA:
+    case CPP_CLOSE_PAREN:
+    case CPP_SEMICOLON:
+      /* These tokens may affect the interpretation of any identifiers
+        following, if doing Objective-C.  */
+      if (c_dialect_objc ())
+       parser->objc_need_raw_identifier = false;
+      break;
+    case CPP_PRAGMA:
+      /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST.  */
+      token->pragma_kind = (enum pragma_kind) TREE_INT_CST_LOW (token->value);
+      token->value = NULL;
+      break;
+    default:
+      break;
+    }
+  timevar_pop (TV_LEX);
+}
+
+/* Return a pointer to the next token from PARSER, reading it in if
+   necessary.  */
+
+static inline c_token *
+c_parser_peek_token (c_parser *parser)
+{
+  if (parser->tokens_avail == 0)
+    {
+      c_lex_one_token (parser, &parser->tokens[0]);
+      parser->tokens_avail = 1;
+    }
+  return &parser->tokens[0];
+}
+
+/* Return true if the next token from PARSER has the indicated
+   TYPE.  */
+
+static inline bool
+c_parser_next_token_is (c_parser *parser, enum cpp_ttype type)
+{
+  return c_parser_peek_token (parser)->type == type;
+}
+
+/* Return true if the next token from PARSER does not have the
+   indicated TYPE.  */
+
+static inline bool
+c_parser_next_token_is_not (c_parser *parser, enum cpp_ttype type)
+{
+  return !c_parser_next_token_is (parser, type);
+}
+
+/* Return true if the next token from PARSER is the indicated
+   KEYWORD.  */
+
+static inline bool
+c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword)
+{
+  return c_parser_peek_token (parser)->keyword == keyword;
+}
+
+/* Return true if TOKEN can start a type name,
+   false otherwise.  */
+static bool
+c_token_starts_typename (c_token *token)
+{
+  switch (token->type)
+    {
+    case CPP_NAME:
+      switch (token->id_kind)
+       {
+       case C_ID_ID:
+         return false;
+       case C_ID_TYPENAME:
+         return true;
+       case C_ID_CLASSNAME:
+         gcc_assert (c_dialect_objc ());
+         return true;
+       default:
+         gcc_unreachable ();
+       }
+    case CPP_KEYWORD:
+      switch (token->keyword)
+       {
+       case RID_UNSIGNED:
+       case RID_LONG:
+       case RID_SHORT:
+       case RID_SIGNED:
+       case RID_COMPLEX:
+       case RID_INT:
+       case RID_CHAR:
+       case RID_FLOAT:
+       case RID_DOUBLE:
+       case RID_VOID:
+       case RID_DFLOAT32:
+       case RID_DFLOAT64:
+       case RID_DFLOAT128:
+       case RID_BOOL:
+       case RID_ENUM:
+       case RID_STRUCT:
+       case RID_UNION:
+       case RID_TYPEOF:
+       case RID_CONST:
+       case RID_VOLATILE:
+       case RID_RESTRICT:
+       case RID_ATTRIBUTE:
+       case RID_FRACT:
+       case RID_ACCUM:
+       case RID_SAT:
+         return true;
+       default:
+         return false;
+       }
+    case CPP_LESS:
+      if (c_dialect_objc ())
+       return true;
+      return false;
+    default:
+      return false;
+    }
+}
+
+/* Return true if the next token from PARSER can start a type name,
+   false otherwise.  */
+static inline bool
+c_parser_next_token_starts_typename (c_parser *parser)
+{
+  c_token *token = c_parser_peek_token (parser);
+  return c_token_starts_typename (token);
+}
+
+/* Return true if TOKEN can start declaration specifiers, false
+   otherwise.  */
+static bool
+c_token_starts_declspecs (c_token *token)
+{
+  switch (token->type)
+    {
+    case CPP_NAME:
+      switch (token->id_kind)
+       {
+       case C_ID_ID:
+         return false;
+       case C_ID_TYPENAME:
+         return true;
+       case C_ID_CLASSNAME:
+         gcc_assert (c_dialect_objc ());
+         return true;
+       default:
+         gcc_unreachable ();
+       }
+    case CPP_KEYWORD:
+      switch (token->keyword)
+       {
+       case RID_STATIC:
+       case RID_EXTERN:
+       case RID_REGISTER:
+       case RID_TYPEDEF:
+       case RID_INLINE:
+       case RID_AUTO:
+       case RID_THREAD:
+       case RID_UNSIGNED:
+       case RID_LONG:
+       case RID_SHORT:
+       case RID_SIGNED:
+       case RID_COMPLEX:
+       case RID_INT:
+       case RID_CHAR:
+       case RID_FLOAT:
+       case RID_DOUBLE:
+       case RID_VOID:
+       case RID_DFLOAT32:
+       case RID_DFLOAT64:
+       case RID_DFLOAT128:
+       case RID_BOOL:
+       case RID_ENUM:
+       case RID_STRUCT:
+       case RID_UNION:
+       case RID_TYPEOF:
+       case RID_CONST:
+       case RID_VOLATILE:
+       case RID_RESTRICT:
+       case RID_ATTRIBUTE:
+       case RID_FRACT:
+       case RID_ACCUM:
+       case RID_SAT:
+         return true;
+       default:
+         return false;
+       }
+    case CPP_LESS:
+      if (c_dialect_objc ())
+       return true;
+      return false;
+    default:
+      return false;
+    }
+}
+
+/* Return true if the next token from PARSER can start declaration
+   specifiers, false otherwise.  */
+static inline bool
+c_parser_next_token_starts_declspecs (c_parser *parser)
+{
+  c_token *token = c_parser_peek_token (parser);
+  return c_token_starts_declspecs (token);
+}
+
+/* Return a pointer to the next-but-one token from PARSER, reading it
+   in if necessary.  The next token is already read in.  */
+
+static c_token *
+c_parser_peek_2nd_token (c_parser *parser)
+{
+  if (parser->tokens_avail >= 2)
+    return &parser->tokens[1];
+  gcc_assert (parser->tokens_avail == 1);
+  gcc_assert (parser->tokens[0].type != CPP_EOF);
+  gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL);
+  c_lex_one_token (parser, &parser->tokens[1]);
+  parser->tokens_avail = 2;
+  return &parser->tokens[1];
+}
+
+/* Consume the next token from PARSER.  */
+
+static void
+c_parser_consume_token (c_parser *parser)
+{
+  gcc_assert (parser->tokens_avail >= 1);
+  gcc_assert (parser->tokens[0].type != CPP_EOF);
+  gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL);
+  gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA);
+  if (parser->tokens_avail == 2)
+    parser->tokens[0] = parser->tokens[1];
+  parser->tokens_avail--;
+}
+
+/* Expect the current token to be a #pragma.  Consume it and remember
+   that we've begun parsing a pragma.  */
+
+static void
+c_parser_consume_pragma (c_parser *parser)
+{
+  gcc_assert (!parser->in_pragma);
+  gcc_assert (parser->tokens_avail >= 1);
+  gcc_assert (parser->tokens[0].type == CPP_PRAGMA);
+  if (parser->tokens_avail == 2)
+    parser->tokens[0] = parser->tokens[1];
+  parser->tokens_avail--;
+  parser->in_pragma = true;
+}
+
+/* Update the globals input_location and in_system_header from
+   TOKEN.  */
+static inline void
+c_parser_set_source_position_from_token (c_token *token)
+{
+  if (token->type != CPP_EOF)
+    {
+      input_location = token->location;
+    }
+}
+
+/* Issue a diagnostic of the form
+      FILE:LINE: MESSAGE before TOKEN
+   where TOKEN is the next token in the input stream of PARSER.
+   MESSAGE (specified by the caller) is usually of the form "expected
+   OTHER-TOKEN".
+
+   Do not issue a diagnostic if still recovering from an error.
+
+   ??? This is taken from the C++ parser, but building up messages in
+   this way is not i18n-friendly and some other approach should be
+   used.  */
+
+static void
+c_parser_error (c_parser *parser, const char *gmsgid)
+{
+  c_token *token = c_parser_peek_token (parser);
+  if (parser->error)
+    return;
+  parser->error = true;
+  if (!gmsgid)
+    return;
+  /* This diagnostic makes more sense if it is tagged to the line of
+     the token we just peeked at.  */
+  c_parser_set_source_position_from_token (token);
+  c_parse_error (gmsgid,
+                /* Because c_parse_error does not understand
+                   CPP_KEYWORD, keywords are treated like
+                   identifiers.  */
+                (token->type == CPP_KEYWORD ? CPP_NAME : token->type),
+                token->value);
+}
+
+/* If the next token is of the indicated TYPE, consume it.  Otherwise,
+   issue the error MSGID.  If MSGID is NULL then a message has already
+   been produced and no message will be produced this time.  Returns
+   true if found, false otherwise.  */
+
+static bool
+c_parser_require (c_parser *parser,
+                 enum cpp_ttype type,
+                 const char *msgid)
+{
+  if (c_parser_next_token_is (parser, type))
+    {
+      c_parser_consume_token (parser);
+      return true;
+    }
+  else
+    {
+      c_parser_error (parser, msgid);
+      return false;
+    }
+}
+
+/* If the next token is the indicated keyword, consume it.  Otherwise,
+   issue the error MSGID.  Returns true if found, false otherwise.  */
+
+static bool
+c_parser_require_keyword (c_parser *parser,
+                         enum rid keyword,
+                         const char *msgid)
+{
+  if (c_parser_next_token_is_keyword (parser, keyword))
+    {
+      c_parser_consume_token (parser);
+      return true;
+    }
+  else
+    {
+      c_parser_error (parser, msgid);
+      return false;
+    }
+}
+
+/* Like c_parser_require, except that tokens will be skipped until the
+   desired token is found.  An error message is still produced if the
+   next token is not as expected.  If MSGID is NULL then a message has
+   already been produced and no message will be produced this
+   time.  */
+
+static void
+c_parser_skip_until_found (c_parser *parser,
+                          enum cpp_ttype type,
+                          const char *msgid)
+{
+  unsigned nesting_depth = 0;
+
+  if (c_parser_require (parser, type, msgid))
+    return;
+
+  /* Skip tokens until the desired token is found.  */
+  while (true)
+    {
+      /* Peek at the next token.  */
+      c_token *token = c_parser_peek_token (parser);
+      /* If we've reached the token we want, consume it and stop.  */
+      if (token->type == type && !nesting_depth)
+       {
+         c_parser_consume_token (parser);
+         break;
+       }
+
+      /* If we've run out of tokens, stop.  */
+      if (token->type == CPP_EOF)
+       return;
+      if (token->type == CPP_PRAGMA_EOL && parser->in_pragma)
+       return;
+      if (token->type == CPP_OPEN_BRACE
+         || token->type == CPP_OPEN_PAREN
+         || token->type == CPP_OPEN_SQUARE)
+       ++nesting_depth;
+      else if (token->type == CPP_CLOSE_BRACE
+              || token->type == CPP_CLOSE_PAREN
+              || token->type == CPP_CLOSE_SQUARE)
+       {
+         if (nesting_depth-- == 0)
+           break;
+       }
+      /* Consume this token.  */
+      c_parser_consume_token (parser);
+    }
+  parser->error = false;
+}
+
+/* Skip tokens until the end of a parameter is found, but do not
+   consume the comma, semicolon or closing delimiter.  */
+
+static void
+c_parser_skip_to_end_of_parameter (c_parser *parser)
+{
+  unsigned nesting_depth = 0;
+
+  while (true)
+    {
+      c_token *token = c_parser_peek_token (parser);
+      if ((token->type == CPP_COMMA || token->type == CPP_SEMICOLON)
+         && !nesting_depth)
+       break;
+      /* If we've run out of tokens, stop.  */
+      if (token->type == CPP_EOF)
+       return;
+      if (token->type == CPP_PRAGMA_EOL && parser->in_pragma)
+       return;
+      if (token->type == CPP_OPEN_BRACE
+         || token->type == CPP_OPEN_PAREN
+         || token->type == CPP_OPEN_SQUARE)
+       ++nesting_depth;
+      else if (token->type == CPP_CLOSE_BRACE
+              || token->type == CPP_CLOSE_PAREN
+              || token->type == CPP_CLOSE_SQUARE)
+       {
+         if (nesting_depth-- == 0)
+           break;
+       }
+      /* Consume this token.  */
+      c_parser_consume_token (parser);
+    }
+  parser->error = false;
+}
+
+/* Expect to be at the end of the pragma directive and consume an
+   end of line marker.  */
+
+static void
+c_parser_skip_to_pragma_eol (c_parser *parser)
+{
+  gcc_assert (parser->in_pragma);
+  parser->in_pragma = false;
+
+  if (!c_parser_require (parser, CPP_PRAGMA_EOL, "expected end of line"))
+    while (true)
+      {
+       c_token *token = c_parser_peek_token (parser);
+       if (token->type == CPP_EOF)
+         break;
+       if (token->type == CPP_PRAGMA_EOL)
+         {
+           c_parser_consume_token (parser);
+           break;
+         }
+       c_parser_consume_token (parser);
+      }
+
+  parser->error = false;
+}
+
+/* Skip tokens until we have consumed an entire block, or until we
+   have consumed a non-nested ';'.  */
+
+static void
+c_parser_skip_to_end_of_block_or_statement (c_parser *parser)
+{
+  unsigned nesting_depth = 0;
+  bool save_error = parser->error;
+
+  while (true)
+    {
+      c_token *token;
+
+      /* Peek at the next token.  */
+      token = c_parser_peek_token (parser);
+
+      switch (token->type)
+       {
+       case CPP_EOF:
+         return;
+
+       case CPP_PRAGMA_EOL:
+         if (parser->in_pragma)
+           return;
+         break;
+
+       case CPP_SEMICOLON:
+         /* If the next token is a ';', we have reached the
+            end of the statement.  */
+         if (!nesting_depth)
+           {
+             /* Consume the ';'.  */
+             c_parser_consume_token (parser);
+             goto finished;
+           }
+         break;
+
+       case CPP_CLOSE_BRACE:
+         /* If the next token is a non-nested '}', then we have
+            reached the end of the current block.  */
+         if (nesting_depth == 0 || --nesting_depth == 0)
+           {
+             c_parser_consume_token (parser);
+             goto finished;
+           }
+         break;
+
+       case CPP_OPEN_BRACE:
+         /* If it the next token is a '{', then we are entering a new
+            block.  Consume the entire block.  */
+         ++nesting_depth;
+         break;
+
+       case CPP_PRAGMA:
+         /* If we see a pragma, consume the whole thing at once.  We
+            have some safeguards against consuming pragmas willy-nilly.
+            Normally, we'd expect to be here with parser->error set,
+            which disables these safeguards.  But it's possible to get
+            here for secondary error recovery, after parser->error has
+            been cleared.  */
+         c_parser_consume_pragma (parser);
+         c_parser_skip_to_pragma_eol (parser);
+         parser->error = save_error;
+         continue;
+
+       default:
+         break;
+       }
+
+      c_parser_consume_token (parser);
+    }
+
+ finished:
+  parser->error = false;
+}
+
+/* CPP's options (initialized by c-opts.c).  */
+extern cpp_options *cpp_opts;
+
+/* Save the warning flags which are controlled by __extension__.  */
+
+static inline int
+disable_extension_diagnostics (void)
+{
+  int ret = (pedantic
+            | (warn_pointer_arith << 1)
+            | (warn_traditional << 2)
+            | (flag_iso << 3)
+            | (warn_long_long << 4)
+            | (cpp_opts->warn_long_long << 5));
+  cpp_opts->pedantic = pedantic = 0;
+  warn_pointer_arith = 0;
+  cpp_opts->warn_traditional = warn_traditional = 0;
+  flag_iso = 0;
+  warn_long_long = 0;
+  cpp_opts->warn_long_long = 0;
+  return ret;
+}
+
+/* Restore the warning flags which are controlled by __extension__.
+   FLAGS is the return value from disable_extension_diagnostics.  */
+
+static inline void
+restore_extension_diagnostics (int flags)
+{
+  cpp_opts->pedantic = pedantic = flags & 1;
+  warn_pointer_arith = (flags >> 1) & 1;
+  cpp_opts->warn_traditional = warn_traditional = (flags >> 2) & 1;
+  flag_iso = (flags >> 3) & 1;
+  warn_long_long = (flags >> 4) & 1;
+  cpp_opts->warn_long_long = (flags >> 5) & 1;
+}
+
+/* Possibly kinds of declarator to parse.  */
+typedef enum c_dtr_syn {
+  /* A normal declarator with an identifier.  */
+  C_DTR_NORMAL,
+  /* An abstract declarator (maybe empty).  */
+  C_DTR_ABSTRACT,
+  /* A parameter declarator: may be either, but after a type name does
+     not redeclare a typedef name as an identifier if it can
+     alternatively be interpreted as a typedef name; see DR#009,
+     applied in C90 TC1, omitted from C99 and reapplied in C99 TC2
+     following DR#249.  For example, given a typedef T, "int T" and
+     "int *T" are valid parameter declarations redeclaring T, while
+     "int (T)" and "int * (T)" and "int (T[])" and "int (T (int))" are
+     abstract declarators rather than involving redundant parentheses;
+     the same applies with attributes inside the parentheses before
+     "T".  */
+  C_DTR_PARM
+} c_dtr_syn;
+
+static void c_parser_external_declaration (c_parser *);
+static void c_parser_asm_definition (c_parser *);
+static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, bool);
+static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
+                               bool);
+static struct c_typespec c_parser_enum_specifier (c_parser *);
+static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);
+static tree c_parser_struct_declaration (c_parser *);
+static struct c_typespec c_parser_typeof_specifier (c_parser *);
+static struct c_declarator *c_parser_declarator (c_parser *, bool, c_dtr_syn,
+                                                bool *);
+static struct c_declarator *c_parser_direct_declarator (c_parser *, bool,
+                                                       c_dtr_syn, bool *);
+static struct c_declarator *c_parser_direct_declarator_inner (c_parser *,
+                                                             bool,
+                                                             struct c_declarator *);
+static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree);
+static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree);
+static struct c_parm *c_parser_parameter_declaration (c_parser *, tree);
+static tree c_parser_simple_asm_expr (c_parser *);
+static tree c_parser_attributes (c_parser *);
+static struct c_type_name *c_parser_type_name (c_parser *);
+static struct c_expr c_parser_initializer (c_parser *);
+static struct c_expr c_parser_braced_init (c_parser *, tree, bool);
+static void c_parser_initelt (c_parser *);
+static void c_parser_initval (c_parser *, struct c_expr *);
+static tree c_parser_compound_statement (c_parser *);
+static void c_parser_compound_statement_nostart (c_parser *);
+static void c_parser_label (c_parser *);
+static void c_parser_statement (c_parser *);
+static void c_parser_statement_after_labels (c_parser *);
+static void c_parser_if_statement (c_parser *);
+static void c_parser_switch_statement (c_parser *);
+static void c_parser_while_statement (c_parser *);
+static void c_parser_do_statement (c_parser *);
+static void c_parser_for_statement (c_parser *);
+static tree c_parser_asm_statement (c_parser *);
+static tree c_parser_asm_operands (c_parser *, bool);
+static tree c_parser_asm_clobbers (c_parser *);
+static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *);
+static struct c_expr c_parser_conditional_expression (c_parser *,
+                                                     struct c_expr *);
+static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *);
+static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
+static struct c_expr c_parser_unary_expression (c_parser *);
+static struct c_expr c_parser_sizeof_expression (c_parser *);
+static struct c_expr c_parser_alignof_expression (c_parser *);
+static struct c_expr c_parser_postfix_expression (c_parser *);
+static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
+                                                                  struct c_type_name *);
+static struct c_expr c_parser_postfix_expression_after_primary (c_parser *,
+                                                               struct c_expr);
+static struct c_expr c_parser_expression (c_parser *);
+static struct c_expr c_parser_expression_conv (c_parser *);
+static tree c_parser_expr_list (c_parser *, bool);
+static void c_parser_omp_construct (c_parser *);
+static void c_parser_omp_threadprivate (c_parser *);
+static void c_parser_omp_barrier (c_parser *);
+static void c_parser_omp_flush (c_parser *);
+static void c_parser_omp_taskwait (c_parser *);
+
+enum pragma_context { pragma_external, pragma_stmt, pragma_compound };
+static bool c_parser_pragma (c_parser *, enum pragma_context);
+
+/* These Objective-C parser functions are only ever called when
+   compiling Objective-C.  */
+static void c_parser_objc_class_definition (c_parser *);
+static void c_parser_objc_class_instance_variables (c_parser *);
+static void c_parser_objc_class_declaration (c_parser *);
+static void c_parser_objc_alias_declaration (c_parser *);
+static void c_parser_objc_protocol_definition (c_parser *);
+static enum tree_code c_parser_objc_method_type (c_parser *);
+static void c_parser_objc_method_definition (c_parser *);
+static void c_parser_objc_methodprotolist (c_parser *);
+static void c_parser_objc_methodproto (c_parser *);
+static tree c_parser_objc_method_decl (c_parser *);
+static tree c_parser_objc_type_name (c_parser *);
+static tree c_parser_objc_protocol_refs (c_parser *);
+static void c_parser_objc_try_catch_statement (c_parser *);
+static void c_parser_objc_synchronized_statement (c_parser *);
+static tree c_parser_objc_selector (c_parser *);
+static tree c_parser_objc_selector_arg (c_parser *);
+static tree c_parser_objc_receiver (c_parser *);
+static tree c_parser_objc_message_args (c_parser *);
+static tree c_parser_objc_keywordexpr (c_parser *);
+
+/* Parse a translation unit (C90 6.7, C99 6.9).
+
+   translation-unit:
+     external-declarations
+
+   external-declarations:
+     external-declaration
+     external-declarations external-declaration
+
+   GNU extensions:
+
+   translation-unit:
+     empty
+*/
+
+static void
+c_parser_translation_unit (c_parser *parser)
+{
+  if (c_parser_next_token_is (parser, CPP_EOF))
+    {
+      pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
+              "ISO C forbids an empty translation unit");
+    }
+  else
+    {
+      void *obstack_position = obstack_alloc (&parser_obstack, 0);
+      do
+       {
+         ggc_collect ();
+         c_parser_external_declaration (parser);
+         obstack_free (&parser_obstack, obstack_position);
+       }
+      while (c_parser_next_token_is_not (parser, CPP_EOF));
+    }
+}
+
+/* Parse an external declaration (C90 6.7, C99 6.9).
+
+   external-declaration:
+     function-definition
+     declaration
+
+   GNU extensions:
+
+   external-declaration:
+     asm-definition
+     ;
+     __extension__ external-declaration
+
+   Objective-C:
+
+   external-declaration:
+     objc-class-definition
+     objc-class-declaration
+     objc-alias-declaration
+     objc-protocol-definition
+     objc-method-definition
+     @end
+*/
+
+static void
+c_parser_external_declaration (c_parser *parser)
+{
+  int ext;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_KEYWORD:
+      switch (c_parser_peek_token (parser)->keyword)
+       {
+       case RID_EXTENSION:
+         ext = disable_extension_diagnostics ();
+         c_parser_consume_token (parser);
+         c_parser_external_declaration (parser);
+         restore_extension_diagnostics (ext);
+         break;
+       case RID_ASM:
+         c_parser_asm_definition (parser);
+         break;
+       case RID_AT_INTERFACE:
+       case RID_AT_IMPLEMENTATION:
+         gcc_assert (c_dialect_objc ());
+         c_parser_objc_class_definition (parser);
+         break;
+       case RID_CLASS:
+         gcc_assert (c_dialect_objc ());
+         c_parser_objc_class_declaration (parser);
+         break;
+       case RID_AT_ALIAS:
+         gcc_assert (c_dialect_objc ());
+         c_parser_objc_alias_declaration (parser);
+         break;
+       case RID_AT_PROTOCOL:
+         gcc_assert (c_dialect_objc ());
+         c_parser_objc_protocol_definition (parser);
+         break;
+       case RID_AT_END:
+         gcc_assert (c_dialect_objc ());
+         c_parser_consume_token (parser);
+         objc_finish_implementation ();
+         break;
+       default:
+         goto decl_or_fndef;
+       }
+      break;
+    case CPP_SEMICOLON:
+      pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
+              "ISO C does not allow extra %<;%> outside of a function");
+      c_parser_consume_token (parser);
+      break;
+    case CPP_PRAGMA:
+      c_parser_pragma (parser, pragma_external);
+      break;
+    case CPP_PLUS:
+    case CPP_MINUS:
+      if (c_dialect_objc ())
+       {
+         c_parser_objc_method_definition (parser);
+         break;
+       }
+      /* Else fall through, and yield a syntax error trying to parse
+        as a declaration or function definition.  */
+    default:
+    decl_or_fndef:
+      /* A declaration or a function definition.  We can only tell
+        which after parsing the declaration specifiers, if any, and
+        the first declarator.  */
+      c_parser_declaration_or_fndef (parser, true, true, false, true);
+      break;
+    }
+}
+
+
+/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
+   6.7, 6.9.1).  If FNDEF_OK is true, a function definition is
+   accepted; otherwise (old-style parameter declarations) only other
+   declarations are accepted.  If NESTED is true, we are inside a
+   function or parsing old-style parameter declarations; any functions
+   encountered are nested functions and declaration specifiers are
+   required; otherwise we are at top level and functions are normal
+   functions and declaration specifiers may be optional.  If EMPTY_OK
+   is true, empty declarations are OK (subject to all other
+   constraints); otherwise (old-style parameter declarations) they are
+   diagnosed.  If START_ATTR_OK is true, the declaration specifiers
+   may start with attributes; otherwise they may not.
+
+   declaration:
+     declaration-specifiers init-declarator-list[opt] ;
+
+   function-definition:
+     declaration-specifiers[opt] declarator declaration-list[opt]
+       compound-statement
+
+   declaration-list:
+     declaration
+     declaration-list declaration
+
+   init-declarator-list:
+     init-declarator
+     init-declarator-list , init-declarator
+
+   init-declarator:
+     declarator simple-asm-expr[opt] attributes[opt]
+     declarator simple-asm-expr[opt] attributes[opt] = initializer
+
+   GNU extensions:
+
+   nested-function-definition:
+     declaration-specifiers declarator declaration-list[opt]
+       compound-statement
+
+   The simple-asm-expr and attributes are GNU extensions.
+
+   This function does not handle __extension__; that is handled in its
+   callers.  ??? Following the old parser, __extension__ may start
+   external declarations, declarations in functions and declarations
+   at the start of "for" loops, but not old-style parameter
+   declarations.
+
+   C99 requires declaration specifiers in a function definition; the
+   absence is diagnosed through the diagnosis of implicit int.  In GNU
+   C we also allow but diagnose declarations without declaration
+   specifiers, but only at top level (elsewhere they conflict with
+   other syntax).
+   
+   OpenMP:
+   
+   declaration:
+     threadprivate-directive  */
+
+static void
+c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok,
+                              bool nested, bool start_attr_ok)
+{
+  struct c_declspecs *specs;
+  tree prefix_attrs;
+  tree all_prefix_attrs;
+  bool diagnosed_no_specs = false;
+  location_t here = c_parser_peek_token (parser)->location;
+
+  specs = build_null_declspecs ();
+  c_parser_declspecs (parser, specs, true, true, start_attr_ok);
+  if (parser->error)
+    {
+      c_parser_skip_to_end_of_block_or_statement (parser);
+      return;
+    }
+  if (nested && !specs->declspecs_seen_p)
+    {
+      c_parser_error (parser, "expected declaration specifiers");
+      c_parser_skip_to_end_of_block_or_statement (parser);
+      return;
+    }
+  finish_declspecs (specs);
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+    {
+      if (empty_ok)
+       shadow_tag (specs);
+      else
+       {
+         shadow_tag_warned (specs, 1);
+         pedwarn (here, 0, "empty declaration");
+       }
+      c_parser_consume_token (parser);
+      return;
+    }
+  pending_xref_error ();
+  prefix_attrs = specs->attrs;
+  all_prefix_attrs = prefix_attrs;
+  specs->attrs = NULL_TREE;
+  while (true)
+    {
+      struct c_declarator *declarator;
+      bool dummy = false;
+      tree fnbody;
+      /* Declaring either one or more declarators (in which case we
+        should diagnose if there were no declaration specifiers) or a
+        function definition (in which case the diagnostic for
+        implicit int suffices).  */
+      declarator = c_parser_declarator (parser, specs->type_seen_p,
+                                       C_DTR_NORMAL, &dummy);
+      if (declarator == NULL)
+       {
+         c_parser_skip_to_end_of_block_or_statement (parser);
+         return;
+       }
+      if (c_parser_next_token_is (parser, CPP_EQ)
+         || c_parser_next_token_is (parser, CPP_COMMA)
+         || c_parser_next_token_is (parser, CPP_SEMICOLON)
+         || c_parser_next_token_is_keyword (parser, RID_ASM)
+         || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+       {
+         tree asm_name = NULL_TREE;
+         tree postfix_attrs = NULL_TREE;
+         if (!diagnosed_no_specs && !specs->declspecs_seen_p)
+           {
+             diagnosed_no_specs = true;
+             pedwarn (here, 0, "data definition has no type or storage class");
+           }
+         /* Having seen a data definition, there cannot now be a
+            function definition.  */
+         fndef_ok = false;
+         if (c_parser_next_token_is_keyword (parser, RID_ASM))
+           asm_name = c_parser_simple_asm_expr (parser);
+         if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+           postfix_attrs = c_parser_attributes (parser);
+         if (c_parser_next_token_is (parser, CPP_EQ))
+           {
+             tree d;
+             struct c_expr init;
+             c_parser_consume_token (parser);
+             /* The declaration of the variable is in effect while
+                its initializer is parsed.  */
+             d = start_decl (declarator, specs, true,
+                             chainon (postfix_attrs, all_prefix_attrs));
+             if (!d)
+               d = error_mark_node;
+             start_init (d, asm_name, global_bindings_p ());
+             init = c_parser_initializer (parser);
+             finish_init ();
+             if (d != error_mark_node)
+               {
+                 maybe_warn_string_init (TREE_TYPE (d), init);
+                 finish_decl (d, init.value, asm_name);
+               }
+           }
+         else
+           {
+             tree d = start_decl (declarator, specs, false,
+                                  chainon (postfix_attrs,
+                                           all_prefix_attrs));
+             if (d)
+               finish_decl (d, NULL_TREE, asm_name);
+           }
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           {
+             c_parser_consume_token (parser);
+             if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+               all_prefix_attrs = chainon (c_parser_attributes (parser),
+                                           prefix_attrs);
+             else
+               all_prefix_attrs = prefix_attrs;
+             continue;
+           }
+         else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+           {
+             c_parser_consume_token (parser);
+             return;
+           }
+         else
+           {
+             c_parser_error (parser, "expected %<,%> or %<;%>");
+             c_parser_skip_to_end_of_block_or_statement (parser);
+             return;
+           }
+       }
+      else if (!fndef_ok)
+       {
+         c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, "
+                         "%<asm%> or %<__attribute__%>");
+         c_parser_skip_to_end_of_block_or_statement (parser);
+         return;
+       }
+      /* Function definition (nested or otherwise).  */
+      if (nested)
+       {
+         pedwarn (here, OPT_pedantic, "ISO C forbids nested functions");
+         c_push_function_context ();
+       }
+      if (!start_function (specs, declarator, all_prefix_attrs))
+       {
+         /* This can appear in many cases looking nothing like a
+            function definition, so we don't give a more specific
+            error suggesting there was one.  */
+         c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, %<asm%> "
+                         "or %<__attribute__%>");
+         if (nested)
+           c_pop_function_context ();
+         break;
+       }
+      /* Parse old-style parameter declarations.  ??? Attributes are
+        not allowed to start declaration specifiers here because of a
+        syntax conflict between a function declaration with attribute
+        suffix and a function definition with an attribute prefix on
+        first old-style parameter declaration.  Following the old
+        parser, they are not accepted on subsequent old-style
+        parameter declarations either.  However, there is no
+        ambiguity after the first declaration, nor indeed on the
+        first as long as we don't allow postfix attributes after a
+        declarator with a nonempty identifier list in a definition;
+        and postfix attributes have never been accepted here in
+        function definitions either.  */
+      while (c_parser_next_token_is_not (parser, CPP_EOF)
+            && c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
+       c_parser_declaration_or_fndef (parser, false, false, true, false);
+      store_parm_decls ();
+      DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
+       = c_parser_peek_token (parser)->location;
+      fnbody = c_parser_compound_statement (parser);
+      if (nested)
+       {
+         tree decl = current_function_decl;
+         add_stmt (fnbody);
+         finish_function ();
+         c_pop_function_context ();
+         add_stmt (build_stmt (DECL_EXPR, decl));
+       }
+      else
+       {
+         add_stmt (fnbody);
+         finish_function ();
+       }
+      break;
+    }
+}
+
+/* Parse an asm-definition (asm() outside a function body).  This is a
+   GNU extension.
+
+   asm-definition:
+     simple-asm-expr ;
+*/
+
+static void
+c_parser_asm_definition (c_parser *parser)
+{
+  tree asm_str = c_parser_simple_asm_expr (parser);
+  if (asm_str)
+    cgraph_add_asm_node (asm_str);
+  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+}
+
+/* Parse some declaration specifiers (possibly none) (C90 6.5, C99
+   6.7), adding them to SPECS (which may already include some).
+   Storage class specifiers are accepted iff SCSPEC_OK; type
+   specifiers are accepted iff TYPESPEC_OK; attributes are accepted at
+   the start iff START_ATTR_OK.
+
+   declaration-specifiers:
+     storage-class-specifier declaration-specifiers[opt]
+     type-specifier declaration-specifiers[opt]
+     type-qualifier declaration-specifiers[opt]
+     function-specifier declaration-specifiers[opt]
+
+   Function specifiers (inline) are from C99, and are currently
+   handled as storage class specifiers, as is __thread.
+
+   C90 6.5.1, C99 6.7.1:
+   storage-class-specifier:
+     typedef
+     extern
+     static
+     auto
+     register
+
+   C99 6.7.4:
+   function-specifier:
+     inline
+
+   C90 6.5.2, C99 6.7.2:
+   type-specifier:
+     void
+     char
+     short
+     int
+     long
+     float
+     double
+     signed
+     unsigned
+     _Bool
+     _Complex
+     [_Imaginary removed in C99 TC2]
+     struct-or-union-specifier
+     enum-specifier
+     typedef-name
+
+   (_Bool and _Complex are new in C99.)
+
+   C90 6.5.3, C99 6.7.3:
+
+   type-qualifier:
+     const
+     restrict
+     volatile
+
+   (restrict is new in C99.)
+
+   GNU extensions:
+
+   declaration-specifiers:
+     attributes declaration-specifiers[opt]
+
+   storage-class-specifier:
+     __thread
+
+   type-specifier:
+     typeof-specifier
+     _Decimal32
+     _Decimal64
+     _Decimal128
+     _Fract
+     _Accum
+     _Sat
+
+  (_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037:
+   http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf)
+
+   Objective-C:
+
+   type-specifier:
+     class-name objc-protocol-refs[opt]
+     typedef-name objc-protocol-refs
+     objc-protocol-refs
+*/
+
+static void
+c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
+                   bool scspec_ok, bool typespec_ok, bool start_attr_ok)
+{
+  bool attrs_ok = start_attr_ok;
+  bool seen_type = specs->type_seen_p;
+  while (c_parser_next_token_is (parser, CPP_NAME)
+        || c_parser_next_token_is (parser, CPP_KEYWORD)
+        || (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS)))
+    {
+      struct c_typespec t;
+      tree attrs;
+      if (c_parser_next_token_is (parser, CPP_NAME))
+       {
+         tree value = c_parser_peek_token (parser)->value;
+         c_id_kind kind = c_parser_peek_token (parser)->id_kind;
+         /* This finishes the specifiers unless a type name is OK, it
+            is declared as a type name and a type name hasn't yet
+            been seen.  */
+         if (!typespec_ok || seen_type
+             || (kind != C_ID_TYPENAME && kind != C_ID_CLASSNAME))
+           break;
+         c_parser_consume_token (parser);
+         seen_type = true;
+         attrs_ok = true;
+         if (kind == C_ID_TYPENAME
+             && (!c_dialect_objc ()
+                 || c_parser_next_token_is_not (parser, CPP_LESS)))
+           {
+             t.kind = ctsk_typedef;
+             /* For a typedef name, record the meaning, not the name.
+                In case of 'foo foo, bar;'.  */
+             t.spec = lookup_name (value);
+           }
+         else
+           {
+             tree proto = NULL_TREE;
+             gcc_assert (c_dialect_objc ());
+             t.kind = ctsk_objc;
+             if (c_parser_next_token_is (parser, CPP_LESS))
+               proto = c_parser_objc_protocol_refs (parser);
+             t.spec = objc_get_protocol_qualified_type (value, proto);
+           }
+         declspecs_add_type (specs, t);
+         continue;
+       }
+      if (c_parser_next_token_is (parser, CPP_LESS))
+       {
+         /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>" -
+            nisse@lysator.liu.se.  */
+         tree proto;
+         gcc_assert (c_dialect_objc ());
+         if (!typespec_ok || seen_type)
+           break;
+         proto = c_parser_objc_protocol_refs (parser);
+         t.kind = ctsk_objc;
+         t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto);
+         declspecs_add_type (specs, t);
+         continue;
+       }
+      gcc_assert (c_parser_next_token_is (parser, CPP_KEYWORD));
+      switch (c_parser_peek_token (parser)->keyword)
+       {
+       case RID_STATIC:
+       case RID_EXTERN:
+       case RID_REGISTER:
+       case RID_TYPEDEF:
+       case RID_INLINE:
+       case RID_AUTO:
+       case RID_THREAD:
+         if (!scspec_ok)
+           goto out;
+         attrs_ok = true;
+         /* TODO: Distinguish between function specifiers (inline)
+            and storage class specifiers, either here or in
+            declspecs_add_scspec.  */
+         declspecs_add_scspec (specs, c_parser_peek_token (parser)->value);
+         c_parser_consume_token (parser);
+         break;
+       case RID_UNSIGNED:
+       case RID_LONG:
+       case RID_SHORT:
+       case RID_SIGNED:
+       case RID_COMPLEX:
+       case RID_INT:
+       case RID_CHAR:
+       case RID_FLOAT:
+       case RID_DOUBLE:
+       case RID_VOID:
+       case RID_DFLOAT32:
+       case RID_DFLOAT64:
+       case RID_DFLOAT128:
+       case RID_BOOL:
+       case RID_FRACT:
+       case RID_ACCUM:
+       case RID_SAT:
+         if (!typespec_ok)
+           goto out;
+         attrs_ok = true;
+         seen_type = true;
+         if (c_dialect_objc ())
+           parser->objc_need_raw_identifier = true;
+         t.kind = ctsk_resword;
+         t.spec = c_parser_peek_token (parser)->value;
+         declspecs_add_type (specs, t);
+         c_parser_consume_token (parser);
+         break;
+       case RID_ENUM:
+         if (!typespec_ok)
+           goto out;
+         attrs_ok = true;
+         seen_type = true;
+         t = c_parser_enum_specifier (parser);
+         declspecs_add_type (specs, t);
+         break;
+       case RID_STRUCT:
+       case RID_UNION:
+         if (!typespec_ok)
+           goto out;
+         attrs_ok = true;
+         seen_type = true;
+         t = c_parser_struct_or_union_specifier (parser);
+         declspecs_add_type (specs, t);
+         break;
+       case RID_TYPEOF:
+         /* ??? The old parser rejected typeof after other type
+            specifiers, but is a syntax error the best way of
+            handling this?  */
+         if (!typespec_ok || seen_type)
+           goto out;
+         attrs_ok = true;
+         seen_type = true;
+         t = c_parser_typeof_specifier (parser);
+         declspecs_add_type (specs, t);
+         break;
+       case RID_CONST:
+       case RID_VOLATILE:
+       case RID_RESTRICT:
+         attrs_ok = true;
+         declspecs_add_qual (specs, c_parser_peek_token (parser)->value);
+         c_parser_consume_token (parser);
+         break;
+       case RID_ATTRIBUTE:
+         if (!attrs_ok)
+           goto out;
+         attrs = c_parser_attributes (parser);
+         declspecs_add_attrs (specs, attrs);
+         break;
+       default:
+         goto out;
+       }
+    }
+ out: ;
+}
+
+/* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2).
+
+   enum-specifier:
+     enum attributes[opt] identifier[opt] { enumerator-list } attributes[opt]
+     enum attributes[opt] identifier[opt] { enumerator-list , } attributes[opt]
+     enum attributes[opt] identifier
+
+   The form with trailing comma is new in C99.  The forms with
+   attributes are GNU extensions.  In GNU C, we accept any expression
+   without commas in the syntax (assignment expressions, not just
+   conditional expressions); assignment expressions will be diagnosed
+   as non-constant.
+
+   enumerator-list:
+     enumerator
+     enumerator-list , enumerator
+
+   enumerator:
+     enumeration-constant
+     enumeration-constant = constant-expression
+*/
+
+static struct c_typespec
+c_parser_enum_specifier (c_parser *parser)
+{
+  struct c_typespec ret;
+  tree attrs;
+  tree ident = NULL_TREE;
+  location_t ident_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM));
+  c_parser_consume_token (parser);
+  attrs = c_parser_attributes (parser);
+  /* Set the location in case we create a decl now.  */
+  c_parser_set_source_position_from_token (c_parser_peek_token (parser));
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      ident = c_parser_peek_token (parser)->value;
+      ident_loc = c_parser_peek_token (parser)->location;
+      c_parser_consume_token (parser);
+    }
+  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    {
+      /* Parse an enum definition.  */
+      struct c_enum_contents the_enum;
+      tree type = start_enum (&the_enum, ident);
+      tree postfix_attrs;
+      /* We chain the enumerators in reverse order, then put them in
+        forward order at the end.  */
+      tree values = NULL_TREE;
+      c_parser_consume_token (parser);
+      while (true)
+       {
+         tree enum_id;
+         tree enum_value;
+         tree enum_decl;
+         bool seen_comma;
+         c_token *token;
+         location_t comma_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
+         location_t value_loc;
+         if (c_parser_next_token_is_not (parser, CPP_NAME))
+           {
+             c_parser_error (parser, "expected identifier");
+             c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+             values = error_mark_node;
+             break;
+           }
+         token = c_parser_peek_token (parser);
+         enum_id = token->value;
+         /* Set the location in case we create a decl now.  */
+         c_parser_set_source_position_from_token (token);
+         value_loc = token->location;
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_EQ))
+           {
+             c_parser_consume_token (parser);
+             value_loc = c_parser_peek_token (parser)->location;
+             enum_value = c_parser_expr_no_commas (parser, NULL).value;
+           }
+         else
+           enum_value = NULL_TREE;
+         enum_decl = build_enumerator (&the_enum, enum_id, enum_value, 
+                                       value_loc);
+         TREE_CHAIN (enum_decl) = values;
+         values = enum_decl;
+         seen_comma = false;
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           {
+             comma_loc = c_parser_peek_token (parser)->location;
+             seen_comma = true;
+             c_parser_consume_token (parser);
+           }
+         if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+           {
+             if (seen_comma && !flag_isoc99)
+               pedwarn (comma_loc, OPT_pedantic, "comma at end of enumerator list");
+             c_parser_consume_token (parser);
+             break;
+           }
+         if (!seen_comma)
+           {
+             c_parser_error (parser, "expected %<,%> or %<}%>");
+             c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+             values = error_mark_node;
+             break;
+           }
+       }
+      postfix_attrs = c_parser_attributes (parser);
+      ret.spec = finish_enum (type, nreverse (values),
+                             chainon (attrs, postfix_attrs));
+      ret.kind = ctsk_tagdef;
+      return ret;
+    }
+  else if (!ident)
+    {
+      c_parser_error (parser, "expected %<{%>");
+      ret.spec = error_mark_node;
+      ret.kind = ctsk_tagref;
+      return ret;
+    }
+  ret = parser_xref_tag (ENUMERAL_TYPE, ident);
+  /* In ISO C, enumerated types can be referred to only if already
+     defined.  */
+  if (pedantic && !COMPLETE_TYPE_P (ret.spec))
+    {
+      gcc_assert (ident);
+      pedwarn (ident_loc, OPT_pedantic,
+              "ISO C forbids forward references to %<enum%> types");
+    }
+  return ret;
+}
+
+/* Parse a struct or union specifier (C90 6.5.2.1, C99 6.7.2.1).
+
+   struct-or-union-specifier:
+     struct-or-union attributes[opt] identifier[opt]
+       { struct-contents } attributes[opt]
+     struct-or-union attributes[opt] identifier
+
+   struct-contents:
+     struct-declaration-list
+
+   struct-declaration-list:
+     struct-declaration ;
+     struct-declaration-list struct-declaration ;
+
+   GNU extensions:
+
+   struct-contents:
+     empty
+     struct-declaration
+     struct-declaration-list struct-declaration
+
+   struct-declaration-list:
+     struct-declaration-list ;
+     ;
+
+   (Note that in the syntax here, unlike that in ISO C, the semicolons
+   are included here rather than in struct-declaration, in order to
+   describe the syntax with extra semicolons and missing semicolon at
+   end.)
+
+   Objective-C:
+
+   struct-declaration-list:
+     @defs ( class-name )
+
+   (Note this does not include a trailing semicolon, but can be
+   followed by further declarations, and gets a pedwarn-if-pedantic
+   when followed by a semicolon.)  */
+
+static struct c_typespec
+c_parser_struct_or_union_specifier (c_parser *parser)
+{
+  struct c_typespec ret;
+  tree attrs;
+  tree ident = NULL_TREE;
+  enum tree_code code;
+  switch (c_parser_peek_token (parser)->keyword)
+    {
+    case RID_STRUCT:
+      code = RECORD_TYPE;
+      break;
+    case RID_UNION:
+      code = UNION_TYPE;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  c_parser_consume_token (parser);
+  attrs = c_parser_attributes (parser);
+  /* Set the location in case we create a decl now.  */
+  c_parser_set_source_position_from_token (c_parser_peek_token (parser));
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      ident = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+    }
+  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    {
+      /* Parse a struct or union definition.  Start the scope of the
+        tag before parsing components.  */
+      tree type = start_struct (code, ident);
+      tree postfix_attrs;
+      /* We chain the components in reverse order, then put them in
+        forward order at the end.  Each struct-declaration may
+        declare multiple components (comma-separated), so we must use
+        chainon to join them, although when parsing each
+        struct-declaration we can use TREE_CHAIN directly.
+
+        The theory behind all this is that there will be more
+        semicolon separated fields than comma separated fields, and
+        so we'll be minimizing the number of node traversals required
+        by chainon.  */
+      tree contents = NULL_TREE;
+      c_parser_consume_token (parser);
+      /* Handle the Objective-C @defs construct,
+        e.g. foo(sizeof(struct{ @defs(ClassName) }));.  */
+      if (c_parser_next_token_is_keyword (parser, RID_AT_DEFS))
+       {
+         tree name;
+         gcc_assert (c_dialect_objc ());
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           goto end_at_defs;
+         if (c_parser_next_token_is (parser, CPP_NAME)
+             && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)
+           {
+             name = c_parser_peek_token (parser)->value;
+             c_parser_consume_token (parser);
+           }
+         else
+           {
+             c_parser_error (parser, "expected class name");
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             goto end_at_defs;
+           }
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         contents = nreverse (objc_get_class_ivars (name));
+       }
+    end_at_defs:
+      /* Parse the struct-declarations and semicolons.  Problems with
+        semicolons are diagnosed here; empty structures are diagnosed
+        elsewhere.  */
+      while (true)
+       {
+         tree decls;
+         /* Parse any stray semicolon.  */
+         if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+           {
+             pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
+                      "extra semicolon in struct or union specified");
+             c_parser_consume_token (parser);
+             continue;
+           }
+         /* Stop if at the end of the struct or union contents.  */
+         if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+           {
+             c_parser_consume_token (parser);
+             break;
+           }
+         /* Accept #pragmas at struct scope.  */
+         if (c_parser_next_token_is (parser, CPP_PRAGMA))
+           {
+             c_parser_pragma (parser, pragma_external);
+             continue;
+           }
+         /* Parse some comma-separated declarations, but not the
+            trailing semicolon if any.  */
+         decls = c_parser_struct_declaration (parser);
+         contents = chainon (decls, contents);
+         /* If no semicolon follows, either we have a parse error or
+            are at the end of the struct or union and should
+            pedwarn.  */
+         if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+           c_parser_consume_token (parser);
+         else
+           {
+             if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+               pedwarn (c_parser_peek_token (parser)->location, 0, 
+                        "no semicolon at end of struct or union");
+             else
+               {
+                 c_parser_error (parser, "expected %<;%>");
+                 c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+                 break;
+               }
+           }
+       }
+      postfix_attrs = c_parser_attributes (parser);
+      ret.spec = finish_struct (type, nreverse (contents),
+                               chainon (attrs, postfix_attrs));
+      ret.kind = ctsk_tagdef;
+      return ret;
+    }
+  else if (!ident)
+    {
+      c_parser_error (parser, "expected %<{%>");
+      ret.spec = error_mark_node;
+      ret.kind = ctsk_tagref;
+      return ret;
+    }
+  ret = parser_xref_tag (code, ident);
+  return ret;
+}
+
+/* Parse a struct-declaration (C90 6.5.2.1, C99 6.7.2.1), *without*
+   the trailing semicolon.
+
+   struct-declaration:
+     specifier-qualifier-list struct-declarator-list
+
+   specifier-qualifier-list:
+     type-specifier specifier-qualifier-list[opt]
+     type-qualifier specifier-qualifier-list[opt]
+     attributes specifier-qualifier-list[opt]
+
+   struct-declarator-list:
+     struct-declarator
+     struct-declarator-list , attributes[opt] struct-declarator
+
+   struct-declarator:
+     declarator attributes[opt]
+     declarator[opt] : constant-expression attributes[opt]
+
+   GNU extensions:
+
+   struct-declaration:
+     __extension__ struct-declaration
+     specifier-qualifier-list
+
+   Unlike the ISO C syntax, semicolons are handled elsewhere.  The use
+   of attributes where shown is a GNU extension.  In GNU C, we accept
+   any expression without commas in the syntax (assignment
+   expressions, not just conditional expressions); assignment
+   expressions will be diagnosed as non-constant.  */
+
+static tree
+c_parser_struct_declaration (c_parser *parser)
+{
+  struct c_declspecs *specs;
+  tree prefix_attrs;
+  tree all_prefix_attrs;
+  tree decls;
+  location_t decl_loc;
+  if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+    {
+      int ext;
+      tree decl;
+      ext = disable_extension_diagnostics ();
+      c_parser_consume_token (parser);
+      decl = c_parser_struct_declaration (parser);
+      restore_extension_diagnostics (ext);
+      return decl;
+    }
+  specs = build_null_declspecs ();
+  decl_loc = c_parser_peek_token (parser)->location;
+  c_parser_declspecs (parser, specs, false, true, true);
+  if (parser->error)
+    return NULL_TREE;
+  if (!specs->declspecs_seen_p)
+    {
+      c_parser_error (parser, "expected specifier-qualifier-list");
+      return NULL_TREE;
+    }
+  finish_declspecs (specs);
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+    {
+      tree ret;
+      if (!specs->type_seen_p)
+       {
+         pedwarn (decl_loc, OPT_pedantic, 
+                  "ISO C forbids member declarations with no members");
+         shadow_tag_warned (specs, pedantic);
+         ret = NULL_TREE;
+       }
+      else
+       {
+         /* Support for unnamed structs or unions as members of
+            structs or unions (which is [a] useful and [b] supports
+            MS P-SDK).  */
+         tree attrs = NULL;
+
+         ret = grokfield (c_parser_peek_token (parser)->location,
+                          build_id_declarator (NULL_TREE), specs,
+                          NULL_TREE, &attrs);
+         if (ret)
+           decl_attributes (&ret, attrs, 0);
+       }
+      return ret;
+    }
+  pending_xref_error ();
+  prefix_attrs = specs->attrs;
+  all_prefix_attrs = prefix_attrs;
+  specs->attrs = NULL_TREE;
+  decls = NULL_TREE;
+  while (true)
+    {
+      /* Declaring one or more declarators or un-named bit-fields.  */
+      struct c_declarator *declarator;
+      bool dummy = false;
+      if (c_parser_next_token_is (parser, CPP_COLON))
+       declarator = build_id_declarator (NULL_TREE);
+      else
+       declarator = c_parser_declarator (parser, specs->type_seen_p,
+                                         C_DTR_NORMAL, &dummy);
+      if (declarator == NULL)
+       {
+         c_parser_skip_to_end_of_block_or_statement (parser);
+         break;
+       }
+      if (c_parser_next_token_is (parser, CPP_COLON)
+         || c_parser_next_token_is (parser, CPP_COMMA)
+         || c_parser_next_token_is (parser, CPP_SEMICOLON)
+         || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)
+         || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+       {
+         tree postfix_attrs = NULL_TREE;
+         tree width = NULL_TREE;
+         tree d;
+         if (c_parser_next_token_is (parser, CPP_COLON))
+           {
+             c_parser_consume_token (parser);
+             width = c_parser_expr_no_commas (parser, NULL).value;
+           }
+         if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+           postfix_attrs = c_parser_attributes (parser);
+         d = grokfield (c_parser_peek_token (parser)->location,
+                        declarator, specs, width, &all_prefix_attrs);
+         decl_attributes (&d, chainon (postfix_attrs,
+                                       all_prefix_attrs), 0);
+         TREE_CHAIN (d) = decls;
+         decls = d;
+         if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+           all_prefix_attrs = chainon (c_parser_attributes (parser),
+                                       prefix_attrs);
+         else
+           all_prefix_attrs = prefix_attrs;
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           c_parser_consume_token (parser);
+         else if (c_parser_next_token_is (parser, CPP_SEMICOLON)
+                  || c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+           {
+             /* Semicolon consumed in caller.  */
+             break;
+           }
+         else
+           {
+             c_parser_error (parser, "expected %<,%>, %<;%> or %<}%>");
+             break;
+           }
+       }
+      else
+       {
+         c_parser_error (parser,
+                         "expected %<:%>, %<,%>, %<;%>, %<}%> or "
+                         "%<__attribute__%>");
+         break;
+       }
+    }
+  return decls;
+}
+
+/* Parse a typeof specifier (a GNU extension).
+
+   typeof-specifier:
+     typeof ( expression )
+     typeof ( type-name )
+*/
+
+static struct c_typespec
+c_parser_typeof_specifier (c_parser *parser)
+{
+  struct c_typespec ret;
+  ret.kind = ctsk_typeof;
+  ret.spec = error_mark_node;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
+  c_parser_consume_token (parser);
+  skip_evaluation++;
+  in_typeof++;
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      skip_evaluation--;
+      in_typeof--;
+      return ret;
+    }
+  if (c_parser_next_token_starts_typename (parser))
+    {
+      struct c_type_name *type = c_parser_type_name (parser);
+      skip_evaluation--;
+      in_typeof--;
+      if (type != NULL)
+       {
+         ret.spec = groktypename (type);
+         pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE));
+       }
+    }
+  else
+    {
+      bool was_vm;
+      location_t here = c_parser_peek_token (parser)->location;
+      struct c_expr expr = c_parser_expression (parser);
+      skip_evaluation--;
+      in_typeof--;
+      if (TREE_CODE (expr.value) == COMPONENT_REF
+         && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
+       error_at (here, "%<typeof%> applied to a bit-field");
+      ret.spec = TREE_TYPE (expr.value);
+      was_vm = variably_modified_type_p (ret.spec, NULL_TREE);
+      /* This should be returned with the type so that when the type
+        is evaluated, this can be evaluated.  For now, we avoid
+        evaluation when the context might.  */
+      if (!skip_evaluation && was_vm)
+       {
+         tree e = expr.value;
+
+         /* If the expression is not of a type to which we cannot assign a line
+            number, wrap the thing in a no-op NOP_EXPR.  */
+         if (DECL_P (e) || CONSTANT_CLASS_P (e))
+           e = build1 (NOP_EXPR, void_type_node, e);
+
+         protected_set_expr_location (e, here);
+
+         add_stmt (e);
+       }
+      pop_maybe_used (was_vm);
+    }
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  return ret;
+}
+
+/* Parse a declarator, possibly an abstract declarator (C90 6.5.4,
+   6.5.5, C99 6.7.5, 6.7.6).  If TYPE_SEEN_P then a typedef name may
+   be redeclared; otherwise it may not.  KIND indicates which kind of
+   declarator is wanted.  Returns a valid declarator except in the
+   case of a syntax error in which case NULL is returned.  *SEEN_ID is
+   set to true if an identifier being declared is seen; this is used
+   to diagnose bad forms of abstract array declarators and to
+   determine whether an identifier list is syntactically permitted.
+
+   declarator:
+     pointer[opt] direct-declarator
+
+   direct-declarator:
+     identifier
+     ( attributes[opt] declarator )
+     direct-declarator array-declarator
+     direct-declarator ( parameter-type-list )
+     direct-declarator ( identifier-list[opt] )
+
+   pointer:
+     * type-qualifier-list[opt]
+     * type-qualifier-list[opt] pointer
+
+   type-qualifier-list:
+     type-qualifier
+     attributes
+     type-qualifier-list type-qualifier
+     type-qualifier-list attributes
+
+   parameter-type-list:
+     parameter-list
+     parameter-list , ...
+
+   parameter-list:
+     parameter-declaration
+     parameter-list , parameter-declaration
+
+   parameter-declaration:
+     declaration-specifiers declarator attributes[opt]
+     declaration-specifiers abstract-declarator[opt] attributes[opt]
+
+   identifier-list:
+     identifier
+     identifier-list , identifier
+
+   abstract-declarator:
+     pointer
+     pointer[opt] direct-abstract-declarator
+
+   direct-abstract-declarator:
+     ( attributes[opt] abstract-declarator )
+     direct-abstract-declarator[opt] array-declarator
+     direct-abstract-declarator[opt] ( parameter-type-list[opt] )
+
+   GNU extensions:
+
+   direct-declarator:
+     direct-declarator ( parameter-forward-declarations
+                        parameter-type-list[opt] )
+
+   direct-abstract-declarator:
+     direct-abstract-declarator[opt] ( parameter-forward-declarations
+                                      parameter-type-list[opt] )
+
+   parameter-forward-declarations:
+     parameter-list ;
+     parameter-forward-declarations parameter-list ;
+
+   The uses of attributes shown above are GNU extensions.
+
+   Some forms of array declarator are not included in C99 in the
+   syntax for abstract declarators; these are disallowed elsewhere.
+   This may be a defect (DR#289).
+
+   This function also accepts an omitted abstract declarator as being
+   an abstract declarator, although not part of the formal syntax.  */
+
+static struct c_declarator *
+c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
+                    bool *seen_id)
+{
+  /* Parse any initial pointer part.  */
+  if (c_parser_next_token_is (parser, CPP_MULT))
+    {
+      struct c_declspecs *quals_attrs = build_null_declspecs ();
+      struct c_declarator *inner;
+      c_parser_consume_token (parser);
+      c_parser_declspecs (parser, quals_attrs, false, false, true);
+      inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
+      if (inner == NULL)
+       return NULL;
+      else
+       return make_pointer_declarator (quals_attrs, inner);
+    }
+  /* Now we have a direct declarator, direct abstract declarator or
+     nothing (which counts as a direct abstract declarator here).  */
+  return c_parser_direct_declarator (parser, type_seen_p, kind, seen_id);
+}
+
+/* Parse a direct declarator or direct abstract declarator; arguments
+   as c_parser_declarator.  */
+
+static struct c_declarator *
+c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
+                           bool *seen_id)
+{
+  /* The direct declarator must start with an identifier (possibly
+     omitted) or a parenthesized declarator (possibly abstract).  In
+     an ordinary declarator, initial parentheses must start a
+     parenthesized declarator.  In an abstract declarator or parameter
+     declarator, they could start a parenthesized declarator or a
+     parameter list.  To tell which, the open parenthesis and any
+     following attributes must be read.  If a declaration specifier
+     follows, then it is a parameter list; if the specifier is a
+     typedef name, there might be an ambiguity about redeclaring it,
+     which is resolved in the direction of treating it as a typedef
+     name.  If a close parenthesis follows, it is also an empty
+     parameter list, as the syntax does not permit empty abstract
+     declarators.  Otherwise, it is a parenthesized declarator (in
+     which case the analysis may be repeated inside it, recursively).
+
+     ??? There is an ambiguity in a parameter declaration "int
+     (__attribute__((foo)) x)", where x is not a typedef name: it
+     could be an abstract declarator for a function, or declare x with
+     parentheses.  The proper resolution of this ambiguity needs
+     documenting.  At present we follow an accident of the old
+     parser's implementation, whereby the first parameter must have
+     some declaration specifiers other than just attributes.  Thus as
+     a parameter declaration it is treated as a parenthesized
+     parameter named x, and as an abstract declarator it is
+     rejected.
+
+     ??? Also following the old parser, attributes inside an empty
+     parameter list are ignored, making it a list not yielding a
+     prototype, rather than giving an error or making it have one
+     parameter with implicit type int.
+
+     ??? Also following the old parser, typedef names may be
+     redeclared in declarators, but not Objective-C class names.  */
+
+  if (kind != C_DTR_ABSTRACT
+      && c_parser_next_token_is (parser, CPP_NAME)
+      && ((type_seen_p
+          && c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME)
+         || c_parser_peek_token (parser)->id_kind == C_ID_ID))
+    {
+      struct c_declarator *inner
+       = build_id_declarator (c_parser_peek_token (parser)->value);
+      *seen_id = true;
+      inner->id_loc = c_parser_peek_token (parser)->location;
+      c_parser_consume_token (parser);
+      return c_parser_direct_declarator_inner (parser, *seen_id, inner);
+    }
+
+  if (kind != C_DTR_NORMAL
+      && c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+    {
+      struct c_declarator *inner = build_id_declarator (NULL_TREE);
+      return c_parser_direct_declarator_inner (parser, *seen_id, inner);
+    }
+
+  /* Either we are at the end of an abstract declarator, or we have
+     parentheses.  */
+
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      tree attrs;
+      struct c_declarator *inner;
+      c_parser_consume_token (parser);
+      attrs = c_parser_attributes (parser);
+      if (kind != C_DTR_NORMAL
+         && (c_parser_next_token_starts_declspecs (parser)
+             || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)))
+       {
+         struct c_arg_info *args
+           = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL,
+                                        attrs);
+         if (args == NULL)
+           return NULL;
+         else
+           {
+             inner
+               = build_function_declarator (args,
+                                            build_id_declarator (NULL_TREE));
+             return c_parser_direct_declarator_inner (parser, *seen_id,
+                                                      inner);
+           }
+       }
+      /* A parenthesized declarator.  */
+      inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
+      if (inner != NULL && attrs != NULL)
+       inner = build_attrs_declarator (attrs, inner);
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       {
+         c_parser_consume_token (parser);
+         if (inner == NULL)
+           return NULL;
+         else
+           return c_parser_direct_declarator_inner (parser, *seen_id, inner);
+       }
+      else
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         return NULL;
+       }
+    }
+  else
+    {
+      if (kind == C_DTR_NORMAL)
+       {
+         c_parser_error (parser, "expected identifier or %<(%>");
+         return NULL;
+       }
+      else
+       return build_id_declarator (NULL_TREE);
+    }
+}
+
+/* Parse part of a direct declarator or direct abstract declarator,
+   given that some (in INNER) has already been parsed; ID_PRESENT is
+   true if an identifier is present, false for an abstract
+   declarator.  */
+
+static struct c_declarator *
+c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
+                                 struct c_declarator *inner)
+{
+  /* Parse a sequence of array declarators and parameter lists.  */
+  if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+    {
+      struct c_declarator *declarator;
+      struct c_declspecs *quals_attrs = build_null_declspecs ();
+      bool static_seen;
+      bool star_seen;
+      tree dimen;
+      c_parser_consume_token (parser);
+      c_parser_declspecs (parser, quals_attrs, false, false, true);
+      static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC);
+      if (static_seen)
+       c_parser_consume_token (parser);
+      if (static_seen && !quals_attrs->declspecs_seen_p)
+       c_parser_declspecs (parser, quals_attrs, false, false, true);
+      if (!quals_attrs->declspecs_seen_p)
+       quals_attrs = NULL;
+      /* If "static" is present, there must be an array dimension.
+        Otherwise, there may be a dimension, "*", or no
+        dimension.  */
+      if (static_seen)
+       {
+         star_seen = false;
+         dimen = c_parser_expr_no_commas (parser, NULL).value;
+       }
+      else
+       {
+         if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+           {
+             dimen = NULL_TREE;
+             star_seen = false;
+           }
+         else if (c_parser_next_token_is (parser, CPP_MULT))
+           {
+             if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE)
+               {
+                 dimen = NULL_TREE;
+                 star_seen = true;
+                 c_parser_consume_token (parser);
+               }
+             else
+               {
+                 star_seen = false;
+                 dimen = c_parser_expr_no_commas (parser, NULL).value;
+               }
+           }
+         else
+           {
+             star_seen = false;
+             dimen = c_parser_expr_no_commas (parser, NULL).value;
+           }
+       }
+      if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+       c_parser_consume_token (parser);
+      else
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                    "expected %<]%>");
+         return NULL;
+       }
+      declarator = build_array_declarator (dimen, quals_attrs, static_seen,
+                                          star_seen);
+      if (declarator == NULL)
+       return NULL;
+      inner = set_array_declarator_inner (declarator, inner);
+      return c_parser_direct_declarator_inner (parser, id_present, inner);
+    }
+  else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      tree attrs;
+      struct c_arg_info *args;
+      c_parser_consume_token (parser);
+      attrs = c_parser_attributes (parser);
+      args = c_parser_parms_declarator (parser, id_present, attrs);
+      if (args == NULL)
+       return NULL;
+      else
+       {
+         inner = build_function_declarator (args, inner);
+         return c_parser_direct_declarator_inner (parser, id_present, inner);
+       }
+    }
+  return inner;
+}
+
+/* Parse a parameter list or identifier list, including the closing
+   parenthesis but not the opening one.  ATTRS are the attributes at
+   the start of the list.  ID_LIST_OK is true if an identifier list is
+   acceptable; such a list must not have attributes at the start.  */
+
+static struct c_arg_info *
+c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs)
+{
+  push_scope ();
+  declare_parm_level ();
+  /* If the list starts with an identifier, it is an identifier list.
+     Otherwise, it is either a prototype list or an empty list.  */
+  if (id_list_ok
+      && !attrs
+      && c_parser_next_token_is (parser, CPP_NAME)
+      && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+    {
+      tree list = NULL_TREE, *nextp = &list;
+      while (c_parser_next_token_is (parser, CPP_NAME)
+            && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+       {
+         *nextp = build_tree_list (NULL_TREE,
+                                   c_parser_peek_token (parser)->value);
+         nextp = & TREE_CHAIN (*nextp);
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is_not (parser, CPP_COMMA))
+           break;
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+           {
+             c_parser_error (parser, "expected identifier");
+             break;
+           }
+       }
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       {
+         struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info);
+         ret->parms = 0;
+         ret->tags = 0;
+         ret->types = list;
+         ret->others = 0;
+         ret->pending_sizes = 0;
+         ret->had_vla_unspec = 0;
+         c_parser_consume_token (parser);
+         pop_scope ();
+         return ret;
+       }
+      else
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         pop_scope ();
+         return NULL;
+       }
+    }
+  else
+    {
+      struct c_arg_info *ret = c_parser_parms_list_declarator (parser, attrs);
+      pop_scope ();
+      return ret;
+    }
+}
+
+/* Parse a parameter list (possibly empty), including the closing
+   parenthesis but not the opening one.  ATTRS are the attributes at
+   the start of the list.  */
+
+static struct c_arg_info *
+c_parser_parms_list_declarator (c_parser *parser, tree attrs)
+{
+  bool good_parm = false;
+  /* ??? Following the old parser, forward parameter declarations may
+     use abstract declarators, and if no real parameter declarations
+     follow the forward declarations then this is not diagnosed.  Also
+     note as above that attributes are ignored as the only contents of
+     the parentheses, or as the only contents after forward
+     declarations.  */
+  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    {
+      struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info);
+      ret->parms = 0;
+      ret->tags = 0;
+      ret->types = 0;
+      ret->others = 0;
+      ret->pending_sizes = 0;
+      ret->had_vla_unspec = 0;
+      c_parser_consume_token (parser);
+      return ret;
+    }
+  if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+    {
+      struct c_arg_info *ret = XOBNEW (&parser_obstack, struct c_arg_info);
+      ret->parms = 0;
+      ret->tags = 0;
+      ret->others = 0;
+      ret->pending_sizes = 0;
+      ret->had_vla_unspec = 0;
+      /* Suppress -Wold-style-definition for this case.  */
+      ret->types = error_mark_node;
+      error_at (c_parser_peek_token (parser)->location,
+               "ISO C requires a named argument before %<...%>");
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       {
+         c_parser_consume_token (parser);
+         return ret;
+       }
+      else
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         return NULL;
+       }
+    }
+  /* Nonempty list of parameters, either terminated with semicolon
+     (forward declarations; recurse) or with close parenthesis (normal
+     function) or with ", ... )" (variadic function).  */
+  while (true)
+    {
+      /* Parse a parameter.  */
+      struct c_parm *parm = c_parser_parameter_declaration (parser, attrs);
+      attrs = NULL_TREE;
+      if (parm != NULL)
+       {
+         good_parm = true;
+         push_parm_decl (parm);
+       }
+      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+       {
+         tree new_attrs;
+         c_parser_consume_token (parser);
+         mark_forward_parm_decls ();
+         new_attrs = c_parser_attributes (parser);
+         return c_parser_parms_list_declarator (parser, new_attrs);
+       }
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       {
+         c_parser_consume_token (parser);
+         if (good_parm)
+           return get_parm_info (false);
+         else
+           {
+             struct c_arg_info *ret
+               = XOBNEW (&parser_obstack, struct c_arg_info);
+             ret->parms = 0;
+             ret->tags = 0;
+             ret->types = 0;
+             ret->others = 0;
+             ret->pending_sizes = 0;
+             ret->had_vla_unspec = 0;
+             return ret;
+           }
+       }
+      if (!c_parser_require (parser, CPP_COMMA,
+                            "expected %<;%>, %<,%> or %<)%>"))
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+         get_pending_sizes ();
+         return NULL;
+       }
+      if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+       {
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+           {
+             c_parser_consume_token (parser);
+             if (good_parm)
+               return get_parm_info (true);
+             else
+               {
+                 struct c_arg_info *ret
+                   = XOBNEW (&parser_obstack, struct c_arg_info);
+                 ret->parms = 0;
+                 ret->tags = 0;
+                 ret->types = 0;
+                 ret->others = 0;
+                 ret->pending_sizes = 0;
+                 ret->had_vla_unspec = 0;
+                 return ret;
+               }
+           }
+         else
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                        "expected %<)%>");
+             get_pending_sizes ();
+             return NULL;
+           }
+       }
+    }
+}
+
+/* Parse a parameter declaration.  ATTRS are the attributes at the
+   start of the declaration if it is the first parameter.  */
+
+static struct c_parm *
+c_parser_parameter_declaration (c_parser *parser, tree attrs)
+{
+  struct c_declspecs *specs;
+  struct c_declarator *declarator;
+  tree prefix_attrs;
+  tree postfix_attrs = NULL_TREE;
+  bool dummy = false;
+  if (!c_parser_next_token_starts_declspecs (parser))
+    {
+      /* ??? In some Objective-C cases '...' isn't applicable so there
+        should be a different message.  */
+      c_parser_error (parser,
+                     "expected declaration specifiers or %<...%>");
+      c_parser_skip_to_end_of_parameter (parser);
+      return NULL;
+    }
+  specs = build_null_declspecs ();
+  if (attrs)
+    {
+      declspecs_add_attrs (specs, attrs);
+      attrs = NULL_TREE;
+    }
+  c_parser_declspecs (parser, specs, true, true, true);
+  finish_declspecs (specs);
+  pending_xref_error ();
+  prefix_attrs = specs->attrs;
+  specs->attrs = NULL_TREE;
+  declarator = c_parser_declarator (parser, specs->type_seen_p,
+                                   C_DTR_PARM, &dummy);
+  if (declarator == NULL)
+    {
+      c_parser_skip_until_found (parser, CPP_COMMA, NULL);
+      return NULL;
+    }
+  if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+    postfix_attrs = c_parser_attributes (parser);
+  return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs),
+                      declarator);
+}
+
+/* Parse a string literal in an asm expression.  It should not be
+   translated, and wide string literals are an error although
+   permitted by the syntax.  This is a GNU extension.
+
+   asm-string-literal:
+     string-literal
+
+   ??? At present, following the old parser, the caller needs to have
+   set lex_untranslated_string to 1.  It would be better to follow the
+   C++ parser rather than using this kludge.  */
+
+static tree
+c_parser_asm_string_literal (c_parser *parser)
+{
+  tree str;
+  if (c_parser_next_token_is (parser, CPP_STRING))
+    {
+      str = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+    }
+  else if (c_parser_next_token_is (parser, CPP_WSTRING))
+    {
+      error_at (c_parser_peek_token (parser)->location,
+               "wide string literal in %<asm%>");
+      str = build_string (1, "");
+      c_parser_consume_token (parser);
+    }
+  else
+    {
+      c_parser_error (parser, "expected string literal");
+      str = NULL_TREE;
+    }
+  return str;
+}
+
+/* Parse a simple asm expression.  This is used in restricted
+   contexts, where a full expression with inputs and outputs does not
+   make sense.  This is a GNU extension.
+
+   simple-asm-expr:
+     asm ( asm-string-literal )
+*/
+
+static tree
+c_parser_simple_asm_expr (c_parser *parser)
+{
+  tree str;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
+  /* ??? Follow the C++ parser rather than using the
+     lex_untranslated_string kludge.  */
+  parser->lex_untranslated_string = true;
+  c_parser_consume_token (parser);
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      parser->lex_untranslated_string = false;
+      return NULL_TREE;
+    }
+  str = c_parser_asm_string_literal (parser);
+  parser->lex_untranslated_string = false;
+  if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+    {
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return NULL_TREE;
+    }
+  return str;
+}
+
+/* Parse (possibly empty) attributes.  This is a GNU extension.
+
+   attributes:
+     empty
+     attributes attribute
+
+   attribute:
+     __attribute__ ( ( attribute-list ) )
+
+   attribute-list:
+     attrib
+     attribute_list , attrib
+
+   attrib:
+     empty
+     any-word
+     any-word ( identifier )
+     any-word ( identifier , nonempty-expr-list )
+     any-word ( expr-list )
+
+   where the "identifier" must not be declared as a type, and
+   "any-word" may be any identifier (including one declared as a
+   type), a reserved word storage class specifier, type specifier or
+   type qualifier.  ??? This still leaves out most reserved keywords
+   (following the old parser), shouldn't we include them, and why not
+   allow identifiers declared as types to start the arguments?  */
+
+static tree
+c_parser_attributes (c_parser *parser)
+{
+  tree attrs = NULL_TREE;
+  while (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+    {
+      /* ??? Follow the C++ parser rather than using the
+        lex_untranslated_string kludge.  */
+      parser->lex_untranslated_string = true;
+      c_parser_consume_token (parser);
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+       {
+         parser->lex_untranslated_string = false;
+         return attrs;
+       }
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+       {
+         parser->lex_untranslated_string = false;
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+         return attrs;
+       }
+      /* Parse the attribute list.  */
+      while (c_parser_next_token_is (parser, CPP_COMMA)
+            || c_parser_next_token_is (parser, CPP_NAME)
+            || c_parser_next_token_is (parser, CPP_KEYWORD))
+       {
+         tree attr, attr_name, attr_args;
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           {
+             c_parser_consume_token (parser);
+             continue;
+           }
+         if (c_parser_next_token_is (parser, CPP_KEYWORD))
+           {
+             /* ??? See comment above about what keywords are
+                accepted here.  */
+             bool ok;
+             switch (c_parser_peek_token (parser)->keyword)
+               {
+               case RID_STATIC:
+               case RID_UNSIGNED:
+               case RID_LONG:
+               case RID_CONST:
+               case RID_EXTERN:
+               case RID_REGISTER:
+               case RID_TYPEDEF:
+               case RID_SHORT:
+               case RID_INLINE:
+               case RID_VOLATILE:
+               case RID_SIGNED:
+               case RID_AUTO:
+               case RID_RESTRICT:
+               case RID_COMPLEX:
+               case RID_THREAD:
+               case RID_INT:
+               case RID_CHAR:
+               case RID_FLOAT:
+               case RID_DOUBLE:
+               case RID_VOID:
+               case RID_DFLOAT32:
+               case RID_DFLOAT64:
+               case RID_DFLOAT128:
+               case RID_BOOL:
+               case RID_FRACT:
+               case RID_ACCUM:
+               case RID_SAT:
+                 ok = true;
+                 break;
+               default:
+                 ok = false;
+                 break;
+               }
+             if (!ok)
+               break;
+             /* Accept __attribute__((__const)) as __attribute__((const))
+                etc.  */
+             attr_name
+               = ridpointers[(int) c_parser_peek_token (parser)->keyword];
+           }
+         else
+           attr_name = c_parser_peek_token (parser)->value;
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+           {
+             attr = build_tree_list (attr_name, NULL_TREE);
+             attrs = chainon (attrs, attr);
+             continue;
+           }
+         c_parser_consume_token (parser);
+         /* Parse the attribute contents.  If they start with an
+            identifier which is followed by a comma or close
+            parenthesis, then the arguments start with that
+            identifier; otherwise they are an expression list.  */
+         if (c_parser_next_token_is (parser, CPP_NAME)
+             && c_parser_peek_token (parser)->id_kind == C_ID_ID
+             && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
+                 || (c_parser_peek_2nd_token (parser)->type
+                     == CPP_CLOSE_PAREN)))
+           {
+             tree arg1 = c_parser_peek_token (parser)->value;
+             c_parser_consume_token (parser);
+             if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+               attr_args = build_tree_list (NULL_TREE, arg1);
+             else
+               {
+                 c_parser_consume_token (parser);
+                 attr_args = tree_cons (NULL_TREE, arg1,
+                                        c_parser_expr_list (parser, false));
+               }
+           }
+         else
+           {
+             if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+               attr_args = NULL_TREE;
+             else
+               attr_args = c_parser_expr_list (parser, false);
+           }
+         attr = build_tree_list (attr_name, attr_args);
+         if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+           c_parser_consume_token (parser);
+         else
+           {
+             parser->lex_untranslated_string = false;
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                        "expected %<)%>");
+             return attrs;
+           }
+         attrs = chainon (attrs, attr);
+       }
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       c_parser_consume_token (parser);
+      else
+       {
+         parser->lex_untranslated_string = false;
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         return attrs;
+       }
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       c_parser_consume_token (parser);
+      else
+       {
+         parser->lex_untranslated_string = false;
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         return attrs;
+       }
+      parser->lex_untranslated_string = false;
+    }
+  return attrs;
+}
+
+/* Parse a type name (C90 6.5.5, C99 6.7.6).
+
+   type-name:
+     specifier-qualifier-list abstract-declarator[opt]
+*/
+
+static struct c_type_name *
+c_parser_type_name (c_parser *parser)
+{
+  struct c_declspecs *specs = build_null_declspecs ();
+  struct c_declarator *declarator;
+  struct c_type_name *ret;
+  bool dummy = false;
+  c_parser_declspecs (parser, specs, false, true, true);
+  if (!specs->declspecs_seen_p)
+    {
+      c_parser_error (parser, "expected specifier-qualifier-list");
+      return NULL;
+    }
+  pending_xref_error ();
+  finish_declspecs (specs);
+  declarator = c_parser_declarator (parser, specs->type_seen_p,
+                                   C_DTR_ABSTRACT, &dummy);
+  if (declarator == NULL)
+    return NULL;
+  ret = XOBNEW (&parser_obstack, struct c_type_name);
+  ret->specs = specs;
+  ret->declarator = declarator;
+  return ret;
+}
+
+/* Parse an initializer (C90 6.5.7, C99 6.7.8).
+
+   initializer:
+     assignment-expression
+     { initializer-list }
+     { initializer-list , }
+
+   initializer-list:
+     designation[opt] initializer
+     initializer-list , designation[opt] initializer
+
+   designation:
+     designator-list =
+
+   designator-list:
+     designator
+     designator-list designator
+
+   designator:
+     array-designator
+     . identifier
+
+   array-designator:
+     [ constant-expression ]
+
+   GNU extensions:
+
+   initializer:
+     { }
+
+   designation:
+     array-designator
+     identifier :
+
+   array-designator:
+     [ constant-expression ... constant-expression ]
+
+   Any expression without commas is accepted in the syntax for the
+   constant-expressions, with non-constant expressions rejected later.
+
+   This function is only used for top-level initializers; for nested
+   ones, see c_parser_initval.  */
+
+static struct c_expr
+c_parser_initializer (c_parser *parser)
+{
+  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    return c_parser_braced_init (parser, NULL_TREE, false);
+  else
+    {
+      struct c_expr ret;
+      ret = c_parser_expr_no_commas (parser, NULL);
+      if (TREE_CODE (ret.value) != STRING_CST
+         && TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR)
+       ret = default_function_array_conversion (ret);
+      return ret;
+    }
+}
+
+/* Parse a braced initializer list.  TYPE is the type specified for a
+   compound literal, and NULL_TREE for other initializers and for
+   nested braced lists.  NESTED_P is true for nested braced lists,
+   false for the list of a compound literal or the list that is the
+   top-level initializer in a declaration.  */
+
+static struct c_expr
+c_parser_braced_init (c_parser *parser, tree type, bool nested_p)
+{
+  location_t brace_loc = c_parser_peek_token (parser)->location;
+  gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
+  c_parser_consume_token (parser);
+  if (nested_p)
+    push_init_level (0);
+  else
+    really_start_incremental_init (type);
+  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+    {
+      pedwarn (brace_loc, OPT_pedantic, "ISO C forbids empty initializer braces");
+    }
+  else
+    {
+      /* Parse a non-empty initializer list, possibly with a trailing
+        comma.  */
+      while (true)
+       {
+         c_parser_initelt (parser);
+         if (parser->error)
+           break;
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           c_parser_consume_token (parser);
+         else
+           break;
+         if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+           break;
+       }
+    }
+  if (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
+    {
+      struct c_expr ret;
+      ret.value = error_mark_node;
+      ret.original_code = ERROR_MARK;
+      c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+      pop_init_level (0);
+      return ret;
+    }
+  c_parser_consume_token (parser);
+  return pop_init_level (0);
+}
+
+/* Parse a nested initializer, including designators.  */
+
+static void
+c_parser_initelt (c_parser *parser)
+{
+  /* Parse any designator or designator list.  A single array
+     designator may have the subsequent "=" omitted in GNU C, but a
+     longer list or a structure member designator may not.  */
+  if (c_parser_next_token_is (parser, CPP_NAME)
+      && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+    {
+      /* Old-style structure member designator.  */
+      set_init_label (c_parser_peek_token (parser)->value);
+      /* Use the colon as the error location.  */
+      pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_pedantic, 
+              "obsolete use of designated initializer with %<:%>");
+      c_parser_consume_token (parser);
+      c_parser_consume_token (parser);
+    }
+  else
+    {
+      /* des_seen is 0 if there have been no designators, 1 if there
+        has been a single array designator and 2 otherwise.  */
+      int des_seen = 0;
+      /* Location of a designator.  */
+      location_t des_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
+      while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)
+            || c_parser_next_token_is (parser, CPP_DOT))
+       {
+         int des_prev = des_seen;
+         if (!des_seen)
+           des_loc = c_parser_peek_token (parser)->location;
+         if (des_seen < 2)
+           des_seen++;
+         if (c_parser_next_token_is (parser, CPP_DOT))
+           {
+             des_seen = 2;
+             c_parser_consume_token (parser);
+             if (c_parser_next_token_is (parser, CPP_NAME))
+               {
+                 set_init_label (c_parser_peek_token (parser)->value);
+                 c_parser_consume_token (parser);
+               }
+             else
+               {
+                 struct c_expr init;
+                 init.value = error_mark_node;
+                 init.original_code = ERROR_MARK;
+                 c_parser_error (parser, "expected identifier");
+                 c_parser_skip_until_found (parser, CPP_COMMA, NULL);
+                 process_init_element (init, false);
+                 return;
+               }
+           }
+         else
+           {
+             tree first, second;
+             location_t ellipsis_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
+             /* ??? Following the old parser, [ objc-receiver
+                objc-message-args ] is accepted as an initializer,
+                being distinguished from a designator by what follows
+                the first assignment expression inside the square
+                brackets, but after a first array designator a
+                subsequent square bracket is for Objective-C taken to
+                start an expression, using the obsolete form of
+                designated initializer without '=', rather than
+                possibly being a second level of designation: in LALR
+                terms, the '[' is shifted rather than reducing
+                designator to designator-list.  */
+             if (des_prev == 1 && c_dialect_objc ())
+               {
+                 des_seen = des_prev;
+                 break;
+               }
+             if (des_prev == 0 && c_dialect_objc ())
+               {
+                 /* This might be an array designator or an
+                    Objective-C message expression.  If the former,
+                    continue parsing here; if the latter, parse the
+                    remainder of the initializer given the starting
+                    primary-expression.  ??? It might make sense to
+                    distinguish when des_prev == 1 as well; see
+                    previous comment.  */
+                 tree rec, args;
+                 struct c_expr mexpr;
+                 c_parser_consume_token (parser);
+                 if (c_parser_peek_token (parser)->type == CPP_NAME
+                     && ((c_parser_peek_token (parser)->id_kind
+                          == C_ID_TYPENAME)
+                         || (c_parser_peek_token (parser)->id_kind
+                             == C_ID_CLASSNAME)))
+                   {
+                     /* Type name receiver.  */
+                     tree id = c_parser_peek_token (parser)->value;
+                     c_parser_consume_token (parser);
+                     rec = objc_get_class_reference (id);
+                     goto parse_message_args;
+                   }
+                 first = c_parser_expr_no_commas (parser, NULL).value;
+                 if (c_parser_next_token_is (parser, CPP_ELLIPSIS)
+                     || c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+                   goto array_desig_after_first;
+                 /* Expression receiver.  So far only one part
+                    without commas has been parsed; there might be
+                    more of the expression.  */
+                 rec = first;
+                 while (c_parser_next_token_is (parser, CPP_COMMA))
+                   {
+                     struct c_expr next;
+                     c_parser_consume_token (parser);
+                     next = c_parser_expr_no_commas (parser, NULL);
+                     next = default_function_array_conversion (next);
+                     rec = build_compound_expr (rec, next.value);
+                   }
+               parse_message_args:
+                 /* Now parse the objc-message-args.  */
+                 args = c_parser_objc_message_args (parser);
+                 c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                            "expected %<]%>");
+                 mexpr.value
+                   = objc_build_message_expr (build_tree_list (rec, args));
+                 mexpr.original_code = ERROR_MARK;
+                 /* Now parse and process the remainder of the
+                    initializer, starting with this message
+                    expression as a primary-expression.  */
+                 c_parser_initval (parser, &mexpr);
+                 return;
+               }
+             c_parser_consume_token (parser);
+             first = c_parser_expr_no_commas (parser, NULL).value;
+           array_desig_after_first:
+             if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+               {
+                 ellipsis_loc = c_parser_peek_token (parser)->location;
+                 c_parser_consume_token (parser);
+                 second = c_parser_expr_no_commas (parser, NULL).value;
+               }
+             else
+               second = NULL_TREE;
+             if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+               {
+                 c_parser_consume_token (parser);
+                 set_init_index (first, second);
+                 if (second)
+                   pedwarn (ellipsis_loc, OPT_pedantic, 
+                            "ISO C forbids specifying range of elements to initialize");
+               }
+             else
+               c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                          "expected %<]%>");
+           }
+       }
+      if (des_seen >= 1)
+       {
+         if (c_parser_next_token_is (parser, CPP_EQ))
+           {
+             if (!flag_isoc99)
+               pedwarn (des_loc, OPT_pedantic, 
+                        "ISO C90 forbids specifying subobject to initialize");
+             c_parser_consume_token (parser);
+           }
+         else
+           {
+             if (des_seen == 1)
+               pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
+                        "obsolete use of designated initializer without %<=%>");
+             else
+               {
+                 struct c_expr init;
+                 init.value = error_mark_node;
+                 init.original_code = ERROR_MARK;
+                 c_parser_error (parser, "expected %<=%>");
+                 c_parser_skip_until_found (parser, CPP_COMMA, NULL);
+                 process_init_element (init, false);
+                 return;
+               }
+           }
+       }
+    }
+  c_parser_initval (parser, NULL);
+}
+
+/* Parse a nested initializer; as c_parser_initializer but parses
+   initializers within braced lists, after any designators have been
+   applied.  If AFTER is not NULL then it is an Objective-C message
+   expression which is the primary-expression starting the
+   initializer.  */
+
+static void
+c_parser_initval (c_parser *parser, struct c_expr *after)
+{
+  struct c_expr init;
+  gcc_assert (!after || c_dialect_objc ());
+  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after)
+    init = c_parser_braced_init (parser, NULL_TREE, true);
+  else
+    {
+      init = c_parser_expr_no_commas (parser, after);
+      if (init.value != NULL_TREE
+         && TREE_CODE (init.value) != STRING_CST
+         && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR)
+       init = default_function_array_conversion (init);
+    }
+  process_init_element (init, false);
+}
+
+/* Parse a compound statement (possibly a function body) (C90 6.6.2,
+   C99 6.8.2).
+
+   compound-statement:
+     { block-item-list[opt] }
+     { label-declarations block-item-list }
+
+   block-item-list:
+     block-item
+     block-item-list block-item
+
+   block-item:
+     nested-declaration
+     statement
+
+   nested-declaration:
+     declaration
+
+   GNU extensions:
+
+   compound-statement:
+     { label-declarations block-item-list }
+
+   nested-declaration:
+     __extension__ nested-declaration
+     nested-function-definition
+
+   label-declarations:
+     label-declaration
+     label-declarations label-declaration
+
+   label-declaration:
+     __label__ identifier-list ;
+
+   Allowing the mixing of declarations and code is new in C99.  The
+   GNU syntax also permits (not shown above) labels at the end of
+   compound statements, which yield an error.  We don't allow labels
+   on declarations; this might seem like a natural extension, but
+   there would be a conflict between attributes on the label and
+   prefix attributes on the declaration.  ??? The syntax follows the
+   old parser in requiring something after label declarations.
+   Although they are erroneous if the labels declared aren't defined,
+   is it useful for the syntax to be this way?
+   
+   OpenMP:
+   
+   block-item:
+     openmp-directive
+
+   openmp-directive:
+     barrier-directive
+     flush-directive  */
+
+static tree
+c_parser_compound_statement (c_parser *parser)
+{
+  tree stmt;
+  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+    {
+      /* Ensure a scope is entered and left anyway to avoid confusion
+        if we have just prepared to enter a function body.  */
+      stmt = c_begin_compound_stmt (true);
+      c_end_compound_stmt (stmt, true);
+      return error_mark_node;
+    }
+  stmt = c_begin_compound_stmt (true);
+  c_parser_compound_statement_nostart (parser);
+  return c_end_compound_stmt (stmt, true);
+}
+
+/* Parse a compound statement except for the opening brace.  This is
+   used for parsing both compound statements and statement expressions
+   (which follow different paths to handling the opening).  */
+
+static void
+c_parser_compound_statement_nostart (c_parser *parser)
+{
+  bool last_stmt = false;
+  bool last_label = false;
+  location_t label_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
+  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+    {
+      c_parser_consume_token (parser);
+      return;
+    }
+  if (c_parser_next_token_is_keyword (parser, RID_LABEL))
+    {
+      location_t err_loc = c_parser_peek_token (parser)->location;
+      /* Read zero or more forward-declarations for labels that nested
+        functions can jump to.  */
+      while (c_parser_next_token_is_keyword (parser, RID_LABEL))
+       {
+         c_parser_consume_token (parser);
+         /* Any identifiers, including those declared as type names,
+            are OK here.  */
+         while (true)
+           {
+             tree label;
+             if (c_parser_next_token_is_not (parser, CPP_NAME))
+               {
+                 c_parser_error (parser, "expected identifier");
+                 break;
+               }
+             label
+               = declare_label (c_parser_peek_token (parser)->value);
+             C_DECLARED_LABEL_FLAG (label) = 1;
+             add_stmt (build_stmt (DECL_EXPR, label));
+             c_parser_consume_token (parser);
+             if (c_parser_next_token_is (parser, CPP_COMMA))
+               c_parser_consume_token (parser);
+             else
+               break;
+           }
+         c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+       }
+      pedwarn (err_loc, OPT_pedantic, "ISO C forbids label declarations");
+    }
+  /* We must now have at least one statement, label or declaration.  */
+  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+    {
+      c_parser_error (parser, "expected declaration or statement");
+      c_parser_consume_token (parser);
+      return;
+    }
+  while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
+    {
+      location_t loc = c_parser_peek_token (parser)->location;
+      if (c_parser_next_token_is_keyword (parser, RID_CASE)
+         || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+         || (c_parser_next_token_is (parser, CPP_NAME)
+             && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+       {
+         if (c_parser_next_token_is_keyword (parser, RID_CASE))
+           label_loc = c_parser_peek_2nd_token (parser)->location;
+         else
+           label_loc = c_parser_peek_token (parser)->location;
+         last_label = true;
+         last_stmt = false;
+         c_parser_label (parser);
+       }
+      else if (!last_label
+              && c_parser_next_token_starts_declspecs (parser))
+       {
+         last_label = false;
+         c_parser_declaration_or_fndef (parser, true, true, true, true);
+         if (last_stmt)
+           pedwarn_c90 (loc, 
+                        (pedantic && !flag_isoc99)
+                        ? OPT_pedantic
+                        : OPT_Wdeclaration_after_statement,
+                        "ISO C90 forbids mixed declarations and code");
+         last_stmt = false;
+       }
+      else if (!last_label
+              && c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+       {
+         /* __extension__ can start a declaration, but is also an
+            unary operator that can start an expression.  Consume all
+            but the last of a possible series of __extension__ to
+            determine which.  */
+         while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD
+                && (c_parser_peek_2nd_token (parser)->keyword
+                    == RID_EXTENSION))
+           c_parser_consume_token (parser);
+         if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser)))
+           {
+             int ext;
+             ext = disable_extension_diagnostics ();
+             c_parser_consume_token (parser);
+             last_label = false;
+             c_parser_declaration_or_fndef (parser, true, true, true, true);
+             /* Following the old parser, __extension__ does not
+                disable this diagnostic.  */
+             restore_extension_diagnostics (ext);
+             if (last_stmt)
+               pedwarn_c90 (loc, (pedantic && !flag_isoc99)
+                            ? OPT_pedantic
+                            : OPT_Wdeclaration_after_statement,
+                            "ISO C90 forbids mixed declarations and code");
+             last_stmt = false;
+           }
+         else
+           goto statement;
+       }
+      else if (c_parser_next_token_is (parser, CPP_PRAGMA))
+       {
+         /* External pragmas, and some omp pragmas, are not associated
+            with regular c code, and so are not to be considered statements
+            syntactically.  This ensures that the user doesn't put them
+            places that would turn into syntax errors if the directive
+            were ignored.  */
+         if (c_parser_pragma (parser, pragma_compound))
+           last_label = false, last_stmt = true;
+       }
+      else if (c_parser_next_token_is (parser, CPP_EOF))
+       {
+         c_parser_error (parser, "expected declaration or statement");
+         return;
+       }
+      else if (c_parser_next_token_is_keyword (parser, RID_ELSE))
+        {
+          if (parser->in_if_block) 
+            {
+              error_at (loc, """expected %<}%> before %<else%>");
+              return;
+            }
+          else 
+            {
+              error_at (loc, "%<else%> without a previous %<if%>");
+              c_parser_consume_token (parser);
+              continue;
+            }
+        }
+      else
+       {
+       statement:
+         last_label = false;
+         last_stmt = true;
+         c_parser_statement_after_labels (parser);
+       }
+
+      parser->error = false;
+    }
+  if (last_label)
+    error_at (label_loc, "label at end of compound statement");
+  c_parser_consume_token (parser);
+}
+
+/* Parse a label (C90 6.6.1, C99 6.8.1).
+
+   label:
+     identifier : attributes[opt]
+     case constant-expression :
+     default :
+
+   GNU extensions:
+
+   label:
+     case constant-expression ... constant-expression :
+
+   The use of attributes on labels is a GNU extension.  The syntax in
+   GNU C accepts any expressions without commas, non-constant
+   expressions being rejected later.  */
+
+static void
+c_parser_label (c_parser *parser)
+{
+  location_t loc1 = c_parser_peek_token (parser)->location;
+  tree label = NULL_TREE;
+  if (c_parser_next_token_is_keyword (parser, RID_CASE))
+    {
+      tree exp1, exp2;
+      c_parser_consume_token (parser);
+      exp1 = c_parser_expr_no_commas (parser, NULL).value;
+      if (c_parser_next_token_is (parser, CPP_COLON))
+       {
+         c_parser_consume_token (parser);
+         label = do_case (exp1, NULL_TREE);
+       }
+      else if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+       {
+         c_parser_consume_token (parser);
+         exp2 = c_parser_expr_no_commas (parser, NULL).value;
+         if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+           label = do_case (exp1, exp2);
+       }
+      else
+       c_parser_error (parser, "expected %<:%> or %<...%>");
+    }
+  else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT))
+    {
+      c_parser_consume_token (parser);
+      if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+       label = do_case (NULL_TREE, NULL_TREE);
+    }
+  else
+    {
+      tree name = c_parser_peek_token (parser)->value;
+      tree tlab;
+      tree attrs;
+      location_t loc2 = c_parser_peek_token (parser)->location;
+      gcc_assert (c_parser_next_token_is (parser, CPP_NAME));
+      c_parser_consume_token (parser);
+      gcc_assert (c_parser_next_token_is (parser, CPP_COLON));
+      c_parser_consume_token (parser);
+      attrs = c_parser_attributes (parser);
+      tlab = define_label (loc2, name);
+      if (tlab)
+       {
+         decl_attributes (&tlab, attrs, 0);
+         label = add_stmt (build_stmt (LABEL_EXPR, tlab));
+       }
+    }
+  if (label)
+    {
+      SET_EXPR_LOCATION (label, loc1);
+      if (c_parser_next_token_starts_declspecs (parser)
+         && !(c_parser_next_token_is (parser, CPP_NAME)
+              && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+       {
+         error_at (c_parser_peek_token (parser)->location,
+                   "a label can only be part of a statement and "
+                   "a declaration is not a statement");
+         c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false, 
+                                        /*nested*/ true, /*empty_ok*/ false,
+                                        /*start_attr_ok*/ true);
+       }
+    }
+}
+
+/* Parse a statement (C90 6.6, C99 6.8).
+
+   statement:
+     labeled-statement
+     compound-statement
+     expression-statement
+     selection-statement
+     iteration-statement
+     jump-statement
+
+   labeled-statement:
+     label statement
+
+   expression-statement:
+     expression[opt] ;
+
+   selection-statement:
+     if-statement
+     switch-statement
+
+   iteration-statement:
+     while-statement
+     do-statement
+     for-statement
+
+   jump-statement:
+     goto identifier ;
+     continue ;
+     break ;
+     return expression[opt] ;
+
+   GNU extensions:
+
+   statement:
+     asm-statement
+
+   jump-statement:
+     goto * expression ;
+
+   Objective-C:
+
+   statement:
+     objc-throw-statement
+     objc-try-catch-statement
+     objc-synchronized-statement
+
+   objc-throw-statement:
+     @throw expression ;
+     @throw ;
+
+   OpenMP:
+
+   statement:
+     openmp-construct
+
+   openmp-construct:
+     parallel-construct
+     for-construct
+     sections-construct
+     single-construct
+     parallel-for-construct
+     parallel-sections-construct
+     master-construct
+     critical-construct
+     atomic-construct
+     ordered-construct
+
+   parallel-construct:
+     parallel-directive structured-block
+
+   for-construct:
+     for-directive iteration-statement
+
+   sections-construct:
+     sections-directive section-scope
+
+   single-construct:
+     single-directive structured-block
+
+   parallel-for-construct:
+     parallel-for-directive iteration-statement
+
+   parallel-sections-construct:
+     parallel-sections-directive section-scope
+
+   master-construct:
+     master-directive structured-block
+
+   critical-construct:
+     critical-directive structured-block
+
+   atomic-construct:
+     atomic-directive expression-statement
+
+   ordered-construct:
+     ordered-directive structured-block  */
+
+static void
+c_parser_statement (c_parser *parser)
+{
+  while (c_parser_next_token_is_keyword (parser, RID_CASE)
+        || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+        || (c_parser_next_token_is (parser, CPP_NAME)
+            && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+    c_parser_label (parser);
+  c_parser_statement_after_labels (parser);
+}
+
+/* Parse a statement, other than a labeled statement.  */
+
+static void
+c_parser_statement_after_labels (c_parser *parser)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  tree stmt = NULL_TREE;
+  bool in_if_block = parser->in_if_block;
+  parser->in_if_block = false;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_OPEN_BRACE:
+      add_stmt (c_parser_compound_statement (parser));
+      break;
+    case CPP_KEYWORD:
+      switch (c_parser_peek_token (parser)->keyword)
+       {
+       case RID_IF:
+         c_parser_if_statement (parser);
+         break;
+       case RID_SWITCH:
+         c_parser_switch_statement (parser);
+         break;
+       case RID_WHILE:
+         c_parser_while_statement (parser);
+         break;
+       case RID_DO:
+         c_parser_do_statement (parser);
+         break;
+       case RID_FOR:
+         c_parser_for_statement (parser);
+         break;
+       case RID_GOTO:
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_NAME))
+           {
+             stmt = c_finish_goto_label (c_parser_peek_token (parser)->value);
+             c_parser_consume_token (parser);
+           }
+         else if (c_parser_next_token_is (parser, CPP_MULT))
+           {
+             c_parser_consume_token (parser);
+             stmt = c_finish_goto_ptr (c_parser_expression (parser).value);
+           }
+         else
+           c_parser_error (parser, "expected identifier or %<*%>");
+         goto expect_semicolon;
+       case RID_CONTINUE:
+         c_parser_consume_token (parser);
+         stmt = c_finish_bc_stmt (&c_cont_label, false);
+         goto expect_semicolon;
+       case RID_BREAK:
+         c_parser_consume_token (parser);
+         stmt = c_finish_bc_stmt (&c_break_label, true);
+         goto expect_semicolon;
+       case RID_RETURN:
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+           {
+             stmt = c_finish_return (NULL_TREE);
+             c_parser_consume_token (parser);
+           }
+         else
+           {
+             stmt = c_finish_return (c_parser_expression_conv (parser).value);
+             goto expect_semicolon;
+           }
+         break;
+       case RID_ASM:
+         stmt = c_parser_asm_statement (parser);
+         break;
+       case RID_THROW:
+         gcc_assert (c_dialect_objc ());
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+           {
+             stmt = objc_build_throw_stmt (NULL_TREE);
+             c_parser_consume_token (parser);
+           }
+         else
+           {
+             stmt
+               = objc_build_throw_stmt (c_parser_expression (parser).value);
+             goto expect_semicolon;
+           }
+         break;
+       case RID_TRY:
+         gcc_assert (c_dialect_objc ());
+         c_parser_objc_try_catch_statement (parser);
+         break;
+       case RID_AT_SYNCHRONIZED:
+         gcc_assert (c_dialect_objc ());
+         c_parser_objc_synchronized_statement (parser);
+         break;
+       default:
+         goto expr_stmt;
+       }
+      break;
+    case CPP_SEMICOLON:
+      c_parser_consume_token (parser);
+      break;
+    case CPP_CLOSE_PAREN:
+    case CPP_CLOSE_SQUARE:
+      /* Avoid infinite loop in error recovery:
+        c_parser_skip_until_found stops at a closing nesting
+        delimiter without consuming it, but here we need to consume
+        it to proceed further.  */
+      c_parser_error (parser, "expected statement");
+      c_parser_consume_token (parser);
+      break;
+    case CPP_PRAGMA:
+      c_parser_pragma (parser, pragma_stmt);
+      break;
+    default:
+    expr_stmt:
+      stmt = c_finish_expr_stmt (c_parser_expression_conv (parser).value);
+    expect_semicolon:
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+      break;
+    }
+  /* Two cases cannot and do not have line numbers associated: If stmt
+     is degenerate, such as "2;", then stmt is an INTEGER_CST, which
+     cannot hold line numbers.  But that's OK because the statement
+     will either be changed to a MODIFY_EXPR during gimplification of
+     the statement expr, or discarded.  If stmt was compound, but
+     without new variables, we will have skipped the creation of a
+     BIND and will have a bare STATEMENT_LIST.  But that's OK because
+     (recursively) all of the component statements should already have
+     line numbers assigned.  ??? Can we discard no-op statements
+     earlier?  */
+  protected_set_expr_location (stmt, loc);
+
+  parser->in_if_block = in_if_block;
+}
+
+/* Parse the condition from an if, do, while or for statements.  */
+
+static tree
+c_parser_condition (c_parser *parser)
+{
+  location_t loc;
+  tree cond;
+  loc = c_parser_peek_token (parser)->location;
+  cond = c_objc_common_truthvalue_conversion 
+    (loc, c_parser_expression_conv (parser).value);
+  protected_set_expr_location (cond, loc);
+  if (warn_sequence_point)
+    verify_sequence_points (cond);
+  return cond;
+}
+
+/* Parse a parenthesized condition from an if, do or while statement.
+
+   condition:
+     ( expression )
+*/
+static tree
+c_parser_paren_condition (c_parser *parser)
+{
+  tree cond;
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return error_mark_node;
+  cond = c_parser_condition (parser);
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+  return cond;
+}
+
+/* Parse a statement which is a block in C99.  */
+
+static tree
+c_parser_c99_block_statement (c_parser *parser)
+{
+  tree block = c_begin_compound_stmt (flag_isoc99);
+  c_parser_statement (parser);
+  return c_end_compound_stmt (block, flag_isoc99);
+}
+
+/* Parse the body of an if statement.  This is just parsing a
+   statement but (a) it is a block in C99, (b) we track whether the
+   body is an if statement for the sake of -Wparentheses warnings, (c)
+   we handle an empty body specially for the sake of -Wempty-body
+   warnings, and (d) we call parser_compound_statement directly
+   because c_parser_statement_after_labels resets
+   parser->in_if_block.  */
+
+static tree
+c_parser_if_body (c_parser *parser, bool *if_p)
+{
+  tree block = c_begin_compound_stmt (flag_isoc99);
+  while (c_parser_next_token_is_keyword (parser, RID_CASE)
+        || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+        || (c_parser_next_token_is (parser, CPP_NAME)
+            && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+    c_parser_label (parser);
+  *if_p = c_parser_next_token_is_keyword (parser, RID_IF);
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+    {
+      location_t loc = c_parser_peek_token (parser)->location;
+      add_stmt (build_empty_stmt ());
+      c_parser_consume_token (parser);
+      if (!c_parser_next_token_is_keyword (parser, RID_ELSE))
+       warning_at (loc, OPT_Wempty_body,
+                   "suggest braces around empty body in an %<if%> statement");
+    }
+  else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    add_stmt (c_parser_compound_statement (parser));
+  else
+    c_parser_statement_after_labels (parser);
+  return c_end_compound_stmt (block, flag_isoc99);
+}
+
+/* Parse the else body of an if statement.  This is just parsing a
+   statement but (a) it is a block in C99, (b) we handle an empty body
+   specially for the sake of -Wempty-body warnings.  */
+
+static tree
+c_parser_else_body (c_parser *parser)
+{
+  tree block = c_begin_compound_stmt (flag_isoc99);
+  while (c_parser_next_token_is_keyword (parser, RID_CASE)
+        || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+        || (c_parser_next_token_is (parser, CPP_NAME)
+            && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+    c_parser_label (parser);
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+    {
+      warning_at (c_parser_peek_token (parser)->location,
+                 OPT_Wempty_body,
+                "suggest braces around empty body in an %<else%> statement");
+      add_stmt (build_empty_stmt ());
+      c_parser_consume_token (parser);
+    }
+  else 
+    c_parser_statement_after_labels (parser);
+  return c_end_compound_stmt (block, flag_isoc99);
+}
+
+/* Parse an if statement (C90 6.6.4, C99 6.8.4).
+
+   if-statement:
+     if ( expression ) statement
+     if ( expression ) statement else statement
+*/
+
+static void
+c_parser_if_statement (c_parser *parser)
+{
+  tree block;
+  location_t loc;
+  tree cond;
+  bool first_if = false;
+  tree first_body, second_body;
+  bool in_if_block;
+
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF));
+  c_parser_consume_token (parser);
+  block = c_begin_compound_stmt (flag_isoc99);
+  loc = c_parser_peek_token (parser)->location;
+  cond = c_parser_paren_condition (parser);
+  in_if_block = parser->in_if_block;
+  parser->in_if_block = true;
+  first_body = c_parser_if_body (parser, &first_if);
+  parser->in_if_block = in_if_block;
+  if (c_parser_next_token_is_keyword (parser, RID_ELSE))
+    {
+      c_parser_consume_token (parser);
+      second_body = c_parser_else_body (parser);
+    }
+  else
+    second_body = NULL_TREE;
+  c_finish_if_stmt (loc, cond, first_body, second_body, first_if);
+  add_stmt (c_end_compound_stmt (block, flag_isoc99));
+}
+
+/* Parse a switch statement (C90 6.6.4, C99 6.8.4).
+
+   switch-statement:
+     switch (expression) statement
+*/
+
+static void
+c_parser_switch_statement (c_parser *parser)
+{
+  tree block, expr, body, save_break;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH));
+  c_parser_consume_token (parser);
+  block = c_begin_compound_stmt (flag_isoc99);
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      expr = c_parser_expression (parser).value;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  else
+    expr = error_mark_node;
+  c_start_case (expr);
+  save_break = c_break_label;
+  c_break_label = NULL_TREE;
+  body = c_parser_c99_block_statement (parser);
+  c_finish_case (body);
+  if (c_break_label)
+    add_stmt (build1 (LABEL_EXPR, void_type_node, c_break_label));
+  c_break_label = save_break;
+  add_stmt (c_end_compound_stmt (block, flag_isoc99));
+}
+
+/* Parse a while statement (C90 6.6.5, C99 6.8.5).
+
+   while-statement:
+      while (expression) statement
+*/
+
+static void
+c_parser_while_statement (c_parser *parser)
+{
+  tree block, cond, body, save_break, save_cont;
+  location_t loc;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE));
+  c_parser_consume_token (parser);
+  block = c_begin_compound_stmt (flag_isoc99);
+  loc = c_parser_peek_token (parser)->location;
+  cond = c_parser_paren_condition (parser);
+  save_break = c_break_label;
+  c_break_label = NULL_TREE;
+  save_cont = c_cont_label;
+  c_cont_label = NULL_TREE;
+  body = c_parser_c99_block_statement (parser);
+  c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, true);
+  add_stmt (c_end_compound_stmt (block, flag_isoc99));
+  c_break_label = save_break;
+  c_cont_label = save_cont;
+}
+
+/* Parse a do statement (C90 6.6.5, C99 6.8.5).
+
+   do-statement:
+     do statement while ( expression ) ;
+*/
+
+static void
+c_parser_do_statement (c_parser *parser)
+{
+  tree block, cond, body, save_break, save_cont, new_break, new_cont;
+  location_t loc;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO));
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+    warning_at (c_parser_peek_token (parser)->location,
+               OPT_Wempty_body,
+               "suggest braces around empty body in %<do%> statement");
+  block = c_begin_compound_stmt (flag_isoc99);
+  loc = c_parser_peek_token (parser)->location;
+  save_break = c_break_label;
+  c_break_label = NULL_TREE;
+  save_cont = c_cont_label;
+  c_cont_label = NULL_TREE;
+  body = c_parser_c99_block_statement (parser);
+  c_parser_require_keyword (parser, RID_WHILE, "expected %<while%>");
+  new_break = c_break_label;
+  c_break_label = save_break;
+  new_cont = c_cont_label;
+  c_cont_label = save_cont;
+  cond = c_parser_paren_condition (parser);
+  if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+    c_parser_skip_to_end_of_block_or_statement (parser);
+  c_finish_loop (loc, cond, NULL, body, new_break, new_cont, false);
+  add_stmt (c_end_compound_stmt (block, flag_isoc99));
+}
+
+/* Parse a for statement (C90 6.6.5, C99 6.8.5).
+
+   for-statement:
+     for ( expression[opt] ; expression[opt] ; expression[opt] ) statement
+     for ( nested-declaration expression[opt] ; expression[opt] ) statement
+
+   The form with a declaration is new in C99.
+
+   ??? In accordance with the old parser, the declaration may be a
+   nested function, which is then rejected in check_for_loop_decls,
+   but does it make any sense for this to be included in the grammar?
+   Note in particular that the nested function does not include a
+   trailing ';', whereas the "declaration" production includes one.
+   Also, can we reject bad declarations earlier and cheaper than
+   check_for_loop_decls?  */
+
+static void
+c_parser_for_statement (c_parser *parser)
+{
+  tree block, cond, incr, save_break, save_cont, body;
+  location_t loc;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR));
+  loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_token (parser);
+  block = c_begin_compound_stmt (flag_isoc99);
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      /* Parse the initialization declaration or expression.  */
+      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+       {
+         c_parser_consume_token (parser);
+         c_finish_expr_stmt (NULL_TREE);
+       }
+      else if (c_parser_next_token_starts_declspecs (parser))
+       {
+         c_parser_declaration_or_fndef (parser, true, true, true, true);
+         check_for_loop_decls ();
+       }
+      else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+       {
+         /* __extension__ can start a declaration, but is also an
+            unary operator that can start an expression.  Consume all
+            but the last of a possible series of __extension__ to
+            determine which.  */
+         while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD
+                && (c_parser_peek_2nd_token (parser)->keyword
+                    == RID_EXTENSION))
+           c_parser_consume_token (parser);
+         if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser)))
+           {
+             int ext;
+             ext = disable_extension_diagnostics ();
+             c_parser_consume_token (parser);
+             c_parser_declaration_or_fndef (parser, true, true, true, true);
+             restore_extension_diagnostics (ext);
+             check_for_loop_decls ();
+           }
+         else
+           goto init_expr;
+       }
+      else
+       {
+       init_expr:
+         c_finish_expr_stmt (c_parser_expression (parser).value);
+         c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+       }
+      /* Parse the loop condition.  */
+      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+       {
+         c_parser_consume_token (parser);
+         cond = NULL_TREE;
+       }
+      else
+       {
+         cond = c_parser_condition (parser);
+         c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+       }
+      /* Parse the increment expression.  */
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       incr = c_process_expr_stmt (NULL_TREE);
+      else
+       incr = c_process_expr_stmt (c_parser_expression (parser).value);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  else
+    {
+      cond = error_mark_node;
+      incr = error_mark_node;
+    }
+  save_break = c_break_label;
+  c_break_label = NULL_TREE;
+  save_cont = c_cont_label;
+  c_cont_label = NULL_TREE;
+  body = c_parser_c99_block_statement (parser);
+  c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, true);
+  add_stmt (c_end_compound_stmt (block, flag_isoc99));
+  c_break_label = save_break;
+  c_cont_label = save_cont;
+}
+
+/* Parse an asm statement, a GNU extension.  This is a full-blown asm
+   statement with inputs, outputs, clobbers, and volatile tag
+   allowed.
+
+   asm-statement:
+     asm type-qualifier[opt] ( asm-argument ) ;
+
+   asm-argument:
+     asm-string-literal
+     asm-string-literal : asm-operands[opt]
+     asm-string-literal : asm-operands[opt] : asm-operands[opt]
+     asm-string-literal : asm-operands[opt] : asm-operands[opt] : asm-clobbers
+
+   Qualifiers other than volatile are accepted in the syntax but
+   warned for.  */
+
+static tree
+c_parser_asm_statement (c_parser *parser)
+{
+  tree quals, str, outputs, inputs, clobbers, ret;
+  bool simple;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is_keyword (parser, RID_VOLATILE))
+    {
+      quals = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+    }
+  else if (c_parser_next_token_is_keyword (parser, RID_CONST)
+          || c_parser_next_token_is_keyword (parser, RID_RESTRICT))
+    {
+      warning_at (c_parser_peek_token (parser)->location,
+                 0,
+                 "%E qualifier ignored on asm",
+                 c_parser_peek_token (parser)->value);
+      quals = NULL_TREE;
+      c_parser_consume_token (parser);
+    }
+  else
+    quals = NULL_TREE;
+  /* ??? Follow the C++ parser rather than using the
+     lex_untranslated_string kludge.  */
+  parser->lex_untranslated_string = true;
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      parser->lex_untranslated_string = false;
+      return NULL_TREE;
+    }
+  str = c_parser_asm_string_literal (parser);
+  if (str == NULL_TREE)
+    {
+      parser->lex_untranslated_string = false;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return NULL_TREE;
+    }
+  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    {
+      simple = true;
+      outputs = NULL_TREE;
+      inputs = NULL_TREE;
+      clobbers = NULL_TREE;
+      goto done_asm;
+    }
+  if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
+    {
+      parser->lex_untranslated_string = false;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return NULL_TREE;
+    }
+  simple = false;
+  /* Parse outputs.  */
+  if (c_parser_next_token_is (parser, CPP_COLON)
+      || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    outputs = NULL_TREE;
+  else
+    outputs = c_parser_asm_operands (parser, false);
+  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    {
+      inputs = NULL_TREE;
+      clobbers = NULL_TREE;
+      goto done_asm;
+    }
+  if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
+    {
+      parser->lex_untranslated_string = false;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return NULL_TREE;
+    }
+  /* Parse inputs.  */
+  if (c_parser_next_token_is (parser, CPP_COLON)
+      || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    inputs = NULL_TREE;
+  else
+    inputs = c_parser_asm_operands (parser, true);
+  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+    {
+      clobbers = NULL_TREE;
+      goto done_asm;
+    }
+  if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
+    {
+      parser->lex_untranslated_string = false;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return NULL_TREE;
+    }
+  /* Parse clobbers.  */
+  clobbers = c_parser_asm_clobbers (parser);
+ done_asm:
+  parser->lex_untranslated_string = false;
+  if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+    {
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return NULL_TREE;
+    }
+  if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+    c_parser_skip_to_end_of_block_or_statement (parser);
+  ret = build_asm_stmt (quals, build_asm_expr (str, outputs, inputs,
+                                              clobbers, simple));
+  return ret;
+}
+
+/* Parse asm operands, a GNU extension.  If CONVERT_P (for inputs but
+   not outputs), apply the default conversion of functions and arrays
+   to pointers.
+
+   asm-operands:
+     asm-operand
+     asm-operands , asm-operand
+
+   asm-operand:
+     asm-string-literal ( expression )
+     [ identifier ] asm-string-literal ( expression )
+*/
+
+static tree
+c_parser_asm_operands (c_parser *parser, bool convert_p)
+{
+  tree list = NULL_TREE;
+  while (true)
+    {
+      tree name, str;
+      struct c_expr expr;
+      if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+       {
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_NAME))
+           {
+             tree id = c_parser_peek_token (parser)->value;
+             c_parser_consume_token (parser);
+             name = build_string (IDENTIFIER_LENGTH (id),
+                                  IDENTIFIER_POINTER (id));
+           }
+         else
+           {
+             c_parser_error (parser, "expected identifier");
+             c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
+             return NULL_TREE;
+           }
+         c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                    "expected %<]%>");
+       }
+      else
+       name = NULL_TREE;
+      str = c_parser_asm_string_literal (parser);
+      if (str == NULL_TREE)
+       return NULL_TREE;
+      parser->lex_untranslated_string = false;
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+       {
+         parser->lex_untranslated_string = true;
+         return NULL_TREE;
+       }
+      expr = c_parser_expression (parser);
+      if (convert_p)
+       expr = default_function_array_conversion (expr);
+      parser->lex_untranslated_string = true;
+      if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+         return NULL_TREE;
+       }
+      list = chainon (list, build_tree_list (build_tree_list (name, str),
+                                            expr.value));
+      if (c_parser_next_token_is (parser, CPP_COMMA))
+       c_parser_consume_token (parser);
+      else
+       break;
+    }
+  return list;
+}
+
+/* Parse asm clobbers, a GNU extension.
+
+   asm-clobbers:
+     asm-string-literal
+     asm-clobbers , asm-string-literal
+*/
+
+static tree
+c_parser_asm_clobbers (c_parser *parser)
+{
+  tree list = NULL_TREE;
+  while (true)
+    {
+      tree str = c_parser_asm_string_literal (parser);
+      if (str)
+       list = tree_cons (NULL_TREE, str, list);
+      else
+       return NULL_TREE;
+      if (c_parser_next_token_is (parser, CPP_COMMA))
+       c_parser_consume_token (parser);
+      else
+       break;
+    }
+  return list;
+}
+
+/* Parse an expression other than a compound expression; that is, an
+   assignment expression (C90 6.3.16, C99 6.5.16).  If AFTER is not
+   NULL then it is an Objective-C message expression which is the
+   primary-expression starting the expression as an initializer.
+
+   assignment-expression:
+     conditional-expression
+     unary-expression assignment-operator assignment-expression
+
+   assignment-operator: one of
+     = *= /= %= += -= <<= >>= &= ^= |=
+
+   In GNU C we accept any conditional expression on the LHS and
+   diagnose the invalid lvalue rather than producing a syntax
+   error.  */
+
+static struct c_expr
+c_parser_expr_no_commas (c_parser *parser, struct c_expr *after)
+{
+  struct c_expr lhs, rhs, ret;
+  enum tree_code code;
+  location_t op_location;
+  gcc_assert (!after || c_dialect_objc ());
+  lhs = c_parser_conditional_expression (parser, after);
+  op_location = c_parser_peek_token (parser)->location;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_EQ:
+      code = NOP_EXPR;
+      break;
+    case CPP_MULT_EQ:
+      code = MULT_EXPR;
+      break;
+    case CPP_DIV_EQ:
+      code = TRUNC_DIV_EXPR;
+      break;
+    case CPP_MOD_EQ:
+      code = TRUNC_MOD_EXPR;
+      break;
+    case CPP_PLUS_EQ:
+      code = PLUS_EXPR;
+      break;
+    case CPP_MINUS_EQ:
+      code = MINUS_EXPR;
+      break;
+    case CPP_LSHIFT_EQ:
+      code = LSHIFT_EXPR;
+      break;
+    case CPP_RSHIFT_EQ:
+      code = RSHIFT_EXPR;
+      break;
+    case CPP_AND_EQ:
+      code = BIT_AND_EXPR;
+      break;
+    case CPP_XOR_EQ:
+      code = BIT_XOR_EXPR;
+      break;
+    case CPP_OR_EQ:
+      code = BIT_IOR_EXPR;
+      break;
+    default:
+      return lhs;
+    }
+  c_parser_consume_token (parser);
+  rhs = c_parser_expr_no_commas (parser, NULL);
+  rhs = default_function_array_conversion (rhs);
+  ret.value = build_modify_expr (op_location, lhs.value, code, rhs.value);
+  if (code == NOP_EXPR)
+    ret.original_code = MODIFY_EXPR;
+  else
+    {
+      TREE_NO_WARNING (ret.value) = 1;
+      ret.original_code = ERROR_MARK;
+    }
+  return ret;
+}
+
+/* Parse a conditional expression (C90 6.3.15, C99 6.5.15).  If AFTER
+   is not NULL then it is an Objective-C message expression which is
+   the primary-expression starting the expression as an initializer.
+
+   conditional-expression:
+     logical-OR-expression
+     logical-OR-expression ? expression : conditional-expression
+
+   GNU extensions:
+
+   conditional-expression:
+     logical-OR-expression ? : conditional-expression
+*/
+
+static struct c_expr
+c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
+{
+  struct c_expr cond, exp1, exp2, ret;
+  location_t cond_loc;
+
+  gcc_assert (!after || c_dialect_objc ());
+
+  cond_loc = c_parser_peek_token (parser)->location;
+  cond = c_parser_binary_expression (parser, after);
+  protected_set_expr_location (cond.value, cond_loc);
+
+  if (c_parser_next_token_is_not (parser, CPP_QUERY))
+    return cond;
+  cond = default_function_array_conversion (cond);
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is (parser, CPP_COLON))
+    {
+      pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
+              "ISO C forbids omitting the middle term of a ?: expression");
+      /* Make sure first operand is calculated only once.  */
+      exp1.value = save_expr (default_conversion (cond.value));
+      cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value);
+      skip_evaluation += cond.value == truthvalue_true_node;
+    }
+  else
+    {
+      cond.value
+       = c_objc_common_truthvalue_conversion
+       (cond_loc, default_conversion (cond.value));
+      skip_evaluation += cond.value == truthvalue_false_node;
+      exp1 = c_parser_expression_conv (parser);
+      skip_evaluation += ((cond.value == truthvalue_true_node)
+                         - (cond.value == truthvalue_false_node));
+    }
+  if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+    {
+      skip_evaluation -= cond.value == truthvalue_true_node;
+      ret.value = error_mark_node;
+      ret.original_code = ERROR_MARK;
+      return ret;
+    }
+  exp2 = c_parser_conditional_expression (parser, NULL);
+  exp2 = default_function_array_conversion (exp2);
+  skip_evaluation -= cond.value == truthvalue_true_node;
+  ret.value = build_conditional_expr (cond.value, exp1.value, exp2.value);
+  ret.original_code = ERROR_MARK;
+  return ret;
+}
+
+/* Parse a binary expression; that is, a logical-OR-expression (C90
+   6.3.5-6.3.14, C99 6.5.5-6.5.14).  If AFTER is not NULL then it is
+   an Objective-C message expression which is the primary-expression
+   starting the expression as an initializer.
+
+   multiplicative-expression:
+     cast-expression
+     multiplicative-expression * cast-expression
+     multiplicative-expression / cast-expression
+     multiplicative-expression % cast-expression
+
+   additive-expression:
+     multiplicative-expression
+     additive-expression + multiplicative-expression
+     additive-expression - multiplicative-expression
+
+   shift-expression:
+     additive-expression
+     shift-expression << additive-expression
+     shift-expression >> additive-expression
+
+   relational-expression:
+     shift-expression
+     relational-expression < shift-expression
+     relational-expression > shift-expression
+     relational-expression <= shift-expression
+     relational-expression >= shift-expression
+
+   equality-expression:
+     relational-expression
+     equality-expression == relational-expression
+     equality-expression != relational-expression
+
+   AND-expression:
+     equality-expression
+     AND-expression & equality-expression
+
+   exclusive-OR-expression:
+     AND-expression
+     exclusive-OR-expression ^ AND-expression
+
+   inclusive-OR-expression:
+     exclusive-OR-expression
+     inclusive-OR-expression | exclusive-OR-expression
+
+   logical-AND-expression:
+     inclusive-OR-expression
+     logical-AND-expression && inclusive-OR-expression
+
+   logical-OR-expression:
+     logical-AND-expression
+     logical-OR-expression || logical-AND-expression
+*/
+
+static struct c_expr
+c_parser_binary_expression (c_parser *parser, struct c_expr *after)
+{
+  /* A binary expression is parsed using operator-precedence parsing,
+     with the operands being cast expressions.  All the binary
+     operators are left-associative.  Thus a binary expression is of
+     form:
+
+     E0 op1 E1 op2 E2 ...
+
+     which we represent on a stack.  On the stack, the precedence
+     levels are strictly increasing.  When a new operator is
+     encountered of higher precedence than that at the top of the
+     stack, it is pushed; its LHS is the top expression, and its RHS
+     is everything parsed until it is popped.  When a new operator is
+     encountered with precedence less than or equal to that at the top
+     of the stack, triples E[i-1] op[i] E[i] are popped and replaced
+     by the result of the operation until the operator at the top of
+     the stack has lower precedence than the new operator or there is
+     only one element on the stack; then the top expression is the LHS
+     of the new operator.  In the case of logical AND and OR
+     expressions, we also need to adjust skip_evaluation as
+     appropriate when the operators are pushed and popped.  */
+
+  /* The precedence levels, where 0 is a dummy lowest level used for
+     the bottom of the stack.  */
+  enum prec {
+    PREC_NONE,
+    PREC_LOGOR,
+    PREC_LOGAND,
+    PREC_BITOR,
+    PREC_BITXOR,
+    PREC_BITAND,
+    PREC_EQ,
+    PREC_REL,
+    PREC_SHIFT,
+    PREC_ADD,
+    PREC_MULT,
+    NUM_PRECS
+  };
+  struct {
+    /* The expression at this stack level.  */
+    struct c_expr expr;
+    /* The precedence of the operator on its left, PREC_NONE at the
+       bottom of the stack.  */
+    enum prec prec;
+    /* The operation on its left.  */
+    enum tree_code op;
+  } stack[NUM_PRECS];
+  int sp;
+  /* Location of the binary operator.  */
+  location_t binary_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
+#define POP                                                                  \
+  do {                                                                       \
+    switch (stack[sp].op)                                                    \
+      {                                                                              \
+      case TRUTH_ANDIF_EXPR:                                                 \
+       skip_evaluation -= stack[sp - 1].expr.value == truthvalue_false_node; \
+       break;                                                                \
+      case TRUTH_ORIF_EXPR:                                                  \
+       skip_evaluation -= stack[sp - 1].expr.value == truthvalue_true_node;  \
+       break;                                                                \
+      default:                                                               \
+       break;                                                                \
+      }                                                                              \
+    stack[sp - 1].expr                                                       \
+      = default_function_array_conversion (stack[sp - 1].expr);                      \
+    stack[sp].expr                                                           \
+      = default_function_array_conversion (stack[sp].expr);                  \
+    stack[sp - 1].expr = parser_build_binary_op (binary_loc,                 \
+                                                stack[sp].op,                \
+                                                stack[sp - 1].expr,          \
+                                                stack[sp].expr);             \
+    sp--;                                                                    \
+  } while (0)
+  gcc_assert (!after || c_dialect_objc ());
+  stack[0].expr = c_parser_cast_expression (parser, after);
+  stack[0].prec = PREC_NONE;
+  sp = 0;
+  while (true)
+    {
+      enum prec oprec;
+      enum tree_code ocode;
+      if (parser->error)
+       goto out;
+      switch (c_parser_peek_token (parser)->type)
+       {
+       case CPP_MULT:
+         oprec = PREC_MULT;
+         ocode = MULT_EXPR;
+         break;
+       case CPP_DIV:
+         oprec = PREC_MULT;
+         ocode = TRUNC_DIV_EXPR;
+         break;
+       case CPP_MOD:
+         oprec = PREC_MULT;
+         ocode = TRUNC_MOD_EXPR;
+         break;
+       case CPP_PLUS:
+         oprec = PREC_ADD;
+         ocode = PLUS_EXPR;
+         break;
+       case CPP_MINUS:
+         oprec = PREC_ADD;
+         ocode = MINUS_EXPR;
+         break;
+       case CPP_LSHIFT:
+         oprec = PREC_SHIFT;
+         ocode = LSHIFT_EXPR;
+         break;
+       case CPP_RSHIFT:
+         oprec = PREC_SHIFT;
+         ocode = RSHIFT_EXPR;
+         break;
+       case CPP_LESS:
+         oprec = PREC_REL;
+         ocode = LT_EXPR;
+         break;
+       case CPP_GREATER:
+         oprec = PREC_REL;
+         ocode = GT_EXPR;
+         break;
+       case CPP_LESS_EQ:
+         oprec = PREC_REL;
+         ocode = LE_EXPR;
+         break;
+       case CPP_GREATER_EQ:
+         oprec = PREC_REL;
+         ocode = GE_EXPR;
+         break;
+       case CPP_EQ_EQ:
+         oprec = PREC_EQ;
+         ocode = EQ_EXPR;
+         break;
+       case CPP_NOT_EQ:
+         oprec = PREC_EQ;
+         ocode = NE_EXPR;
+         break;
+       case CPP_AND:
+         oprec = PREC_BITAND;
+         ocode = BIT_AND_EXPR;
+         break;
+       case CPP_XOR:
+         oprec = PREC_BITXOR;
+         ocode = BIT_XOR_EXPR;
+         break;
+       case CPP_OR:
+         oprec = PREC_BITOR;
+         ocode = BIT_IOR_EXPR;
+         break;
+       case CPP_AND_AND:
+         oprec = PREC_LOGAND;
+         ocode = TRUTH_ANDIF_EXPR;
+         break;
+       case CPP_OR_OR:
+         oprec = PREC_LOGOR;
+         ocode = TRUTH_ORIF_EXPR;
+         break;
+       default:
+         /* Not a binary operator, so end of the binary
+            expression.  */
+         goto out;
+       }
+      binary_loc = c_parser_peek_token (parser)->location;
+      c_parser_consume_token (parser);
+      while (oprec <= stack[sp].prec)
+       POP;
+      switch (ocode)
+       {
+       case TRUTH_ANDIF_EXPR:
+         stack[sp].expr
+           = default_function_array_conversion (stack[sp].expr);
+         stack[sp].expr.value = c_objc_common_truthvalue_conversion
+           (binary_loc, default_conversion (stack[sp].expr.value));
+         skip_evaluation += stack[sp].expr.value == truthvalue_false_node;
+         break;
+       case TRUTH_ORIF_EXPR:
+         stack[sp].expr
+           = default_function_array_conversion (stack[sp].expr);
+         stack[sp].expr.value = c_objc_common_truthvalue_conversion
+           (binary_loc, default_conversion (stack[sp].expr.value));
+         skip_evaluation += stack[sp].expr.value == truthvalue_true_node;
+         break;
+       default:
+         break;
+       }
+      sp++;
+      stack[sp].expr = c_parser_cast_expression (parser, NULL);
+      stack[sp].prec = oprec;
+      stack[sp].op = ocode;
+    }
+ out:
+  while (sp > 0)
+    POP;
+  return stack[0].expr;
+#undef POP
+}
+
+/* Parse a cast expression (C90 6.3.4, C99 6.5.4).  If AFTER is not
+   NULL then it is an Objective-C message expression which is the
+   primary-expression starting the expression as an initializer.
+
+   cast-expression:
+     unary-expression
+     ( type-name ) unary-expression
+*/
+
+static struct c_expr
+c_parser_cast_expression (c_parser *parser, struct c_expr *after)
+{
+  gcc_assert (!after || c_dialect_objc ());
+  if (after)
+    return c_parser_postfix_expression_after_primary (parser, *after);
+  /* If the expression begins with a parenthesized type name, it may
+     be either a cast or a compound literal; we need to see whether
+     the next character is '{' to tell the difference.  If not, it is
+     an unary expression.  */
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+      && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+    {
+      struct c_type_name *type_name;
+      struct c_expr ret;
+      struct c_expr expr;
+      c_parser_consume_token (parser);
+      type_name = c_parser_type_name (parser);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      if (type_name == NULL)
+       {
+         ret.value = error_mark_node;
+         ret.original_code = ERROR_MARK;
+         return ret;
+       }
+
+      /* Save casted types in the function's used types hash table.  */
+      used_types_insert (type_name->specs->type);
+
+      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+       return c_parser_postfix_expression_after_paren_type (parser,
+                                                            type_name);
+      expr = c_parser_cast_expression (parser, NULL);
+      expr = default_function_array_conversion (expr);
+      ret.value = c_cast_expr (type_name, expr.value);
+      ret.original_code = ERROR_MARK;
+      return ret;
+    }
+  else
+    return c_parser_unary_expression (parser);
+}
+
+/* Parse an unary expression (C90 6.3.3, C99 6.5.3).
+
+   unary-expression:
+     postfix-expression
+     ++ unary-expression
+     -- unary-expression
+     unary-operator cast-expression
+     sizeof unary-expression
+     sizeof ( type-name )
+
+   unary-operator: one of
+     & * + - ~ !
+
+   GNU extensions:
+
+   unary-expression:
+     __alignof__ unary-expression
+     __alignof__ ( type-name )
+     && identifier
+
+   unary-operator: one of
+     __extension__ __real__ __imag__
+
+   In addition, the GNU syntax treats ++ and -- as unary operators, so
+   they may be applied to cast expressions with errors for non-lvalues
+   given later.  */
+
+static struct c_expr
+c_parser_unary_expression (c_parser *parser)
+{
+  int ext;
+  struct c_expr ret, op;
+  location_t loc = c_parser_peek_token (parser)->location;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_PLUS_PLUS:
+      c_parser_consume_token (parser);
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (op);
+      return parser_build_unary_op (PREINCREMENT_EXPR, op, loc);
+    case CPP_MINUS_MINUS:
+      c_parser_consume_token (parser);
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (op);
+      return parser_build_unary_op (PREDECREMENT_EXPR, op, loc);
+    case CPP_AND:
+      c_parser_consume_token (parser);
+      return parser_build_unary_op (ADDR_EXPR,
+                                   c_parser_cast_expression (parser, NULL),
+                                   loc);
+    case CPP_MULT:
+      c_parser_consume_token (parser);
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (op);
+      ret.value = build_indirect_ref (loc, op.value, "unary *");
+      ret.original_code = ERROR_MARK;
+      return ret;
+    case CPP_PLUS:
+      if (!c_dialect_objc () && !in_system_header)
+       warning_at (c_parser_peek_token (parser)->location,
+                   OPT_Wtraditional,
+                   "traditional C rejects the unary plus operator");
+      c_parser_consume_token (parser);
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (op);
+      return parser_build_unary_op (CONVERT_EXPR, op, loc);
+    case CPP_MINUS:
+      c_parser_consume_token (parser);
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (op);
+      return parser_build_unary_op (NEGATE_EXPR, op, loc);
+    case CPP_COMPL:
+      c_parser_consume_token (parser);
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (op);
+      return parser_build_unary_op (BIT_NOT_EXPR, op, loc);
+    case CPP_NOT:
+      c_parser_consume_token (parser);
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (op);
+      return parser_build_unary_op (TRUTH_NOT_EXPR, op, loc);
+    case CPP_AND_AND:
+      /* Refer to the address of a label as a pointer.  */
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_NAME))
+       {
+         ret.value = finish_label_address_expr
+           (c_parser_peek_token (parser)->value, loc);
+         c_parser_consume_token (parser);
+       }
+      else
+       {
+         c_parser_error (parser, "expected identifier");
+         ret.value = error_mark_node;
+       }
+       ret.original_code = ERROR_MARK;
+       return ret;
+    case CPP_KEYWORD:
+      switch (c_parser_peek_token (parser)->keyword)
+       {
+       case RID_SIZEOF:
+         return c_parser_sizeof_expression (parser);
+       case RID_ALIGNOF:
+         return c_parser_alignof_expression (parser);
+       case RID_EXTENSION:
+         c_parser_consume_token (parser);
+         ext = disable_extension_diagnostics ();
+         ret = c_parser_cast_expression (parser, NULL);
+         restore_extension_diagnostics (ext);
+         return ret;
+       case RID_REALPART:
+         c_parser_consume_token (parser);
+         op = c_parser_cast_expression (parser, NULL);
+         op = default_function_array_conversion (op);
+         return parser_build_unary_op (REALPART_EXPR, op, loc);
+       case RID_IMAGPART:
+         c_parser_consume_token (parser);
+         op = c_parser_cast_expression (parser, NULL);
+         op = default_function_array_conversion (op);
+         return parser_build_unary_op (IMAGPART_EXPR, op, loc);
+       default:
+         return c_parser_postfix_expression (parser);
+       }
+    default:
+      return c_parser_postfix_expression (parser);
+    }
+}
+
+/* Parse a sizeof expression.  */
+
+static struct c_expr
+c_parser_sizeof_expression (c_parser *parser)
+{
+  struct c_expr expr;
+  location_t expr_loc;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
+  c_parser_consume_token (parser);
+  skip_evaluation++;
+  in_sizeof++;
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+      && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+    {
+      /* Either sizeof ( type-name ) or sizeof unary-expression
+        starting with a compound literal.  */
+      struct c_type_name *type_name;
+      c_parser_consume_token (parser);
+      expr_loc = c_parser_peek_token (parser)->location;
+      type_name = c_parser_type_name (parser);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      if (type_name == NULL)
+       {
+         struct c_expr ret;
+         skip_evaluation--;
+         in_sizeof--;
+         ret.value = error_mark_node;
+         ret.original_code = ERROR_MARK;
+         return ret;
+       }
+      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+       {
+         expr = c_parser_postfix_expression_after_paren_type (parser,
+                                                              type_name);
+         goto sizeof_expr;
+       }
+      /* sizeof ( type-name ).  */
+      skip_evaluation--;
+      in_sizeof--;
+      return c_expr_sizeof_type (type_name);
+    }
+  else
+    {
+      expr_loc = c_parser_peek_token (parser)->location;
+      expr = c_parser_unary_expression (parser);
+    sizeof_expr:
+      skip_evaluation--;
+      in_sizeof--;
+      if (TREE_CODE (expr.value) == COMPONENT_REF
+         && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
+       error_at (expr_loc, "%<sizeof%> applied to a bit-field");
+      return c_expr_sizeof_expr (expr);
+    }
+}
+
+/* Parse an alignof expression.  */
+
+static struct c_expr
+c_parser_alignof_expression (c_parser *parser)
+{
+  struct c_expr expr;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF));
+  c_parser_consume_token (parser);
+  skip_evaluation++;
+  in_alignof++;
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+      && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+    {
+      /* Either __alignof__ ( type-name ) or __alignof__
+        unary-expression starting with a compound literal.  */
+      struct c_type_name *type_name;
+      struct c_expr ret;
+      c_parser_consume_token (parser);
+      type_name = c_parser_type_name (parser);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      if (type_name == NULL)
+       {
+         struct c_expr ret;
+         skip_evaluation--;
+         in_alignof--;
+         ret.value = error_mark_node;
+         ret.original_code = ERROR_MARK;
+         return ret;
+       }
+      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+       {
+         expr = c_parser_postfix_expression_after_paren_type (parser,
+                                                              type_name);
+         goto alignof_expr;
+       }
+      /* alignof ( type-name ).  */
+      skip_evaluation--;
+      in_alignof--;
+      ret.value = c_alignof (groktypename (type_name));
+      ret.original_code = ERROR_MARK;
+      return ret;
+    }
+  else
+    {
+      struct c_expr ret;
+      expr = c_parser_unary_expression (parser);
+    alignof_expr:
+      skip_evaluation--;
+      in_alignof--;
+      ret.value = c_alignof_expr (expr.value);
+      ret.original_code = ERROR_MARK;
+      return ret;
+    }
+}
+
+/* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2).
+
+   postfix-expression:
+     primary-expression
+     postfix-expression [ expression ]
+     postfix-expression ( argument-expression-list[opt] )
+     postfix-expression . identifier
+     postfix-expression -> identifier
+     postfix-expression ++
+     postfix-expression --
+     ( type-name ) { initializer-list }
+     ( type-name ) { initializer-list , }
+
+   argument-expression-list:
+     argument-expression
+     argument-expression-list , argument-expression
+
+   primary-expression:
+     identifier
+     constant
+     string-literal
+     ( expression )
+
+   GNU extensions:
+
+   primary-expression:
+     __func__
+       (treated as a keyword in GNU C)
+     __FUNCTION__
+     __PRETTY_FUNCTION__
+     ( compound-statement )
+     __builtin_va_arg ( assignment-expression , type-name )
+     __builtin_offsetof ( type-name , offsetof-member-designator )
+     __builtin_choose_expr ( assignment-expression ,
+                            assignment-expression ,
+                            assignment-expression )
+     __builtin_types_compatible_p ( type-name , type-name )
+
+   offsetof-member-designator:
+     identifier
+     offsetof-member-designator . identifier
+     offsetof-member-designator [ expression ]
+
+   Objective-C:
+
+   primary-expression:
+     [ objc-receiver objc-message-args ]
+     @selector ( objc-selector-arg )
+     @protocol ( identifier )
+     @encode ( type-name )
+     objc-string-literal
+*/
+
+static struct c_expr
+c_parser_postfix_expression (c_parser *parser)
+{
+  struct c_expr expr, e1, e2, e3;
+  struct c_type_name *t1, *t2;
+  location_t loc;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_NUMBER:
+      expr.value = c_parser_peek_token (parser)->value;
+      expr.original_code = ERROR_MARK;
+      loc = c_parser_peek_token (parser)->location;
+      c_parser_consume_token (parser);
+      if (TREE_CODE (expr.value) == FIXED_CST
+         && !targetm.fixed_point_supported_p ())
+       {
+         error_at (loc, "fixed-point types not supported for this target");
+         expr.value = error_mark_node;
+       }
+      break;
+    case CPP_CHAR:
+    case CPP_CHAR16:
+    case CPP_CHAR32:
+    case CPP_WCHAR:
+      expr.value = c_parser_peek_token (parser)->value;
+      expr.original_code = ERROR_MARK;
+      c_parser_consume_token (parser);
+      break;
+    case CPP_STRING:
+    case CPP_STRING16:
+    case CPP_STRING32:
+    case CPP_WSTRING:
+      expr.value = c_parser_peek_token (parser)->value;
+      expr.original_code = STRING_CST;
+      c_parser_consume_token (parser);
+      break;
+    case CPP_OBJC_STRING:
+      gcc_assert (c_dialect_objc ());
+      expr.value
+       = objc_build_string_object (c_parser_peek_token (parser)->value);
+      expr.original_code = ERROR_MARK;
+      c_parser_consume_token (parser);
+      break;
+    case CPP_NAME:
+      if (c_parser_peek_token (parser)->id_kind != C_ID_ID)
+       {
+         c_parser_error (parser, "expected expression");
+         expr.value = error_mark_node;
+         expr.original_code = ERROR_MARK;
+         break;
+       }
+      {
+       tree id = c_parser_peek_token (parser)->value;
+       location_t loc = c_parser_peek_token (parser)->location;
+       c_parser_consume_token (parser);
+       expr.value = build_external_ref (id,
+                                        (c_parser_peek_token (parser)->type
+                                         == CPP_OPEN_PAREN), loc);
+       expr.original_code = ERROR_MARK;
+      }
+      break;
+    case CPP_OPEN_PAREN:
+      /* A parenthesized expression, statement expression or compound
+        literal.  */
+      if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE)
+       {
+         /* A statement expression.  */
+         tree stmt;
+         location_t here = c_parser_peek_token (parser)->location;
+         c_parser_consume_token (parser);
+         c_parser_consume_token (parser);
+         if (cur_stmt_list == NULL)
+           {
+             error_at (here, "braced-group within expression allowed "
+                       "only inside a function");
+             parser->error = true;
+             c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         stmt = c_begin_stmt_expr ();
+         c_parser_compound_statement_nostart (parser);
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         pedwarn (here, OPT_pedantic, 
+                  "ISO C forbids braced-groups within expressions");
+         expr.value = c_finish_stmt_expr (stmt);
+         expr.original_code = ERROR_MARK;
+       }
+      else if (c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+       {
+         /* A compound literal.  ??? Can we actually get here rather
+            than going directly to
+            c_parser_postfix_expression_after_paren_type from
+            elsewhere?  */
+         struct c_type_name *type_name;
+         c_parser_consume_token (parser);
+         type_name = c_parser_type_name (parser);
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         if (type_name == NULL)
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+           }
+         else
+           expr = c_parser_postfix_expression_after_paren_type (parser,
+                                                                type_name);
+       }
+      else
+       {
+         /* A parenthesized expression.  */
+         c_parser_consume_token (parser);
+         expr = c_parser_expression (parser);
+         if (TREE_CODE (expr.value) == MODIFY_EXPR)
+           TREE_NO_WARNING (expr.value) = 1;
+         expr.original_code = ERROR_MARK;
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+       }
+      break;
+    case CPP_KEYWORD:
+      switch (c_parser_peek_token (parser)->keyword)
+       {
+       case RID_FUNCTION_NAME:
+       case RID_PRETTY_FUNCTION_NAME:
+       case RID_C99_FUNCTION_NAME:
+         expr.value = fname_decl (c_parser_peek_token (parser)->location,
+                                  c_parser_peek_token (parser)->keyword,
+                                  c_parser_peek_token (parser)->value);
+         expr.original_code = ERROR_MARK;
+         c_parser_consume_token (parser);
+         break;
+       case RID_VA_ARG:
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         e1 = c_parser_expr_no_commas (parser, NULL);
+         if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         t1 = c_parser_type_name (parser);
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         if (t1 == NULL)
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+           }
+         else
+           {
+             expr.value = build_va_arg (e1.value, groktypename (t1));
+             expr.original_code = ERROR_MARK;
+           }
+         break;
+       case RID_OFFSETOF:
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         t1 = c_parser_type_name (parser);
+         if (t1 == NULL)
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         {
+           tree type = groktypename (t1);
+           tree offsetof_ref;
+           if (type == error_mark_node)
+             offsetof_ref = error_mark_node;
+           else
+             offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node);
+           /* Parse the second argument to __builtin_offsetof.  We
+              must have one identifier, and beyond that we want to
+              accept sub structure and sub array references.  */
+           if (c_parser_next_token_is (parser, CPP_NAME))
+             {
+               offsetof_ref = build_component_ref
+                 (offsetof_ref, c_parser_peek_token (parser)->value);
+               c_parser_consume_token (parser);
+               while (c_parser_next_token_is (parser, CPP_DOT)
+                      || c_parser_next_token_is (parser,
+                                                 CPP_OPEN_SQUARE)
+                      || c_parser_next_token_is (parser,
+                                                 CPP_DEREF))
+                 {
+                   if (c_parser_next_token_is (parser, CPP_DEREF))
+                     {
+                       loc = c_parser_peek_token (parser)->location;
+                       offsetof_ref = build_array_ref (offsetof_ref,
+                                                       integer_zero_node,
+                                                       loc);
+                       goto do_dot;
+                     }
+                   else if (c_parser_next_token_is (parser, CPP_DOT))
+                     {
+                     do_dot:
+                       c_parser_consume_token (parser);
+                       if (c_parser_next_token_is_not (parser,
+                                                       CPP_NAME))
+                         {
+                           c_parser_error (parser, "expected identifier");
+                           break;
+                         }
+                       offsetof_ref = build_component_ref
+                         (offsetof_ref,
+                          c_parser_peek_token (parser)->value);
+                       c_parser_consume_token (parser);
+                     }
+                   else
+                     {
+                       tree idx;
+                       loc = c_parser_peek_token (parser)->location;
+                       c_parser_consume_token (parser);
+                       idx = c_parser_expression (parser).value;
+                       c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                                  "expected %<]%>");
+                       offsetof_ref = build_array_ref (offsetof_ref, idx, loc);
+                     }
+                 }
+             }
+           else
+             c_parser_error (parser, "expected identifier");
+           c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                      "expected %<)%>");
+           expr.value = fold_offsetof (offsetof_ref, NULL_TREE);
+           expr.original_code = ERROR_MARK;
+         }
+         break;
+       case RID_CHOOSE_EXPR:
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         loc = c_parser_peek_token (parser)->location;
+         e1 = c_parser_expr_no_commas (parser, NULL);
+         if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         e2 = c_parser_expr_no_commas (parser, NULL);
+         if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         e3 = c_parser_expr_no_commas (parser, NULL);
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         {
+           tree c;
+
+           c = fold (e1.value);
+           if (TREE_CODE (c) != INTEGER_CST)
+             error_at (loc,
+                       "first argument to %<__builtin_choose_expr%> not"
+                       " a constant");
+           expr = integer_zerop (c) ? e3 : e2;
+         }
+         break;
+       case RID_TYPES_COMPATIBLE_P:
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         t1 = c_parser_type_name (parser);
+         if (t1 == NULL)
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         t2 = c_parser_type_name (parser);
+         if (t2 == NULL)
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         {
+           tree e1, e2;
+
+           e1 = TYPE_MAIN_VARIANT (groktypename (t1));
+           e2 = TYPE_MAIN_VARIANT (groktypename (t2));
+
+           expr.value = comptypes (e1, e2)
+             ? build_int_cst (NULL_TREE, 1)
+             : build_int_cst (NULL_TREE, 0);
+           expr.original_code = ERROR_MARK;
+         }
+         break;
+       case RID_AT_SELECTOR:
+         gcc_assert (c_dialect_objc ());
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         {
+           tree sel = c_parser_objc_selector_arg (parser);
+           c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                      "expected %<)%>");
+           expr.value = objc_build_selector_expr (sel);
+           expr.original_code = ERROR_MARK;
+         }
+         break;
+       case RID_AT_PROTOCOL:
+         gcc_assert (c_dialect_objc ());
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         if (c_parser_next_token_is_not (parser, CPP_NAME))
+           {
+             c_parser_error (parser, "expected identifier");
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         {
+           tree id = c_parser_peek_token (parser)->value;
+           c_parser_consume_token (parser);
+           c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                      "expected %<)%>");
+           expr.value = objc_build_protocol_expr (id);
+           expr.original_code = ERROR_MARK;
+         }
+         break;
+       case RID_AT_ENCODE:
+         /* Extension to support C-structures in the archiver.  */
+         gcc_assert (c_dialect_objc ());
+         c_parser_consume_token (parser);
+         if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             break;
+           }
+         t1 = c_parser_type_name (parser);
+         if (t1 == NULL)
+           {
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             break;
+           }
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         {
+           tree type = groktypename (t1);
+           expr.value = objc_build_encode_expr (type);
+           expr.original_code = ERROR_MARK;
+         }
+         break;
+       default:
+         c_parser_error (parser, "expected expression");
+         expr.value = error_mark_node;
+         expr.original_code = ERROR_MARK;
+         break;
+       }
+      break;
+    case CPP_OPEN_SQUARE:
+      if (c_dialect_objc ())
+       {
+         tree receiver, args;
+         c_parser_consume_token (parser);
+         receiver = c_parser_objc_receiver (parser);
+         args = c_parser_objc_message_args (parser);
+         c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                    "expected %<]%>");
+         expr.value = objc_build_message_expr (build_tree_list (receiver,
+                                                                args));
+         expr.original_code = ERROR_MARK;
+         break;
+       }
+      /* Else fall through to report error.  */
+    default:
+      c_parser_error (parser, "expected expression");
+      expr.value = error_mark_node;
+      expr.original_code = ERROR_MARK;
+      break;
+    }
+  return c_parser_postfix_expression_after_primary (parser, expr);
+}
+
+/* Parse a postfix expression after a parenthesized type name: the
+   brace-enclosed initializer of a compound literal, possibly followed
+   by some postfix operators.  This is separate because it is not
+   possible to tell until after the type name whether a cast
+   expression has a cast or a compound literal, or whether the operand
+   of sizeof is a parenthesized type name or starts with a compound
+   literal.  */
+
+static struct c_expr
+c_parser_postfix_expression_after_paren_type (c_parser *parser,
+                                             struct c_type_name *type_name)
+{
+  tree type;
+  struct c_expr init;
+  struct c_expr expr;
+  location_t start_loc;
+  start_init (NULL_TREE, NULL, 0);
+  type = groktypename (type_name);
+  start_loc = c_parser_peek_token (parser)->location;
+  if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type))
+    {
+      error_at (start_loc, "compound literal has variable size");
+      type = error_mark_node;
+    }
+  init = c_parser_braced_init (parser, type, false);
+  finish_init ();
+  maybe_warn_string_init (type, init);
+
+  if (!flag_isoc99)
+    pedwarn (start_loc, OPT_pedantic, "ISO C90 forbids compound literals");
+  expr.value = build_compound_literal (type, init.value);
+  expr.original_code = ERROR_MARK;
+  return c_parser_postfix_expression_after_primary (parser, expr);
+}
+
+/* Parse a postfix expression after the initial primary or compound
+   literal; that is, parse a series of postfix operators.  */
+
+static struct c_expr
+c_parser_postfix_expression_after_primary (c_parser *parser,
+                                          struct c_expr expr)
+{
+  tree ident, idx, exprlist;
+  location_t loc = c_parser_peek_token (parser)->location;
+  while (true)
+    {
+      switch (c_parser_peek_token (parser)->type)
+       {
+       case CPP_OPEN_SQUARE:
+         /* Array reference.  */
+         loc = c_parser_peek_token (parser)->location;
+         c_parser_consume_token (parser);
+         idx = c_parser_expression (parser).value;
+         c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                                    "expected %<]%>");
+         expr.value = build_array_ref (expr.value, idx, loc);
+         expr.original_code = ERROR_MARK;
+         break;
+       case CPP_OPEN_PAREN:
+         /* Function call.  */
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+           exprlist = NULL_TREE;
+         else
+           exprlist = c_parser_expr_list (parser, true);
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         expr.value = build_function_call (expr.value, exprlist);
+         expr.original_code = ERROR_MARK;
+         break;
+       case CPP_DOT:
+         /* Structure element reference.  */
+         c_parser_consume_token (parser);
+         expr = default_function_array_conversion (expr);
+         if (c_parser_next_token_is (parser, CPP_NAME))
+           ident = c_parser_peek_token (parser)->value;
+         else
+           {
+             c_parser_error (parser, "expected identifier");
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             return expr;
+           }
+         c_parser_consume_token (parser);
+         expr.value = build_component_ref (expr.value, ident);
+         expr.original_code = ERROR_MARK;
+         break;
+       case CPP_DEREF:
+         /* Structure element reference.  */
+         c_parser_consume_token (parser);
+         expr = default_function_array_conversion (expr);
+         if (c_parser_next_token_is (parser, CPP_NAME))
+           ident = c_parser_peek_token (parser)->value;
+         else
+           {
+             c_parser_error (parser, "expected identifier");
+             expr.value = error_mark_node;
+             expr.original_code = ERROR_MARK;
+             return expr;
+           }
+         c_parser_consume_token (parser);
+         expr.value = build_component_ref (build_indirect_ref (loc,
+                                                               expr.value,
+                                                               "->"),
+                                           ident);
+         expr.original_code = ERROR_MARK;
+         break;
+       case CPP_PLUS_PLUS:
+         /* Postincrement.  */
+         c_parser_consume_token (parser);
+         expr = default_function_array_conversion (expr);
+         expr.value = build_unary_op (loc,
+                                      POSTINCREMENT_EXPR, expr.value, 0);
+         expr.original_code = ERROR_MARK;
+         break;
+       case CPP_MINUS_MINUS:
+         /* Postdecrement.  */
+         c_parser_consume_token (parser);
+         expr = default_function_array_conversion (expr);
+         expr.value = build_unary_op (loc,
+                                      POSTDECREMENT_EXPR, expr.value, 0);
+         expr.original_code = ERROR_MARK;
+         break;
+       default:
+         return expr;
+       }
+    }
+}
+
+/* Parse an expression (C90 6.3.17, C99 6.5.17).
+
+   expression:
+     assignment-expression
+     expression , assignment-expression
+*/
+
+static struct c_expr
+c_parser_expression (c_parser *parser)
+{
+  struct c_expr expr;
+  expr = c_parser_expr_no_commas (parser, NULL);
+  while (c_parser_next_token_is (parser, CPP_COMMA))
+    {
+      struct c_expr next;
+      c_parser_consume_token (parser);
+      next = c_parser_expr_no_commas (parser, NULL);
+      next = default_function_array_conversion (next);
+      expr.value = build_compound_expr (expr.value, next.value);
+      expr.original_code = COMPOUND_EXPR;
+    }
+  return expr;
+}
+
+/* Parse an expression and convert functions or arrays to
+   pointers.  */
+
+static struct c_expr
+c_parser_expression_conv (c_parser *parser)
+{
+  struct c_expr expr;
+  expr = c_parser_expression (parser);
+  expr = default_function_array_conversion (expr);
+  return expr;
+}
+
+/* Parse a non-empty list of expressions.  If CONVERT_P, convert
+   functions and arrays to pointers.
+
+   nonempty-expr-list:
+     assignment-expression
+     nonempty-expr-list , assignment-expression
+*/
+
+static tree
+c_parser_expr_list (c_parser *parser, bool convert_p)
+{
+  struct c_expr expr;
+  tree ret, cur;
+  expr = c_parser_expr_no_commas (parser, NULL);
+  if (convert_p)
+    expr = default_function_array_conversion (expr);
+  ret = cur = build_tree_list (NULL_TREE, expr.value);
+  while (c_parser_next_token_is (parser, CPP_COMMA))
+    {
+      c_parser_consume_token (parser);
+      expr = c_parser_expr_no_commas (parser, NULL);
+      if (convert_p)
+       expr = default_function_array_conversion (expr);
+      cur = TREE_CHAIN (cur) = build_tree_list (NULL_TREE, expr.value);
+    }
+  return ret;
+}
+
+\f
+/* Parse Objective-C-specific constructs.  */
+
+/* Parse an objc-class-definition.
+
+   objc-class-definition:
+     @interface identifier objc-superclass[opt] objc-protocol-refs[opt]
+       objc-class-instance-variables[opt] objc-methodprotolist @end
+     @implementation identifier objc-superclass[opt]
+       objc-class-instance-variables[opt]
+     @interface identifier ( identifier ) objc-protocol-refs[opt]
+       objc-methodprotolist @end
+     @implementation identifier ( identifier )
+
+   objc-superclass:
+     : identifier
+
+   "@interface identifier (" must start "@interface identifier (
+   identifier ) ...": objc-methodprotolist in the first production may
+   not start with a parenthesized identifier as a declarator of a data
+   definition with no declaration specifiers if the objc-superclass,
+   objc-protocol-refs and objc-class-instance-variables are omitted.  */
+
+static void
+c_parser_objc_class_definition (c_parser *parser)
+{
+  bool iface_p;
+  tree id1;
+  tree superclass;
+  if (c_parser_next_token_is_keyword (parser, RID_AT_INTERFACE))
+    iface_p = true;
+  else if (c_parser_next_token_is_keyword (parser, RID_AT_IMPLEMENTATION))
+    iface_p = false;
+  else
+    gcc_unreachable ();
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is_not (parser, CPP_NAME))
+    {
+      c_parser_error (parser, "expected identifier");
+      return;
+    }
+  id1 = c_parser_peek_token (parser)->value;
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      tree id2;
+      tree proto = NULL_TREE;
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is_not (parser, CPP_NAME))
+       {
+         c_parser_error (parser, "expected identifier");
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+         return;
+       }
+      id2 = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      if (!iface_p)
+       {
+         objc_start_category_implementation (id1, id2);
+         return;
+       }
+      if (c_parser_next_token_is (parser, CPP_LESS))
+       proto = c_parser_objc_protocol_refs (parser);
+      objc_start_category_interface (id1, id2, proto);
+      c_parser_objc_methodprotolist (parser);
+      c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
+      objc_finish_interface ();
+      return;
+    }
+  if (c_parser_next_token_is (parser, CPP_COLON))
+    {
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is_not (parser, CPP_NAME))
+       {
+         c_parser_error (parser, "expected identifier");
+         return;
+       }
+      superclass = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+    }
+  else
+    superclass = NULL_TREE;
+  if (iface_p)
+    {
+      tree proto = NULL_TREE;
+      if (c_parser_next_token_is (parser, CPP_LESS))
+       proto = c_parser_objc_protocol_refs (parser);
+      objc_start_class_interface (id1, superclass, proto);
+    }
+  else
+    objc_start_class_implementation (id1, superclass);
+  if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    c_parser_objc_class_instance_variables (parser);
+  if (iface_p)
+    {
+      objc_continue_interface ();
+      c_parser_objc_methodprotolist (parser);
+      c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
+      objc_finish_interface ();
+    }
+  else
+    {
+      objc_continue_implementation ();
+      return;
+    }
+}
+
+/* Parse objc-class-instance-variables.
+
+   objc-class-instance-variables:
+     { objc-instance-variable-decl-list[opt] }
+
+   objc-instance-variable-decl-list:
+     objc-visibility-spec
+     objc-instance-variable-decl ;
+     ;
+     objc-instance-variable-decl-list objc-visibility-spec
+     objc-instance-variable-decl-list objc-instance-variable-decl ;
+     objc-instance-variable-decl-list ;
+
+   objc-visibility-spec:
+     @private
+     @protected
+     @public
+
+   objc-instance-variable-decl:
+     struct-declaration
+*/
+
+static void
+c_parser_objc_class_instance_variables (c_parser *parser)
+{
+  gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
+  c_parser_consume_token (parser);
+  while (c_parser_next_token_is_not (parser, CPP_EOF))
+    {
+      tree decls;
+      /* Parse any stray semicolon.  */
+      if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+       {
+         pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
+                  "extra semicolon in struct or union specified");
+         c_parser_consume_token (parser);
+         continue;
+       }
+      /* Stop if at the end of the instance variables.  */
+      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+       {
+         c_parser_consume_token (parser);
+         break;
+       }
+      /* Parse any objc-visibility-spec.  */
+      if (c_parser_next_token_is_keyword (parser, RID_PRIVATE))
+       {
+         c_parser_consume_token (parser);
+         objc_set_visibility (2);
+         continue;
+       }
+      else if (c_parser_next_token_is_keyword (parser, RID_PROTECTED))
+       {
+         c_parser_consume_token (parser);
+         objc_set_visibility (0);
+         continue;
+       }
+      else if (c_parser_next_token_is_keyword (parser, RID_PUBLIC))
+       {
+         c_parser_consume_token (parser);
+         objc_set_visibility (1);
+         continue;
+       }
+      else if (c_parser_next_token_is (parser, CPP_PRAGMA))
+       {
+         c_parser_pragma (parser, pragma_external);
+         continue;
+       }
+
+      /* Parse some comma-separated declarations.  */
+      decls = c_parser_struct_declaration (parser);
+      {
+       /* Comma-separated instance variables are chained together in
+          reverse order; add them one by one.  */
+       tree ivar = nreverse (decls);
+       for (; ivar; ivar = TREE_CHAIN (ivar))
+         objc_add_instance_variable (copy_node (ivar));
+      }
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+    }
+}
+
+/* Parse an objc-class-declaration.
+
+   objc-class-declaration:
+     @class identifier-list ;
+*/
+
+static void
+c_parser_objc_class_declaration (c_parser *parser)
+{
+  tree list = NULL_TREE;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_CLASS));
+  c_parser_consume_token (parser);
+  /* Any identifiers, including those declared as type names, are OK
+     here.  */
+  while (true)
+    {
+      tree id;
+      if (c_parser_next_token_is_not (parser, CPP_NAME))
+       {
+         c_parser_error (parser, "expected identifier");
+         break;
+       }
+      id = c_parser_peek_token (parser)->value;
+      list = chainon (list, build_tree_list (NULL_TREE, id));
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_COMMA))
+       c_parser_consume_token (parser);
+      else
+       break;
+    }
+  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+  objc_declare_class (list);
+}
+
+/* Parse an objc-alias-declaration.
+
+   objc-alias-declaration:
+     @compatibility_alias identifier identifier ;
+*/
+
+static void
+c_parser_objc_alias_declaration (c_parser *parser)
+{
+  tree id1, id2;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_ALIAS));
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is_not (parser, CPP_NAME))
+    {
+      c_parser_error (parser, "expected identifier");
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+      return;
+    }
+  id1 = c_parser_peek_token (parser)->value;
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is_not (parser, CPP_NAME))
+    {
+      c_parser_error (parser, "expected identifier");
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+      return;
+    }
+  id2 = c_parser_peek_token (parser)->value;
+  c_parser_consume_token (parser);
+  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+  objc_declare_alias (id1, id2);
+}
+
+/* Parse an objc-protocol-definition.
+
+   objc-protocol-definition:
+     @protocol identifier objc-protocol-refs[opt] objc-methodprotolist @end
+     @protocol identifier-list ;
+
+   "@protocol identifier ;" should be resolved as "@protocol
+   identifier-list ;": objc-methodprotolist may not start with a
+   semicolon in the first alternative if objc-protocol-refs are
+   omitted.  */
+
+static void
+c_parser_objc_protocol_definition (c_parser *parser)
+{
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROTOCOL));
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is_not (parser, CPP_NAME))
+    {
+      c_parser_error (parser, "expected identifier");
+      return;
+    }
+  if (c_parser_peek_2nd_token (parser)->type == CPP_COMMA
+      || c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON)
+    {
+      tree list = NULL_TREE;
+      /* Any identifiers, including those declared as type names, are
+        OK here.  */
+      while (true)
+       {
+         tree id;
+         if (c_parser_next_token_is_not (parser, CPP_NAME))
+           {
+             c_parser_error (parser, "expected identifier");
+             break;
+           }
+         id = c_parser_peek_token (parser)->value;
+         list = chainon (list, build_tree_list (NULL_TREE, id));
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           c_parser_consume_token (parser);
+         else
+           break;
+       }
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+      objc_declare_protocols (list);
+    }
+  else
+    {
+      tree id = c_parser_peek_token (parser)->value;
+      tree proto = NULL_TREE;
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_LESS))
+       proto = c_parser_objc_protocol_refs (parser);
+      parser->objc_pq_context = true;
+      objc_start_protocol (id, proto);
+      c_parser_objc_methodprotolist (parser);
+      c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
+      parser->objc_pq_context = false;
+      objc_finish_interface ();
+    }
+}
+
+/* Parse an objc-method-type.
+
+   objc-method-type:
+     +
+     -
+*/
+
+static enum tree_code
+c_parser_objc_method_type (c_parser *parser)
+{
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_PLUS:
+      c_parser_consume_token (parser);
+      return PLUS_EXPR;
+    case CPP_MINUS:
+      c_parser_consume_token (parser);
+      return MINUS_EXPR;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Parse an objc-method-definition.
+
+   objc-method-definition:
+     objc-method-type objc-method-decl ;[opt] compound-statement
+*/
+
+static void
+c_parser_objc_method_definition (c_parser *parser)
+{
+  enum tree_code type = c_parser_objc_method_type (parser);
+  tree decl;
+  objc_set_method_type (type);
+  parser->objc_pq_context = true;
+  decl = c_parser_objc_method_decl (parser);
+  if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+    {
+      c_parser_consume_token (parser);
+      pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
+              "extra semicolon in method definition specified");
+    }
+  if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    {
+      c_parser_error (parser, "expected %<{%>");
+      return;
+    }
+  parser->objc_pq_context = false;
+  objc_start_method_definition (decl);
+  add_stmt (c_parser_compound_statement (parser));
+  objc_finish_method_definition (current_function_decl);
+}
+
+/* Parse an objc-methodprotolist.
+
+   objc-methodprotolist:
+     empty
+     objc-methodprotolist objc-methodproto
+     objc-methodprotolist declaration
+     objc-methodprotolist ;
+
+   The declaration is a data definition, which may be missing
+   declaration specifiers under the same rules and diagnostics as
+   other data definitions outside functions, and the stray semicolon
+   is diagnosed the same way as a stray semicolon outside a
+   function.  */
+
+static void
+c_parser_objc_methodprotolist (c_parser *parser)
+{
+  while (true)
+    {
+      /* The list is terminated by @end.  */
+      switch (c_parser_peek_token (parser)->type)
+       {
+       case CPP_SEMICOLON:
+         pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic, 
+                  "ISO C does not allow extra %<;%> outside of a function");
+         c_parser_consume_token (parser);
+         break;
+       case CPP_PLUS:
+       case CPP_MINUS:
+         c_parser_objc_methodproto (parser);
+         break;
+       case CPP_PRAGMA:
+         c_parser_pragma (parser, pragma_external);
+         break;
+       case CPP_EOF:
+         return;
+       default:
+         if (c_parser_next_token_is_keyword (parser, RID_AT_END))
+           return;
+         c_parser_declaration_or_fndef (parser, false, true, false, true);
+         break;
+       }
+    }
+}
+
+/* Parse an objc-methodproto.
+
+   objc-methodproto:
+     objc-method-type objc-method-decl ;
+*/
+
+static void
+c_parser_objc_methodproto (c_parser *parser)
+{
+  enum tree_code type = c_parser_objc_method_type (parser);
+  tree decl;
+  objc_set_method_type (type);
+  /* Remember protocol qualifiers in prototypes.  */
+  parser->objc_pq_context = true;
+  decl = c_parser_objc_method_decl (parser);
+  /* Forget protocol qualifiers here.  */
+  parser->objc_pq_context = false;
+  objc_add_method_declaration (decl);
+  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+}
+
+/* Parse an objc-method-decl.
+
+   objc-method-decl:
+     ( objc-type-name ) objc-selector
+     objc-selector
+     ( objc-type-name ) objc-keyword-selector objc-optparmlist
+     objc-keyword-selector objc-optparmlist
+
+   objc-keyword-selector:
+     objc-keyword-decl
+     objc-keyword-selector objc-keyword-decl
+
+   objc-keyword-decl:
+     objc-selector : ( objc-type-name ) identifier
+     objc-selector : identifier
+     : ( objc-type-name ) identifier
+     : identifier
+
+   objc-optparmlist:
+     objc-optparms objc-optellipsis
+
+   objc-optparms:
+     empty
+     objc-opt-parms , parameter-declaration
+
+   objc-optellipsis:
+     empty
+     , ...
+*/
+
+static tree
+c_parser_objc_method_decl (c_parser *parser)
+{
+  tree type = NULL_TREE;
+  tree sel;
+  tree parms = NULL_TREE;
+  bool ellipsis = false;
+
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      c_parser_consume_token (parser);
+      type = c_parser_objc_type_name (parser);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  sel = c_parser_objc_selector (parser);
+  /* If there is no selector, or a colon follows, we have an
+     objc-keyword-selector.  If there is a selector, and a colon does
+     not follow, that selector ends the objc-method-decl.  */
+  if (!sel || c_parser_next_token_is (parser, CPP_COLON))
+    {
+      tree tsel = sel;
+      tree list = NULL_TREE;
+      while (true)
+       {
+         tree atype = NULL_TREE, id, keyworddecl;
+         if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+           break;
+         if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+           {
+             c_parser_consume_token (parser);
+             atype = c_parser_objc_type_name (parser);
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                        "expected %<)%>");
+           }
+         if (c_parser_next_token_is_not (parser, CPP_NAME))
+           {
+             c_parser_error (parser, "expected identifier");
+             return error_mark_node;
+           }
+         id = c_parser_peek_token (parser)->value;
+         c_parser_consume_token (parser);
+         keyworddecl = objc_build_keyword_decl (tsel, atype, id);
+         list = chainon (list, keyworddecl);
+         tsel = c_parser_objc_selector (parser);
+         if (!tsel && c_parser_next_token_is_not (parser, CPP_COLON))
+           break;
+       }
+      /* Parse the optional parameter list.  Optional Objective-C
+        method parameters follow the C syntax, and may include '...'
+        to denote a variable number of arguments.  */
+      parms = make_node (TREE_LIST);
+      while (c_parser_next_token_is (parser, CPP_COMMA))
+       {
+         struct c_parm *parm;
+         c_parser_consume_token (parser);
+         if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+           {
+             ellipsis = true;
+             c_parser_consume_token (parser);
+             break;
+           }
+         parm = c_parser_parameter_declaration (parser, NULL_TREE);
+         if (parm == NULL)
+           break;
+         parms = chainon (parms,
+                          build_tree_list (NULL_TREE, grokparm (parm)));
+       }
+      sel = list;
+    }
+  return objc_build_method_signature (type, sel, parms, ellipsis);
+}
+
+/* Parse an objc-type-name.
+
+   objc-type-name:
+     objc-type-qualifiers[opt] type-name
+     objc-type-qualifiers[opt]
+
+   objc-type-qualifiers:
+     objc-type-qualifier
+     objc-type-qualifiers objc-type-qualifier
+
+   objc-type-qualifier: one of
+     in out inout bycopy byref oneway
+*/
+
+static tree
+c_parser_objc_type_name (c_parser *parser)
+{
+  tree quals = NULL_TREE;
+  struct c_type_name *type_name = NULL;
+  tree type = NULL_TREE;
+  while (true)
+    {
+      c_token *token = c_parser_peek_token (parser);
+      if (token->type == CPP_KEYWORD
+         && (token->keyword == RID_IN
+             || token->keyword == RID_OUT
+             || token->keyword == RID_INOUT
+             || token->keyword == RID_BYCOPY
+             || token->keyword == RID_BYREF
+             || token->keyword == RID_ONEWAY))
+       {
+         quals = chainon (quals, build_tree_list (NULL_TREE, token->value));
+         c_parser_consume_token (parser);
+       }
+      else
+       break;
+    }
+  if (c_parser_next_token_starts_typename (parser))
+    type_name = c_parser_type_name (parser);
+  if (type_name)
+    type = groktypename (type_name);
+  return build_tree_list (quals, type);
+}
+
+/* Parse objc-protocol-refs.
+
+   objc-protocol-refs:
+     < identifier-list >
+*/
+
+static tree
+c_parser_objc_protocol_refs (c_parser *parser)
+{
+  tree list = NULL_TREE;
+  gcc_assert (c_parser_next_token_is (parser, CPP_LESS));
+  c_parser_consume_token (parser);
+  /* Any identifiers, including those declared as type names, are OK
+     here.  */
+  while (true)
+    {
+      tree id;
+      if (c_parser_next_token_is_not (parser, CPP_NAME))
+       {
+         c_parser_error (parser, "expected identifier");
+         break;
+       }
+      id = c_parser_peek_token (parser)->value;
+      list = chainon (list, build_tree_list (NULL_TREE, id));
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_COMMA))
+       c_parser_consume_token (parser);
+      else
+       break;
+    }
+  c_parser_require (parser, CPP_GREATER, "expected %<>%>");
+  return list;
+}
+
+/* Parse an objc-try-catch-statement.
+
+   objc-try-catch-statement:
+     @try compound-statement objc-catch-list[opt]
+     @try compound-statement objc-catch-list[opt] @finally compound-statement
+
+   objc-catch-list:
+     @catch ( parameter-declaration ) compound-statement
+     objc-catch-list @catch ( parameter-declaration ) compound-statement
+*/
+
+static void
+c_parser_objc_try_catch_statement (c_parser *parser)
+{
+  location_t loc;
+  tree stmt;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRY));
+  c_parser_consume_token (parser);
+  loc = c_parser_peek_token (parser)->location;
+  stmt = c_parser_compound_statement (parser);
+  objc_begin_try_stmt (loc, stmt);
+  while (c_parser_next_token_is_keyword (parser, RID_CATCH))
+    {
+      struct c_parm *parm;
+      c_parser_consume_token (parser);
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+       break;
+      parm = c_parser_parameter_declaration (parser, NULL_TREE);
+      if (parm == NULL)
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+         break;
+       }
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      objc_begin_catch_clause (grokparm (parm));
+      if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+       c_parser_compound_statement_nostart (parser);
+      objc_finish_catch_clause ();
+    }
+  if (c_parser_next_token_is_keyword (parser, RID_AT_FINALLY))
+    {
+      location_t finloc;
+      tree finstmt;
+      c_parser_consume_token (parser);
+      finloc = c_parser_peek_token (parser)->location;
+      finstmt = c_parser_compound_statement (parser);
+      objc_build_finally_clause (finloc, finstmt);
+    }
+  objc_finish_try_stmt ();
+}
+
+/* Parse an objc-synchronized-statement.
+
+   objc-synchronized-statement:
+     @synchronized ( expression ) compound-statement
+*/
+
+static void
+c_parser_objc_synchronized_statement (c_parser *parser)
+{
+  location_t loc;
+  tree expr, stmt;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED));
+  c_parser_consume_token (parser);
+  loc = c_parser_peek_token (parser)->location;
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      expr = c_parser_expression (parser).value;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  else
+    expr = error_mark_node;
+  stmt = c_parser_compound_statement (parser);
+  objc_build_synchronized (loc, expr, stmt);
+}
+
+/* Parse an objc-selector; return NULL_TREE without an error if the
+   next token is not an objc-selector.
+
+   objc-selector:
+     identifier
+     one of
+       enum struct union if else while do for switch case default
+       break continue return goto asm sizeof typeof __alignof
+       unsigned long const short volatile signed restrict _Complex
+       in out inout bycopy byref oneway int char float double void _Bool
+
+   ??? Why this selection of keywords but not, for example, storage
+   class specifiers?  */
+
+static tree
+c_parser_objc_selector (c_parser *parser)
+{
+  c_token *token = c_parser_peek_token (parser);
+  tree value = token->value;
+  if (token->type == CPP_NAME)
+    {
+      c_parser_consume_token (parser);
+      return value;
+    }
+  if (token->type != CPP_KEYWORD)
+    return NULL_TREE;
+  switch (token->keyword)
+    {
+    case RID_ENUM:
+    case RID_STRUCT:
+    case RID_UNION:
+    case RID_IF:
+    case RID_ELSE:
+    case RID_WHILE:
+    case RID_DO:
+    case RID_FOR:
+    case RID_SWITCH:
+    case RID_CASE:
+    case RID_DEFAULT:
+    case RID_BREAK:
+    case RID_CONTINUE:
+    case RID_RETURN:
+    case RID_GOTO:
+    case RID_ASM:
+    case RID_SIZEOF:
+    case RID_TYPEOF:
+    case RID_ALIGNOF:
+    case RID_UNSIGNED:
+    case RID_LONG:
+    case RID_CONST:
+    case RID_SHORT:
+    case RID_VOLATILE:
+    case RID_SIGNED:
+    case RID_RESTRICT:
+    case RID_COMPLEX:
+    case RID_IN:
+    case RID_OUT:
+    case RID_INOUT:
+    case RID_BYCOPY:
+    case RID_BYREF:
+    case RID_ONEWAY:
+    case RID_INT:
+    case RID_CHAR:
+    case RID_FLOAT:
+    case RID_DOUBLE:
+    case RID_VOID:
+    case RID_BOOL:
+      c_parser_consume_token (parser);
+      return value;
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Parse an objc-selector-arg.
+
+   objc-selector-arg:
+     objc-selector
+     objc-keywordname-list
+
+   objc-keywordname-list:
+     objc-keywordname
+     objc-keywordname-list objc-keywordname
+
+   objc-keywordname:
+     objc-selector :
+     :
+*/
+
+static tree
+c_parser_objc_selector_arg (c_parser *parser)
+{
+  tree sel = c_parser_objc_selector (parser);
+  tree list = NULL_TREE;
+  if (sel && c_parser_next_token_is_not (parser, CPP_COLON))
+    return sel;
+  while (true)
+    {
+      if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+       return list;
+      list = chainon (list, build_tree_list (sel, NULL_TREE));
+      sel = c_parser_objc_selector (parser);
+      if (!sel && c_parser_next_token_is_not (parser, CPP_COLON))
+       break;
+    }
+  return list;
+}
+
+/* Parse an objc-receiver.
+
+   objc-receiver:
+     expression
+     class-name
+     type-name
+*/
+
+static tree
+c_parser_objc_receiver (c_parser *parser)
+{
+  if (c_parser_peek_token (parser)->type == CPP_NAME
+      && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME
+         || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
+    {
+      tree id = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+      return objc_get_class_reference (id);
+    }
+  return c_parser_expression (parser).value;
+}
+
+/* Parse objc-message-args.
+
+   objc-message-args:
+     objc-selector
+     objc-keywordarg-list
+
+   objc-keywordarg-list:
+     objc-keywordarg
+     objc-keywordarg-list objc-keywordarg
+
+   objc-keywordarg:
+     objc-selector : objc-keywordexpr
+     : objc-keywordexpr
+*/
+
+static tree
+c_parser_objc_message_args (c_parser *parser)
+{
+  tree sel = c_parser_objc_selector (parser);
+  tree list = NULL_TREE;
+  if (sel && c_parser_next_token_is_not (parser, CPP_COLON))
+    return sel;
+  while (true)
+    {
+      tree keywordexpr;
+      if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+       return error_mark_node;
+      keywordexpr = c_parser_objc_keywordexpr (parser);
+      list = chainon (list, build_tree_list (sel, keywordexpr));
+      sel = c_parser_objc_selector (parser);
+      if (!sel && c_parser_next_token_is_not (parser, CPP_COLON))
+       break;
+    }
+  return list;
+}
+
+/* Parse an objc-keywordexpr.
+
+   objc-keywordexpr:
+     nonempty-expr-list
+*/
+
+static tree
+c_parser_objc_keywordexpr (c_parser *parser)
+{
+  tree list = c_parser_expr_list (parser, true);
+  if (TREE_CHAIN (list) == NULL_TREE)
+    {
+      /* Just return the expression, remove a level of
+        indirection.  */
+      return TREE_VALUE (list);
+    }
+  else
+    {
+      /* We have a comma expression, we will collapse later.  */
+      return list;
+    }
+}
+
+\f
+/* Handle pragmas.  Some OpenMP pragmas are associated with, and therefore
+   should be considered, statements.  ALLOW_STMT is true if we're within
+   the context of a function and such pragmas are to be allowed.  Returns
+   true if we actually parsed such a pragma.  */
+
+static bool
+c_parser_pragma (c_parser *parser, enum pragma_context context)
+{
+  unsigned int id;
+
+  id = c_parser_peek_token (parser)->pragma_kind;
+  gcc_assert (id != PRAGMA_NONE);
+
+  switch (id)
+    {
+    case PRAGMA_OMP_BARRIER:
+      if (context != pragma_compound)
+       {
+         if (context == pragma_stmt)
+           c_parser_error (parser, "%<#pragma omp barrier%> may only be "
+                           "used in compound statements");
+         goto bad_stmt;
+       }
+      c_parser_omp_barrier (parser);
+      return false;
+
+    case PRAGMA_OMP_FLUSH:
+      if (context != pragma_compound)
+       {
+         if (context == pragma_stmt)
+           c_parser_error (parser, "%<#pragma omp flush%> may only be "
+                           "used in compound statements");
+         goto bad_stmt;
+       }
+      c_parser_omp_flush (parser);
+      return false;
+
+    case PRAGMA_OMP_TASKWAIT:
+      if (context != pragma_compound)
+       {
+         if (context == pragma_stmt)
+           c_parser_error (parser, "%<#pragma omp taskwait%> may only be "
+                           "used in compound statements");
+         goto bad_stmt;
+       }
+      c_parser_omp_taskwait (parser);
+      return false;
+
+    case PRAGMA_OMP_THREADPRIVATE:
+      c_parser_omp_threadprivate (parser);
+      return false;
+
+    case PRAGMA_OMP_SECTION:
+      error_at (c_parser_peek_token (parser)->location,
+               "%<#pragma omp section%> may only be used in "
+               "%<#pragma omp sections%> construct");
+      c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+      return false;
+
+    case PRAGMA_GCC_PCH_PREPROCESS:
+      c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first");
+      c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+      return false;
+
+    default:
+      if (id < PRAGMA_FIRST_EXTERNAL)
+       {
+         if (context == pragma_external)
+           {
+           bad_stmt:
+             c_parser_error (parser, "expected declaration specifiers");
+             c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+             return false;
+           }
+         c_parser_omp_construct (parser);
+         return true;
+       }
+      break;
+    }
+
+  c_parser_consume_pragma (parser);
+  c_invoke_pragma_handler (id);
+
+  /* Skip to EOL, but suppress any error message.  Those will have been 
+     generated by the handler routine through calling error, as opposed
+     to calling c_parser_error.  */
+  parser->error = true;
+  c_parser_skip_to_pragma_eol (parser);
+
+  return false;
+}
+
+/* The interface the pragma parsers have to the lexer.  */
+
+enum cpp_ttype
+pragma_lex (tree *value)
+{
+  c_token *tok = c_parser_peek_token (the_parser);
+  enum cpp_ttype ret = tok->type;
+
+  *value = tok->value;
+  if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF)
+    ret = CPP_EOF;
+  else
+    {
+      if (ret == CPP_KEYWORD)
+       ret = CPP_NAME;
+      c_parser_consume_token (the_parser);
+    }
+
+  return ret;
+}
+
+static void
+c_parser_pragma_pch_preprocess (c_parser *parser)
+{
+  tree name = NULL;
+
+  c_parser_consume_pragma (parser);
+  if (c_parser_next_token_is (parser, CPP_STRING))
+    {
+      name = c_parser_peek_token (parser)->value;
+      c_parser_consume_token (parser);
+    }
+  else
+    c_parser_error (parser, "expected string literal");
+  c_parser_skip_to_pragma_eol (parser);
+
+  if (name)
+    c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name));
+}
+\f
+/* OpenMP 2.5 parsing routines.  */
+
+/* Returns name of the next clause.
+   If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and
+   the token is not consumed.  Otherwise appropriate pragma_omp_clause is
+   returned and the token is consumed.  */
+
+static pragma_omp_clause
+c_parser_omp_clause_name (c_parser *parser)
+{
+  pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE;
+
+  if (c_parser_next_token_is_keyword (parser, RID_IF))
+    result = PRAGMA_OMP_CLAUSE_IF;
+  else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT))
+    result = PRAGMA_OMP_CLAUSE_DEFAULT;
+  else if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+      switch (p[0])
+       {
+       case 'c':
+         if (!strcmp ("collapse", p))
+           result = PRAGMA_OMP_CLAUSE_COLLAPSE;
+         else if (!strcmp ("copyin", p))
+           result = PRAGMA_OMP_CLAUSE_COPYIN;
+          else if (!strcmp ("copyprivate", p))
+           result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
+         break;
+       case 'f':
+         if (!strcmp ("firstprivate", p))
+           result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
+         break;
+       case 'l':
+         if (!strcmp ("lastprivate", p))
+           result = PRAGMA_OMP_CLAUSE_LASTPRIVATE;
+         break;
+       case 'n':
+         if (!strcmp ("nowait", p))
+           result = PRAGMA_OMP_CLAUSE_NOWAIT;
+         else if (!strcmp ("num_threads", p))
+           result = PRAGMA_OMP_CLAUSE_NUM_THREADS;
+         break;
+       case 'o':
+         if (!strcmp ("ordered", p))
+           result = PRAGMA_OMP_CLAUSE_ORDERED;
+         break;
+       case 'p':
+         if (!strcmp ("private", p))
+           result = PRAGMA_OMP_CLAUSE_PRIVATE;
+         break;
+       case 'r':
+         if (!strcmp ("reduction", p))
+           result = PRAGMA_OMP_CLAUSE_REDUCTION;
+         break;
+       case 's':
+         if (!strcmp ("schedule", p))
+           result = PRAGMA_OMP_CLAUSE_SCHEDULE;
+         else if (!strcmp ("shared", p))
+           result = PRAGMA_OMP_CLAUSE_SHARED;
+         break;
+       case 'u':
+         if (!strcmp ("untied", p))
+           result = PRAGMA_OMP_CLAUSE_UNTIED;
+         break;
+       }
+    }
+
+  if (result != PRAGMA_OMP_CLAUSE_NONE)
+    c_parser_consume_token (parser);
+
+  return result;
+}
+
+/* Validate that a clause of the given type does not already exist.  */
+
+static void
+check_no_duplicate_clause (tree clauses, enum omp_clause_code code,
+                          const char *name)
+{
+  tree c;
+
+  for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+    if (OMP_CLAUSE_CODE (c) == code)
+      {
+       error ("too many %qs clauses", name);
+       break;
+      }
+}
+
+/* OpenMP 2.5:
+   variable-list:
+     identifier
+     variable-list , identifier
+
+   If KIND is nonzero, create the appropriate node and install the decl
+   in OMP_CLAUSE_DECL and add the node to the head of the list.
+
+   If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE;
+   return the list created.  */
+
+static tree
+c_parser_omp_variable_list (c_parser *parser, enum omp_clause_code kind,
+                            tree list)
+{
+  if (c_parser_next_token_is_not (parser, CPP_NAME)
+      || c_parser_peek_token (parser)->id_kind != C_ID_ID)
+    c_parser_error (parser, "expected identifier");
+
+  while (c_parser_next_token_is (parser, CPP_NAME)
+        && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+    {
+      tree t = lookup_name (c_parser_peek_token (parser)->value);
+
+      if (t == NULL_TREE)
+       undeclared_variable (c_parser_peek_token (parser)->value,
+                            c_parser_peek_token (parser)->location);
+      else if (t == error_mark_node)
+       ;
+      else if (kind != 0)
+       {
+         tree u = build_omp_clause (kind);
+         OMP_CLAUSE_DECL (u) = t;
+         OMP_CLAUSE_CHAIN (u) = list;
+         list = u;
+       }
+      else
+       list = tree_cons (t, NULL_TREE, list);
+
+      c_parser_consume_token (parser);
+
+      if (c_parser_next_token_is_not (parser, CPP_COMMA))
+       break;
+
+      c_parser_consume_token (parser);
+    }
+
+  return list;
+}
+
+/* Similarly, but expect leading and trailing parenthesis.  This is a very
+   common case for omp clauses.  */
+
+static tree
+c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind,
+                             tree list)
+{
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      list = c_parser_omp_variable_list (parser, kind, list);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  return list;
+}
+
+/* OpenMP 3.0:
+   collapse ( constant-expression ) */
+
+static tree
+c_parser_omp_clause_collapse (c_parser *parser, tree list)
+{
+  tree c, num = error_mark_node;
+  HOST_WIDE_INT n;
+  location_t loc;
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_COLLAPSE, "collapse");
+
+  loc = c_parser_peek_token (parser)->location;
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      num = c_parser_expr_no_commas (parser, NULL).value;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  if (num == error_mark_node)
+    return list;
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (num))
+      || !host_integerp (num, 0)
+      || (n = tree_low_cst (num, 0)) <= 0
+      || (int) n != n)
+    {
+      error_at (loc,
+               "collapse argument needs positive constant integer expression");
+      return list;
+    }
+  c = build_omp_clause (OMP_CLAUSE_COLLAPSE);
+  OMP_CLAUSE_COLLAPSE_EXPR (c) = num;
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
+}
+
+/* OpenMP 2.5:
+   copyin ( variable-list ) */
+
+static tree
+c_parser_omp_clause_copyin (c_parser *parser, tree list)
+{
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYIN, list);
+}
+
+/* OpenMP 2.5:
+   copyprivate ( variable-list ) */
+
+static tree
+c_parser_omp_clause_copyprivate (c_parser *parser, tree list)
+{
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYPRIVATE, list);
+}
+
+/* OpenMP 2.5:
+   default ( shared | none ) */
+
+static tree
+c_parser_omp_clause_default (c_parser *parser, tree list)
+{
+  enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
+  tree c;
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+      switch (p[0])
+       {
+       case 'n':
+         if (strcmp ("none", p) != 0)
+           goto invalid_kind;
+         kind = OMP_CLAUSE_DEFAULT_NONE;
+         break;
+
+       case 's':
+         if (strcmp ("shared", p) != 0)
+           goto invalid_kind;
+         kind = OMP_CLAUSE_DEFAULT_SHARED;
+         break;
+
+       default:
+         goto invalid_kind;
+       }
+
+      c_parser_consume_token (parser);
+    }
+  else
+    {
+    invalid_kind:
+      c_parser_error (parser, "expected %<none%> or %<shared%>");
+    }
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+  if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED)
+    return list;
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default");
+  c = build_omp_clause (OMP_CLAUSE_DEFAULT);
+  OMP_CLAUSE_CHAIN (c) = list;
+  OMP_CLAUSE_DEFAULT_KIND (c) = kind;
+
+  return c;
+}
+
+/* OpenMP 2.5:
+   firstprivate ( variable-list ) */
+
+static tree
+c_parser_omp_clause_firstprivate (c_parser *parser, tree list)
+{
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list);
+}
+
+/* OpenMP 2.5:
+   if ( expression ) */
+
+static tree
+c_parser_omp_clause_if (c_parser *parser, tree list)
+{
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      tree t = c_parser_paren_condition (parser);
+      tree c;
+
+      check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if");
+
+      c = build_omp_clause (OMP_CLAUSE_IF);
+      OMP_CLAUSE_IF_EXPR (c) = t;
+      OMP_CLAUSE_CHAIN (c) = list;
+      list = c;
+    }
+  else
+    c_parser_error (parser, "expected %<(%>");
+
+  return list;
+}
+
+/* OpenMP 2.5:
+   lastprivate ( variable-list ) */
+
+static tree
+c_parser_omp_clause_lastprivate (c_parser *parser, tree list)
+{
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list);
+}
+
+/* OpenMP 2.5:
+   nowait */
+
+static tree
+c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+  tree c;
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait");
+
+  c = build_omp_clause (OMP_CLAUSE_NOWAIT);
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
+}
+
+/* OpenMP 2.5:
+   num_threads ( expression ) */
+
+static tree
+c_parser_omp_clause_num_threads (c_parser *parser, tree list)
+{
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      location_t expr_loc = c_parser_peek_token (parser)->location;
+      tree c, t = c_parser_expression (parser).value;
+
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+       {
+         c_parser_error (parser, "expected integer expression");
+         return list;
+       }
+
+      /* Attempt to statically determine when the number isn't positive.  */
+      c = fold_build2 (LE_EXPR, boolean_type_node, t,
+                      build_int_cst (TREE_TYPE (t), 0));
+      if (c == boolean_true_node)
+       {
+         warning_at (expr_loc, 0,
+                     "%<num_threads%> value must be positive");
+         t = integer_one_node;
+       }
+
+      check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads");
+
+      c = build_omp_clause (OMP_CLAUSE_NUM_THREADS);
+      OMP_CLAUSE_NUM_THREADS_EXPR (c) = t;
+      OMP_CLAUSE_CHAIN (c) = list;
+      list = c;
+    }
+
+  return list;
+}
+
+/* OpenMP 2.5:
+   ordered */
+
+static tree
+c_parser_omp_clause_ordered (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+  tree c;
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered");
+
+  c = build_omp_clause (OMP_CLAUSE_ORDERED);
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
+}
+
+/* OpenMP 2.5:
+   private ( variable-list ) */
+
+static tree
+c_parser_omp_clause_private (c_parser *parser, tree list)
+{
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_PRIVATE, list);
+}
+
+/* OpenMP 2.5:
+   reduction ( reduction-operator : variable-list )
+
+   reduction-operator:
+     One of: + * - & ^ | && || */
+
+static tree
+c_parser_omp_clause_reduction (c_parser *parser, tree list)
+{
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      enum tree_code code;
+
+      switch (c_parser_peek_token (parser)->type)
+       {
+       case CPP_PLUS:
+         code = PLUS_EXPR;
+         break;
+       case CPP_MULT:
+         code = MULT_EXPR;
+         break;
+       case CPP_MINUS:
+         code = MINUS_EXPR;
+         break;
+       case CPP_AND:
+         code = BIT_AND_EXPR;
+         break;
+       case CPP_XOR:
+         code = BIT_XOR_EXPR;
+         break;
+       case CPP_OR:
+         code = BIT_IOR_EXPR;
+         break;
+       case CPP_AND_AND:
+         code = TRUTH_ANDIF_EXPR;
+         break;
+       case CPP_OR_OR:
+         code = TRUTH_ORIF_EXPR;
+         break;
+       default:
+         c_parser_error (parser,
+                         "expected %<+%>, %<*%>, %<-%>, %<&%>, "
+                         "%<^%>, %<|%>, %<&&%>, or %<||%>");
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0);
+         return list;
+       }
+      c_parser_consume_token (parser);
+      if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+       {
+         tree nl, c;
+
+         nl = c_parser_omp_variable_list (parser, OMP_CLAUSE_REDUCTION, list);
+         for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+           OMP_CLAUSE_REDUCTION_CODE (c) = code;
+
+         list = nl;
+       }
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  return list;
+}
+
+/* OpenMP 2.5:
+   schedule ( schedule-kind )
+   schedule ( schedule-kind , expression )
+
+   schedule-kind:
+     static | dynamic | guided | runtime | auto
+*/
+
+static tree
+c_parser_omp_clause_schedule (c_parser *parser, tree list)
+{
+  tree c, t;
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
+
+  c = build_omp_clause (OMP_CLAUSE_SCHEDULE);
+
+  if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      tree kind = c_parser_peek_token (parser)->value;
+      const char *p = IDENTIFIER_POINTER (kind);
+
+      switch (p[0])
+       {
+       case 'd':
+         if (strcmp ("dynamic", p) != 0)
+           goto invalid_kind;
+         OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC;
+         break;
+
+        case 'g':
+         if (strcmp ("guided", p) != 0)
+           goto invalid_kind;
+         OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED;
+         break;
+
+       case 'r':
+         if (strcmp ("runtime", p) != 0)
+           goto invalid_kind;
+         OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME;
+         break;
+
+       default:
+         goto invalid_kind;
+       }
+    }
+  else if (c_parser_next_token_is_keyword (parser, RID_STATIC))
+    OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC;
+  else if (c_parser_next_token_is_keyword (parser, RID_AUTO))
+    OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO;
+  else
+    goto invalid_kind;
+
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is (parser, CPP_COMMA))
+    {
+      location_t here;
+      c_parser_consume_token (parser);
+
+      here = c_parser_peek_token (parser)->location;
+      t = c_parser_expr_no_commas (parser, NULL).value;
+
+      if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME)
+       error_at (here, "schedule %<runtime%> does not take "
+                 "a %<chunk_size%> parameter");
+      else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO)
+       error_at (here,
+                 "schedule %<auto%> does not take "
+                 "a %<chunk_size%> parameter");
+      else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE)
+       OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t;
+      else
+       c_parser_error (parser, "expected integer expression");
+
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  else
+    c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                              "expected %<,%> or %<)%>");
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule");
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
+
+ invalid_kind:
+  c_parser_error (parser, "invalid schedule kind");
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0);
+  return list;
+}
+
+/* OpenMP 2.5:
+   shared ( variable-list ) */
+
+static tree
+c_parser_omp_clause_shared (c_parser *parser, tree list)
+{
+  return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_SHARED, list);
+}
+
+/* OpenMP 3.0:
+   untied */
+
+static tree
+c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+  tree c;
+
+  /* FIXME: Should we allow duplicates?  */
+  check_no_duplicate_clause (list, OMP_CLAUSE_UNTIED, "untied");
+
+  c = build_omp_clause (OMP_CLAUSE_UNTIED);
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
+}
+
+/* Parse all OpenMP clauses.  The set clauses allowed by the directive
+   is a bitmask in MASK.  Return the list of clauses found; the result
+   of clause default goes in *pdefault.  */
+
+static tree
+c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
+                         const char *where)
+{
+  tree clauses = NULL;
+  bool first = true;
+
+  while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+    {
+      location_t here;
+      pragma_omp_clause c_kind;
+      const char *c_name;
+      tree prev = clauses;
+
+      if (!first && c_parser_next_token_is (parser, CPP_COMMA))
+       c_parser_consume_token (parser);
+
+      first = false;
+      here = c_parser_peek_token (parser)->location;
+      c_kind = c_parser_omp_clause_name (parser);
+
+      switch (c_kind)
+       {
+       case PRAGMA_OMP_CLAUSE_COLLAPSE:
+         clauses = c_parser_omp_clause_collapse (parser, clauses);
+         c_name = "collapse";
+         break;
+       case PRAGMA_OMP_CLAUSE_COPYIN:
+         clauses = c_parser_omp_clause_copyin (parser, clauses);
+         c_name = "copyin";
+         break;
+       case PRAGMA_OMP_CLAUSE_COPYPRIVATE:
+         clauses = c_parser_omp_clause_copyprivate (parser, clauses);
+         c_name = "copyprivate";
+         break;
+       case PRAGMA_OMP_CLAUSE_DEFAULT:
+         clauses = c_parser_omp_clause_default (parser, clauses);
+         c_name = "default";
+         break;
+       case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
+         clauses = c_parser_omp_clause_firstprivate (parser, clauses);
+         c_name = "firstprivate";
+         break;
+       case PRAGMA_OMP_CLAUSE_IF:
+         clauses = c_parser_omp_clause_if (parser, clauses);
+         c_name = "if";
+         break;
+       case PRAGMA_OMP_CLAUSE_LASTPRIVATE:
+         clauses = c_parser_omp_clause_lastprivate (parser, clauses);
+         c_name = "lastprivate";
+         break;
+       case PRAGMA_OMP_CLAUSE_NOWAIT:
+         clauses = c_parser_omp_clause_nowait (parser, clauses);
+         c_name = "nowait";
+         break;
+       case PRAGMA_OMP_CLAUSE_NUM_THREADS:
+         clauses = c_parser_omp_clause_num_threads (parser, clauses);
+         c_name = "num_threads";
+         break;
+       case PRAGMA_OMP_CLAUSE_ORDERED:
+         clauses = c_parser_omp_clause_ordered (parser, clauses);
+         c_name = "ordered";
+         break;
+       case PRAGMA_OMP_CLAUSE_PRIVATE:
+         clauses = c_parser_omp_clause_private (parser, clauses);
+         c_name = "private";
+         break;
+       case PRAGMA_OMP_CLAUSE_REDUCTION:
+         clauses = c_parser_omp_clause_reduction (parser, clauses);
+         c_name = "reduction";
+         break;
+       case PRAGMA_OMP_CLAUSE_SCHEDULE:
+         clauses = c_parser_omp_clause_schedule (parser, clauses);
+         c_name = "schedule";
+         break;
+       case PRAGMA_OMP_CLAUSE_SHARED:
+         clauses = c_parser_omp_clause_shared (parser, clauses);
+         c_name = "shared";
+         break;
+       case PRAGMA_OMP_CLAUSE_UNTIED:
+         clauses = c_parser_omp_clause_untied (parser, clauses);
+         c_name = "untied";
+         break;
+       default:
+         c_parser_error (parser, "expected %<#pragma omp%> clause");
+         goto saw_error;
+       }
+
+      if (((mask >> c_kind) & 1) == 0 && !parser->error)
+       {
+         /* Remove the invalid clause(s) from the list to avoid
+            confusing the rest of the compiler.  */
+         clauses = prev;
+         error_at (here, "%qs is not valid for %qs", c_name, where);
+       }
+    }
+
+ saw_error:
+  c_parser_skip_to_pragma_eol (parser);
+
+  return c_finish_omp_clauses (clauses);
+}
+
+/* OpenMP 2.5:
+   structured-block:
+     statement
+
+   In practice, we're also interested in adding the statement to an
+   outer node.  So it is convenient if we work around the fact that
+   c_parser_statement calls add_stmt.  */
+
+static tree
+c_parser_omp_structured_block (c_parser *parser)
+{
+  tree stmt = push_stmt_list ();
+  c_parser_statement (parser);
+  return pop_stmt_list (stmt);
+}
+
+/* OpenMP 2.5:
+   # pragma omp atomic new-line
+     expression-stmt
+
+   expression-stmt:
+     x binop= expr | x++ | ++x | x-- | --x
+   binop:
+     +, *, -, /, &, ^, |, <<, >>
+
+  where x is an lvalue expression with scalar type.  */
+
+static void
+c_parser_omp_atomic (c_parser *parser)
+{
+  tree lhs, rhs;
+  tree stmt;
+  enum tree_code code;
+  struct c_expr rhs_expr;
+
+  c_parser_skip_to_pragma_eol (parser);
+
+  lhs = c_parser_unary_expression (parser).value;
+  switch (TREE_CODE (lhs))
+    {
+    case ERROR_MARK:
+    saw_error:
+      c_parser_skip_to_end_of_block_or_statement (parser);
+      return;
+
+    case PREINCREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+      lhs = TREE_OPERAND (lhs, 0);
+      code = PLUS_EXPR;
+      rhs = integer_one_node;
+      break;
+
+    case PREDECREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+      lhs = TREE_OPERAND (lhs, 0);
+      code = MINUS_EXPR;
+      rhs = integer_one_node;
+      break;
+
+    default:
+      switch (c_parser_peek_token (parser)->type)
+       {
+       case CPP_MULT_EQ:
+         code = MULT_EXPR;
+         break;
+       case CPP_DIV_EQ:
+         code = TRUNC_DIV_EXPR;
+         break;
+       case CPP_PLUS_EQ:
+         code = PLUS_EXPR;
+         break;
+       case CPP_MINUS_EQ:
+         code = MINUS_EXPR;
+         break;
+       case CPP_LSHIFT_EQ:
+         code = LSHIFT_EXPR;
+         break;
+       case CPP_RSHIFT_EQ:
+         code = RSHIFT_EXPR;
+         break;
+       case CPP_AND_EQ:
+         code = BIT_AND_EXPR;
+         break;
+       case CPP_OR_EQ:
+         code = BIT_IOR_EXPR;
+         break;
+       case CPP_XOR_EQ:
+         code = BIT_XOR_EXPR;
+         break;
+       default:
+         c_parser_error (parser,
+                         "invalid operator for %<#pragma omp atomic%>");
+         goto saw_error;
+       }
+
+      c_parser_consume_token (parser);
+      rhs_expr = c_parser_expression (parser);
+      rhs_expr = default_function_array_conversion (rhs_expr);
+      rhs = rhs_expr.value;
+      break;
+    }
+  stmt = c_finish_omp_atomic (code, lhs, rhs);
+  if (stmt != error_mark_node)
+    add_stmt (stmt);
+  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+}
+
+
+/* OpenMP 2.5:
+   # pragma omp barrier new-line
+*/
+
+static void
+c_parser_omp_barrier (c_parser *parser)
+{
+  c_parser_consume_pragma (parser);
+  c_parser_skip_to_pragma_eol (parser);
+
+  c_finish_omp_barrier ();
+}
+
+/* OpenMP 2.5:
+   # pragma omp critical [(name)] new-line
+     structured-block
+*/
+
+static tree
+c_parser_omp_critical (c_parser *parser)
+{
+  tree stmt, name = NULL;
+
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    {
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_NAME))
+       {
+         name = c_parser_peek_token (parser)->value;
+         c_parser_consume_token (parser);
+         c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+       }
+      else
+       c_parser_error (parser, "expected identifier");
+    }
+  else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+    c_parser_error (parser, "expected %<(%> or end of line");
+  c_parser_skip_to_pragma_eol (parser);
+
+  stmt = c_parser_omp_structured_block (parser);
+  return c_finish_omp_critical (stmt, name);
+}
+
+/* OpenMP 2.5:
+   # pragma omp flush flush-vars[opt] new-line
+
+   flush-vars:
+     ( variable-list ) */
+
+static void
+c_parser_omp_flush (c_parser *parser)
+{
+  c_parser_consume_pragma (parser);
+  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+    c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
+  else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+    c_parser_error (parser, "expected %<(%> or end of line");
+  c_parser_skip_to_pragma_eol (parser);
+
+  c_finish_omp_flush ();
+}
+
+/* Parse the restricted form of the for statement allowed by OpenMP.
+   The real trick here is to determine the loop control variable early
+   so that we can push a new decl if necessary to make it private.  */
+
+static tree
+c_parser_omp_for_loop (c_parser *parser, tree clauses, tree *par_clauses)
+{
+  tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
+  tree declv, condv, incrv, initv, for_block = NULL, ret = NULL;
+  location_t loc;
+  bool fail = false, open_brace_parsed = false;
+  int i, collapse = 1, nbraces = 0;
+
+  for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
+    if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
+      collapse = tree_low_cst (OMP_CLAUSE_COLLAPSE_EXPR (cl), 0);
+
+  gcc_assert (collapse >= 1);
+
+  declv = make_tree_vec (collapse);
+  initv = make_tree_vec (collapse);
+  condv = make_tree_vec (collapse);
+  incrv = make_tree_vec (collapse);
+
+  if (!c_parser_next_token_is_keyword (parser, RID_FOR))
+    {
+      c_parser_error (parser, "for statement expected");
+      return NULL;
+    }
+  loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_token (parser);
+
+  for (i = 0; i < collapse; i++)
+    {
+      int bracecount = 0;
+
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+       goto pop_scopes;
+
+      /* Parse the initialization declaration or expression.  */
+      if (c_parser_next_token_starts_declspecs (parser))
+       {
+         if (i > 0)
+           for_block
+             = tree_cons (NULL, c_begin_compound_stmt (true), for_block);
+         c_parser_declaration_or_fndef (parser, true, true, true, true);
+         decl = check_for_loop_decls ();
+         if (decl == NULL)
+           goto error_init;
+         if (DECL_INITIAL (decl) == error_mark_node)
+           decl = error_mark_node;
+         init = decl;
+       }
+      else if (c_parser_next_token_is (parser, CPP_NAME)
+              && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
+       {
+         struct c_expr init_exp;
+         location_t init_loc;
+
+         decl = c_parser_postfix_expression (parser).value;
+
+         c_parser_require (parser, CPP_EQ, "expected %<=%>");
+         init_loc = c_parser_peek_token (parser)->location;
+
+         init_exp = c_parser_expr_no_commas (parser, NULL);
+         init_exp = default_function_array_conversion (init_exp);
+         init = build_modify_expr (init_loc,
+                                   decl, NOP_EXPR, init_exp.value);
+         init = c_process_expr_stmt (init);
+
+         c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+       }
+      else
+       {
+       error_init:
+         c_parser_error (parser,
+                         "expected iteration declaration or initialization");
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                                    "expected %<)%>");
+         fail = true;
+         goto parse_next;
+       }
+
+      /* Parse the loop condition.  */
+      cond = NULL_TREE;
+      if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+       {
+         location_t cond_loc = c_parser_peek_token (parser)->location;
+         struct c_expr cond_expr = c_parser_binary_expression (parser, NULL);
+
+         cond = cond_expr.value;
+         cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
+         switch (cond_expr.original_code)
+           {
+           case GT_EXPR:
+           case GE_EXPR:
+           case LT_EXPR:
+           case LE_EXPR:
+             break;
+           default:
+             /* Can't be cond = error_mark_node, because we want to preserve
+                the location until c_finish_omp_for.  */
+             cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node);
+             break;
+           }
+         protected_set_expr_location (cond, cond_loc);
+       }
+      c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+
+      /* Parse the increment expression.  */
+      incr = NULL_TREE;
+      if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+       {
+         location_t incr_loc = c_parser_peek_token (parser)->location;
+
+         incr = c_process_expr_stmt (c_parser_expression (parser).value);
+         protected_set_expr_location (incr, incr_loc);
+       }
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+      if (decl == NULL || decl == error_mark_node || init == error_mark_node)
+       fail = true;
+      else
+       {
+         TREE_VEC_ELT (declv, i) = decl;
+         TREE_VEC_ELT (initv, i) = init;
+         TREE_VEC_ELT (condv, i) = cond;
+         TREE_VEC_ELT (incrv, i) = incr;
+       }
+
+    parse_next:
+      if (i == collapse - 1)
+       break;
+
+      /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed
+        in between the collapsed for loops to be still considered perfectly
+        nested.  Hopefully the final version clarifies this.
+        For now handle (multiple) {'s and empty statements.  */
+      do
+       {
+         if (c_parser_next_token_is_keyword (parser, RID_FOR))
+           {
+             c_parser_consume_token (parser);
+             break;
+           }
+         else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+           {
+             c_parser_consume_token (parser);
+             bracecount++;
+           }
+         else if (bracecount
+                  && c_parser_next_token_is (parser, CPP_SEMICOLON))
+           c_parser_consume_token (parser);
+         else
+           {
+             c_parser_error (parser, "not enough perfectly nested loops");
+             if (bracecount)
+               {
+                 open_brace_parsed = true;
+                 bracecount--;
+               }
+             fail = true;
+             collapse = 0;
+             break;
+           }
+       }
+      while (1);
+
+      nbraces += bracecount;
+    }
+
+  save_break = c_break_label;
+  c_break_label = size_one_node;
+  save_cont = c_cont_label;
+  c_cont_label = NULL_TREE;
+  body = push_stmt_list ();
+
+  if (open_brace_parsed)
+    {
+      stmt = c_begin_compound_stmt (true);
+      c_parser_compound_statement_nostart (parser);
+      add_stmt (c_end_compound_stmt (stmt, true));
+    }
+  else
+    add_stmt (c_parser_c99_block_statement (parser));
+  if (c_cont_label)
+    add_stmt (build1 (LABEL_EXPR, void_type_node, c_cont_label));
+
+  body = pop_stmt_list (body);
+  c_break_label = save_break;
+  c_cont_label = save_cont;
+
+  while (nbraces)
+    {
+      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+       {
+         c_parser_consume_token (parser);
+         nbraces--;
+       }
+      else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+       c_parser_consume_token (parser);
+      else
+       {
+         c_parser_error (parser, "collapsed loops not perfectly nested");
+         while (nbraces)
+           {
+             stmt = c_begin_compound_stmt (true);
+             add_stmt (body);
+             c_parser_compound_statement_nostart (parser);
+             body = c_end_compound_stmt (stmt, true);
+             nbraces--;
+           }
+         goto pop_scopes;
+       }
+    }
+
+  /* Only bother calling c_finish_omp_for if we haven't already generated
+     an error from the initialization parsing.  */
+  if (!fail)
+    {
+      stmt = c_finish_omp_for (loc, declv, initv, condv, incrv, body, NULL);
+      if (stmt)
+       {
+         if (par_clauses != NULL)
+           {
+             tree *c;
+             for (c = par_clauses; *c ; )
+               if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE
+                   && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE)
+                 c = &OMP_CLAUSE_CHAIN (*c);
+               else
+                 {
+                   for (i = 0; i < collapse; i++)
+                     if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c))
+                       break;
+                   if (i == collapse)
+                     c = &OMP_CLAUSE_CHAIN (*c);
+                   else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE)
+                     {
+                       error_at (loc,
+                                 "iteration variable %qD should not be firstprivate",
+                                 OMP_CLAUSE_DECL (*c));
+                       *c = OMP_CLAUSE_CHAIN (*c);
+                     }
+                   else
+                     {
+                       /* Copy lastprivate (decl) clause to OMP_FOR_CLAUSES,
+                          change it to shared (decl) in
+                          OMP_PARALLEL_CLAUSES.  */
+                       tree l = build_omp_clause (OMP_CLAUSE_LASTPRIVATE);
+                       OMP_CLAUSE_DECL (l) = OMP_CLAUSE_DECL (*c);
+                       OMP_CLAUSE_CHAIN (l) = clauses;
+                       clauses = l;
+                       OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED);
+                     }
+                 }
+           }
+         OMP_FOR_CLAUSES (stmt) = clauses;
+       }
+      ret = stmt;
+    }
+pop_scopes:
+  while (for_block)
+    {
+      stmt = c_end_compound_stmt (TREE_VALUE (for_block), true);
+      add_stmt (stmt);
+      for_block = TREE_CHAIN (for_block);
+    }
+  return ret;
+}
+
+/* OpenMP 2.5:
+   #pragma omp for for-clause[optseq] new-line
+     for-loop
+*/
+
+#define OMP_FOR_CLAUSE_MASK                            \
+       ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE)             \
+       | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)        \
+       | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE)         \
+       | (1u << PRAGMA_OMP_CLAUSE_REDUCTION)           \
+       | (1u << PRAGMA_OMP_CLAUSE_ORDERED)             \
+       | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE)            \
+       | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE)            \
+       | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_for (c_parser *parser)
+{
+  tree block, clauses, ret;
+
+  clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK,
+                                     "#pragma omp for");
+
+  block = c_begin_compound_stmt (true);
+  ret = c_parser_omp_for_loop (parser, clauses, NULL);
+  block = c_end_compound_stmt (block, true);
+  add_stmt (block);
+
+  return ret;
+}
+
+/* OpenMP 2.5:
+   # pragma omp master new-line
+     structured-block
+*/
+
+static tree
+c_parser_omp_master (c_parser *parser)
+{
+  c_parser_skip_to_pragma_eol (parser);
+  return c_finish_omp_master (c_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 2.5:
+   # pragma omp ordered new-line
+     structured-block
+*/
+
+static tree
+c_parser_omp_ordered (c_parser *parser)
+{
+  c_parser_skip_to_pragma_eol (parser);
+  return c_finish_omp_ordered (c_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 2.5:
+
+   section-scope:
+     { section-sequence }
+
+   section-sequence:
+     section-directive[opt] structured-block
+     section-sequence section-directive structured-block  */
+
+static tree
+c_parser_omp_sections_scope (c_parser *parser)
+{
+  tree stmt, substmt;
+  bool error_suppress = false;
+  location_t loc;
+
+  if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+    {
+      /* Avoid skipping until the end of the block.  */
+      parser->error = false;
+      return NULL_TREE;
+    }
+
+  stmt = push_stmt_list ();
+
+  loc = c_parser_peek_token (parser)->location;
+  if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION)
+    {
+      substmt = push_stmt_list ();
+
+      while (1)
+       {
+          c_parser_statement (parser);
+
+         if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
+           break;
+         if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+           break;
+         if (c_parser_next_token_is (parser, CPP_EOF))
+           break;
+       }
+
+      substmt = pop_stmt_list (substmt);
+      substmt = build1 (OMP_SECTION, void_type_node, substmt);
+      SET_EXPR_LOCATION (substmt, loc);
+      add_stmt (substmt);
+    }
+
+  while (1)
+    {
+      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+       break;
+      if (c_parser_next_token_is (parser, CPP_EOF))
+       break;
+
+      loc = c_parser_peek_token (parser)->location;
+      if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
+       {
+         c_parser_consume_pragma (parser);
+         c_parser_skip_to_pragma_eol (parser);
+         error_suppress = false;
+       }
+      else if (!error_suppress)
+       {
+         error_at (loc, "expected %<#pragma omp section%> or %<}%>");
+         error_suppress = true;
+       }
+
+      substmt = c_parser_omp_structured_block (parser);
+      substmt = build1 (OMP_SECTION, void_type_node, substmt);
+      SET_EXPR_LOCATION (substmt, loc);
+      add_stmt (substmt);
+    }
+  c_parser_skip_until_found (parser, CPP_CLOSE_BRACE,
+                            "expected %<#pragma omp section%> or %<}%>");
+
+  substmt = pop_stmt_list (stmt);
+
+  stmt = make_node (OMP_SECTIONS);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_SECTIONS_BODY (stmt) = substmt;
+
+  return add_stmt (stmt);
+}
+
+/* OpenMP 2.5:
+   # pragma omp sections sections-clause[optseq] newline
+     sections-scope
+*/
+
+#define OMP_SECTIONS_CLAUSE_MASK                       \
+       ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE)             \
+       | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)        \
+       | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE)         \
+       | (1u << PRAGMA_OMP_CLAUSE_REDUCTION)           \
+       | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_sections (c_parser *parser)
+{
+  tree block, clauses, ret;
+
+  clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK,
+                                     "#pragma omp sections");
+
+  block = c_begin_compound_stmt (true);
+  ret = c_parser_omp_sections_scope (parser);
+  if (ret)
+    OMP_SECTIONS_CLAUSES (ret) = clauses;
+  block = c_end_compound_stmt (block, true);
+  add_stmt (block);
+
+  return ret;
+}
+
+/* OpenMP 2.5:
+   # pragma parallel parallel-clause new-line
+   # pragma parallel for parallel-for-clause new-line
+   # pragma parallel sections parallel-sections-clause new-line
+*/
+
+#define OMP_PARALLEL_CLAUSE_MASK                       \
+       ( (1u << PRAGMA_OMP_CLAUSE_IF)                  \
+       | (1u << PRAGMA_OMP_CLAUSE_PRIVATE)             \
+       | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)        \
+       | (1u << PRAGMA_OMP_CLAUSE_DEFAULT)             \
+       | (1u << PRAGMA_OMP_CLAUSE_SHARED)              \
+       | (1u << PRAGMA_OMP_CLAUSE_COPYIN)              \
+       | (1u << PRAGMA_OMP_CLAUSE_REDUCTION)           \
+       | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+
+static tree
+c_parser_omp_parallel (c_parser *parser)
+{
+  enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL;
+  const char *p_name = "#pragma omp parallel";
+  tree stmt, clauses, par_clause, ws_clause, block;
+  unsigned int mask = OMP_PARALLEL_CLAUSE_MASK;
+
+  if (c_parser_next_token_is_keyword (parser, RID_FOR))
+    {
+      c_parser_consume_token (parser);
+      p_kind = PRAGMA_OMP_PARALLEL_FOR;
+      p_name = "#pragma omp parallel for";
+      mask |= OMP_FOR_CLAUSE_MASK;
+      mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+    }
+  else if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if (strcmp (p, "sections") == 0)
+       {
+         c_parser_consume_token (parser);
+         p_kind = PRAGMA_OMP_PARALLEL_SECTIONS;
+         p_name = "#pragma omp parallel sections";
+         mask |= OMP_SECTIONS_CLAUSE_MASK;
+         mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+       }
+    }
+
+  clauses = c_parser_omp_all_clauses (parser, mask, p_name);
+
+  switch (p_kind)
+    {
+    case PRAGMA_OMP_PARALLEL:
+      block = c_begin_omp_parallel ();
+      c_parser_statement (parser);
+      stmt = c_finish_omp_parallel (clauses, block);
+      break;
+
+    case PRAGMA_OMP_PARALLEL_FOR:
+      block = c_begin_omp_parallel ();
+      c_split_parallel_clauses (clauses, &par_clause, &ws_clause);
+      c_parser_omp_for_loop (parser, ws_clause, &par_clause);
+      stmt = c_finish_omp_parallel (par_clause, block);
+      OMP_PARALLEL_COMBINED (stmt) = 1;
+      break;
+
+    case PRAGMA_OMP_PARALLEL_SECTIONS:
+      block = c_begin_omp_parallel ();
+      c_split_parallel_clauses (clauses, &par_clause, &ws_clause);
+      stmt = c_parser_omp_sections_scope (parser);
+      if (stmt)
+       OMP_SECTIONS_CLAUSES (stmt) = ws_clause;
+      stmt = c_finish_omp_parallel (par_clause, block);
+      OMP_PARALLEL_COMBINED (stmt) = 1;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return stmt;
+}
+
+/* OpenMP 2.5:
+   # pragma omp single single-clause[optseq] new-line
+     structured-block
+*/
+
+#define OMP_SINGLE_CLAUSE_MASK                         \
+       ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE)             \
+       | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)        \
+       | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE)         \
+       | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_single (c_parser *parser)
+{
+  tree stmt = make_node (OMP_SINGLE);
+  TREE_TYPE (stmt) = void_type_node;
+
+  OMP_SINGLE_CLAUSES (stmt)
+    = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK,
+                               "#pragma omp single");
+  OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser);
+
+  return add_stmt (stmt);
+}
+
+/* OpenMP 3.0:
+   # pragma omp task task-clause[optseq] new-line
+*/
+
+#define OMP_TASK_CLAUSE_MASK                           \
+       ( (1u << PRAGMA_OMP_CLAUSE_IF)                  \
+       | (1u << PRAGMA_OMP_CLAUSE_UNTIED)              \
+       | (1u << PRAGMA_OMP_CLAUSE_DEFAULT)             \
+       | (1u << PRAGMA_OMP_CLAUSE_PRIVATE)             \
+       | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)        \
+       | (1u << PRAGMA_OMP_CLAUSE_SHARED))
+
+static tree
+c_parser_omp_task (c_parser *parser)
+{
+  tree clauses, block;
+
+  clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK,
+                                     "#pragma omp task");
+
+  block = c_begin_omp_task ();
+  c_parser_statement (parser);
+  return c_finish_omp_task (clauses, block);
+}
+
+/* OpenMP 3.0:
+   # pragma omp taskwait new-line
+*/
+
+static void
+c_parser_omp_taskwait (c_parser *parser)
+{
+  c_parser_consume_pragma (parser);
+  c_parser_skip_to_pragma_eol (parser);
+
+  c_finish_omp_taskwait ();
+}
+
+/* Main entry point to parsing most OpenMP pragmas.  */
+
+static void
+c_parser_omp_construct (c_parser *parser)
+{
+  enum pragma_kind p_kind;
+  location_t loc;
+  tree stmt;
+
+  loc = c_parser_peek_token (parser)->location;
+  p_kind = c_parser_peek_token (parser)->pragma_kind;
+  c_parser_consume_pragma (parser);
+
+  /* For all constructs below except #pragma omp atomic
+     MUST_NOT_THROW catch handlers are needed when exceptions
+     are enabled.  */
+  if (p_kind != PRAGMA_OMP_ATOMIC)
+    c_maybe_initialize_eh ();
+
+  switch (p_kind)
+    {
+    case PRAGMA_OMP_ATOMIC:
+      c_parser_omp_atomic (parser);
+      return;
+    case PRAGMA_OMP_CRITICAL:
+      stmt = c_parser_omp_critical (parser);
+      break;
+    case PRAGMA_OMP_FOR:
+      stmt = c_parser_omp_for (parser);
+      break;
+    case PRAGMA_OMP_MASTER:
+      stmt = c_parser_omp_master (parser);
+      break;
+    case PRAGMA_OMP_ORDERED:
+      stmt = c_parser_omp_ordered (parser);
+      break;
+    case PRAGMA_OMP_PARALLEL:
+      stmt = c_parser_omp_parallel (parser);
+      break;
+    case PRAGMA_OMP_SECTIONS:
+      stmt = c_parser_omp_sections (parser);
+      break;
+    case PRAGMA_OMP_SINGLE:
+      stmt = c_parser_omp_single (parser);
+      break;
+    case PRAGMA_OMP_TASK:
+      stmt = c_parser_omp_task (parser);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (stmt)
+    SET_EXPR_LOCATION (stmt, loc);
+}
+
+
+/* OpenMP 2.5:
+   # pragma omp threadprivate (variable-list) */
+
+static void
+c_parser_omp_threadprivate (c_parser *parser)
+{
+  tree vars, t;
+
+  c_parser_consume_pragma (parser);
+  vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
+
+  /* Mark every variable in VARS to be assigned thread local storage.  */
+  for (t = vars; t; t = TREE_CHAIN (t))
+    {
+      tree v = TREE_PURPOSE (t);
+
+      /* If V had already been marked threadprivate, it doesn't matter
+        whether it had been used prior to this point.  */
+      if (TREE_CODE (v) != VAR_DECL)
+       error ("%qD is not a variable", v);
+      else if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v))
+       error ("%qE declared %<threadprivate%> after first use", v);
+      else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v))
+       error ("automatic variable %qE cannot be %<threadprivate%>", v);
+      else if (TREE_TYPE (v) == error_mark_node)
+       ;
+      else if (! COMPLETE_TYPE_P (TREE_TYPE (v)))
+       error ("%<threadprivate%> %qE has incomplete type", v);
+      else
+       {
+         if (! DECL_THREAD_LOCAL_P (v))
+           {
+             DECL_TLS_MODEL (v) = decl_default_tls_model (v);
+             /* If rtl has been already set for this var, call
+                make_decl_rtl once again, so that encode_section_info
+                has a chance to look at the new decl flags.  */
+             if (DECL_RTL_SET_P (v))
+               make_decl_rtl (v);
+           }
+         C_DECL_THREADPRIVATE_P (v) = 1;
+       }
+    }
+
+  c_parser_skip_to_pragma_eol (parser);
+}
+
+\f
+/* Parse a single source file.  */
+
+void
+c_parse_file (void)
+{
+  /* Use local storage to begin.  If the first token is a pragma, parse it.
+     If it is #pragma GCC pch_preprocess, then this will load a PCH file
+     which will cause garbage collection.  */
+  c_parser tparser;
+
+  memset (&tparser, 0, sizeof tparser);
+  the_parser = &tparser;
+
+  if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS)
+    c_parser_pragma_pch_preprocess (&tparser);
+
+  the_parser = GGC_NEW (c_parser);
+  *the_parser = tparser;
+
+  c_parser_translation_unit (the_parser);
+  the_parser = NULL;
+}
+
+#include "gt-c-parser.h"