aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1/gcc/c-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1/gcc/c-parser.c')
-rw-r--r--gcc-4.2.1/gcc/c-parser.c7868
1 files changed, 7868 insertions, 0 deletions
diff --git a/gcc-4.2.1/gcc/c-parser.c b/gcc-4.2.1/gcc/c-parser.c
new file mode 100644
index 000000000..c6be63918
--- /dev/null
+++ b/gcc-4.2.1/gcc/c-parser.c
@@ -0,0 +1,7868 @@
+/* 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 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 2, 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 COPYING. If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
+
+/* 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"
+
+
+/* Miscellaneous data and functions needed for the parser. */
+
+int yydebug;
+
+/* Objective-C specific parser/lexer information. */
+
+static int objc_pq_context = 0;
+
+/* 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. */
+static int objc_need_raw_identifier = 0;
+#define OBJC_NEED_RAW_IDENTIFIER(VAL) \
+ do { \
+ if (c_dialect_objc ()) \
+ objc_need_raw_identifier = VAL; \
+ } while (0)
+
+/* The reserved keyword table. */
+struct resword
+{
+ const char *word;
+ ENUM_BITFIELD(rid) rid : 16;
+ unsigned int disable : 16;
+};
+
+/* Disable mask. Keywords are disabled if (reswords[i].disable &
+ mask) is _true_. */
+#define D_C89 0x01 /* not in C89 */
+#define D_EXT 0x02 /* GCC extension */
+#define D_EXT89 0x04 /* GCC extension incorporated in C99 */
+#define D_OBJC 0x08 /* Objective C only */
+
+static const struct resword reswords[] =
+{
+ { "_Bool", RID_BOOL, 0 },
+ { "_Complex", RID_COMPLEX, 0 },
+ { "_Decimal32", RID_DFLOAT32, D_EXT },
+ { "_Decimal64", RID_DFLOAT64, D_EXT },
+ { "_Decimal128", RID_DFLOAT128, D_EXT },
+ { "__FUNCTION__", RID_FUNCTION_NAME, 0 },
+ { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
+ { "__alignof", RID_ALIGNOF, 0 },
+ { "__alignof__", RID_ALIGNOF, 0 },
+ { "__asm", RID_ASM, 0 },
+ { "__asm__", RID_ASM, 0 },
+ { "__attribute", RID_ATTRIBUTE, 0 },
+ { "__attribute__", RID_ATTRIBUTE, 0 },
+ { "__builtin_choose_expr", RID_CHOOSE_EXPR, 0 },
+ { "__builtin_offsetof", RID_OFFSETOF, 0 },
+ { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, 0 },
+ { "__builtin_va_arg", RID_VA_ARG, 0 },
+ { "__complex", RID_COMPLEX, 0 },
+ { "__complex__", RID_COMPLEX, 0 },
+ { "__const", RID_CONST, 0 },
+ { "__const__", RID_CONST, 0 },
+ { "__extension__", RID_EXTENSION, 0 },
+ { "__func__", RID_C99_FUNCTION_NAME, 0 },
+ { "__imag", RID_IMAGPART, 0 },
+ { "__imag__", RID_IMAGPART, 0 },
+ { "__inline", RID_INLINE, 0 },
+ { "__inline__", RID_INLINE, 0 },
+ { "__label__", RID_LABEL, 0 },
+ { "__real", RID_REALPART, 0 },
+ { "__real__", RID_REALPART, 0 },
+ { "__restrict", RID_RESTRICT, 0 },
+ { "__restrict__", RID_RESTRICT, 0 },
+ { "__signed", RID_SIGNED, 0 },
+ { "__signed__", RID_SIGNED, 0 },
+ { "__thread", RID_THREAD, 0 },
+ { "__typeof", RID_TYPEOF, 0 },
+ { "__typeof__", RID_TYPEOF, 0 },
+ { "__volatile", RID_VOLATILE, 0 },
+ { "__volatile__", RID_VOLATILE, 0 },
+ { "asm", RID_ASM, D_EXT },
+ { "auto", RID_AUTO, 0 },
+ { "break", RID_BREAK, 0 },
+ { "case", RID_CASE, 0 },
+ { "char", RID_CHAR, 0 },
+ { "const", RID_CONST, 0 },
+ { "continue", RID_CONTINUE, 0 },
+ { "default", RID_DEFAULT, 0 },
+ { "do", RID_DO, 0 },
+ { "double", RID_DOUBLE, 0 },
+ { "else", RID_ELSE, 0 },
+ { "enum", RID_ENUM, 0 },
+ { "extern", RID_EXTERN, 0 },
+ { "float", RID_FLOAT, 0 },
+ { "for", RID_FOR, 0 },
+ { "goto", RID_GOTO, 0 },
+ { "if", RID_IF, 0 },
+ { "inline", RID_INLINE, D_EXT89 },
+ { "int", RID_INT, 0 },
+ { "long", RID_LONG, 0 },
+ { "register", RID_REGISTER, 0 },
+ { "restrict", RID_RESTRICT, D_C89 },
+ { "return", RID_RETURN, 0 },
+ { "short", RID_SHORT, 0 },
+ { "signed", RID_SIGNED, 0 },
+ { "sizeof", RID_SIZEOF, 0 },
+ { "static", RID_STATIC, 0 },
+ { "struct", RID_STRUCT, 0 },
+ { "switch", RID_SWITCH, 0 },
+ { "typedef", RID_TYPEDEF, 0 },
+ { "typeof", RID_TYPEOF, D_EXT },
+ { "union", RID_UNION, 0 },
+ { "unsigned", RID_UNSIGNED, 0 },
+ { "void", RID_VOID, 0 },
+ { "volatile", RID_VOLATILE, 0 },
+ { "while", RID_WHILE, 0 },
+ /* These Objective-C keywords are recognized only immediately after
+ an '@'. */
+ { "class", RID_AT_CLASS, D_OBJC },
+ { "compatibility_alias", RID_AT_ALIAS, D_OBJC },
+ { "defs", RID_AT_DEFS, D_OBJC },
+ { "encode", RID_AT_ENCODE, D_OBJC },
+ { "end", RID_AT_END, D_OBJC },
+ { "implementation", RID_AT_IMPLEMENTATION, D_OBJC },
+ { "interface", RID_AT_INTERFACE, D_OBJC },
+ { "private", RID_AT_PRIVATE, D_OBJC },
+ { "protected", RID_AT_PROTECTED, D_OBJC },
+ { "protocol", RID_AT_PROTOCOL, D_OBJC },
+ { "public", RID_AT_PUBLIC, D_OBJC },
+ { "selector", RID_AT_SELECTOR, D_OBJC },
+ { "throw", RID_AT_THROW, D_OBJC },
+ { "try", RID_AT_TRY, D_OBJC },
+ { "catch", RID_AT_CATCH, D_OBJC },
+ { "finally", RID_AT_FINALLY, D_OBJC },
+ { "synchronized", RID_AT_SYNCHRONIZED, D_OBJC },
+ /* These are recognized only in protocol-qualifier context
+ (see above) */
+ { "bycopy", RID_BYCOPY, D_OBJC },
+ { "byref", RID_BYREF, D_OBJC },
+ { "in", RID_IN, D_OBJC },
+ { "inout", RID_INOUT, D_OBJC },
+ { "oneway", RID_ONEWAY, D_OBJC },
+ { "out", RID_OUT, D_OBJC },
+};
+#define N_reswords (sizeof reswords / sizeof (struct resword))
+
+/* All OpenMP clauses. OpenMP 2.5. */
+typedef enum pragma_omp_clause {
+ PRAGMA_OMP_CLAUSE_NONE = 0,
+
+ PRAGMA_OMP_CLAUSE_COPYIN,
+ PRAGMA_OMP_CLAUSE_COPYPRIVATE,
+ PRAGMA_OMP_CLAUSE_DEFAULT,
+ PRAGMA_OMP_CLAUSE_FIRSTPRIVATE,
+ PRAGMA_OMP_CLAUSE_IF,
+ PRAGMA_OMP_CLAUSE_LASTPRIVATE,
+ PRAGMA_OMP_CLAUSE_NOWAIT,
+ PRAGMA_OMP_CLAUSE_NUM_THREADS,
+ PRAGMA_OMP_CLAUSE_ORDERED,
+ PRAGMA_OMP_CLAUSE_PRIVATE,
+ PRAGMA_OMP_CLAUSE_REDUCTION,
+ PRAGMA_OMP_CLAUSE_SCHEDULE,
+ PRAGMA_OMP_CLAUSE_SHARED
+} pragma_omp_clause;
+
+
+/* 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 = (flag_isoc99 ? 0 : D_C89)
+ | (flag_no_asm ? (flag_isoc99 ? D_EXT : D_EXT|D_EXT89) : 0);
+
+ if (!c_dialect_objc ())
+ mask |= D_OBJC;
+
+ ridpointers = GGC_CNEWVEC (tree, (int) RID_MAX);
+ for (i = 0; i < N_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 (reswords[i].disable & mask)
+ continue;
+
+ id = get_identifier (reswords[i].word);
+ C_RID_CODE (id) = reswords[i].rid;
+ C_IS_RESERVED_WORD (id) = 1;
+ ridpointers [(int) 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,
+ /* Not an identifier. */
+ C_ID_NONE
+} c_id_kind;
+
+/* A single C token after string literal concatenation and conversion
+ of preprocessing tokens to tokens. */
+typedef struct c_token GTY (())
+{
+ /* The kind of token. */
+ ENUM_BITFIELD (cpp_ttype) type : 8;
+ /* If this token is a CPP_NAME, this value indicates whether also
+ declared as some kind of type. Otherwise, it is C_ID_NONE. */
+ ENUM_BITFIELD (c_id_kind) id_kind : 8;
+ /* If this token is a keyword, this value indicates which keyword.
+ Otherwise, this value is RID_MAX. */
+ ENUM_BITFIELD (rid) keyword : 8;
+ /* If this token is a CPP_PRAGMA, this indicates the pragma that
+ was seen. Otherwise it is PRAGMA_NONE. */
+ ENUM_BITFIELD (pragma_kind) pragma_kind : 7;
+ /* True if this token is from a system header. */
+ BOOL_BITFIELD in_system_header : 1;
+ /* The value associated with this token, if any. */
+ tree value;
+ /* The location at which this token was found. */
+ location_t location;
+} c_token;
+
+/* A parser structure recording information about the state and
+ context of parsing. Includes lexer information with up to two
+ tokens of look-ahead; more are not needed for C. */
+typedef struct c_parser GTY(())
+{
+ /* The look-ahead tokens. */
+ c_token tokens[2];
+ /* How many look-ahead tokens are available (0, 1 or 2). */
+ short tokens_avail;
+ /* True if a syntax error is being recovered from; false otherwise.
+ c_parser_error sets this flag. It should clear this flag when
+ enough tokens have been consumed to recover from the error. */
+ BOOL_BITFIELD error : 1;
+ /* True if we're processing a pragma, and shouldn't automatically
+ consume CPP_PRAGMA_EOL. */
+ BOOL_BITFIELD in_pragma : 1;
+} 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_token *token)
+{
+ timevar_push (TV_LEX);
+
+ token->type = c_lex_with_flags (&token->value, &token->location, NULL);
+ token->id_kind = C_ID_NONE;
+ token->keyword = RID_MAX;
+ token->pragma_kind = PRAGMA_NONE;
+ token->in_system_header = in_system_header;
+
+ switch (token->type)
+ {
+ case CPP_NAME:
+ {
+ tree decl;
+
+ int objc_force_identifier = objc_need_raw_identifier;
+ OBJC_NEED_RAW_IDENTIFIER (0);
+
+ if (C_IS_RESERVED_WORD (token->value))
+ {
+ enum rid rid_code = C_RID_CODE (token->value);
+
+ if (c_dialect_objc ())
+ {
+ if (!OBJC_IS_AT_KEYWORD (rid_code)
+ && (!OBJC_IS_PQ_KEYWORD (rid_code) || 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
+ {
+ /* Return the canonical spelling for this keyword. */
+ token->value = ridpointers[(int) rid_code];
+ 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. */
+ OBJC_NEED_RAW_IDENTIFIER (0);
+ break;
+ case CPP_PRAGMA:
+ /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */
+ token->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->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)
+{
+ c_token *token;
+
+ /* Peek at the next token. */
+ token = c_parser_peek_token (parser);
+ /* Check to see if it is the indicated keyword. */
+ return token->keyword == keyword;
+}
+
+/* Return true if TOKEN can start a type name,
+ false otherwise. */
+static bool
+c_token_starts_typename (c_token *token)
+{
+ switch (token->type)
+ {
+ case CPP_NAME:
+ switch (token->id_kind)
+ {
+ case C_ID_ID:
+ return false;
+ case C_ID_TYPENAME:
+ return true;
+ case C_ID_CLASSNAME:
+ gcc_assert (c_dialect_objc ());
+ return true;
+ default:
+ gcc_unreachable ();
+ }
+ case CPP_KEYWORD:
+ switch (token->keyword)
+ {
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_SHORT:
+ case RID_SIGNED:
+ case RID_COMPLEX:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ case RID_BOOL:
+ case RID_ENUM:
+ case RID_STRUCT:
+ case RID_UNION:
+ case RID_TYPEOF:
+ case RID_CONST:
+ case RID_VOLATILE:
+ case RID_RESTRICT:
+ case RID_ATTRIBUTE:
+ return true;
+ default:
+ return false;
+ }
+ case CPP_LESS:
+ if (c_dialect_objc ())
+ return true;
+ return false;
+ default:
+ return false;
+ }
+}
+
+/* Return true if the next token from PARSER can start a type name,
+ false otherwise. */
+static inline bool
+c_parser_next_token_starts_typename (c_parser *parser)
+{
+ c_token *token = c_parser_peek_token (parser);
+ return c_token_starts_typename (token);
+}
+
+/* Return true if TOKEN can start declaration specifiers, false
+ otherwise. */
+static bool
+c_token_starts_declspecs (c_token *token)
+{
+ switch (token->type)
+ {
+ case CPP_NAME:
+ switch (token->id_kind)
+ {
+ case C_ID_ID:
+ return false;
+ case C_ID_TYPENAME:
+ return true;
+ case C_ID_CLASSNAME:
+ gcc_assert (c_dialect_objc ());
+ return true;
+ default:
+ gcc_unreachable ();
+ }
+ case CPP_KEYWORD:
+ switch (token->keyword)
+ {
+ case RID_STATIC:
+ case RID_EXTERN:
+ case RID_REGISTER:
+ case RID_TYPEDEF:
+ case RID_INLINE:
+ case RID_AUTO:
+ case RID_THREAD:
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_SHORT:
+ case RID_SIGNED:
+ case RID_COMPLEX:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ case RID_BOOL:
+ case RID_ENUM:
+ case RID_STRUCT:
+ case RID_UNION:
+ case RID_TYPEOF:
+ case RID_CONST:
+ case RID_VOLATILE:
+ case RID_RESTRICT:
+ case RID_ATTRIBUTE:
+ 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->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;
+ in_system_header = token->in_system_header;
+ }
+}
+
+/* Issue a diagnostic of the form
+ FILE:LINE: MESSAGE before TOKEN
+ where TOKEN is the next token in the input stream of PARSER.
+ MESSAGE (specified by the caller) is usually of the form "expected
+ OTHER-TOKEN".
+
+ Do not issue a diagnostic if still recovering from an error.
+
+ ??? This is taken from the C++ parser, but building up messages in
+ this way is not i18n-friendly and some other approach should be
+ used. */
+
+static void
+c_parser_error (c_parser *parser, const char *gmsgid)
+{
+ c_token *token = c_parser_peek_token (parser);
+ if (parser->error)
+ return;
+ parser->error = true;
+ if (!gmsgid)
+ return;
+ /* This diagnostic makes more sense if it is tagged to the line of
+ the token we just peeked at. */
+ c_parser_set_source_position_from_token (token);
+ c_parse_error (gmsgid,
+ /* Because c_parse_error does not understand
+ CPP_KEYWORD, keywords are treated like
+ identifiers. */
+ (token->type == CPP_KEYWORD ? CPP_NAME : token->type),
+ token->value);
+}
+
+/* If the next token is of the indicated TYPE, consume it. Otherwise,
+ issue the error MSGID. If MSGID is NULL then a message has already
+ been produced and no message will be produced this time. Returns
+ true if found, false otherwise. */
+
+static bool
+c_parser_require (c_parser *parser,
+ enum cpp_ttype type,
+ const char *msgid)
+{
+ if (c_parser_next_token_is (parser, type))
+ {
+ c_parser_consume_token (parser);
+ return true;
+ }
+ else
+ {
+ c_parser_error (parser, msgid);
+ return false;
+ }
+}
+
+/* If the next token is the indicated keyword, consume it. Otherwise,
+ issue the error MSGID. Returns true if found, false otherwise. */
+
+static bool
+c_parser_require_keyword (c_parser *parser,
+ enum rid keyword,
+ const char *msgid)
+{
+ if (c_parser_next_token_is_keyword (parser, keyword))
+ {
+ c_parser_consume_token (parser);
+ return true;
+ }
+ else
+ {
+ c_parser_error (parser, msgid);
+ return false;
+ }
+}
+
+/* Like c_parser_require, except that tokens will be skipped until the
+ desired token is found. An error message is still produced if the
+ next token is not as expected. If MSGID is NULL then a message has
+ already been produced and no message will be produced this
+ time. */
+
+static void
+c_parser_skip_until_found (c_parser *parser,
+ enum cpp_ttype type,
+ const char *msgid)
+{
+ unsigned nesting_depth = 0;
+
+ if (c_parser_require (parser, type, msgid))
+ return;
+
+ /* Skip tokens until the desired token is found. */
+ while (true)
+ {
+ /* Peek at the next token. */
+ c_token *token = c_parser_peek_token (parser);
+ /* If we've reached the token we want, consume it and stop. */
+ if (token->type == type && !nesting_depth)
+ {
+ c_parser_consume_token (parser);
+ break;
+ }
+
+ /* If we've run out of tokens, stop. */
+ if (token->type == CPP_EOF)
+ return;
+ if (token->type == CPP_PRAGMA_EOL && parser->in_pragma)
+ return;
+ if (token->type == CPP_OPEN_BRACE
+ || token->type == CPP_OPEN_PAREN
+ || token->type == CPP_OPEN_SQUARE)
+ ++nesting_depth;
+ else if (token->type == CPP_CLOSE_BRACE
+ || token->type == CPP_CLOSE_PAREN
+ || token->type == CPP_CLOSE_SQUARE)
+ {
+ if (nesting_depth-- == 0)
+ break;
+ }
+ /* Consume this token. */
+ c_parser_consume_token (parser);
+ }
+ parser->error = false;
+}
+
+/* Skip tokens until the end of a parameter is found, but do not
+ consume the comma, semicolon or closing delimiter. */
+
+static void
+c_parser_skip_to_end_of_parameter (c_parser *parser)
+{
+ unsigned nesting_depth = 0;
+
+ while (true)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if ((token->type == CPP_COMMA || token->type == CPP_SEMICOLON)
+ && !nesting_depth)
+ break;
+ /* If we've run out of tokens, stop. */
+ if (token->type == CPP_EOF)
+ return;
+ if (token->type == CPP_PRAGMA_EOL && parser->in_pragma)
+ return;
+ if (token->type == CPP_OPEN_BRACE
+ || token->type == CPP_OPEN_PAREN
+ || token->type == CPP_OPEN_SQUARE)
+ ++nesting_depth;
+ else if (token->type == CPP_CLOSE_BRACE
+ || token->type == CPP_CLOSE_PAREN
+ || token->type == CPP_CLOSE_SQUARE)
+ {
+ if (nesting_depth-- == 0)
+ break;
+ }
+ /* Consume this token. */
+ c_parser_consume_token (parser);
+ }
+ parser->error = false;
+}
+
+/* Expect to be at the end of the pragma directive and consume an
+ end of line marker. */
+
+static void
+c_parser_skip_to_pragma_eol (c_parser *parser)
+{
+ gcc_assert (parser->in_pragma);
+ parser->in_pragma = false;
+
+ if (!c_parser_require (parser, CPP_PRAGMA_EOL, "expected end of line"))
+ while (true)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ break;
+ if (token->type == CPP_PRAGMA_EOL)
+ {
+ c_parser_consume_token (parser);
+ break;
+ }
+ c_parser_consume_token (parser);
+ }
+
+ parser->error = false;
+}
+
+/* Skip tokens until we have consumed an entire block, or until we
+ have consumed a non-nested ';'. */
+
+static void
+c_parser_skip_to_end_of_block_or_statement (c_parser *parser)
+{
+ unsigned nesting_depth = 0;
+ bool save_error = parser->error;
+
+ while (true)
+ {
+ c_token *token;
+
+ /* Peek at the next token. */
+ token = c_parser_peek_token (parser);
+
+ switch (token->type)
+ {
+ case CPP_EOF:
+ return;
+
+ case CPP_PRAGMA_EOL:
+ if (parser->in_pragma)
+ return;
+ break;
+
+ case CPP_SEMICOLON:
+ /* If the next token is a ';', we have reached the
+ end of the statement. */
+ if (!nesting_depth)
+ {
+ /* Consume the ';'. */
+ c_parser_consume_token (parser);
+ goto finished;
+ }
+ break;
+
+ case CPP_CLOSE_BRACE:
+ /* If the next token is a non-nested '}', then we have
+ reached the end of the current block. */
+ if (nesting_depth == 0 || --nesting_depth == 0)
+ {
+ c_parser_consume_token (parser);
+ goto finished;
+ }
+ break;
+
+ case CPP_OPEN_BRACE:
+ /* If it the next token is a '{', then we are entering a new
+ block. Consume the entire block. */
+ ++nesting_depth;
+ break;
+
+ case CPP_PRAGMA:
+ /* If we see a pragma, consume the whole thing at once. We
+ have some safeguards against consuming pragmas willy-nilly.
+ Normally, we'd expect to be here with parser->error set,
+ which disables these safeguards. But it's possible to get
+ here for secondary error recovery, after parser->error has
+ been cleared. */
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+ parser->error = save_error;
+ continue;
+
+ default:
+ break;
+ }
+
+ c_parser_consume_token (parser);
+ }
+
+ finished:
+ parser->error = false;
+}
+
+/* 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));
+ pedantic = 0;
+ warn_pointer_arith = 0;
+ warn_traditional = 0;
+ flag_iso = 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)
+{
+ pedantic = flags & 1;
+ warn_pointer_arith = (flags >> 1) & 1;
+ warn_traditional = (flags >> 2) & 1;
+ flag_iso = (flags >> 3) & 1;
+}
+
+/* Possibly kinds of declarator to parse. */
+typedef enum c_dtr_syn {
+ /* A normal declarator with an identifier. */
+ C_DTR_NORMAL,
+ /* An abstract declarator (maybe empty). */
+ C_DTR_ABSTRACT,
+ /* A parameter declarator: may be either, but after a type name does
+ not redeclare a typedef name as an identifier if it can
+ alternatively be interpreted as a typedef name; see DR#009,
+ applied in C90 TC1, omitted from C99 and reapplied in C99 TC2
+ following DR#249. For example, given a typedef T, "int T" and
+ "int *T" are valid parameter declarations redeclaring T, while
+ "int (T)" and "int * (T)" and "int (T[])" and "int (T (int))" are
+ abstract declarators rather than involving redundant parentheses;
+ the same applies with attributes inside the parentheses before
+ "T". */
+ C_DTR_PARM
+} c_dtr_syn;
+
+static void c_parser_external_declaration (c_parser *);
+static void c_parser_asm_definition (c_parser *);
+static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, bool);
+static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
+ bool);
+static struct c_typespec c_parser_enum_specifier (c_parser *);
+static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);
+static tree c_parser_struct_declaration (c_parser *);
+static struct c_typespec c_parser_typeof_specifier (c_parser *);
+static struct c_declarator *c_parser_declarator (c_parser *, bool, c_dtr_syn,
+ bool *);
+static struct c_declarator *c_parser_direct_declarator (c_parser *, bool,
+ c_dtr_syn, bool *);
+static struct c_declarator *c_parser_direct_declarator_inner (c_parser *,
+ bool,
+ struct c_declarator *);
+static struct c_arg_info *c_parser_parms_declarator (c_parser *, bool, tree);
+static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree);
+static struct c_parm *c_parser_parameter_declaration (c_parser *, tree);
+static tree c_parser_simple_asm_expr (c_parser *);
+static tree c_parser_attributes (c_parser *);
+static struct c_type_name *c_parser_type_name (c_parser *);
+static struct c_expr c_parser_initializer (c_parser *);
+static struct c_expr c_parser_braced_init (c_parser *, tree, bool);
+static void c_parser_initelt (c_parser *);
+static void c_parser_initval (c_parser *, struct c_expr *);
+static tree c_parser_compound_statement (c_parser *);
+static void c_parser_compound_statement_nostart (c_parser *);
+static void c_parser_label (c_parser *);
+static void c_parser_statement (c_parser *);
+static void c_parser_statement_after_labels (c_parser *);
+static void c_parser_if_statement (c_parser *);
+static void c_parser_switch_statement (c_parser *);
+static void c_parser_while_statement (c_parser *);
+static void c_parser_do_statement (c_parser *);
+static void c_parser_for_statement (c_parser *);
+static tree c_parser_asm_statement (c_parser *);
+static tree c_parser_asm_operands (c_parser *, bool);
+static tree c_parser_asm_clobbers (c_parser *);
+static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *);
+static struct c_expr c_parser_conditional_expression (c_parser *,
+ struct c_expr *);
+static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *);
+static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
+static struct c_expr c_parser_unary_expression (c_parser *);
+static struct c_expr c_parser_sizeof_expression (c_parser *);
+static struct c_expr c_parser_alignof_expression (c_parser *);
+static struct c_expr c_parser_postfix_expression (c_parser *);
+static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
+ struct c_type_name *);
+static struct c_expr c_parser_postfix_expression_after_primary (c_parser *,
+ struct c_expr);
+static struct c_expr c_parser_expression (c_parser *);
+static struct c_expr c_parser_expression_conv (c_parser *);
+static tree c_parser_expr_list (c_parser *, bool);
+static void c_parser_omp_construct (c_parser *);
+static void c_parser_omp_threadprivate (c_parser *);
+static void c_parser_omp_barrier (c_parser *);
+static void c_parser_omp_flush (c_parser *);
+
+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))
+ {
+ if (pedantic)
+ pedwarn ("ISO C forbids an empty source file");
+ }
+ else
+ {
+ void *obstack_position = obstack_alloc (&parser_obstack, 0);
+ do
+ {
+ ggc_collect ();
+ c_parser_external_declaration (parser);
+ obstack_free (&parser_obstack, obstack_position);
+ }
+ while (c_parser_next_token_is_not (parser, CPP_EOF));
+ }
+}
+
+/* Parse an external declaration (C90 6.7, C99 6.9).
+
+ external-declaration:
+ function-definition
+ declaration
+
+ GNU extensions:
+
+ external-declaration:
+ asm-definition
+ ;
+ __extension__ external-declaration
+
+ Objective-C:
+
+ external-declaration:
+ objc-class-definition
+ objc-class-declaration
+ objc-alias-declaration
+ objc-protocol-definition
+ objc-method-definition
+ @end
+*/
+
+static void
+c_parser_external_declaration (c_parser *parser)
+{
+ int ext;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_KEYWORD:
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_EXTENSION:
+ ext = disable_extension_diagnostics ();
+ c_parser_consume_token (parser);
+ c_parser_external_declaration (parser);
+ restore_extension_diagnostics (ext);
+ break;
+ case RID_ASM:
+ c_parser_asm_definition (parser);
+ break;
+ case RID_AT_INTERFACE:
+ case RID_AT_IMPLEMENTATION:
+ gcc_assert (c_dialect_objc ());
+ c_parser_objc_class_definition (parser);
+ break;
+ case RID_AT_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:
+ if (pedantic)
+ pedwarn ("ISO C does not allow extra %<;%> outside of a function");
+ c_parser_consume_token (parser);
+ break;
+ case CPP_PRAGMA:
+ c_parser_pragma (parser, pragma_external);
+ break;
+ case CPP_PLUS:
+ case CPP_MINUS:
+ if (c_dialect_objc ())
+ {
+ c_parser_objc_method_definition (parser);
+ break;
+ }
+ /* Else fall through, and yield a syntax error trying to parse
+ as a declaration or function definition. */
+ default:
+ decl_or_fndef:
+ /* A declaration or a function definition. We can only tell
+ which after parsing the declaration specifiers, if any, and
+ the first declarator. */
+ c_parser_declaration_or_fndef (parser, true, true, false, true);
+ break;
+ }
+}
+
+
+/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
+ 6.7, 6.9.1). If FNDEF_OK is true, a function definition is
+ accepted; otherwise (old-style parameter declarations) only other
+ declarations are accepted. If NESTED is true, we are inside a
+ function or parsing old-style parameter declarations; any functions
+ encountered are nested functions and declaration specifiers are
+ required; otherwise we are at top level and functions are normal
+ functions and declaration specifiers may be optional. If EMPTY_OK
+ is true, empty declarations are OK (subject to all other
+ constraints); otherwise (old-style parameter declarations) they are
+ diagnosed. If START_ATTR_OK is true, the declaration specifiers
+ may start with attributes; otherwise they may not.
+
+ declaration:
+ declaration-specifiers init-declarator-list[opt] ;
+
+ function-definition:
+ declaration-specifiers[opt] declarator declaration-list[opt]
+ compound-statement
+
+ declaration-list:
+ declaration
+ declaration-list declaration
+
+ init-declarator-list:
+ init-declarator
+ init-declarator-list , init-declarator
+
+ init-declarator:
+ declarator simple-asm-expr[opt] attributes[opt]
+ declarator simple-asm-expr[opt] attributes[opt] = initializer
+
+ GNU extensions:
+
+ nested-function-definition:
+ declaration-specifiers declarator declaration-list[opt]
+ compound-statement
+
+ The simple-asm-expr and attributes are GNU extensions.
+
+ This function does not handle __extension__; that is handled in its
+ callers. ??? Following the old parser, __extension__ may start
+ external declarations, declarations in functions and declarations
+ at the start of "for" loops, but not old-style parameter
+ declarations.
+
+ C99 requires declaration specifiers in a function definition; the
+ absence is diagnosed through the diagnosis of implicit int. In GNU
+ C we also allow but diagnose declarations without declaration
+ specifiers, but only at top level (elsewhere they conflict with
+ other syntax).
+
+ OpenMP:
+
+ declaration:
+ threadprivate-directive */
+
+static void
+c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok,
+ bool nested, bool start_attr_ok)
+{
+ struct c_declspecs *specs;
+ tree prefix_attrs;
+ tree all_prefix_attrs;
+ bool diagnosed_no_specs = false;
+
+ 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 ("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 ("data definition has no type or storage class");
+ }
+ /* Having seen a data definition, there cannot now be a
+ function definition. */
+ fndef_ok = false;
+ if (c_parser_next_token_is_keyword (parser, RID_ASM))
+ asm_name = c_parser_simple_asm_expr (parser);
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ postfix_attrs = c_parser_attributes (parser);
+ if (c_parser_next_token_is (parser, CPP_EQ))
+ {
+ tree d;
+ struct c_expr init;
+ c_parser_consume_token (parser);
+ /* The declaration of the variable is in effect while
+ its initializer is parsed. */
+ d = start_decl (declarator, specs, true,
+ chainon (postfix_attrs, all_prefix_attrs));
+ if (!d)
+ d = error_mark_node;
+ start_init (d, asm_name, global_bindings_p ());
+ init = c_parser_initializer (parser);
+ finish_init ();
+ if (d != error_mark_node)
+ {
+ maybe_warn_string_init (TREE_TYPE (d), init);
+ finish_decl (d, init.value, asm_name);
+ }
+ }
+ else
+ {
+ tree d = start_decl (declarator, specs, false,
+ chainon (postfix_attrs,
+ all_prefix_attrs));
+ if (d)
+ finish_decl (d, NULL_TREE, asm_name);
+ }
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ all_prefix_attrs = chainon (c_parser_attributes (parser),
+ prefix_attrs);
+ else
+ all_prefix_attrs = prefix_attrs;
+ continue;
+ }
+ else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ c_parser_consume_token (parser);
+ return;
+ }
+ else
+ {
+ c_parser_error (parser, "expected %<,%> or %<;%>");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
+ }
+ else if (!fndef_ok)
+ {
+ c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, "
+ "%<asm%> or %<__attribute__%>");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
+ /* Function definition (nested or otherwise). */
+ if (nested)
+ {
+ if (pedantic)
+ pedwarn ("ISO C forbids nested functions");
+ 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)
+ 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);
+ DECL_SOURCE_LOCATION (current_function_decl)
+ = c_parser_peek_token (parser)->location;
+ store_parm_decls ();
+ fnbody = c_parser_compound_statement (parser);
+ if (nested)
+ {
+ tree decl = current_function_decl;
+ add_stmt (fnbody);
+ finish_function ();
+ pop_function_context ();
+ add_stmt (build_stmt (DECL_EXPR, decl));
+ }
+ else
+ {
+ add_stmt (fnbody);
+ finish_function ();
+ }
+ break;
+ }
+}
+
+/* Parse an asm-definition (asm() outside a function body). This is a
+ GNU extension.
+
+ asm-definition:
+ simple-asm-expr ;
+*/
+
+static void
+c_parser_asm_definition (c_parser *parser)
+{
+ tree asm_str = c_parser_simple_asm_expr (parser);
+ if (asm_str)
+ cgraph_add_asm_node (asm_str);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+}
+
+/* Parse some declaration specifiers (possibly none) (C90 6.5, C99
+ 6.7), adding them to SPECS (which may already include some).
+ Storage class specifiers are accepted iff SCSPEC_OK; type
+ specifiers are accepted iff TYPESPEC_OK; attributes are accepted at
+ the start iff START_ATTR_OK.
+
+ declaration-specifiers:
+ storage-class-specifier declaration-specifiers[opt]
+ type-specifier declaration-specifiers[opt]
+ type-qualifier declaration-specifiers[opt]
+ function-specifier declaration-specifiers[opt]
+
+ Function specifiers (inline) are from C99, and are currently
+ handled as storage class specifiers, as is __thread.
+
+ C90 6.5.1, C99 6.7.1:
+ storage-class-specifier:
+ typedef
+ extern
+ static
+ auto
+ register
+
+ C99 6.7.4:
+ function-specifier:
+ inline
+
+ C90 6.5.2, C99 6.7.2:
+ type-specifier:
+ void
+ char
+ short
+ int
+ long
+ float
+ double
+ signed
+ unsigned
+ _Bool
+ _Complex
+ [_Imaginary removed in C99 TC2]
+ struct-or-union-specifier
+ enum-specifier
+ typedef-name
+
+ (_Bool and _Complex are new in C99.)
+
+ C90 6.5.3, C99 6.7.3:
+
+ type-qualifier:
+ const
+ restrict
+ volatile
+
+ (restrict is new in C99.)
+
+ GNU extensions:
+
+ declaration-specifiers:
+ attributes declaration-specifiers[opt]
+
+ storage-class-specifier:
+ __thread
+
+ type-specifier:
+ typeof-specifier
+ _Decimal32
+ _Decimal64
+ _Decimal128
+
+ Objective-C:
+
+ type-specifier:
+ class-name objc-protocol-refs[opt]
+ typedef-name objc-protocol-refs
+ objc-protocol-refs
+*/
+
+static void
+c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
+ bool scspec_ok, bool typespec_ok, bool start_attr_ok)
+{
+ bool attrs_ok = start_attr_ok;
+ bool seen_type = specs->type_seen_p;
+ while (c_parser_next_token_is (parser, CPP_NAME)
+ || c_parser_next_token_is (parser, CPP_KEYWORD)
+ || (c_dialect_objc () && c_parser_next_token_is (parser, CPP_LESS)))
+ {
+ struct c_typespec t;
+ tree attrs;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ tree value = c_parser_peek_token (parser)->value;
+ c_id_kind kind = c_parser_peek_token (parser)->id_kind;
+ /* This finishes the specifiers unless a type name is OK, it
+ is declared as a type name and a type name hasn't yet
+ been seen. */
+ if (!typespec_ok || seen_type
+ || (kind != C_ID_TYPENAME && kind != C_ID_CLASSNAME))
+ break;
+ c_parser_consume_token (parser);
+ seen_type = true;
+ attrs_ok = true;
+ if (kind == C_ID_TYPENAME
+ && (!c_dialect_objc ()
+ || c_parser_next_token_is_not (parser, CPP_LESS)))
+ {
+ t.kind = ctsk_typedef;
+ /* For a typedef name, record the meaning, not the name.
+ In case of 'foo foo, bar;'. */
+ t.spec = lookup_name (value);
+ }
+ else
+ {
+ tree proto = NULL_TREE;
+ gcc_assert (c_dialect_objc ());
+ t.kind = ctsk_objc;
+ if (c_parser_next_token_is (parser, CPP_LESS))
+ proto = c_parser_objc_protocol_refs (parser);
+ t.spec = objc_get_protocol_qualified_type (value, proto);
+ }
+ declspecs_add_type (specs, t);
+ continue;
+ }
+ if (c_parser_next_token_is (parser, CPP_LESS))
+ {
+ /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>" -
+ nisse@lysator.liu.se. */
+ tree proto;
+ gcc_assert (c_dialect_objc ());
+ if (!typespec_ok || seen_type)
+ break;
+ proto = c_parser_objc_protocol_refs (parser);
+ t.kind = ctsk_objc;
+ t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto);
+ declspecs_add_type (specs, t);
+ continue;
+ }
+ gcc_assert (c_parser_next_token_is (parser, CPP_KEYWORD));
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_STATIC:
+ case RID_EXTERN:
+ case RID_REGISTER:
+ case RID_TYPEDEF:
+ case RID_INLINE:
+ case RID_AUTO:
+ case RID_THREAD:
+ if (!scspec_ok)
+ goto out;
+ attrs_ok = true;
+ /* TODO: Distinguish between function specifiers (inline)
+ and storage class specifiers, either here or in
+ declspecs_add_scspec. */
+ declspecs_add_scspec (specs, c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ break;
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_SHORT:
+ case RID_SIGNED:
+ case RID_COMPLEX:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ case RID_BOOL:
+ if (!typespec_ok)
+ goto out;
+ attrs_ok = true;
+ seen_type = true;
+ OBJC_NEED_RAW_IDENTIFIER (1);
+ t.kind = ctsk_resword;
+ t.spec = c_parser_peek_token (parser)->value;
+ declspecs_add_type (specs, t);
+ c_parser_consume_token (parser);
+ break;
+ case RID_ENUM:
+ if (!typespec_ok)
+ goto out;
+ attrs_ok = true;
+ seen_type = true;
+ t = c_parser_enum_specifier (parser);
+ declspecs_add_type (specs, t);
+ break;
+ case RID_STRUCT:
+ case RID_UNION:
+ if (!typespec_ok)
+ goto out;
+ attrs_ok = true;
+ seen_type = true;
+ t = c_parser_struct_or_union_specifier (parser);
+ declspecs_add_type (specs, t);
+ break;
+ case RID_TYPEOF:
+ /* ??? The old parser rejected typeof after other type
+ specifiers, but is a syntax error the best way of
+ handling this? */
+ if (!typespec_ok || seen_type)
+ goto out;
+ attrs_ok = true;
+ seen_type = true;
+ t = c_parser_typeof_specifier (parser);
+ declspecs_add_type (specs, t);
+ break;
+ case RID_CONST:
+ case RID_VOLATILE:
+ case RID_RESTRICT:
+ attrs_ok = true;
+ declspecs_add_qual (specs, c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ break;
+ case RID_ATTRIBUTE:
+ if (!attrs_ok)
+ goto out;
+ attrs = c_parser_attributes (parser);
+ declspecs_add_attrs (specs, attrs);
+ break;
+ default:
+ goto out;
+ }
+ }
+ out: ;
+}
+
+/* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2).
+
+ enum-specifier:
+ enum attributes[opt] identifier[opt] { enumerator-list } attributes[opt]
+ enum attributes[opt] identifier[opt] { enumerator-list , } attributes[opt]
+ enum attributes[opt] identifier
+
+ The form with trailing comma is new in C99. The forms with
+ attributes are GNU extensions. In GNU C, we accept any expression
+ without commas in the syntax (assignment expressions, not just
+ conditional expressions); assignment expressions will be diagnosed
+ as non-constant.
+
+ enumerator-list:
+ enumerator
+ enumerator-list , enumerator
+
+ enumerator:
+ enumeration-constant
+ enumeration-constant = constant-expression
+*/
+
+static struct c_typespec
+c_parser_enum_specifier (c_parser *parser)
+{
+ struct c_typespec ret;
+ tree attrs;
+ tree ident = NULL_TREE;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM));
+ c_parser_consume_token (parser);
+ attrs = c_parser_attributes (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ ident = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ /* Parse an enum definition. */
+ tree type = start_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;
+ 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;
+ }
+ enum_id = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_EQ))
+ {
+ c_parser_consume_token (parser);
+ enum_value = c_parser_expr_no_commas (parser, NULL).value;
+ }
+ else
+ enum_value = NULL_TREE;
+ enum_decl = build_enumerator (enum_id, enum_value);
+ TREE_CHAIN (enum_decl) = values;
+ values = enum_decl;
+ seen_comma = false;
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ seen_comma = true;
+ c_parser_consume_token (parser);
+ }
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ if (seen_comma && pedantic && !flag_isoc99)
+ pedwarn ("comma at end of enumerator list");
+ c_parser_consume_token (parser);
+ break;
+ }
+ if (!seen_comma)
+ {
+ c_parser_error (parser, "expected %<,%> or %<}%>");
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+ values = error_mark_node;
+ break;
+ }
+ }
+ postfix_attrs = c_parser_attributes (parser);
+ ret.spec = finish_enum (type, nreverse (values),
+ chainon (attrs, postfix_attrs));
+ ret.kind = ctsk_tagdef;
+ return ret;
+ }
+ else if (!ident)
+ {
+ c_parser_error (parser, "expected %<{%>");
+ ret.spec = error_mark_node;
+ ret.kind = ctsk_tagref;
+ return ret;
+ }
+ ret = parser_xref_tag (ENUMERAL_TYPE, ident);
+ /* In ISO C, enumerated types can be referred to only if already
+ defined. */
+ if (pedantic && !COMPLETE_TYPE_P (ret.spec))
+ pedwarn ("ISO C forbids forward references to %<enum%> types");
+ return ret;
+}
+
+/* Parse a struct or union specifier (C90 6.5.2.1, C99 6.7.2.1).
+
+ struct-or-union-specifier:
+ struct-or-union attributes[opt] identifier[opt]
+ { struct-contents } attributes[opt]
+ struct-or-union attributes[opt] identifier
+
+ struct-contents:
+ struct-declaration-list
+
+ struct-declaration-list:
+ struct-declaration ;
+ struct-declaration-list struct-declaration ;
+
+ GNU extensions:
+
+ struct-contents:
+ empty
+ struct-declaration
+ struct-declaration-list struct-declaration
+
+ struct-declaration-list:
+ struct-declaration-list ;
+ ;
+
+ (Note that in the syntax here, unlike that in ISO C, the semicolons
+ are included here rather than in struct-declaration, in order to
+ describe the syntax with extra semicolons and missing semicolon at
+ end.)
+
+ Objective-C:
+
+ struct-declaration-list:
+ @defs ( class-name )
+
+ (Note this does not include a trailing semicolon, but can be
+ followed by further declarations, and gets a pedwarn-if-pedantic
+ when followed by a semicolon.) */
+
+static struct c_typespec
+c_parser_struct_or_union_specifier (c_parser *parser)
+{
+ struct c_typespec ret;
+ tree attrs;
+ tree ident = NULL_TREE;
+ enum tree_code code;
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_STRUCT:
+ code = RECORD_TYPE;
+ break;
+ case RID_UNION:
+ code = UNION_TYPE;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ c_parser_consume_token (parser);
+ attrs = c_parser_attributes (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ ident = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ /* Parse a struct or union definition. Start the scope of the
+ tag before parsing components. */
+ tree type = start_struct (code, ident);
+ tree postfix_attrs;
+ /* We chain the components in reverse order, then put them in
+ forward order at the end. Each struct-declaration may
+ declare multiple components (comma-separated), so we must use
+ chainon to join them, although when parsing each
+ struct-declaration we can use TREE_CHAIN directly.
+
+ The theory behind all this is that there will be more
+ semicolon separated fields than comma separated fields, and
+ so we'll be minimizing the number of node traversals required
+ by chainon. */
+ tree contents = NULL_TREE;
+ c_parser_consume_token (parser);
+ /* Handle the Objective-C @defs construct,
+ e.g. foo(sizeof(struct{ @defs(ClassName) }));. */
+ if (c_parser_next_token_is_keyword (parser, RID_AT_DEFS))
+ {
+ tree name;
+ gcc_assert (c_dialect_objc ());
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ goto end_at_defs;
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)
+ {
+ name = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ c_parser_error (parser, "expected class name");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ goto end_at_defs;
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ contents = nreverse (objc_get_class_ivars (name));
+ }
+ end_at_defs:
+ /* Parse the struct-declarations and semicolons. Problems with
+ semicolons are diagnosed here; empty structures are diagnosed
+ elsewhere. */
+ while (true)
+ {
+ tree decls;
+ /* Parse any stray semicolon. */
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ if (pedantic)
+ pedwarn ("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 ("no semicolon at end of struct or union");
+ else
+ {
+ c_parser_error (parser, "expected %<;%>");
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+ break;
+ }
+ }
+ }
+ postfix_attrs = c_parser_attributes (parser);
+ ret.spec = finish_struct (type, nreverse (contents),
+ chainon (attrs, postfix_attrs));
+ ret.kind = ctsk_tagdef;
+ return ret;
+ }
+ else if (!ident)
+ {
+ c_parser_error (parser, "expected %<{%>");
+ ret.spec = error_mark_node;
+ ret.kind = ctsk_tagref;
+ return ret;
+ }
+ ret = parser_xref_tag (code, ident);
+ return ret;
+}
+
+/* Parse a struct-declaration (C90 6.5.2.1, C99 6.7.2.1), *without*
+ the trailing semicolon.
+
+ struct-declaration:
+ specifier-qualifier-list struct-declarator-list
+
+ specifier-qualifier-list:
+ type-specifier specifier-qualifier-list[opt]
+ type-qualifier specifier-qualifier-list[opt]
+ attributes specifier-qualifier-list[opt]
+
+ struct-declarator-list:
+ struct-declarator
+ struct-declarator-list , attributes[opt] struct-declarator
+
+ struct-declarator:
+ declarator attributes[opt]
+ declarator[opt] : constant-expression attributes[opt]
+
+ GNU extensions:
+
+ struct-declaration:
+ __extension__ struct-declaration
+ specifier-qualifier-list
+
+ Unlike the ISO C syntax, semicolons are handled elsewhere. The use
+ of attributes where shown is a GNU extension. In GNU C, we accept
+ any expression without commas in the syntax (assignment
+ expressions, not just conditional expressions); assignment
+ expressions will be diagnosed as non-constant. */
+
+static tree
+c_parser_struct_declaration (c_parser *parser)
+{
+ struct c_declspecs *specs;
+ tree prefix_attrs;
+ tree all_prefix_attrs;
+ tree decls;
+ 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 ();
+ 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)
+ {
+ if (pedantic)
+ pedwarn ("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). */
+ ret = grokfield (build_id_declarator (NULL_TREE), specs, NULL_TREE);
+ }
+ 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 (declarator, specs, width);
+ decl_attributes (&d, chainon (postfix_attrs,
+ all_prefix_attrs), 0);
+ TREE_CHAIN (d) = decls;
+ decls = d;
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ all_prefix_attrs = chainon (c_parser_attributes (parser),
+ prefix_attrs);
+ else
+ all_prefix_attrs = prefix_attrs;
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else if (c_parser_next_token_is (parser, CPP_SEMICOLON)
+ || c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ /* Semicolon consumed in caller. */
+ break;
+ }
+ else
+ {
+ c_parser_error (parser, "expected %<,%>, %<;%> or %<}%>");
+ break;
+ }
+ }
+ else
+ {
+ c_parser_error (parser,
+ "expected %<:%>, %<,%>, %<;%>, %<}%> or "
+ "%<__attribute__%>");
+ break;
+ }
+ }
+ return decls;
+}
+
+/* Parse a typeof specifier (a GNU extension).
+
+ typeof-specifier:
+ typeof ( expression )
+ typeof ( type-name )
+*/
+
+static struct c_typespec
+c_parser_typeof_specifier (c_parser *parser)
+{
+ struct c_typespec ret;
+ ret.kind = ctsk_typeof;
+ ret.spec = error_mark_node;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
+ c_parser_consume_token (parser);
+ skip_evaluation++;
+ in_typeof++;
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ skip_evaluation--;
+ in_typeof--;
+ return ret;
+ }
+ if (c_parser_next_token_starts_typename (parser))
+ {
+ struct c_type_name *type = c_parser_type_name (parser);
+ skip_evaluation--;
+ in_typeof--;
+ if (type != NULL)
+ {
+ ret.spec = groktypename (type);
+ pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE));
+ }
+ }
+ else
+ {
+ bool was_vm;
+ struct c_expr expr = c_parser_expression (parser);
+ skip_evaluation--;
+ in_typeof--;
+ if (TREE_CODE (expr.value) == COMPONENT_REF
+ && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
+ error ("%<typeof%> applied to a bit-field");
+ ret.spec = TREE_TYPE (expr.value);
+ was_vm = variably_modified_type_p (ret.spec, NULL_TREE);
+ /* This should be returned with the type so that when the type
+ is evaluated, this can be evaluated. For now, we avoid
+ evaluation when the context might. */
+ if (!skip_evaluation && was_vm)
+ {
+ tree e = expr.value;
+
+ /* If the expression is not of a type to which we cannot assign a line
+ number, wrap the thing in a no-op NOP_EXPR. */
+ if (DECL_P (e) || CONSTANT_CLASS_P (e))
+ e = build1 (NOP_EXPR, void_type_node, e);
+
+ if (EXPR_P (e))
+ SET_EXPR_LOCATION (e, input_location);
+
+ add_stmt (e);
+ }
+ pop_maybe_used (was_vm);
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return ret;
+}
+
+/* Parse a declarator, possibly an abstract declarator (C90 6.5.4,
+ 6.5.5, C99 6.7.5, 6.7.6). If TYPE_SEEN_P then a typedef name may
+ be redeclared; otherwise it may not. KIND indicates which kind of
+ declarator is wanted. Returns a valid declarator except in the
+ case of a syntax error in which case NULL is returned. *SEEN_ID is
+ set to true if an identifier being declared is seen; this is used
+ to diagnose bad forms of abstract array declarators and to
+ determine whether an identifier list is syntactically permitted.
+
+ declarator:
+ pointer[opt] direct-declarator
+
+ direct-declarator:
+ identifier
+ ( attributes[opt] declarator )
+ direct-declarator array-declarator
+ direct-declarator ( parameter-type-list )
+ direct-declarator ( identifier-list[opt] )
+
+ pointer:
+ * type-qualifier-list[opt]
+ * type-qualifier-list[opt] pointer
+
+ type-qualifier-list:
+ type-qualifier
+ attributes
+ type-qualifier-list type-qualifier
+ type-qualifier-list attributes
+
+ parameter-type-list:
+ parameter-list
+ parameter-list , ...
+
+ parameter-list:
+ parameter-declaration
+ parameter-list , parameter-declaration
+
+ parameter-declaration:
+ declaration-specifiers declarator attributes[opt]
+ declaration-specifiers abstract-declarator[opt] attributes[opt]
+
+ identifier-list:
+ identifier
+ identifier-list , identifier
+
+ abstract-declarator:
+ pointer
+ pointer[opt] direct-abstract-declarator
+
+ direct-abstract-declarator:
+ ( attributes[opt] abstract-declarator )
+ direct-abstract-declarator[opt] array-declarator
+ direct-abstract-declarator[opt] ( parameter-type-list[opt] )
+
+ GNU extensions:
+
+ direct-declarator:
+ direct-declarator ( parameter-forward-declarations
+ parameter-type-list[opt] )
+
+ direct-abstract-declarator:
+ direct-abstract-declarator[opt] ( parameter-forward-declarations
+ parameter-type-list[opt] )
+
+ parameter-forward-declarations:
+ parameter-list ;
+ parameter-forward-declarations parameter-list ;
+
+ The uses of attributes shown above are GNU extensions.
+
+ Some forms of array declarator are not included in C99 in the
+ syntax for abstract declarators; these are disallowed elsewhere.
+ This may be a defect (DR#289).
+
+ This function also accepts an omitted abstract declarator as being
+ an abstract declarator, although not part of the formal syntax. */
+
+static struct c_declarator *
+c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
+ bool *seen_id)
+{
+ /* Parse any initial pointer part. */
+ if (c_parser_next_token_is (parser, CPP_MULT))
+ {
+ struct c_declspecs *quals_attrs = build_null_declspecs ();
+ struct c_declarator *inner;
+ c_parser_consume_token (parser);
+ c_parser_declspecs (parser, quals_attrs, false, false, true);
+ inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
+ if (inner == NULL)
+ return NULL;
+ else
+ return make_pointer_declarator (quals_attrs, inner);
+ }
+ /* Now we have a direct declarator, direct abstract declarator or
+ nothing (which counts as a direct abstract declarator here). */
+ return c_parser_direct_declarator (parser, type_seen_p, kind, seen_id);
+}
+
+/* Parse a direct declarator or direct abstract declarator; arguments
+ as c_parser_declarator. */
+
+static struct c_declarator *
+c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
+ bool *seen_id)
+{
+ /* The direct declarator must start with an identifier (possibly
+ omitted) or a parenthesized declarator (possibly abstract). In
+ an ordinary declarator, initial parentheses must start a
+ parenthesized declarator. In an abstract declarator or parameter
+ declarator, they could start a parenthesized declarator or a
+ parameter list. To tell which, the open parenthesis and any
+ following attributes must be read. If a declaration specifier
+ follows, then it is a parameter list; if the specifier is a
+ typedef name, there might be an ambiguity about redeclaring it,
+ which is resolved in the direction of treating it as a typedef
+ name. If a close parenthesis follows, it is also an empty
+ parameter list, as the syntax does not permit empty abstract
+ declarators. Otherwise, it is a parenthesized declarator (in
+ which case the analysis may be repeated inside it, recursively).
+
+ ??? There is an ambiguity in a parameter declaration "int
+ (__attribute__((foo)) x)", where x is not a typedef name: it
+ could be an abstract declarator for a function, or declare x with
+ parentheses. The proper resolution of this ambiguity needs
+ documenting. At present we follow an accident of the old
+ parser's implementation, whereby the first parameter must have
+ some declaration specifiers other than just attributes. Thus as
+ a parameter declaration it is treated as a parenthesized
+ parameter named x, and as an abstract declarator it is
+ rejected.
+
+ ??? Also following the old parser, attributes inside an empty
+ parameter list are ignored, making it a list not yielding a
+ prototype, rather than giving an error or making it have one
+ parameter with implicit type int.
+
+ ??? Also following the old parser, typedef names may be
+ redeclared in declarators, but not Objective-C class names. */
+
+ if (kind != C_DTR_ABSTRACT
+ && c_parser_next_token_is (parser, CPP_NAME)
+ && ((type_seen_p
+ && c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME)
+ || c_parser_peek_token (parser)->id_kind == C_ID_ID))
+ {
+ struct c_declarator *inner
+ = build_id_declarator (c_parser_peek_token (parser)->value);
+ *seen_id = true;
+ inner->id_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ return c_parser_direct_declarator_inner (parser, *seen_id, inner);
+ }
+
+ if (kind != C_DTR_NORMAL
+ && c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ {
+ struct c_declarator *inner = build_id_declarator (NULL_TREE);
+ return c_parser_direct_declarator_inner (parser, *seen_id, inner);
+ }
+
+ /* Either we are at the end of an abstract declarator, or we have
+ parentheses. */
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ tree attrs;
+ struct c_declarator *inner;
+ c_parser_consume_token (parser);
+ attrs = c_parser_attributes (parser);
+ if (kind != C_DTR_NORMAL
+ && (c_parser_next_token_starts_declspecs (parser)
+ || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)))
+ {
+ struct c_arg_info *args
+ = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL,
+ attrs);
+ if (args == NULL)
+ return NULL;
+ else
+ {
+ inner
+ = build_function_declarator (args,
+ build_id_declarator (NULL_TREE));
+ return c_parser_direct_declarator_inner (parser, *seen_id,
+ inner);
+ }
+ }
+ /* A parenthesized declarator. */
+ inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
+ if (inner != NULL && attrs != NULL)
+ inner = build_attrs_declarator (attrs, inner);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ c_parser_consume_token (parser);
+ if (inner == NULL)
+ return NULL;
+ else
+ return c_parser_direct_declarator_inner (parser, *seen_id, inner);
+ }
+ else
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return NULL;
+ }
+ }
+ else
+ {
+ if (kind == C_DTR_NORMAL)
+ {
+ c_parser_error (parser, "expected identifier or %<(%>");
+ return NULL;
+ }
+ else
+ return build_id_declarator (NULL_TREE);
+ }
+}
+
+/* Parse part of a direct declarator or direct abstract declarator,
+ given that some (in INNER) has already been parsed; ID_PRESENT is
+ true if an identifier is present, false for an abstract
+ declarator. */
+
+static struct c_declarator *
+c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
+ struct c_declarator *inner)
+{
+ /* Parse a sequence of array declarators and parameter lists. */
+ if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ {
+ struct c_declarator *declarator;
+ struct c_declspecs *quals_attrs = build_null_declspecs ();
+ bool static_seen;
+ bool star_seen;
+ tree dimen;
+ c_parser_consume_token (parser);
+ c_parser_declspecs (parser, quals_attrs, false, false, true);
+ static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC);
+ if (static_seen)
+ c_parser_consume_token (parser);
+ if (static_seen && !quals_attrs->declspecs_seen_p)
+ c_parser_declspecs (parser, quals_attrs, false, false, true);
+ if (!quals_attrs->declspecs_seen_p)
+ quals_attrs = NULL;
+ /* If "static" is present, there must be an array dimension.
+ Otherwise, there may be a dimension, "*", or no
+ dimension. */
+ if (static_seen)
+ {
+ star_seen = false;
+ dimen = c_parser_expr_no_commas (parser, NULL).value;
+ }
+ else
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ {
+ dimen = NULL_TREE;
+ star_seen = false;
+ }
+ else if (c_parser_next_token_is (parser, CPP_MULT))
+ {
+ if (c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_SQUARE)
+ {
+ dimen = NULL_TREE;
+ star_seen = true;
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ star_seen = false;
+ dimen = c_parser_expr_no_commas (parser, NULL).value;
+ }
+ }
+ else
+ {
+ star_seen = false;
+ dimen = c_parser_expr_no_commas (parser, NULL).value;
+ }
+ }
+ if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ return NULL;
+ }
+ declarator = build_array_declarator (dimen, quals_attrs, static_seen,
+ star_seen);
+ if (declarator == NULL)
+ return NULL;
+ inner = set_array_declarator_inner (declarator, inner, !id_present);
+ 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 ("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);
+ 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 %<)%>");
+ 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 c_lex_string_translate to 0. It would be better to follow the
+ C++ parser rather than using the c_lex_string_translate 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 ("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
+ c_lex_string_translate kludge. */
+ c_lex_string_translate = 0;
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ c_lex_string_translate = 1;
+ return NULL_TREE;
+ }
+ str = c_parser_asm_string_literal (parser);
+ c_lex_string_translate = 1;
+ 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
+ c_lex_string_translate kludge. */
+ c_lex_string_translate = 0;
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ c_lex_string_translate = 1;
+ return attrs;
+ }
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ c_lex_string_translate = 1;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return attrs;
+ }
+ /* Parse the attribute list. */
+ while (c_parser_next_token_is (parser, CPP_COMMA)
+ || c_parser_next_token_is (parser, CPP_NAME)
+ || c_parser_next_token_is (parser, CPP_KEYWORD))
+ {
+ tree attr, attr_name, attr_args;
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ continue;
+ }
+ if (c_parser_next_token_is (parser, CPP_KEYWORD))
+ {
+ /* ??? See comment above about what keywords are
+ accepted here. */
+ bool ok;
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_STATIC:
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_CONST:
+ case RID_EXTERN:
+ case RID_REGISTER:
+ case RID_TYPEDEF:
+ case RID_SHORT:
+ case RID_INLINE:
+ case RID_VOLATILE:
+ case RID_SIGNED:
+ case RID_AUTO:
+ case RID_RESTRICT:
+ case RID_COMPLEX:
+ case RID_THREAD:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ case RID_BOOL:
+ ok = true;
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ if (!ok)
+ break;
+ }
+ attr_name = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+ {
+ attr = build_tree_list (attr_name, NULL_TREE);
+ attrs = chainon (attrs, attr);
+ continue;
+ }
+ c_parser_consume_token (parser);
+ /* Parse the attribute contents. If they start with an
+ identifier which is followed by a comma or close
+ parenthesis, then the arguments start with that
+ identifier; otherwise they are an expression list. */
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_token (parser)->id_kind == C_ID_ID
+ && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
+ || (c_parser_peek_2nd_token (parser)->type
+ == CPP_CLOSE_PAREN)))
+ {
+ tree arg1 = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ attr_args = build_tree_list (NULL_TREE, arg1);
+ else
+ {
+ c_parser_consume_token (parser);
+ attr_args = tree_cons (NULL_TREE, arg1,
+ c_parser_expr_list (parser, false));
+ }
+ }
+ else
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ attr_args = NULL_TREE;
+ else
+ attr_args = c_parser_expr_list (parser, false);
+ }
+ attr = build_tree_list (attr_name, attr_args);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+ else
+ {
+ c_lex_string_translate = 1;
+ 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
+ {
+ c_lex_string_translate = 1;
+ 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
+ {
+ c_lex_string_translate = 1;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return attrs;
+ }
+ c_lex_string_translate = 1;
+ }
+ return attrs;
+}
+
+/* Parse a type name (C90 6.5.5, C99 6.7.6).
+
+ type-name:
+ specifier-qualifier-list abstract-declarator[opt]
+*/
+
+static struct c_type_name *
+c_parser_type_name (c_parser *parser)
+{
+ struct c_declspecs *specs = build_null_declspecs ();
+ struct c_declarator *declarator;
+ struct c_type_name *ret;
+ bool dummy = false;
+ c_parser_declspecs (parser, specs, false, true, true);
+ if (!specs->declspecs_seen_p)
+ {
+ c_parser_error (parser, "expected specifier-qualifier-list");
+ return NULL;
+ }
+ pending_xref_error ();
+ finish_declspecs (specs);
+ declarator = c_parser_declarator (parser, specs->type_seen_p,
+ C_DTR_ABSTRACT, &dummy);
+ if (declarator == NULL)
+ return NULL;
+ ret = XOBNEW (&parser_obstack, struct c_type_name);
+ ret->specs = specs;
+ ret->declarator = declarator;
+ return ret;
+}
+
+/* Parse an initializer (C90 6.5.7, C99 6.7.8).
+
+ initializer:
+ assignment-expression
+ { initializer-list }
+ { initializer-list , }
+
+ initializer-list:
+ designation[opt] initializer
+ initializer-list , designation[opt] initializer
+
+ designation:
+ designator-list =
+
+ designator-list:
+ designator
+ designator-list designator
+
+ designator:
+ array-designator
+ . identifier
+
+ array-designator:
+ [ constant-expression ]
+
+ GNU extensions:
+
+ initializer:
+ { }
+
+ designation:
+ array-designator
+ identifier :
+
+ array-designator:
+ [ constant-expression ... constant-expression ]
+
+ Any expression without commas is accepted in the syntax for the
+ constant-expressions, with non-constant expressions rejected later.
+
+ This function is only used for top-level initializers; for nested
+ ones, see c_parser_initval. */
+
+static struct c_expr
+c_parser_initializer (c_parser *parser)
+{
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ return c_parser_braced_init (parser, NULL_TREE, false);
+ else
+ {
+ struct c_expr ret;
+ ret = c_parser_expr_no_commas (parser, NULL);
+ if (TREE_CODE (ret.value) != STRING_CST
+ && TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR)
+ ret = default_function_array_conversion (ret);
+ return ret;
+ }
+}
+
+/* Parse a braced initializer list. TYPE is the type specified for a
+ compound literal, and NULL_TREE for other initializers and for
+ nested braced lists. NESTED_P is true for nested braced lists,
+ false for the list of a compound literal or the list that is the
+ top-level initializer in a declaration. */
+
+static struct c_expr
+c_parser_braced_init (c_parser *parser, tree type, bool nested_p)
+{
+ 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))
+ {
+ if (pedantic)
+ pedwarn ("ISO C forbids empty initializer braces");
+ }
+ else
+ {
+ /* Parse a non-empty initializer list, possibly with a trailing
+ comma. */
+ while (true)
+ {
+ c_parser_initelt (parser);
+ if (parser->error)
+ break;
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ break;
+ }
+ }
+ if (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
+ {
+ struct c_expr ret;
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+ 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);
+ if (pedantic)
+ pedwarn ("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;
+ 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 < 2)
+ des_seen++;
+ if (c_parser_next_token_is (parser, CPP_DOT))
+ {
+ des_seen = 2;
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ set_init_label (c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ struct c_expr init;
+ init.value = error_mark_node;
+ init.original_code = ERROR_MARK;
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_COMMA, NULL);
+ process_init_element (init);
+ return;
+ }
+ }
+ else
+ {
+ tree first, second;
+ /* ??? Following the old parser, [ objc-receiver
+ objc-message-args ] is accepted as an initializer,
+ being distinguished from a designator by what follows
+ the first assignment expression inside the square
+ brackets, but after a first array designator a
+ subsequent square bracket is for Objective-C taken to
+ start an expression, using the obsolete form of
+ designated initializer without '=', rather than
+ possibly being a second level of designation: in LALR
+ terms, the '[' is shifted rather than reducing
+ designator to designator-list. */
+ if (des_prev == 1 && c_dialect_objc ())
+ {
+ des_seen = des_prev;
+ break;
+ }
+ if (des_prev == 0 && c_dialect_objc ())
+ {
+ /* This might be an array designator or an
+ Objective-C message expression. If the former,
+ continue parsing here; if the latter, parse the
+ remainder of the initializer given the starting
+ primary-expression. ??? It might make sense to
+ distinguish when des_prev == 1 as well; see
+ previous comment. */
+ tree rec, args;
+ struct c_expr mexpr;
+ c_parser_consume_token (parser);
+ if (c_parser_peek_token (parser)->type == CPP_NAME
+ && ((c_parser_peek_token (parser)->id_kind
+ == C_ID_TYPENAME)
+ || (c_parser_peek_token (parser)->id_kind
+ == C_ID_CLASSNAME)))
+ {
+ /* Type name receiver. */
+ tree id = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ rec = objc_get_class_reference (id);
+ goto parse_message_args;
+ }
+ first = c_parser_expr_no_commas (parser, NULL).value;
+ if (c_parser_next_token_is (parser, CPP_ELLIPSIS)
+ || c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ goto array_desig_after_first;
+ /* Expression receiver. So far only one part
+ without commas has been parsed; there might be
+ more of the expression. */
+ rec = first;
+ while (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ struct c_expr next;
+ c_parser_consume_token (parser);
+ next = c_parser_expr_no_commas (parser, NULL);
+ next = default_function_array_conversion (next);
+ rec = build_compound_expr (rec, next.value);
+ }
+ parse_message_args:
+ /* Now parse the objc-message-args. */
+ args = c_parser_objc_message_args (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ mexpr.value
+ = objc_build_message_expr (build_tree_list (rec, args));
+ mexpr.original_code = ERROR_MARK;
+ /* Now parse and process the remainder of the
+ initializer, starting with this message
+ expression as a primary-expression. */
+ c_parser_initval (parser, &mexpr);
+ return;
+ }
+ c_parser_consume_token (parser);
+ first = c_parser_expr_no_commas (parser, NULL).value;
+ array_desig_after_first:
+ if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+ {
+ 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 (pedantic && second)
+ pedwarn ("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 (pedantic && !flag_isoc99)
+ pedwarn ("ISO C90 forbids specifying subobject to initialize");
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ if (des_seen == 1)
+ {
+ if (pedantic)
+ pedwarn ("obsolete use of designated initializer "
+ "without %<=%>");
+ }
+ else
+ {
+ struct c_expr init;
+ init.value = error_mark_node;
+ init.original_code = ERROR_MARK;
+ c_parser_error (parser, "expected %<=%>");
+ c_parser_skip_until_found (parser, CPP_COMMA, NULL);
+ process_init_element (init);
+ return;
+ }
+ }
+ }
+ }
+ c_parser_initval (parser, NULL);
+}
+
+/* Parse a nested initializer; as c_parser_initializer but parses
+ initializers within braced lists, after any designators have been
+ applied. If AFTER is not NULL then it is an Objective-C message
+ expression which is the primary-expression starting the
+ initializer. */
+
+static void
+c_parser_initval (c_parser *parser, struct c_expr *after)
+{
+ struct c_expr init;
+ gcc_assert (!after || c_dialect_objc ());
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after)
+ init = c_parser_braced_init (parser, NULL_TREE, true);
+ else
+ {
+ init = c_parser_expr_no_commas (parser, after);
+ if (init.value != NULL_TREE
+ && TREE_CODE (init.value) != STRING_CST
+ && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR)
+ init = default_function_array_conversion (init);
+ }
+ process_init_element (init);
+}
+
+/* Parse a compound statement (possibly a function body) (C90 6.6.2,
+ C99 6.8.2).
+
+ compound-statement:
+ { block-item-list[opt] }
+ { label-declarations block-item-list }
+
+ block-item-list:
+ block-item
+ block-item-list block-item
+
+ block-item:
+ nested-declaration
+ statement
+
+ nested-declaration:
+ declaration
+
+ GNU extensions:
+
+ compound-statement:
+ { label-declarations block-item-list }
+
+ nested-declaration:
+ __extension__ nested-declaration
+ nested-function-definition
+
+ label-declarations:
+ label-declaration
+ label-declarations label-declaration
+
+ label-declaration:
+ __label__ identifier-list ;
+
+ Allowing the mixing of declarations and code is new in C99. The
+ GNU syntax also permits (not shown above) labels at the end of
+ compound statements, which yield an error. We don't allow labels
+ on declarations; this might seem like a natural extension, but
+ there would be a conflict between attributes on the label and
+ prefix attributes on the declaration. ??? The syntax follows the
+ old parser in requiring something after label declarations.
+ Although they are erroneous if the labels declared aren't defined,
+ is it useful for the syntax to be this way?
+
+ OpenMP:
+
+ block-item:
+ openmp-directive
+
+ openmp-directive:
+ barrier-directive
+ flush-directive */
+
+static tree
+c_parser_compound_statement (c_parser *parser)
+{
+ tree stmt;
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ return error_mark_node;
+ stmt = c_begin_compound_stmt (true);
+ c_parser_compound_statement_nostart (parser);
+ return c_end_compound_stmt (stmt, true);
+}
+
+/* Parse a compound statement except for the opening brace. This is
+ used for parsing both compound statements and statement expressions
+ (which follow different paths to handling the opening). */
+
+static void
+c_parser_compound_statement_nostart (c_parser *parser)
+{
+ bool last_stmt = false;
+ bool last_label = false;
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ c_parser_consume_token (parser);
+ return;
+ }
+ if (c_parser_next_token_is_keyword (parser, RID_LABEL))
+ {
+ /* Read zero or more forward-declarations for labels that nested
+ functions can jump to. */
+ while (c_parser_next_token_is_keyword (parser, RID_LABEL))
+ {
+ c_parser_consume_token (parser);
+ /* Any identifiers, including those declared as type names,
+ are OK here. */
+ while (true)
+ {
+ tree label;
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ break;
+ }
+ label
+ = declare_label (c_parser_peek_token (parser)->value);
+ C_DECLARED_LABEL_FLAG (label) = 1;
+ add_stmt (build_stmt (DECL_EXPR, label));
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ /* ??? Locating this diagnostic on the token after the
+ declarations end follows the old parser, but it might be
+ better to locate it where the declarations start instead. */
+ if (pedantic)
+ pedwarn ("ISO C forbids label declarations");
+ }
+ /* We must now have at least one statement, label or declaration. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ c_parser_error (parser, "expected declaration or statement");
+ c_parser_consume_token (parser);
+ return;
+ }
+ while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
+ {
+ location_t loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is_keyword (parser, RID_CASE)
+ || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+ || (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+ {
+ last_label = true;
+ last_stmt = false;
+ c_parser_label (parser);
+ }
+ else if (!last_label
+ && c_parser_next_token_starts_declspecs (parser))
+ {
+ last_label = false;
+ c_parser_declaration_or_fndef (parser, true, true, true, true);
+ if (last_stmt
+ && ((pedantic && !flag_isoc99)
+ || warn_declaration_after_statement))
+ pedwarn_c90 ("%HISO C90 forbids mixed declarations and code",
+ &loc);
+ last_stmt = false;
+ }
+ else if (!last_label
+ && c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+ {
+ /* __extension__ can start a declaration, but is also an
+ unary operator that can start an expression. Consume all
+ but the last of a possible series of __extension__ to
+ determine which. */
+ while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD
+ && (c_parser_peek_2nd_token (parser)->keyword
+ == RID_EXTENSION))
+ c_parser_consume_token (parser);
+ if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser)))
+ {
+ int ext;
+ ext = disable_extension_diagnostics ();
+ c_parser_consume_token (parser);
+ last_label = false;
+ c_parser_declaration_or_fndef (parser, true, true, true, true);
+ /* Following the old parser, __extension__ does not
+ disable this diagnostic. */
+ restore_extension_diagnostics (ext);
+ if (last_stmt
+ && ((pedantic && !flag_isoc99)
+ || warn_declaration_after_statement))
+ pedwarn_c90 ("%HISO C90 forbids mixed declarations and code",
+ &loc);
+ last_stmt = false;
+ }
+ else
+ goto statement;
+ }
+ else if (c_parser_next_token_is (parser, CPP_PRAGMA))
+ {
+ /* External pragmas, and some omp pragmas, are not associated
+ with regular c code, and so are not to be considered statements
+ syntactically. This ensures that the user doesn't put them
+ places that would turn into syntax errors if the directive
+ were ignored. */
+ if (c_parser_pragma (parser, pragma_compound))
+ last_label = false, last_stmt = true;
+ }
+ else if (c_parser_next_token_is (parser, CPP_EOF))
+ {
+ c_parser_error (parser, "expected declaration or statement");
+ return;
+ }
+ else
+ {
+ statement:
+ last_label = false;
+ last_stmt = true;
+ c_parser_statement_after_labels (parser);
+ }
+
+ parser->error = false;
+ }
+ if (last_label)
+ error ("label at end of compound statement");
+ c_parser_consume_token (parser);
+}
+
+/* Parse a label (C90 6.6.1, C99 6.8.1).
+
+ label:
+ identifier : attributes[opt]
+ case constant-expression :
+ default :
+
+ GNU extensions:
+
+ label:
+ case constant-expression ... constant-expression :
+
+ The use of attributes on labels is a GNU extension. The syntax in
+ GNU C accepts any expressions without commas, non-constant
+ expressions being rejected later. */
+
+static void
+c_parser_label (c_parser *parser)
+{
+ location_t loc1 = c_parser_peek_token (parser)->location;
+ tree label = NULL_TREE;
+ if (c_parser_next_token_is_keyword (parser, RID_CASE))
+ {
+ tree exp1, exp2;
+ c_parser_consume_token (parser);
+ exp1 = c_parser_expr_no_commas (parser, NULL).value;
+ if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ c_parser_consume_token (parser);
+ label = do_case (exp1, NULL_TREE);
+ }
+ else if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+ {
+ c_parser_consume_token (parser);
+ exp2 = c_parser_expr_no_commas (parser, NULL).value;
+ if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ label = do_case (exp1, exp2);
+ }
+ else
+ c_parser_error (parser, "expected %<:%> or %<...%>");
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT))
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ label = do_case (NULL_TREE, NULL_TREE);
+ }
+ else
+ {
+ tree name = c_parser_peek_token (parser)->value;
+ tree tlab;
+ location_t loc2;
+ tree attrs;
+ 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));
+ loc2 = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ attrs = c_parser_attributes (parser);
+ tlab = define_label (loc2, name);
+ if (tlab)
+ {
+ decl_attributes (&tlab, attrs, 0);
+ label = add_stmt (build_stmt (LABEL_EXPR, tlab));
+ }
+ }
+ if (label)
+ SET_EXPR_LOCATION (label, loc1);
+}
+
+/* Parse a statement (C90 6.6, C99 6.8).
+
+ statement:
+ labeled-statement
+ compound-statement
+ expression-statement
+ selection-statement
+ iteration-statement
+ jump-statement
+
+ labeled-statement:
+ label statement
+
+ expression-statement:
+ expression[opt] ;
+
+ selection-statement:
+ if-statement
+ switch-statement
+
+ iteration-statement:
+ while-statement
+ do-statement
+ for-statement
+
+ jump-statement:
+ goto identifier ;
+ continue ;
+ break ;
+ return expression[opt] ;
+
+ GNU extensions:
+
+ statement:
+ asm-statement
+
+ jump-statement:
+ goto * expression ;
+
+ Objective-C:
+
+ statement:
+ objc-throw-statement
+ objc-try-catch-statement
+ objc-synchronized-statement
+
+ objc-throw-statement:
+ @throw expression ;
+ @throw ;
+
+ OpenMP:
+
+ statement:
+ openmp-construct
+
+ openmp-construct:
+ parallel-construct
+ for-construct
+ sections-construct
+ single-construct
+ parallel-for-construct
+ parallel-sections-construct
+ master-construct
+ critical-construct
+ atomic-construct
+ ordered-construct
+
+ parallel-construct:
+ parallel-directive structured-block
+
+ for-construct:
+ for-directive iteration-statement
+
+ sections-construct:
+ sections-directive section-scope
+
+ single-construct:
+ single-directive structured-block
+
+ parallel-for-construct:
+ parallel-for-directive iteration-statement
+
+ parallel-sections-construct:
+ parallel-sections-directive section-scope
+
+ master-construct:
+ master-directive structured-block
+
+ critical-construct:
+ critical-directive structured-block
+
+ atomic-construct:
+ atomic-directive expression-statement
+
+ ordered-construct:
+ ordered-directive structured-block */
+
+static void
+c_parser_statement (c_parser *parser)
+{
+ while (c_parser_next_token_is_keyword (parser, RID_CASE)
+ || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+ || (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+ c_parser_label (parser);
+ c_parser_statement_after_labels (parser);
+}
+
+/* Parse a statement, other than a labeled statement. */
+
+static void
+c_parser_statement_after_labels (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree stmt = NULL_TREE;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_OPEN_BRACE:
+ add_stmt (c_parser_compound_statement (parser));
+ break;
+ case CPP_KEYWORD:
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_IF:
+ c_parser_if_statement (parser);
+ break;
+ case RID_SWITCH:
+ c_parser_switch_statement (parser);
+ break;
+ case RID_WHILE:
+ c_parser_while_statement (parser);
+ break;
+ case RID_DO:
+ c_parser_do_statement (parser);
+ break;
+ case RID_FOR:
+ c_parser_for_statement (parser);
+ break;
+ case RID_GOTO:
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ stmt = c_finish_goto_label (c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ }
+ else if (c_parser_next_token_is (parser, CPP_MULT))
+ {
+ c_parser_consume_token (parser);
+ stmt = c_finish_goto_ptr (c_parser_expression (parser).value);
+ }
+ else
+ c_parser_error (parser, "expected identifier or %<*%>");
+ goto expect_semicolon;
+ case RID_CONTINUE:
+ c_parser_consume_token (parser);
+ stmt = c_finish_bc_stmt (&c_cont_label, false);
+ goto expect_semicolon;
+ case RID_BREAK:
+ c_parser_consume_token (parser);
+ stmt = c_finish_bc_stmt (&c_break_label, true);
+ goto expect_semicolon;
+ case RID_RETURN:
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ stmt = c_finish_return (NULL_TREE);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ stmt = c_finish_return (c_parser_expression_conv (parser).value);
+ goto expect_semicolon;
+ }
+ break;
+ case RID_ASM:
+ stmt = c_parser_asm_statement (parser);
+ break;
+ case RID_AT_THROW:
+ gcc_assert (c_dialect_objc ());
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ stmt = objc_build_throw_stmt (NULL_TREE);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ stmt
+ = objc_build_throw_stmt (c_parser_expression (parser).value);
+ goto expect_semicolon;
+ }
+ break;
+ case RID_AT_TRY:
+ gcc_assert (c_dialect_objc ());
+ c_parser_objc_try_catch_statement (parser);
+ break;
+ case RID_AT_SYNCHRONIZED:
+ gcc_assert (c_dialect_objc ());
+ c_parser_objc_synchronized_statement (parser);
+ break;
+ default:
+ goto expr_stmt;
+ }
+ break;
+ case CPP_SEMICOLON:
+ c_parser_consume_token (parser);
+ break;
+ case CPP_CLOSE_PAREN:
+ case CPP_CLOSE_SQUARE:
+ /* Avoid infinite loop in error recovery:
+ c_parser_skip_until_found stops at a closing nesting
+ delimiter without consuming it, but here we need to consume
+ it to proceed further. */
+ c_parser_error (parser, "expected statement");
+ c_parser_consume_token (parser);
+ break;
+ case CPP_PRAGMA:
+ c_parser_pragma (parser, pragma_stmt);
+ break;
+ default:
+ expr_stmt:
+ stmt = c_finish_expr_stmt (c_parser_expression_conv (parser).value);
+ expect_semicolon:
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ break;
+ }
+ /* Two cases cannot and do not have line numbers associated: If stmt
+ is degenerate, such as "2;", then stmt is an INTEGER_CST, which
+ cannot hold line numbers. But that's OK because the statement
+ will either be changed to a MODIFY_EXPR during gimplification of
+ the statement expr, or discarded. If stmt was compound, but
+ without new variables, we will have skipped the creation of a
+ BIND and will have a bare STATEMENT_LIST. But that's OK because
+ (recursively) all of the component statements should already have
+ line numbers assigned. ??? Can we discard no-op statements
+ earlier? */
+ if (stmt && EXPR_P (stmt))
+ SET_EXPR_LOCATION (stmt, loc);
+}
+
+/* Parse a parenthesized condition from an if, do or while statement.
+
+ condition:
+ ( expression )
+*/
+static tree
+c_parser_paren_condition (c_parser *parser)
+{
+ location_t loc;
+ tree cond;
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return error_mark_node;
+ loc = c_parser_peek_token (parser)->location;
+ cond = c_objc_common_truthvalue_conversion
+ (c_parser_expression_conv (parser).value);
+ if (EXPR_P (cond))
+ SET_EXPR_LOCATION (cond, loc);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return cond;
+}
+
+/* Parse a statement which is a block in C99. */
+
+static tree
+c_parser_c99_block_statement (c_parser *parser)
+{
+ tree block = c_begin_compound_stmt (flag_isoc99);
+ c_parser_statement (parser);
+ return c_end_compound_stmt (block, flag_isoc99);
+}
+
+/* Parse the body of an if statement or the else half thereof. 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 -Wextra warnings. */
+
+static tree
+c_parser_if_body (c_parser *parser, bool *if_p)
+{
+ tree block = c_begin_compound_stmt (flag_isoc99);
+ while (c_parser_next_token_is_keyword (parser, RID_CASE)
+ || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+ || (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+ c_parser_label (parser);
+ *if_p = c_parser_next_token_is_keyword (parser, RID_IF);
+ if (extra_warnings && c_parser_next_token_is (parser, CPP_SEMICOLON))
+ add_stmt (build_empty_stmt ());
+ c_parser_statement_after_labels (parser);
+ return c_end_compound_stmt (block, flag_isoc99);
+}
+
+/* Parse an if statement (C90 6.6.4, C99 6.8.4).
+
+ if-statement:
+ if ( expression ) statement
+ if ( expression ) statement else statement
+*/
+
+static void
+c_parser_if_statement (c_parser *parser)
+{
+ tree block;
+ location_t loc;
+ tree cond;
+ bool first_if = false, second_if = false;
+ tree first_body, second_body;
+ 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);
+ first_body = c_parser_if_body (parser, &first_if);
+ if (c_parser_next_token_is_keyword (parser, RID_ELSE))
+ {
+ c_parser_consume_token (parser);
+ second_body = c_parser_if_body (parser, &second_if);
+ }
+ else
+ second_body = NULL_TREE;
+ c_finish_if_stmt (loc, cond, first_body, second_body, first_if);
+ add_stmt (c_end_compound_stmt (block, flag_isoc99));
+}
+
+/* Parse a switch statement (C90 6.6.4, C99 6.8.4).
+
+ switch-statement:
+ switch (expression) statement
+*/
+
+static void
+c_parser_switch_statement (c_parser *parser)
+{
+ tree block, expr, body, save_break;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH));
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (flag_isoc99);
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr = c_parser_expression (parser).value;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ else
+ expr = error_mark_node;
+ c_start_case (expr);
+ save_break = c_break_label;
+ c_break_label = NULL_TREE;
+ body = c_parser_c99_block_statement (parser);
+ c_finish_case (body);
+ if (c_break_label)
+ add_stmt (build1 (LABEL_EXPR, void_type_node, c_break_label));
+ c_break_label = save_break;
+ add_stmt (c_end_compound_stmt (block, flag_isoc99));
+}
+
+/* Parse a while statement (C90 6.6.5, C99 6.8.5).
+
+ while-statement:
+ while (expression) statement
+*/
+
+static void
+c_parser_while_statement (c_parser *parser)
+{
+ tree block, cond, body, save_break, save_cont;
+ location_t loc;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE));
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (flag_isoc99);
+ loc = c_parser_peek_token (parser)->location;
+ cond = c_parser_paren_condition (parser);
+ save_break = c_break_label;
+ c_break_label = NULL_TREE;
+ save_cont = c_cont_label;
+ c_cont_label = NULL_TREE;
+ body = c_parser_c99_block_statement (parser);
+ c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, true);
+ add_stmt (c_end_compound_stmt (block, flag_isoc99));
+ c_break_label = save_break;
+ c_cont_label = save_cont;
+}
+
+/* Parse a do statement (C90 6.6.5, C99 6.8.5).
+
+ do-statement:
+ do statement while ( expression ) ;
+*/
+
+static void
+c_parser_do_statement (c_parser *parser)
+{
+ tree block, cond, body, save_break, save_cont, new_break, new_cont;
+ location_t loc;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO));
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (flag_isoc99);
+ loc = c_parser_peek_token (parser)->location;
+ save_break = c_break_label;
+ c_break_label = NULL_TREE;
+ save_cont = c_cont_label;
+ c_cont_label = NULL_TREE;
+ body = c_parser_c99_block_statement (parser);
+ c_parser_require_keyword (parser, RID_WHILE, "expected %<while%>");
+ new_break = c_break_label;
+ c_break_label = save_break;
+ new_cont = c_cont_label;
+ c_cont_label = save_cont;
+ cond = c_parser_paren_condition (parser);
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ c_finish_loop (loc, cond, NULL, body, new_break, new_cont, false);
+ add_stmt (c_end_compound_stmt (block, flag_isoc99));
+}
+
+/* Parse a for statement (C90 6.6.5, C99 6.8.5).
+
+ for-statement:
+ for ( expression[opt] ; expression[opt] ; expression[opt] ) statement
+ for ( nested-declaration expression[opt] ; expression[opt] ) statement
+
+ The form with a declaration is new in C99.
+
+ ??? In accordance with the old parser, the declaration may be a
+ nested function, which is then rejected in check_for_loop_decls,
+ but does it make any sense for this to be included in the grammar?
+ Note in particular that the nested function does not include a
+ trailing ';', whereas the "declaration" production includes one.
+ Also, can we reject bad declarations earlier and cheaper than
+ check_for_loop_decls? */
+
+static void
+c_parser_for_statement (c_parser *parser)
+{
+ tree block, cond, incr, save_break, save_cont, body;
+ location_t loc;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR));
+ loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (flag_isoc99);
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ /* Parse the initialization declaration or expression. */
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ c_parser_consume_token (parser);
+ c_finish_expr_stmt (NULL_TREE);
+ }
+ else if (c_parser_next_token_starts_declspecs (parser))
+ {
+ c_parser_declaration_or_fndef (parser, true, true, true, true);
+ check_for_loop_decls ();
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+ {
+ /* __extension__ can start a declaration, but is also an
+ unary operator that can start an expression. Consume all
+ but the last of a possible series of __extension__ to
+ determine which. */
+ while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD
+ && (c_parser_peek_2nd_token (parser)->keyword
+ == RID_EXTENSION))
+ c_parser_consume_token (parser);
+ if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser)))
+ {
+ int ext;
+ ext = disable_extension_diagnostics ();
+ c_parser_consume_token (parser);
+ c_parser_declaration_or_fndef (parser, true, true, true, true);
+ restore_extension_diagnostics (ext);
+ check_for_loop_decls ();
+ }
+ else
+ goto init_expr;
+ }
+ else
+ {
+ init_expr:
+ c_finish_expr_stmt (c_parser_expression (parser).value);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ /* Parse the loop condition. */
+ loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ c_parser_consume_token (parser);
+ cond = NULL_TREE;
+ }
+ else
+ {
+ tree ocond = c_parser_expression_conv (parser).value;
+ cond = c_objc_common_truthvalue_conversion (ocond);
+ if (EXPR_P (cond))
+ SET_EXPR_LOCATION (cond, loc);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ /* Parse the increment expression. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ incr = c_process_expr_stmt (NULL_TREE);
+ else
+ incr = c_process_expr_stmt (c_parser_expression (parser).value);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ else
+ {
+ cond = error_mark_node;
+ incr = error_mark_node;
+ }
+ save_break = c_break_label;
+ c_break_label = NULL_TREE;
+ save_cont = c_cont_label;
+ c_cont_label = NULL_TREE;
+ body = c_parser_c99_block_statement (parser);
+ c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, true);
+ add_stmt (c_end_compound_stmt (block, flag_isoc99));
+ c_break_label = save_break;
+ c_cont_label = save_cont;
+}
+
+/* Parse an asm statement, a GNU extension. This is a full-blown asm
+ statement with inputs, outputs, clobbers, and volatile tag
+ allowed.
+
+ asm-statement:
+ asm type-qualifier[opt] ( asm-argument ) ;
+
+ asm-argument:
+ asm-string-literal
+ asm-string-literal : asm-operands[opt]
+ asm-string-literal : asm-operands[opt] : asm-operands[opt]
+ asm-string-literal : asm-operands[opt] : asm-operands[opt] : asm-clobbers
+
+ Qualifiers other than volatile are accepted in the syntax but
+ warned for. */
+
+static tree
+c_parser_asm_statement (c_parser *parser)
+{
+ tree quals, str, outputs, inputs, clobbers, ret;
+ bool simple;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is_keyword (parser, RID_VOLATILE))
+ {
+ quals = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_CONST)
+ || c_parser_next_token_is_keyword (parser, RID_RESTRICT))
+ {
+ warning (0, "%E qualifier ignored on asm",
+ c_parser_peek_token (parser)->value);
+ quals = NULL_TREE;
+ c_parser_consume_token (parser);
+ }
+ else
+ quals = NULL_TREE;
+ /* ??? Follow the C++ parser rather than using the
+ c_lex_string_translate kludge. */
+ c_lex_string_translate = 0;
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ c_lex_string_translate = 1;
+ return NULL_TREE;
+ }
+ str = c_parser_asm_string_literal (parser);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ simple = true;
+ outputs = NULL_TREE;
+ inputs = NULL_TREE;
+ clobbers = NULL_TREE;
+ goto done_asm;
+ }
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
+ {
+ c_lex_string_translate = 1;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return NULL_TREE;
+ }
+ simple = false;
+ /* Parse outputs. */
+ if (c_parser_next_token_is (parser, CPP_COLON)
+ || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ outputs = NULL_TREE;
+ else
+ outputs = c_parser_asm_operands (parser, false);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ inputs = NULL_TREE;
+ clobbers = NULL_TREE;
+ goto done_asm;
+ }
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
+ {
+ c_lex_string_translate = 1;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return NULL_TREE;
+ }
+ /* Parse inputs. */
+ if (c_parser_next_token_is (parser, CPP_COLON)
+ || c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ inputs = NULL_TREE;
+ else
+ inputs = c_parser_asm_operands (parser, true);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ clobbers = NULL_TREE;
+ goto done_asm;
+ }
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%> or %<)%>"))
+ {
+ c_lex_string_translate = 1;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return NULL_TREE;
+ }
+ /* Parse clobbers. */
+ clobbers = c_parser_asm_clobbers (parser);
+ done_asm:
+ c_lex_string_translate = 1;
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return NULL_TREE;
+ }
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ ret = build_asm_stmt (quals, build_asm_expr (str, outputs, inputs,
+ clobbers, simple));
+ return ret;
+}
+
+/* Parse asm operands, a GNU extension. If CONVERT_P (for inputs but
+ not outputs), apply the default conversion of functions and arrays
+ to pointers.
+
+ asm-operands:
+ asm-operand
+ asm-operands , asm-operand
+
+ asm-operand:
+ asm-string-literal ( expression )
+ [ identifier ] asm-string-literal ( expression )
+*/
+
+static tree
+c_parser_asm_operands (c_parser *parser, bool convert_p)
+{
+ tree list = NULL_TREE;
+ while (true)
+ {
+ tree name, str;
+ struct c_expr expr;
+ if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ tree id = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ name = build_string (IDENTIFIER_LENGTH (id),
+ IDENTIFIER_POINTER (id));
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
+ return NULL_TREE;
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ }
+ else
+ name = NULL_TREE;
+ str = c_parser_asm_string_literal (parser);
+ if (str == NULL_TREE)
+ return NULL_TREE;
+ c_lex_string_translate = 1;
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ c_lex_string_translate = 0;
+ return NULL_TREE;
+ }
+ expr = c_parser_expression (parser);
+ if (convert_p)
+ expr = default_function_array_conversion (expr);
+ c_lex_string_translate = 0;
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return NULL_TREE;
+ }
+ list = chainon (list, build_tree_list (build_tree_list (name, str),
+ expr.value));
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ return list;
+}
+
+/* Parse asm clobbers, a GNU extension.
+
+ asm-clobbers:
+ asm-string-literal
+ asm-clobbers , asm-string-literal
+*/
+
+static tree
+c_parser_asm_clobbers (c_parser *parser)
+{
+ tree list = NULL_TREE;
+ while (true)
+ {
+ tree str = c_parser_asm_string_literal (parser);
+ if (str)
+ list = tree_cons (NULL_TREE, str, list);
+ else
+ return NULL_TREE;
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ return list;
+}
+
+/* Parse an expression other than a compound expression; that is, an
+ assignment expression (C90 6.3.16, C99 6.5.16). If AFTER is not
+ NULL then it is an Objective-C message expression which is the
+ primary-expression starting the expression as an initializer.
+
+ assignment-expression:
+ conditional-expression
+ unary-expression assignment-operator assignment-expression
+
+ assignment-operator: one of
+ = *= /= %= += -= <<= >>= &= ^= |=
+
+ In GNU C we accept any conditional expression on the LHS and
+ diagnose the invalid lvalue rather than producing a syntax
+ error. */
+
+static struct c_expr
+c_parser_expr_no_commas (c_parser *parser, struct c_expr *after)
+{
+ struct c_expr lhs, rhs, ret;
+ enum tree_code code;
+ gcc_assert (!after || c_dialect_objc ());
+ lhs = c_parser_conditional_expression (parser, after);
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_EQ:
+ code = NOP_EXPR;
+ break;
+ case CPP_MULT_EQ:
+ code = MULT_EXPR;
+ break;
+ case CPP_DIV_EQ:
+ code = TRUNC_DIV_EXPR;
+ break;
+ case CPP_MOD_EQ:
+ code = TRUNC_MOD_EXPR;
+ break;
+ case CPP_PLUS_EQ:
+ code = PLUS_EXPR;
+ break;
+ case CPP_MINUS_EQ:
+ code = MINUS_EXPR;
+ break;
+ case CPP_LSHIFT_EQ:
+ code = LSHIFT_EXPR;
+ break;
+ case CPP_RSHIFT_EQ:
+ code = RSHIFT_EXPR;
+ break;
+ case CPP_AND_EQ:
+ code = BIT_AND_EXPR;
+ break;
+ case CPP_XOR_EQ:
+ code = BIT_XOR_EXPR;
+ break;
+ case CPP_OR_EQ:
+ code = BIT_IOR_EXPR;
+ break;
+ default:
+ return lhs;
+ }
+ c_parser_consume_token (parser);
+ rhs = c_parser_expr_no_commas (parser, NULL);
+ rhs = default_function_array_conversion (rhs);
+ ret.value = build_modify_expr (lhs.value, code, rhs.value);
+ if (code == NOP_EXPR)
+ ret.original_code = MODIFY_EXPR;
+ else
+ {
+ TREE_NO_WARNING (ret.value) = 1;
+ ret.original_code = ERROR_MARK;
+ }
+ return ret;
+}
+
+/* Parse a conditional expression (C90 6.3.15, C99 6.5.15). If AFTER
+ is not NULL then it is an Objective-C message expression which is
+ the primary-expression starting the expression as an initializer.
+
+ conditional-expression:
+ logical-OR-expression
+ logical-OR-expression ? expression : conditional-expression
+
+ GNU extensions:
+
+ conditional-expression:
+ logical-OR-expression ? : conditional-expression
+*/
+
+static struct c_expr
+c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
+{
+ struct c_expr cond, exp1, exp2, ret;
+ 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 = default_function_array_conversion (cond);
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ if (pedantic)
+ pedwarn ("ISO C forbids omitting the middle term of a ?: expression");
+ /* Make sure first operand is calculated only once. */
+ exp1.value = save_expr (default_conversion (cond.value));
+ cond.value = c_objc_common_truthvalue_conversion (exp1.value);
+ skip_evaluation += cond.value == truthvalue_true_node;
+ }
+ else
+ {
+ cond.value
+ = c_objc_common_truthvalue_conversion
+ (default_conversion (cond.value));
+ skip_evaluation += cond.value == truthvalue_false_node;
+ exp1 = c_parser_expression_conv (parser);
+ skip_evaluation += ((cond.value == truthvalue_true_node)
+ - (cond.value == truthvalue_false_node));
+ }
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ {
+ skip_evaluation -= cond.value == truthvalue_true_node;
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ return ret;
+ }
+ exp2 = c_parser_conditional_expression (parser, NULL);
+ exp2 = default_function_array_conversion (exp2);
+ skip_evaluation -= cond.value == truthvalue_true_node;
+ ret.value = build_conditional_expr (cond.value, exp1.value, exp2.value);
+ ret.original_code = ERROR_MARK;
+ return ret;
+}
+
+/* Parse a binary expression; that is, a logical-OR-expression (C90
+ 6.3.5-6.3.14, C99 6.5.5-6.5.14). If AFTER is not NULL then it is
+ an Objective-C message expression which is the primary-expression
+ starting the expression as an initializer.
+
+ multiplicative-expression:
+ cast-expression
+ multiplicative-expression * cast-expression
+ multiplicative-expression / cast-expression
+ multiplicative-expression % cast-expression
+
+ additive-expression:
+ multiplicative-expression
+ additive-expression + multiplicative-expression
+ additive-expression - multiplicative-expression
+
+ shift-expression:
+ additive-expression
+ shift-expression << additive-expression
+ shift-expression >> additive-expression
+
+ relational-expression:
+ shift-expression
+ relational-expression < shift-expression
+ relational-expression > shift-expression
+ relational-expression <= shift-expression
+ relational-expression >= shift-expression
+
+ equality-expression:
+ relational-expression
+ equality-expression == relational-expression
+ equality-expression != relational-expression
+
+ AND-expression:
+ equality-expression
+ AND-expression & equality-expression
+
+ exclusive-OR-expression:
+ AND-expression
+ exclusive-OR-expression ^ AND-expression
+
+ inclusive-OR-expression:
+ exclusive-OR-expression
+ inclusive-OR-expression | exclusive-OR-expression
+
+ logical-AND-expression:
+ inclusive-OR-expression
+ logical-AND-expression && inclusive-OR-expression
+
+ logical-OR-expression:
+ logical-AND-expression
+ logical-OR-expression || logical-AND-expression
+*/
+
+static struct c_expr
+c_parser_binary_expression (c_parser *parser, struct c_expr *after)
+{
+ /* A binary expression is parsed using operator-precedence parsing,
+ with the operands being cast expressions. All the binary
+ operators are left-associative. Thus a binary expression is of
+ form:
+
+ E0 op1 E1 op2 E2 ...
+
+ which we represent on a stack. On the stack, the precedence
+ levels are strictly increasing. When a new operator is
+ encountered of higher precedence than that at the top of the
+ stack, it is pushed; its LHS is the top expression, and its RHS
+ is everything parsed until it is popped. When a new operator is
+ encountered with precedence less than or equal to that at the top
+ of the stack, triples E[i-1] op[i] E[i] are popped and replaced
+ by the result of the operation until the operator at the top of
+ the stack has lower precedence than the new operator or there is
+ only one element on the stack; then the top expression is the LHS
+ of the new operator. In the case of logical AND and OR
+ expressions, we also need to adjust skip_evaluation as
+ appropriate when the operators are pushed and popped. */
+
+ /* The precedence levels, where 0 is a dummy lowest level used for
+ the bottom of the stack. */
+ enum prec {
+ PREC_NONE,
+ PREC_LOGOR,
+ PREC_LOGAND,
+ PREC_BITOR,
+ PREC_BITXOR,
+ PREC_BITAND,
+ PREC_EQ,
+ PREC_REL,
+ PREC_SHIFT,
+ PREC_ADD,
+ PREC_MULT,
+ NUM_PRECS
+ };
+ struct {
+ /* The expression at this stack level. */
+ struct c_expr expr;
+ /* The precedence of the operator on its left, PREC_NONE at the
+ bottom of the stack. */
+ enum prec prec;
+ /* The operation on its left. */
+ enum tree_code op;
+ } stack[NUM_PRECS];
+ int sp;
+#define POP \
+ do { \
+ switch (stack[sp].op) \
+ { \
+ case TRUTH_ANDIF_EXPR: \
+ skip_evaluation -= stack[sp - 1].expr.value == truthvalue_false_node; \
+ break; \
+ case TRUTH_ORIF_EXPR: \
+ skip_evaluation -= stack[sp - 1].expr.value == truthvalue_true_node; \
+ break; \
+ default: \
+ break; \
+ } \
+ stack[sp - 1].expr \
+ = default_function_array_conversion (stack[sp - 1].expr); \
+ stack[sp].expr \
+ = default_function_array_conversion (stack[sp].expr); \
+ stack[sp - 1].expr = parser_build_binary_op (stack[sp].op, \
+ stack[sp - 1].expr, \
+ stack[sp].expr); \
+ sp--; \
+ } while (0)
+ gcc_assert (!after || c_dialect_objc ());
+ stack[0].expr = c_parser_cast_expression (parser, after);
+ stack[0].prec = PREC_NONE;
+ sp = 0;
+ while (true)
+ {
+ enum prec oprec;
+ enum tree_code ocode;
+ if (parser->error)
+ goto out;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_MULT:
+ oprec = PREC_MULT;
+ ocode = MULT_EXPR;
+ break;
+ case CPP_DIV:
+ oprec = PREC_MULT;
+ ocode = TRUNC_DIV_EXPR;
+ break;
+ case CPP_MOD:
+ oprec = PREC_MULT;
+ ocode = TRUNC_MOD_EXPR;
+ break;
+ case CPP_PLUS:
+ oprec = PREC_ADD;
+ ocode = PLUS_EXPR;
+ break;
+ case CPP_MINUS:
+ oprec = PREC_ADD;
+ ocode = MINUS_EXPR;
+ break;
+ case CPP_LSHIFT:
+ oprec = PREC_SHIFT;
+ ocode = LSHIFT_EXPR;
+ break;
+ case CPP_RSHIFT:
+ oprec = PREC_SHIFT;
+ ocode = RSHIFT_EXPR;
+ break;
+ case CPP_LESS:
+ oprec = PREC_REL;
+ ocode = LT_EXPR;
+ break;
+ case CPP_GREATER:
+ oprec = PREC_REL;
+ ocode = GT_EXPR;
+ break;
+ case CPP_LESS_EQ:
+ oprec = PREC_REL;
+ ocode = LE_EXPR;
+ break;
+ case CPP_GREATER_EQ:
+ oprec = PREC_REL;
+ ocode = GE_EXPR;
+ break;
+ case CPP_EQ_EQ:
+ oprec = PREC_EQ;
+ ocode = EQ_EXPR;
+ break;
+ case CPP_NOT_EQ:
+ oprec = PREC_EQ;
+ ocode = NE_EXPR;
+ break;
+ case CPP_AND:
+ oprec = PREC_BITAND;
+ ocode = BIT_AND_EXPR;
+ break;
+ case CPP_XOR:
+ oprec = PREC_BITXOR;
+ ocode = BIT_XOR_EXPR;
+ break;
+ case CPP_OR:
+ oprec = PREC_BITOR;
+ ocode = BIT_IOR_EXPR;
+ break;
+ case CPP_AND_AND:
+ oprec = PREC_LOGAND;
+ ocode = TRUTH_ANDIF_EXPR;
+ break;
+ case CPP_OR_OR:
+ oprec = PREC_LOGOR;
+ ocode = TRUTH_ORIF_EXPR;
+ break;
+ default:
+ /* Not a binary operator, so end of the binary
+ expression. */
+ goto out;
+ }
+ c_parser_consume_token (parser);
+ while (oprec <= stack[sp].prec)
+ POP;
+ switch (ocode)
+ {
+ case TRUTH_ANDIF_EXPR:
+ stack[sp].expr
+ = default_function_array_conversion (stack[sp].expr);
+ stack[sp].expr.value = c_objc_common_truthvalue_conversion
+ (default_conversion (stack[sp].expr.value));
+ skip_evaluation += stack[sp].expr.value == truthvalue_false_node;
+ break;
+ case TRUTH_ORIF_EXPR:
+ stack[sp].expr
+ = default_function_array_conversion (stack[sp].expr);
+ stack[sp].expr.value = c_objc_common_truthvalue_conversion
+ (default_conversion (stack[sp].expr.value));
+ skip_evaluation += stack[sp].expr.value == truthvalue_true_node;
+ break;
+ default:
+ break;
+ }
+ sp++;
+ stack[sp].expr = c_parser_cast_expression (parser, NULL);
+ stack[sp].prec = oprec;
+ stack[sp].op = ocode;
+ }
+ out:
+ while (sp > 0)
+ POP;
+ return stack[0].expr;
+#undef POP
+}
+
+/* Parse a cast expression (C90 6.3.4, C99 6.5.4). If AFTER is not
+ NULL then it is an Objective-C message expression which is the
+ primary-expression starting the expression as an initializer.
+
+ cast-expression:
+ unary-expression
+ ( type-name ) unary-expression
+*/
+
+static struct c_expr
+c_parser_cast_expression (c_parser *parser, struct c_expr *after)
+{
+ gcc_assert (!after || c_dialect_objc ());
+ if (after)
+ return c_parser_postfix_expression_after_primary (parser, *after);
+ /* If the expression begins with a parenthesized type name, it may
+ be either a cast or a compound literal; we need to see whether
+ the next character is '{' to tell the difference. If not, it is
+ an unary expression. */
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+ && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+ {
+ struct c_type_name *type_name;
+ struct c_expr ret;
+ struct c_expr expr;
+ c_parser_consume_token (parser);
+ type_name = c_parser_type_name (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ if (type_name == NULL)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ return ret;
+ }
+
+ /* Save casted types in the function's used types hash table. */
+ used_types_insert (type_name->specs->type);
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ return c_parser_postfix_expression_after_paren_type (parser,
+ type_name);
+ expr = c_parser_cast_expression (parser, NULL);
+ expr = default_function_array_conversion (expr);
+ ret.value = c_cast_expr (type_name, expr.value);
+ ret.original_code = ERROR_MARK;
+ return ret;
+ }
+ else
+ return c_parser_unary_expression (parser);
+}
+
+/* Parse an unary expression (C90 6.3.3, C99 6.5.3).
+
+ unary-expression:
+ postfix-expression
+ ++ unary-expression
+ -- unary-expression
+ unary-operator cast-expression
+ sizeof unary-expression
+ sizeof ( type-name )
+
+ unary-operator: one of
+ & * + - ~ !
+
+ GNU extensions:
+
+ unary-expression:
+ __alignof__ unary-expression
+ __alignof__ ( type-name )
+ && identifier
+
+ unary-operator: one of
+ __extension__ __real__ __imag__
+
+ In addition, the GNU syntax treats ++ and -- as unary operators, so
+ they may be applied to cast expressions with errors for non-lvalues
+ given later. */
+
+static struct c_expr
+c_parser_unary_expression (c_parser *parser)
+{
+ int ext;
+ struct c_expr ret, op;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_PLUS_PLUS:
+ c_parser_consume_token (parser);
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_conversion (op);
+ return parser_build_unary_op (PREINCREMENT_EXPR, op);
+ case CPP_MINUS_MINUS:
+ c_parser_consume_token (parser);
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_conversion (op);
+ return parser_build_unary_op (PREDECREMENT_EXPR, op);
+ case CPP_AND:
+ c_parser_consume_token (parser);
+ return parser_build_unary_op (ADDR_EXPR,
+ c_parser_cast_expression (parser, NULL));
+ case CPP_MULT:
+ c_parser_consume_token (parser);
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_conversion (op);
+ ret.value = build_indirect_ref (op.value, "unary *");
+ ret.original_code = ERROR_MARK;
+ return ret;
+ case CPP_PLUS:
+ c_parser_consume_token (parser);
+ if (!c_dialect_objc () && !in_system_header)
+ warning (OPT_Wtraditional,
+ "traditional C rejects the unary plus operator");
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_conversion (op);
+ return parser_build_unary_op (CONVERT_EXPR, op);
+ case CPP_MINUS:
+ c_parser_consume_token (parser);
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_conversion (op);
+ return parser_build_unary_op (NEGATE_EXPR, op);
+ case CPP_COMPL:
+ c_parser_consume_token (parser);
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_conversion (op);
+ return parser_build_unary_op (BIT_NOT_EXPR, op);
+ case CPP_NOT:
+ c_parser_consume_token (parser);
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_conversion (op);
+ return parser_build_unary_op (TRUTH_NOT_EXPR, op);
+ 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);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ ret.value = error_mark_node;
+ }
+ ret.original_code = ERROR_MARK;
+ return ret;
+ case CPP_KEYWORD:
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_SIZEOF:
+ return c_parser_sizeof_expression (parser);
+ case RID_ALIGNOF:
+ return c_parser_alignof_expression (parser);
+ case RID_EXTENSION:
+ c_parser_consume_token (parser);
+ ext = disable_extension_diagnostics ();
+ ret = c_parser_cast_expression (parser, NULL);
+ restore_extension_diagnostics (ext);
+ return ret;
+ case RID_REALPART:
+ c_parser_consume_token (parser);
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_conversion (op);
+ return parser_build_unary_op (REALPART_EXPR, op);
+ case RID_IMAGPART:
+ c_parser_consume_token (parser);
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_conversion (op);
+ return parser_build_unary_op (IMAGPART_EXPR, op);
+ 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;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
+ c_parser_consume_token (parser);
+ skip_evaluation++;
+ in_sizeof++;
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+ && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+ {
+ /* Either sizeof ( type-name ) or sizeof unary-expression
+ starting with a compound literal. */
+ struct c_type_name *type_name;
+ c_parser_consume_token (parser);
+ type_name = c_parser_type_name (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ if (type_name == NULL)
+ {
+ struct c_expr ret;
+ skip_evaluation--;
+ in_sizeof--;
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ return ret;
+ }
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ expr = c_parser_postfix_expression_after_paren_type (parser,
+ type_name);
+ goto sizeof_expr;
+ }
+ /* sizeof ( type-name ). */
+ skip_evaluation--;
+ in_sizeof--;
+ if (type_name->declarator->kind == cdk_array
+ && type_name->declarator->u.array.vla_unspec_p)
+ {
+ /* C99 6.7.5.2p4 */
+ error ("%<[*]%> not allowed in other than a declaration");
+ }
+ return c_expr_sizeof_type (type_name);
+ }
+ else
+ {
+ expr = c_parser_unary_expression (parser);
+ sizeof_expr:
+ skip_evaluation--;
+ in_sizeof--;
+ if (TREE_CODE (expr.value) == COMPONENT_REF
+ && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
+ error ("%<sizeof%> applied to a bit-field");
+ return c_expr_sizeof_expr (expr);
+ }
+}
+
+/* Parse an alignof expression. */
+
+static struct c_expr
+c_parser_alignof_expression (c_parser *parser)
+{
+ struct c_expr expr;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF));
+ c_parser_consume_token (parser);
+ skip_evaluation++;
+ in_alignof++;
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+ && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+ {
+ /* Either __alignof__ ( type-name ) or __alignof__
+ unary-expression starting with a compound literal. */
+ struct c_type_name *type_name;
+ struct c_expr ret;
+ c_parser_consume_token (parser);
+ type_name = c_parser_type_name (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ if (type_name == NULL)
+ {
+ struct c_expr ret;
+ skip_evaluation--;
+ in_alignof--;
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ return ret;
+ }
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ expr = c_parser_postfix_expression_after_paren_type (parser,
+ type_name);
+ goto alignof_expr;
+ }
+ /* alignof ( type-name ). */
+ skip_evaluation--;
+ in_alignof--;
+ ret.value = c_alignof (groktypename (type_name));
+ ret.original_code = ERROR_MARK;
+ return ret;
+ }
+ else
+ {
+ struct c_expr ret;
+ expr = c_parser_unary_expression (parser);
+ alignof_expr:
+ skip_evaluation--;
+ in_alignof--;
+ ret.value = c_alignof_expr (expr.value);
+ ret.original_code = ERROR_MARK;
+ return ret;
+ }
+}
+
+/* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2).
+
+ postfix-expression:
+ primary-expression
+ postfix-expression [ expression ]
+ postfix-expression ( argument-expression-list[opt] )
+ postfix-expression . identifier
+ postfix-expression -> identifier
+ postfix-expression ++
+ postfix-expression --
+ ( type-name ) { initializer-list }
+ ( type-name ) { initializer-list , }
+
+ argument-expression-list:
+ argument-expression
+ argument-expression-list , argument-expression
+
+ primary-expression:
+ identifier
+ constant
+ string-literal
+ ( expression )
+
+ GNU extensions:
+
+ primary-expression:
+ __func__
+ (treated as a keyword in GNU C)
+ __FUNCTION__
+ __PRETTY_FUNCTION__
+ ( compound-statement )
+ __builtin_va_arg ( assignment-expression , type-name )
+ __builtin_offsetof ( type-name , offsetof-member-designator )
+ __builtin_choose_expr ( assignment-expression ,
+ assignment-expression ,
+ assignment-expression )
+ __builtin_types_compatible_p ( type-name , type-name )
+
+ offsetof-member-designator:
+ identifier
+ offsetof-member-designator . identifier
+ offsetof-member-designator [ expression ]
+
+ Objective-C:
+
+ primary-expression:
+ [ objc-receiver objc-message-args ]
+ @selector ( objc-selector-arg )
+ @protocol ( identifier )
+ @encode ( type-name )
+ objc-string-literal
+*/
+
+static struct c_expr
+c_parser_postfix_expression (c_parser *parser)
+{
+ struct c_expr expr, e1, e2, e3;
+ struct c_type_name *t1, *t2;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_NUMBER:
+ case CPP_CHAR:
+ case CPP_WCHAR:
+ expr.value = c_parser_peek_token (parser)->value;
+ expr.original_code = ERROR_MARK;
+ c_parser_consume_token (parser);
+ break;
+ case CPP_STRING:
+ case CPP_WSTRING:
+ expr.value = c_parser_peek_token (parser)->value;
+ expr.original_code = STRING_CST;
+ c_parser_consume_token (parser);
+ break;
+ case CPP_OBJC_STRING:
+ gcc_assert (c_dialect_objc ());
+ expr.value
+ = objc_build_string_object (c_parser_peek_token (parser)->value);
+ expr.original_code = ERROR_MARK;
+ c_parser_consume_token (parser);
+ break;
+ case CPP_NAME:
+ if (c_parser_peek_token (parser)->id_kind != C_ID_ID)
+ {
+ c_parser_error (parser, "expected expression");
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ {
+ tree id = c_parser_peek_token (parser)->value;
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ expr.value = build_external_ref (id,
+ (c_parser_peek_token (parser)->type
+ == CPP_OPEN_PAREN), loc);
+ expr.original_code = ERROR_MARK;
+ }
+ break;
+ case CPP_OPEN_PAREN:
+ /* A parenthesized expression, statement expression or compound
+ literal. */
+ if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE)
+ {
+ /* A statement expression. */
+ tree stmt;
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ if (cur_stmt_list == NULL)
+ {
+ error ("braced-group within expression allowed "
+ "only inside a function");
+ parser->error = true;
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ stmt = c_begin_stmt_expr ();
+ c_parser_compound_statement_nostart (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ if (pedantic)
+ pedwarn ("ISO C forbids braced-groups within expressions");
+ expr.value = c_finish_stmt_expr (stmt);
+ expr.original_code = ERROR_MARK;
+ }
+ else if (c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+ {
+ /* A compound literal. ??? Can we actually get here rather
+ than going directly to
+ c_parser_postfix_expression_after_paren_type from
+ elsewhere? */
+ struct c_type_name *type_name;
+ c_parser_consume_token (parser);
+ type_name = c_parser_type_name (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ if (type_name == NULL)
+ {
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ }
+ else
+ expr = c_parser_postfix_expression_after_paren_type (parser,
+ type_name);
+ }
+ else
+ {
+ /* A parenthesized expression. */
+ c_parser_consume_token (parser);
+ expr = c_parser_expression (parser);
+ if (TREE_CODE (expr.value) == MODIFY_EXPR)
+ TREE_NO_WARNING (expr.value) = 1;
+ expr.original_code = ERROR_MARK;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ }
+ break;
+ case CPP_KEYWORD:
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_FUNCTION_NAME:
+ case RID_PRETTY_FUNCTION_NAME:
+ case RID_C99_FUNCTION_NAME:
+ expr.value = fname_decl (c_parser_peek_token (parser)->keyword,
+ c_parser_peek_token (parser)->value);
+ expr.original_code = ERROR_MARK;
+ c_parser_consume_token (parser);
+ break;
+ case RID_VA_ARG:
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ e1 = c_parser_expr_no_commas (parser, NULL);
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ t1 = c_parser_type_name (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ if (t1 == NULL)
+ {
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ }
+ else
+ {
+ expr.value = build_va_arg (e1.value, groktypename (t1));
+ expr.original_code = ERROR_MARK;
+ }
+ break;
+ case RID_OFFSETOF:
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ t1 = c_parser_type_name (parser);
+ if (t1 == NULL)
+ {
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ {
+ tree type = groktypename (t1);
+ tree offsetof_ref;
+ if (type == error_mark_node)
+ offsetof_ref = error_mark_node;
+ else
+ offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node);
+ /* Parse the second argument to __builtin_offsetof. We
+ must have one identifier, and beyond that we want to
+ accept sub structure and sub array references. */
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ offsetof_ref = build_component_ref
+ (offsetof_ref, c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ while (c_parser_next_token_is (parser, CPP_DOT)
+ || c_parser_next_token_is (parser,
+ CPP_OPEN_SQUARE))
+ {
+ if (c_parser_next_token_is (parser, CPP_DOT))
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is_not (parser,
+ CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ break;
+ }
+ offsetof_ref = build_component_ref
+ (offsetof_ref,
+ c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ tree idx;
+ c_parser_consume_token (parser);
+ idx = c_parser_expression (parser).value;
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ offsetof_ref = build_array_ref (offsetof_ref, idx);
+ }
+ }
+ }
+ else
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ expr.value = fold_offsetof (offsetof_ref, NULL_TREE);
+ expr.original_code = ERROR_MARK;
+ }
+ break;
+ case RID_CHOOSE_EXPR:
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ e1 = c_parser_expr_no_commas (parser, NULL);
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ e2 = c_parser_expr_no_commas (parser, NULL);
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ e3 = c_parser_expr_no_commas (parser, NULL);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ {
+ tree c;
+
+ c = fold (e1.value);
+ if (TREE_CODE (c) != INTEGER_CST)
+ error ("first argument to %<__builtin_choose_expr%> not"
+ " a constant");
+ expr = integer_zerop (c) ? e3 : e2;
+ }
+ break;
+ case RID_TYPES_COMPATIBLE_P:
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ t1 = c_parser_type_name (parser);
+ if (t1 == NULL)
+ {
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ t2 = c_parser_type_name (parser);
+ if (t2 == NULL)
+ {
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ {
+ tree e1, e2;
+
+ e1 = TYPE_MAIN_VARIANT (groktypename (t1));
+ e2 = TYPE_MAIN_VARIANT (groktypename (t2));
+
+ expr.value = comptypes (e1, e2)
+ ? build_int_cst (NULL_TREE, 1)
+ : build_int_cst (NULL_TREE, 0);
+ expr.original_code = ERROR_MARK;
+ }
+ break;
+ case RID_AT_SELECTOR:
+ gcc_assert (c_dialect_objc ());
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ {
+ tree sel = c_parser_objc_selector_arg (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ expr.value = objc_build_selector_expr (sel);
+ expr.original_code = ERROR_MARK;
+ }
+ break;
+ case RID_AT_PROTOCOL:
+ gcc_assert (c_dialect_objc ());
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ {
+ tree id = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ expr.value = objc_build_protocol_expr (id);
+ expr.original_code = ERROR_MARK;
+ }
+ break;
+ case RID_AT_ENCODE:
+ /* Extension to support C-structures in the archiver. */
+ gcc_assert (c_dialect_objc ());
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ t1 = c_parser_type_name (parser);
+ if (t1 == NULL)
+ {
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ break;
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ {
+ tree type = groktypename (t1);
+ expr.value = objc_build_encode_expr (type);
+ expr.original_code = ERROR_MARK;
+ }
+ break;
+ default:
+ c_parser_error (parser, "expected expression");
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ break;
+ case CPP_OPEN_SQUARE:
+ if (c_dialect_objc ())
+ {
+ tree receiver, args;
+ c_parser_consume_token (parser);
+ receiver = c_parser_objc_receiver (parser);
+ args = c_parser_objc_message_args (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ expr.value = objc_build_message_expr (build_tree_list (receiver,
+ args));
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ /* Else fall through to report error. */
+ default:
+ c_parser_error (parser, "expected expression");
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ break;
+ }
+ return c_parser_postfix_expression_after_primary (parser, expr);
+}
+
+/* Parse a postfix expression after a parenthesized type name: the
+ brace-enclosed initializer of a compound literal, possibly followed
+ by some postfix operators. This is separate because it is not
+ possible to tell until after the type name whether a cast
+ expression has a cast or a compound literal, or whether the operand
+ of sizeof is a parenthesized type name or starts with a compound
+ literal. */
+
+static struct c_expr
+c_parser_postfix_expression_after_paren_type (c_parser *parser,
+ struct c_type_name *type_name)
+{
+ tree type;
+ struct c_expr init;
+ struct c_expr expr;
+ start_init (NULL_TREE, NULL, 0);
+ type = groktypename (type_name);
+ if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type))
+ {
+ error ("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 (pedantic && !flag_isoc99)
+ pedwarn ("ISO C90 forbids compound literals");
+ expr.value = build_compound_literal (type, init.value);
+ expr.original_code = ERROR_MARK;
+ return c_parser_postfix_expression_after_primary (parser, expr);
+}
+
+/* Parse a postfix expression after the initial primary or compound
+ literal; that is, parse a series of postfix operators. */
+
+static struct c_expr
+c_parser_postfix_expression_after_primary (c_parser *parser,
+ struct c_expr expr)
+{
+ tree ident, idx, exprlist;
+ while (true)
+ {
+ 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 (expr.value, idx);
+ expr.original_code = ERROR_MARK;
+ break;
+ case CPP_OPEN_PAREN:
+ /* Function call. */
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ exprlist = NULL_TREE;
+ else
+ exprlist = c_parser_expr_list (parser, true);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ expr.value = build_function_call (expr.value, exprlist);
+ expr.original_code = ERROR_MARK;
+ break;
+ case CPP_DOT:
+ /* Structure element reference. */
+ c_parser_consume_token (parser);
+ expr = default_function_array_conversion (expr);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ ident = c_parser_peek_token (parser)->value;
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ return expr;
+ }
+ c_parser_consume_token (parser);
+ expr.value = build_component_ref (expr.value, ident);
+ expr.original_code = ERROR_MARK;
+ break;
+ case CPP_DEREF:
+ /* Structure element reference. */
+ c_parser_consume_token (parser);
+ expr = default_function_array_conversion (expr);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ ident = c_parser_peek_token (parser)->value;
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ return expr;
+ }
+ c_parser_consume_token (parser);
+ expr.value = build_component_ref (build_indirect_ref (expr.value,
+ "->"), ident);
+ expr.original_code = ERROR_MARK;
+ break;
+ case CPP_PLUS_PLUS:
+ /* Postincrement. */
+ c_parser_consume_token (parser);
+ expr = default_function_array_conversion (expr);
+ expr.value = build_unary_op (POSTINCREMENT_EXPR, expr.value, 0);
+ expr.original_code = ERROR_MARK;
+ break;
+ case CPP_MINUS_MINUS:
+ /* Postdecrement. */
+ c_parser_consume_token (parser);
+ expr = default_function_array_conversion (expr);
+ expr.value = build_unary_op (POSTDECREMENT_EXPR, expr.value, 0);
+ expr.original_code = ERROR_MARK;
+ break;
+ default:
+ return expr;
+ }
+ }
+}
+
+/* Parse an expression (C90 6.3.17, C99 6.5.17).
+
+ expression:
+ assignment-expression
+ expression , assignment-expression
+*/
+
+static struct c_expr
+c_parser_expression (c_parser *parser)
+{
+ struct c_expr expr;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ while (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ struct c_expr next;
+ c_parser_consume_token (parser);
+ next = c_parser_expr_no_commas (parser, NULL);
+ next = default_function_array_conversion (next);
+ expr.value = build_compound_expr (expr.value, next.value);
+ expr.original_code = COMPOUND_EXPR;
+ }
+ return expr;
+}
+
+/* Parse an expression and convert functions or arrays to
+ pointers. */
+
+static struct c_expr
+c_parser_expression_conv (c_parser *parser)
+{
+ struct c_expr expr;
+ expr = c_parser_expression (parser);
+ expr = default_function_array_conversion (expr);
+ return expr;
+}
+
+/* Parse a non-empty list of expressions. If CONVERT_P, convert
+ functions and arrays to pointers.
+
+ nonempty-expr-list:
+ assignment-expression
+ nonempty-expr-list , assignment-expression
+*/
+
+static tree
+c_parser_expr_list (c_parser *parser, bool convert_p)
+{
+ struct c_expr expr;
+ tree ret, cur;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ if (convert_p)
+ expr = default_function_array_conversion (expr);
+ ret = cur = build_tree_list (NULL_TREE, expr.value);
+ while (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ expr = c_parser_expr_no_commas (parser, NULL);
+ if (convert_p)
+ expr = default_function_array_conversion (expr);
+ cur = TREE_CHAIN (cur) = build_tree_list (NULL_TREE, expr.value);
+ }
+ return ret;
+}
+
+
+/* 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))
+ {
+ if (pedantic)
+ pedwarn ("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_AT_PRIVATE))
+ {
+ c_parser_consume_token (parser);
+ objc_set_visibility (2);
+ continue;
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_PROTECTED))
+ {
+ c_parser_consume_token (parser);
+ objc_set_visibility (0);
+ continue;
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_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_AT_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);
+ objc_pq_context = 1;
+ objc_start_protocol (id, proto);
+ c_parser_objc_methodprotolist (parser);
+ c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
+ objc_pq_context = 0;
+ 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);
+ objc_pq_context = 1;
+ decl = c_parser_objc_method_decl (parser);
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ c_parser_consume_token (parser);
+ if (pedantic)
+ pedwarn ("extra semicolon in method definition specified");
+ }
+ if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ c_parser_error (parser, "expected %<{%>");
+ return;
+ }
+ objc_pq_context = 0;
+ 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:
+ if (pedantic)
+ pedwarn ("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. */
+ objc_pq_context = 1;
+ decl = c_parser_objc_method_decl (parser);
+ /* Forget protocol qualifiers here. */
+ objc_pq_context = 0;
+ 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 *typename = 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))
+ typename = c_parser_type_name (parser);
+ if (typename)
+ type = groktypename (typename);
+ 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_AT_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_AT_CATCH))
+ {
+ struct c_parm *parm;
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ break;
+ parm = c_parser_parameter_declaration (parser, NULL_TREE);
+ if (parm == NULL)
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ break;
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ objc_begin_catch_clause (grokparm (parm));
+ if (c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ c_parser_compound_statement_nostart (parser);
+ objc_finish_catch_clause ();
+ }
+ if (c_parser_next_token_is_keyword (parser, RID_AT_FINALLY))
+ {
+ location_t finloc;
+ tree finstmt;
+ c_parser_consume_token (parser);
+ finloc = c_parser_peek_token (parser)->location;
+ finstmt = c_parser_compound_statement (parser);
+ objc_build_finally_clause (finloc, finstmt);
+ }
+ objc_finish_try_stmt ();
+}
+
+/* Parse an objc-synchronized-statement.
+
+ objc-synchronized-statement:
+ @synchronized ( expression ) compound-statement
+*/
+
+static void
+c_parser_objc_synchronized_statement (c_parser *parser)
+{
+ location_t loc;
+ tree expr, stmt;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNCHRONIZED));
+ c_parser_consume_token (parser);
+ loc = c_parser_peek_token (parser)->location;
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr = c_parser_expression (parser).value;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ else
+ expr = error_mark_node;
+ stmt = c_parser_compound_statement (parser);
+ objc_build_synchronized (loc, expr, stmt);
+}
+
+/* Parse an objc-selector; return NULL_TREE without an error if the
+ next token is not an objc-selector.
+
+ objc-selector:
+ identifier
+ one of
+ enum struct union if else while do for switch case default
+ break continue return goto asm sizeof typeof __alignof
+ unsigned long const short volatile signed restrict _Complex
+ in out inout bycopy byref oneway int char float double void _Bool
+
+ ??? Why this selection of keywords but not, for example, storage
+ class specifiers? */
+
+static tree
+c_parser_objc_selector (c_parser *parser)
+{
+ c_token *token = c_parser_peek_token (parser);
+ tree value = token->value;
+ if (token->type == CPP_NAME)
+ {
+ c_parser_consume_token (parser);
+ return value;
+ }
+ if (token->type != CPP_KEYWORD)
+ return NULL_TREE;
+ switch (token->keyword)
+ {
+ case RID_ENUM:
+ case RID_STRUCT:
+ case RID_UNION:
+ case RID_IF:
+ case RID_ELSE:
+ case RID_WHILE:
+ case RID_DO:
+ case RID_FOR:
+ case RID_SWITCH:
+ case RID_CASE:
+ case RID_DEFAULT:
+ case RID_BREAK:
+ case RID_CONTINUE:
+ case RID_RETURN:
+ case RID_GOTO:
+ case RID_ASM:
+ case RID_SIZEOF:
+ case RID_TYPEOF:
+ case RID_ALIGNOF:
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_CONST:
+ case RID_SHORT:
+ case RID_VOLATILE:
+ case RID_SIGNED:
+ case RID_RESTRICT:
+ case RID_COMPLEX:
+ case RID_IN:
+ case RID_OUT:
+ case RID_INOUT:
+ case RID_BYCOPY:
+ case RID_BYREF:
+ case RID_ONEWAY:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_BOOL:
+ c_parser_consume_token (parser);
+ return value;
+ default:
+ return NULL_TREE;
+ }
+}
+
+/* Parse an objc-selector-arg.
+
+ objc-selector-arg:
+ objc-selector
+ objc-keywordname-list
+
+ objc-keywordname-list:
+ objc-keywordname
+ objc-keywordname-list objc-keywordname
+
+ objc-keywordname:
+ objc-selector :
+ :
+*/
+
+static tree
+c_parser_objc_selector_arg (c_parser *parser)
+{
+ tree sel = c_parser_objc_selector (parser);
+ tree list = NULL_TREE;
+ if (sel && c_parser_next_token_is_not (parser, CPP_COLON))
+ return sel;
+ while (true)
+ {
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ return list;
+ list = chainon (list, build_tree_list (sel, NULL_TREE));
+ sel = c_parser_objc_selector (parser);
+ if (!sel && c_parser_next_token_is_not (parser, CPP_COLON))
+ break;
+ }
+ return list;
+}
+
+/* Parse an objc-receiver.
+
+ objc-receiver:
+ expression
+ class-name
+ type-name
+*/
+
+static tree
+c_parser_objc_receiver (c_parser *parser)
+{
+ if (c_parser_peek_token (parser)->type == CPP_NAME
+ && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME
+ || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
+ {
+ tree id = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ return objc_get_class_reference (id);
+ }
+ return c_parser_expression (parser).value;
+}
+
+/* Parse objc-message-args.
+
+ objc-message-args:
+ objc-selector
+ objc-keywordarg-list
+
+ objc-keywordarg-list:
+ objc-keywordarg
+ objc-keywordarg-list objc-keywordarg
+
+ objc-keywordarg:
+ objc-selector : objc-keywordexpr
+ : objc-keywordexpr
+*/
+
+static tree
+c_parser_objc_message_args (c_parser *parser)
+{
+ tree sel = c_parser_objc_selector (parser);
+ tree list = NULL_TREE;
+ if (sel && c_parser_next_token_is_not (parser, CPP_COLON))
+ return sel;
+ while (true)
+ {
+ tree keywordexpr;
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ return list;
+ keywordexpr = c_parser_objc_keywordexpr (parser);
+ list = chainon (list, build_tree_list (sel, keywordexpr));
+ sel = c_parser_objc_selector (parser);
+ if (!sel && c_parser_next_token_is_not (parser, CPP_COLON))
+ break;
+ }
+ return list;
+}
+
+/* Parse an objc-keywordexpr.
+
+ objc-keywordexpr:
+ nonempty-expr-list
+*/
+
+static tree
+c_parser_objc_keywordexpr (c_parser *parser)
+{
+ tree list = c_parser_expr_list (parser, true);
+ if (TREE_CHAIN (list) == NULL_TREE)
+ {
+ /* Just return the expression, remove a level of
+ indirection. */
+ return TREE_VALUE (list);
+ }
+ else
+ {
+ /* We have a comma expression, we will collapse later. */
+ return list;
+ }
+}
+
+
+/* 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_THREADPRIVATE:
+ c_parser_omp_threadprivate (parser);
+ return false;
+
+ case PRAGMA_OMP_SECTION:
+ error ("%<#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 ("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;
+ }
+ }
+
+ 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 tree_code code, const char *name)
+{
+ tree c;
+
+ for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == code)
+ {
+ error ("too many %qs clauses", name);
+ break;
+ }
+}
+
+/* OpenMP 2.5:
+ variable-list:
+ identifier
+ variable-list , identifier
+
+ If KIND is nonzero, create the appropriate node and install the decl
+ in OMP_CLAUSE_DECL and add the node to the head of the list.
+
+ If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE;
+ return the list created. */
+
+static tree
+c_parser_omp_variable_list (c_parser *parser, enum omp_clause_code kind,
+ tree list)
+{
+ if (c_parser_next_token_is_not (parser, CPP_NAME)
+ || c_parser_peek_token (parser)->id_kind != C_ID_ID)
+ c_parser_error (parser, "expected identifier");
+
+ while (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+ {
+ tree t = lookup_name (c_parser_peek_token (parser)->value);
+
+ if (t == NULL_TREE)
+ undeclared_variable (c_parser_peek_token (parser)->value,
+ c_parser_peek_token (parser)->location);
+ else if (t == error_mark_node)
+ ;
+ else if (kind != 0)
+ {
+ tree u = build_omp_clause (kind);
+ OMP_CLAUSE_DECL (u) = t;
+ OMP_CLAUSE_CHAIN (u) = list;
+ list = u;
+ }
+ else
+ list = tree_cons (t, NULL_TREE, list);
+
+ c_parser_consume_token (parser);
+
+ if (c_parser_next_token_is_not (parser, CPP_COMMA))
+ break;
+
+ c_parser_consume_token (parser);
+ }
+
+ return list;
+}
+
+/* Similarly, but expect leading and trailing parenthesis. This is a very
+ common case for omp clauses. */
+
+static tree
+c_parser_omp_var_list_parens (c_parser *parser, enum tree_code kind, tree list)
+{
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ list = c_parser_omp_variable_list (parser, kind, list);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ return list;
+}
+
+/* OpenMP 2.5:
+ copyin ( variable-list ) */
+
+static tree
+c_parser_omp_clause_copyin (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYIN, list);
+}
+
+/* OpenMP 2.5:
+ copyprivate ( variable-list ) */
+
+static tree
+c_parser_omp_clause_copyprivate (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYPRIVATE, list);
+}
+
+/* OpenMP 2.5:
+ default ( shared | none ) */
+
+static tree
+c_parser_omp_clause_default (c_parser *parser, tree list)
+{
+ enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
+ tree c;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ switch (p[0])
+ {
+ case 'n':
+ if (strcmp ("none", p) != 0)
+ goto invalid_kind;
+ kind = OMP_CLAUSE_DEFAULT_NONE;
+ break;
+
+ case 's':
+ if (strcmp ("shared", p) != 0)
+ goto invalid_kind;
+ kind = OMP_CLAUSE_DEFAULT_SHARED;
+ break;
+
+ default:
+ goto invalid_kind;
+ }
+
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ invalid_kind:
+ c_parser_error (parser, "expected %<none%> or %<shared%>");
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED)
+ return list;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default");
+ c = build_omp_clause (OMP_CLAUSE_DEFAULT);
+ OMP_CLAUSE_CHAIN (c) = list;
+ OMP_CLAUSE_DEFAULT_KIND (c) = kind;
+
+ return c;
+}
+
+/* OpenMP 2.5:
+ firstprivate ( variable-list ) */
+
+static tree
+c_parser_omp_clause_firstprivate (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list);
+}
+
+/* OpenMP 2.5:
+ if ( expression ) */
+
+static tree
+c_parser_omp_clause_if (c_parser *parser, tree list)
+{
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ tree t = c_parser_paren_condition (parser);
+ tree c;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if");
+
+ c = build_omp_clause (OMP_CLAUSE_IF);
+ OMP_CLAUSE_IF_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+ else
+ c_parser_error (parser, "expected %<(%>");
+
+ return list;
+}
+
+/* OpenMP 2.5:
+ lastprivate ( variable-list ) */
+
+static tree
+c_parser_omp_clause_lastprivate (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list);
+}
+
+/* OpenMP 2.5:
+ nowait */
+
+static tree
+c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+ tree c;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait");
+
+ c = build_omp_clause (OMP_CLAUSE_NOWAIT);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 2.5:
+ num_threads ( expression ) */
+
+static tree
+c_parser_omp_clause_num_threads (c_parser *parser, tree list)
+{
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ tree c, t = c_parser_expression (parser).value;
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ c_parser_error (parser, "expected integer expression");
+ return list;
+ }
+
+ /* Attempt to statically determine when the number isn't positive. */
+ c = fold_build2 (LE_EXPR, boolean_type_node, t,
+ build_int_cst (TREE_TYPE (t), 0));
+ if (c == boolean_true_node)
+ {
+ warning (0, "%<num_threads%> value must be positive");
+ t = integer_one_node;
+ }
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads");
+
+ c = build_omp_clause (OMP_CLAUSE_NUM_THREADS);
+ OMP_CLAUSE_NUM_THREADS_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+/* OpenMP 2.5:
+ ordered */
+
+static tree
+c_parser_omp_clause_ordered (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+ tree c;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered");
+
+ c = build_omp_clause (OMP_CLAUSE_ORDERED);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 2.5:
+ private ( variable-list ) */
+
+static tree
+c_parser_omp_clause_private (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_PRIVATE, list);
+}
+
+/* OpenMP 2.5:
+ reduction ( reduction-operator : variable-list )
+
+ reduction-operator:
+ One of: + * - & ^ | && || */
+
+static tree
+c_parser_omp_clause_reduction (c_parser *parser, tree list)
+{
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ enum tree_code code;
+
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_PLUS:
+ code = PLUS_EXPR;
+ break;
+ case CPP_MULT:
+ code = MULT_EXPR;
+ break;
+ case CPP_MINUS:
+ code = MINUS_EXPR;
+ break;
+ case CPP_AND:
+ code = BIT_AND_EXPR;
+ break;
+ case CPP_XOR:
+ code = BIT_XOR_EXPR;
+ break;
+ case CPP_OR:
+ code = BIT_IOR_EXPR;
+ break;
+ case CPP_AND_AND:
+ code = TRUTH_ANDIF_EXPR;
+ break;
+ case CPP_OR_OR:
+ code = TRUTH_ORIF_EXPR;
+ break;
+ default:
+ c_parser_error (parser,
+ "expected %<+%>, %<*%>, %<-%>, %<&%>, "
+ "%<^%>, %<|%>, %<&&%>, or %<||%>");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0);
+ return list;
+ }
+ c_parser_consume_token (parser);
+ if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ {
+ tree nl, c;
+
+ nl = c_parser_omp_variable_list (parser, OMP_CLAUSE_REDUCTION, list);
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_REDUCTION_CODE (c) = code;
+
+ list = nl;
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ return list;
+}
+
+/* OpenMP 2.5:
+ schedule ( schedule-kind )
+ schedule ( schedule-kind , expression )
+
+ schedule-kind:
+ static | dynamic | guided | runtime
+*/
+
+static tree
+c_parser_omp_clause_schedule (c_parser *parser, tree list)
+{
+ tree c, t;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ c = build_omp_clause (OMP_CLAUSE_SCHEDULE);
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ tree kind = c_parser_peek_token (parser)->value;
+ const char *p = IDENTIFIER_POINTER (kind);
+
+ switch (p[0])
+ {
+ case 'd':
+ if (strcmp ("dynamic", p) != 0)
+ goto invalid_kind;
+ OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC;
+ break;
+
+ case 'g':
+ if (strcmp ("guided", p) != 0)
+ goto invalid_kind;
+ OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED;
+ break;
+
+ case 'r':
+ if (strcmp ("runtime", p) != 0)
+ goto invalid_kind;
+ OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME;
+ break;
+
+ default:
+ goto invalid_kind;
+ }
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_STATIC))
+ OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC;
+ else
+ goto invalid_kind;
+
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+
+ t = c_parser_expr_no_commas (parser, NULL).value;
+
+ if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME)
+ error ("schedule %<runtime%> 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);
+}
+
+/* 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;
+
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ const pragma_omp_clause c_kind = c_parser_omp_clause_name (parser);
+ const char *c_name;
+ tree prev = clauses;
+
+ switch (c_kind)
+ {
+ 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;
+ 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 ("%qs is not valid for %qs", c_name, where);
+ }
+ }
+
+ saw_error:
+ c_parser_skip_to_pragma_eol (parser);
+
+ return c_finish_omp_clauses (clauses);
+}
+
+/* OpenMP 2.5:
+ structured-block:
+ statement
+
+ In practice, we're also interested in adding the statement to an
+ outer node. So it is convenient if we work around the fact that
+ c_parser_statement calls add_stmt. */
+
+static tree
+c_parser_omp_structured_block (c_parser *parser)
+{
+ tree stmt = push_stmt_list ();
+ c_parser_statement (parser);
+ return pop_stmt_list (stmt);
+}
+
+/* OpenMP 2.5:
+ # pragma omp atomic new-line
+ expression-stmt
+
+ expression-stmt:
+ x binop= expr | x++ | ++x | x-- | --x
+ binop:
+ +, *, -, /, &, ^, |, <<, >>
+
+ where x is an lvalue expression with scalar type. */
+
+static void
+c_parser_omp_atomic (c_parser *parser)
+{
+ tree lhs, rhs;
+ tree stmt;
+ enum tree_code code;
+
+ c_parser_skip_to_pragma_eol (parser);
+
+ lhs = c_parser_unary_expression (parser).value;
+ switch (TREE_CODE (lhs))
+ {
+ case ERROR_MARK:
+ saw_error:
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+
+ case PREINCREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ lhs = TREE_OPERAND (lhs, 0);
+ code = PLUS_EXPR;
+ rhs = integer_one_node;
+ break;
+
+ case PREDECREMENT_EXPR:
+ case POSTDECREMENT_EXPR:
+ lhs = TREE_OPERAND (lhs, 0);
+ code = MINUS_EXPR;
+ rhs = integer_one_node;
+ break;
+
+ default:
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_MULT_EQ:
+ code = MULT_EXPR;
+ break;
+ case CPP_DIV_EQ:
+ code = TRUNC_DIV_EXPR;
+ break;
+ case CPP_PLUS_EQ:
+ code = PLUS_EXPR;
+ break;
+ case CPP_MINUS_EQ:
+ code = MINUS_EXPR;
+ break;
+ case CPP_LSHIFT_EQ:
+ code = LSHIFT_EXPR;
+ break;
+ case CPP_RSHIFT_EQ:
+ code = RSHIFT_EXPR;
+ break;
+ case CPP_AND_EQ:
+ code = BIT_AND_EXPR;
+ break;
+ case CPP_OR_EQ:
+ code = BIT_IOR_EXPR;
+ break;
+ case CPP_XOR_EQ:
+ code = BIT_XOR_EXPR;
+ break;
+ default:
+ c_parser_error (parser,
+ "invalid operator for %<#pragma omp atomic%>");
+ goto saw_error;
+ }
+
+ c_parser_consume_token (parser);
+ rhs = c_parser_expression (parser).value;
+ break;
+ }
+ stmt = c_finish_omp_atomic (code, lhs, rhs);
+ if (stmt != error_mark_node)
+ add_stmt (stmt);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+}
+
+
+/* OpenMP 2.5:
+ # pragma omp barrier new-line
+*/
+
+static void
+c_parser_omp_barrier (c_parser *parser)
+{
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+
+ c_finish_omp_barrier ();
+}
+
+/* OpenMP 2.5:
+ # pragma omp critical [(name)] new-line
+ structured-block
+*/
+
+static tree
+c_parser_omp_critical (c_parser *parser)
+{
+ tree stmt, name = NULL;
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ name = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ else
+ c_parser_error (parser, "expected identifier");
+ }
+ else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ c_parser_error (parser, "expected %<(%> or end of line");
+ c_parser_skip_to_pragma_eol (parser);
+
+ stmt = c_parser_omp_structured_block (parser);
+ return c_finish_omp_critical (stmt, name);
+}
+
+/* OpenMP 2.5:
+ # pragma omp flush flush-vars[opt] new-line
+
+ flush-vars:
+ ( variable-list ) */
+
+static void
+c_parser_omp_flush (c_parser *parser)
+{
+ c_parser_consume_pragma (parser);
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ c_parser_omp_var_list_parens (parser, 0, NULL);
+ else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ c_parser_error (parser, "expected %<(%> or end of line");
+ c_parser_skip_to_pragma_eol (parser);
+
+ c_finish_omp_flush ();
+}
+
+/* Parse the restricted form of the for statment allowed by OpenMP.
+ The real trick here is to determine the loop control variable early
+ so that we can push a new decl if necessary to make it private. */
+
+static tree
+c_parser_omp_for_loop (c_parser *parser)
+{
+ tree decl, cond, incr, save_break, save_cont, body, init;
+ location_t loc;
+
+ if (!c_parser_next_token_is_keyword (parser, RID_FOR))
+ {
+ c_parser_error (parser, "for statement expected");
+ return NULL;
+ }
+ loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return NULL;
+
+ /* Parse the initialization declaration or expression. */
+ if (c_parser_next_token_starts_declspecs (parser))
+ {
+ c_parser_declaration_or_fndef (parser, true, true, true, true);
+ decl = check_for_loop_decls ();
+ if (decl == NULL)
+ goto error_init;
+ init = decl;
+ }
+ else if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
+ {
+ decl = c_parser_postfix_expression (parser).value;
+
+ c_parser_require (parser, CPP_EQ, "expected %<=%>");
+
+ init = c_parser_expr_no_commas (parser, NULL).value;
+ init = build_modify_expr (decl, NOP_EXPR, init);
+ init = c_process_expr_stmt (init);
+
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ else
+ goto error_init;
+
+ /* Parse the loop condition. */
+ cond = NULL_TREE;
+ if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+ {
+ cond = c_parser_expression_conv (parser).value;
+ cond = c_objc_common_truthvalue_conversion (cond);
+ if (EXPR_P (cond))
+ SET_EXPR_LOCATION (cond, input_location);
+ }
+ 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))
+ incr = c_process_expr_stmt (c_parser_expression (parser).value);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ parse_body:
+ 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 ();
+
+ add_stmt (c_parser_c99_block_statement (parser));
+ if (c_cont_label)
+ add_stmt (build1 (LABEL_EXPR, void_type_node, c_cont_label));
+
+ body = pop_stmt_list (body);
+ c_break_label = save_break;
+ c_cont_label = save_cont;
+
+ /* Only bother calling c_finish_omp_for if we havn't already generated
+ an error from the initialization parsing. */
+ if (decl != NULL && decl != error_mark_node && init != error_mark_node)
+ return c_finish_omp_for (loc, decl, init, cond, incr, body, NULL);
+ return NULL;
+
+ error_init:
+ c_parser_error (parser, "expected iteration declaration or initialization");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ decl = init = cond = incr = NULL_TREE;
+ goto parse_body;
+}
+
+/* OpenMP 2.5:
+ #pragma omp for for-clause[optseq] new-line
+ for-loop
+*/
+
+#define OMP_FOR_CLAUSE_MASK \
+ ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \
+ | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \
+ | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_for (c_parser *parser)
+{
+ tree block, clauses, ret;
+
+ clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK,
+ "#pragma omp for");
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (parser);
+ if (ret)
+ OMP_FOR_CLAUSES (ret) = clauses;
+ block = c_end_compound_stmt (block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
+/* OpenMP 2.5:
+ # pragma omp master new-line
+ structured-block
+*/
+
+static tree
+c_parser_omp_master (c_parser *parser)
+{
+ c_parser_skip_to_pragma_eol (parser);
+ return c_finish_omp_master (c_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 2.5:
+ # pragma omp ordered new-line
+ structured-block
+*/
+
+static tree
+c_parser_omp_ordered (c_parser *parser)
+{
+ c_parser_skip_to_pragma_eol (parser);
+ return c_finish_omp_ordered (c_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 2.5:
+
+ section-scope:
+ { section-sequence }
+
+ section-sequence:
+ section-directive[opt] structured-block
+ section-sequence section-directive structured-block */
+
+static tree
+c_parser_omp_sections_scope (c_parser *parser)
+{
+ tree stmt, substmt;
+ bool error_suppress = false;
+ location_t loc;
+
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ {
+ /* Avoid skipping until the end of the block. */
+ parser->error = false;
+ return NULL_TREE;
+ }
+
+ stmt = push_stmt_list ();
+
+ loc = c_parser_peek_token (parser)->location;
+ if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION)
+ {
+ substmt = push_stmt_list ();
+
+ while (1)
+ {
+ c_parser_statement (parser);
+
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
+ break;
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ break;
+ if (c_parser_next_token_is (parser, CPP_EOF))
+ break;
+ }
+
+ substmt = pop_stmt_list (substmt);
+ substmt = build1 (OMP_SECTION, void_type_node, substmt);
+ SET_EXPR_LOCATION (substmt, loc);
+ add_stmt (substmt);
+ }
+
+ while (1)
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ break;
+ if (c_parser_next_token_is (parser, CPP_EOF))
+ break;
+
+ loc = c_parser_peek_token (parser)->location;
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
+ {
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+ error_suppress = false;
+ }
+ else if (!error_suppress)
+ {
+ error ("expected %<#pragma omp section%> or %<}%>");
+ error_suppress = true;
+ }
+
+ substmt = c_parser_omp_structured_block (parser);
+ substmt = build1 (OMP_SECTION, void_type_node, substmt);
+ SET_EXPR_LOCATION (substmt, loc);
+ add_stmt (substmt);
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE,
+ "expected %<#pragma omp section%> or %<}%>");
+
+ substmt = pop_stmt_list (stmt);
+
+ stmt = make_node (OMP_SECTIONS);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_SECTIONS_BODY (stmt) = substmt;
+
+ return add_stmt (stmt);
+}
+
+/* OpenMP 2.5:
+ # pragma omp sections sections-clause[optseq] newline
+ sections-scope
+*/
+
+#define OMP_SECTIONS_CLAUSE_MASK \
+ ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_sections (c_parser *parser)
+{
+ tree block, clauses, ret;
+
+ clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK,
+ "#pragma omp sections");
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_sections_scope (parser);
+ if (ret)
+ OMP_SECTIONS_CLAUSES (ret) = clauses;
+ block = c_end_compound_stmt (block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
+/* OpenMP 2.5:
+ # pragma parallel parallel-clause new-line
+ # pragma parallel for parallel-for-clause new-line
+ # pragma parallel sections parallel-sections-clause new-line
+*/
+
+#define OMP_PARALLEL_CLAUSE_MASK \
+ ( (1u << PRAGMA_OMP_CLAUSE_IF) \
+ | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \
+ | (1u << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \
+ | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+
+static tree
+c_parser_omp_parallel (c_parser *parser)
+{
+ enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL;
+ const char *p_name = "#pragma omp parallel";
+ tree stmt, clauses, par_clause, ws_clause, block;
+ unsigned int mask = OMP_PARALLEL_CLAUSE_MASK;
+
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ {
+ c_parser_consume_token (parser);
+ p_kind = PRAGMA_OMP_PARALLEL_FOR;
+ p_name = "#pragma omp parallel for";
+ mask |= OMP_FOR_CLAUSE_MASK;
+ mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+ }
+ else if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "sections") == 0)
+ {
+ c_parser_consume_token (parser);
+ p_kind = PRAGMA_OMP_PARALLEL_SECTIONS;
+ p_name = "#pragma omp parallel sections";
+ mask |= OMP_SECTIONS_CLAUSE_MASK;
+ mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+ }
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name);
+
+ switch (p_kind)
+ {
+ case PRAGMA_OMP_PARALLEL:
+ block = c_begin_omp_parallel ();
+ c_parser_statement (parser);
+ stmt = c_finish_omp_parallel (clauses, block);
+ break;
+
+ case PRAGMA_OMP_PARALLEL_FOR:
+ block = c_begin_omp_parallel ();
+ c_split_parallel_clauses (clauses, &par_clause, &ws_clause);
+ stmt = c_parser_omp_for_loop (parser);
+ if (stmt)
+ OMP_FOR_CLAUSES (stmt) = ws_clause;
+ stmt = c_finish_omp_parallel (par_clause, block);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ break;
+
+ case PRAGMA_OMP_PARALLEL_SECTIONS:
+ block = c_begin_omp_parallel ();
+ c_split_parallel_clauses (clauses, &par_clause, &ws_clause);
+ stmt = c_parser_omp_sections_scope (parser);
+ if (stmt)
+ OMP_SECTIONS_CLAUSES (stmt) = ws_clause;
+ stmt = c_finish_omp_parallel (par_clause, block);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return stmt;
+}
+
+/* OpenMP 2.5:
+ # pragma omp single single-clause[optseq] new-line
+ structured-block
+*/
+
+#define OMP_SINGLE_CLAUSE_MASK \
+ ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_single (c_parser *parser)
+{
+ tree stmt = make_node (OMP_SINGLE);
+ TREE_TYPE (stmt) = void_type_node;
+
+ OMP_SINGLE_CLAUSES (stmt)
+ = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK,
+ "#pragma omp single");
+ OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser);
+
+ return add_stmt (stmt);
+}
+
+
+/* Main entry point to parsing most OpenMP pragmas. */
+
+static void
+c_parser_omp_construct (c_parser *parser)
+{
+ enum pragma_kind p_kind;
+ location_t loc;
+ tree stmt;
+
+ loc = c_parser_peek_token (parser)->location;
+ p_kind = c_parser_peek_token (parser)->pragma_kind;
+ c_parser_consume_pragma (parser);
+
+ /* For all constructs below except #pragma omp atomic
+ MUST_NOT_THROW catch handlers are needed when exceptions
+ are enabled. */
+ if (p_kind != PRAGMA_OMP_ATOMIC)
+ c_maybe_initialize_eh ();
+
+ switch (p_kind)
+ {
+ case PRAGMA_OMP_ATOMIC:
+ c_parser_omp_atomic (parser);
+ return;
+ case PRAGMA_OMP_CRITICAL:
+ stmt = c_parser_omp_critical (parser);
+ break;
+ case PRAGMA_OMP_FOR:
+ stmt = c_parser_omp_for (parser);
+ break;
+ case PRAGMA_OMP_MASTER:
+ stmt = c_parser_omp_master (parser);
+ break;
+ case PRAGMA_OMP_ORDERED:
+ stmt = c_parser_omp_ordered (parser);
+ break;
+ case PRAGMA_OMP_PARALLEL:
+ stmt = c_parser_omp_parallel (parser);
+ break;
+ case PRAGMA_OMP_SECTIONS:
+ stmt = c_parser_omp_sections (parser);
+ break;
+ case PRAGMA_OMP_SINGLE:
+ stmt = c_parser_omp_single (parser);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (stmt)
+ SET_EXPR_LOCATION (stmt, loc);
+}
+
+
+/* OpenMP 2.5:
+ # pragma omp threadprivate (variable-list) */
+
+static void
+c_parser_omp_threadprivate (c_parser *parser)
+{
+ tree vars, t;
+
+ c_parser_consume_pragma (parser);
+ vars = c_parser_omp_var_list_parens (parser, 0, NULL);
+
+ if (!targetm.have_tls)
+ sorry ("threadprivate variables not supported in this target");
+
+ /* Mark every variable in VARS to be assigned thread local storage. */
+ for (t = vars; t; t = TREE_CHAIN (t))
+ {
+ tree v = TREE_PURPOSE (t);
+
+ /* If V had already been marked threadprivate, it doesn't matter
+ whether it had been used prior to this point. */
+ if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v))
+ error ("%qE declared %<threadprivate%> after first use", v);
+ else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v))
+ error ("automatic variable %qE cannot be %<threadprivate%>", v);
+ else if (! COMPLETE_TYPE_P (TREE_TYPE (v)))
+ error ("%<threadprivate%> %qE has incomplete type", v);
+ else
+ {
+ if (! DECL_THREAD_LOCAL_P (v))
+ {
+ DECL_TLS_MODEL (v) = decl_default_tls_model (v);
+ /* If rtl has been already set for this var, call
+ make_decl_rtl once again, so that encode_section_info
+ has a chance to look at the new decl flags. */
+ if (DECL_RTL_SET_P (v))
+ make_decl_rtl (v);
+ }
+ C_DECL_THREADPRIVATE_P (v) = 1;
+ }
+ }
+
+ c_parser_skip_to_pragma_eol (parser);
+}
+
+
+/* Parse a single source file. */
+
+void
+c_parse_file (void)
+{
+ /* Use local storage to begin. If the first token is a pragma, parse it.
+ If it is #pragma GCC pch_preprocess, then this will load a PCH file
+ which will cause garbage collection. */
+ c_parser tparser;
+
+ memset (&tparser, 0, sizeof tparser);
+ the_parser = &tparser;
+
+ if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS)
+ c_parser_pragma_pch_preprocess (&tparser);
+
+ the_parser = GGC_NEW (c_parser);
+ *the_parser = tparser;
+
+ c_parser_translation_unit (the_parser);
+ the_parser = NULL;
+}
+
+#include "gt-c-parser.h"