diff gcc/c-parser.c.orig @ 57:326d9e06c2e3

modify c-parser.c
author ryoma <e075725@ie.u-ryukyu.ac.jp>
date Mon, 15 Feb 2010 00:54:17 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/c-parser.c.orig	Mon Feb 15 00:54:17 2010 +0900
@@ -0,0 +1,9152 @@
+/* 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"
+#ifndef noCbC
+#include "cbc-tree.h"
+#endif
+#include "plugin.h"
+#include "except.h"
+
+
+/* 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;
+
+  /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in
+     the c_token structure.  */
+  gcc_assert (RID_MAX <= 255);
+
+  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;
+    }
+}
+
+/* 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,
+  /* An address space identifier.  */
+  C_ID_ADDRSPACE,
+  /* 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 GTY (()) c_token {
+  /* 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 GTY(()) c_parser {
+  /* 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 %qE conflicts with C++ keyword",
+                token->value);
+          }
+        else if (rid_code >= RID_FIRST_ADDR_SPACE
+             && rid_code <= RID_LAST_ADDR_SPACE)
+          {
+        token->id_kind = C_ID_ADDRSPACE;
+        token->keyword = rid_code;
+        break;
+          }
+        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_ADDRSPACE:
+      return true;
+    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_ADDRSPACE:
+      return true;
+    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:
+#ifndef noCbC
+    case RID_CbC_CODE:
+#endif
+      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),
+         /* ??? The C parser does not save the cpp flags of a
+            token, we need to pass 0 here and we will not get
+            the source spelling of some tokens but rather the
+            canonical spelling.  */
+         token->value, /*flags=*/0);
+}
+
+/* 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)
+         | (warn_cxx_compat << 5));
+  cpp_opts->pedantic = pedantic = 0;
+  warn_pointer_arith = 0;
+  cpp_opts->warn_traditional = warn_traditional = 0;
+  flag_iso = 0;
+  cpp_opts->warn_long_long = warn_long_long = 0;
+  warn_cxx_compat = 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;
+  cpp_opts->warn_long_long = warn_long_long = (flags >> 4) & 1;
+  warn_cxx_compat = (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_goto_operands (c_parser *);
+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 *,
+                                   location_t);
+static struct c_expr c_parser_postfix_expression_after_primary (c_parser *,
+                                location_t loc,
+                                struct c_expr);
+static struct c_expr c_parser_expression (c_parser *);
+static struct c_expr c_parser_expression_conv (c_parser *);
+static VEC(tree,gc) *c_parser_expr_list (c_parser *, bool, bool,
+                     VEC(tree,gc) **);
+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);
+      mark_valid_location_for_stdc_pragma (false);
+      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:
+      mark_valid_location_for_stdc_pragma (true);
+      c_parser_pragma (parser, pragma_external);
+      mark_valid_location_for_stdc_pragma (false);
+      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;
+          location_t init_loc;
+          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_loc = c_parser_peek_token (parser)->location;
+          init = c_parser_initializer (parser);
+          finish_init ();
+          if (d != error_mark_node)
+        {
+          maybe_warn_string_init (TREE_TYPE (d), init);
+          finish_decl (d, init_loc, init.value,
+                       init.original_type, asm_name);
+        }
+        }
+      else
+        {
+          tree d = start_decl (declarator, specs, false,
+                   chainon (postfix_attrs,
+                        all_prefix_attrs));
+          if (d)
+        finish_decl (d, UNKNOWN_LOCATION, NULL_TREE,
+                     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;
+      /* Mark nested functions as needing static-chain initially.
+         lower_nested_functions will recompute it but the
+         DECL_STATIC_CHAIN flag is also used before that happens,
+         by initializer_constant_valid_p.  See gcc.dg/nested-fn-2.c.  */
+      DECL_STATIC_CHAIN (decl) = 1;
+      add_stmt (fnbody);
+      finish_function ();
+      c_pop_function_context ();
+      add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), 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
+     address-space-qualifier
+
+   (restrict is new in C99.)
+
+   GNU extensions:
+
+   declaration-specifiers:
+     attributes declaration-specifiers[opt]
+
+   type-qualifier:
+     address-space
+
+   address-space:
+     identifier recognized by the target
+
+   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;
+      location_t loc = c_parser_peek_token (parser)->location;
+      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;
+
+      if (kind == C_ID_ADDRSPACE)
+        {
+          addr_space_t as
+        = c_parser_peek_token (parser)->keyword - RID_FIRST_ADDR_SPACE;
+          declspecs_add_addrspace (specs, as);
+          c_parser_consume_token (parser);
+          attrs_ok = true;
+          continue;
+        }
+
+      /* This finishes the specifiers unless a type name is OK, it
+         is declared as a type name and a type name hasn't yet
+         been seen.  */
+      if (!typespec_ok || seen_type
+          || (kind != C_ID_TYPENAME && kind != C_ID_CLASSNAME))
+        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);
+          t.expr = NULL_TREE;
+          t.expr_const_operands = true;
+        }
+      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);
+          t.expr = NULL_TREE;
+          t.expr_const_operands = true;
+        }
+      declspecs_add_type (loc, 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);
+      t.expr = NULL_TREE;
+      t.expr_const_operands = true;
+      declspecs_add_type (loc, 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;
+      t.expr = NULL_TREE;
+      t.expr_const_operands = true;
+      declspecs_add_type (loc, specs, t);
+      c_parser_consume_token (parser);
+      break;
+#ifndef noCbC
+    case RID_CbC_CODE:
+      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);
+
+      /*
+      attrs = get_identifier("fastcall");
+      attrs = build_tree_list(attrs, NULL_TREE);
+      declspecs_add_attrs(specs, attrs);
+      */
+      attrs = build_tree_list (get_identifier("fastcall"), NULL_TREE);
+      /*attrs = build_tree_list (get_identifier("noreturn"), attrs);*/
+      declspecs_add_attrs(specs, attrs);
+
+      c_parser_consume_token (parser);
+      break;
+#endif
+    case RID_ENUM:
+      if (!typespec_ok)
+        goto out;
+      attrs_ok = true;
+      seen_type = true;
+      t = c_parser_enum_specifier (parser);
+      declspecs_add_type (loc, 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);
+          invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec);
+      declspecs_add_type (loc, 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 (loc, 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 enum_loc;
+  location_t ident_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM));
+  enum_loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_token (parser);
+  attrs = c_parser_attributes (parser);
+  enum_loc = c_parser_peek_token (parser)->location;
+  /* 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;
+      enum_loc = ident_loc;
+      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 (enum_loc, &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 (value_loc,
+                        &the_enum, enum_id, enum_value);
+      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;
+      ret.expr = NULL_TREE;
+      ret.expr_const_operands = true;
+      return ret;
+    }
+  else if (!ident)
+    {
+      c_parser_error (parser, "expected %<{%>");
+      ret.spec = error_mark_node;
+      ret.kind = ctsk_tagref;
+      ret.expr = NULL_TREE;
+      ret.expr_const_operands = true;
+      return ret;
+    }
+  ret = parser_xref_tag (ident_loc, 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 (enum_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;
+  location_t struct_loc;
+  location_t ident_loc = UNKNOWN_LOCATION;
+  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 ();
+    }
+  struct_loc = c_parser_peek_token (parser)->location;
+  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;
+      struct_loc = ident_loc;
+      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.  */
+      struct c_struct_parse_info *struct_info;
+      tree type = start_struct (struct_loc, code, ident, &struct_info);
+      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 (struct_loc, type, nreverse (contents),
+                chainon (attrs, postfix_attrs), struct_info);
+      ret.kind = ctsk_tagdef;
+      ret.expr = NULL_TREE;
+      ret.expr_const_operands = true;
+      return ret;
+    }
+  else if (!ident)
+    {
+      c_parser_error (parser, "expected %<{%>");
+      ret.spec = error_mark_node;
+      ret.kind = ctsk_tagref;
+      ret.expr = NULL_TREE;
+      ret.expr_const_operands = true;
+      return ret;
+    }
+  ret = parser_xref_tag (ident_loc, 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;
+  ret.expr = NULL_TREE;
+  ret.expr_const_operands = true;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
+  c_parser_consume_token (parser);
+  c_inhibit_evaluation_warnings++;
+  in_typeof++;
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      c_inhibit_evaluation_warnings--;
+      in_typeof--;
+      return ret;
+    }
+  if (c_parser_next_token_starts_typename (parser))
+    {
+      struct c_type_name *type = c_parser_type_name (parser);
+      c_inhibit_evaluation_warnings--;
+      in_typeof--;
+      if (type != NULL)
+    {
+      ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands);
+      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);
+      c_inhibit_evaluation_warnings--;
+      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 is returned with the type so that when the type is
+     evaluated, this can be evaluated.  */
+      if (was_vm)
+    ret.expr = c_fully_fold (expr.value, false, &ret.expr_const_operands);
+      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))
+    {
+      location_t brace_loc = c_parser_peek_token (parser)->location;
+      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 (brace_loc, 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;
+      VEC(tree,gc) *expr_list;
+      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
+        {
+          tree tree_list;
+          c_parser_consume_token (parser);
+          expr_list = c_parser_expr_list (parser, false, true, NULL);
+          tree_list = build_tree_list_vec (expr_list);
+          attr_args = tree_cons (NULL_TREE, arg1, tree_list);
+          release_tree_vector (expr_list);
+        }
+        }
+      else
+        {
+          if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+        attr_args = NULL_TREE;
+          else
+        {
+          expr_list = c_parser_expr_list (parser, false, true, NULL);
+          attr_args = build_tree_list_vec (expr_list);
+          release_tree_vector (expr_list);
+        }
+        }
+      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;
+      location_t loc = c_parser_peek_token (parser)->location;
+      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 (loc, 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;
+      ret.original_type = NULL;
+      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;
+          init.original_type = NULL;
+          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;
+              location_t comma_loc, exp_loc;
+              comma_loc = c_parser_peek_token (parser)->location;
+              c_parser_consume_token (parser);
+              exp_loc = c_parser_peek_token (parser)->location;
+              next = c_parser_expr_no_commas (parser, NULL);
+              next = default_function_array_conversion (exp_loc, next);
+              rec = build_compound_expr (comma_loc, 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;
+          mexpr.original_type = NULL;
+          /* 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;
+          init.original_type = NULL;
+          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
+    {
+      location_t loc = c_parser_peek_token (parser)->location;
+      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 (loc, 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;
+  location_t brace_loc;
+  brace_loc = c_parser_peek_token (parser)->location;
+  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 (brace_loc, stmt, true);
+      return error_mark_node;
+    }
+  stmt = c_begin_compound_stmt (true);
+  c_parser_compound_statement_nostart (parser);
+  return c_end_compound_stmt (brace_loc, 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;
+  bool save_valid_for_pragma = valid_location_for_stdc_pragma_p ();
+  location_t label_loc = UNKNOWN_LOCATION;  /* Quiet warning.  */
+  if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+    {
+      c_parser_consume_token (parser);
+      return;
+    }
+  mark_valid_location_for_stdc_pragma (true);
+  if (c_parser_next_token_is_keyword (parser, RID_LABEL))
+    {
+      /* Read zero or more forward-declarations for labels that nested
+     functions can jump to.  */
+      mark_valid_location_for_stdc_pragma (false);
+      while (c_parser_next_token_is_keyword (parser, RID_LABEL))
+    {
+      label_loc = c_parser_peek_token (parser)->location;
+      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 (label_loc, 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 (label_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))
+    {
+      mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
+      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;
+      mark_valid_location_for_stdc_pragma (false);
+      c_parser_label (parser);
+    }
+      else if (!last_label
+           && c_parser_next_token_starts_declspecs (parser))
+    {
+      last_label = false;
+      mark_valid_location_for_stdc_pragma (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;
+          mark_valid_location_for_stdc_pragma (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))
+    {
+      mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
+      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)
+            {
+          mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
+              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;
+      mark_valid_location_for_stdc_pragma (false);
+      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);
+  /* Restore the value we started with.  */
+  mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
+}
+
+/* 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 (loc1, 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 (loc1, 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 (loc1, 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 (loc1, LABEL_EXPR, tlab));
+    }
+    }
+  if (label)
+    {
+      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);
+}
+
+#if 0
+static tree
+c_parser_cbc_make_env(c_parser *parser)
+{
+  struct c_expr env;
+  tree field, fields=NULL_TREE;
+  tree env_struct, env_struct_type;
+  tree ebp, argsp;
+  tree tmp;
+
+  c_parser_consume_token (parser);
+  env = c_parser_expr_no_commas (parser, NULL);
+  env = default_function_array_conversion (env);
+
+    /* build type_node of environment structure  */
+    env_struct_type = start_struct (RECORD_TYPE, NULL_TREE);
+    field = build_decl (FIELD_DECL, get_identifier("sp"), ptr_type_node);
+    fields = chainon (field, fields);
+    field = build_decl (FIELD_DECL, get_identifier("argsp"), ptr_type_node);
+    fields = chainon (field, fields);
+    //field = build_decl (FIELD_DECL, get_identifier("retval"), intSI_type_node);
+    //fields = chainon (field, fields);
+    fields = nreverse(fields);
+    finish_struct (env_struct_type, fields, NULL_TREE);
+
+    env_struct = build_c_cast (build_pointer_type(env_struct_type), env.value);
+    //build_component_ref (cbc_env, get_identifier("argsp"));
+    ebp = build_component_ref (build_indirect_ref (loc,env_struct, "CbCenv->sp"), get_identifier("sp"));
+    argsp = build_component_ref (build_indirect_ref (loc, env_struct, "CbCenv->sp"), get_identifier("argsp"));
+    //ebp = chainon (ebp, argsp);
+    tmp = build_tree_list (ebp, argsp);
+
+    return tmp;
+}
+#endif
+
+static tree
+cbc_replace_arguments (location_t loc, tree call)
+{
+  tree args;
+  tree fn;
+  tree tmp_decl;
+  int i=0;
+
+  fn = CALL_EXPR_FN (call);
+  if ( TREE_CODE (fn)==PARM_DECL || !TREE_CONSTANT (fn) )
+    {
+      tmp_decl = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE(fn));
+      pushdecl (tmp_decl);
+
+      add_stmt (build_modify_expr (loc, tmp_decl, NOP_EXPR, fn));
+      CALL_EXPR_FN (call) = tmp_decl;
+    }
+
+  args = CALL_EXPR_ARGS (call);
+  for ( ;args; args = TREE_CHAIN (args), i++)
+    {
+      tree arg = TREE_VALUE (args);
+
+      //if ( !CONSTANT_CLASS_P (arg) && !VAR_OR_FUNCTION_DECL_P (arg) )
+      if ( TREE_CODE (arg)==PARM_DECL || !TREE_CONSTANT (arg) )
+    {
+      tmp_decl = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE(arg));
+      pushdecl (tmp_decl);
+
+      add_stmt (build_modify_expr (loc, tmp_decl, NOP_EXPR, arg));
+      CALL_EXPR_ARG (call, i) = tmp_decl;
+    }
+    }
+
+  return call;
+}
+
+/* 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);
+#ifndef noCbC
+      if ( c_parser_next_token_is (parser, CPP_NAME)
+           && c_parser_peek_2nd_token (parser)->type == CPP_SEMICOLON )
+        {
+#else
+      if (c_parser_next_token_is (parser, CPP_NAME))
+        {
+#endif
+          stmt = c_finish_goto_label (loc,
+                      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 (loc,
+                    c_parser_expression (parser).value);
+        }
+      else
+#ifndef noCbC
+        {
+          struct c_expr expr;
+          if (c_parser_next_token_is (parser, CPP_NAME))
+        {
+          tree id = c_parser_peek_token (parser)->value;
+                  location_t loc = c_parser_peek_token (parser)->location;
+          build_external_ref (id,RID_CbC_CODE , loc);
+        }
+          expr = c_parser_expr_no_commas (parser, NULL);
+          if (TREE_CODE(expr.value) == CALL_EXPR )
+        {
+          location_t loc = c_parser_peek_token (parser)->location;
+          cbc_replace_arguments (loc, expr.value);
+
+          TREE_TYPE(expr.value) = void_type_node;
+          /*tree env = NULL_TREE;**/
+          CbC_IS_CbC_GOTO (expr.value) = 1;
+          CALL_EXPR_TAILCALL (expr.value) = 1;
+          add_stmt(expr.value);
+          stmt = c_finish_return (0);
+        }
+          else
+        c_parser_error (parser, "expected code segment jump or %<*%>");
+        }
+#else
+        c_parser_error (parser, "expected identifier or %<*%>");
+#endif
+      goto expect_semicolon;
+    case RID_CONTINUE:
+      c_parser_consume_token (parser);
+      stmt = c_finish_bc_stmt (loc, &c_cont_label, false);
+      goto expect_semicolon;
+    case RID_BREAK:
+      c_parser_consume_token (parser);
+      stmt = c_finish_bc_stmt (loc, &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 (loc, NULL_TREE, NULL_TREE);
+          c_parser_consume_token (parser);
+        }
+      else
+        {
+          struct c_expr expr = c_parser_expression_conv (parser);
+          stmt = c_finish_return (loc, expr.value, expr.original_type);
+          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 (loc, NULL_TREE);
+          c_parser_consume_token (parser);
+        }
+      else
+        {
+          tree expr = c_parser_expression (parser).value;
+          expr = c_fully_fold (expr, false, NULL);
+          stmt = objc_build_throw_stmt (loc, expr);
+          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 (loc, 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?  */
+  if (CAN_HAVE_LOCATION_P (stmt)
+      && EXPR_LOCATION (stmt) == UNKNOWN_LOCATION)
+    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 = c_parser_peek_token (parser)->location;
+  tree cond;
+  cond = c_parser_expression_conv (parser).value;
+  cond = c_objc_common_truthvalue_conversion (loc, cond);
+  cond = c_fully_fold (cond, false, NULL);
+  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);
+  location_t loc = c_parser_peek_token (parser)->location;
+  c_parser_statement (parser);
+  return c_end_compound_stmt (loc, 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);
+  location_t body_loc = c_parser_peek_token (parser)->location;
+  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 (loc));
+      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 (body_loc, 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)
+{
+  location_t else_loc = c_parser_peek_token (parser)->location;
+  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))
+    {
+      location_t loc = c_parser_peek_token (parser)->location;
+      warning_at (loc,
+          OPT_Wempty_body,
+             "suggest braces around empty body in an %<else%> statement");
+      add_stmt (build_empty_stmt (loc));
+      c_parser_consume_token (parser);
+    }
+  else
+    c_parser_statement_after_labels (parser);
+  return c_end_compound_stmt (else_loc, 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 (loc, 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;
+  location_t switch_loc = c_parser_peek_token (parser)->location;
+  location_t switch_cond_loc;
+  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 %<(%>"))
+    {
+      switch_cond_loc = c_parser_peek_token (parser)->location;
+      expr = c_parser_expression (parser).value;
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+    }
+  else
+    {
+      switch_cond_loc = UNKNOWN_LOCATION;
+      expr = error_mark_node;
+    }
+  c_start_case (switch_loc, switch_cond_loc, 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)
+    {
+      location_t here = c_parser_peek_token (parser)->location;
+      tree t = build1 (LABEL_EXPR, void_type_node, c_break_label);
+      SET_EXPR_LOCATION (t, here);
+      add_stmt (t);
+    }
+  c_break_label = save_break;
+  add_stmt (c_end_compound_stmt (switch_loc, 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 (loc, 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 (loc, 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 = c_parser_peek_token (parser)->location;
+  location_t for_loc = c_parser_peek_token (parser)->location;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR));
+  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 (loc, 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 (for_loc);
+    }
+      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 (for_loc);
+        }
+      else
+        goto init_expr;
+    }
+      else
+    {
+    init_expr:
+      c_finish_expr_stmt (loc, 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 (loc, NULL_TREE);
+      else
+    incr = c_process_expr_stmt (loc, 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 (loc, 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 type-qualifier[opt] goto ( asm-goto-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[opt]
+
+   asm-goto-argument:
+     asm-string-literal : : asm-operands[opt] : asm-clobbers[opt] \
+       : asm-goto-operands
+
+   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, labels, ret;
+  bool simple, is_goto;
+  location_t asm_loc = c_parser_peek_token (parser)->location;
+  int section, nsections;
+
+  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;
+
+  is_goto = false;
+  if (c_parser_next_token_is_keyword (parser, RID_GOTO))
+    {
+      c_parser_consume_token (parser);
+      is_goto = true;
+    }
+
+  /* ??? Follow the C++ parser rather than using the
+     lex_untranslated_string kludge.  */
+  parser->lex_untranslated_string = true;
+  ret = NULL;
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    goto error;
+
+  str = c_parser_asm_string_literal (parser);
+  if (str == NULL_TREE)
+    goto error_close_paren;
+
+  simple = true;
+  outputs = NULL_TREE;
+  inputs = NULL_TREE;
+  clobbers = NULL_TREE;
+  labels = NULL_TREE;
+
+  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto)
+    goto done_asm;
+
+  /* Parse each colon-delimited section of operands.  */
+  nsections = 3 + is_goto;
+  for (section = 0; section < nsections; ++section)
+    {
+      if (!c_parser_require (parser, CPP_COLON,
+                 is_goto
+                 ? "expected %<:%>"
+                 : "expected %<:%> or %<)%>"))
+    goto error_close_paren;
+
+      /* Once past any colon, we're no longer a simple asm.  */
+      simple = false;
+
+      if ((!c_parser_next_token_is (parser, CPP_COLON)
+       && !c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+      || section == 3)
+    switch (section)
+      {
+      case 0:
+        /* For asm goto, we don't allow output operands, but reserve
+           the slot for a future extension that does allow them.  */
+        if (!is_goto)
+          outputs = c_parser_asm_operands (parser, false);
+        break;
+      case 1:
+        inputs = c_parser_asm_operands (parser, true);
+        break;
+      case 2:
+        clobbers = c_parser_asm_clobbers (parser);
+        break;
+      case 3:
+        labels = c_parser_asm_goto_operands (parser);
+        break;
+      default:
+        gcc_unreachable ();
+      }
+
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto)
+    goto done_asm;
+    }
+
+ done_asm:
+  if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+    {
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      goto error;
+    }
+
+  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 (asm_loc, str, outputs, inputs,
+                           clobbers, labels, simple));
+
+ error:
+  parser->lex_untranslated_string = false;
+  return ret;
+
+ error_close_paren:
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+  goto error;
+}
+
+/* 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;
+  location_t loc;
+  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;
+    }
+      loc = c_parser_peek_token (parser)->location;
+      expr = c_parser_expression (parser);
+      if (convert_p)
+    expr = default_function_array_conversion (loc, expr);
+      expr.value = c_fully_fold (expr.value, false, NULL);
+      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 asm goto labels, a GNU extension.
+
+   asm-goto-operands:
+     identifier
+     asm-goto-operands , identifier
+*/
+
+static tree
+c_parser_asm_goto_operands (c_parser *parser)
+{
+  tree list = NULL_TREE;
+  while (true)
+    {
+      tree name, label;
+
+      if (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      c_token *tok = c_parser_peek_token (parser);
+      name = tok->value;
+      label = lookup_label_for_goto (tok->location, name);
+      c_parser_consume_token (parser);
+      TREE_USED (label) = 1;
+    }
+      else
+    {
+      c_parser_error (parser, "expected identifier");
+      return NULL_TREE;
+    }
+
+      name = build_string (IDENTIFIER_LENGTH (name),
+               IDENTIFIER_POINTER (name));
+      list = tree_cons (name, label, list);
+      if (c_parser_next_token_is (parser, CPP_COMMA))
+    c_parser_consume_token (parser);
+      else
+    return nreverse (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, exp_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);
+  exp_location = c_parser_peek_token (parser)->location;
+  rhs = c_parser_expr_no_commas (parser, NULL);
+  rhs = default_function_array_conversion (exp_location, rhs);
+  ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type,
+                 code, exp_location, rhs.value,
+                 rhs.original_type);
+  if (code == NOP_EXPR)
+    ret.original_code = MODIFY_EXPR;
+  else
+    {
+      TREE_NO_WARNING (ret.value) = 1;
+      ret.original_code = ERROR_MARK;
+    }
+  ret.original_type = NULL;
+  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, colon_loc;
+
+  gcc_assert (!after || c_dialect_objc ());
+
+  cond = c_parser_binary_expression (parser, after);
+
+  if (c_parser_next_token_is_not (parser, CPP_QUERY))
+    return cond;
+  cond_loc = c_parser_peek_token (parser)->location;
+  cond = default_function_array_conversion (cond_loc, cond);
+  c_parser_consume_token (parser);
+  if (c_parser_next_token_is (parser, CPP_COLON))
+    {
+      tree eptype = NULL_TREE;
+      pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
+           "ISO C forbids omitting the middle term of a ?: expression");
+      if (TREE_CODE (cond.value) == EXCESS_PRECISION_EXPR)
+    {
+      eptype = TREE_TYPE (cond.value);
+      cond.value = TREE_OPERAND (cond.value, 0);
+    }
+      /* Make sure first operand is calculated only once.  */
+      exp1.value = c_save_expr (default_conversion (cond.value));
+      if (eptype)
+    exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value);
+      exp1.original_type = NULL;
+      cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value);
+      c_inhibit_evaluation_warnings += cond.value == truthvalue_true_node;
+    }
+  else
+    {
+      cond.value
+    = c_objc_common_truthvalue_conversion
+    (cond_loc, default_conversion (cond.value));
+      c_inhibit_evaluation_warnings += cond.value == truthvalue_false_node;
+      exp1 = c_parser_expression_conv (parser);
+      c_inhibit_evaluation_warnings +=
+    ((cond.value == truthvalue_true_node)
+     - (cond.value == truthvalue_false_node));
+    }
+
+  colon_loc = c_parser_peek_token (parser)->location;
+  if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+    {
+      c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
+      ret.value = error_mark_node;
+      ret.original_code = ERROR_MARK;
+      ret.original_type = NULL;
+      return ret;
+    }
+  {
+    location_t exp2_loc = c_parser_peek_token (parser)->location;
+    exp2 = c_parser_conditional_expression (parser, NULL);
+    exp2 = default_function_array_conversion (exp2_loc, exp2);
+  }
+  c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
+  ret.value = build_conditional_expr (colon_loc, cond.value,
+                      cond.original_code == C_MAYBE_CONST_EXPR,
+                      exp1.value, exp1.original_type,
+                      exp2.value, exp2.original_type);
+  ret.original_code = ERROR_MARK;
+  if (exp1.value == error_mark_node || exp2.value == error_mark_node)
+    ret.original_type = NULL;
+  else
+    {
+      tree t1, t2;
+
+      /* If both sides are enum type, the default conversion will have
+     made the type of the result be an integer type.  We want to
+     remember the enum types we started with.  */
+      t1 = exp1.original_type ? exp1.original_type : TREE_TYPE (exp1.value);
+      t2 = exp2.original_type ? exp2.original_type : TREE_TYPE (exp2.value);
+      ret.original_type = ((t1 != error_mark_node
+                && t2 != error_mark_node
+                && (TYPE_MAIN_VARIANT (t1)
+                == TYPE_MAIN_VARIANT (t2)))
+               ? t1
+               : NULL);
+    }
+  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 c_inhibit_evaluation_warnings
+     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;
+    /* The source location of this operation.  */
+    location_t loc;
+  } 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:                              \
+    c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value        \
+                      == truthvalue_false_node);          \
+    break;                                    \
+      case TRUTH_ORIF_EXPR:                           \
+    c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value        \
+                      == truthvalue_true_node);       \
+    break;                                    \
+      default:                                    \
+    break;                                    \
+      }                                       \
+    stack[sp - 1].expr                                \
+      = default_function_array_conversion (stack[sp - 1].loc,             \
+                       stack[sp - 1].expr);           \
+    stack[sp].expr                                \
+      = default_function_array_conversion (stack[sp].loc, stack[sp].expr);    \
+    stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc,           \
+                         stack[sp].op,            \
+                         stack[sp - 1].expr,          \
+                         stack[sp].expr);         \
+    sp--;                                     \
+  } while (0)
+  gcc_assert (!after || c_dialect_objc ());
+  stack[0].loc = c_parser_peek_token (parser)->location;
+  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].loc,
+                         stack[sp].expr);
+      stack[sp].expr.value = c_objc_common_truthvalue_conversion
+        (stack[sp].loc, default_conversion (stack[sp].expr.value));
+      c_inhibit_evaluation_warnings += (stack[sp].expr.value
+                        == truthvalue_false_node);
+      break;
+    case TRUTH_ORIF_EXPR:
+      stack[sp].expr
+        = default_function_array_conversion (stack[sp].loc,
+                         stack[sp].expr);
+      stack[sp].expr.value = c_objc_common_truthvalue_conversion
+        (stack[sp].loc, default_conversion (stack[sp].expr.value));
+      c_inhibit_evaluation_warnings += (stack[sp].expr.value
+                        == truthvalue_true_node);
+      break;
+    default:
+      break;
+    }
+      sp++;
+      stack[sp].loc = binary_loc;
+      stack[sp].expr = c_parser_cast_expression (parser, NULL);
+      stack[sp].prec = oprec;
+      stack[sp].op = ocode;
+      stack[sp].loc = binary_loc;
+    }
+ 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)
+{
+  location_t cast_loc = c_parser_peek_token (parser)->location;
+  gcc_assert (!after || c_dialect_objc ());
+  if (after)
+    return c_parser_postfix_expression_after_primary (parser,
+                              cast_loc, *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;
+      ret.original_type = NULL;
+      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,
+                                 cast_loc);
+      {
+    location_t expr_loc = c_parser_peek_token (parser)->location;
+    expr = c_parser_cast_expression (parser, NULL);
+    expr = default_function_array_conversion (expr_loc, expr);
+      }
+      ret.value = c_cast_expr (cast_loc, type_name, expr.value);
+      ret.original_code = ERROR_MARK;
+      ret.original_type = NULL;
+      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 op_loc = c_parser_peek_token (parser)->location;
+  location_t exp_loc;
+  ret.original_code = ERROR_MARK;
+  ret.original_type = NULL;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_PLUS_PLUS:
+      c_parser_consume_token (parser);
+      exp_loc = c_parser_peek_token (parser)->location;
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (exp_loc, op);
+      return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op);
+    case CPP_MINUS_MINUS:
+      c_parser_consume_token (parser);
+      exp_loc = c_parser_peek_token (parser)->location;
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (exp_loc, op);
+      return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op);
+    case CPP_AND:
+      c_parser_consume_token (parser);
+      return parser_build_unary_op (op_loc, ADDR_EXPR,
+                    c_parser_cast_expression (parser, NULL));
+    case CPP_MULT:
+      c_parser_consume_token (parser);
+      exp_loc = c_parser_peek_token (parser)->location;
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (exp_loc, op);
+      ret.value = build_indirect_ref (op_loc, op.value, RO_UNARY_STAR);
+      return ret;
+    case CPP_PLUS:
+      if (!c_dialect_objc () && !in_system_header)
+    warning_at (op_loc,
+            OPT_Wtraditional,
+            "traditional C rejects the unary plus operator");
+      c_parser_consume_token (parser);
+      exp_loc = c_parser_peek_token (parser)->location;
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (exp_loc, op);
+      return parser_build_unary_op (op_loc, CONVERT_EXPR, op);
+    case CPP_MINUS:
+      c_parser_consume_token (parser);
+      exp_loc = c_parser_peek_token (parser)->location;
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (exp_loc, op);
+      return parser_build_unary_op (op_loc, NEGATE_EXPR, op);
+    case CPP_COMPL:
+      c_parser_consume_token (parser);
+      exp_loc = c_parser_peek_token (parser)->location;
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (exp_loc, op);
+      return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op);
+    case CPP_NOT:
+      c_parser_consume_token (parser);
+      exp_loc = c_parser_peek_token (parser)->location;
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (exp_loc, op);
+      return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op);
+    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, op_loc);
+      c_parser_consume_token (parser);
+    }
+      else
+    {
+      c_parser_error (parser, "expected identifier");
+      ret.value = error_mark_node;
+    }
+    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);
+      exp_loc = c_parser_peek_token (parser)->location;
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (exp_loc, op);
+      return parser_build_unary_op (op_loc, REALPART_EXPR, op);
+    case RID_IMAGPART:
+      c_parser_consume_token (parser);
+      exp_loc = c_parser_peek_token (parser)->location;
+      op = c_parser_cast_expression (parser, NULL);
+      op = default_function_array_conversion (exp_loc, op);
+      return parser_build_unary_op (op_loc, IMAGPART_EXPR, op);
+    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);
+  c_inhibit_evaluation_warnings++;
+  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;
+      c_inhibit_evaluation_warnings--;
+      in_sizeof--;
+      ret.value = error_mark_node;
+      ret.original_code = ERROR_MARK;
+      ret.original_type = NULL;
+      return ret;
+    }
+      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    {
+      expr = c_parser_postfix_expression_after_paren_type (parser,
+                                   type_name,
+                                   expr_loc);
+      goto sizeof_expr;
+    }
+      /* sizeof ( type-name ).  */
+      c_inhibit_evaluation_warnings--;
+      in_sizeof--;
+      return c_expr_sizeof_type (expr_loc, type_name);
+    }
+  else
+    {
+      expr_loc = c_parser_peek_token (parser)->location;
+      expr = c_parser_unary_expression (parser);
+    sizeof_expr:
+      c_inhibit_evaluation_warnings--;
+      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_loc, expr);
+    }
+}
+
+/* Parse an alignof expression.  */
+
+static struct c_expr
+c_parser_alignof_expression (c_parser *parser)
+{
+  struct c_expr expr;
+  location_t loc = c_parser_peek_token (parser)->location;
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF));
+  c_parser_consume_token (parser);
+  c_inhibit_evaluation_warnings++;
+  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.  */
+      location_t loc;
+      struct c_type_name *type_name;
+      struct c_expr ret;
+      c_parser_consume_token (parser);
+      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;
+      c_inhibit_evaluation_warnings--;
+      in_alignof--;
+      ret.value = error_mark_node;
+      ret.original_code = ERROR_MARK;
+      ret.original_type = NULL;
+      return ret;
+    }
+      if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+    {
+      expr = c_parser_postfix_expression_after_paren_type (parser,
+                                   type_name,
+                                   loc);
+      goto alignof_expr;
+    }
+      /* alignof ( type-name ).  */
+      c_inhibit_evaluation_warnings--;
+      in_alignof--;
+      ret.value = c_alignof (loc, groktypename (type_name, NULL, NULL));
+      ret.original_code = ERROR_MARK;
+      ret.original_type = NULL;
+      return ret;
+    }
+  else
+    {
+      struct c_expr ret;
+      expr = c_parser_unary_expression (parser);
+    alignof_expr:
+      c_inhibit_evaluation_warnings--;
+      in_alignof--;
+      ret.value = c_alignof_expr (loc, expr.value);
+      ret.original_code = ERROR_MARK;
+      ret.original_type = NULL;
+      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 void
+cbc_finish_labeled_goto (location_t loc, tree label, tree retval)
+{
+  /* add statement below.
+   *
+   * if (0) {
+   *   _cbc_exit0:
+   *   return retval;
+   * }
+   */
+  tree tlab;
+  tree cond;
+
+  tree cstmt = c_begin_compound_stmt (true);
+
+  tlab = define_label (loc, label);
+  gcc_assert (tlab);
+  decl_attributes (&tlab, NULL_TREE, 0);
+  add_stmt (build_stmt (LABEL_EXPR, tlab));
+
+  tree ret = c_finish_return (retval);
+  TREE_USED(ret) = 1;
+
+  cond = integer_zero_node;
+  tree if_body = c_end_compound_stmt (cstmt, true);
+  TREE_SIDE_EFFECTS (cstmt) = 1;
+  c_finish_if_stmt (loc, cond, if_body, NULL_TREE, false);
+}
+
+static tree
+cbc_finish_nested_function (location_t loc, tree label, tree retval_decl)
+{
+
+  /* add statement below.
+   * void __return_func(int _retval, void *_envp){
+   *   retval = _retval;
+   *   goto exit0;
+   * }
+   */
+  /* TODO:
+   * retval(lhs)のTREE_DECLを引数から取得するように
+   * int _retvalパラメータのタイプはretvalに合わせる
+   */
+
+  tree fnbody;
+  tree _retval_decl, _envp_decl;
+  struct c_declarator *declarator;
+  tree ident;
+  struct c_arg_info *args;
+  struct c_declspecs *specs;
+  struct c_typespec t;
+  {
+    push_scope ();
+    declare_parm_level ();
+    /*tree retval_type = TREE_TYPE(retval_decl);*/
+
+    _retval_decl = build_decl (PARM_DECL, get_identifier ("_retval"), TREE_TYPE(retval_decl));
+    DECL_SOURCE_LOCATION (_retval_decl) = loc;
+    DECL_ARTIFICIAL (_retval_decl) = 1;
+    DECL_ARG_TYPE (_retval_decl) = TREE_TYPE(retval_decl);
+    pushdecl (_retval_decl);
+    finish_decl (_retval_decl, NULL_TREE, NULL_TREE);
+
+    _envp_decl = build_decl (PARM_DECL, get_identifier ("_envp"), ptr_type_node);
+    DECL_SOURCE_LOCATION (_envp_decl) = loc;
+    DECL_ARTIFICIAL (_envp_decl) = 1;
+    DECL_ARG_TYPE (_envp_decl) = ptr_type_node;
+    pushdecl (_envp_decl);
+    finish_decl (_envp_decl, NULL_TREE, NULL_TREE);
+
+    args = get_parm_info(false);
+    pop_scope();
+  }
+
+  t.kind = ctsk_resword;
+  t.spec = get_identifier("void");
+  specs = build_null_declspecs();
+  declspecs_add_type (specs, t);
+  finish_declspecs (specs);
+
+  /* make nested function.  */
+  declarator = build_id_declarator (get_identifier ("_cbc_internal_return"));
+  declarator = build_function_declarator (args, declarator);
+
+  c_push_function_context ();
+
+  if (!start_function (specs, declarator, NULL_TREE))
+    {
+      c_pop_function_context();
+      gcc_assert (0);
+    }
+  store_parm_decls ();
+
+
+  /* start compound statement.  */
+  tree cstmt = c_begin_compound_stmt (true);
+
+  add_stmt (build_modify_expr (loc, retval_decl, NOP_EXPR, _retval_decl));
+  tree stmt = c_finish_goto_label (label);
+
+  /* end compound statement.  */
+  fnbody = c_end_compound_stmt (cstmt, true);
+  TREE_SIDE_EFFECTS (cstmt) = 1;
+
+  /* finish declaration of nested function.  */
+  tree decl = current_function_decl;
+  add_stmt (fnbody);
+  finish_function ();
+  c_pop_function_context ();
+
+  add_stmt (build_stmt (DECL_EXPR, decl));
+  return decl;
+
+}
+
+static struct c_expr
+c_parser_postfix_expression (c_parser *parser)
+{
+  struct c_expr expr, e1, e2, e3;
+  struct c_type_name *t1, *t2;
+  //cbc? static tree return_label1;
+  location_t loc = c_parser_peek_token (parser)->location;;
+  expr.original_code = ERROR_MARK;
+  expr.original_type = NULL;
+  switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_NUMBER:
+      expr.value = c_parser_peek_token (parser)->value;
+      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;
+      c_parser_consume_token (parser);
+      break;
+    case CPP_STRING:
+    case CPP_STRING16:
+    case CPP_STRING32:
+    case CPP_WSTRING:
+    case CPP_UTF8STRING:
+      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);
+      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;
+      break;
+    }
+      {
+    tree id = c_parser_peek_token (parser)->value;
+    c_parser_consume_token (parser);
+    expr.value = build_external_ref (loc, id,
+                     (c_parser_peek_token (parser)->type
+                      == CPP_OPEN_PAREN),
+                     &expr.original_type);
+      }
+      break;
+    case CPP_OPEN_PAREN:
+      /* A parenthesized expression, statement expression or compound
+     literal.  */
+      if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE)
+    {
+      /* A statement expression.  */
+      tree stmt;
+      location_t brace_loc;
+      c_parser_consume_token (parser);
+      brace_loc = c_parser_peek_token (parser)->location;
+      c_parser_consume_token (parser);
+      if (cur_stmt_list == NULL)
+        {
+          error_at (loc, "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;
+          break;
+        }
+      stmt = c_begin_stmt_expr ();
+      c_parser_compound_statement_nostart (parser);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                     "expected %<)%>");
+      pedwarn (loc, OPT_pedantic,
+           "ISO C forbids braced-groups within expressions");
+      expr.value = c_finish_stmt_expr (brace_loc, stmt);
+    }
+      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?  */
+      location_t loc;
+      struct c_type_name *type_name;
+      c_parser_consume_token (parser);
+      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)
+        {
+          expr.value = error_mark_node;
+        }
+      else
+        expr = c_parser_postfix_expression_after_paren_type (parser,
+                                 type_name,
+                                 loc);
+    }
+      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;
+      if (expr.original_code != C_MAYBE_CONST_EXPR)
+        expr.original_code = ERROR_MARK;
+      /* Don't change EXPR.ORIGINAL_TYPE.  */
+      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 (loc,
+                   c_parser_peek_token (parser)->keyword,
+                   c_parser_peek_token (parser)->value);
+      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;
+          break;
+        }
+      e1 = c_parser_expr_no_commas (parser, NULL);
+      e1.value = c_fully_fold (e1.value, false, NULL);
+      if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+        {
+          c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+          expr.value = error_mark_node;
+          break;
+        }
+      loc = c_parser_peek_token (parser)->location;
+      t1 = c_parser_type_name (parser);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                     "expected %<)%>");
+      if (t1 == NULL)
+        {
+          expr.value = error_mark_node;
+        }
+      else
+        {
+          tree type_expr = NULL_TREE;
+          expr.value = c_build_va_arg (loc, e1.value,
+                       groktypename (t1, &type_expr, NULL));
+          if (type_expr)
+        {
+          expr.value = build2 (C_MAYBE_CONST_EXPR,
+                       TREE_TYPE (expr.value), type_expr,
+                       expr.value);
+          C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true;
+        }
+        }
+      break;
+    case RID_OFFSETOF:
+      c_parser_consume_token (parser);
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+        {
+          expr.value = error_mark_node;
+          break;
+        }
+      t1 = c_parser_type_name (parser);
+      if (t1 == NULL)
+        {
+          expr.value = error_mark_node;
+          break;
+        }
+      if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+        {
+          c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+          expr.value = error_mark_node;
+          break;
+        }
+      {
+        tree type = groktypename (t1, NULL, NULL);
+        tree offsetof_ref;
+        if (type == error_mark_node)
+          offsetof_ref = error_mark_node;
+        else
+          {
+        offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node);
+        SET_EXPR_LOCATION (offsetof_ref, loc);
+          }
+        /* 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
+          (loc, 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 (loc,
+                            offsetof_ref,
+                            integer_zero_node);
+            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
+              (loc, 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;
+            idx = c_fully_fold (idx, false, NULL);
+            c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+                           "expected %<]%>");
+            offsetof_ref = build_array_ref (loc, offsetof_ref, idx);
+              }
+          }
+          }
+        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);
+      }
+      break;
+    case RID_CHOOSE_EXPR:
+      c_parser_consume_token (parser);
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+        {
+          expr.value = error_mark_node;
+          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;
+          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;
+          break;
+        }
+      e3 = c_parser_expr_no_commas (parser, NULL);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                     "expected %<)%>");
+      {
+        tree c;
+
+        c = e1.value;
+        if (TREE_CODE (c) != INTEGER_CST
+        || !INTEGRAL_TYPE_P (TREE_TYPE (c)))
+          error_at (loc,
+            "first argument to %<__builtin_choose_expr%> not"
+            " a constant");
+        constant_expression_warning (c);
+        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;
+          break;
+        }
+      t1 = c_parser_type_name (parser);
+      if (t1 == NULL)
+        {
+          expr.value = error_mark_node;
+          break;
+        }
+      if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+        {
+          c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+          expr.value = error_mark_node;
+          break;
+        }
+      t2 = c_parser_type_name (parser);
+      if (t2 == NULL)
+        {
+          expr.value = error_mark_node;
+          break;
+        }
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                     "expected %<)%>");
+      {
+        tree e1, e2;
+
+        e1 = TYPE_MAIN_VARIANT (groktypename (t1, NULL, NULL));
+        e2 = TYPE_MAIN_VARIANT (groktypename (t2, NULL, NULL));
+
+        expr.value = comptypes (e1, e2)
+          ? build_int_cst (NULL_TREE, 1)
+          : build_int_cst (NULL_TREE, 0);
+      }
+      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;
+          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 (loc, sel);
+      }
+      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;
+          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;
+          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);
+      }
+      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;
+          break;
+        }
+      t1 = c_parser_type_name (parser);
+      if (t1 == NULL)
+        {
+          expr.value = error_mark_node;
+          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, NULL, NULL);
+        expr.value = objc_build_encode_expr (type);
+      }
+      break;
+#ifndef noCbC
+    case RID_CbC_ENV:
+          {
+        c_parser_consume_token (parser);
+        /* get value of %ebp.  */
+        tree env_tree = build_external_ref (
+                get_identifier ("__builtin_frame_address"), 0,
+            c_parser_peek_token (parser)->location);
+        expr.value = build_function_call(env_tree,
+               build_tree_list (NULL_TREE, build_int_cst (NULL_TREE,0)));
+        expr.original_code = ERROR_MARK;
+
+          }
+      break;
+    case RID_CbC_RET:
+    case RID_RETURN:
+
+#if 0
+      if (cbc_return_f==0)
+        {  tree retval;
+
+              /*
+                   Generates something like...
+
+    int retval = 1;
+    void (*ret)(int retval_,void *fp) ;
+
+    ret = ({
+        __label__ exit0;
+        volatile static flag = 0;
+        void __return_func(int retval_,void *fp) {
+            retval = retval_;
+            goto exit0;
+        }
+        if (flag) {
+        exit0:
+            printf("f1: fp = 0x%x\n",__builtin_frame_address(0));
+            return retval;
+        }
+        __return_func;
+    });
+
+               */
+
+          tree stmt = c_begin_stmt_expr ();
+              cbc_return_f = c_parser_peek_token (parser)->value;
+              cbc_return = c_parser_peek_token (parser)->location;
+          c_parser_consume_token (parser);
+              location_t next = c_parser_peek_token (parser)->location;
+
+              // dummy variable for hidden condition
+          struct c_expr cexpr;
+          tree cond;
+          location_t loc;
+          loc = next;
+              tree decl_cond =
+            build_decl (VAR_DECL, get_identifier ("__return"),
+            intHI_type_node);
+              TREE_STATIC (decl_cond) = 1;
+          cexpr.value = lang_hooks.decls.pushdecl(decl_cond);
+
+          cexpr.original_code = ERROR_MARK;
+          cond = c_objc_common_truthvalue_conversion(loc, cexpr.value);
+          if (EXPR_P (cond))
+        SET_EXPR_LOCATION (cond, loc);
+
+
+
+
+          tree fwlabel = create_artificial_label ();
+          //TREE_USED(fwlabel) = 1;
+
+          //add_stmt (build1 (GOTO_EXPR, void_type_node, fwlabel));
+          tree block = c_begin_compound_stmt (flag_isoc99);
+
+          tree tlab = lookup_label(cbc_return_f);
+
+          tree decl= build_stmt (LABEL_EXPR, tlab);
+          //TREE_USED(decl) = 1;
+          add_stmt(decl);
+
+          //tree hoge = build_int_cst(NULL_TREE,55);
+        retval = build_component_ref (cbc_env, get_identifier("retval"));
+          tree ret = c_finish_return (retval);
+          TREE_USED(ret) = 1;
+          tree first_body = c_end_compound_stmt (block, flag_isoc99);
+
+              c_finish_if_stmt (loc, cond, first_body, NULL_TREE, false);
+
+          // define_label(EXPR_LOCATION(decl) ,cbc_return_f);
+          return_label1 =
+           define_label(cbc_return ,cbc_return_f);
+          tree fwdef= build_stmt (LABEL_EXPR, fwlabel);
+
+          //TREE_USED(fwdef) = 1;
+          add_stmt(fwdef);
+          TREE_SIDE_EFFECTS (block) = 1;
+
+          // tree label = lookup_label(c_parser_peek_token (parser)->value);
+          //TREE_USED(label) = 1;
+
+          tree value = build1(ADDR_EXPR, ptr_type_node, return_label1);
+              SET_EXPR_LOCATION (value, next);
+          TREE_SIDE_EFFECTS (value) = 1;
+          add_stmt(value);
+
+          TREE_SIDE_EFFECTS (stmt) = 1;
+          expr.value = c_finish_stmt_expr (stmt);
+          expr.original_code = ERROR_MARK;
+
+
+        }
+      else
+        {
+          //tree label = lookup_label(c_parser_peek_token (parser)->value);
+          //TREE_USED(label) = 1;
+          //expr.value = build1(ADDR_EXPR, ptr_type_node, label);
+          expr.value = build1(ADDR_EXPR, ptr_type_node, return_label1);
+          c_parser_consume_token (parser);
+            }
+#else //by KENT.
+      {
+        /*
+        ({
+            __label__ _cbc_exit0;
+            void __return_func(int retval_, void *_envp){
+            retval = retval_;
+            goto exit0;
+            }
+            if (0) {
+              _cbc_exit0:
+            return retval;
+            }
+            __return_func;
+        });
+         */
+        tree value, stmt, label, tlab, decl;
+        c_parser_consume_token (parser);
+
+        stmt = c_begin_stmt_expr ();
+        cbc_return_f = c_parser_peek_token (parser)->value;
+        location_t location = c_parser_peek_token (parser)->location;
+
+        /* create label. (__label__ _cbc_exit0;) */
+        label = get_identifier ("_cbc_exit0");
+        tlab = declare_label (label);
+        C_DECLARED_LABEL_FLAG (tlab) = 1;
+        add_stmt (build_stmt (DECL_EXPR, tlab));
+
+        /* declare retval.  (int retval;) */
+        tree decl_cond =
+          build_decl (VAR_DECL, get_identifier ("retval"),
+          TREE_TYPE (TREE_TYPE (current_function_decl)));
+        TREE_STATIC (decl_cond) = 1;
+        DECL_ARTIFICIAL (decl_cond) = 1;
+        pushdecl (decl_cond);
+
+        /* define nested function.  */
+        decl =
+          cbc_finish_nested_function (location, label, decl_cond);
+
+        /* define if-ed goto label and return statement. */
+        cbc_finish_labeled_goto (location, label, decl_cond);
+
+        /* get pointer to nested function.  */
+        value = build_addr (decl , current_function_decl);
+        SET_EXPR_LOCATION (value, location);
+        add_stmt (value);
+        /*value = build_external_ref (get_identifier("_cbc_internal_return"), false, location);*/
+        /*value = build_unary_op (location, ADDR_EXPR, value, 0);*/
+        /*add_stmt (value);*/
+
+        TREE_SIDE_EFFECTS (stmt) = 1;
+        expr.value = c_finish_stmt_expr (stmt);
+        expr.original_code = ERROR_MARK;
+      }
+
+#endif //0
+      break;
+#endif  //noCbC
+    default:
+      c_parser_error (parser, "expected expression");
+      expr.value = error_mark_node;
+      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));
+      break;
+    }
+      /* Else fall through to report error.  */
+    default:
+      c_parser_error (parser, "expected expression");
+      expr.value = error_mark_node;
+      break;
+    }
+  return c_parser_postfix_expression_after_primary (parser, loc, 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.  TYPE_LOC is the location where TYPE_NAME starts--the
+   location of the first token after the parentheses around the type
+   name.  */
+
+static struct c_expr
+c_parser_postfix_expression_after_paren_type (c_parser *parser,
+                          struct c_type_name *type_name,
+                          location_t type_loc)
+{
+  tree type;
+  struct c_expr init;
+  bool non_const;
+  struct c_expr expr;
+  location_t start_loc;
+  tree type_expr = NULL_TREE;
+  bool type_expr_const = true;
+  check_compound_literal_type (type_loc, type_name);
+  start_init (NULL_TREE, NULL, 0);
+  type = groktypename (type_name, &type_expr, &type_expr_const);
+  start_loc = c_parser_peek_token (parser)->location;
+  if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type))
+    {
+      error_at (type_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 (type != error_mark_node
+      && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type))
+      && current_function_decl)
+    {
+      error ("compound literal qualified by address-space qualifier");
+      type = error_mark_node;
+    }
+
+  if (!flag_isoc99)
+    pedwarn (start_loc, OPT_pedantic, "ISO C90 forbids compound literals");
+  non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR)
+           ? CONSTRUCTOR_NON_CONST (init.value)
+           : init.original_code == C_MAYBE_CONST_EXPR);
+  non_const |= !type_expr_const;
+  expr.value = build_compound_literal (start_loc, type, init.value, non_const);
+  expr.original_code = ERROR_MARK;
+  expr.original_type = NULL;
+  if (type_expr)
+    {
+      if (TREE_CODE (expr.value) == C_MAYBE_CONST_EXPR)
+    {
+      gcc_assert (C_MAYBE_CONST_EXPR_PRE (expr.value) == NULL_TREE);
+      C_MAYBE_CONST_EXPR_PRE (expr.value) = type_expr;
+    }
+      else
+    {
+      gcc_assert (!non_const);
+      expr.value = build2 (C_MAYBE_CONST_EXPR, type,
+                   type_expr, expr.value);
+    }
+    }
+  return c_parser_postfix_expression_after_primary (parser, start_loc, expr);
+}
+
+/* Parse a postfix expression after the initial primary or compound
+   literal; that is, parse a series of postfix operators.
+
+   EXPR_LOC is the location of the primary expression.  */
+
+static struct c_expr
+c_parser_postfix_expression_after_primary (c_parser *parser,
+                       location_t expr_loc,
+                       struct c_expr expr)
+{
+  struct c_expr orig_expr;
+  tree ident, idx;
+  VEC(tree,gc) *exprlist;
+  VEC(tree,gc) *origtypes;
+  while (true)
+    {
+      location_t op_loc = c_parser_peek_token (parser)->location;
+      switch (c_parser_peek_token (parser)->type)
+    {
+    case CPP_OPEN_SQUARE:
+      /* Array reference.  */
+      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 (op_loc, expr.value, idx);
+      expr.original_code = ERROR_MARK;
+      expr.original_type = NULL;
+      break;
+    case CPP_OPEN_PAREN:
+      /* Function call.  */
+      c_parser_consume_token (parser);
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+        exprlist = NULL;
+      else
+        exprlist = c_parser_expr_list (parser, true, false, &origtypes);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+                     "expected %<)%>");
+      orig_expr = expr;
+      /* FIXME diagnostics: Ideally we want the FUNCNAME, not the
+         "(" after the FUNCNAME, which is what we have now.    */
+      expr.value = build_function_call_vec (op_loc, expr.value, exprlist,
+                        origtypes);
+      expr.original_code = ERROR_MARK;
+      if (TREE_CODE (expr.value) == INTEGER_CST
+          && TREE_CODE (orig_expr.value) == FUNCTION_DECL
+          && DECL_BUILT_IN_CLASS (orig_expr.value) == BUILT_IN_NORMAL
+          && DECL_FUNCTION_CODE (orig_expr.value) == BUILT_IN_CONSTANT_P)
+        expr.original_code = C_MAYBE_CONST_EXPR;
+      expr.original_type = NULL;
+      if (exprlist != NULL)
+        {
+          release_tree_vector (exprlist);
+          release_tree_vector (origtypes);
+        }
+      break;
+    case CPP_DOT:
+      /* Structure element reference.  */
+      c_parser_consume_token (parser);
+      expr = default_function_array_conversion (expr_loc, 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;
+              expr.original_type = NULL;
+          return expr;
+        }
+      c_parser_consume_token (parser);
+      expr.value = build_component_ref (op_loc, expr.value, ident);
+      expr.original_code = ERROR_MARK;
+      if (TREE_CODE (expr.value) != COMPONENT_REF)
+        expr.original_type = NULL;
+      else
+        {
+          /* Remember the original type of a bitfield.  */
+          tree field = TREE_OPERAND (expr.value, 1);
+          if (TREE_CODE (field) != FIELD_DECL)
+        expr.original_type = NULL;
+          else
+        expr.original_type = DECL_BIT_FIELD_TYPE (field);
+        }
+      break;
+    case CPP_DEREF:
+      /* Structure element reference.  */
+      c_parser_consume_token (parser);
+      expr = default_function_array_conversion (expr_loc, 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;
+          expr.original_type = NULL;
+          return expr;
+        }
+      c_parser_consume_token (parser);
+      expr.value = build_component_ref (op_loc,
+                        build_indirect_ref (op_loc,
+                                expr.value,
+                                RO_ARROW),
+                        ident);
+      expr.original_code = ERROR_MARK;
+      if (TREE_CODE (expr.value) != COMPONENT_REF)
+        expr.original_type = NULL;
+      else
+        {
+          /* Remember the original type of a bitfield.  */
+          tree field = TREE_OPERAND (expr.value, 1);
+          if (TREE_CODE (field) != FIELD_DECL)
+        expr.original_type = NULL;
+          else
+        expr.original_type = DECL_BIT_FIELD_TYPE (field);
+        }
+      break;
+    case CPP_PLUS_PLUS:
+      /* Postincrement.  */
+      c_parser_consume_token (parser);
+      expr = default_function_array_conversion (expr_loc, expr);
+      expr.value = build_unary_op (op_loc,
+                       POSTINCREMENT_EXPR, expr.value, 0);
+      expr.original_code = ERROR_MARK;
+      expr.original_type = NULL;
+      break;
+    case CPP_MINUS_MINUS:
+      /* Postdecrement.  */
+      c_parser_consume_token (parser);
+      expr = default_function_array_conversion (expr_loc, expr);
+      expr.value = build_unary_op (op_loc,
+                       POSTDECREMENT_EXPR, expr.value, 0);
+      expr.original_code = ERROR_MARK;
+      expr.original_type = NULL;
+      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;
+      location_t loc = c_parser_peek_token (parser)->location;
+      location_t expr_loc;
+      c_parser_consume_token (parser);
+      expr_loc = c_parser_peek_token (parser)->location;
+      next = c_parser_expr_no_commas (parser, NULL);
+      next = default_function_array_conversion (expr_loc, next);
+      expr.value = build_compound_expr (loc, expr.value, next.value);
+      expr.original_code = COMPOUND_EXPR;
+      expr.original_type = next.original_type;
+    }
+  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;
+  location_t loc = c_parser_peek_token (parser)->location;
+  expr = c_parser_expression (parser);
+  expr = default_function_array_conversion (loc, expr);
+  return expr;
+}
+
+/* Parse a non-empty list of expressions.  If CONVERT_P, convert
+   functions and arrays to pointers.  If FOLD_P, fold the expressions.
+
+   nonempty-expr-list:
+     assignment-expression
+     nonempty-expr-list , assignment-expression
+*/
+
+static VEC(tree,gc) *
+c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
+            VEC(tree,gc) **p_orig_types)
+{
+  VEC(tree,gc) *ret;
+  VEC(tree,gc) *orig_types;
+  struct c_expr expr;
+  location_t loc = c_parser_peek_token (parser)->location;
+
+  ret = make_tree_vector ();
+  if (p_orig_types == NULL)
+    orig_types = NULL;
+  else
+    orig_types = make_tree_vector ();
+
+  expr = c_parser_expr_no_commas (parser, NULL);
+  if (convert_p)
+    expr = default_function_array_conversion (loc, expr);
+  if (fold_p)
+    expr.value = c_fully_fold (expr.value, false, NULL);
+  VEC_quick_push (tree, ret, expr.value);
+  if (orig_types != NULL)
+    VEC_quick_push (tree, orig_types, expr.original_type);
+  while (c_parser_next_token_is (parser, CPP_COMMA))
+    {
+      c_parser_consume_token (parser);
+      loc = c_parser_peek_token (parser)->location;
+      expr = c_parser_expr_no_commas (parser, NULL);
+      if (convert_p)
+    expr = default_function_array_conversion (loc, expr);
+      if (fold_p)
+    expr.value = c_fully_fold (expr.value, false, NULL);
+      VEC_safe_push (tree, gc, ret, expr.value);
+      if (orig_types != NULL)
+    VEC_safe_push (tree, gc, orig_types, expr.original_type);
+    }
+  if (orig_types != NULL)
+    *p_orig_types = orig_types;
+  return ret;
+}
+
+/* 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, NULL, NULL);
+  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;
+      expr = c_fully_fold (expr, false, NULL);
+      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_fully_fold (c_parser_expression (parser).value, false, NULL);
+}
+
+/* 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 ret;
+  VEC(tree,gc) *expr_list = c_parser_expr_list (parser, true, true, NULL);
+  if (VEC_length (tree, expr_list) == 1)
+    {
+      /* Just return the expression, remove a level of
+     indirection.  */
+      ret = VEC_index (tree, expr_list, 0);
+    }
+  else
+    {
+      /* We have a comma expression, we will collapse later.  */
+      ret = build_tree_list_vec (expr_list);
+    }
+  release_tree_vector (expr_list);
+  return ret;
+}
+
+
+/* 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));
+}
+
+/* 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)
+      {
+    location_t loc = OMP_CLAUSE_LOCATION (c);
+    error_at (loc, "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 nonzero, CLAUSE_LOC is the location of the clause.
+
+   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,
+                location_t clause_loc,
+                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)->location,
+                 c_parser_peek_token (parser)->value);
+      else if (t == error_mark_node)
+    ;
+      else if (kind != 0)
+    {
+      tree u = build_omp_clause (clause_loc, 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)
+{
+  /* The clauses location.  */
+  location_t loc = c_parser_peek_token (parser)->location;
+
+  if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    {
+      list = c_parser_omp_variable_list (parser, loc, 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 (loc, 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;
+  location_t loc = c_parser_peek_token (parser)->location;
+  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 (loc, 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)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  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 (loc, 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;
+  location_t loc = c_parser_peek_token (parser)->location;
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait");
+
+  c = build_omp_clause (loc, 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)
+{
+  location_t num_threads_loc = c_parser_peek_token (parser)->location;
+  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;
+      t = c_fully_fold (t, false, NULL);
+
+      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_loc (expr_loc, LE_EXPR, boolean_type_node, t,
+               build_int_cst (TREE_TYPE (t), 0));
+      if (CAN_HAVE_LOCATION_P (c))
+    SET_EXPR_LOCATION (c, expr_loc);
+      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 (num_threads_loc, 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, tree list)
+{
+  tree c;
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered");
+
+  c = build_omp_clause (c_parser_peek_token (parser)->location,
+            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)
+{
+  location_t clause_loc = c_parser_peek_token (parser)->location;
+  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, clause_loc,
+                       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;
+  location_t loc = c_parser_peek_token (parser)->location;
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
+
+  c = build_omp_clause (loc, 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;
+      t = c_fully_fold (t, false, NULL);
+
+      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 (c_parser_peek_token (parser)->location,
+            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.
+
+  LOC is the location of the #pragma token.  */
+
+static void
+c_parser_omp_atomic (location_t loc, 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;
+  lhs = c_fully_fold (lhs, false, NULL);
+  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);
+      {
+    location_t rhs_loc = c_parser_peek_token (parser)->location;
+    rhs_expr = c_parser_expression (parser);
+    rhs_expr = default_function_array_conversion (rhs_loc, rhs_expr);
+      }
+      rhs = rhs_expr.value;
+      rhs = c_fully_fold (rhs, false, NULL);
+      break;
+    }
+  stmt = c_finish_omp_atomic (loc, 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)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_pragma (parser);
+  c_parser_skip_to_pragma_eol (parser);
+
+  c_finish_omp_barrier (loc);
+}
+
+/* OpenMP 2.5:
+   # pragma omp critical [(name)] new-line
+     structured-block
+
+  LOC is the location of the #pragma itself.  */
+
+static tree
+c_parser_omp_critical (location_t loc, 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 (loc, 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)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  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 (loc);
+}
+
+/* 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.
+   LOC is the location of the OMP in "#pragma omp".  */
+
+static tree
+c_parser_omp_for_loop (location_t loc,
+               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;
+  bool fail = false, open_brace_parsed = false;
+  int i, collapse = 1, nbraces = 0;
+  location_t for_loc;
+
+  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;
+    }
+  for_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 (for_loc);
+      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 decl_exp;
+      struct c_expr init_exp;
+      location_t init_loc;
+
+      decl_exp = c_parser_postfix_expression (parser);
+      decl = decl_exp.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_loc, init_exp);
+      init = build_modify_expr (init_loc, decl, decl_exp.original_type,
+                    NOP_EXPR, init_loc, init_exp.value,
+                    init_exp.original_type);
+      init = c_process_expr_stmt (init_loc, 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);
+      cond = c_fully_fold (cond, false, NULL);
+      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 (incr_loc,
+                      c_parser_expression (parser).value);
+    }
+      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)
+    {
+      location_t here = c_parser_peek_token (parser)->location;
+      stmt = c_begin_compound_stmt (true);
+      c_parser_compound_statement_nostart (parser);
+      add_stmt (c_end_compound_stmt (here, stmt, true));
+    }
+  else
+    add_stmt (c_parser_c99_block_statement (parser));
+  if (c_cont_label)
+    {
+      tree t = build1 (LABEL_EXPR, void_type_node, c_cont_label);
+      SET_EXPR_LOCATION (t, loc);
+      add_stmt (t);
+    }
+
+  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)
+        {
+          location_t here = c_parser_peek_token (parser)->location;
+          stmt = c_begin_compound_stmt (true);
+          add_stmt (body);
+          c_parser_compound_statement_nostart (parser);
+          body = c_end_compound_stmt (here, 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_LOCATION (*c),
+                           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)
+    {
+      /* FIXME diagnostics: LOC below should be the actual location of
+     this particular for block.  We need to build a list of
+     locations to go along with FOR_BLOCK.  */
+      stmt = c_end_compound_stmt (loc, 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
+
+   LOC is the location of the #pragma token.
+*/
+
+#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 (location_t loc, 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 (loc, parser, clauses, NULL);
+  block = c_end_compound_stmt (loc, block, true);
+  add_stmt (block);
+
+  return ret;
+}
+
+/* OpenMP 2.5:
+   # pragma omp master new-line
+     structured-block
+
+   LOC is the location of the #pragma token.
+*/
+
+static tree
+c_parser_omp_master (location_t loc, c_parser *parser)
+{
+  c_parser_skip_to_pragma_eol (parser);
+  return c_finish_omp_master (loc, c_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 2.5:
+   # pragma omp ordered new-line
+     structured-block
+
+   LOC is the location of the #pragma itself.
+*/
+
+static tree
+c_parser_omp_ordered (location_t loc, c_parser *parser)
+{
+  c_parser_skip_to_pragma_eol (parser);
+  return c_finish_omp_ordered (loc, 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
+
+    SECTIONS_LOC is the location of the #pragma omp sections.  */
+
+static tree
+c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser)
+{
+  tree stmt, substmt;
+  bool error_suppress = false;
+  location_t loc;
+
+  loc = c_parser_peek_token (parser)->location;
+  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 ();
+
+  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);
+  SET_EXPR_LOCATION (stmt, sections_loc);
+  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
+
+   LOC is the location of the #pragma token.
+*/
+
+#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 (location_t loc, 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 (loc, parser);
+  if (ret)
+    OMP_SECTIONS_CLAUSES (ret) = clauses;
+  block = c_end_compound_stmt (loc, 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
+
+   LOC is the location of the #pragma token.
+*/
+
+#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 (location_t loc, 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 (loc, clauses, block);
+      break;
+
+    case PRAGMA_OMP_PARALLEL_FOR:
+      block = c_begin_omp_parallel ();
+      c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
+      c_parser_omp_for_loop (loc, parser, ws_clause, &par_clause);
+      stmt = c_finish_omp_parallel (loc, par_clause, block);
+      OMP_PARALLEL_COMBINED (stmt) = 1;
+      break;
+
+    case PRAGMA_OMP_PARALLEL_SECTIONS:
+      block = c_begin_omp_parallel ();
+      c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
+      stmt = c_parser_omp_sections_scope (loc, parser);
+      if (stmt)
+    OMP_SECTIONS_CLAUSES (stmt) = ws_clause;
+      stmt = c_finish_omp_parallel (loc, 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
+
+   LOC is the location of the #pragma.
+*/
+
+#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 (location_t loc, c_parser *parser)
+{
+  tree stmt = make_node (OMP_SINGLE);
+  SET_EXPR_LOCATION (stmt, loc);
+  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
+
+   LOC is the location of the #pragma.
+*/
+
+#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 (location_t loc, 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 (loc, clauses, block);
+}
+
+/* OpenMP 3.0:
+   # pragma omp taskwait new-line
+*/
+
+static void
+c_parser_omp_taskwait (c_parser *parser)
+{
+  location_t loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_pragma (parser);
+  c_parser_skip_to_pragma_eol (parser);
+
+  c_finish_omp_taskwait (loc);
+}
+
+/* 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);
+
+  switch (p_kind)
+    {
+    case PRAGMA_OMP_ATOMIC:
+      c_parser_omp_atomic (loc, parser);
+      return;
+    case PRAGMA_OMP_CRITICAL:
+      stmt = c_parser_omp_critical (loc, parser);
+      break;
+    case PRAGMA_OMP_FOR:
+      stmt = c_parser_omp_for (loc, parser);
+      break;
+    case PRAGMA_OMP_MASTER:
+      stmt = c_parser_omp_master (loc, parser);
+      break;
+    case PRAGMA_OMP_ORDERED:
+      stmt = c_parser_omp_ordered (loc, parser);
+      break;
+    case PRAGMA_OMP_PARALLEL:
+      stmt = c_parser_omp_parallel (loc, parser);
+      break;
+    case PRAGMA_OMP_SECTIONS:
+      stmt = c_parser_omp_sections (loc, parser);
+      break;
+    case PRAGMA_OMP_SINGLE:
+      stmt = c_parser_omp_single (loc, parser);
+      break;
+    case PRAGMA_OMP_TASK:
+      stmt = c_parser_omp_task (loc, parser);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  if (stmt)
+    gcc_assert (EXPR_LOCATION (stmt) != UNKNOWN_LOCATION);
+}
+
+
+/* OpenMP 2.5:
+   # pragma omp threadprivate (variable-list) */
+
+static void
+c_parser_omp_threadprivate (c_parser *parser)
+{
+  tree vars, t;
+  location_t loc;
+
+  c_parser_consume_pragma (parser);
+  loc = c_parser_peek_token (parser)->location;
+  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);
+
+      /* FIXME diagnostics: Ideally we should keep individual
+     locations for all the variables in the var list to make the
+     following errors more precise.  Perhaps
+     c_parser_omp_var_list_parens() should construct a list of
+     locations to go along with the var list.  */
+
+      /* 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_at (loc, "%qD is not a variable", v);
+      else if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v))
+    error_at (loc, "%qE declared %<threadprivate%> after first use", v);
+      else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v))
+    error_at (loc, "automatic variable %qE cannot be %<threadprivate%>", v);
+      else if (TREE_TYPE (v) == error_mark_node)
+    ;
+      else if (! COMPLETE_TYPE_P (TREE_TYPE (v)))
+    error_at (loc, "%<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);
+}
+
+
+/* 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;
+
+  /* Initialize EH, if we've been told to do so.  */
+  if (flag_exceptions)
+    using_eh_for_cleanups ();
+
+  c_parser_translation_unit (the_parser);
+  the_parser = NULL;
+}
+
+#include "gt-c-parser.h"