aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.8.3/gcc/c/c-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.8.3/gcc/c/c-parser.c')
-rw-r--r--gcc-4.8.3/gcc/c/c-parser.c10884
1 files changed, 10884 insertions, 0 deletions
diff --git a/gcc-4.8.3/gcc/c/c-parser.c b/gcc-4.8.3/gcc/c/c-parser.c
new file mode 100644
index 000000000..215327356
--- /dev/null
+++ b/gcc-4.8.3/gcc/c/c-parser.c
@@ -0,0 +1,10884 @@
+/* Parser for C and Objective-C.
+ Copyright (C) 1987-2013 Free Software Foundation, Inc.
+
+ Parser actions based on the old Bison parser; structure somewhat
+ influenced by and fragments based on the C++ parser.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* TODO:
+
+ Make sure all relevant comments, and all relevant code from all
+ actions, brought over from old parser. Verify exact correspondence
+ of syntax accepted.
+
+ Add testcases covering every input symbol in every state in old and
+ new parsers.
+
+ Include full syntax for GNU C, including erroneous cases accepted
+ with error messages, in syntax productions in comments.
+
+ Make more diagnostics in the front end generally take an explicit
+ location rather than implicitly using input_location. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h" /* For rtl.h: needs enum reg_class. */
+#include "tree.h"
+#include "langhooks.h"
+#include "input.h"
+#include "cpplib.h"
+#include "timevar.h"
+#include "c-family/c-pragma.h"
+#include "c-tree.h"
+#include "flags.h"
+#include "ggc.h"
+#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
+#include "vec.h"
+#include "target.h"
+#include "cgraph.h"
+#include "plugin.h"
+
+
+/* Initialization routine for this file. */
+
+void
+c_parse_init (void)
+{
+ /* The only initialization required is of the reserved word
+ identifiers. */
+ unsigned int i;
+ tree id;
+ int mask = 0;
+
+ /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in
+ the c_token structure. */
+ gcc_assert (RID_MAX <= 255);
+
+ mask |= D_CXXONLY;
+ if (!flag_isoc99)
+ mask |= D_C99;
+ if (flag_no_asm)
+ {
+ mask |= D_ASM | D_EXT;
+ if (!flag_isoc99)
+ mask |= D_EXT89;
+ }
+ if (!c_dialect_objc ())
+ mask |= D_OBJC | D_CXX_OBJC;
+
+ ridpointers = ggc_alloc_cleared_vec_tree ((int) RID_MAX);
+ for (i = 0; i < num_c_common_reswords; i++)
+ {
+ /* If a keyword is disabled, do not enter it into the table
+ and so create a canonical spelling that isn't a keyword. */
+ if (c_common_reswords[i].disable & mask)
+ {
+ if (warn_cxx_compat
+ && (c_common_reswords[i].disable & D_CXXWARN))
+ {
+ id = get_identifier (c_common_reswords[i].word);
+ C_SET_RID_CODE (id, RID_CXX_COMPAT_WARN);
+ C_IS_RESERVED_WORD (id) = 1;
+ }
+ continue;
+ }
+
+ id = get_identifier (c_common_reswords[i].word);
+ C_SET_RID_CODE (id, c_common_reswords[i].rid);
+ C_IS_RESERVED_WORD (id) = 1;
+ ridpointers [(int) c_common_reswords[i].rid] = id;
+ }
+}
+
+/* The C lexer intermediates between the lexer in cpplib and c-lex.c
+ and the C parser. Unlike the C++ lexer, the parser structure
+ stores the lexer information instead of using a separate structure.
+ Identifiers are separated into ordinary identifiers, type names,
+ keywords and some other Objective-C types of identifiers, and some
+ look-ahead is maintained.
+
+ ??? It might be a good idea to lex the whole file up front (as for
+ C++). It would then be possible to share more of the C and C++
+ lexer code, if desired. */
+
+/* The following local token type is used. */
+
+/* A keyword. */
+#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
+
+/* More information about the type of a CPP_NAME token. */
+typedef enum c_id_kind {
+ /* An ordinary identifier. */
+ C_ID_ID,
+ /* An identifier declared as a typedef name. */
+ C_ID_TYPENAME,
+ /* An identifier declared as an Objective-C class name. */
+ C_ID_CLASSNAME,
+ /* An address space identifier. */
+ C_ID_ADDRSPACE,
+ /* Not an identifier. */
+ C_ID_NONE
+} c_id_kind;
+
+/* A single C token after string literal concatenation and conversion
+ of preprocessing tokens to tokens. */
+typedef struct GTY (()) c_token {
+ /* The kind of token. */
+ ENUM_BITFIELD (cpp_ttype) type : 8;
+ /* If this token is a CPP_NAME, this value indicates whether also
+ declared as some kind of type. Otherwise, it is C_ID_NONE. */
+ ENUM_BITFIELD (c_id_kind) id_kind : 8;
+ /* If this token is a keyword, this value indicates which keyword.
+ Otherwise, this value is RID_MAX. */
+ ENUM_BITFIELD (rid) keyword : 8;
+ /* If this token is a CPP_PRAGMA, this indicates the pragma that
+ was seen. Otherwise it is PRAGMA_NONE. */
+ ENUM_BITFIELD (pragma_kind) pragma_kind : 8;
+ /* The location at which this token was found. */
+ location_t location;
+ /* The value associated with this token, if any. */
+ tree value;
+} c_token;
+
+/* A parser structure recording information about the state and
+ context of parsing. Includes lexer information with up to two
+ tokens of look-ahead; more are not needed for C. */
+typedef struct GTY(()) c_parser {
+ /* The look-ahead tokens. */
+ c_token tokens[2];
+ /* How many look-ahead tokens are available (0, 1 or 2). */
+ short tokens_avail;
+ /* True if a syntax error is being recovered from; false otherwise.
+ c_parser_error sets this flag. It should clear this flag when
+ enough tokens have been consumed to recover from the error. */
+ BOOL_BITFIELD error : 1;
+ /* True if we're processing a pragma, and shouldn't automatically
+ consume CPP_PRAGMA_EOL. */
+ BOOL_BITFIELD in_pragma : 1;
+ /* True if we're parsing the outermost block of an if statement. */
+ BOOL_BITFIELD in_if_block : 1;
+ /* True if we want to lex an untranslated string. */
+ BOOL_BITFIELD lex_untranslated_string : 1;
+
+ /* Objective-C specific parser/lexer information. */
+
+ /* True if we are in a context where the Objective-C "PQ" keywords
+ are considered keywords. */
+ BOOL_BITFIELD objc_pq_context : 1;
+ /* True if we are parsing a (potential) Objective-C foreach
+ statement. This is set to true after we parsed 'for (' and while
+ we wait for 'in' or ';' to decide if it's a standard C for loop or an
+ Objective-C foreach loop. */
+ BOOL_BITFIELD objc_could_be_foreach_context : 1;
+ /* The following flag is needed to contextualize Objective-C lexical
+ analysis. In some cases (e.g., 'int NSObject;'), it is
+ undesirable to bind an identifier to an Objective-C class, even
+ if a class with that name exists. */
+ BOOL_BITFIELD objc_need_raw_identifier : 1;
+ /* Nonzero if we're processing a __transaction statement. The value
+ is 1 | TM_STMT_ATTR_*. */
+ unsigned int in_transaction : 4;
+ /* True if we are in a context where the Objective-C "Property attribute"
+ keywords are valid. */
+ BOOL_BITFIELD objc_property_attr_context : 1;
+} c_parser;
+
+
+/* The actual parser and external interface. ??? Does this need to be
+ garbage-collected? */
+
+static GTY (()) c_parser *the_parser;
+
+/* Read in and lex a single token, storing it in *TOKEN. */
+
+static void
+c_lex_one_token (c_parser *parser, c_token *token)
+{
+ timevar_push (TV_LEX);
+
+ token->type = c_lex_with_flags (&token->value, &token->location, NULL,
+ (parser->lex_untranslated_string
+ ? C_LEX_STRING_NO_TRANSLATE : 0));
+ token->id_kind = C_ID_NONE;
+ token->keyword = RID_MAX;
+ token->pragma_kind = PRAGMA_NONE;
+
+ switch (token->type)
+ {
+ case CPP_NAME:
+ {
+ tree decl;
+
+ bool objc_force_identifier = parser->objc_need_raw_identifier;
+ if (c_dialect_objc ())
+ parser->objc_need_raw_identifier = false;
+
+ if (C_IS_RESERVED_WORD (token->value))
+ {
+ enum rid rid_code = C_RID_CODE (token->value);
+
+ if (rid_code == RID_CXX_COMPAT_WARN)
+ {
+ warning_at (token->location,
+ OPT_Wc___compat,
+ "identifier %qE conflicts with C++ keyword",
+ token->value);
+ }
+ else if (rid_code >= RID_FIRST_ADDR_SPACE
+ && rid_code <= RID_LAST_ADDR_SPACE)
+ {
+ token->id_kind = C_ID_ADDRSPACE;
+ token->keyword = rid_code;
+ break;
+ }
+ else if (c_dialect_objc () && OBJC_IS_PQ_KEYWORD (rid_code))
+ {
+ /* We found an Objective-C "pq" keyword (in, out,
+ inout, bycopy, byref, oneway). They need special
+ care because the interpretation depends on the
+ context. */
+ if (parser->objc_pq_context)
+ {
+ token->type = CPP_KEYWORD;
+ token->keyword = rid_code;
+ break;
+ }
+ else if (parser->objc_could_be_foreach_context
+ && rid_code == RID_IN)
+ {
+ /* We are in Objective-C, inside a (potential)
+ foreach context (which means after having
+ parsed 'for (', but before having parsed ';'),
+ and we found 'in'. We consider it the keyword
+ which terminates the declaration at the
+ beginning of a foreach-statement. Note that
+ this means you can't use 'in' for anything else
+ in that context; in particular, in Objective-C
+ you can't use 'in' as the name of the running
+ variable in a C for loop. We could potentially
+ try to add code here to disambiguate, but it
+ seems a reasonable limitation. */
+ token->type = CPP_KEYWORD;
+ token->keyword = rid_code;
+ break;
+ }
+ /* Else, "pq" keywords outside of the "pq" context are
+ not keywords, and we fall through to the code for
+ normal tokens. */
+ }
+ else if (c_dialect_objc () && OBJC_IS_PATTR_KEYWORD (rid_code))
+ {
+ /* We found an Objective-C "property attribute"
+ keyword (getter, setter, readonly, etc). These are
+ only valid in the property context. */
+ if (parser->objc_property_attr_context)
+ {
+ token->type = CPP_KEYWORD;
+ token->keyword = rid_code;
+ break;
+ }
+ /* Else they are not special keywords.
+ */
+ }
+ else if (c_dialect_objc ()
+ && (OBJC_IS_AT_KEYWORD (rid_code)
+ || OBJC_IS_CXX_KEYWORD (rid_code)))
+ {
+ /* We found one of the Objective-C "@" keywords (defs,
+ selector, synchronized, etc) or one of the
+ Objective-C "cxx" keywords (class, private,
+ protected, public, try, catch, throw) without a
+ preceding '@' sign. Do nothing and fall through to
+ the code for normal tokens (in C++ we would still
+ consider the CXX ones keywords, but not in C). */
+ ;
+ }
+ else
+ {
+ token->type = CPP_KEYWORD;
+ token->keyword = rid_code;
+ break;
+ }
+ }
+
+ decl = lookup_name (token->value);
+ if (decl)
+ {
+ if (TREE_CODE (decl) == TYPE_DECL)
+ {
+ token->id_kind = C_ID_TYPENAME;
+ break;
+ }
+ }
+ else if (c_dialect_objc ())
+ {
+ tree objc_interface_decl = objc_is_class_name (token->value);
+ /* Objective-C class names are in the same namespace as
+ variables and typedefs, and hence are shadowed by local
+ declarations. */
+ if (objc_interface_decl
+ && (!objc_force_identifier || global_bindings_p ()))
+ {
+ 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;
+ switch (C_RID_CODE (token->value))
+ {
+ /* Replace 'class' with '@class', 'private' with '@private',
+ etc. This prevents confusion with the C++ keyword
+ 'class', and makes the tokens consistent with other
+ Objective-C 'AT' keywords. For example '@class' is
+ reported as RID_AT_CLASS which is consistent with
+ '@synchronized', which is reported as
+ RID_AT_SYNCHRONIZED.
+ */
+ case RID_CLASS: token->keyword = RID_AT_CLASS; break;
+ case RID_PRIVATE: token->keyword = RID_AT_PRIVATE; break;
+ case RID_PROTECTED: token->keyword = RID_AT_PROTECTED; break;
+ case RID_PUBLIC: token->keyword = RID_AT_PUBLIC; break;
+ case RID_THROW: token->keyword = RID_AT_THROW; break;
+ case RID_TRY: token->keyword = RID_AT_TRY; break;
+ case RID_CATCH: token->keyword = RID_AT_CATCH; break;
+ default: token->keyword = C_RID_CODE (token->value);
+ }
+ break;
+ case CPP_COLON:
+ case CPP_COMMA:
+ case CPP_CLOSE_PAREN:
+ case CPP_SEMICOLON:
+ /* These tokens may affect the interpretation of any identifiers
+ following, if doing Objective-C. */
+ if (c_dialect_objc ())
+ parser->objc_need_raw_identifier = false;
+ break;
+ case CPP_PRAGMA:
+ /* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */
+ token->pragma_kind = (enum pragma_kind) TREE_INT_CST_LOW (token->value);
+ token->value = NULL;
+ break;
+ default:
+ break;
+ }
+ timevar_pop (TV_LEX);
+}
+
+/* Return a pointer to the next token from PARSER, reading it in if
+ necessary. */
+
+static inline c_token *
+c_parser_peek_token (c_parser *parser)
+{
+ if (parser->tokens_avail == 0)
+ {
+ c_lex_one_token (parser, &parser->tokens[0]);
+ parser->tokens_avail = 1;
+ }
+ return &parser->tokens[0];
+}
+
+/* Return true if the next token from PARSER has the indicated
+ TYPE. */
+
+static inline bool
+c_parser_next_token_is (c_parser *parser, enum cpp_ttype type)
+{
+ return c_parser_peek_token (parser)->type == type;
+}
+
+/* Return true if the next token from PARSER does not have the
+ indicated TYPE. */
+
+static inline bool
+c_parser_next_token_is_not (c_parser *parser, enum cpp_ttype type)
+{
+ return !c_parser_next_token_is (parser, type);
+}
+
+/* Return true if the next token from PARSER is the indicated
+ KEYWORD. */
+
+static inline bool
+c_parser_next_token_is_keyword (c_parser *parser, enum rid keyword)
+{
+ return c_parser_peek_token (parser)->keyword == keyword;
+}
+
+/* Return a pointer to the next-but-one token from PARSER, reading it
+ in if necessary. The next token is already read in. */
+
+static c_token *
+c_parser_peek_2nd_token (c_parser *parser)
+{
+ if (parser->tokens_avail >= 2)
+ return &parser->tokens[1];
+ gcc_assert (parser->tokens_avail == 1);
+ gcc_assert (parser->tokens[0].type != CPP_EOF);
+ gcc_assert (parser->tokens[0].type != CPP_PRAGMA_EOL);
+ c_lex_one_token (parser, &parser->tokens[1]);
+ parser->tokens_avail = 2;
+ return &parser->tokens[1];
+}
+
+/* Return true if TOKEN can start a type name,
+ false otherwise. */
+static bool
+c_token_starts_typename (c_token *token)
+{
+ switch (token->type)
+ {
+ case CPP_NAME:
+ switch (token->id_kind)
+ {
+ case C_ID_ID:
+ return false;
+ case C_ID_ADDRSPACE:
+ return true;
+ case C_ID_TYPENAME:
+ return true;
+ case C_ID_CLASSNAME:
+ gcc_assert (c_dialect_objc ());
+ return true;
+ default:
+ gcc_unreachable ();
+ }
+ case CPP_KEYWORD:
+ switch (token->keyword)
+ {
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_INT128:
+ case RID_SHORT:
+ case RID_SIGNED:
+ case RID_COMPLEX:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ case RID_BOOL:
+ case RID_ENUM:
+ case RID_STRUCT:
+ case RID_UNION:
+ case RID_TYPEOF:
+ case RID_CONST:
+ case RID_VOLATILE:
+ case RID_RESTRICT:
+ case RID_ATTRIBUTE:
+ case RID_FRACT:
+ case RID_ACCUM:
+ case RID_SAT:
+ return true;
+ default:
+ return false;
+ }
+ case CPP_LESS:
+ if (c_dialect_objc ())
+ return true;
+ return false;
+ default:
+ return false;
+ }
+}
+
+enum c_lookahead_kind {
+ /* Always treat unknown identifiers as typenames. */
+ cla_prefer_type,
+
+ /* Could be parsing a nonabstract declarator. Only treat an identifier
+ as a typename if followed by another identifier or a star. */
+ cla_nonabstract_decl,
+
+ /* Never treat identifiers as typenames. */
+ cla_prefer_id
+};
+
+/* Return true if the next token from PARSER can start a type name,
+ false otherwise. LA specifies how to do lookahead in order to
+ detect unknown type names. If unsure, pick CLA_PREFER_ID. */
+
+static inline bool
+c_parser_next_tokens_start_typename (c_parser *parser, enum c_lookahead_kind la)
+{
+ c_token *token = c_parser_peek_token (parser);
+ if (c_token_starts_typename (token))
+ return true;
+
+ /* Try a bit harder to detect an unknown typename. */
+ if (la != cla_prefer_id
+ && token->type == CPP_NAME
+ && token->id_kind == C_ID_ID
+
+ /* Do not try too hard when we could have "object in array". */
+ && !parser->objc_could_be_foreach_context
+
+ && (la == cla_prefer_type
+ || c_parser_peek_2nd_token (parser)->type == CPP_NAME
+ || c_parser_peek_2nd_token (parser)->type == CPP_MULT)
+
+ /* Only unknown identifiers. */
+ && !lookup_name (token->value))
+ return true;
+
+ return false;
+}
+
+/* Return true if TOKEN is a type qualifier, false otherwise. */
+static bool
+c_token_is_qualifier (c_token *token)
+{
+ switch (token->type)
+ {
+ case CPP_NAME:
+ switch (token->id_kind)
+ {
+ case C_ID_ADDRSPACE:
+ return true;
+ default:
+ return false;
+ }
+ case CPP_KEYWORD:
+ switch (token->keyword)
+ {
+ case RID_CONST:
+ case RID_VOLATILE:
+ case RID_RESTRICT:
+ case RID_ATTRIBUTE:
+ return true;
+ default:
+ return false;
+ }
+ case CPP_LESS:
+ return false;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Return true if the next token from PARSER is a type qualifier,
+ false otherwise. */
+static inline bool
+c_parser_next_token_is_qualifier (c_parser *parser)
+{
+ c_token *token = c_parser_peek_token (parser);
+ return c_token_is_qualifier (token);
+}
+
+/* Return true if TOKEN can start declaration specifiers, false
+ otherwise. */
+static bool
+c_token_starts_declspecs (c_token *token)
+{
+ switch (token->type)
+ {
+ case CPP_NAME:
+ switch (token->id_kind)
+ {
+ case C_ID_ID:
+ return false;
+ case C_ID_ADDRSPACE:
+ return true;
+ case C_ID_TYPENAME:
+ return true;
+ case C_ID_CLASSNAME:
+ gcc_assert (c_dialect_objc ());
+ return true;
+ default:
+ gcc_unreachable ();
+ }
+ case CPP_KEYWORD:
+ switch (token->keyword)
+ {
+ case RID_STATIC:
+ case RID_EXTERN:
+ case RID_REGISTER:
+ case RID_TYPEDEF:
+ case RID_INLINE:
+ case RID_NORETURN:
+ case RID_AUTO:
+ case RID_THREAD:
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_INT128:
+ case RID_SHORT:
+ case RID_SIGNED:
+ case RID_COMPLEX:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ case RID_BOOL:
+ case RID_ENUM:
+ case RID_STRUCT:
+ case RID_UNION:
+ case RID_TYPEOF:
+ case RID_CONST:
+ case RID_VOLATILE:
+ case RID_RESTRICT:
+ case RID_ATTRIBUTE:
+ case RID_FRACT:
+ case RID_ACCUM:
+ case RID_SAT:
+ case RID_ALIGNAS:
+ return true;
+ default:
+ return false;
+ }
+ case CPP_LESS:
+ if (c_dialect_objc ())
+ return true;
+ return false;
+ default:
+ return false;
+ }
+}
+
+
+/* Return true if TOKEN can start declaration specifiers or a static
+ assertion, false otherwise. */
+static bool
+c_token_starts_declaration (c_token *token)
+{
+ if (c_token_starts_declspecs (token)
+ || token->keyword == RID_STATIC_ASSERT)
+ return true;
+ else
+ 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);
+
+ /* In Objective-C, a classname normally starts a declspecs unless it
+ is immediately followed by a dot. In that case, it is the
+ Objective-C 2.0 "dot-syntax" for class objects, ie, calls the
+ setter/getter on the class. c_token_starts_declspecs() can't
+ differentiate between the two cases because it only checks the
+ current token, so we have a special check here. */
+ if (c_dialect_objc ()
+ && token->type == CPP_NAME
+ && token->id_kind == C_ID_CLASSNAME
+ && c_parser_peek_2nd_token (parser)->type == CPP_DOT)
+ return false;
+
+ return c_token_starts_declspecs (token);
+}
+
+/* Return true if the next tokens from PARSER can start declaration
+ specifiers or a static assertion, false otherwise. */
+static inline bool
+c_parser_next_tokens_start_declaration (c_parser *parser)
+{
+ c_token *token = c_parser_peek_token (parser);
+
+ /* Same as above. */
+ if (c_dialect_objc ()
+ && token->type == CPP_NAME
+ && token->id_kind == C_ID_CLASSNAME
+ && c_parser_peek_2nd_token (parser)->type == CPP_DOT)
+ return false;
+
+ /* Labels do not start declarations. */
+ if (token->type == CPP_NAME
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ return false;
+
+ if (c_token_starts_declaration (token))
+ return true;
+
+ if (c_parser_next_tokens_start_typename (parser, cla_nonabstract_decl))
+ return true;
+
+ return false;
+}
+
+/* Consume the next token from PARSER. */
+
+static void
+c_parser_consume_token (c_parser *parser)
+{
+ gcc_assert (parser->tokens_avail >= 1);
+ gcc_assert (parser->tokens[0].type != CPP_EOF);
+ gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL);
+ gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA);
+ if (parser->tokens_avail == 2)
+ parser->tokens[0] = parser->tokens[1];
+ parser->tokens_avail--;
+}
+
+/* Expect the current token to be a #pragma. Consume it and remember
+ that we've begun parsing a pragma. */
+
+static void
+c_parser_consume_pragma (c_parser *parser)
+{
+ gcc_assert (!parser->in_pragma);
+ gcc_assert (parser->tokens_avail >= 1);
+ gcc_assert (parser->tokens[0].type == CPP_PRAGMA);
+ if (parser->tokens_avail == 2)
+ parser->tokens[0] = parser->tokens[1];
+ parser->tokens_avail--;
+ parser->in_pragma = true;
+}
+
+/* Update the globals input_location and in_system_header from
+ TOKEN. */
+static inline void
+c_parser_set_source_position_from_token (c_token *token)
+{
+ if (token->type != CPP_EOF)
+ {
+ input_location = token->location;
+ }
+}
+
+/* Issue a diagnostic of the form
+ FILE:LINE: MESSAGE before TOKEN
+ where TOKEN is the next token in the input stream of PARSER.
+ MESSAGE (specified by the caller) is usually of the form "expected
+ OTHER-TOKEN".
+
+ Do not issue a diagnostic if still recovering from an error.
+
+ ??? This is taken from the C++ parser, but building up messages in
+ this way is not i18n-friendly and some other approach should be
+ used. */
+
+static void
+c_parser_error (c_parser *parser, const char *gmsgid)
+{
+ c_token *token = c_parser_peek_token (parser);
+ if (parser->error)
+ return;
+ parser->error = true;
+ if (!gmsgid)
+ return;
+ /* This diagnostic makes more sense if it is tagged to the line of
+ the token we just peeked at. */
+ c_parser_set_source_position_from_token (token);
+ c_parse_error (gmsgid,
+ /* Because c_parse_error does not understand
+ CPP_KEYWORD, keywords are treated like
+ identifiers. */
+ (token->type == CPP_KEYWORD ? CPP_NAME : token->type),
+ /* ??? The C parser does not save the cpp flags of a
+ token, we need to pass 0 here and we will not get
+ the source spelling of some tokens but rather the
+ canonical spelling. */
+ token->value, /*flags=*/0);
+}
+
+/* If the next token is of the indicated TYPE, consume it. Otherwise,
+ issue the error MSGID. If MSGID is NULL then a message has already
+ been produced and no message will be produced this time. Returns
+ true if found, false otherwise. */
+
+static bool
+c_parser_require (c_parser *parser,
+ enum cpp_ttype type,
+ const char *msgid)
+{
+ if (c_parser_next_token_is (parser, type))
+ {
+ c_parser_consume_token (parser);
+ return true;
+ }
+ else
+ {
+ c_parser_error (parser, msgid);
+ return false;
+ }
+}
+
+/* If the next token is the indicated keyword, consume it. Otherwise,
+ issue the error MSGID. Returns true if found, false otherwise. */
+
+static bool
+c_parser_require_keyword (c_parser *parser,
+ enum rid keyword,
+ const char *msgid)
+{
+ if (c_parser_next_token_is_keyword (parser, keyword))
+ {
+ c_parser_consume_token (parser);
+ return true;
+ }
+ else
+ {
+ c_parser_error (parser, msgid);
+ return false;
+ }
+}
+
+/* Like c_parser_require, except that tokens will be skipped until the
+ desired token is found. An error message is still produced if the
+ next token is not as expected. If MSGID is NULL then a message has
+ already been produced and no message will be produced this
+ time. */
+
+static void
+c_parser_skip_until_found (c_parser *parser,
+ enum cpp_ttype type,
+ const char *msgid)
+{
+ unsigned nesting_depth = 0;
+
+ if (c_parser_require (parser, type, msgid))
+ return;
+
+ /* Skip tokens until the desired token is found. */
+ while (true)
+ {
+ /* Peek at the next token. */
+ c_token *token = c_parser_peek_token (parser);
+ /* If we've reached the token we want, consume it and stop. */
+ if (token->type == type && !nesting_depth)
+ {
+ c_parser_consume_token (parser);
+ break;
+ }
+
+ /* If we've run out of tokens, stop. */
+ if (token->type == CPP_EOF)
+ return;
+ if (token->type == CPP_PRAGMA_EOL && parser->in_pragma)
+ return;
+ if (token->type == CPP_OPEN_BRACE
+ || token->type == CPP_OPEN_PAREN
+ || token->type == CPP_OPEN_SQUARE)
+ ++nesting_depth;
+ else if (token->type == CPP_CLOSE_BRACE
+ || token->type == CPP_CLOSE_PAREN
+ || token->type == CPP_CLOSE_SQUARE)
+ {
+ if (nesting_depth-- == 0)
+ break;
+ }
+ /* Consume this token. */
+ c_parser_consume_token (parser);
+ }
+ parser->error = false;
+}
+
+/* Skip tokens until the end of a parameter is found, but do not
+ consume the comma, semicolon or closing delimiter. */
+
+static void
+c_parser_skip_to_end_of_parameter (c_parser *parser)
+{
+ unsigned nesting_depth = 0;
+
+ while (true)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if ((token->type == CPP_COMMA || token->type == CPP_SEMICOLON)
+ && !nesting_depth)
+ break;
+ /* If we've run out of tokens, stop. */
+ if (token->type == CPP_EOF)
+ return;
+ if (token->type == CPP_PRAGMA_EOL && parser->in_pragma)
+ return;
+ if (token->type == CPP_OPEN_BRACE
+ || token->type == CPP_OPEN_PAREN
+ || token->type == CPP_OPEN_SQUARE)
+ ++nesting_depth;
+ else if (token->type == CPP_CLOSE_BRACE
+ || token->type == CPP_CLOSE_PAREN
+ || token->type == CPP_CLOSE_SQUARE)
+ {
+ if (nesting_depth-- == 0)
+ break;
+ }
+ /* Consume this token. */
+ c_parser_consume_token (parser);
+ }
+ parser->error = false;
+}
+
+/* Expect to be at the end of the pragma directive and consume an
+ end of line marker. */
+
+static void
+c_parser_skip_to_pragma_eol (c_parser *parser)
+{
+ gcc_assert (parser->in_pragma);
+ parser->in_pragma = false;
+
+ if (!c_parser_require (parser, CPP_PRAGMA_EOL, "expected end of line"))
+ while (true)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ break;
+ if (token->type == CPP_PRAGMA_EOL)
+ {
+ c_parser_consume_token (parser);
+ break;
+ }
+ c_parser_consume_token (parser);
+ }
+
+ parser->error = false;
+}
+
+/* Skip tokens until we have consumed an entire block, or until we
+ have consumed a non-nested ';'. */
+
+static void
+c_parser_skip_to_end_of_block_or_statement (c_parser *parser)
+{
+ unsigned nesting_depth = 0;
+ bool save_error = parser->error;
+
+ while (true)
+ {
+ c_token *token;
+
+ /* Peek at the next token. */
+ token = c_parser_peek_token (parser);
+
+ switch (token->type)
+ {
+ case CPP_EOF:
+ return;
+
+ case CPP_PRAGMA_EOL:
+ if (parser->in_pragma)
+ return;
+ break;
+
+ case CPP_SEMICOLON:
+ /* If the next token is a ';', we have reached the
+ end of the statement. */
+ if (!nesting_depth)
+ {
+ /* Consume the ';'. */
+ c_parser_consume_token (parser);
+ goto finished;
+ }
+ break;
+
+ case CPP_CLOSE_BRACE:
+ /* If the next token is a non-nested '}', then we have
+ reached the end of the current block. */
+ if (nesting_depth == 0 || --nesting_depth == 0)
+ {
+ c_parser_consume_token (parser);
+ goto finished;
+ }
+ break;
+
+ case CPP_OPEN_BRACE:
+ /* If it the next token is a '{', then we are entering a new
+ block. Consume the entire block. */
+ ++nesting_depth;
+ break;
+
+ case CPP_PRAGMA:
+ /* If we see a pragma, consume the whole thing at once. We
+ have some safeguards against consuming pragmas willy-nilly.
+ Normally, we'd expect to be here with parser->error set,
+ which disables these safeguards. But it's possible to get
+ here for secondary error recovery, after parser->error has
+ been cleared. */
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+ parser->error = save_error;
+ continue;
+
+ default:
+ break;
+ }
+
+ c_parser_consume_token (parser);
+ }
+
+ finished:
+ parser->error = false;
+}
+
+/* CPP's options (initialized by c-opts.c). */
+extern cpp_options *cpp_opts;
+
+/* Save the warning flags which are controlled by __extension__. */
+
+static inline int
+disable_extension_diagnostics (void)
+{
+ int ret = (pedantic
+ | (warn_pointer_arith << 1)
+ | (warn_traditional << 2)
+ | (flag_iso << 3)
+ | (warn_long_long << 4)
+ | (warn_cxx_compat << 5)
+ | (warn_overlength_strings << 6));
+ cpp_opts->cpp_pedantic = pedantic = 0;
+ warn_pointer_arith = 0;
+ cpp_opts->cpp_warn_traditional = warn_traditional = 0;
+ flag_iso = 0;
+ cpp_opts->cpp_warn_long_long = warn_long_long = 0;
+ warn_cxx_compat = 0;
+ warn_overlength_strings = 0;
+ return ret;
+}
+
+/* Restore the warning flags which are controlled by __extension__.
+ FLAGS is the return value from disable_extension_diagnostics. */
+
+static inline void
+restore_extension_diagnostics (int flags)
+{
+ cpp_opts->cpp_pedantic = pedantic = flags & 1;
+ warn_pointer_arith = (flags >> 1) & 1;
+ cpp_opts->cpp_warn_traditional = warn_traditional = (flags >> 2) & 1;
+ flag_iso = (flags >> 3) & 1;
+ cpp_opts->cpp_warn_long_long = warn_long_long = (flags >> 4) & 1;
+ warn_cxx_compat = (flags >> 5) & 1;
+ warn_overlength_strings = (flags >> 6) & 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;
+
+/* The binary operation precedence levels, where 0 is a dummy lowest level
+ used for the bottom of the stack. */
+enum c_parser_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
+};
+
+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, bool, tree *);
+static void c_parser_static_assert_declaration_no_semi (c_parser *);
+static void c_parser_static_assert_declaration (c_parser *);
+static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
+ bool, enum c_lookahead_kind);
+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 tree c_parser_alignas_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,
+ 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 *, struct obstack *);
+static void c_parser_initval (c_parser *, struct c_expr *,
+ struct obstack *);
+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 *);
+static tree c_parser_asm_goto_operands (c_parser *);
+static tree c_parser_asm_clobbers (c_parser *);
+static struct c_expr c_parser_expr_no_commas (c_parser *, struct c_expr *);
+static struct c_expr c_parser_conditional_expression (c_parser *,
+ struct c_expr *);
+static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
+ enum c_parser_prec);
+static struct c_expr c_parser_cast_expression (c_parser *, struct c_expr *);
+static struct c_expr c_parser_unary_expression (c_parser *);
+static struct c_expr c_parser_sizeof_expression (c_parser *);
+static struct c_expr c_parser_alignof_expression (c_parser *);
+static struct c_expr c_parser_postfix_expression (c_parser *);
+static struct c_expr c_parser_postfix_expression_after_paren_type (c_parser *,
+ struct c_type_name *,
+ location_t);
+static struct c_expr c_parser_postfix_expression_after_primary (c_parser *,
+ location_t loc,
+ struct c_expr);
+static tree c_parser_transaction (c_parser *, enum rid);
+static struct c_expr c_parser_transaction_expression (c_parser *, enum rid);
+static tree c_parser_transaction_cancel (c_parser *);
+static struct c_expr c_parser_expression (c_parser *);
+static struct c_expr c_parser_expression_conv (c_parser *);
+static vec<tree, va_gc> *c_parser_expr_list (c_parser *, bool, bool,
+ vec<tree, va_gc> **, location_t *,
+ tree *);
+static void c_parser_omp_construct (c_parser *);
+static void c_parser_omp_threadprivate (c_parser *);
+static void c_parser_omp_barrier (c_parser *);
+static void c_parser_omp_flush (c_parser *);
+static void c_parser_omp_taskwait (c_parser *);
+static void c_parser_omp_taskyield (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 *, tree);
+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 *, tree);
+static bool 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 *, bool, tree *, tree *);
+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_finally_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 *);
+static void c_parser_objc_at_property_declaration (c_parser *);
+static void c_parser_objc_at_synthesize_declaration (c_parser *);
+static void c_parser_objc_at_dynamic_declaration (c_parser *);
+static bool c_parser_objc_diagnose_bad_element_prefix
+ (c_parser *, struct c_declspecs *);
+
+/* Parse a translation unit (C90 6.7, C99 6.9).
+
+ translation-unit:
+ external-declarations
+
+ external-declarations:
+ external-declaration
+ external-declarations external-declaration
+
+ GNU extensions:
+
+ translation-unit:
+ empty
+*/
+
+static void
+c_parser_translation_unit (c_parser *parser)
+{
+ if (c_parser_next_token_is (parser, CPP_EOF))
+ {
+ pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic,
+ "ISO C forbids an empty translation unit");
+ }
+ else
+ {
+ void *obstack_position = obstack_alloc (&parser_obstack, 0);
+ mark_valid_location_for_stdc_pragma (false);
+ do
+ {
+ ggc_collect ();
+ c_parser_external_declaration (parser);
+ obstack_free (&parser_obstack, obstack_position);
+ }
+ while (c_parser_next_token_is_not (parser, CPP_EOF));
+ }
+}
+
+/* Parse an external declaration (C90 6.7, C99 6.9).
+
+ external-declaration:
+ function-definition
+ declaration
+
+ GNU extensions:
+
+ external-declaration:
+ asm-definition
+ ;
+ __extension__ external-declaration
+
+ Objective-C:
+
+ external-declaration:
+ objc-class-definition
+ objc-class-declaration
+ objc-alias-declaration
+ objc-protocol-definition
+ objc-method-definition
+ @end
+*/
+
+static void
+c_parser_external_declaration (c_parser *parser)
+{
+ int ext;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_KEYWORD:
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_EXTENSION:
+ ext = disable_extension_diagnostics ();
+ c_parser_consume_token (parser);
+ c_parser_external_declaration (parser);
+ restore_extension_diagnostics (ext);
+ break;
+ case RID_ASM:
+ c_parser_asm_definition (parser);
+ break;
+ case RID_AT_INTERFACE:
+ case RID_AT_IMPLEMENTATION:
+ gcc_assert (c_dialect_objc ());
+ c_parser_objc_class_definition (parser, NULL_TREE);
+ 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, NULL_TREE);
+ break;
+ case RID_AT_PROPERTY:
+ gcc_assert (c_dialect_objc ());
+ c_parser_objc_at_property_declaration (parser);
+ break;
+ case RID_AT_SYNTHESIZE:
+ gcc_assert (c_dialect_objc ());
+ c_parser_objc_at_synthesize_declaration (parser);
+ break;
+ case RID_AT_DYNAMIC:
+ gcc_assert (c_dialect_objc ());
+ c_parser_objc_at_dynamic_declaration (parser);
+ break;
+ case RID_AT_END:
+ gcc_assert (c_dialect_objc ());
+ c_parser_consume_token (parser);
+ objc_finish_implementation ();
+ break;
+ default:
+ goto decl_or_fndef;
+ }
+ break;
+ case CPP_SEMICOLON:
+ pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic,
+ "ISO C does not allow extra %<;%> outside of a function");
+ c_parser_consume_token (parser);
+ break;
+ case CPP_PRAGMA:
+ mark_valid_location_for_stdc_pragma (true);
+ c_parser_pragma (parser, pragma_external);
+ mark_valid_location_for_stdc_pragma (false);
+ break;
+ case CPP_PLUS:
+ case CPP_MINUS:
+ if (c_dialect_objc ())
+ {
+ c_parser_objc_method_definition (parser);
+ break;
+ }
+ /* Else fall through, and yield a syntax error trying to parse
+ as a declaration or function definition. */
+ default:
+ decl_or_fndef:
+ /* A declaration or a function definition (or, in Objective-C,
+ an @interface or @protocol with prefix attributes). We can
+ only tell which after parsing the declaration specifiers, if
+ any, and the first declarator. */
+ c_parser_declaration_or_fndef (parser, true, true, true, false, true, NULL);
+ 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 STATIC_ASSERT_OK is true, a static
+ assertion is accepted; otherwise (old-style parameter declarations)
+ it is not. 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.
+ OBJC_FOREACH_OBJECT_DECLARATION can be used to get back the parsed
+ declaration when parsing an Objective-C foreach statement.
+
+ declaration:
+ declaration-specifiers init-declarator-list[opt] ;
+ static_assert-declaration
+
+ 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
+
+ Objective-C:
+ attributes objc-class-definition
+ attributes objc-category-definition
+ attributes objc-protocol-definition
+
+ 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).
+
+ In Objective-C, declarations of the looping variable in a foreach
+ statement are exceptionally terminated by 'in' (for example, 'for
+ (NSObject *object in array) { ... }').
+
+ OpenMP:
+
+ declaration:
+ threadprivate-directive */
+
+static void
+c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
+ bool static_assert_ok, bool empty_ok,
+ bool nested, bool start_attr_ok,
+ tree *objc_foreach_object_declaration)
+{
+ struct c_declspecs *specs;
+ tree prefix_attrs;
+ tree all_prefix_attrs;
+ bool diagnosed_no_specs = false;
+ location_t here = c_parser_peek_token (parser)->location;
+
+ if (static_assert_ok
+ && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
+ {
+ c_parser_static_assert_declaration (parser);
+ return;
+ }
+ specs = build_null_declspecs ();
+
+ /* Try to detect an unknown type name when we have "A B" or "A *B". */
+ if (c_parser_peek_token (parser)->type == CPP_NAME
+ && c_parser_peek_token (parser)->id_kind == C_ID_ID
+ && (c_parser_peek_2nd_token (parser)->type == CPP_NAME
+ || c_parser_peek_2nd_token (parser)->type == CPP_MULT)
+ && (!nested || !lookup_name (c_parser_peek_token (parser)->value)))
+ {
+ error_at (here, "unknown type name %qE",
+ c_parser_peek_token (parser)->value);
+
+ /* Parse declspecs normally to get a correct pointer type, but avoid
+ a further "fails to be a type name" error. Refuse nested functions
+ since it is not how the user likely wants us to recover. */
+ c_parser_peek_token (parser)->type = CPP_KEYWORD;
+ c_parser_peek_token (parser)->keyword = RID_VOID;
+ c_parser_peek_token (parser)->value = error_mark_node;
+ fndef_ok = !nested;
+ }
+
+ c_parser_declspecs (parser, specs, true, true, start_attr_ok, cla_nonabstract_decl);
+ if (parser->error)
+ {
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
+ if (nested && !specs->declspecs_seen_p)
+ {
+ c_parser_error (parser, "expected declaration specifiers");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
+ finish_declspecs (specs);
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ if (empty_ok)
+ shadow_tag (specs);
+ else
+ {
+ shadow_tag_warned (specs, 1);
+ pedwarn (here, 0, "empty declaration");
+ }
+ c_parser_consume_token (parser);
+ return;
+ }
+
+ /* Provide better error recovery. Note that a type name here is usually
+ better diagnosed as a redeclaration. */
+ if (empty_ok
+ && specs->typespec_kind == ctsk_tagdef
+ && c_parser_next_token_starts_declspecs (parser)
+ && !c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected %<;%>, identifier or %<(%>");
+ parser->error = false;
+ shadow_tag_warned (specs, 1);
+ return;
+ }
+ else if (c_dialect_objc ())
+ {
+ /* Prefix attributes are an error on method decls. */
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_PLUS:
+ case CPP_MINUS:
+ if (c_parser_objc_diagnose_bad_element_prefix (parser, specs))
+ return;
+ if (specs->attrs)
+ {
+ warning_at (c_parser_peek_token (parser)->location,
+ OPT_Wattributes,
+ "prefix attributes are ignored for methods");
+ specs->attrs = NULL_TREE;
+ }
+ if (fndef_ok)
+ c_parser_objc_method_definition (parser);
+ else
+ c_parser_objc_methodproto (parser);
+ return;
+ break;
+ default:
+ break;
+ }
+ /* This is where we parse 'attributes @interface ...',
+ 'attributes @implementation ...', 'attributes @protocol ...'
+ (where attributes could be, for example, __attribute__
+ ((deprecated)).
+ */
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_AT_INTERFACE:
+ {
+ if (c_parser_objc_diagnose_bad_element_prefix (parser, specs))
+ return;
+ c_parser_objc_class_definition (parser, specs->attrs);
+ return;
+ }
+ break;
+ case RID_AT_IMPLEMENTATION:
+ {
+ if (c_parser_objc_diagnose_bad_element_prefix (parser, specs))
+ return;
+ if (specs->attrs)
+ {
+ warning_at (c_parser_peek_token (parser)->location,
+ OPT_Wattributes,
+ "prefix attributes are ignored for implementations");
+ specs->attrs = NULL_TREE;
+ }
+ c_parser_objc_class_definition (parser, NULL_TREE);
+ return;
+ }
+ break;
+ case RID_AT_PROTOCOL:
+ {
+ if (c_parser_objc_diagnose_bad_element_prefix (parser, specs))
+ return;
+ c_parser_objc_protocol_definition (parser, specs->attrs);
+ return;
+ }
+ break;
+ case RID_AT_ALIAS:
+ case RID_AT_CLASS:
+ case RID_AT_END:
+ case RID_AT_PROPERTY:
+ if (specs->attrs)
+ {
+ c_parser_error (parser, "unexpected attribute");
+ specs->attrs = NULL;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ 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;
+ timevar_id_t tv;
+ 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->typespec_kind != ctsk_none,
+ 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)
+ || c_parser_next_token_is_keyword (parser, RID_IN))
+ {
+ tree asm_name = NULL_TREE;
+ tree postfix_attrs = NULL_TREE;
+ if (!diagnosed_no_specs && !specs->declspecs_seen_p)
+ {
+ diagnosed_no_specs = true;
+ pedwarn (here, 0, "data definition has no type or storage class");
+ }
+ /* Having seen a data definition, there cannot now be a
+ function definition. */
+ fndef_ok = false;
+ if (c_parser_next_token_is_keyword (parser, RID_ASM))
+ asm_name = c_parser_simple_asm_expr (parser);
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ postfix_attrs = c_parser_attributes (parser);
+ if (c_parser_next_token_is (parser, CPP_EQ))
+ {
+ tree d;
+ struct c_expr init;
+ location_t init_loc;
+ c_parser_consume_token (parser);
+ /* The declaration of the variable is in effect while
+ its initializer is parsed. */
+ d = start_decl (declarator, specs, true,
+ chainon (postfix_attrs, all_prefix_attrs));
+ if (!d)
+ d = error_mark_node;
+ start_init (d, asm_name, global_bindings_p ());
+ init_loc = c_parser_peek_token (parser)->location;
+ init = c_parser_initializer (parser);
+ finish_init ();
+ if (d != error_mark_node)
+ {
+ maybe_warn_string_init (TREE_TYPE (d), init);
+ finish_decl (d, init_loc, init.value,
+ init.original_type, asm_name);
+ }
+ }
+ else
+ {
+ tree d = start_decl (declarator, specs, false,
+ chainon (postfix_attrs,
+ all_prefix_attrs));
+ if (d)
+ finish_decl (d, UNKNOWN_LOCATION, NULL_TREE,
+ NULL_TREE, asm_name);
+
+ if (c_parser_next_token_is_keyword (parser, RID_IN))
+ {
+ if (d)
+ *objc_foreach_object_declaration = d;
+ else
+ *objc_foreach_object_declaration = error_mark_node;
+ }
+ }
+ 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 if (c_parser_next_token_is_keyword (parser, RID_IN))
+ {
+ /* This can only happen in Objective-C: we found the
+ 'in' that terminates the declaration inside an
+ Objective-C foreach statement. Do not consume the
+ token, so that the caller can use it to determine
+ that this indeed is a foreach context. */
+ return;
+ }
+ else
+ {
+ c_parser_error (parser, "expected %<,%> or %<;%>");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
+ }
+ else if (!fndef_ok)
+ {
+ c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, "
+ "%<asm%> or %<__attribute__%>");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
+ /* Function definition (nested or otherwise). */
+ if (nested)
+ {
+ pedwarn (here, OPT_Wpedantic, "ISO C forbids nested functions");
+ c_push_function_context ();
+ }
+ if (!start_function (specs, declarator, all_prefix_attrs))
+ {
+ /* This can appear in many cases looking nothing like a
+ function definition, so we don't give a more specific
+ error suggesting there was one. */
+ c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, %<asm%> "
+ "or %<__attribute__%>");
+ if (nested)
+ c_pop_function_context ();
+ break;
+ }
+
+ if (DECL_DECLARED_INLINE_P (current_function_decl))
+ tv = TV_PARSE_INLINE;
+ else
+ tv = TV_PARSE_FUNC;
+ timevar_push (tv);
+
+ /* 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, false,
+ true, false, NULL);
+ store_parm_decls ();
+ DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
+ = c_parser_peek_token (parser)->location;
+ fnbody = c_parser_compound_statement (parser);
+ if (nested)
+ {
+ tree decl = current_function_decl;
+ /* Mark nested functions as needing static-chain initially.
+ lower_nested_functions will recompute it but the
+ DECL_STATIC_CHAIN flag is also used before that happens,
+ by initializer_constant_valid_p. See gcc.dg/nested-fn-2.c. */
+ DECL_STATIC_CHAIN (decl) = 1;
+ add_stmt (fnbody);
+ finish_function ();
+ c_pop_function_context ();
+ add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
+ }
+ else
+ {
+ add_stmt (fnbody);
+ finish_function ();
+ }
+
+ timevar_pop (tv);
+ 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)
+ add_asm_node (asm_str);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+}
+
+/* Parse a static assertion (C11 6.7.10).
+
+ static_assert-declaration:
+ static_assert-declaration-no-semi ;
+*/
+
+static void
+c_parser_static_assert_declaration (c_parser *parser)
+{
+ c_parser_static_assert_declaration_no_semi (parser);
+ if (parser->error
+ || !c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ c_parser_skip_to_end_of_block_or_statement (parser);
+}
+
+/* Parse a static assertion (C11 6.7.10), without the trailing
+ semicolon.
+
+ static_assert-declaration-no-semi:
+ _Static_assert ( constant-expression , string-literal )
+*/
+
+static void
+c_parser_static_assert_declaration_no_semi (c_parser *parser)
+{
+ location_t assert_loc, value_loc;
+ tree value;
+ tree string;
+
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT));
+ assert_loc = c_parser_peek_token (parser)->location;
+ if (!flag_isoc11)
+ {
+ if (flag_isoc99)
+ pedwarn (assert_loc, OPT_Wpedantic,
+ "ISO C99 does not support %<_Static_assert%>");
+ else
+ pedwarn (assert_loc, OPT_Wpedantic,
+ "ISO C90 does not support %<_Static_assert%>");
+ }
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return;
+ value_loc = c_parser_peek_token (parser)->location;
+ value = c_parser_expr_no_commas (parser, NULL).value;
+ parser->lex_untranslated_string = true;
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ parser->lex_untranslated_string = false;
+ return;
+ }
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_STRING:
+ case CPP_STRING16:
+ case CPP_STRING32:
+ case CPP_WSTRING:
+ case CPP_UTF8STRING:
+ string = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ parser->lex_untranslated_string = false;
+ break;
+ default:
+ c_parser_error (parser, "expected string literal");
+ parser->lex_untranslated_string = false;
+ return;
+ }
+ c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (value)))
+ {
+ error_at (value_loc, "expression in static assertion is not an integer");
+ return;
+ }
+ if (TREE_CODE (value) != INTEGER_CST)
+ {
+ value = c_fully_fold (value, false, NULL);
+ if (TREE_CODE (value) == INTEGER_CST)
+ pedwarn (value_loc, OPT_Wpedantic, "expression in static assertion "
+ "is not an integer constant expression");
+ }
+ if (TREE_CODE (value) != INTEGER_CST)
+ {
+ error_at (value_loc, "expression in static assertion is not constant");
+ return;
+ }
+ constant_expression_warning (value);
+ if (integer_zerop (value))
+ error_at (assert_loc, "static assertion failed: %E", string);
+}
+
+/* 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]
+ alignment-specifier declaration-specifiers[opt]
+
+ Function specifiers (inline) are from C99, and are currently
+ handled as storage class specifiers, as is __thread. Alignment
+ specifiers are from C11.
+
+ C90 6.5.1, C99 6.7.1:
+ storage-class-specifier:
+ typedef
+ extern
+ static
+ auto
+ register
+
+ C99 6.7.4:
+ function-specifier:
+ inline
+ _Noreturn
+
+ (_Noreturn is new in C11.)
+
+ C90 6.5.2, C99 6.7.2:
+ type-specifier:
+ void
+ char
+ short
+ int
+ long
+ float
+ double
+ signed
+ unsigned
+ _Bool
+ _Complex
+ [_Imaginary removed in C99 TC2]
+ struct-or-union-specifier
+ enum-specifier
+ typedef-name
+
+ (_Bool and _Complex are new in C99.)
+
+ C90 6.5.3, C99 6.7.3:
+
+ type-qualifier:
+ const
+ restrict
+ volatile
+ address-space-qualifier
+
+ (restrict is new in C99.)
+
+ GNU extensions:
+
+ declaration-specifiers:
+ attributes declaration-specifiers[opt]
+
+ type-qualifier:
+ address-space
+
+ address-space:
+ identifier recognized by the target
+
+ storage-class-specifier:
+ __thread
+
+ type-specifier:
+ typeof-specifier
+ __int128
+ _Decimal32
+ _Decimal64
+ _Decimal128
+ _Fract
+ _Accum
+ _Sat
+
+ (_Fract, _Accum, and _Sat are new from ISO/IEC DTR 18037:
+ http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1169.pdf)
+
+ Objective-C:
+
+ type-specifier:
+ class-name objc-protocol-refs[opt]
+ typedef-name objc-protocol-refs
+ objc-protocol-refs
+*/
+
+static void
+c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
+ bool scspec_ok, bool typespec_ok, bool start_attr_ok,
+ enum c_lookahead_kind la)
+{
+ bool attrs_ok = start_attr_ok;
+ bool seen_type = specs->typespec_kind != ctsk_none;
+
+ if (!typespec_ok)
+ gcc_assert (la == cla_prefer_id);
+
+ 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;
+ tree align;
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ /* If we cannot accept a type, exit if the next token must start
+ one. Also, if we already have seen a tagged definition,
+ a typename would be an error anyway and likely the user
+ has simply forgotten a semicolon, so we exit. */
+ if ((!typespec_ok || specs->typespec_kind == ctsk_tagdef)
+ && c_parser_next_tokens_start_typename (parser, la)
+ && !c_parser_next_token_is_qualifier (parser))
+ break;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_token *name_token = c_parser_peek_token (parser);
+ tree value = name_token->value;
+ c_id_kind kind = name_token->id_kind;
+
+ if (kind == C_ID_ADDRSPACE)
+ {
+ addr_space_t as
+ = name_token->keyword - RID_FIRST_ADDR_SPACE;
+ declspecs_add_addrspace (name_token->location, specs, as);
+ c_parser_consume_token (parser);
+ attrs_ok = true;
+ continue;
+ }
+
+ gcc_assert (!c_parser_next_token_is_qualifier (parser));
+
+ /* If we cannot accept a type, and the next token must start one,
+ exit. Do the same if we already have seen a tagged definition,
+ since it would be an error anyway and likely the user has simply
+ forgotten a semicolon. */
+ if (seen_type || !c_parser_next_tokens_start_typename (parser, la))
+ break;
+
+ /* Now at an unknown typename (C_ID_ID), a C_ID_TYPENAME or
+ a C_ID_CLASSNAME. */
+ c_parser_consume_token (parser);
+ seen_type = true;
+ attrs_ok = true;
+ if (kind == C_ID_ID)
+ {
+ error ("unknown type name %qE", value);
+ t.kind = ctsk_typedef;
+ t.spec = error_mark_node;
+ }
+ else 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);
+ }
+ t.expr = NULL_TREE;
+ t.expr_const_operands = true;
+ declspecs_add_type (name_token->location, specs, t);
+ continue;
+ }
+ if (c_parser_next_token_is (parser, CPP_LESS))
+ {
+ /* Make "<SomeProtocol>" equivalent to "id <SomeProtocol>" -
+ nisse@lysator.liu.se. */
+ tree proto;
+ gcc_assert (c_dialect_objc ());
+ if (!typespec_ok || seen_type)
+ break;
+ proto = c_parser_objc_protocol_refs (parser);
+ t.kind = ctsk_objc;
+ t.spec = objc_get_protocol_qualified_type (NULL_TREE, proto);
+ t.expr = NULL_TREE;
+ t.expr_const_operands = true;
+ declspecs_add_type (loc, specs, t);
+ continue;
+ }
+ gcc_assert (c_parser_next_token_is (parser, CPP_KEYWORD));
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_STATIC:
+ case RID_EXTERN:
+ case RID_REGISTER:
+ case RID_TYPEDEF:
+ case RID_INLINE:
+ case RID_NORETURN:
+ case RID_AUTO:
+ case RID_THREAD:
+ if (!scspec_ok)
+ goto out;
+ attrs_ok = true;
+ /* TODO: Distinguish between function specifiers (inline, noreturn)
+ and storage class specifiers, either here or in
+ declspecs_add_scspec. */
+ declspecs_add_scspec (loc, specs,
+ c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ break;
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_INT128:
+ case RID_SHORT:
+ case RID_SIGNED:
+ case RID_COMPLEX:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ case RID_BOOL:
+ case RID_FRACT:
+ case RID_ACCUM:
+ case RID_SAT:
+ if (!typespec_ok)
+ goto out;
+ attrs_ok = true;
+ seen_type = true;
+ if (c_dialect_objc ())
+ parser->objc_need_raw_identifier = true;
+ t.kind = ctsk_resword;
+ t.spec = c_parser_peek_token (parser)->value;
+ t.expr = NULL_TREE;
+ t.expr_const_operands = true;
+ declspecs_add_type (loc, specs, t);
+ c_parser_consume_token (parser);
+ break;
+ case RID_ENUM:
+ if (!typespec_ok)
+ goto out;
+ attrs_ok = true;
+ seen_type = true;
+ t = c_parser_enum_specifier (parser);
+ declspecs_add_type (loc, specs, t);
+ break;
+ case RID_STRUCT:
+ case RID_UNION:
+ if (!typespec_ok)
+ goto out;
+ attrs_ok = true;
+ seen_type = true;
+ t = c_parser_struct_or_union_specifier (parser);
+ invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec);
+ declspecs_add_type (loc, specs, t);
+ break;
+ case RID_TYPEOF:
+ /* ??? The old parser rejected typeof after other type
+ specifiers, but is a syntax error the best way of
+ handling this? */
+ if (!typespec_ok || seen_type)
+ goto out;
+ attrs_ok = true;
+ seen_type = true;
+ t = c_parser_typeof_specifier (parser);
+ declspecs_add_type (loc, specs, t);
+ break;
+ case RID_CONST:
+ case RID_VOLATILE:
+ case RID_RESTRICT:
+ attrs_ok = true;
+ declspecs_add_qual (loc, 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 (loc, specs, attrs);
+ break;
+ case RID_ALIGNAS:
+ align = c_parser_alignas_specifier (parser);
+ declspecs_add_alignas (loc, specs, align);
+ break;
+ default:
+ goto out;
+ }
+ }
+ out: ;
+}
+
+/* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2).
+
+ enum-specifier:
+ enum attributes[opt] identifier[opt] { enumerator-list } attributes[opt]
+ enum attributes[opt] identifier[opt] { enumerator-list , } attributes[opt]
+ enum attributes[opt] identifier
+
+ The form with trailing comma is new in C99. The forms with
+ attributes are GNU extensions. In GNU C, we accept any expression
+ without commas in the syntax (assignment expressions, not just
+ conditional expressions); assignment expressions will be diagnosed
+ as non-constant.
+
+ enumerator-list:
+ enumerator
+ enumerator-list , enumerator
+
+ enumerator:
+ enumeration-constant
+ enumeration-constant = constant-expression
+*/
+
+static struct c_typespec
+c_parser_enum_specifier (c_parser *parser)
+{
+ struct c_typespec ret;
+ tree attrs;
+ tree ident = NULL_TREE;
+ location_t enum_loc;
+ location_t ident_loc = UNKNOWN_LOCATION; /* Quiet warning. */
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ENUM));
+ enum_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ attrs = c_parser_attributes (parser);
+ enum_loc = c_parser_peek_token (parser)->location;
+ /* Set the location in case we create a decl now. */
+ c_parser_set_source_position_from_token (c_parser_peek_token (parser));
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ ident = c_parser_peek_token (parser)->value;
+ ident_loc = c_parser_peek_token (parser)->location;
+ enum_loc = ident_loc;
+ c_parser_consume_token (parser);
+ }
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ /* Parse an enum definition. */
+ struct c_enum_contents the_enum;
+ tree type;
+ tree postfix_attrs;
+ /* We chain the enumerators in reverse order, then put them in
+ forward order at the end. */
+ tree values;
+ timevar_push (TV_PARSE_ENUM);
+ type = start_enum (enum_loc, &the_enum, ident);
+ values = NULL_TREE;
+ c_parser_consume_token (parser);
+ while (true)
+ {
+ tree enum_id;
+ tree enum_value;
+ tree enum_decl;
+ bool seen_comma;
+ c_token *token;
+ location_t comma_loc = UNKNOWN_LOCATION; /* Quiet warning. */
+ location_t decl_loc, value_loc;
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+ values = error_mark_node;
+ break;
+ }
+ token = c_parser_peek_token (parser);
+ enum_id = token->value;
+ /* Set the location in case we create a decl now. */
+ c_parser_set_source_position_from_token (token);
+ decl_loc = value_loc = token->location;
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_EQ))
+ {
+ c_parser_consume_token (parser);
+ value_loc = c_parser_peek_token (parser)->location;
+ enum_value = c_parser_expr_no_commas (parser, NULL).value;
+ }
+ else
+ enum_value = NULL_TREE;
+ enum_decl = build_enumerator (decl_loc, value_loc,
+ &the_enum, enum_id, enum_value);
+ TREE_CHAIN (enum_decl) = values;
+ values = enum_decl;
+ seen_comma = false;
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ comma_loc = c_parser_peek_token (parser)->location;
+ seen_comma = true;
+ c_parser_consume_token (parser);
+ }
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ if (seen_comma && !flag_isoc99)
+ pedwarn (comma_loc, OPT_Wpedantic, "comma at end of enumerator list");
+ c_parser_consume_token (parser);
+ break;
+ }
+ if (!seen_comma)
+ {
+ c_parser_error (parser, "expected %<,%> or %<}%>");
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+ values = error_mark_node;
+ break;
+ }
+ }
+ postfix_attrs = c_parser_attributes (parser);
+ ret.spec = finish_enum (type, nreverse (values),
+ chainon (attrs, postfix_attrs));
+ ret.kind = ctsk_tagdef;
+ ret.expr = NULL_TREE;
+ ret.expr_const_operands = true;
+ timevar_pop (TV_PARSE_ENUM);
+ return ret;
+ }
+ else if (!ident)
+ {
+ c_parser_error (parser, "expected %<{%>");
+ ret.spec = error_mark_node;
+ ret.kind = ctsk_tagref;
+ ret.expr = NULL_TREE;
+ ret.expr_const_operands = true;
+ return ret;
+ }
+ ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident);
+ /* In ISO C, enumerated types can be referred to only if already
+ defined. */
+ if (pedantic && !COMPLETE_TYPE_P (ret.spec))
+ {
+ gcc_assert (ident);
+ pedwarn (enum_loc, OPT_Wpedantic,
+ "ISO C forbids forward references to %<enum%> types");
+ }
+ return ret;
+}
+
+/* Parse a struct or union specifier (C90 6.5.2.1, C99 6.7.2.1).
+
+ struct-or-union-specifier:
+ struct-or-union attributes[opt] identifier[opt]
+ { struct-contents } attributes[opt]
+ struct-or-union attributes[opt] identifier
+
+ struct-contents:
+ struct-declaration-list
+
+ struct-declaration-list:
+ struct-declaration ;
+ struct-declaration-list struct-declaration ;
+
+ GNU extensions:
+
+ struct-contents:
+ empty
+ struct-declaration
+ struct-declaration-list struct-declaration
+
+ struct-declaration-list:
+ struct-declaration-list ;
+ ;
+
+ (Note that in the syntax here, unlike that in ISO C, the semicolons
+ are included here rather than in struct-declaration, in order to
+ describe the syntax with extra semicolons and missing semicolon at
+ end.)
+
+ Objective-C:
+
+ struct-declaration-list:
+ @defs ( class-name )
+
+ (Note this does not include a trailing semicolon, but can be
+ followed by further declarations, and gets a pedwarn-if-pedantic
+ when followed by a semicolon.) */
+
+static struct c_typespec
+c_parser_struct_or_union_specifier (c_parser *parser)
+{
+ struct c_typespec ret;
+ tree attrs;
+ tree ident = NULL_TREE;
+ location_t struct_loc;
+ location_t ident_loc = UNKNOWN_LOCATION;
+ enum tree_code code;
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_STRUCT:
+ code = RECORD_TYPE;
+ break;
+ case RID_UNION:
+ code = UNION_TYPE;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ struct_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ attrs = c_parser_attributes (parser);
+
+ /* Set the location in case we create a decl now. */
+ c_parser_set_source_position_from_token (c_parser_peek_token (parser));
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ ident = c_parser_peek_token (parser)->value;
+ ident_loc = c_parser_peek_token (parser)->location;
+ struct_loc = ident_loc;
+ c_parser_consume_token (parser);
+ }
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ /* Parse a struct or union definition. Start the scope of the
+ tag before parsing components. */
+ struct c_struct_parse_info *struct_info;
+ tree type = start_struct (struct_loc, code, ident, &struct_info);
+ tree postfix_attrs;
+ /* We chain the components in reverse order, then put them in
+ forward order at the end. Each struct-declaration may
+ declare multiple components (comma-separated), so we must use
+ chainon to join them, although when parsing each
+ struct-declaration we can use TREE_CHAIN directly.
+
+ The theory behind all this is that there will be more
+ semicolon separated fields than comma separated fields, and
+ so we'll be minimizing the number of node traversals required
+ by chainon. */
+ tree contents;
+ timevar_push (TV_PARSE_STRUCT);
+ contents = NULL_TREE;
+ c_parser_consume_token (parser);
+ /* Handle the Objective-C @defs construct,
+ e.g. foo(sizeof(struct{ @defs(ClassName) }));. */
+ if (c_parser_next_token_is_keyword (parser, RID_AT_DEFS))
+ {
+ tree name;
+ gcc_assert (c_dialect_objc ());
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ goto end_at_defs;
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME)
+ {
+ name = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ c_parser_error (parser, "expected class name");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ goto end_at_defs;
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ contents = nreverse (objc_get_class_ivars (name));
+ }
+ end_at_defs:
+ /* Parse the struct-declarations and semicolons. Problems with
+ semicolons are diagnosed here; empty structures are diagnosed
+ elsewhere. */
+ while (true)
+ {
+ tree decls;
+ /* Parse any stray semicolon. */
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic,
+ "extra semicolon in struct or union specified");
+ c_parser_consume_token (parser);
+ continue;
+ }
+ /* Stop if at the end of the struct or union contents. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ c_parser_consume_token (parser);
+ break;
+ }
+ /* Accept #pragmas at struct scope. */
+ if (c_parser_next_token_is (parser, CPP_PRAGMA))
+ {
+ c_parser_pragma (parser, pragma_external);
+ continue;
+ }
+ /* Parse some comma-separated declarations, but not the
+ trailing semicolon if any. */
+ decls = c_parser_struct_declaration (parser);
+ contents = chainon (decls, contents);
+ /* If no semicolon follows, either we have a parse error or
+ are at the end of the struct or union and should
+ pedwarn. */
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ c_parser_consume_token (parser);
+ else
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ pedwarn (c_parser_peek_token (parser)->location, 0,
+ "no semicolon at end of struct or union");
+ else if (parser->error
+ || !c_parser_next_token_starts_declspecs (parser))
+ {
+ c_parser_error (parser, "expected %<;%>");
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+ break;
+ }
+
+ /* If we come here, we have already emitted an error
+ for an expected `;', identifier or `(', and we also
+ recovered already. Go on with the next field. */
+ }
+ }
+ postfix_attrs = c_parser_attributes (parser);
+ ret.spec = finish_struct (struct_loc, type, nreverse (contents),
+ chainon (attrs, postfix_attrs), struct_info);
+ ret.kind = ctsk_tagdef;
+ ret.expr = NULL_TREE;
+ ret.expr_const_operands = true;
+ timevar_pop (TV_PARSE_STRUCT);
+ return ret;
+ }
+ else if (!ident)
+ {
+ c_parser_error (parser, "expected %<{%>");
+ ret.spec = error_mark_node;
+ ret.kind = ctsk_tagref;
+ ret.expr = NULL_TREE;
+ ret.expr_const_operands = true;
+ return ret;
+ }
+ ret = parser_xref_tag (ident_loc, code, ident);
+ return ret;
+}
+
+/* Parse a struct-declaration (C90 6.5.2.1, C99 6.7.2.1), *without*
+ the trailing semicolon.
+
+ struct-declaration:
+ specifier-qualifier-list struct-declarator-list
+ static_assert-declaration-no-semi
+
+ specifier-qualifier-list:
+ type-specifier specifier-qualifier-list[opt]
+ type-qualifier specifier-qualifier-list[opt]
+ attributes specifier-qualifier-list[opt]
+
+ struct-declarator-list:
+ struct-declarator
+ struct-declarator-list , attributes[opt] struct-declarator
+
+ struct-declarator:
+ declarator attributes[opt]
+ declarator[opt] : constant-expression attributes[opt]
+
+ GNU extensions:
+
+ struct-declaration:
+ __extension__ struct-declaration
+ specifier-qualifier-list
+
+ Unlike the ISO C syntax, semicolons are handled elsewhere. The use
+ of attributes where shown is a GNU extension. In GNU C, we accept
+ any expression without commas in the syntax (assignment
+ expressions, not just conditional expressions); assignment
+ expressions will be diagnosed as non-constant. */
+
+static tree
+c_parser_struct_declaration (c_parser *parser)
+{
+ struct c_declspecs *specs;
+ tree prefix_attrs;
+ tree all_prefix_attrs;
+ tree decls;
+ location_t decl_loc;
+ if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+ {
+ int ext;
+ tree decl;
+ ext = disable_extension_diagnostics ();
+ c_parser_consume_token (parser);
+ decl = c_parser_struct_declaration (parser);
+ restore_extension_diagnostics (ext);
+ return decl;
+ }
+ if (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
+ {
+ c_parser_static_assert_declaration_no_semi (parser);
+ return NULL_TREE;
+ }
+ specs = build_null_declspecs ();
+ decl_loc = c_parser_peek_token (parser)->location;
+ c_parser_declspecs (parser, specs, false, true, true, cla_nonabstract_decl);
+ 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)
+ || c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ tree ret;
+ if (specs->typespec_kind == ctsk_none)
+ {
+ pedwarn (decl_loc, OPT_Wpedantic,
+ "ISO C forbids member declarations with no members");
+ shadow_tag_warned (specs, pedantic);
+ ret = NULL_TREE;
+ }
+ else
+ {
+ /* Support for unnamed structs or unions as members of
+ structs or unions (which is [a] useful and [b] supports
+ MS P-SDK). */
+ tree attrs = NULL;
+
+ ret = grokfield (c_parser_peek_token (parser)->location,
+ build_id_declarator (NULL_TREE), specs,
+ NULL_TREE, &attrs);
+ if (ret)
+ decl_attributes (&ret, attrs, 0);
+ }
+ return ret;
+ }
+
+ /* Provide better error recovery. Note that a type name here is valid,
+ and will be treated as a field name. */
+ if (specs->typespec_kind == ctsk_tagdef
+ && TREE_CODE (specs->type) != ENUMERAL_TYPE
+ && c_parser_next_token_starts_declspecs (parser)
+ && !c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected %<;%>, identifier or %<(%>");
+ parser->error = false;
+ return NULL_TREE;
+ }
+
+ 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->typespec_kind != ctsk_none,
+ C_DTR_NORMAL, &dummy);
+ if (declarator == NULL)
+ {
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ break;
+ }
+ if (c_parser_next_token_is (parser, CPP_COLON)
+ || c_parser_next_token_is (parser, CPP_COMMA)
+ || c_parser_next_token_is (parser, CPP_SEMICOLON)
+ || c_parser_next_token_is (parser, CPP_CLOSE_BRACE)
+ || c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ {
+ tree postfix_attrs = NULL_TREE;
+ tree width = NULL_TREE;
+ tree d;
+ if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ c_parser_consume_token (parser);
+ width = c_parser_expr_no_commas (parser, NULL).value;
+ }
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ postfix_attrs = c_parser_attributes (parser);
+ d = grokfield (c_parser_peek_token (parser)->location,
+ declarator, specs, width, &all_prefix_attrs);
+ decl_attributes (&d, chainon (postfix_attrs,
+ all_prefix_attrs), 0);
+ DECL_CHAIN (d) = decls;
+ decls = d;
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ all_prefix_attrs = chainon (c_parser_attributes (parser),
+ prefix_attrs);
+ else
+ all_prefix_attrs = prefix_attrs;
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else if (c_parser_next_token_is (parser, CPP_SEMICOLON)
+ || c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ /* Semicolon consumed in caller. */
+ break;
+ }
+ else
+ {
+ c_parser_error (parser, "expected %<,%>, %<;%> or %<}%>");
+ break;
+ }
+ }
+ else
+ {
+ c_parser_error (parser,
+ "expected %<:%>, %<,%>, %<;%>, %<}%> or "
+ "%<__attribute__%>");
+ break;
+ }
+ }
+ return decls;
+}
+
+/* Parse a typeof specifier (a GNU extension).
+
+ typeof-specifier:
+ typeof ( expression )
+ typeof ( type-name )
+*/
+
+static struct c_typespec
+c_parser_typeof_specifier (c_parser *parser)
+{
+ struct c_typespec ret;
+ ret.kind = ctsk_typeof;
+ ret.spec = error_mark_node;
+ ret.expr = NULL_TREE;
+ ret.expr_const_operands = true;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
+ c_parser_consume_token (parser);
+ c_inhibit_evaluation_warnings++;
+ in_typeof++;
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ c_inhibit_evaluation_warnings--;
+ in_typeof--;
+ return ret;
+ }
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_id))
+ {
+ struct c_type_name *type = c_parser_type_name (parser);
+ c_inhibit_evaluation_warnings--;
+ in_typeof--;
+ if (type != NULL)
+ {
+ ret.spec = groktypename (type, &ret.expr, &ret.expr_const_operands);
+ pop_maybe_used (variably_modified_type_p (ret.spec, NULL_TREE));
+ }
+ }
+ else
+ {
+ bool was_vm;
+ location_t here = c_parser_peek_token (parser)->location;
+ struct c_expr expr = c_parser_expression (parser);
+ c_inhibit_evaluation_warnings--;
+ in_typeof--;
+ if (TREE_CODE (expr.value) == COMPONENT_REF
+ && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
+ error_at (here, "%<typeof%> applied to a bit-field");
+ mark_exp_read (expr.value);
+ ret.spec = TREE_TYPE (expr.value);
+ was_vm = variably_modified_type_p (ret.spec, NULL_TREE);
+ /* This is returned with the type so that when the type is
+ evaluated, this can be evaluated. */
+ if (was_vm)
+ ret.expr = c_fully_fold (expr.value, false, &ret.expr_const_operands);
+ pop_maybe_used (was_vm);
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return ret;
+}
+
+/* Parse an alignment-specifier.
+
+ C11 6.7.5:
+
+ alignment-specifier:
+ _Alignas ( type-name )
+ _Alignas ( constant-expression )
+*/
+
+static tree
+c_parser_alignas_specifier (c_parser * parser)
+{
+ tree ret = error_mark_node;
+ location_t loc = c_parser_peek_token (parser)->location;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNAS));
+ c_parser_consume_token (parser);
+ if (!flag_isoc11)
+ {
+ if (flag_isoc99)
+ pedwarn (loc, OPT_Wpedantic,
+ "ISO C99 does not support %<_Alignas%>");
+ else
+ pedwarn (loc, OPT_Wpedantic,
+ "ISO C90 does not support %<_Alignas%>");
+ }
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return ret;
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_id))
+ {
+ struct c_type_name *type = c_parser_type_name (parser);
+ if (type != NULL)
+ ret = c_alignof (loc, groktypename (type, NULL, NULL));
+ }
+ else
+ ret = c_parser_expr_no_commas (parser, NULL).value;
+ 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, cla_prefer_id);
+ 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_CLASSNAME))
+ || c_parser_peek_token (parser)->id_kind == C_ID_ID))
+ {
+ struct c_declarator *inner
+ = build_id_declarator (c_parser_peek_token (parser)->value);
+ *seen_id = true;
+ inner->id_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ return c_parser_direct_declarator_inner (parser, *seen_id, inner);
+ }
+
+ if (kind != C_DTR_NORMAL
+ && c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ {
+ struct c_declarator *inner = build_id_declarator (NULL_TREE);
+ return c_parser_direct_declarator_inner (parser, *seen_id, inner);
+ }
+
+ /* Either we are at the end of an abstract declarator, or we have
+ parentheses. */
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ tree attrs;
+ struct c_declarator *inner;
+ c_parser_consume_token (parser);
+ attrs = c_parser_attributes (parser);
+ if (kind != C_DTR_NORMAL
+ && (c_parser_next_token_starts_declspecs (parser)
+ || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)))
+ {
+ struct c_arg_info *args
+ = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL,
+ attrs);
+ if (args == NULL)
+ return NULL;
+ else
+ {
+ inner
+ = build_function_declarator (args,
+ build_id_declarator (NULL_TREE));
+ return c_parser_direct_declarator_inner (parser, *seen_id,
+ inner);
+ }
+ }
+ /* A parenthesized declarator. */
+ inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
+ if (inner != NULL && attrs != NULL)
+ inner = build_attrs_declarator (attrs, inner);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ c_parser_consume_token (parser);
+ if (inner == NULL)
+ return NULL;
+ else
+ return c_parser_direct_declarator_inner (parser, *seen_id, inner);
+ }
+ else
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return NULL;
+ }
+ }
+ else
+ {
+ if (kind == C_DTR_NORMAL)
+ {
+ c_parser_error (parser, "expected identifier or %<(%>");
+ return NULL;
+ }
+ else
+ return build_id_declarator (NULL_TREE);
+ }
+}
+
+/* Parse part of a direct declarator or direct abstract declarator,
+ given that some (in INNER) has already been parsed; ID_PRESENT is
+ true if an identifier is present, false for an abstract
+ declarator. */
+
+static struct c_declarator *
+c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
+ struct c_declarator *inner)
+{
+ /* Parse a sequence of array declarators and parameter lists. */
+ if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ {
+ location_t brace_loc = c_parser_peek_token (parser)->location;
+ struct c_declarator *declarator;
+ struct c_declspecs *quals_attrs = build_null_declspecs ();
+ bool static_seen;
+ bool star_seen;
+ tree dimen;
+ c_parser_consume_token (parser);
+ c_parser_declspecs (parser, quals_attrs, false, false, true, cla_prefer_id);
+ 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, cla_prefer_id);
+ 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;
+ }
+ if (dimen)
+ mark_exp_read (dimen);
+ declarator = build_array_declarator (brace_loc, dimen, quals_attrs,
+ static_seen, star_seen);
+ if (declarator == NULL)
+ return NULL;
+ inner = set_array_declarator_inner (declarator, inner);
+ return c_parser_direct_declarator_inner (parser, id_present, inner);
+ }
+ else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ tree attrs;
+ struct c_arg_info *args;
+ c_parser_consume_token (parser);
+ attrs = c_parser_attributes (parser);
+ args = c_parser_parms_declarator (parser, id_present, attrs);
+ if (args == NULL)
+ return NULL;
+ else
+ {
+ inner = build_function_declarator (args, inner);
+ return c_parser_direct_declarator_inner (parser, id_present, inner);
+ }
+ }
+ return inner;
+}
+
+/* Parse a parameter list or identifier list, including the closing
+ parenthesis but not the opening one. ATTRS are the attributes at
+ the start of the list. ID_LIST_OK is true if an identifier list is
+ acceptable; such a list must not have attributes at the start. */
+
+static struct c_arg_info *
+c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs)
+{
+ push_scope ();
+ declare_parm_level ();
+ /* If the list starts with an identifier, it is an identifier list.
+ Otherwise, it is either a prototype list or an empty list. */
+ if (id_list_ok
+ && !attrs
+ && c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_token (parser)->id_kind == C_ID_ID
+
+ /* Look ahead to detect typos in type names. */
+ && c_parser_peek_2nd_token (parser)->type != CPP_NAME
+ && c_parser_peek_2nd_token (parser)->type != CPP_MULT
+ && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN
+ && c_parser_peek_2nd_token (parser)->type != CPP_OPEN_SQUARE)
+ {
+ 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 = build_arg_info ();
+ ret->types = list;
+ 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,
+ NULL);
+ 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. EXPR is NULL or an expression that needs to
+ be evaluated for the side effects of array size expressions in the
+ parameters. */
+
+static struct c_arg_info *
+c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr)
+{
+ bool bad_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 = build_arg_info ();
+ c_parser_consume_token (parser);
+ return ret;
+ }
+ if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+ {
+ struct c_arg_info *ret = build_arg_info ();
+
+ if (flag_allow_parameterless_variadic_functions)
+ {
+ /* F (...) is allowed. */
+ ret->types = NULL_TREE;
+ }
+ else
+ {
+ /* Suppress -Wold-style-definition for this case. */
+ ret->types = error_mark_node;
+ error_at (c_parser_peek_token (parser)->location,
+ "ISO C requires a named argument before %<...%>");
+ }
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ c_parser_consume_token (parser);
+ return ret;
+ }
+ else
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return NULL;
+ }
+ }
+ /* Nonempty list of parameters, either terminated with semicolon
+ (forward declarations; recurse) or with close parenthesis (normal
+ function) or with ", ... )" (variadic function). */
+ while (true)
+ {
+ /* Parse a parameter. */
+ struct c_parm *parm = c_parser_parameter_declaration (parser, attrs);
+ attrs = NULL_TREE;
+ if (parm == NULL)
+ bad_parm = true;
+ else
+ push_parm_decl (parm, &expr);
+ 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, expr);
+ }
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ c_parser_consume_token (parser);
+ if (bad_parm)
+ return NULL;
+ else
+ return get_parm_info (false, expr);
+ }
+ 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 (bad_parm)
+ return NULL;
+ else
+ return get_parm_info (true, expr);
+ }
+ 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;
+
+ /* Accept #pragmas between parameter declarations. */
+ while (c_parser_next_token_is (parser, CPP_PRAGMA))
+ c_parser_pragma (parser, pragma_external);
+
+ if (!c_parser_next_token_starts_declspecs (parser))
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (parser->error)
+ return NULL;
+ c_parser_set_source_position_from_token (token);
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
+ {
+ error ("unknown type name %qE", token->value);
+ parser->error = true;
+ }
+ /* ??? In some Objective-C cases '...' isn't applicable so there
+ should be a different message. */
+ else
+ 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 (input_location, specs, attrs);
+ attrs = NULL_TREE;
+ }
+ c_parser_declspecs (parser, specs, true, true, true, cla_nonabstract_decl);
+ finish_declspecs (specs);
+ pending_xref_error ();
+ prefix_attrs = specs->attrs;
+ specs->attrs = NULL_TREE;
+ declarator = c_parser_declarator (parser,
+ specs->typespec_kind != ctsk_none,
+ C_DTR_PARM, &dummy);
+ if (declarator == NULL)
+ {
+ c_parser_skip_until_found (parser, CPP_COMMA, NULL);
+ return NULL;
+ }
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ postfix_attrs = c_parser_attributes (parser);
+ return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs),
+ declarator);
+}
+
+/* Parse a string literal in an asm expression. It should not be
+ translated, and wide string literals are an error although
+ permitted by the syntax. This is a GNU extension.
+
+ asm-string-literal:
+ string-literal
+
+ ??? At present, following the old parser, the caller needs to have
+ set lex_untranslated_string to 1. It would be better to follow the
+ C++ parser rather than using this kludge. */
+
+static tree
+c_parser_asm_string_literal (c_parser *parser)
+{
+ tree str;
+ int save_flag = warn_overlength_strings;
+ warn_overlength_strings = 0;
+ if (c_parser_next_token_is (parser, CPP_STRING))
+ {
+ str = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ else if (c_parser_next_token_is (parser, CPP_WSTRING))
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "wide string literal in %<asm%>");
+ str = build_string (1, "");
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ c_parser_error (parser, "expected string literal");
+ str = NULL_TREE;
+ }
+ warn_overlength_strings = save_flag;
+ return str;
+}
+
+/* Parse a simple asm expression. This is used in restricted
+ contexts, where a full expression with inputs and outputs does not
+ make sense. This is a GNU extension.
+
+ simple-asm-expr:
+ asm ( asm-string-literal )
+*/
+
+static tree
+c_parser_simple_asm_expr (c_parser *parser)
+{
+ tree str;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
+ /* ??? Follow the C++ parser rather than using the
+ lex_untranslated_string kludge. */
+ parser->lex_untranslated_string = true;
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ parser->lex_untranslated_string = false;
+ return NULL_TREE;
+ }
+ str = c_parser_asm_string_literal (parser);
+ parser->lex_untranslated_string = false;
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return NULL_TREE;
+ }
+ return str;
+}
+
+static tree
+c_parser_attribute_any_word (c_parser *parser)
+{
+ tree attr_name = NULL_TREE;
+
+ 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_INT128:
+ case RID_CONST:
+ case RID_EXTERN:
+ case RID_REGISTER:
+ case RID_TYPEDEF:
+ case RID_SHORT:
+ case RID_INLINE:
+ case RID_NORETURN:
+ case RID_VOLATILE:
+ case RID_SIGNED:
+ case RID_AUTO:
+ case RID_RESTRICT:
+ case RID_COMPLEX:
+ case RID_THREAD:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ case RID_BOOL:
+ case RID_FRACT:
+ case RID_ACCUM:
+ case RID_SAT:
+ case RID_TRANSACTION_ATOMIC:
+ case RID_TRANSACTION_CANCEL:
+ ok = true;
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ if (!ok)
+ return NULL_TREE;
+
+ /* Accept __attribute__((__const)) as __attribute__((const)) etc. */
+ attr_name = ridpointers[(int) c_parser_peek_token (parser)->keyword];
+ }
+ else if (c_parser_next_token_is (parser, CPP_NAME))
+ attr_name = c_parser_peek_token (parser)->value;
+
+ return attr_name;
+}
+
+/* Parse (possibly empty) attributes. This is a GNU extension.
+
+ attributes:
+ empty
+ attributes attribute
+
+ attribute:
+ __attribute__ ( ( attribute-list ) )
+
+ attribute-list:
+ attrib
+ attribute_list , attrib
+
+ attrib:
+ empty
+ any-word
+ any-word ( identifier )
+ any-word ( identifier , nonempty-expr-list )
+ any-word ( expr-list )
+
+ where the "identifier" must not be declared as a type, and
+ "any-word" may be any identifier (including one declared as a
+ type), a reserved word storage class specifier, type specifier or
+ type qualifier. ??? This still leaves out most reserved keywords
+ (following the old parser), shouldn't we include them, and why not
+ allow identifiers declared as types to start the arguments? */
+
+static tree
+c_parser_attributes (c_parser *parser)
+{
+ tree attrs = NULL_TREE;
+ while (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ {
+ /* ??? Follow the C++ parser rather than using the
+ lex_untranslated_string kludge. */
+ parser->lex_untranslated_string = true;
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ parser->lex_untranslated_string = false;
+ return attrs;
+ }
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ parser->lex_untranslated_string = false;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return attrs;
+ }
+ /* Parse the attribute list. */
+ while (c_parser_next_token_is (parser, CPP_COMMA)
+ || c_parser_next_token_is (parser, CPP_NAME)
+ || c_parser_next_token_is (parser, CPP_KEYWORD))
+ {
+ tree attr, attr_name, attr_args;
+ vec<tree, va_gc> *expr_list;
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ continue;
+ }
+
+ attr_name = c_parser_attribute_any_word (parser);
+ if (attr_name == NULL)
+ break;
+ 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.
+ In objective-c the identifier may be a classname. */
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && (c_parser_peek_token (parser)->id_kind == C_ID_ID
+ || (c_dialect_objc ()
+ && c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
+ && ((c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
+ || (c_parser_peek_2nd_token (parser)->type
+ == CPP_CLOSE_PAREN)))
+ {
+ tree arg1 = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ attr_args = build_tree_list (NULL_TREE, arg1);
+ else
+ {
+ tree tree_list;
+ c_parser_consume_token (parser);
+ expr_list = c_parser_expr_list (parser, false, true,
+ NULL, NULL, NULL);
+ tree_list = build_tree_list_vec (expr_list);
+ attr_args = tree_cons (NULL_TREE, arg1, tree_list);
+ release_tree_vector (expr_list);
+ }
+ }
+ else
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ attr_args = NULL_TREE;
+ else
+ {
+ expr_list = c_parser_expr_list (parser, false, true,
+ NULL, NULL, NULL);
+ attr_args = build_tree_list_vec (expr_list);
+ release_tree_vector (expr_list);
+ }
+ }
+ attr = build_tree_list (attr_name, attr_args);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+ else
+ {
+ parser->lex_untranslated_string = false;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return attrs;
+ }
+ attrs = chainon (attrs, attr);
+ }
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+ else
+ {
+ parser->lex_untranslated_string = false;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return attrs;
+ }
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+ else
+ {
+ parser->lex_untranslated_string = false;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return attrs;
+ }
+ parser->lex_untranslated_string = false;
+ }
+ return attrs;
+}
+
+/* Parse a type name (C90 6.5.5, C99 6.7.6).
+
+ type-name:
+ specifier-qualifier-list abstract-declarator[opt]
+*/
+
+static struct c_type_name *
+c_parser_type_name (c_parser *parser)
+{
+ struct c_declspecs *specs = build_null_declspecs ();
+ struct c_declarator *declarator;
+ struct c_type_name *ret;
+ bool dummy = false;
+ c_parser_declspecs (parser, specs, false, true, true, cla_prefer_type);
+ if (!specs->declspecs_seen_p)
+ {
+ c_parser_error (parser, "expected specifier-qualifier-list");
+ return NULL;
+ }
+ if (specs->type != error_mark_node)
+ {
+ pending_xref_error ();
+ finish_declspecs (specs);
+ }
+ declarator = c_parser_declarator (parser,
+ specs->typespec_kind != ctsk_none,
+ C_DTR_ABSTRACT, &dummy);
+ if (declarator == NULL)
+ return NULL;
+ ret = XOBNEW (&parser_obstack, struct c_type_name);
+ ret->specs = specs;
+ ret->declarator = declarator;
+ return ret;
+}
+
+/* Parse an initializer (C90 6.5.7, C99 6.7.8).
+
+ initializer:
+ assignment-expression
+ { initializer-list }
+ { initializer-list , }
+
+ initializer-list:
+ designation[opt] initializer
+ initializer-list , designation[opt] initializer
+
+ designation:
+ designator-list =
+
+ designator-list:
+ designator
+ designator-list designator
+
+ designator:
+ array-designator
+ . identifier
+
+ array-designator:
+ [ constant-expression ]
+
+ GNU extensions:
+
+ initializer:
+ { }
+
+ designation:
+ array-designator
+ identifier :
+
+ array-designator:
+ [ constant-expression ... constant-expression ]
+
+ Any expression without commas is accepted in the syntax for the
+ constant-expressions, with non-constant expressions rejected later.
+
+ This function is only used for top-level initializers; for nested
+ ones, see c_parser_initval. */
+
+static struct c_expr
+c_parser_initializer (c_parser *parser)
+{
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ return c_parser_braced_init (parser, NULL_TREE, false);
+ else
+ {
+ struct c_expr ret;
+ location_t loc = c_parser_peek_token (parser)->location;
+ ret = c_parser_expr_no_commas (parser, NULL);
+ if (TREE_CODE (ret.value) != STRING_CST
+ && TREE_CODE (ret.value) != COMPOUND_LITERAL_EXPR)
+ ret = default_function_array_read_conversion (loc, ret);
+ return ret;
+ }
+}
+
+/* Parse a braced initializer list. TYPE is the type specified for a
+ compound literal, and NULL_TREE for other initializers and for
+ nested braced lists. NESTED_P is true for nested braced lists,
+ false for the list of a compound literal or the list that is the
+ top-level initializer in a declaration. */
+
+static struct c_expr
+c_parser_braced_init (c_parser *parser, tree type, bool nested_p)
+{
+ struct c_expr ret;
+ struct obstack braced_init_obstack;
+ location_t brace_loc = c_parser_peek_token (parser)->location;
+ gcc_obstack_init (&braced_init_obstack);
+ gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
+ c_parser_consume_token (parser);
+ if (nested_p)
+ push_init_level (0, &braced_init_obstack);
+ else
+ really_start_incremental_init (type);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ pedwarn (brace_loc, OPT_Wpedantic, "ISO C forbids empty initializer braces");
+ }
+ else
+ {
+ /* Parse a non-empty initializer list, possibly with a trailing
+ comma. */
+ while (true)
+ {
+ c_parser_initelt (parser, &braced_init_obstack);
+ 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))
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+ pop_init_level (0, &braced_init_obstack);
+ obstack_free (&braced_init_obstack, NULL);
+ return ret;
+ }
+ c_parser_consume_token (parser);
+ ret = pop_init_level (0, &braced_init_obstack);
+ obstack_free (&braced_init_obstack, NULL);
+ return ret;
+}
+
+/* Parse a nested initializer, including designators. */
+
+static void
+c_parser_initelt (c_parser *parser, struct obstack * braced_init_obstack)
+{
+ /* 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,
+ braced_init_obstack);
+ /* Use the colon as the error location. */
+ pedwarn (c_parser_peek_2nd_token (parser)->location, OPT_Wpedantic,
+ "obsolete use of designated initializer with %<:%>");
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ /* des_seen is 0 if there have been no designators, 1 if there
+ has been a single array designator and 2 otherwise. */
+ int des_seen = 0;
+ /* Location of a designator. */
+ location_t des_loc = UNKNOWN_LOCATION; /* Quiet warning. */
+ while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE)
+ || c_parser_next_token_is (parser, CPP_DOT))
+ {
+ int des_prev = des_seen;
+ if (!des_seen)
+ des_loc = c_parser_peek_token (parser)->location;
+ if (des_seen < 2)
+ des_seen++;
+ if (c_parser_next_token_is (parser, CPP_DOT))
+ {
+ des_seen = 2;
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ set_init_label (c_parser_peek_token (parser)->value,
+ braced_init_obstack);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ struct c_expr init;
+ init.value = error_mark_node;
+ init.original_code = ERROR_MARK;
+ init.original_type = NULL;
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_COMMA, NULL);
+ process_init_element (init, false, braced_init_obstack);
+ return;
+ }
+ }
+ else
+ {
+ tree first, second;
+ location_t ellipsis_loc = UNKNOWN_LOCATION; /* Quiet warning. */
+ /* ??? Following the old parser, [ objc-receiver
+ objc-message-args ] is accepted as an initializer,
+ being distinguished from a designator by what follows
+ the first assignment expression inside the square
+ brackets, but after a first array designator a
+ subsequent square bracket is for Objective-C taken to
+ start an expression, using the obsolete form of
+ designated initializer without '=', rather than
+ possibly being a second level of designation: in LALR
+ terms, the '[' is shifted rather than reducing
+ designator to designator-list. */
+ if (des_prev == 1 && c_dialect_objc ())
+ {
+ des_seen = des_prev;
+ break;
+ }
+ if (des_prev == 0 && c_dialect_objc ())
+ {
+ /* This might be an array designator or an
+ Objective-C message expression. If the former,
+ continue parsing here; if the latter, parse the
+ remainder of the initializer given the starting
+ primary-expression. ??? It might make sense to
+ distinguish when des_prev == 1 as well; see
+ previous comment. */
+ tree rec, args;
+ struct c_expr mexpr;
+ c_parser_consume_token (parser);
+ if (c_parser_peek_token (parser)->type == CPP_NAME
+ && ((c_parser_peek_token (parser)->id_kind
+ == C_ID_TYPENAME)
+ || (c_parser_peek_token (parser)->id_kind
+ == C_ID_CLASSNAME)))
+ {
+ /* Type name receiver. */
+ tree id = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ rec = objc_get_class_reference (id);
+ goto parse_message_args;
+ }
+ first = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (first);
+ if (c_parser_next_token_is (parser, CPP_ELLIPSIS)
+ || c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ goto array_desig_after_first;
+ /* Expression receiver. So far only one part
+ without commas has been parsed; there might be
+ more of the expression. */
+ rec = first;
+ while (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ struct c_expr next;
+ location_t comma_loc, exp_loc;
+ comma_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
+ next = c_parser_expr_no_commas (parser, NULL);
+ next = default_function_array_read_conversion (exp_loc,
+ next);
+ rec = build_compound_expr (comma_loc, rec, next.value);
+ }
+ parse_message_args:
+ /* Now parse the objc-message-args. */
+ args = c_parser_objc_message_args (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ mexpr.value
+ = objc_build_message_expr (rec, args);
+ mexpr.original_code = ERROR_MARK;
+ mexpr.original_type = NULL;
+ /* Now parse and process the remainder of the
+ initializer, starting with this message
+ expression as a primary-expression. */
+ c_parser_initval (parser, &mexpr, braced_init_obstack);
+ return;
+ }
+ c_parser_consume_token (parser);
+ first = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (first);
+ array_desig_after_first:
+ if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+ {
+ ellipsis_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ second = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (second);
+ }
+ else
+ second = NULL_TREE;
+ if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ {
+ c_parser_consume_token (parser);
+ set_init_index (first, second, braced_init_obstack);
+ if (second)
+ pedwarn (ellipsis_loc, OPT_Wpedantic,
+ "ISO C forbids specifying range of elements to initialize");
+ }
+ else
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ }
+ }
+ if (des_seen >= 1)
+ {
+ if (c_parser_next_token_is (parser, CPP_EQ))
+ {
+ if (!flag_isoc99)
+ pedwarn (des_loc, OPT_Wpedantic,
+ "ISO C90 forbids specifying subobject to initialize");
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ if (des_seen == 1)
+ pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic,
+ "obsolete use of designated initializer without %<=%>");
+ else
+ {
+ struct c_expr init;
+ init.value = error_mark_node;
+ init.original_code = ERROR_MARK;
+ init.original_type = NULL;
+ c_parser_error (parser, "expected %<=%>");
+ c_parser_skip_until_found (parser, CPP_COMMA, NULL);
+ process_init_element (init, false, braced_init_obstack);
+ return;
+ }
+ }
+ }
+ }
+ c_parser_initval (parser, NULL, braced_init_obstack);
+}
+
+/* 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 obstack * braced_init_obstack)
+{
+ struct c_expr init;
+ gcc_assert (!after || c_dialect_objc ());
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after)
+ init = c_parser_braced_init (parser, NULL_TREE, true);
+ else
+ {
+ location_t loc = c_parser_peek_token (parser)->location;
+ init = c_parser_expr_no_commas (parser, after);
+ if (init.value != NULL_TREE
+ && TREE_CODE (init.value) != STRING_CST
+ && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR)
+ init = default_function_array_read_conversion (loc, init);
+ }
+ process_init_element (init, false, braced_init_obstack);
+}
+
+/* Parse a compound statement (possibly a function body) (C90 6.6.2,
+ C99 6.8.2).
+
+ compound-statement:
+ { block-item-list[opt] }
+ { label-declarations block-item-list }
+
+ block-item-list:
+ block-item
+ block-item-list block-item
+
+ block-item:
+ nested-declaration
+ statement
+
+ nested-declaration:
+ declaration
+
+ GNU extensions:
+
+ compound-statement:
+ { label-declarations block-item-list }
+
+ nested-declaration:
+ __extension__ nested-declaration
+ nested-function-definition
+
+ label-declarations:
+ label-declaration
+ label-declarations label-declaration
+
+ label-declaration:
+ __label__ identifier-list ;
+
+ Allowing the mixing of declarations and code is new in C99. The
+ GNU syntax also permits (not shown above) labels at the end of
+ compound statements, which yield an error. We don't allow labels
+ on declarations; this might seem like a natural extension, but
+ there would be a conflict between attributes on the label and
+ prefix attributes on the declaration. ??? The syntax follows the
+ old parser in requiring something after label declarations.
+ Although they are erroneous if the labels declared aren't defined,
+ is it useful for the syntax to be this way?
+
+ OpenMP:
+
+ block-item:
+ openmp-directive
+
+ openmp-directive:
+ barrier-directive
+ flush-directive */
+
+static tree
+c_parser_compound_statement (c_parser *parser)
+{
+ tree stmt;
+ location_t brace_loc;
+ brace_loc = c_parser_peek_token (parser)->location;
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ {
+ /* Ensure a scope is entered and left anyway to avoid confusion
+ if we have just prepared to enter a function body. */
+ stmt = c_begin_compound_stmt (true);
+ c_end_compound_stmt (brace_loc, stmt, true);
+ return error_mark_node;
+ }
+ stmt = c_begin_compound_stmt (true);
+ c_parser_compound_statement_nostart (parser);
+ return c_end_compound_stmt (brace_loc, stmt, true);
+}
+
+/* Parse a compound statement except for the opening brace. This is
+ used for parsing both compound statements and statement expressions
+ (which follow different paths to handling the opening). */
+
+static void
+c_parser_compound_statement_nostart (c_parser *parser)
+{
+ bool last_stmt = false;
+ bool last_label = false;
+ bool save_valid_for_pragma = valid_location_for_stdc_pragma_p ();
+ location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ c_parser_consume_token (parser);
+ return;
+ }
+ mark_valid_location_for_stdc_pragma (true);
+ if (c_parser_next_token_is_keyword (parser, RID_LABEL))
+ {
+ /* Read zero or more forward-declarations for labels that nested
+ functions can jump to. */
+ mark_valid_location_for_stdc_pragma (false);
+ while (c_parser_next_token_is_keyword (parser, RID_LABEL))
+ {
+ label_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ /* Any identifiers, including those declared as type names,
+ are OK here. */
+ while (true)
+ {
+ tree label;
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ break;
+ }
+ label
+ = declare_label (c_parser_peek_token (parser)->value);
+ C_DECLARED_LABEL_FLAG (label) = 1;
+ add_stmt (build_stmt (label_loc, DECL_EXPR, label));
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ pedwarn (label_loc, OPT_Wpedantic, "ISO C forbids label declarations");
+ }
+ /* We must now have at least one statement, label or declaration. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
+ c_parser_error (parser, "expected declaration or statement");
+ c_parser_consume_token (parser);
+ return;
+ }
+ while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
+ {
+ location_t loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is_keyword (parser, RID_CASE)
+ || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+ || (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+ {
+ if (c_parser_next_token_is_keyword (parser, RID_CASE))
+ label_loc = c_parser_peek_2nd_token (parser)->location;
+ else
+ label_loc = c_parser_peek_token (parser)->location;
+ last_label = true;
+ last_stmt = false;
+ mark_valid_location_for_stdc_pragma (false);
+ c_parser_label (parser);
+ }
+ else if (!last_label
+ && c_parser_next_tokens_start_declaration (parser))
+ {
+ last_label = false;
+ mark_valid_location_for_stdc_pragma (false);
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL);
+ if (last_stmt)
+ pedwarn_c90 (loc,
+ (pedantic && !flag_isoc99)
+ ? OPT_Wpedantic
+ : OPT_Wdeclaration_after_statement,
+ "ISO C90 forbids mixed declarations and code");
+ last_stmt = false;
+ }
+ else if (!last_label
+ && c_parser_next_token_is_keyword (parser, RID_EXTENSION))
+ {
+ /* __extension__ can start a declaration, but is also an
+ unary operator that can start an expression. Consume all
+ but the last of a possible series of __extension__ to
+ determine which. */
+ while (c_parser_peek_2nd_token (parser)->type == CPP_KEYWORD
+ && (c_parser_peek_2nd_token (parser)->keyword
+ == RID_EXTENSION))
+ c_parser_consume_token (parser);
+ if (c_token_starts_declaration (c_parser_peek_2nd_token (parser)))
+ {
+ int ext;
+ ext = disable_extension_diagnostics ();
+ c_parser_consume_token (parser);
+ last_label = false;
+ mark_valid_location_for_stdc_pragma (false);
+ c_parser_declaration_or_fndef (parser, true, true, true, true,
+ true, NULL);
+ /* Following the old parser, __extension__ does not
+ disable this diagnostic. */
+ restore_extension_diagnostics (ext);
+ if (last_stmt)
+ pedwarn_c90 (loc, (pedantic && !flag_isoc99)
+ ? OPT_Wpedantic
+ : OPT_Wdeclaration_after_statement,
+ "ISO C90 forbids mixed declarations and code");
+ last_stmt = false;
+ }
+ else
+ goto statement;
+ }
+ else if (c_parser_next_token_is (parser, CPP_PRAGMA))
+ {
+ /* External pragmas, and some omp pragmas, are not associated
+ with regular c code, and so are not to be considered statements
+ syntactically. This ensures that the user doesn't put them
+ places that would turn into syntax errors if the directive
+ were ignored. */
+ if (c_parser_pragma (parser, pragma_compound))
+ last_label = false, last_stmt = true;
+ }
+ else if (c_parser_next_token_is (parser, CPP_EOF))
+ {
+ mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
+ c_parser_error (parser, "expected declaration or statement");
+ return;
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_ELSE))
+ {
+ if (parser->in_if_block)
+ {
+ mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
+ error_at (loc, """expected %<}%> before %<else%>");
+ return;
+ }
+ else
+ {
+ error_at (loc, "%<else%> without a previous %<if%>");
+ c_parser_consume_token (parser);
+ continue;
+ }
+ }
+ else
+ {
+ statement:
+ last_label = false;
+ last_stmt = true;
+ mark_valid_location_for_stdc_pragma (false);
+ c_parser_statement_after_labels (parser);
+ }
+
+ parser->error = false;
+ }
+ if (last_label)
+ error_at (label_loc, "label at end of compound statement");
+ c_parser_consume_token (parser);
+ /* Restore the value we started with. */
+ mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
+}
+
+/* Parse a label (C90 6.6.1, C99 6.8.1).
+
+ label:
+ identifier : attributes[opt]
+ case constant-expression :
+ default :
+
+ GNU extensions:
+
+ label:
+ case constant-expression ... constant-expression :
+
+ The use of attributes on labels is a GNU extension. The syntax in
+ GNU C accepts any expressions without commas, non-constant
+ expressions being rejected later. */
+
+static void
+c_parser_label (c_parser *parser)
+{
+ location_t loc1 = c_parser_peek_token (parser)->location;
+ tree label = NULL_TREE;
+ if (c_parser_next_token_is_keyword (parser, RID_CASE))
+ {
+ tree exp1, exp2;
+ c_parser_consume_token (parser);
+ exp1 = c_parser_expr_no_commas (parser, NULL).value;
+ if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ c_parser_consume_token (parser);
+ label = do_case (loc1, exp1, NULL_TREE);
+ }
+ else if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+ {
+ c_parser_consume_token (parser);
+ exp2 = c_parser_expr_no_commas (parser, NULL).value;
+ if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ label = do_case (loc1, exp1, exp2);
+ }
+ else
+ c_parser_error (parser, "expected %<:%> or %<...%>");
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT))
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ label = do_case (loc1, NULL_TREE, NULL_TREE);
+ }
+ else
+ {
+ tree name = c_parser_peek_token (parser)->value;
+ tree tlab;
+ tree attrs;
+ location_t loc2 = c_parser_peek_token (parser)->location;
+ gcc_assert (c_parser_next_token_is (parser, CPP_NAME));
+ c_parser_consume_token (parser);
+ gcc_assert (c_parser_next_token_is (parser, CPP_COLON));
+ c_parser_consume_token (parser);
+ attrs = c_parser_attributes (parser);
+ tlab = define_label (loc2, name);
+ if (tlab)
+ {
+ decl_attributes (&tlab, attrs, 0);
+ label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab));
+ }
+ }
+ if (label)
+ {
+ if (c_parser_next_tokens_start_declaration (parser))
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "a label can only be part of a statement and "
+ "a declaration is not a statement");
+ c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false,
+ /*static_assert_ok*/ true,
+ /*empty_ok*/ true, /*nested*/ true,
+ /*start_attr_ok*/ true, NULL);
+ }
+ }
+}
+
+/* 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
+
+ Transactional Memory:
+
+ statement:
+ transaction-statement
+ transaction-cancel-statement
+*/
+
+static void
+c_parser_statement (c_parser *parser)
+{
+ while (c_parser_next_token_is_keyword (parser, RID_CASE)
+ || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+ || (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+ c_parser_label (parser);
+ c_parser_statement_after_labels (parser);
+}
+
+/* Parse a statement, other than a labeled statement. */
+
+static void
+c_parser_statement_after_labels (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree stmt = NULL_TREE;
+ bool in_if_block = parser->in_if_block;
+ parser->in_if_block = false;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_OPEN_BRACE:
+ add_stmt (c_parser_compound_statement (parser));
+ break;
+ case CPP_KEYWORD:
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_IF:
+ c_parser_if_statement (parser);
+ break;
+ case RID_SWITCH:
+ c_parser_switch_statement (parser);
+ break;
+ case RID_WHILE:
+ c_parser_while_statement (parser);
+ break;
+ case RID_DO:
+ c_parser_do_statement (parser);
+ break;
+ case RID_FOR:
+ c_parser_for_statement (parser);
+ break;
+ case RID_GOTO:
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ stmt = c_finish_goto_label (loc,
+ c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ }
+ else if (c_parser_next_token_is (parser, CPP_MULT))
+ {
+ tree val;
+
+ c_parser_consume_token (parser);
+ val = c_parser_expression (parser).value;
+ mark_exp_read (val);
+ stmt = c_finish_goto_ptr (loc, val);
+ }
+ else
+ c_parser_error (parser, "expected identifier or %<*%>");
+ goto expect_semicolon;
+ case RID_CONTINUE:
+ c_parser_consume_token (parser);
+ stmt = c_finish_bc_stmt (loc, &c_cont_label, false);
+ goto expect_semicolon;
+ case RID_BREAK:
+ c_parser_consume_token (parser);
+ stmt = c_finish_bc_stmt (loc, &c_break_label, true);
+ goto expect_semicolon;
+ case RID_RETURN:
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ stmt = c_finish_return (loc, NULL_TREE, NULL_TREE);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ struct c_expr expr = c_parser_expression_conv (parser);
+ mark_exp_read (expr.value);
+ stmt = c_finish_return (loc, expr.value, expr.original_type);
+ goto expect_semicolon;
+ }
+ break;
+ case RID_ASM:
+ stmt = c_parser_asm_statement (parser);
+ break;
+ case RID_TRANSACTION_ATOMIC:
+ case RID_TRANSACTION_RELAXED:
+ stmt = c_parser_transaction (parser,
+ c_parser_peek_token (parser)->keyword);
+ break;
+ case RID_TRANSACTION_CANCEL:
+ stmt = c_parser_transaction_cancel (parser);
+ goto expect_semicolon;
+ 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 (loc, NULL_TREE);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ tree expr = c_parser_expression (parser).value;
+ expr = c_fully_fold (expr, false, NULL);
+ stmt = objc_build_throw_stmt (loc, expr);
+ goto expect_semicolon;
+ }
+ break;
+ case RID_AT_TRY:
+ gcc_assert (c_dialect_objc ());
+ c_parser_objc_try_catch_finally_statement (parser);
+ break;
+ case RID_AT_SYNCHRONIZED:
+ gcc_assert (c_dialect_objc ());
+ c_parser_objc_synchronized_statement (parser);
+ break;
+ default:
+ goto expr_stmt;
+ }
+ break;
+ case CPP_SEMICOLON:
+ c_parser_consume_token (parser);
+ break;
+ case CPP_CLOSE_PAREN:
+ case CPP_CLOSE_SQUARE:
+ /* Avoid infinite loop in error recovery:
+ c_parser_skip_until_found stops at a closing nesting
+ delimiter without consuming it, but here we need to consume
+ it to proceed further. */
+ c_parser_error (parser, "expected statement");
+ c_parser_consume_token (parser);
+ break;
+ case CPP_PRAGMA:
+ c_parser_pragma (parser, pragma_stmt);
+ break;
+ default:
+ expr_stmt:
+ stmt = c_finish_expr_stmt (loc, c_parser_expression_conv (parser).value);
+ expect_semicolon:
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ break;
+ }
+ /* Two cases cannot and do not have line numbers associated: If stmt
+ is degenerate, such as "2;", then stmt is an INTEGER_CST, which
+ cannot hold line numbers. But that's OK because the statement
+ will either be changed to a MODIFY_EXPR during gimplification of
+ the statement expr, or discarded. If stmt was compound, but
+ without new variables, we will have skipped the creation of a
+ BIND and will have a bare STATEMENT_LIST. But that's OK because
+ (recursively) all of the component statements should already have
+ line numbers assigned. ??? Can we discard no-op statements
+ earlier? */
+ if (CAN_HAVE_LOCATION_P (stmt)
+ && EXPR_LOCATION (stmt) == UNKNOWN_LOCATION)
+ SET_EXPR_LOCATION (stmt, loc);
+
+ parser->in_if_block = in_if_block;
+}
+
+/* Parse the condition from an if, do, while or for statements. */
+
+static tree
+c_parser_condition (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree cond;
+ cond = c_parser_expression_conv (parser).value;
+ cond = c_objc_common_truthvalue_conversion (loc, cond);
+ cond = c_fully_fold (cond, false, NULL);
+ if (warn_sequence_point)
+ verify_sequence_points (cond);
+ return cond;
+}
+
+/* Parse a parenthesized condition from an if, do or while statement.
+
+ condition:
+ ( expression )
+*/
+static tree
+c_parser_paren_condition (c_parser *parser)
+{
+ tree cond;
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return error_mark_node;
+ cond = c_parser_condition (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ return cond;
+}
+
+/* Parse a statement which is a block in C99. */
+
+static tree
+c_parser_c99_block_statement (c_parser *parser)
+{
+ tree block = c_begin_compound_stmt (flag_isoc99);
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_statement (parser);
+ return c_end_compound_stmt (loc, block, flag_isoc99);
+}
+
+/* Parse the body of an if statement. This is just parsing a
+ statement but (a) it is a block in C99, (b) we track whether the
+ body is an if statement for the sake of -Wparentheses warnings, (c)
+ we handle an empty body specially for the sake of -Wempty-body
+ warnings, and (d) we call parser_compound_statement directly
+ because c_parser_statement_after_labels resets
+ parser->in_if_block. */
+
+static tree
+c_parser_if_body (c_parser *parser, bool *if_p)
+{
+ tree block = c_begin_compound_stmt (flag_isoc99);
+ location_t body_loc = c_parser_peek_token (parser)->location;
+ while (c_parser_next_token_is_keyword (parser, RID_CASE)
+ || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+ || (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+ c_parser_label (parser);
+ *if_p = c_parser_next_token_is_keyword (parser, RID_IF);
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ location_t loc = c_parser_peek_token (parser)->location;
+ add_stmt (build_empty_stmt (loc));
+ c_parser_consume_token (parser);
+ if (!c_parser_next_token_is_keyword (parser, RID_ELSE))
+ warning_at (loc, OPT_Wempty_body,
+ "suggest braces around empty body in an %<if%> statement");
+ }
+ else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ add_stmt (c_parser_compound_statement (parser));
+ else
+ c_parser_statement_after_labels (parser);
+ return c_end_compound_stmt (body_loc, block, flag_isoc99);
+}
+
+/* Parse the else body of an if statement. This is just parsing a
+ statement but (a) it is a block in C99, (b) we handle an empty body
+ specially for the sake of -Wempty-body warnings. */
+
+static tree
+c_parser_else_body (c_parser *parser)
+{
+ location_t else_loc = c_parser_peek_token (parser)->location;
+ tree block = c_begin_compound_stmt (flag_isoc99);
+ while (c_parser_next_token_is_keyword (parser, RID_CASE)
+ || c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+ || (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON))
+ c_parser_label (parser);
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ location_t loc = c_parser_peek_token (parser)->location;
+ warning_at (loc,
+ OPT_Wempty_body,
+ "suggest braces around empty body in an %<else%> statement");
+ add_stmt (build_empty_stmt (loc));
+ c_parser_consume_token (parser);
+ }
+ else
+ c_parser_statement_after_labels (parser);
+ return c_end_compound_stmt (else_loc, block, flag_isoc99);
+}
+
+/* Parse an if statement (C90 6.6.4, C99 6.8.4).
+
+ if-statement:
+ if ( expression ) statement
+ if ( expression ) statement else statement
+*/
+
+static void
+c_parser_if_statement (c_parser *parser)
+{
+ tree block;
+ location_t loc;
+ tree cond;
+ bool first_if = false;
+ tree first_body, second_body;
+ bool in_if_block;
+
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF));
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (flag_isoc99);
+ loc = c_parser_peek_token (parser)->location;
+ cond = c_parser_paren_condition (parser);
+ in_if_block = parser->in_if_block;
+ parser->in_if_block = true;
+ first_body = c_parser_if_body (parser, &first_if);
+ parser->in_if_block = in_if_block;
+ if (c_parser_next_token_is_keyword (parser, RID_ELSE))
+ {
+ c_parser_consume_token (parser);
+ second_body = c_parser_else_body (parser);
+ }
+ else
+ second_body = NULL_TREE;
+ c_finish_if_stmt (loc, cond, first_body, second_body, first_if);
+ add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
+}
+
+/* Parse a switch statement (C90 6.6.4, C99 6.8.4).
+
+ switch-statement:
+ switch (expression) statement
+*/
+
+static void
+c_parser_switch_statement (c_parser *parser)
+{
+ tree block, expr, body, save_break;
+ location_t switch_loc = c_parser_peek_token (parser)->location;
+ location_t switch_cond_loc;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_SWITCH));
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (flag_isoc99);
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ switch_cond_loc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expression (parser).value;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ else
+ {
+ switch_cond_loc = UNKNOWN_LOCATION;
+ expr = error_mark_node;
+ }
+ c_start_case (switch_loc, switch_cond_loc, expr);
+ save_break = c_break_label;
+ c_break_label = NULL_TREE;
+ body = c_parser_c99_block_statement (parser);
+ c_finish_case (body);
+ if (c_break_label)
+ {
+ location_t here = c_parser_peek_token (parser)->location;
+ tree t = build1 (LABEL_EXPR, void_type_node, c_break_label);
+ SET_EXPR_LOCATION (t, here);
+ add_stmt (t);
+ }
+ c_break_label = save_break;
+ add_stmt (c_end_compound_stmt (switch_loc, block, flag_isoc99));
+}
+
+/* Parse a while statement (C90 6.6.5, C99 6.8.5).
+
+ while-statement:
+ while (expression) statement
+*/
+
+static void
+c_parser_while_statement (c_parser *parser)
+{
+ tree block, cond, body, save_break, save_cont;
+ location_t loc;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE));
+ c_parser_consume_token (parser);
+ block = c_begin_compound_stmt (flag_isoc99);
+ loc = c_parser_peek_token (parser)->location;
+ cond = c_parser_paren_condition (parser);
+ save_break = c_break_label;
+ c_break_label = NULL_TREE;
+ save_cont = c_cont_label;
+ c_cont_label = NULL_TREE;
+ body = c_parser_c99_block_statement (parser);
+ c_finish_loop (loc, cond, NULL, body, c_break_label, c_cont_label, true);
+ add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
+ c_break_label = save_break;
+ c_cont_label = save_cont;
+}
+
+/* Parse a do statement (C90 6.6.5, C99 6.8.5).
+
+ do-statement:
+ do statement while ( expression ) ;
+*/
+
+static void
+c_parser_do_statement (c_parser *parser)
+{
+ tree block, cond, body, save_break, save_cont, new_break, new_cont;
+ location_t loc;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO));
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ warning_at (c_parser_peek_token (parser)->location,
+ OPT_Wempty_body,
+ "suggest braces around empty body in %<do%> statement");
+ block = c_begin_compound_stmt (flag_isoc99);
+ loc = c_parser_peek_token (parser)->location;
+ save_break = c_break_label;
+ c_break_label = NULL_TREE;
+ save_cont = c_cont_label;
+ c_cont_label = NULL_TREE;
+ body = c_parser_c99_block_statement (parser);
+ c_parser_require_keyword (parser, RID_WHILE, "expected %<while%>");
+ new_break = c_break_label;
+ c_break_label = save_break;
+ new_cont = c_cont_label;
+ c_cont_label = save_cont;
+ cond = c_parser_paren_condition (parser);
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ c_finish_loop (loc, cond, NULL, body, new_break, new_cont, false);
+ add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
+}
+
+/* Parse a for statement (C90 6.6.5, C99 6.8.5).
+
+ for-statement:
+ for ( expression[opt] ; expression[opt] ; expression[opt] ) statement
+ for ( nested-declaration expression[opt] ; expression[opt] ) statement
+
+ The form with a declaration is new in C99.
+
+ ??? In accordance with the old parser, the declaration may be a
+ nested function, which is then rejected in check_for_loop_decls,
+ but does it make any sense for this to be included in the grammar?
+ Note in particular that the nested function does not include a
+ trailing ';', whereas the "declaration" production includes one.
+ Also, can we reject bad declarations earlier and cheaper than
+ check_for_loop_decls?
+
+ In Objective-C, there are two additional variants:
+
+ foreach-statement:
+ for ( expression in expresssion ) statement
+ for ( declaration in expression ) statement
+
+ This is inconsistent with C, because the second variant is allowed
+ even if c99 is not enabled.
+
+ The rest of the comment documents these Objective-C foreach-statement.
+
+ Here is the canonical example of the first variant:
+ for (object in array) { do something with object }
+ we call the first expression ("object") the "object_expression" and
+ the second expression ("array") the "collection_expression".
+ object_expression must be an lvalue of type "id" (a generic Objective-C
+ object) because the loop works by assigning to object_expression the
+ various objects from the collection_expression. collection_expression
+ must evaluate to something of type "id" which responds to the method
+ countByEnumeratingWithState:objects:count:.
+
+ The canonical example of the second variant is:
+ for (id object in array) { do something with object }
+ which is completely equivalent to
+ {
+ id object;
+ for (object in array) { do something with object }
+ }
+ Note that initizializing 'object' in some way (eg, "for ((object =
+ xxx) in array) { do something with object }") is possibly
+ technically valid, but completely pointless as 'object' will be
+ assigned to something else as soon as the loop starts. We should
+ most likely reject it (TODO).
+
+ The beginning of the Objective-C foreach-statement looks exactly
+ like the beginning of the for-statement, and we can tell it is a
+ foreach-statement only because the initial declaration or
+ expression is terminated by 'in' instead of ';'.
+*/
+
+static void
+c_parser_for_statement (c_parser *parser)
+{
+ tree block, cond, incr, save_break, save_cont, body;
+ /* The following are only used when parsing an ObjC foreach statement. */
+ tree object_expression;
+ /* Silence the bogus uninitialized warning. */
+ tree collection_expression = NULL;
+ location_t loc = c_parser_peek_token (parser)->location;
+ location_t for_loc = c_parser_peek_token (parser)->location;
+ bool is_foreach_statement = false;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR));
+ c_parser_consume_token (parser);
+ /* Open a compound statement in Objective-C as well, just in case this is
+ as foreach expression. */
+ block = c_begin_compound_stmt (flag_isoc99 || c_dialect_objc ());
+ cond = error_mark_node;
+ incr = error_mark_node;
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ /* Parse the initialization declaration or expression. */
+ object_expression = error_mark_node;
+ parser->objc_could_be_foreach_context = c_dialect_objc ();
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ parser->objc_could_be_foreach_context = false;
+ c_parser_consume_token (parser);
+ c_finish_expr_stmt (loc, NULL_TREE);
+ }
+ else if (c_parser_next_tokens_start_declaration (parser))
+ {
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true,
+ &object_expression);
+ parser->objc_could_be_foreach_context = false;
+
+ if (c_parser_next_token_is_keyword (parser, RID_IN))
+ {
+ c_parser_consume_token (parser);
+ is_foreach_statement = true;
+ if (check_for_loop_decls (for_loc, true) == NULL_TREE)
+ c_parser_error (parser, "multiple iterating variables in fast enumeration");
+ }
+ else
+ check_for_loop_decls (for_loc, flag_isoc99);
+ }
+ 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_declaration (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,
+ true, &object_expression);
+ parser->objc_could_be_foreach_context = false;
+
+ restore_extension_diagnostics (ext);
+ if (c_parser_next_token_is_keyword (parser, RID_IN))
+ {
+ c_parser_consume_token (parser);
+ is_foreach_statement = true;
+ if (check_for_loop_decls (for_loc, true) == NULL_TREE)
+ c_parser_error (parser, "multiple iterating variables in fast enumeration");
+ }
+ else
+ check_for_loop_decls (for_loc, flag_isoc99);
+ }
+ else
+ goto init_expr;
+ }
+ else
+ {
+ init_expr:
+ {
+ tree init_expression;
+ init_expression = c_parser_expression (parser).value;
+ parser->objc_could_be_foreach_context = false;
+ if (c_parser_next_token_is_keyword (parser, RID_IN))
+ {
+ c_parser_consume_token (parser);
+ is_foreach_statement = true;
+ if (! lvalue_p (init_expression))
+ c_parser_error (parser, "invalid iterating variable in fast enumeration");
+ object_expression = c_fully_fold (init_expression, false, NULL);
+ }
+ else
+ {
+ c_finish_expr_stmt (loc, init_expression);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ }
+ }
+ /* Parse the loop condition. In the case of a foreach
+ statement, there is no loop condition. */
+ gcc_assert (!parser->objc_could_be_foreach_context);
+ if (!is_foreach_statement)
+ {
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ c_parser_consume_token (parser);
+ cond = NULL_TREE;
+ }
+ else
+ {
+ cond = c_parser_condition (parser);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ }
+ /* Parse the increment expression (the third expression in a
+ for-statement). In the case of a foreach-statement, this is
+ the expression that follows the 'in'. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ if (is_foreach_statement)
+ {
+ c_parser_error (parser, "missing collection in fast enumeration");
+ collection_expression = error_mark_node;
+ }
+ else
+ incr = c_process_expr_stmt (loc, NULL_TREE);
+ }
+ else
+ {
+ if (is_foreach_statement)
+ collection_expression = c_fully_fold (c_parser_expression (parser).value,
+ false, NULL);
+ else
+ incr = c_process_expr_stmt (loc, c_parser_expression (parser).value);
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ 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);
+ if (is_foreach_statement)
+ objc_finish_foreach_loop (loc, object_expression, collection_expression, body, c_break_label, c_cont_label);
+ else
+ c_finish_loop (loc, cond, incr, body, c_break_label, c_cont_label, true);
+ add_stmt (c_end_compound_stmt (loc, block, flag_isoc99 || c_dialect_objc ()));
+ c_break_label = save_break;
+ c_cont_label = save_cont;
+}
+
+/* Parse an asm statement, a GNU extension. This is a full-blown asm
+ statement with inputs, outputs, clobbers, and volatile tag
+ allowed.
+
+ asm-statement:
+ asm type-qualifier[opt] ( asm-argument ) ;
+ asm type-qualifier[opt] goto ( asm-goto-argument ) ;
+
+ asm-argument:
+ asm-string-literal
+ asm-string-literal : asm-operands[opt]
+ asm-string-literal : asm-operands[opt] : asm-operands[opt]
+ asm-string-literal : asm-operands[opt] : asm-operands[opt] : asm-clobbers[opt]
+
+ asm-goto-argument:
+ asm-string-literal : : asm-operands[opt] : asm-clobbers[opt] \
+ : asm-goto-operands
+
+ Qualifiers other than volatile are accepted in the syntax but
+ warned for. */
+
+static tree
+c_parser_asm_statement (c_parser *parser)
+{
+ tree quals, str, outputs, inputs, clobbers, labels, ret;
+ bool simple, is_goto;
+ location_t asm_loc = c_parser_peek_token (parser)->location;
+ int section, nsections;
+
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ASM));
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is_keyword (parser, RID_VOLATILE))
+ {
+ quals = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_CONST)
+ || c_parser_next_token_is_keyword (parser, RID_RESTRICT))
+ {
+ warning_at (c_parser_peek_token (parser)->location,
+ 0,
+ "%E qualifier ignored on asm",
+ c_parser_peek_token (parser)->value);
+ quals = NULL_TREE;
+ c_parser_consume_token (parser);
+ }
+ else
+ quals = NULL_TREE;
+
+ is_goto = false;
+ if (c_parser_next_token_is_keyword (parser, RID_GOTO))
+ {
+ c_parser_consume_token (parser);
+ is_goto = true;
+ }
+
+ /* ??? Follow the C++ parser rather than using the
+ lex_untranslated_string kludge. */
+ parser->lex_untranslated_string = true;
+ ret = NULL;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ goto error;
+
+ str = c_parser_asm_string_literal (parser);
+ if (str == NULL_TREE)
+ goto error_close_paren;
+
+ simple = true;
+ outputs = NULL_TREE;
+ inputs = NULL_TREE;
+ clobbers = NULL_TREE;
+ labels = NULL_TREE;
+
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto)
+ goto done_asm;
+
+ /* Parse each colon-delimited section of operands. */
+ nsections = 3 + is_goto;
+ for (section = 0; section < nsections; ++section)
+ {
+ if (!c_parser_require (parser, CPP_COLON,
+ is_goto
+ ? "expected %<:%>"
+ : "expected %<:%> or %<)%>"))
+ goto error_close_paren;
+
+ /* Once past any colon, we're no longer a simple asm. */
+ simple = false;
+
+ if ((!c_parser_next_token_is (parser, CPP_COLON)
+ && !c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ || section == 3)
+ switch (section)
+ {
+ case 0:
+ /* For asm goto, we don't allow output operands, but reserve
+ the slot for a future extension that does allow them. */
+ if (!is_goto)
+ outputs = c_parser_asm_operands (parser);
+ break;
+ case 1:
+ inputs = c_parser_asm_operands (parser);
+ break;
+ case 2:
+ clobbers = c_parser_asm_clobbers (parser);
+ break;
+ case 3:
+ labels = c_parser_asm_goto_operands (parser);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN) && !is_goto)
+ goto done_asm;
+ }
+
+ done_asm:
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ goto error;
+ }
+
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ c_parser_skip_to_end_of_block_or_statement (parser);
+
+ ret = build_asm_stmt (quals, build_asm_expr (asm_loc, str, outputs, inputs,
+ clobbers, labels, simple));
+
+ error:
+ parser->lex_untranslated_string = false;
+ return ret;
+
+ error_close_paren:
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ goto error;
+}
+
+/* Parse asm operands, a GNU extension.
+
+ 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)
+{
+ tree list = NULL_TREE;
+ while (true)
+ {
+ tree name, str;
+ struct c_expr expr;
+ if (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ tree id = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ name = build_string (IDENTIFIER_LENGTH (id),
+ IDENTIFIER_POINTER (id));
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, NULL);
+ return NULL_TREE;
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ }
+ else
+ name = NULL_TREE;
+ str = c_parser_asm_string_literal (parser);
+ if (str == NULL_TREE)
+ return NULL_TREE;
+ parser->lex_untranslated_string = false;
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ parser->lex_untranslated_string = true;
+ return NULL_TREE;
+ }
+ expr = c_parser_expression (parser);
+ mark_exp_read (expr.value);
+ parser->lex_untranslated_string = true;
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return NULL_TREE;
+ }
+ list = chainon (list, build_tree_list (build_tree_list (name, str),
+ expr.value));
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ return list;
+}
+
+/* Parse asm clobbers, a GNU extension.
+
+ asm-clobbers:
+ asm-string-literal
+ asm-clobbers , asm-string-literal
+*/
+
+static tree
+c_parser_asm_clobbers (c_parser *parser)
+{
+ tree list = NULL_TREE;
+ while (true)
+ {
+ tree str = c_parser_asm_string_literal (parser);
+ if (str)
+ list = tree_cons (NULL_TREE, str, list);
+ else
+ return NULL_TREE;
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ return list;
+}
+
+/* Parse asm goto labels, a GNU extension.
+
+ asm-goto-operands:
+ identifier
+ asm-goto-operands , identifier
+*/
+
+static tree
+c_parser_asm_goto_operands (c_parser *parser)
+{
+ tree list = NULL_TREE;
+ while (true)
+ {
+ tree name, label;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_token *tok = c_parser_peek_token (parser);
+ name = tok->value;
+ label = lookup_label_for_goto (tok->location, name);
+ c_parser_consume_token (parser);
+ TREE_USED (label) = 1;
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ return NULL_TREE;
+ }
+
+ name = build_string (IDENTIFIER_LENGTH (name),
+ IDENTIFIER_POINTER (name));
+ list = tree_cons (name, label, list);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ return nreverse (list);
+ }
+}
+
+/* Parse an expression other than a compound expression; that is, an
+ assignment expression (C90 6.3.16, C99 6.5.16). If AFTER is not
+ NULL then it is an Objective-C message expression which is the
+ primary-expression starting the expression as an initializer.
+
+ assignment-expression:
+ conditional-expression
+ unary-expression assignment-operator assignment-expression
+
+ assignment-operator: one of
+ = *= /= %= += -= <<= >>= &= ^= |=
+
+ In GNU C we accept any conditional expression on the LHS and
+ diagnose the invalid lvalue rather than producing a syntax
+ error. */
+
+static struct c_expr
+c_parser_expr_no_commas (c_parser *parser, struct c_expr *after)
+{
+ struct c_expr lhs, rhs, ret;
+ enum tree_code code;
+ location_t op_location, exp_location;
+ gcc_assert (!after || c_dialect_objc ());
+ lhs = c_parser_conditional_expression (parser, after);
+ op_location = c_parser_peek_token (parser)->location;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_EQ:
+ code = NOP_EXPR;
+ break;
+ case CPP_MULT_EQ:
+ code = MULT_EXPR;
+ break;
+ case CPP_DIV_EQ:
+ code = TRUNC_DIV_EXPR;
+ break;
+ case CPP_MOD_EQ:
+ code = TRUNC_MOD_EXPR;
+ break;
+ case CPP_PLUS_EQ:
+ code = PLUS_EXPR;
+ break;
+ case CPP_MINUS_EQ:
+ code = MINUS_EXPR;
+ break;
+ case CPP_LSHIFT_EQ:
+ code = LSHIFT_EXPR;
+ break;
+ case CPP_RSHIFT_EQ:
+ code = RSHIFT_EXPR;
+ break;
+ case CPP_AND_EQ:
+ code = BIT_AND_EXPR;
+ break;
+ case CPP_XOR_EQ:
+ code = BIT_XOR_EXPR;
+ break;
+ case CPP_OR_EQ:
+ code = BIT_IOR_EXPR;
+ break;
+ default:
+ return lhs;
+ }
+ c_parser_consume_token (parser);
+ exp_location = c_parser_peek_token (parser)->location;
+ rhs = c_parser_expr_no_commas (parser, NULL);
+ rhs = default_function_array_read_conversion (exp_location, rhs);
+ ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type,
+ code, exp_location, rhs.value,
+ rhs.original_type);
+ if (code == NOP_EXPR)
+ ret.original_code = MODIFY_EXPR;
+ else
+ {
+ TREE_NO_WARNING (ret.value) = 1;
+ ret.original_code = ERROR_MARK;
+ }
+ ret.original_type = NULL;
+ return ret;
+}
+
+/* Parse a conditional expression (C90 6.3.15, C99 6.5.15). If AFTER
+ is not NULL then it is an Objective-C message expression which is
+ the primary-expression starting the expression as an initializer.
+
+ conditional-expression:
+ logical-OR-expression
+ logical-OR-expression ? expression : conditional-expression
+
+ GNU extensions:
+
+ conditional-expression:
+ logical-OR-expression ? : conditional-expression
+*/
+
+static struct c_expr
+c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
+{
+ struct c_expr cond, exp1, exp2, ret;
+ location_t cond_loc, colon_loc, middle_loc;
+
+ gcc_assert (!after || c_dialect_objc ());
+
+ cond = c_parser_binary_expression (parser, after, PREC_NONE);
+
+ if (c_parser_next_token_is_not (parser, CPP_QUERY))
+ return cond;
+ cond_loc = c_parser_peek_token (parser)->location;
+ cond = default_function_array_read_conversion (cond_loc, cond);
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ tree eptype = NULL_TREE;
+
+ middle_loc = c_parser_peek_token (parser)->location;
+ pedwarn (middle_loc, OPT_Wpedantic,
+ "ISO C forbids omitting the middle term of a ?: expression");
+ warn_for_omitted_condop (middle_loc, cond.value);
+ if (TREE_CODE (cond.value) == EXCESS_PRECISION_EXPR)
+ {
+ eptype = TREE_TYPE (cond.value);
+ cond.value = TREE_OPERAND (cond.value, 0);
+ }
+ /* Make sure first operand is calculated only once. */
+ exp1.value = c_save_expr (default_conversion (cond.value));
+ if (eptype)
+ exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value);
+ exp1.original_type = NULL;
+ cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value);
+ c_inhibit_evaluation_warnings += cond.value == truthvalue_true_node;
+ }
+ else
+ {
+ cond.value
+ = c_objc_common_truthvalue_conversion
+ (cond_loc, default_conversion (cond.value));
+ c_inhibit_evaluation_warnings += cond.value == truthvalue_false_node;
+ exp1 = c_parser_expression_conv (parser);
+ mark_exp_read (exp1.value);
+ c_inhibit_evaluation_warnings +=
+ ((cond.value == truthvalue_true_node)
+ - (cond.value == truthvalue_false_node));
+ }
+
+ colon_loc = c_parser_peek_token (parser)->location;
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ {
+ c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ return ret;
+ }
+ {
+ location_t exp2_loc = c_parser_peek_token (parser)->location;
+ exp2 = c_parser_conditional_expression (parser, NULL);
+ exp2 = default_function_array_read_conversion (exp2_loc, exp2);
+ }
+ c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
+ ret.value = build_conditional_expr (colon_loc, cond.value,
+ cond.original_code == C_MAYBE_CONST_EXPR,
+ exp1.value, exp1.original_type,
+ exp2.value, exp2.original_type);
+ ret.original_code = ERROR_MARK;
+ if (exp1.value == error_mark_node || exp2.value == error_mark_node)
+ ret.original_type = NULL;
+ else
+ {
+ tree t1, t2;
+
+ /* If both sides are enum type, the default conversion will have
+ made the type of the result be an integer type. We want to
+ remember the enum types we started with. */
+ t1 = exp1.original_type ? exp1.original_type : TREE_TYPE (exp1.value);
+ t2 = exp2.original_type ? exp2.original_type : TREE_TYPE (exp2.value);
+ ret.original_type = ((t1 != error_mark_node
+ && t2 != error_mark_node
+ && (TYPE_MAIN_VARIANT (t1)
+ == TYPE_MAIN_VARIANT (t2)))
+ ? t1
+ : NULL);
+ }
+ return ret;
+}
+
+/* Parse a binary expression; that is, a logical-OR-expression (C90
+ 6.3.5-6.3.14, C99 6.5.5-6.5.14). If AFTER is not NULL then it is
+ an Objective-C message expression which is the primary-expression
+ starting the expression as an initializer. PREC is the starting
+ precedence, usually PREC_NONE.
+
+ 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,
+ enum c_parser_prec prec)
+{
+ /* A binary expression is parsed using operator-precedence parsing,
+ with the operands being cast expressions. All the binary
+ operators are left-associative. Thus a binary expression is of
+ form:
+
+ E0 op1 E1 op2 E2 ...
+
+ which we represent on a stack. On the stack, the precedence
+ levels are strictly increasing. When a new operator is
+ encountered of higher precedence than that at the top of the
+ stack, it is pushed; its LHS is the top expression, and its RHS
+ is everything parsed until it is popped. When a new operator is
+ encountered with precedence less than or equal to that at the top
+ of the stack, triples E[i-1] op[i] E[i] are popped and replaced
+ by the result of the operation until the operator at the top of
+ the stack has lower precedence than the new operator or there is
+ only one element on the stack; then the top expression is the LHS
+ of the new operator. In the case of logical AND and OR
+ expressions, we also need to adjust c_inhibit_evaluation_warnings
+ as appropriate when the operators are pushed and popped. */
+
+ 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 c_parser_prec prec;
+ /* The operation on its left. */
+ enum tree_code op;
+ /* The source location of this operation. */
+ location_t loc;
+ } stack[NUM_PRECS];
+ int sp;
+ /* Location of the binary operator. */
+ location_t binary_loc = UNKNOWN_LOCATION; /* Quiet warning. */
+#define POP \
+ do { \
+ switch (stack[sp].op) \
+ { \
+ case TRUTH_ANDIF_EXPR: \
+ c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \
+ == truthvalue_false_node); \
+ break; \
+ case TRUTH_ORIF_EXPR: \
+ c_inhibit_evaluation_warnings -= (stack[sp - 1].expr.value \
+ == truthvalue_true_node); \
+ break; \
+ default: \
+ break; \
+ } \
+ stack[sp - 1].expr \
+ = default_function_array_read_conversion (stack[sp - 1].loc, \
+ stack[sp - 1].expr); \
+ stack[sp].expr \
+ = default_function_array_read_conversion (stack[sp].loc, \
+ stack[sp].expr); \
+ stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \
+ stack[sp].op, \
+ stack[sp - 1].expr, \
+ stack[sp].expr); \
+ sp--; \
+ } while (0)
+ gcc_assert (!after || c_dialect_objc ());
+ stack[0].loc = c_parser_peek_token (parser)->location;
+ stack[0].expr = c_parser_cast_expression (parser, after);
+ stack[0].prec = prec;
+ sp = 0;
+ while (true)
+ {
+ enum c_parser_prec oprec;
+ enum tree_code ocode;
+ if (parser->error)
+ goto out;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_MULT:
+ oprec = PREC_MULT;
+ ocode = MULT_EXPR;
+ break;
+ case CPP_DIV:
+ oprec = PREC_MULT;
+ ocode = TRUNC_DIV_EXPR;
+ break;
+ case CPP_MOD:
+ oprec = PREC_MULT;
+ ocode = TRUNC_MOD_EXPR;
+ break;
+ case CPP_PLUS:
+ oprec = PREC_ADD;
+ ocode = PLUS_EXPR;
+ break;
+ case CPP_MINUS:
+ oprec = PREC_ADD;
+ ocode = MINUS_EXPR;
+ break;
+ case CPP_LSHIFT:
+ oprec = PREC_SHIFT;
+ ocode = LSHIFT_EXPR;
+ break;
+ case CPP_RSHIFT:
+ oprec = PREC_SHIFT;
+ ocode = RSHIFT_EXPR;
+ break;
+ case CPP_LESS:
+ oprec = PREC_REL;
+ ocode = LT_EXPR;
+ break;
+ case CPP_GREATER:
+ oprec = PREC_REL;
+ ocode = GT_EXPR;
+ break;
+ case CPP_LESS_EQ:
+ oprec = PREC_REL;
+ ocode = LE_EXPR;
+ break;
+ case CPP_GREATER_EQ:
+ oprec = PREC_REL;
+ ocode = GE_EXPR;
+ break;
+ case CPP_EQ_EQ:
+ oprec = PREC_EQ;
+ ocode = EQ_EXPR;
+ break;
+ case CPP_NOT_EQ:
+ oprec = PREC_EQ;
+ ocode = NE_EXPR;
+ break;
+ case CPP_AND:
+ oprec = PREC_BITAND;
+ ocode = BIT_AND_EXPR;
+ break;
+ case CPP_XOR:
+ oprec = PREC_BITXOR;
+ ocode = BIT_XOR_EXPR;
+ break;
+ case CPP_OR:
+ oprec = PREC_BITOR;
+ ocode = BIT_IOR_EXPR;
+ break;
+ case CPP_AND_AND:
+ oprec = PREC_LOGAND;
+ ocode = TRUTH_ANDIF_EXPR;
+ break;
+ case CPP_OR_OR:
+ oprec = PREC_LOGOR;
+ ocode = TRUTH_ORIF_EXPR;
+ break;
+ default:
+ /* Not a binary operator, so end of the binary
+ expression. */
+ goto out;
+ }
+ binary_loc = c_parser_peek_token (parser)->location;
+ while (oprec <= stack[sp].prec)
+ {
+ if (sp == 0)
+ goto out;
+ POP;
+ }
+ c_parser_consume_token (parser);
+ switch (ocode)
+ {
+ case TRUTH_ANDIF_EXPR:
+ stack[sp].expr
+ = default_function_array_read_conversion (stack[sp].loc,
+ stack[sp].expr);
+ stack[sp].expr.value = c_objc_common_truthvalue_conversion
+ (stack[sp].loc, default_conversion (stack[sp].expr.value));
+ c_inhibit_evaluation_warnings += (stack[sp].expr.value
+ == truthvalue_false_node);
+ break;
+ case TRUTH_ORIF_EXPR:
+ stack[sp].expr
+ = default_function_array_read_conversion (stack[sp].loc,
+ stack[sp].expr);
+ stack[sp].expr.value = c_objc_common_truthvalue_conversion
+ (stack[sp].loc, default_conversion (stack[sp].expr.value));
+ c_inhibit_evaluation_warnings += (stack[sp].expr.value
+ == truthvalue_true_node);
+ break;
+ default:
+ break;
+ }
+ sp++;
+ stack[sp].loc = binary_loc;
+ stack[sp].expr = c_parser_cast_expression (parser, NULL);
+ stack[sp].prec = oprec;
+ stack[sp].op = ocode;
+ stack[sp].loc = binary_loc;
+ }
+ out:
+ while (sp > 0)
+ POP;
+ return stack[0].expr;
+#undef POP
+}
+
+/* Parse a cast expression (C90 6.3.4, C99 6.5.4). If AFTER is not
+ NULL then it is an Objective-C message expression which is the
+ primary-expression starting the expression as an initializer.
+
+ cast-expression:
+ unary-expression
+ ( type-name ) unary-expression
+*/
+
+static struct c_expr
+c_parser_cast_expression (c_parser *parser, struct c_expr *after)
+{
+ location_t cast_loc = c_parser_peek_token (parser)->location;
+ gcc_assert (!after || c_dialect_objc ());
+ if (after)
+ return c_parser_postfix_expression_after_primary (parser,
+ cast_loc, *after);
+ /* If the expression begins with a parenthesized type name, it may
+ be either a cast or a compound literal; we need to see whether
+ the next character is '{' to tell the difference. If not, it is
+ an unary expression. Full detection of unknown typenames here
+ would require a 3-token lookahead. */
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+ && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+ {
+ struct c_type_name *type_name;
+ struct c_expr ret;
+ struct c_expr expr;
+ c_parser_consume_token (parser);
+ type_name = c_parser_type_name (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ if (type_name == NULL)
+ {
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ return ret;
+ }
+
+ /* Save casted types in the function's used types hash table. */
+ used_types_insert (type_name->specs->type);
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ return c_parser_postfix_expression_after_paren_type (parser, type_name,
+ cast_loc);
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ expr = c_parser_cast_expression (parser, NULL);
+ expr = default_function_array_read_conversion (expr_loc, expr);
+ }
+ ret.value = c_cast_expr (cast_loc, type_name, expr.value);
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ return ret;
+ }
+ else
+ return c_parser_unary_expression (parser);
+}
+
+/* Parse an unary expression (C90 6.3.3, C99 6.5.3).
+
+ unary-expression:
+ postfix-expression
+ ++ unary-expression
+ -- unary-expression
+ unary-operator cast-expression
+ sizeof unary-expression
+ sizeof ( type-name )
+
+ unary-operator: one of
+ & * + - ~ !
+
+ GNU extensions:
+
+ unary-expression:
+ __alignof__ unary-expression
+ __alignof__ ( type-name )
+ && identifier
+
+ (C11 permits _Alignof with type names only.)
+
+ unary-operator: one of
+ __extension__ __real__ __imag__
+
+ Transactional Memory:
+
+ unary-expression:
+ transaction-expression
+
+ In addition, the GNU syntax treats ++ and -- as unary operators, so
+ they may be applied to cast expressions with errors for non-lvalues
+ given later. */
+
+static struct c_expr
+c_parser_unary_expression (c_parser *parser)
+{
+ int ext;
+ struct c_expr ret, op;
+ location_t op_loc = c_parser_peek_token (parser)->location;
+ location_t exp_loc;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_PLUS_PLUS:
+ c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, PREINCREMENT_EXPR, op);
+ case CPP_MINUS_MINUS:
+ c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, PREDECREMENT_EXPR, op);
+ case CPP_AND:
+ c_parser_consume_token (parser);
+ op = c_parser_cast_expression (parser, NULL);
+ mark_exp_read (op.value);
+ return parser_build_unary_op (op_loc, ADDR_EXPR, op);
+ case CPP_MULT:
+ c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_read_conversion (exp_loc, op);
+ ret.value = build_indirect_ref (op_loc, op.value, RO_UNARY_STAR);
+ return ret;
+ case CPP_PLUS:
+ if (!c_dialect_objc () && !in_system_header)
+ warning_at (op_loc,
+ OPT_Wtraditional,
+ "traditional C rejects the unary plus operator");
+ c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, CONVERT_EXPR, op);
+ case CPP_MINUS:
+ c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, NEGATE_EXPR, op);
+ case CPP_COMPL:
+ c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, BIT_NOT_EXPR, op);
+ case CPP_NOT:
+ c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_read_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, TRUTH_NOT_EXPR, op);
+ case CPP_AND_AND:
+ /* Refer to the address of a label as a pointer. */
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ ret.value = finish_label_address_expr
+ (c_parser_peek_token (parser)->value, op_loc);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ ret.value = error_mark_node;
+ }
+ return ret;
+ case CPP_KEYWORD:
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_SIZEOF:
+ return c_parser_sizeof_expression (parser);
+ case RID_ALIGNOF:
+ return c_parser_alignof_expression (parser);
+ case RID_EXTENSION:
+ c_parser_consume_token (parser);
+ ext = disable_extension_diagnostics ();
+ ret = c_parser_cast_expression (parser, NULL);
+ restore_extension_diagnostics (ext);
+ return ret;
+ case RID_REALPART:
+ c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, REALPART_EXPR, op);
+ case RID_IMAGPART:
+ c_parser_consume_token (parser);
+ exp_loc = c_parser_peek_token (parser)->location;
+ op = c_parser_cast_expression (parser, NULL);
+ op = default_function_array_conversion (exp_loc, op);
+ return parser_build_unary_op (op_loc, IMAGPART_EXPR, op);
+ case RID_TRANSACTION_ATOMIC:
+ case RID_TRANSACTION_RELAXED:
+ return c_parser_transaction_expression (parser,
+ c_parser_peek_token (parser)->keyword);
+ default:
+ return c_parser_postfix_expression (parser);
+ }
+ default:
+ return c_parser_postfix_expression (parser);
+ }
+}
+
+/* Parse a sizeof expression. */
+
+static struct c_expr
+c_parser_sizeof_expression (c_parser *parser)
+{
+ struct c_expr expr;
+ location_t expr_loc;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
+ c_parser_consume_token (parser);
+ c_inhibit_evaluation_warnings++;
+ in_sizeof++;
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+ && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+ {
+ /* Either sizeof ( type-name ) or sizeof unary-expression
+ starting with a compound literal. */
+ struct c_type_name *type_name;
+ c_parser_consume_token (parser);
+ expr_loc = c_parser_peek_token (parser)->location;
+ type_name = c_parser_type_name (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ if (type_name == NULL)
+ {
+ struct c_expr ret;
+ c_inhibit_evaluation_warnings--;
+ in_sizeof--;
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ return ret;
+ }
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ expr = c_parser_postfix_expression_after_paren_type (parser,
+ type_name,
+ expr_loc);
+ goto sizeof_expr;
+ }
+ /* sizeof ( type-name ). */
+ c_inhibit_evaluation_warnings--;
+ in_sizeof--;
+ return c_expr_sizeof_type (expr_loc, type_name);
+ }
+ else
+ {
+ expr_loc = c_parser_peek_token (parser)->location;
+ expr = c_parser_unary_expression (parser);
+ sizeof_expr:
+ c_inhibit_evaluation_warnings--;
+ in_sizeof--;
+ mark_exp_read (expr.value);
+ if (TREE_CODE (expr.value) == COMPONENT_REF
+ && DECL_C_BIT_FIELD (TREE_OPERAND (expr.value, 1)))
+ error_at (expr_loc, "%<sizeof%> applied to a bit-field");
+ return c_expr_sizeof_expr (expr_loc, expr);
+ }
+}
+
+/* Parse an alignof expression. */
+
+static struct c_expr
+c_parser_alignof_expression (c_parser *parser)
+{
+ struct c_expr expr;
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree alignof_spelling = c_parser_peek_token (parser)->value;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF));
+ /* A diagnostic is not required for the use of this identifier in
+ the implementation namespace; only diagnose it for the C11
+ spelling because of existing code using the other spellings. */
+ if (!flag_isoc11
+ && strcmp (IDENTIFIER_POINTER (alignof_spelling), "_Alignof") == 0)
+ {
+ if (flag_isoc99)
+ pedwarn (loc, OPT_Wpedantic, "ISO C99 does not support %qE",
+ alignof_spelling);
+ else
+ pedwarn (loc, OPT_Wpedantic, "ISO C90 does not support %qE",
+ alignof_spelling);
+ }
+ c_parser_consume_token (parser);
+ c_inhibit_evaluation_warnings++;
+ in_alignof++;
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+ && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+ {
+ /* Either __alignof__ ( type-name ) or __alignof__
+ unary-expression starting with a compound literal. */
+ location_t loc;
+ struct c_type_name *type_name;
+ struct c_expr ret;
+ c_parser_consume_token (parser);
+ loc = c_parser_peek_token (parser)->location;
+ type_name = c_parser_type_name (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ if (type_name == NULL)
+ {
+ struct c_expr ret;
+ c_inhibit_evaluation_warnings--;
+ in_alignof--;
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ return ret;
+ }
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ expr = c_parser_postfix_expression_after_paren_type (parser,
+ type_name,
+ loc);
+ goto alignof_expr;
+ }
+ /* alignof ( type-name ). */
+ c_inhibit_evaluation_warnings--;
+ in_alignof--;
+ ret.value = c_alignof (loc, groktypename (type_name, NULL, NULL));
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ return ret;
+ }
+ else
+ {
+ struct c_expr ret;
+ expr = c_parser_unary_expression (parser);
+ alignof_expr:
+ mark_exp_read (expr.value);
+ c_inhibit_evaluation_warnings--;
+ in_alignof--;
+ pedwarn (loc, OPT_Wpedantic, "ISO C does not allow %<%E (expression)%>",
+ alignof_spelling);
+ ret.value = c_alignof_expr (loc, expr.value);
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ return ret;
+ }
+}
+
+/* Helper function to read arguments of builtins which are interfaces
+ for the middle-end nodes like COMPLEX_EXPR, VEC_PERM_EXPR and
+ others. The name of the builtin is passed using BNAME parameter.
+ Function returns true if there were no errors while parsing and
+ stores the arguments in CEXPR_LIST. */
+static bool
+c_parser_get_builtin_args (c_parser *parser, const char *bname,
+ vec<c_expr_t, va_gc> **ret_cexpr_list)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ vec<c_expr_t, va_gc> *cexpr_list;
+ c_expr_t expr;
+
+ *ret_cexpr_list = NULL;
+ if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+ {
+ error_at (loc, "cannot take address of %qs", bname);
+ return false;
+ }
+
+ c_parser_consume_token (parser);
+
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ c_parser_consume_token (parser);
+ return true;
+ }
+
+ expr = c_parser_expr_no_commas (parser, NULL);
+ vec_alloc (cexpr_list, 1);
+ C_EXPR_APPEND (cexpr_list, expr);
+ while (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ expr = c_parser_expr_no_commas (parser, NULL);
+ C_EXPR_APPEND (cexpr_list, expr);
+ }
+
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ return false;
+
+ *ret_cexpr_list = cexpr_list;
+ return true;
+}
+
+
+/* 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 )
+ __builtin_complex ( assignment-expression , assignment-expression )
+ __builtin_shuffle ( assignment-expression , assignment-expression )
+ __builtin_shuffle ( assignment-expression ,
+ assignment-expression ,
+ assignment-expression, )
+
+ 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
+ Classname . identifier
+*/
+
+static struct c_expr
+c_parser_postfix_expression (c_parser *parser)
+{
+ struct c_expr expr, e1;
+ struct c_type_name *t1, *t2;
+ location_t loc = c_parser_peek_token (parser)->location;;
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_NUMBER:
+ expr.value = c_parser_peek_token (parser)->value;
+ loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ if (TREE_CODE (expr.value) == FIXED_CST
+ && !targetm.fixed_point_supported_p ())
+ {
+ error_at (loc, "fixed-point types not supported for this target");
+ expr.value = error_mark_node;
+ }
+ break;
+ case CPP_CHAR:
+ case CPP_CHAR16:
+ case CPP_CHAR32:
+ case CPP_WCHAR:
+ expr.value = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ break;
+ case CPP_STRING:
+ case CPP_STRING16:
+ case CPP_STRING32:
+ case CPP_WSTRING:
+ case CPP_UTF8STRING:
+ expr.value = c_parser_peek_token (parser)->value;
+ expr.original_code = STRING_CST;
+ c_parser_consume_token (parser);
+ break;
+ case CPP_OBJC_STRING:
+ gcc_assert (c_dialect_objc ());
+ expr.value
+ = objc_build_string_object (c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ break;
+ case CPP_NAME:
+ switch (c_parser_peek_token (parser)->id_kind)
+ {
+ case C_ID_ID:
+ {
+ tree id = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ expr.value = build_external_ref (loc, id,
+ (c_parser_peek_token (parser)->type
+ == CPP_OPEN_PAREN),
+ &expr.original_type);
+ break;
+ }
+ case C_ID_CLASSNAME:
+ {
+ /* Here we parse the Objective-C 2.0 Class.name dot
+ syntax. */
+ tree class_name = c_parser_peek_token (parser)->value;
+ tree component;
+ c_parser_consume_token (parser);
+ gcc_assert (c_dialect_objc ());
+ if (!c_parser_require (parser, CPP_DOT, "expected %<.%>"))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ expr.value = error_mark_node;
+ break;
+ }
+ component = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ expr.value = objc_build_class_component_ref (class_name,
+ component);
+ break;
+ }
+ default:
+ c_parser_error (parser, "expected expression");
+ expr.value = error_mark_node;
+ break;
+ }
+ break;
+ case CPP_OPEN_PAREN:
+ /* A parenthesized expression, statement expression or compound
+ literal. */
+ if (c_parser_peek_2nd_token (parser)->type == CPP_OPEN_BRACE)
+ {
+ /* A statement expression. */
+ tree stmt;
+ location_t brace_loc;
+ c_parser_consume_token (parser);
+ brace_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ if (!building_stmt_list_p ())
+ {
+ error_at (loc, "braced-group within expression allowed "
+ "only inside a function");
+ parser->error = true;
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.value = error_mark_node;
+ break;
+ }
+ stmt = c_begin_stmt_expr ();
+ c_parser_compound_statement_nostart (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ pedwarn (loc, OPT_Wpedantic,
+ "ISO C forbids braced-groups within expressions");
+ expr.value = c_finish_stmt_expr (brace_loc, stmt);
+ mark_exp_read (expr.value);
+ }
+ else if (c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+ {
+ /* A compound literal. ??? Can we actually get here rather
+ than going directly to
+ c_parser_postfix_expression_after_paren_type from
+ elsewhere? */
+ location_t loc;
+ struct c_type_name *type_name;
+ c_parser_consume_token (parser);
+ loc = c_parser_peek_token (parser)->location;
+ type_name = c_parser_type_name (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ if (type_name == NULL)
+ {
+ expr.value = error_mark_node;
+ }
+ else
+ expr = c_parser_postfix_expression_after_paren_type (parser,
+ type_name,
+ loc);
+ }
+ else
+ {
+ /* A parenthesized expression. */
+ c_parser_consume_token (parser);
+ expr = c_parser_expression (parser);
+ if (TREE_CODE (expr.value) == MODIFY_EXPR)
+ TREE_NO_WARNING (expr.value) = 1;
+ if (expr.original_code != C_MAYBE_CONST_EXPR)
+ expr.original_code = ERROR_MARK;
+ /* Don't change EXPR.ORIGINAL_TYPE. */
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ }
+ break;
+ case CPP_KEYWORD:
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_FUNCTION_NAME:
+ case RID_PRETTY_FUNCTION_NAME:
+ case RID_C99_FUNCTION_NAME:
+ expr.value = fname_decl (loc,
+ c_parser_peek_token (parser)->keyword,
+ c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ break;
+ case RID_VA_ARG:
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+ e1 = c_parser_expr_no_commas (parser, NULL);
+ mark_exp_read (e1.value);
+ e1.value = c_fully_fold (e1.value, false, NULL);
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.value = error_mark_node;
+ break;
+ }
+ loc = c_parser_peek_token (parser)->location;
+ t1 = c_parser_type_name (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ if (t1 == NULL)
+ {
+ expr.value = error_mark_node;
+ }
+ else
+ {
+ tree type_expr = NULL_TREE;
+ expr.value = c_build_va_arg (loc, e1.value,
+ groktypename (t1, &type_expr, NULL));
+ if (type_expr)
+ {
+ expr.value = build2 (C_MAYBE_CONST_EXPR,
+ TREE_TYPE (expr.value), type_expr,
+ expr.value);
+ C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true;
+ }
+ }
+ break;
+ case RID_OFFSETOF:
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+ t1 = c_parser_type_name (parser);
+ if (t1 == NULL)
+ parser->error = true;
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ gcc_assert (parser->error);
+ if (parser->error)
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.value = error_mark_node;
+ break;
+ }
+
+ {
+ tree type = groktypename (t1, NULL, NULL);
+ tree offsetof_ref;
+ if (type == error_mark_node)
+ offsetof_ref = error_mark_node;
+ else
+ {
+ offsetof_ref = build1 (INDIRECT_REF, type, null_pointer_node);
+ SET_EXPR_LOCATION (offsetof_ref, loc);
+ }
+ /* Parse the second argument to __builtin_offsetof. We
+ must have one identifier, and beyond that we want to
+ accept sub structure and sub array references. */
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ offsetof_ref = build_component_ref
+ (loc, offsetof_ref, c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ while (c_parser_next_token_is (parser, CPP_DOT)
+ || c_parser_next_token_is (parser,
+ CPP_OPEN_SQUARE)
+ || c_parser_next_token_is (parser,
+ CPP_DEREF))
+ {
+ if (c_parser_next_token_is (parser, CPP_DEREF))
+ {
+ loc = c_parser_peek_token (parser)->location;
+ offsetof_ref = build_array_ref (loc,
+ offsetof_ref,
+ integer_zero_node);
+ goto do_dot;
+ }
+ else if (c_parser_next_token_is (parser, CPP_DOT))
+ {
+ do_dot:
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is_not (parser,
+ CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ break;
+ }
+ offsetof_ref = build_component_ref
+ (loc, offsetof_ref,
+ c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ tree idx;
+ loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ idx = c_parser_expression (parser).value;
+ idx = c_fully_fold (idx, false, NULL);
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ offsetof_ref = build_array_ref (loc, offsetof_ref, idx);
+ }
+ }
+ }
+ else
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ expr.value = fold_offsetof (offsetof_ref);
+ }
+ break;
+ case RID_CHOOSE_EXPR:
+ {
+ vec<c_expr_t, va_gc> *cexpr_list;
+ c_expr_t *e1_p, *e2_p, *e3_p;
+ tree c;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_choose_expr",
+ &cexpr_list))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+
+ if (vec_safe_length (cexpr_list) != 3)
+ {
+ error_at (loc, "wrong number of arguments to "
+ "%<__builtin_choose_expr%>");
+ expr.value = error_mark_node;
+ break;
+ }
+
+ e1_p = &(*cexpr_list)[0];
+ e2_p = &(*cexpr_list)[1];
+ e3_p = &(*cexpr_list)[2];
+
+ c = e1_p->value;
+ mark_exp_read (e2_p->value);
+ mark_exp_read (e3_p->value);
+ if (TREE_CODE (c) != INTEGER_CST
+ || !INTEGRAL_TYPE_P (TREE_TYPE (c)))
+ error_at (loc,
+ "first argument to %<__builtin_choose_expr%> not"
+ " a constant");
+ constant_expression_warning (c);
+ expr = integer_zerop (c) ? *e3_p : *e2_p;
+ break;
+ }
+ case RID_TYPES_COMPATIBLE_P:
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+ t1 = c_parser_type_name (parser);
+ if (t1 == NULL)
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.value = error_mark_node;
+ break;
+ }
+ t2 = c_parser_type_name (parser);
+ if (t2 == NULL)
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ {
+ tree e1, e2;
+ e1 = groktypename (t1, NULL, NULL);
+ e2 = groktypename (t2, NULL, NULL);
+ if (e1 == error_mark_node || e2 == error_mark_node)
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+
+ e1 = TYPE_MAIN_VARIANT (e1);
+ e2 = TYPE_MAIN_VARIANT (e2);
+
+ expr.value
+ = comptypes (e1, e2) ? integer_one_node : integer_zero_node;
+ }
+ break;
+ case RID_BUILTIN_COMPLEX:
+ {
+ vec<c_expr_t, va_gc> *cexpr_list;
+ c_expr_t *e1_p, *e2_p;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_complex",
+ &cexpr_list))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+
+ if (vec_safe_length (cexpr_list) != 2)
+ {
+ error_at (loc, "wrong number of arguments to "
+ "%<__builtin_complex%>");
+ expr.value = error_mark_node;
+ break;
+ }
+
+ e1_p = &(*cexpr_list)[0];
+ e2_p = &(*cexpr_list)[1];
+
+ mark_exp_read (e1_p->value);
+ if (TREE_CODE (e1_p->value) == EXCESS_PRECISION_EXPR)
+ e1_p->value = convert (TREE_TYPE (e1_p->value),
+ TREE_OPERAND (e1_p->value, 0));
+ mark_exp_read (e2_p->value);
+ if (TREE_CODE (e2_p->value) == EXCESS_PRECISION_EXPR)
+ e2_p->value = convert (TREE_TYPE (e2_p->value),
+ TREE_OPERAND (e2_p->value, 0));
+ if (!SCALAR_FLOAT_TYPE_P (TREE_TYPE (e1_p->value))
+ || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e1_p->value))
+ || !SCALAR_FLOAT_TYPE_P (TREE_TYPE (e2_p->value))
+ || DECIMAL_FLOAT_TYPE_P (TREE_TYPE (e2_p->value)))
+ {
+ error_at (loc, "%<__builtin_complex%> operand "
+ "not of real binary floating-point type");
+ expr.value = error_mark_node;
+ break;
+ }
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (e1_p->value))
+ != TYPE_MAIN_VARIANT (TREE_TYPE (e2_p->value)))
+ {
+ error_at (loc,
+ "%<__builtin_complex%> operands of different types");
+ expr.value = error_mark_node;
+ break;
+ }
+ if (!flag_isoc99)
+ pedwarn (loc, OPT_Wpedantic,
+ "ISO C90 does not support complex types");
+ expr.value = build2 (COMPLEX_EXPR,
+ build_complex_type
+ (TYPE_MAIN_VARIANT
+ (TREE_TYPE (e1_p->value))),
+ e1_p->value, e2_p->value);
+ break;
+ }
+ case RID_BUILTIN_SHUFFLE:
+ {
+ vec<c_expr_t, va_gc> *cexpr_list;
+ unsigned int i;
+ c_expr_t *p;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_shuffle",
+ &cexpr_list))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+
+ FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p)
+ mark_exp_read (p->value);
+
+ if (vec_safe_length (cexpr_list) == 2)
+ expr.value =
+ c_build_vec_perm_expr
+ (loc, (*cexpr_list)[0].value,
+ NULL_TREE, (*cexpr_list)[1].value);
+
+ else if (vec_safe_length (cexpr_list) == 3)
+ expr.value =
+ c_build_vec_perm_expr
+ (loc, (*cexpr_list)[0].value,
+ (*cexpr_list)[1].value,
+ (*cexpr_list)[2].value);
+ else
+ {
+ error_at (loc, "wrong number of arguments to "
+ "%<__builtin_shuffle%>");
+ expr.value = error_mark_node;
+ }
+ break;
+ }
+ case RID_AT_SELECTOR:
+ gcc_assert (c_dialect_objc ());
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+ {
+ tree sel = c_parser_objc_selector_arg (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ expr.value = objc_build_selector_expr (loc, sel);
+ }
+ break;
+ case RID_AT_PROTOCOL:
+ gcc_assert (c_dialect_objc ());
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.value = error_mark_node;
+ break;
+ }
+ {
+ tree id = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ expr.value = objc_build_protocol_expr (id);
+ }
+ break;
+ case RID_AT_ENCODE:
+ /* Extension to support C-structures in the archiver. */
+ gcc_assert (c_dialect_objc ());
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr.value = error_mark_node;
+ break;
+ }
+ t1 = c_parser_type_name (parser);
+ if (t1 == NULL)
+ {
+ expr.value = error_mark_node;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ break;
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ {
+ tree type = groktypename (t1, NULL, NULL);
+ expr.value = objc_build_encode_expr (type);
+ }
+ break;
+ default:
+ c_parser_error (parser, "expected expression");
+ expr.value = error_mark_node;
+ break;
+ }
+ break;
+ case CPP_OPEN_SQUARE:
+ if (c_dialect_objc ())
+ {
+ tree receiver, args;
+ c_parser_consume_token (parser);
+ receiver = c_parser_objc_receiver (parser);
+ args = c_parser_objc_message_args (parser);
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ expr.value = objc_build_message_expr (receiver, args);
+ break;
+ }
+ /* Else fall through to report error. */
+ default:
+ c_parser_error (parser, "expected expression");
+ expr.value = error_mark_node;
+ break;
+ }
+ return c_parser_postfix_expression_after_primary (parser, loc, expr);
+}
+
+/* Parse a postfix expression after a parenthesized type name: the
+ brace-enclosed initializer of a compound literal, possibly followed
+ by some postfix operators. This is separate because it is not
+ possible to tell until after the type name whether a cast
+ expression has a cast or a compound literal, or whether the operand
+ of sizeof is a parenthesized type name or starts with a compound
+ literal. TYPE_LOC is the location where TYPE_NAME starts--the
+ location of the first token after the parentheses around the type
+ name. */
+
+static struct c_expr
+c_parser_postfix_expression_after_paren_type (c_parser *parser,
+ struct c_type_name *type_name,
+ location_t type_loc)
+{
+ tree type;
+ struct c_expr init;
+ bool non_const;
+ struct c_expr expr;
+ location_t start_loc;
+ tree type_expr = NULL_TREE;
+ bool type_expr_const = true;
+ check_compound_literal_type (type_loc, type_name);
+ start_init (NULL_TREE, NULL, 0);
+ type = groktypename (type_name, &type_expr, &type_expr_const);
+ start_loc = c_parser_peek_token (parser)->location;
+ if (type != error_mark_node && C_TYPE_VARIABLE_SIZE (type))
+ {
+ error_at (type_loc, "compound literal has variable size");
+ type = error_mark_node;
+ }
+ init = c_parser_braced_init (parser, type, false);
+ finish_init ();
+ maybe_warn_string_init (type, init);
+
+ if (type != error_mark_node
+ && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type))
+ && current_function_decl)
+ {
+ error ("compound literal qualified by address-space qualifier");
+ type = error_mark_node;
+ }
+
+ if (!flag_isoc99)
+ pedwarn (start_loc, OPT_Wpedantic, "ISO C90 forbids compound literals");
+ non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR)
+ ? CONSTRUCTOR_NON_CONST (init.value)
+ : init.original_code == C_MAYBE_CONST_EXPR);
+ non_const |= !type_expr_const;
+ expr.value = build_compound_literal (start_loc, type, init.value, non_const);
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ if (type_expr)
+ {
+ if (TREE_CODE (expr.value) == C_MAYBE_CONST_EXPR)
+ {
+ gcc_assert (C_MAYBE_CONST_EXPR_PRE (expr.value) == NULL_TREE);
+ C_MAYBE_CONST_EXPR_PRE (expr.value) = type_expr;
+ }
+ else
+ {
+ gcc_assert (!non_const);
+ expr.value = build2 (C_MAYBE_CONST_EXPR, type,
+ type_expr, expr.value);
+ }
+ }
+ return c_parser_postfix_expression_after_primary (parser, start_loc, expr);
+}
+
+/* Callback function for sizeof_pointer_memaccess_warning to compare
+ types. */
+
+static bool
+sizeof_ptr_memacc_comptypes (tree type1, tree type2)
+{
+ return comptypes (type1, type2) == 1;
+}
+
+/* Parse a postfix expression after the initial primary or compound
+ literal; that is, parse a series of postfix operators.
+
+ EXPR_LOC is the location of the primary expression. */
+
+static struct c_expr
+c_parser_postfix_expression_after_primary (c_parser *parser,
+ location_t expr_loc,
+ struct c_expr expr)
+{
+ struct c_expr orig_expr;
+ tree ident, idx;
+ location_t sizeof_arg_loc[3];
+ tree sizeof_arg[3];
+ unsigned int i;
+ vec<tree, va_gc> *exprlist;
+ vec<tree, va_gc> *origtypes = NULL;
+ while (true)
+ {
+ location_t op_loc = c_parser_peek_token (parser)->location;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_OPEN_SQUARE:
+ /* Array reference. */
+ c_parser_consume_token (parser);
+ idx = c_parser_expression (parser).value;
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ expr.value = build_array_ref (op_loc, expr.value, idx);
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ break;
+ case CPP_OPEN_PAREN:
+ /* Function call. */
+ c_parser_consume_token (parser);
+ for (i = 0; i < 3; i++)
+ {
+ sizeof_arg[i] = NULL_TREE;
+ sizeof_arg_loc[i] = UNKNOWN_LOCATION;
+ }
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ exprlist = NULL;
+ else
+ exprlist = c_parser_expr_list (parser, true, false, &origtypes,
+ sizeof_arg_loc, sizeof_arg);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ orig_expr = expr;
+ mark_exp_read (expr.value);
+ if (warn_sizeof_pointer_memaccess)
+ sizeof_pointer_memaccess_warning (sizeof_arg_loc,
+ expr.value, exprlist,
+ sizeof_arg,
+ sizeof_ptr_memacc_comptypes);
+ /* FIXME diagnostics: Ideally we want the FUNCNAME, not the
+ "(" after the FUNCNAME, which is what we have now. */
+ expr.value = c_build_function_call_vec (op_loc, expr.value, exprlist,
+ origtypes);
+ expr.original_code = ERROR_MARK;
+ if (TREE_CODE (expr.value) == INTEGER_CST
+ && TREE_CODE (orig_expr.value) == FUNCTION_DECL
+ && DECL_BUILT_IN_CLASS (orig_expr.value) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (orig_expr.value) == BUILT_IN_CONSTANT_P)
+ expr.original_code = C_MAYBE_CONST_EXPR;
+ expr.original_type = NULL;
+ if (exprlist)
+ {
+ release_tree_vector (exprlist);
+ release_tree_vector (origtypes);
+ }
+ break;
+ case CPP_DOT:
+ /* Structure element reference. */
+ c_parser_consume_token (parser);
+ expr = default_function_array_conversion (expr_loc, expr);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ ident = c_parser_peek_token (parser)->value;
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ return expr;
+ }
+ c_parser_consume_token (parser);
+ expr.value = build_component_ref (op_loc, expr.value, ident);
+ expr.original_code = ERROR_MARK;
+ if (TREE_CODE (expr.value) != COMPONENT_REF)
+ expr.original_type = NULL;
+ else
+ {
+ /* Remember the original type of a bitfield. */
+ tree field = TREE_OPERAND (expr.value, 1);
+ if (TREE_CODE (field) != FIELD_DECL)
+ expr.original_type = NULL;
+ else
+ expr.original_type = DECL_BIT_FIELD_TYPE (field);
+ }
+ break;
+ case CPP_DEREF:
+ /* Structure element reference. */
+ c_parser_consume_token (parser);
+ expr = default_function_array_conversion (expr_loc, expr);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ ident = c_parser_peek_token (parser)->value;
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ expr.value = error_mark_node;
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ return expr;
+ }
+ c_parser_consume_token (parser);
+ expr.value = build_component_ref (op_loc,
+ build_indirect_ref (op_loc,
+ expr.value,
+ RO_ARROW),
+ ident);
+ expr.original_code = ERROR_MARK;
+ if (TREE_CODE (expr.value) != COMPONENT_REF)
+ expr.original_type = NULL;
+ else
+ {
+ /* Remember the original type of a bitfield. */
+ tree field = TREE_OPERAND (expr.value, 1);
+ if (TREE_CODE (field) != FIELD_DECL)
+ expr.original_type = NULL;
+ else
+ expr.original_type = DECL_BIT_FIELD_TYPE (field);
+ }
+ break;
+ case CPP_PLUS_PLUS:
+ /* Postincrement. */
+ c_parser_consume_token (parser);
+ expr = default_function_array_read_conversion (expr_loc, expr);
+ expr.value = build_unary_op (op_loc,
+ POSTINCREMENT_EXPR, expr.value, 0);
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ break;
+ case CPP_MINUS_MINUS:
+ /* Postdecrement. */
+ c_parser_consume_token (parser);
+ expr = default_function_array_read_conversion (expr_loc, expr);
+ expr.value = build_unary_op (op_loc,
+ POSTDECREMENT_EXPR, expr.value, 0);
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ break;
+ default:
+ return expr;
+ }
+ }
+}
+
+/* Parse an expression (C90 6.3.17, C99 6.5.17).
+
+ expression:
+ assignment-expression
+ expression , assignment-expression
+*/
+
+static struct c_expr
+c_parser_expression (c_parser *parser)
+{
+ struct c_expr expr;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ while (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ struct c_expr next;
+ tree lhsval;
+ location_t loc = c_parser_peek_token (parser)->location;
+ location_t expr_loc;
+ c_parser_consume_token (parser);
+ expr_loc = c_parser_peek_token (parser)->location;
+ lhsval = expr.value;
+ while (TREE_CODE (lhsval) == COMPOUND_EXPR)
+ lhsval = TREE_OPERAND (lhsval, 1);
+ if (DECL_P (lhsval) || handled_component_p (lhsval))
+ mark_exp_read (lhsval);
+ next = c_parser_expr_no_commas (parser, NULL);
+ next = default_function_array_conversion (expr_loc, next);
+ expr.value = build_compound_expr (loc, expr.value, next.value);
+ expr.original_code = COMPOUND_EXPR;
+ expr.original_type = next.original_type;
+ }
+ return expr;
+}
+
+/* Parse an expression and convert functions or arrays to
+ pointers. */
+
+static struct c_expr
+c_parser_expression_conv (c_parser *parser)
+{
+ struct c_expr expr;
+ location_t loc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expression (parser);
+ expr = default_function_array_conversion (loc, expr);
+ return expr;
+}
+
+/* Parse a non-empty list of expressions. If CONVERT_P, convert
+ functions and arrays to pointers. If FOLD_P, fold the expressions.
+
+ nonempty-expr-list:
+ assignment-expression
+ nonempty-expr-list , assignment-expression
+*/
+
+static vec<tree, va_gc> *
+c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
+ vec<tree, va_gc> **p_orig_types,
+ location_t *sizeof_arg_loc, tree *sizeof_arg)
+{
+ vec<tree, va_gc> *ret;
+ vec<tree, va_gc> *orig_types;
+ struct c_expr expr;
+ location_t loc = c_parser_peek_token (parser)->location;
+ location_t cur_sizeof_arg_loc = UNKNOWN_LOCATION;
+ unsigned int idx = 0;
+
+ ret = make_tree_vector ();
+ if (p_orig_types == NULL)
+ orig_types = NULL;
+ else
+ orig_types = make_tree_vector ();
+
+ if (sizeof_arg != NULL
+ && c_parser_next_token_is_keyword (parser, RID_SIZEOF))
+ cur_sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ if (convert_p)
+ expr = default_function_array_read_conversion (loc, expr);
+ if (fold_p)
+ expr.value = c_fully_fold (expr.value, false, NULL);
+ ret->quick_push (expr.value);
+ if (orig_types)
+ orig_types->quick_push (expr.original_type);
+ if (sizeof_arg != NULL
+ && cur_sizeof_arg_loc != UNKNOWN_LOCATION
+ && expr.original_code == SIZEOF_EXPR)
+ {
+ sizeof_arg[0] = c_last_sizeof_arg;
+ sizeof_arg_loc[0] = cur_sizeof_arg_loc;
+ }
+ while (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ loc = c_parser_peek_token (parser)->location;
+ if (sizeof_arg != NULL
+ && c_parser_next_token_is_keyword (parser, RID_SIZEOF))
+ cur_sizeof_arg_loc = c_parser_peek_2nd_token (parser)->location;
+ else
+ cur_sizeof_arg_loc = UNKNOWN_LOCATION;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ if (convert_p)
+ expr = default_function_array_read_conversion (loc, expr);
+ if (fold_p)
+ expr.value = c_fully_fold (expr.value, false, NULL);
+ vec_safe_push (ret, expr.value);
+ if (orig_types)
+ vec_safe_push (orig_types, expr.original_type);
+ if (++idx < 3
+ && sizeof_arg != NULL
+ && cur_sizeof_arg_loc != UNKNOWN_LOCATION
+ && expr.original_code == SIZEOF_EXPR)
+ {
+ sizeof_arg[idx] = c_last_sizeof_arg;
+ sizeof_arg_loc[idx] = cur_sizeof_arg_loc;
+ }
+ }
+ if (orig_types)
+ *p_orig_types = orig_types;
+ return ret;
+}
+
+/* Parse Objective-C-specific constructs. */
+
+/* Parse an objc-class-definition.
+
+ objc-class-definition:
+ @interface identifier objc-superclass[opt] objc-protocol-refs[opt]
+ objc-class-instance-variables[opt] objc-methodprotolist @end
+ @implementation identifier objc-superclass[opt]
+ objc-class-instance-variables[opt]
+ @interface identifier ( identifier ) objc-protocol-refs[opt]
+ objc-methodprotolist @end
+ @interface 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, tree attributes)
+{
+ 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))
+ {
+ /* We have a category or class extension. */
+ tree id2;
+ tree proto = NULL_TREE;
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ if (iface_p && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ /* We have a class extension. */
+ id2 = NULL_TREE;
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier or %<)%>");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return;
+ }
+ }
+ else
+ {
+ 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, attributes);
+ 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, attributes);
+ }
+ else
+ objc_start_class_implementation (id1, superclass);
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ c_parser_objc_class_instance_variables (parser);
+ if (iface_p)
+ {
+ objc_continue_interface ();
+ c_parser_objc_methodprotolist (parser);
+ c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
+ objc_finish_interface ();
+ }
+ else
+ {
+ objc_continue_implementation ();
+ return;
+ }
+}
+
+/* Parse objc-class-instance-variables.
+
+ objc-class-instance-variables:
+ { objc-instance-variable-decl-list[opt] }
+
+ objc-instance-variable-decl-list:
+ objc-visibility-spec
+ objc-instance-variable-decl ;
+ ;
+ objc-instance-variable-decl-list objc-visibility-spec
+ objc-instance-variable-decl-list objc-instance-variable-decl ;
+ objc-instance-variable-decl-list ;
+
+ objc-visibility-spec:
+ @private
+ @protected
+ @public
+
+ objc-instance-variable-decl:
+ struct-declaration
+*/
+
+static void
+c_parser_objc_class_instance_variables (c_parser *parser)
+{
+ gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
+ c_parser_consume_token (parser);
+ while (c_parser_next_token_is_not (parser, CPP_EOF))
+ {
+ tree decls;
+ /* Parse any stray semicolon. */
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic,
+ "extra semicolon");
+ 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 (OBJC_IVAR_VIS_PRIVATE);
+ continue;
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_PROTECTED))
+ {
+ c_parser_consume_token (parser);
+ objc_set_visibility (OBJC_IVAR_VIS_PROTECTED);
+ continue;
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_PUBLIC))
+ {
+ c_parser_consume_token (parser);
+ objc_set_visibility (OBJC_IVAR_VIS_PUBLIC);
+ continue;
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_PACKAGE))
+ {
+ c_parser_consume_token (parser);
+ objc_set_visibility (OBJC_IVAR_VIS_PACKAGE);
+ 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);
+ if (decls == NULL)
+ {
+ /* There is a syntax error. We want to skip the offending
+ tokens up to the next ';' (included) or '}'
+ (excluded). */
+
+ /* First, skip manually a ')' or ']'. This is because they
+ reduce the nesting level, so c_parser_skip_until_found()
+ wouldn't be able to skip past them. */
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_CLOSE_PAREN || token->type == CPP_CLOSE_SQUARE)
+ c_parser_consume_token (parser);
+
+ /* Then, do the standard skipping. */
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+
+ /* We hopefully recovered. Start normal parsing again. */
+ parser->error = false;
+ continue;
+ }
+ else
+ {
+ /* Comma-separated instance variables are chained together
+ in reverse order; add them one by one. */
+ tree ivar = nreverse (decls);
+ for (; ivar; ivar = DECL_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)
+{
+ 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");
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+ parser->error = false;
+ return;
+ }
+ id = c_parser_peek_token (parser)->value;
+ objc_declare_class (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 %<;%>");
+}
+
+/* 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, tree attributes)
+{
+ 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)
+ {
+ /* 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;
+ objc_declare_protocol (id, attributes);
+ 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 %<;%>");
+ }
+ else
+ {
+ tree id = c_parser_peek_token (parser)->value;
+ tree proto = NULL_TREE;
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_LESS))
+ proto = c_parser_objc_protocol_refs (parser);
+ parser->objc_pq_context = true;
+ objc_start_protocol (id, proto, attributes);
+ c_parser_objc_methodprotolist (parser);
+ c_parser_require_keyword (parser, RID_AT_END, "expected %<@end%>");
+ parser->objc_pq_context = false;
+ objc_finish_interface ();
+ }
+}
+
+/* Parse an objc-method-type.
+
+ objc-method-type:
+ +
+ -
+
+ Return true if it is a class method (+) and false if it is
+ an instance method (-).
+*/
+static inline bool
+c_parser_objc_method_type (c_parser *parser)
+{
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_PLUS:
+ c_parser_consume_token (parser);
+ return true;
+ case CPP_MINUS:
+ c_parser_consume_token (parser);
+ return false;
+ 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)
+{
+ bool is_class_method = c_parser_objc_method_type (parser);
+ tree decl, attributes = NULL_TREE, expr = NULL_TREE;
+ parser->objc_pq_context = true;
+ decl = c_parser_objc_method_decl (parser, is_class_method, &attributes,
+ &expr);
+ if (decl == error_mark_node)
+ return; /* Bail here. */
+
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ c_parser_consume_token (parser);
+ pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic,
+ "extra semicolon in method definition specified");
+ }
+
+ if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ c_parser_error (parser, "expected %<{%>");
+ return;
+ }
+
+ parser->objc_pq_context = false;
+ if (objc_start_method_definition (is_class_method, decl, attributes, expr))
+ {
+ add_stmt (c_parser_compound_statement (parser));
+ objc_finish_method_definition (current_function_decl);
+ }
+ else
+ {
+ /* This code is executed when we find a method definition
+ outside of an @implementation context (or invalid for other
+ reasons). Parse the method (to keep going) but do not emit
+ any code.
+ */
+ c_parser_compound_statement (parser);
+ }
+}
+
+/* Parse an objc-methodprotolist.
+
+ objc-methodprotolist:
+ empty
+ objc-methodprotolist objc-methodproto
+ objc-methodprotolist declaration
+ objc-methodprotolist ;
+ @optional
+ @required
+
+ The declaration is a data definition, which may be missing
+ declaration specifiers under the same rules and diagnostics as
+ other data definitions outside functions, and the stray semicolon
+ is diagnosed the same way as a stray semicolon outside a
+ function. */
+
+static void
+c_parser_objc_methodprotolist (c_parser *parser)
+{
+ while (true)
+ {
+ /* The list is terminated by @end. */
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_SEMICOLON:
+ pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic,
+ "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;
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY))
+ c_parser_objc_at_property_declaration (parser);
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_OPTIONAL))
+ {
+ objc_set_method_opt (true);
+ c_parser_consume_token (parser);
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_AT_REQUIRED))
+ {
+ objc_set_method_opt (false);
+ c_parser_consume_token (parser);
+ }
+ else
+ c_parser_declaration_or_fndef (parser, false, false, true,
+ false, true, NULL);
+ break;
+ }
+ }
+}
+
+/* Parse an objc-methodproto.
+
+ objc-methodproto:
+ objc-method-type objc-method-decl ;
+*/
+
+static void
+c_parser_objc_methodproto (c_parser *parser)
+{
+ bool is_class_method = c_parser_objc_method_type (parser);
+ tree decl, attributes = NULL_TREE;
+
+ /* Remember protocol qualifiers in prototypes. */
+ parser->objc_pq_context = true;
+ decl = c_parser_objc_method_decl (parser, is_class_method, &attributes,
+ NULL);
+ /* Forget protocol qualifiers now. */
+ parser->objc_pq_context = false;
+
+ /* Do not allow the presence of attributes to hide an erroneous
+ method implementation in the interface section. */
+ if (!c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ c_parser_error (parser, "expected %<;%>");
+ return;
+ }
+
+ if (decl != error_mark_node)
+ objc_add_method_declaration (is_class_method, decl, attributes);
+
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+}
+
+/* If we are at a position that method attributes may be present, check that
+ there are not any parsed already (a syntax error) and then collect any
+ specified at the current location. Finally, if new attributes were present,
+ check that the next token is legal ( ';' for decls and '{' for defs). */
+
+static bool
+c_parser_objc_maybe_method_attributes (c_parser* parser, tree* attributes)
+{
+ bool bad = false;
+ if (*attributes)
+ {
+ c_parser_error (parser,
+ "method attributes must be specified at the end only");
+ *attributes = NULL_TREE;
+ bad = true;
+ }
+
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ *attributes = c_parser_attributes (parser);
+
+ /* If there were no attributes here, just report any earlier error. */
+ if (*attributes == NULL_TREE || bad)
+ return bad;
+
+ /* If the attributes are followed by a ; or {, then just report any earlier
+ error. */
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON)
+ || c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ return bad;
+
+ /* We've got attributes, but not at the end. */
+ c_parser_error (parser,
+ "expected %<;%> or %<{%> after method attribute definition");
+ return true;
+}
+
+/* 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
+ attributes
+
+ 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, bool is_class_method,
+ tree *attributes, tree *expr)
+{
+ tree type = NULL_TREE;
+ tree sel;
+ tree parms = NULL_TREE;
+ bool ellipsis = false;
+ bool attr_err = false;
+
+ *attributes = NULL_TREE;
+ 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;
+ tree param_attr = NULL_TREE;
+ 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 %<)%>");
+ }
+ /* New ObjC allows attributes on method parameters. */
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ param_attr = c_parser_attributes (parser);
+ 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, param_attr);
+ list = chainon (list, keyworddecl);
+ tsel = c_parser_objc_selector (parser);
+ if (!tsel && c_parser_next_token_is_not (parser, CPP_COLON))
+ break;
+ }
+
+ attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ;
+
+ /* 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);
+ attr_err |= c_parser_objc_maybe_method_attributes
+ (parser, attributes) ;
+ break;
+ }
+ parm = c_parser_parameter_declaration (parser, NULL_TREE);
+ if (parm == NULL)
+ break;
+ parms = chainon (parms,
+ build_tree_list (NULL_TREE, grokparm (parm, expr)));
+ }
+ sel = list;
+ }
+ else
+ attr_err |= c_parser_objc_maybe_method_attributes (parser, attributes) ;
+
+ if (sel == NULL)
+ {
+ c_parser_error (parser, "objective-c method declaration is expected");
+ return error_mark_node;
+ }
+
+ if (attr_err)
+ return error_mark_node;
+
+ return objc_build_method_signature (is_class_method, type, sel, parms, ellipsis);
+}
+
+/* Parse an objc-type-name.
+
+ objc-type-name:
+ objc-type-qualifiers[opt] type-name
+ objc-type-qualifiers[opt]
+
+ objc-type-qualifiers:
+ objc-type-qualifier
+ objc-type-qualifiers objc-type-qualifier
+
+ objc-type-qualifier: one of
+ in out inout bycopy byref oneway
+*/
+
+static tree
+c_parser_objc_type_name (c_parser *parser)
+{
+ tree quals = NULL_TREE;
+ struct c_type_name *type_name = NULL;
+ tree type = NULL_TREE;
+ while (true)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_KEYWORD
+ && (token->keyword == RID_IN
+ || token->keyword == RID_OUT
+ || token->keyword == RID_INOUT
+ || token->keyword == RID_BYCOPY
+ || token->keyword == RID_BYREF
+ || token->keyword == RID_ONEWAY))
+ {
+ quals = chainon (build_tree_list (NULL_TREE, token->value), quals);
+ c_parser_consume_token (parser);
+ }
+ else
+ break;
+ }
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_type))
+ type_name = c_parser_type_name (parser);
+ if (type_name)
+ type = groktypename (type_name, NULL, NULL);
+
+ /* If the type is unknown, and error has already been produced and
+ we need to recover from the error. In that case, use NULL_TREE
+ for the type, as if no type had been specified; this will use the
+ default type ('id') which is good for error recovery. */
+ if (type == error_mark_node)
+ type = NULL_TREE;
+
+ 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-finally-statement.
+
+ objc-try-catch-finally-statement:
+ @try compound-statement objc-catch-list[opt]
+ @try compound-statement objc-catch-list[opt] @finally compound-statement
+
+ objc-catch-list:
+ @catch ( objc-catch-parameter-declaration ) compound-statement
+ objc-catch-list @catch ( objc-catch-parameter-declaration ) compound-statement
+
+ objc-catch-parameter-declaration:
+ parameter-declaration
+ '...'
+
+ where '...' is to be interpreted literally, that is, it means CPP_ELLIPSIS.
+
+ PS: This function is identical to cp_parser_objc_try_catch_finally_statement
+ for C++. Keep them in sync. */
+
+static void
+c_parser_objc_try_catch_finally_statement (c_parser *parser)
+{
+ location_t location;
+ tree stmt;
+
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_TRY));
+ c_parser_consume_token (parser);
+ location = c_parser_peek_token (parser)->location;
+ objc_maybe_warn_exceptions (location);
+ stmt = c_parser_compound_statement (parser);
+ objc_begin_try_stmt (location, stmt);
+
+ while (c_parser_next_token_is_keyword (parser, RID_AT_CATCH))
+ {
+ struct c_parm *parm;
+ tree parameter_declaration = error_mark_node;
+ bool seen_open_paren = false;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ seen_open_paren = true;
+ if (c_parser_next_token_is (parser, CPP_ELLIPSIS))
+ {
+ /* We have "@catch (...)" (where the '...' are literally
+ what is in the code). Skip the '...'.
+ parameter_declaration is set to NULL_TREE, and
+ objc_being_catch_clauses() knows that that means
+ '...'. */
+ c_parser_consume_token (parser);
+ parameter_declaration = NULL_TREE;
+ }
+ else
+ {
+ /* We have "@catch (NSException *exception)" or something
+ like that. Parse the parameter declaration. */
+ parm = c_parser_parameter_declaration (parser, NULL_TREE);
+ if (parm == NULL)
+ parameter_declaration = error_mark_node;
+ else
+ parameter_declaration = grokparm (parm, NULL);
+ }
+ if (seen_open_paren)
+ c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ else
+ {
+ /* If there was no open parenthesis, we are recovering from
+ an error, and we are trying to figure out what mistake
+ the user has made. */
+
+ /* If there is an immediate closing parenthesis, the user
+ probably forgot the opening one (ie, they typed "@catch
+ NSException *e)". Parse the closing parenthesis and keep
+ going. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+
+ /* If these is no immediate closing parenthesis, the user
+ probably doesn't know that parenthesis are required at
+ all (ie, they typed "@catch NSException *e"). So, just
+ forget about the closing parenthesis and keep going. */
+ }
+ objc_begin_catch_clause (parameter_declaration);
+ 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))
+ {
+ c_parser_consume_token (parser);
+ location = c_parser_peek_token (parser)->location;
+ stmt = c_parser_compound_statement (parser);
+ objc_build_finally_clause (location, stmt);
+ }
+ 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;
+ objc_maybe_warn_exceptions (loc);
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ expr = c_parser_expression (parser).value;
+ expr = c_fully_fold (expr, false, NULL);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ else
+ expr = error_mark_node;
+ stmt = c_parser_compound_statement (parser);
+ objc_build_synchronized (loc, expr, stmt);
+}
+
+/* Parse an objc-selector; return NULL_TREE without an error if the
+ next token is not an objc-selector.
+
+ objc-selector:
+ identifier
+ one of
+ enum struct union if else while do for switch case default
+ break continue return goto asm sizeof typeof __alignof
+ unsigned long const short volatile signed restrict _Complex
+ in out inout bycopy byref oneway int char float double void _Bool
+
+ ??? Why this selection of keywords but not, for example, storage
+ class specifiers? */
+
+static tree
+c_parser_objc_selector (c_parser *parser)
+{
+ c_token *token = c_parser_peek_token (parser);
+ tree value = token->value;
+ if (token->type == CPP_NAME)
+ {
+ c_parser_consume_token (parser);
+ return value;
+ }
+ if (token->type != CPP_KEYWORD)
+ return NULL_TREE;
+ switch (token->keyword)
+ {
+ case RID_ENUM:
+ case RID_STRUCT:
+ case RID_UNION:
+ case RID_IF:
+ case RID_ELSE:
+ case RID_WHILE:
+ case RID_DO:
+ case RID_FOR:
+ case RID_SWITCH:
+ case RID_CASE:
+ case RID_DEFAULT:
+ case RID_BREAK:
+ case RID_CONTINUE:
+ case RID_RETURN:
+ case RID_GOTO:
+ case RID_ASM:
+ case RID_SIZEOF:
+ case RID_TYPEOF:
+ case RID_ALIGNOF:
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_INT128:
+ case RID_CONST:
+ case RID_SHORT:
+ case RID_VOLATILE:
+ case RID_SIGNED:
+ case RID_RESTRICT:
+ case RID_COMPLEX:
+ case RID_IN:
+ case RID_OUT:
+ case RID_INOUT:
+ case RID_BYCOPY:
+ case RID_BYREF:
+ case RID_ONEWAY:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_BOOL:
+ c_parser_consume_token (parser);
+ return value;
+ default:
+ return NULL_TREE;
+ }
+}
+
+/* Parse an objc-selector-arg.
+
+ objc-selector-arg:
+ objc-selector
+ objc-keywordname-list
+
+ objc-keywordname-list:
+ objc-keywordname
+ objc-keywordname-list objc-keywordname
+
+ objc-keywordname:
+ objc-selector :
+ :
+*/
+
+static tree
+c_parser_objc_selector_arg (c_parser *parser)
+{
+ tree sel = c_parser_objc_selector (parser);
+ tree list = NULL_TREE;
+ if (sel && c_parser_next_token_is_not (parser, CPP_COLON))
+ return sel;
+ while (true)
+ {
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ return list;
+ list = chainon (list, build_tree_list (sel, NULL_TREE));
+ sel = c_parser_objc_selector (parser);
+ if (!sel && c_parser_next_token_is_not (parser, CPP_COLON))
+ break;
+ }
+ return list;
+}
+
+/* Parse an objc-receiver.
+
+ objc-receiver:
+ expression
+ class-name
+ type-name
+*/
+
+static tree
+c_parser_objc_receiver (c_parser *parser)
+{
+ if (c_parser_peek_token (parser)->type == CPP_NAME
+ && (c_parser_peek_token (parser)->id_kind == C_ID_TYPENAME
+ || c_parser_peek_token (parser)->id_kind == C_ID_CLASSNAME))
+ {
+ tree id = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ return objc_get_class_reference (id);
+ }
+ return c_fully_fold (c_parser_expression (parser).value, false, NULL);
+}
+
+/* Parse objc-message-args.
+
+ objc-message-args:
+ objc-selector
+ objc-keywordarg-list
+
+ objc-keywordarg-list:
+ objc-keywordarg
+ objc-keywordarg-list objc-keywordarg
+
+ objc-keywordarg:
+ objc-selector : objc-keywordexpr
+ : objc-keywordexpr
+*/
+
+static tree
+c_parser_objc_message_args (c_parser *parser)
+{
+ tree sel = c_parser_objc_selector (parser);
+ tree list = NULL_TREE;
+ if (sel && c_parser_next_token_is_not (parser, CPP_COLON))
+ return sel;
+ while (true)
+ {
+ tree keywordexpr;
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ return error_mark_node;
+ keywordexpr = c_parser_objc_keywordexpr (parser);
+ list = chainon (list, build_tree_list (sel, keywordexpr));
+ sel = c_parser_objc_selector (parser);
+ if (!sel && c_parser_next_token_is_not (parser, CPP_COLON))
+ break;
+ }
+ return list;
+}
+
+/* Parse an objc-keywordexpr.
+
+ objc-keywordexpr:
+ nonempty-expr-list
+*/
+
+static tree
+c_parser_objc_keywordexpr (c_parser *parser)
+{
+ tree ret;
+ vec<tree, va_gc> *expr_list = c_parser_expr_list (parser, true, true,
+ NULL, NULL, NULL);
+ if (vec_safe_length (expr_list) == 1)
+ {
+ /* Just return the expression, remove a level of
+ indirection. */
+ ret = (*expr_list)[0];
+ }
+ else
+ {
+ /* We have a comma expression, we will collapse later. */
+ ret = build_tree_list_vec (expr_list);
+ }
+ release_tree_vector (expr_list);
+ return ret;
+}
+
+/* A check, needed in several places, that ObjC interface, implementation or
+ method definitions are not prefixed by incorrect items. */
+static bool
+c_parser_objc_diagnose_bad_element_prefix (c_parser *parser,
+ struct c_declspecs *specs)
+{
+ if (!specs->declspecs_seen_p || specs->non_sc_seen_p
+ || specs->typespec_kind != ctsk_none)
+ {
+ c_parser_error (parser,
+ "no type or storage class may be specified here,");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return true;
+ }
+ return false;
+}
+
+/* Parse an Objective-C @property declaration. The syntax is:
+
+ objc-property-declaration:
+ '@property' objc-property-attributes[opt] struct-declaration ;
+
+ objc-property-attributes:
+ '(' objc-property-attribute-list ')'
+
+ objc-property-attribute-list:
+ objc-property-attribute
+ objc-property-attribute-list, objc-property-attribute
+
+ objc-property-attribute
+ 'getter' = identifier
+ 'setter' = identifier
+ 'readonly'
+ 'readwrite'
+ 'assign'
+ 'retain'
+ 'copy'
+ 'nonatomic'
+
+ For example:
+ @property NSString *name;
+ @property (readonly) id object;
+ @property (retain, nonatomic, getter=getTheName) id name;
+ @property int a, b, c;
+
+ PS: This function is identical to cp_parser_objc_at_propery_declaration
+ for C++. Keep them in sync. */
+static void
+c_parser_objc_at_property_declaration (c_parser *parser)
+{
+ /* The following variables hold the attributes of the properties as
+ parsed. They are 'false' or 'NULL_TREE' if the attribute was not
+ seen. When we see an attribute, we set them to 'true' (if they
+ are boolean properties) or to the identifier (if they have an
+ argument, ie, for getter and setter). Note that here we only
+ parse the list of attributes, check the syntax and accumulate the
+ attributes that we find. objc_add_property_declaration() will
+ then process the information. */
+ bool property_assign = false;
+ bool property_copy = false;
+ tree property_getter_ident = NULL_TREE;
+ bool property_nonatomic = false;
+ bool property_readonly = false;
+ bool property_readwrite = false;
+ bool property_retain = false;
+ tree property_setter_ident = NULL_TREE;
+
+ /* 'properties' is the list of properties that we read. Usually a
+ single one, but maybe more (eg, in "@property int a, b, c;" there
+ are three). */
+ tree properties;
+ location_t loc;
+
+ loc = c_parser_peek_token (parser)->location;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY));
+
+ c_parser_consume_token (parser); /* Eat '@property'. */
+
+ /* Parse the optional attribute list... */
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ /* Eat the '(' */
+ c_parser_consume_token (parser);
+
+ /* Property attribute keywords are valid now. */
+ parser->objc_property_attr_context = true;
+
+ while (true)
+ {
+ bool syntax_error = false;
+ c_token *token = c_parser_peek_token (parser);
+ enum rid keyword;
+
+ if (token->type != CPP_KEYWORD)
+ {
+ if (token->type == CPP_CLOSE_PAREN)
+ c_parser_error (parser, "expected identifier");
+ else
+ {
+ c_parser_consume_token (parser);
+ c_parser_error (parser, "unknown property attribute");
+ }
+ break;
+ }
+ keyword = token->keyword;
+ c_parser_consume_token (parser);
+ switch (keyword)
+ {
+ case RID_ASSIGN: property_assign = true; break;
+ case RID_COPY: property_copy = true; break;
+ case RID_NONATOMIC: property_nonatomic = true; break;
+ case RID_READONLY: property_readonly = true; break;
+ case RID_READWRITE: property_readwrite = true; break;
+ case RID_RETAIN: property_retain = true; break;
+
+ case RID_GETTER:
+ case RID_SETTER:
+ if (c_parser_next_token_is_not (parser, CPP_EQ))
+ {
+ if (keyword == RID_GETTER)
+ c_parser_error (parser,
+ "missing %<=%> (after %<getter%> attribute)");
+ else
+ c_parser_error (parser,
+ "missing %<=%> (after %<setter%> attribute)");
+ syntax_error = true;
+ break;
+ }
+ c_parser_consume_token (parser); /* eat the = */
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ syntax_error = true;
+ break;
+ }
+ if (keyword == RID_SETTER)
+ {
+ if (property_setter_ident != NULL_TREE)
+ c_parser_error (parser, "the %<setter%> attribute may only be specified once");
+ else
+ property_setter_ident = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is_not (parser, CPP_COLON))
+ c_parser_error (parser, "setter name must terminate with %<:%>");
+ else
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ if (property_getter_ident != NULL_TREE)
+ c_parser_error (parser, "the %<getter%> attribute may only be specified once");
+ else
+ property_getter_ident = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ break;
+ default:
+ c_parser_error (parser, "unknown property attribute");
+ syntax_error = true;
+ break;
+ }
+
+ if (syntax_error)
+ break;
+
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ parser->objc_property_attr_context = false;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ /* ... and the property declaration(s). */
+ properties = c_parser_struct_declaration (parser);
+
+ if (properties == error_mark_node)
+ {
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+ parser->error = false;
+ return;
+ }
+
+ if (properties == NULL_TREE)
+ c_parser_error (parser, "expected identifier");
+ else
+ {
+ /* Comma-separated properties are chained together in
+ reverse order; add them one by one. */
+ properties = nreverse (properties);
+
+ for (; properties; properties = TREE_CHAIN (properties))
+ objc_add_property_declaration (loc, copy_node (properties),
+ property_readonly, property_readwrite,
+ property_assign, property_retain,
+ property_copy, property_nonatomic,
+ property_getter_ident, property_setter_ident);
+ }
+
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ parser->error = false;
+}
+
+/* Parse an Objective-C @synthesize declaration. The syntax is:
+
+ objc-synthesize-declaration:
+ @synthesize objc-synthesize-identifier-list ;
+
+ objc-synthesize-identifier-list:
+ objc-synthesize-identifier
+ objc-synthesize-identifier-list, objc-synthesize-identifier
+
+ objc-synthesize-identifier
+ identifier
+ identifier = identifier
+
+ For example:
+ @synthesize MyProperty;
+ @synthesize OneProperty, AnotherProperty=MyIvar, YetAnotherProperty;
+
+ PS: This function is identical to cp_parser_objc_at_synthesize_declaration
+ for C++. Keep them in sync.
+*/
+static void
+c_parser_objc_at_synthesize_declaration (c_parser *parser)
+{
+ tree list = NULL_TREE;
+ location_t loc;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_SYNTHESIZE));
+ loc = c_parser_peek_token (parser)->location;
+
+ c_parser_consume_token (parser);
+ while (true)
+ {
+ tree property, ivar;
+ 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);
+ /* Once we find the semicolon, we can resume normal parsing.
+ We have to reset parser->error manually because
+ c_parser_skip_until_found() won't reset it for us if the
+ next token is precisely a semicolon. */
+ parser->error = false;
+ return;
+ }
+ property = 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);
+ 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);
+ parser->error = false;
+ return;
+ }
+ ivar = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ else
+ ivar = NULL_TREE;
+ list = chainon (list, build_tree_list (ivar, property));
+ 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_add_synthesize_declaration (loc, list);
+}
+
+/* Parse an Objective-C @dynamic declaration. The syntax is:
+
+ objc-dynamic-declaration:
+ @dynamic identifier-list ;
+
+ For example:
+ @dynamic MyProperty;
+ @dynamic MyProperty, AnotherProperty;
+
+ PS: This function is identical to cp_parser_objc_at_dynamic_declaration
+ for C++. Keep them in sync.
+*/
+static void
+c_parser_objc_at_dynamic_declaration (c_parser *parser)
+{
+ tree list = NULL_TREE;
+ location_t loc;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_DYNAMIC));
+ loc = c_parser_peek_token (parser)->location;
+
+ c_parser_consume_token (parser);
+ while (true)
+ {
+ tree property;
+ 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);
+ parser->error = false;
+ return;
+ }
+ property = c_parser_peek_token (parser)->value;
+ list = chainon (list, build_tree_list (NULL_TREE, property));
+ 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_add_dynamic_declaration (loc, 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_TASKWAIT:
+ if (context != pragma_compound)
+ {
+ if (context == pragma_stmt)
+ c_parser_error (parser, "%<#pragma omp taskwait%> may only be "
+ "used in compound statements");
+ goto bad_stmt;
+ }
+ c_parser_omp_taskwait (parser);
+ return false;
+
+ case PRAGMA_OMP_TASKYIELD:
+ if (context != pragma_compound)
+ {
+ if (context == pragma_stmt)
+ c_parser_error (parser, "%<#pragma omp taskyield%> may only be "
+ "used in compound statements");
+ goto bad_stmt;
+ }
+ c_parser_omp_taskyield (parser);
+ return false;
+
+ case PRAGMA_OMP_THREADPRIVATE:
+ c_parser_omp_threadprivate (parser);
+ return false;
+
+ case PRAGMA_OMP_SECTION:
+ error_at (c_parser_peek_token (parser)->location,
+ "%<#pragma omp section%> may only be used in "
+ "%<#pragma omp sections%> construct");
+ c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+ return false;
+
+ case PRAGMA_GCC_PCH_PREPROCESS:
+ c_parser_error (parser, "%<#pragma GCC pch_preprocess%> must be first");
+ c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+ return false;
+
+ default:
+ if (id < PRAGMA_FIRST_EXTERNAL)
+ {
+ if (context == pragma_external)
+ {
+ bad_stmt:
+ c_parser_error (parser, "expected declaration specifiers");
+ c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+ return false;
+ }
+ c_parser_omp_construct (parser);
+ return true;
+ }
+ break;
+ }
+
+ c_parser_consume_pragma (parser);
+ c_invoke_pragma_handler (id);
+
+ /* Skip to EOL, but suppress any error message. Those will have been
+ generated by the handler routine through calling error, as opposed
+ to calling c_parser_error. */
+ parser->error = true;
+ c_parser_skip_to_pragma_eol (parser);
+
+ return false;
+}
+
+/* The interface the pragma parsers have to the lexer. */
+
+enum cpp_ttype
+pragma_lex (tree *value)
+{
+ c_token *tok = c_parser_peek_token (the_parser);
+ enum cpp_ttype ret = tok->type;
+
+ *value = tok->value;
+ if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF)
+ ret = CPP_EOF;
+ else
+ {
+ if (ret == CPP_KEYWORD)
+ ret = CPP_NAME;
+ c_parser_consume_token (the_parser);
+ }
+
+ return ret;
+}
+
+static void
+c_parser_pragma_pch_preprocess (c_parser *parser)
+{
+ tree name = NULL;
+
+ c_parser_consume_pragma (parser);
+ if (c_parser_next_token_is (parser, CPP_STRING))
+ {
+ name = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ else
+ c_parser_error (parser, "expected string literal");
+ c_parser_skip_to_pragma_eol (parser);
+
+ if (name)
+ c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name));
+}
+
+/* OpenMP 2.5 parsing routines. */
+
+/* Returns name of the next clause.
+ If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and
+ the token is not consumed. Otherwise appropriate pragma_omp_clause is
+ returned and the token is consumed. */
+
+static pragma_omp_clause
+c_parser_omp_clause_name (c_parser *parser)
+{
+ pragma_omp_clause result = PRAGMA_OMP_CLAUSE_NONE;
+
+ if (c_parser_next_token_is_keyword (parser, RID_IF))
+ result = PRAGMA_OMP_CLAUSE_IF;
+ else if (c_parser_next_token_is_keyword (parser, RID_DEFAULT))
+ result = PRAGMA_OMP_CLAUSE_DEFAULT;
+ else if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ switch (p[0])
+ {
+ case 'c':
+ if (!strcmp ("collapse", p))
+ result = PRAGMA_OMP_CLAUSE_COLLAPSE;
+ else if (!strcmp ("copyin", p))
+ result = PRAGMA_OMP_CLAUSE_COPYIN;
+ else if (!strcmp ("copyprivate", p))
+ result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
+ break;
+ case 'f':
+ if (!strcmp ("final", p))
+ result = PRAGMA_OMP_CLAUSE_FINAL;
+ else if (!strcmp ("firstprivate", p))
+ result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
+ break;
+ case 'l':
+ if (!strcmp ("lastprivate", p))
+ result = PRAGMA_OMP_CLAUSE_LASTPRIVATE;
+ break;
+ case 'm':
+ if (!strcmp ("mergeable", p))
+ result = PRAGMA_OMP_CLAUSE_MERGEABLE;
+ break;
+ case 'n':
+ if (!strcmp ("nowait", p))
+ result = PRAGMA_OMP_CLAUSE_NOWAIT;
+ else if (!strcmp ("num_threads", p))
+ result = PRAGMA_OMP_CLAUSE_NUM_THREADS;
+ break;
+ case 'o':
+ if (!strcmp ("ordered", p))
+ result = PRAGMA_OMP_CLAUSE_ORDERED;
+ break;
+ case 'p':
+ if (!strcmp ("private", p))
+ result = PRAGMA_OMP_CLAUSE_PRIVATE;
+ break;
+ case 'r':
+ if (!strcmp ("reduction", p))
+ result = PRAGMA_OMP_CLAUSE_REDUCTION;
+ break;
+ case 's':
+ if (!strcmp ("schedule", p))
+ result = PRAGMA_OMP_CLAUSE_SCHEDULE;
+ else if (!strcmp ("shared", p))
+ result = PRAGMA_OMP_CLAUSE_SHARED;
+ break;
+ case 'u':
+ if (!strcmp ("untied", p))
+ result = PRAGMA_OMP_CLAUSE_UNTIED;
+ break;
+ }
+ }
+
+ if (result != PRAGMA_OMP_CLAUSE_NONE)
+ c_parser_consume_token (parser);
+
+ return result;
+}
+
+/* Validate that a clause of the given type does not already exist. */
+
+static void
+check_no_duplicate_clause (tree clauses, enum omp_clause_code code,
+ const char *name)
+{
+ tree c;
+
+ for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == code)
+ {
+ location_t loc = OMP_CLAUSE_LOCATION (c);
+ error_at (loc, "too many %qs clauses", name);
+ break;
+ }
+}
+
+/* OpenMP 2.5:
+ variable-list:
+ identifier
+ variable-list , identifier
+
+ If KIND is nonzero, create the appropriate node and install the
+ decl in OMP_CLAUSE_DECL and add the node to the head of the list.
+ If KIND is nonzero, CLAUSE_LOC is the location of the clause.
+
+ If KIND is zero, create a TREE_LIST with the decl in TREE_PURPOSE;
+ return the list created. */
+
+static tree
+c_parser_omp_variable_list (c_parser *parser,
+ location_t clause_loc,
+ enum omp_clause_code kind,
+ tree list)
+{
+ if (c_parser_next_token_is_not (parser, CPP_NAME)
+ || c_parser_peek_token (parser)->id_kind != C_ID_ID)
+ c_parser_error (parser, "expected identifier");
+
+ while (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+ {
+ tree t = lookup_name (c_parser_peek_token (parser)->value);
+
+ if (t == NULL_TREE)
+ undeclared_variable (c_parser_peek_token (parser)->location,
+ c_parser_peek_token (parser)->value);
+ else if (t == error_mark_node)
+ ;
+ else if (kind != 0)
+ {
+ tree u = build_omp_clause (clause_loc, kind);
+ OMP_CLAUSE_DECL (u) = t;
+ OMP_CLAUSE_CHAIN (u) = list;
+ list = u;
+ }
+ else
+ list = tree_cons (t, NULL_TREE, list);
+
+ c_parser_consume_token (parser);
+
+ if (c_parser_next_token_is_not (parser, CPP_COMMA))
+ break;
+
+ c_parser_consume_token (parser);
+ }
+
+ return list;
+}
+
+/* Similarly, but expect leading and trailing parenthesis. This is a very
+ common case for omp clauses. */
+
+static tree
+c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind,
+ tree list)
+{
+ /* The clauses location. */
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ list = c_parser_omp_variable_list (parser, loc, kind, list);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ return list;
+}
+
+/* OpenMP 3.0:
+ collapse ( constant-expression ) */
+
+static tree
+c_parser_omp_clause_collapse (c_parser *parser, tree list)
+{
+ tree c, num = error_mark_node;
+ HOST_WIDE_INT n;
+ location_t loc;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_COLLAPSE, "collapse");
+
+ loc = c_parser_peek_token (parser)->location;
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ num = c_parser_expr_no_commas (parser, NULL).value;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ if (num == error_mark_node)
+ return list;
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (num))
+ || !host_integerp (num, 0)
+ || (n = tree_low_cst (num, 0)) <= 0
+ || (int) n != n)
+ {
+ error_at (loc,
+ "collapse argument needs positive constant integer expression");
+ return list;
+ }
+ c = build_omp_clause (loc, OMP_CLAUSE_COLLAPSE);
+ OMP_CLAUSE_COLLAPSE_EXPR (c) = num;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 2.5:
+ copyin ( variable-list ) */
+
+static tree
+c_parser_omp_clause_copyin (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYIN, list);
+}
+
+/* OpenMP 2.5:
+ copyprivate ( variable-list ) */
+
+static tree
+c_parser_omp_clause_copyprivate (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_COPYPRIVATE, list);
+}
+
+/* OpenMP 2.5:
+ default ( shared | none ) */
+
+static tree
+c_parser_omp_clause_default (c_parser *parser, tree list)
+{
+ enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree c;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ switch (p[0])
+ {
+ case 'n':
+ if (strcmp ("none", p) != 0)
+ goto invalid_kind;
+ kind = OMP_CLAUSE_DEFAULT_NONE;
+ break;
+
+ case 's':
+ if (strcmp ("shared", p) != 0)
+ goto invalid_kind;
+ kind = OMP_CLAUSE_DEFAULT_SHARED;
+ break;
+
+ default:
+ goto invalid_kind;
+ }
+
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ invalid_kind:
+ c_parser_error (parser, "expected %<none%> or %<shared%>");
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED)
+ return list;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_DEFAULT, "default");
+ c = build_omp_clause (loc, OMP_CLAUSE_DEFAULT);
+ OMP_CLAUSE_CHAIN (c) = list;
+ OMP_CLAUSE_DEFAULT_KIND (c) = kind;
+
+ return c;
+}
+
+/* OpenMP 2.5:
+ firstprivate ( variable-list ) */
+
+static tree
+c_parser_omp_clause_firstprivate (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FIRSTPRIVATE, list);
+}
+
+/* OpenMP 3.1:
+ final ( expression ) */
+
+static tree
+c_parser_omp_clause_final (c_parser *parser, tree list)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ tree t = c_parser_paren_condition (parser);
+ tree c;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_FINAL, "final");
+
+ c = build_omp_clause (loc, OMP_CLAUSE_FINAL);
+ OMP_CLAUSE_FINAL_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+ else
+ c_parser_error (parser, "expected %<(%>");
+
+ return list;
+}
+
+/* OpenMP 2.5:
+ if ( expression ) */
+
+static tree
+c_parser_omp_clause_if (c_parser *parser, tree list)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ tree t = c_parser_paren_condition (parser);
+ tree c;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if");
+
+ c = build_omp_clause (loc, OMP_CLAUSE_IF);
+ OMP_CLAUSE_IF_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+ else
+ c_parser_error (parser, "expected %<(%>");
+
+ return list;
+}
+
+/* OpenMP 2.5:
+ lastprivate ( variable-list ) */
+
+static tree
+c_parser_omp_clause_lastprivate (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LASTPRIVATE, list);
+}
+
+/* OpenMP 3.1:
+ mergeable */
+
+static tree
+c_parser_omp_clause_mergeable (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+ tree c;
+
+ /* FIXME: Should we allow duplicates? */
+ check_no_duplicate_clause (list, OMP_CLAUSE_MERGEABLE, "mergeable");
+
+ c = build_omp_clause (c_parser_peek_token (parser)->location,
+ OMP_CLAUSE_MERGEABLE);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* OpenMP 2.5:
+ nowait */
+
+static tree
+c_parser_omp_clause_nowait (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+ tree c;
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_NOWAIT, "nowait");
+
+ c = build_omp_clause (loc, OMP_CLAUSE_NOWAIT);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 2.5:
+ num_threads ( expression ) */
+
+static tree
+c_parser_omp_clause_num_threads (c_parser *parser, tree list)
+{
+ location_t num_threads_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ tree c, t = c_parser_expression (parser).value;
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ c_parser_error (parser, "expected integer expression");
+ return list;
+ }
+
+ /* Attempt to statically determine when the number isn't positive. */
+ c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, t,
+ build_int_cst (TREE_TYPE (t), 0));
+ if (CAN_HAVE_LOCATION_P (c))
+ SET_EXPR_LOCATION (c, expr_loc);
+ if (c == boolean_true_node)
+ {
+ warning_at (expr_loc, 0,
+ "%<num_threads%> value must be positive");
+ t = integer_one_node;
+ }
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_NUM_THREADS, "num_threads");
+
+ c = build_omp_clause (num_threads_loc, OMP_CLAUSE_NUM_THREADS);
+ OMP_CLAUSE_NUM_THREADS_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+/* OpenMP 2.5:
+ ordered */
+
+static tree
+c_parser_omp_clause_ordered (c_parser *parser, tree list)
+{
+ tree c;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered");
+
+ c = build_omp_clause (c_parser_peek_token (parser)->location,
+ OMP_CLAUSE_ORDERED);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* OpenMP 2.5:
+ private ( variable-list ) */
+
+static tree
+c_parser_omp_clause_private (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_PRIVATE, list);
+}
+
+/* OpenMP 2.5:
+ reduction ( reduction-operator : variable-list )
+
+ reduction-operator:
+ One of: + * - & ^ | && ||
+
+ OpenMP 3.1:
+
+ reduction-operator:
+ One of: + * - & ^ | && || max min */
+
+static tree
+c_parser_omp_clause_reduction (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ enum tree_code code;
+
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_PLUS:
+ code = PLUS_EXPR;
+ break;
+ case CPP_MULT:
+ code = MULT_EXPR;
+ break;
+ case CPP_MINUS:
+ code = MINUS_EXPR;
+ break;
+ case CPP_AND:
+ code = BIT_AND_EXPR;
+ break;
+ case CPP_XOR:
+ code = BIT_XOR_EXPR;
+ break;
+ case CPP_OR:
+ code = BIT_IOR_EXPR;
+ break;
+ case CPP_AND_AND:
+ code = TRUTH_ANDIF_EXPR;
+ break;
+ case CPP_OR_OR:
+ code = TRUTH_ORIF_EXPR;
+ break;
+ case CPP_NAME:
+ {
+ const char *p
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "min") == 0)
+ {
+ code = MIN_EXPR;
+ break;
+ }
+ if (strcmp (p, "max") == 0)
+ {
+ code = MAX_EXPR;
+ break;
+ }
+ }
+ /* FALLTHRU */
+ default:
+ c_parser_error (parser,
+ "expected %<+%>, %<*%>, %<-%>, %<&%>, "
+ "%<^%>, %<|%>, %<&&%>, %<||%>, %<min%> or %<max%>");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0);
+ return list;
+ }
+ c_parser_consume_token (parser);
+ if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ {
+ tree nl, c;
+
+ nl = c_parser_omp_variable_list (parser, clause_loc,
+ OMP_CLAUSE_REDUCTION, list);
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_REDUCTION_CODE (c) = code;
+
+ list = nl;
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ return list;
+}
+
+/* OpenMP 2.5:
+ schedule ( schedule-kind )
+ schedule ( schedule-kind , expression )
+
+ schedule-kind:
+ static | dynamic | guided | runtime | auto
+*/
+
+static tree
+c_parser_omp_clause_schedule (c_parser *parser, tree list)
+{
+ tree c, t;
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return list;
+
+ c = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE);
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ tree kind = c_parser_peek_token (parser)->value;
+ const char *p = IDENTIFIER_POINTER (kind);
+
+ switch (p[0])
+ {
+ case 'd':
+ if (strcmp ("dynamic", p) != 0)
+ goto invalid_kind;
+ OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC;
+ break;
+
+ case 'g':
+ if (strcmp ("guided", p) != 0)
+ goto invalid_kind;
+ OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED;
+ break;
+
+ case 'r':
+ if (strcmp ("runtime", p) != 0)
+ goto invalid_kind;
+ OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_RUNTIME;
+ break;
+
+ default:
+ goto invalid_kind;
+ }
+ }
+ else if (c_parser_next_token_is_keyword (parser, RID_STATIC))
+ OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC;
+ else if (c_parser_next_token_is_keyword (parser, RID_AUTO))
+ OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO;
+ else
+ goto invalid_kind;
+
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ location_t here;
+ c_parser_consume_token (parser);
+
+ here = c_parser_peek_token (parser)->location;
+ t = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+
+ if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME)
+ error_at (here, "schedule %<runtime%> does not take "
+ "a %<chunk_size%> parameter");
+ else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO)
+ error_at (here,
+ "schedule %<auto%> does not take "
+ "a %<chunk_size%> parameter");
+ else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE)
+ OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t;
+ else
+ c_parser_error (parser, "expected integer expression");
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ else
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<,%> or %<)%>");
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_SCHEDULE, "schedule");
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+
+ invalid_kind:
+ c_parser_error (parser, "invalid schedule kind");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0);
+ return list;
+}
+
+/* OpenMP 2.5:
+ shared ( variable-list ) */
+
+static tree
+c_parser_omp_clause_shared (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_SHARED, list);
+}
+
+/* OpenMP 3.0:
+ untied */
+
+static tree
+c_parser_omp_clause_untied (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+ tree c;
+
+ /* FIXME: Should we allow duplicates? */
+ check_no_duplicate_clause (list, OMP_CLAUSE_UNTIED, "untied");
+
+ c = build_omp_clause (c_parser_peek_token (parser)->location,
+ OMP_CLAUSE_UNTIED);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* Parse all OpenMP clauses. The set clauses allowed by the directive
+ is a bitmask in MASK. Return the list of clauses found; the result
+ of clause default goes in *pdefault. */
+
+static tree
+c_parser_omp_all_clauses (c_parser *parser, unsigned int mask,
+ const char *where)
+{
+ tree clauses = NULL;
+ bool first = true;
+
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ location_t here;
+ pragma_omp_clause c_kind;
+ const char *c_name;
+ tree prev = clauses;
+
+ if (!first && c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+
+ first = false;
+ here = c_parser_peek_token (parser)->location;
+ c_kind = c_parser_omp_clause_name (parser);
+
+ switch (c_kind)
+ {
+ case PRAGMA_OMP_CLAUSE_COLLAPSE:
+ clauses = c_parser_omp_clause_collapse (parser, clauses);
+ c_name = "collapse";
+ break;
+ case PRAGMA_OMP_CLAUSE_COPYIN:
+ clauses = c_parser_omp_clause_copyin (parser, clauses);
+ c_name = "copyin";
+ break;
+ case PRAGMA_OMP_CLAUSE_COPYPRIVATE:
+ clauses = c_parser_omp_clause_copyprivate (parser, clauses);
+ c_name = "copyprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEFAULT:
+ clauses = c_parser_omp_clause_default (parser, clauses);
+ c_name = "default";
+ break;
+ case PRAGMA_OMP_CLAUSE_FIRSTPRIVATE:
+ clauses = c_parser_omp_clause_firstprivate (parser, clauses);
+ c_name = "firstprivate";
+ break;
+ case PRAGMA_OMP_CLAUSE_FINAL:
+ clauses = c_parser_omp_clause_final (parser, clauses);
+ c_name = "final";
+ 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_MERGEABLE:
+ clauses = c_parser_omp_clause_mergeable (parser, clauses);
+ c_name = "mergeable";
+ break;
+ case PRAGMA_OMP_CLAUSE_NOWAIT:
+ clauses = c_parser_omp_clause_nowait (parser, clauses);
+ c_name = "nowait";
+ break;
+ case PRAGMA_OMP_CLAUSE_NUM_THREADS:
+ clauses = c_parser_omp_clause_num_threads (parser, clauses);
+ c_name = "num_threads";
+ break;
+ case PRAGMA_OMP_CLAUSE_ORDERED:
+ clauses = c_parser_omp_clause_ordered (parser, clauses);
+ c_name = "ordered";
+ break;
+ case PRAGMA_OMP_CLAUSE_PRIVATE:
+ clauses = c_parser_omp_clause_private (parser, clauses);
+ c_name = "private";
+ break;
+ case PRAGMA_OMP_CLAUSE_REDUCTION:
+ clauses = c_parser_omp_clause_reduction (parser, clauses);
+ c_name = "reduction";
+ break;
+ case PRAGMA_OMP_CLAUSE_SCHEDULE:
+ clauses = c_parser_omp_clause_schedule (parser, clauses);
+ c_name = "schedule";
+ break;
+ case PRAGMA_OMP_CLAUSE_SHARED:
+ clauses = c_parser_omp_clause_shared (parser, clauses);
+ c_name = "shared";
+ break;
+ case PRAGMA_OMP_CLAUSE_UNTIED:
+ clauses = c_parser_omp_clause_untied (parser, clauses);
+ c_name = "untied";
+ break;
+ default:
+ c_parser_error (parser, "expected %<#pragma omp%> clause");
+ goto saw_error;
+ }
+
+ if (((mask >> c_kind) & 1) == 0 && !parser->error)
+ {
+ /* Remove the invalid clause(s) from the list to avoid
+ confusing the rest of the compiler. */
+ clauses = prev;
+ error_at (here, "%qs is not valid for %qs", c_name, where);
+ }
+ }
+
+ saw_error:
+ c_parser_skip_to_pragma_eol (parser);
+
+ return c_finish_omp_clauses (clauses);
+}
+
+/* OpenMP 2.5:
+ structured-block:
+ statement
+
+ In practice, we're also interested in adding the statement to an
+ outer node. So it is convenient if we work around the fact that
+ c_parser_statement calls add_stmt. */
+
+static tree
+c_parser_omp_structured_block (c_parser *parser)
+{
+ tree stmt = push_stmt_list ();
+ c_parser_statement (parser);
+ return pop_stmt_list (stmt);
+}
+
+/* OpenMP 2.5:
+ # pragma omp atomic new-line
+ expression-stmt
+
+ expression-stmt:
+ x binop= expr | x++ | ++x | x-- | --x
+ binop:
+ +, *, -, /, &, ^, |, <<, >>
+
+ where x is an lvalue expression with scalar type.
+
+ OpenMP 3.1:
+ # pragma omp atomic new-line
+ update-stmt
+
+ # pragma omp atomic read new-line
+ read-stmt
+
+ # pragma omp atomic write new-line
+ write-stmt
+
+ # pragma omp atomic update new-line
+ update-stmt
+
+ # pragma omp atomic capture new-line
+ capture-stmt
+
+ # pragma omp atomic capture new-line
+ capture-block
+
+ read-stmt:
+ v = x
+ write-stmt:
+ x = expr
+ update-stmt:
+ expression-stmt | x = x binop expr
+ capture-stmt:
+ v = x binop= expr | v = x++ | v = ++x | v = x-- | v = --x
+ capture-block:
+ { v = x; update-stmt; } | { update-stmt; v = x; }
+
+ where x and v are lvalue expressions with scalar type.
+
+ LOC is the location of the #pragma token. */
+
+static void
+c_parser_omp_atomic (location_t loc, c_parser *parser)
+{
+ tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE;
+ tree lhs1 = NULL_TREE, rhs1 = NULL_TREE;
+ tree stmt, orig_lhs;
+ enum tree_code code = OMP_ATOMIC, opcode = NOP_EXPR;
+ struct c_expr rhs_expr;
+ bool structured_block = false;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (!strcmp (p, "read"))
+ code = OMP_ATOMIC_READ;
+ else if (!strcmp (p, "write"))
+ code = NOP_EXPR;
+ else if (!strcmp (p, "update"))
+ code = OMP_ATOMIC;
+ else if (!strcmp (p, "capture"))
+ code = OMP_ATOMIC_CAPTURE_NEW;
+ else
+ p = NULL;
+ if (p)
+ c_parser_consume_token (parser);
+ }
+ c_parser_skip_to_pragma_eol (parser);
+
+ switch (code)
+ {
+ case OMP_ATOMIC_READ:
+ case NOP_EXPR: /* atomic write */
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ loc = c_parser_peek_token (parser)->location;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ if (code == NOP_EXPR)
+ lhs = c_parser_expression (parser).value;
+ else
+ lhs = c_parser_unary_expression (parser).value;
+ lhs = c_fully_fold (lhs, false, NULL);
+ if (lhs == error_mark_node)
+ goto saw_error;
+ if (code == NOP_EXPR)
+ {
+ /* atomic write is represented by OMP_ATOMIC with NOP_EXPR
+ opcode. */
+ code = OMP_ATOMIC;
+ rhs = lhs;
+ lhs = v;
+ v = NULL_TREE;
+ }
+ goto done;
+ case OMP_ATOMIC_CAPTURE_NEW:
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ c_parser_consume_token (parser);
+ structured_block = true;
+ }
+ else
+ {
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* For structured_block case we don't know yet whether
+ old or new x should be captured. */
+restart:
+ lhs = c_parser_unary_expression (parser).value;
+ lhs = c_fully_fold (lhs, false, NULL);
+ orig_lhs = lhs;
+ switch (TREE_CODE (lhs))
+ {
+ case ERROR_MARK:
+ saw_error:
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ if (structured_block)
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ c_parser_consume_token (parser);
+ else if (code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ c_parser_consume_token (parser);
+ }
+ }
+ return;
+
+ case POSTINCREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREINCREMENT_EXPR:
+ lhs = TREE_OPERAND (lhs, 0);
+ opcode = PLUS_EXPR;
+ rhs = integer_one_node;
+ break;
+
+ case POSTDECREMENT_EXPR:
+ if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ /* FALLTHROUGH */
+ case PREDECREMENT_EXPR:
+ lhs = TREE_OPERAND (lhs, 0);
+ opcode = MINUS_EXPR;
+ rhs = integer_one_node;
+ break;
+
+ case COMPOUND_EXPR:
+ if (TREE_CODE (TREE_OPERAND (lhs, 0)) == SAVE_EXPR
+ && TREE_CODE (TREE_OPERAND (lhs, 1)) == COMPOUND_EXPR
+ && TREE_CODE (TREE_OPERAND (TREE_OPERAND (lhs, 1), 0)) == MODIFY_EXPR
+ && TREE_OPERAND (TREE_OPERAND (lhs, 1), 1) == TREE_OPERAND (lhs, 0)
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (TREE_OPERAND
+ (TREE_OPERAND (lhs, 1), 0), 0)))
+ == BOOLEAN_TYPE)
+ /* Undo effects of boolean_increment for post {in,de}crement. */
+ lhs = TREE_OPERAND (TREE_OPERAND (lhs, 1), 0);
+ /* FALLTHRU */
+ case MODIFY_EXPR:
+ if (TREE_CODE (lhs) == MODIFY_EXPR
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (lhs, 0))) == BOOLEAN_TYPE)
+ {
+ /* Undo effects of boolean_increment. */
+ if (integer_onep (TREE_OPERAND (lhs, 1)))
+ {
+ /* This is pre or post increment. */
+ rhs = TREE_OPERAND (lhs, 1);
+ lhs = TREE_OPERAND (lhs, 0);
+ opcode = NOP_EXPR;
+ if (code == OMP_ATOMIC_CAPTURE_NEW
+ && !structured_block
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ break;
+ }
+ if (TREE_CODE (TREE_OPERAND (lhs, 1)) == TRUTH_NOT_EXPR
+ && TREE_OPERAND (lhs, 0)
+ == TREE_OPERAND (TREE_OPERAND (lhs, 1), 0))
+ {
+ /* This is pre or post decrement. */
+ rhs = TREE_OPERAND (lhs, 1);
+ lhs = TREE_OPERAND (lhs, 0);
+ opcode = NOP_EXPR;
+ if (code == OMP_ATOMIC_CAPTURE_NEW
+ && !structured_block
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ break;
+ }
+ }
+ /* FALLTHRU */
+ default:
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_MULT_EQ:
+ opcode = MULT_EXPR;
+ break;
+ case CPP_DIV_EQ:
+ opcode = TRUNC_DIV_EXPR;
+ break;
+ case CPP_PLUS_EQ:
+ opcode = PLUS_EXPR;
+ break;
+ case CPP_MINUS_EQ:
+ opcode = MINUS_EXPR;
+ break;
+ case CPP_LSHIFT_EQ:
+ opcode = LSHIFT_EXPR;
+ break;
+ case CPP_RSHIFT_EQ:
+ opcode = RSHIFT_EXPR;
+ break;
+ case CPP_AND_EQ:
+ opcode = BIT_AND_EXPR;
+ break;
+ case CPP_OR_EQ:
+ opcode = BIT_IOR_EXPR;
+ break;
+ case CPP_XOR_EQ:
+ opcode = BIT_XOR_EXPR;
+ break;
+ case CPP_EQ:
+ if (structured_block || code == OMP_ATOMIC)
+ {
+ location_t aloc = c_parser_peek_token (parser)->location;
+ location_t rhs_loc;
+ enum c_parser_prec oprec = PREC_NONE;
+
+ c_parser_consume_token (parser);
+ rhs1 = c_parser_unary_expression (parser).value;
+ rhs1 = c_fully_fold (rhs1, false, NULL);
+ if (rhs1 == error_mark_node)
+ goto saw_error;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_SEMICOLON:
+ if (code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ v = lhs;
+ lhs = NULL_TREE;
+ lhs1 = rhs1;
+ rhs1 = NULL_TREE;
+ c_parser_consume_token (parser);
+ goto restart;
+ }
+ c_parser_error (parser,
+ "invalid form of %<#pragma omp atomic%>");
+ goto saw_error;
+ case CPP_MULT:
+ opcode = MULT_EXPR;
+ oprec = PREC_MULT;
+ break;
+ case CPP_DIV:
+ opcode = TRUNC_DIV_EXPR;
+ oprec = PREC_MULT;
+ break;
+ case CPP_PLUS:
+ opcode = PLUS_EXPR;
+ oprec = PREC_ADD;
+ break;
+ case CPP_MINUS:
+ opcode = MINUS_EXPR;
+ oprec = PREC_ADD;
+ break;
+ case CPP_LSHIFT:
+ opcode = LSHIFT_EXPR;
+ oprec = PREC_SHIFT;
+ break;
+ case CPP_RSHIFT:
+ opcode = RSHIFT_EXPR;
+ oprec = PREC_SHIFT;
+ break;
+ case CPP_AND:
+ opcode = BIT_AND_EXPR;
+ oprec = PREC_BITAND;
+ break;
+ case CPP_OR:
+ opcode = BIT_IOR_EXPR;
+ oprec = PREC_BITOR;
+ break;
+ case CPP_XOR:
+ opcode = BIT_XOR_EXPR;
+ oprec = PREC_BITXOR;
+ break;
+ default:
+ c_parser_error (parser,
+ "invalid operator for %<#pragma omp atomic%>");
+ goto saw_error;
+ }
+ loc = aloc;
+ c_parser_consume_token (parser);
+ rhs_loc = c_parser_peek_token (parser)->location;
+ if (commutative_tree_code (opcode))
+ oprec = (enum c_parser_prec) (oprec - 1);
+ rhs_expr = c_parser_binary_expression (parser, NULL, oprec);
+ rhs_expr = default_function_array_read_conversion (rhs_loc,
+ rhs_expr);
+ rhs = rhs_expr.value;
+ rhs = c_fully_fold (rhs, false, NULL);
+ goto stmt_done;
+ }
+ /* FALLTHROUGH */
+ default:
+ c_parser_error (parser,
+ "invalid operator for %<#pragma omp atomic%>");
+ goto saw_error;
+ }
+
+ /* Arrange to pass the location of the assignment operator to
+ c_finish_omp_atomic. */
+ loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ {
+ location_t rhs_loc = c_parser_peek_token (parser)->location;
+ rhs_expr = c_parser_expression (parser);
+ rhs_expr = default_function_array_read_conversion (rhs_loc, rhs_expr);
+ }
+ rhs = rhs_expr.value;
+ rhs = c_fully_fold (rhs, false, NULL);
+ break;
+ }
+stmt_done:
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ goto saw_error;
+ v = c_parser_unary_expression (parser).value;
+ v = c_fully_fold (v, false, NULL);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ lhs1 = c_parser_unary_expression (parser).value;
+ lhs1 = c_fully_fold (lhs1, false, NULL);
+ if (lhs1 == error_mark_node)
+ goto saw_error;
+ }
+ if (structured_block)
+ {
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+ }
+done:
+ stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1);
+ if (stmt != error_mark_node)
+ add_stmt (stmt);
+
+ if (!structured_block)
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+}
+
+
+/* OpenMP 2.5:
+ # pragma omp barrier new-line
+*/
+
+static void
+c_parser_omp_barrier (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+
+ c_finish_omp_barrier (loc);
+}
+
+/* OpenMP 2.5:
+ # pragma omp critical [(name)] new-line
+ structured-block
+
+ LOC is the location of the #pragma itself. */
+
+static tree
+c_parser_omp_critical (location_t loc, c_parser *parser)
+{
+ tree stmt, name = NULL;
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ name = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ }
+ else
+ c_parser_error (parser, "expected identifier");
+ }
+ else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ c_parser_error (parser, "expected %<(%> or end of line");
+ c_parser_skip_to_pragma_eol (parser);
+
+ stmt = c_parser_omp_structured_block (parser);
+ return c_finish_omp_critical (loc, stmt, name);
+}
+
+/* OpenMP 2.5:
+ # pragma omp flush flush-vars[opt] new-line
+
+ flush-vars:
+ ( variable-list ) */
+
+static void
+c_parser_omp_flush (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
+ else if (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ c_parser_error (parser, "expected %<(%> or end of line");
+ c_parser_skip_to_pragma_eol (parser);
+
+ c_finish_omp_flush (loc);
+}
+
+/* Parse the restricted form of the for statement allowed by OpenMP.
+ The real trick here is to determine the loop control variable early
+ so that we can push a new decl if necessary to make it private.
+ LOC is the location of the OMP in "#pragma omp". */
+
+static tree
+c_parser_omp_for_loop (location_t loc,
+ c_parser *parser, tree clauses, tree *par_clauses)
+{
+ tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
+ tree declv, condv, incrv, initv, ret = NULL;
+ bool fail = false, open_brace_parsed = false;
+ int i, collapse = 1, nbraces = 0;
+ location_t for_loc;
+ vec<tree, va_gc> *for_block = make_tree_vector ();
+
+ for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
+ if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
+ collapse = tree_low_cst (OMP_CLAUSE_COLLAPSE_EXPR (cl), 0);
+
+ gcc_assert (collapse >= 1);
+
+ declv = make_tree_vec (collapse);
+ initv = make_tree_vec (collapse);
+ condv = make_tree_vec (collapse);
+ incrv = make_tree_vec (collapse);
+
+ if (!c_parser_next_token_is_keyword (parser, RID_FOR))
+ {
+ c_parser_error (parser, "for statement expected");
+ return NULL;
+ }
+ for_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+
+ for (i = 0; i < collapse; i++)
+ {
+ int bracecount = 0;
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ goto pop_scopes;
+
+ /* Parse the initialization declaration or expression. */
+ if (c_parser_next_tokens_start_declaration (parser))
+ {
+ if (i > 0)
+ vec_safe_push (for_block, c_begin_compound_stmt (true));
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true, NULL);
+ decl = check_for_loop_decls (for_loc, flag_isoc99);
+ if (decl == NULL)
+ goto error_init;
+ if (DECL_INITIAL (decl) == error_mark_node)
+ decl = error_mark_node;
+ init = decl;
+ }
+ else if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
+ {
+ struct c_expr decl_exp;
+ struct c_expr init_exp;
+ location_t init_loc;
+
+ decl_exp = c_parser_postfix_expression (parser);
+ decl = decl_exp.value;
+
+ c_parser_require (parser, CPP_EQ, "expected %<=%>");
+
+ init_loc = c_parser_peek_token (parser)->location;
+ init_exp = c_parser_expr_no_commas (parser, NULL);
+ init_exp = default_function_array_read_conversion (init_loc,
+ init_exp);
+ init = build_modify_expr (init_loc, decl, decl_exp.original_type,
+ NOP_EXPR, init_loc, init_exp.value,
+ init_exp.original_type);
+ init = c_process_expr_stmt (init_loc, init);
+
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ else
+ {
+ error_init:
+ c_parser_error (parser,
+ "expected iteration declaration or initialization");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ fail = true;
+ goto parse_next;
+ }
+
+ /* Parse the loop condition. */
+ cond = NULL_TREE;
+ if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+ {
+ location_t cond_loc = c_parser_peek_token (parser)->location;
+ struct c_expr cond_expr = c_parser_binary_expression (parser, NULL,
+ PREC_NONE);
+
+ cond = cond_expr.value;
+ cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
+ cond = c_fully_fold (cond, false, NULL);
+ switch (cond_expr.original_code)
+ {
+ case GT_EXPR:
+ case GE_EXPR:
+ case LT_EXPR:
+ case LE_EXPR:
+ break;
+ default:
+ /* Can't be cond = error_mark_node, because we want to preserve
+ the location until c_finish_omp_for. */
+ cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node);
+ break;
+ }
+ protected_set_expr_location (cond, cond_loc);
+ }
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+
+ /* Parse the increment expression. */
+ incr = NULL_TREE;
+ if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+ {
+ location_t incr_loc = c_parser_peek_token (parser)->location;
+
+ incr = c_process_expr_stmt (incr_loc,
+ c_parser_expression (parser).value);
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (decl == NULL || decl == error_mark_node || init == error_mark_node)
+ fail = true;
+ else
+ {
+ TREE_VEC_ELT (declv, i) = decl;
+ TREE_VEC_ELT (initv, i) = init;
+ TREE_VEC_ELT (condv, i) = cond;
+ TREE_VEC_ELT (incrv, i) = incr;
+ }
+
+ parse_next:
+ if (i == collapse - 1)
+ break;
+
+ /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed
+ in between the collapsed for loops to be still considered perfectly
+ nested. Hopefully the final version clarifies this.
+ For now handle (multiple) {'s and empty statements. */
+ do
+ {
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ {
+ c_parser_consume_token (parser);
+ break;
+ }
+ else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ c_parser_consume_token (parser);
+ bracecount++;
+ }
+ else if (bracecount
+ && c_parser_next_token_is (parser, CPP_SEMICOLON))
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_error (parser, "not enough perfectly nested loops");
+ if (bracecount)
+ {
+ open_brace_parsed = true;
+ bracecount--;
+ }
+ fail = true;
+ collapse = 0;
+ break;
+ }
+ }
+ while (1);
+
+ nbraces += bracecount;
+ }
+
+ save_break = c_break_label;
+ c_break_label = size_one_node;
+ save_cont = c_cont_label;
+ c_cont_label = NULL_TREE;
+ body = push_stmt_list ();
+
+ if (open_brace_parsed)
+ {
+ location_t here = c_parser_peek_token (parser)->location;
+ stmt = c_begin_compound_stmt (true);
+ c_parser_compound_statement_nostart (parser);
+ add_stmt (c_end_compound_stmt (here, stmt, true));
+ }
+ else
+ add_stmt (c_parser_c99_block_statement (parser));
+ if (c_cont_label)
+ {
+ tree t = build1 (LABEL_EXPR, void_type_node, c_cont_label);
+ SET_EXPR_LOCATION (t, loc);
+ add_stmt (t);
+ }
+
+ body = pop_stmt_list (body);
+ c_break_label = save_break;
+ c_cont_label = save_cont;
+
+ while (nbraces)
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ {
+ c_parser_consume_token (parser);
+ nbraces--;
+ }
+ else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_error (parser, "collapsed loops not perfectly nested");
+ while (nbraces)
+ {
+ location_t here = c_parser_peek_token (parser)->location;
+ stmt = c_begin_compound_stmt (true);
+ add_stmt (body);
+ c_parser_compound_statement_nostart (parser);
+ body = c_end_compound_stmt (here, stmt, true);
+ nbraces--;
+ }
+ goto pop_scopes;
+ }
+ }
+
+ /* Only bother calling c_finish_omp_for if we haven't already generated
+ an error from the initialization parsing. */
+ if (!fail)
+ {
+ stmt = c_finish_omp_for (loc, declv, initv, condv, incrv, body, NULL);
+ if (stmt)
+ {
+ if (par_clauses != NULL)
+ {
+ tree *c;
+ for (c = par_clauses; *c ; )
+ if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE
+ && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE)
+ c = &OMP_CLAUSE_CHAIN (*c);
+ else
+ {
+ for (i = 0; i < collapse; i++)
+ if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c))
+ break;
+ if (i == collapse)
+ c = &OMP_CLAUSE_CHAIN (*c);
+ else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE)
+ {
+ error_at (loc,
+ "iteration variable %qD should not be firstprivate",
+ OMP_CLAUSE_DECL (*c));
+ *c = OMP_CLAUSE_CHAIN (*c);
+ }
+ else
+ {
+ /* Copy lastprivate (decl) clause to OMP_FOR_CLAUSES,
+ change it to shared (decl) in
+ OMP_PARALLEL_CLAUSES. */
+ tree l = build_omp_clause (OMP_CLAUSE_LOCATION (*c),
+ OMP_CLAUSE_LASTPRIVATE);
+ OMP_CLAUSE_DECL (l) = OMP_CLAUSE_DECL (*c);
+ OMP_CLAUSE_CHAIN (l) = clauses;
+ clauses = l;
+ OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED);
+ }
+ }
+ }
+ OMP_FOR_CLAUSES (stmt) = clauses;
+ }
+ ret = stmt;
+ }
+pop_scopes:
+ while (!for_block->is_empty ())
+ {
+ /* FIXME diagnostics: LOC below should be the actual location of
+ this particular for block. We need to build a list of
+ locations to go along with FOR_BLOCK. */
+ stmt = c_end_compound_stmt (loc, for_block->pop (), true);
+ add_stmt (stmt);
+ }
+ release_tree_vector (for_block);
+ return ret;
+}
+
+/* OpenMP 2.5:
+ #pragma omp for for-clause[optseq] new-line
+ for-loop
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OMP_FOR_CLAUSE_MASK \
+ ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (1u << PRAGMA_OMP_CLAUSE_ORDERED) \
+ | (1u << PRAGMA_OMP_CLAUSE_SCHEDULE) \
+ | (1u << PRAGMA_OMP_CLAUSE_COLLAPSE) \
+ | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_for (location_t loc, c_parser *parser)
+{
+ tree block, clauses, ret;
+
+ clauses = c_parser_omp_all_clauses (parser, OMP_FOR_CLAUSE_MASK,
+ "#pragma omp for");
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, clauses, NULL);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
+/* OpenMP 2.5:
+ # pragma omp master new-line
+ structured-block
+
+ LOC is the location of the #pragma token.
+*/
+
+static tree
+c_parser_omp_master (location_t loc, c_parser *parser)
+{
+ c_parser_skip_to_pragma_eol (parser);
+ return c_finish_omp_master (loc, c_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 2.5:
+ # pragma omp ordered new-line
+ structured-block
+
+ LOC is the location of the #pragma itself.
+*/
+
+static tree
+c_parser_omp_ordered (location_t loc, c_parser *parser)
+{
+ c_parser_skip_to_pragma_eol (parser);
+ return c_finish_omp_ordered (loc, c_parser_omp_structured_block (parser));
+}
+
+/* OpenMP 2.5:
+
+ section-scope:
+ { section-sequence }
+
+ section-sequence:
+ section-directive[opt] structured-block
+ section-sequence section-directive structured-block
+
+ SECTIONS_LOC is the location of the #pragma omp sections. */
+
+static tree
+c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser)
+{
+ tree stmt, substmt;
+ bool error_suppress = false;
+ location_t loc;
+
+ loc = c_parser_peek_token (parser)->location;
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ {
+ /* Avoid skipping until the end of the block. */
+ parser->error = false;
+ return NULL_TREE;
+ }
+
+ stmt = push_stmt_list ();
+
+ if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION)
+ {
+ substmt = push_stmt_list ();
+
+ while (1)
+ {
+ c_parser_statement (parser);
+
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
+ break;
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ break;
+ if (c_parser_next_token_is (parser, CPP_EOF))
+ break;
+ }
+
+ substmt = pop_stmt_list (substmt);
+ substmt = build1 (OMP_SECTION, void_type_node, substmt);
+ SET_EXPR_LOCATION (substmt, loc);
+ add_stmt (substmt);
+ }
+
+ while (1)
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ break;
+ if (c_parser_next_token_is (parser, CPP_EOF))
+ break;
+
+ loc = c_parser_peek_token (parser)->location;
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
+ {
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+ error_suppress = false;
+ }
+ else if (!error_suppress)
+ {
+ error_at (loc, "expected %<#pragma omp section%> or %<}%>");
+ error_suppress = true;
+ }
+
+ substmt = c_parser_omp_structured_block (parser);
+ substmt = build1 (OMP_SECTION, void_type_node, substmt);
+ SET_EXPR_LOCATION (substmt, loc);
+ add_stmt (substmt);
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE,
+ "expected %<#pragma omp section%> or %<}%>");
+
+ substmt = pop_stmt_list (stmt);
+
+ stmt = make_node (OMP_SECTIONS);
+ SET_EXPR_LOCATION (stmt, sections_loc);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_SECTIONS_BODY (stmt) = substmt;
+
+ return add_stmt (stmt);
+}
+
+/* OpenMP 2.5:
+ # pragma omp sections sections-clause[optseq] newline
+ sections-scope
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OMP_SECTIONS_CLAUSE_MASK \
+ ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_sections (location_t loc, c_parser *parser)
+{
+ tree block, clauses, ret;
+
+ clauses = c_parser_omp_all_clauses (parser, OMP_SECTIONS_CLAUSE_MASK,
+ "#pragma omp sections");
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_sections_scope (loc, parser);
+ if (ret)
+ OMP_SECTIONS_CLAUSES (ret) = clauses;
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
+/* OpenMP 2.5:
+ # pragma parallel parallel-clause new-line
+ # pragma parallel for parallel-for-clause new-line
+ # pragma parallel sections parallel-sections-clause new-line
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OMP_PARALLEL_CLAUSE_MASK \
+ ( (1u << PRAGMA_OMP_CLAUSE_IF) \
+ | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \
+ | (1u << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (1u << PRAGMA_OMP_CLAUSE_COPYIN) \
+ | (1u << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (1u << PRAGMA_OMP_CLAUSE_NUM_THREADS))
+
+static tree
+c_parser_omp_parallel (location_t loc, c_parser *parser)
+{
+ enum pragma_kind p_kind = PRAGMA_OMP_PARALLEL;
+ const char *p_name = "#pragma omp parallel";
+ tree stmt, clauses, par_clause, ws_clause, block;
+ unsigned int mask = OMP_PARALLEL_CLAUSE_MASK;
+
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ {
+ c_parser_consume_token (parser);
+ p_kind = PRAGMA_OMP_PARALLEL_FOR;
+ p_name = "#pragma omp parallel for";
+ mask |= OMP_FOR_CLAUSE_MASK;
+ mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+ }
+ else if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "sections") == 0)
+ {
+ c_parser_consume_token (parser);
+ p_kind = PRAGMA_OMP_PARALLEL_SECTIONS;
+ p_name = "#pragma omp parallel sections";
+ mask |= OMP_SECTIONS_CLAUSE_MASK;
+ mask &= ~(1u << PRAGMA_OMP_CLAUSE_NOWAIT);
+ }
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name);
+
+ switch (p_kind)
+ {
+ case PRAGMA_OMP_PARALLEL:
+ block = c_begin_omp_parallel ();
+ c_parser_statement (parser);
+ stmt = c_finish_omp_parallel (loc, clauses, block);
+ break;
+
+ case PRAGMA_OMP_PARALLEL_FOR:
+ block = c_begin_omp_parallel ();
+ c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
+ c_parser_omp_for_loop (loc, parser, ws_clause, &par_clause);
+ stmt = c_finish_omp_parallel (loc, par_clause, block);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ break;
+
+ case PRAGMA_OMP_PARALLEL_SECTIONS:
+ block = c_begin_omp_parallel ();
+ c_split_parallel_clauses (loc, clauses, &par_clause, &ws_clause);
+ stmt = c_parser_omp_sections_scope (loc, parser);
+ if (stmt)
+ OMP_SECTIONS_CLAUSES (stmt) = ws_clause;
+ stmt = c_finish_omp_parallel (loc, par_clause, block);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return stmt;
+}
+
+/* OpenMP 2.5:
+ # pragma omp single single-clause[optseq] new-line
+ structured-block
+
+ LOC is the location of the #pragma.
+*/
+
+#define OMP_SINGLE_CLAUSE_MASK \
+ ( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_single (location_t loc, c_parser *parser)
+{
+ tree stmt = make_node (OMP_SINGLE);
+ SET_EXPR_LOCATION (stmt, loc);
+ TREE_TYPE (stmt) = void_type_node;
+
+ OMP_SINGLE_CLAUSES (stmt)
+ = c_parser_omp_all_clauses (parser, OMP_SINGLE_CLAUSE_MASK,
+ "#pragma omp single");
+ OMP_SINGLE_BODY (stmt) = c_parser_omp_structured_block (parser);
+
+ return add_stmt (stmt);
+}
+
+/* OpenMP 3.0:
+ # pragma omp task task-clause[optseq] new-line
+
+ LOC is the location of the #pragma.
+*/
+
+#define OMP_TASK_CLAUSE_MASK \
+ ( (1u << PRAGMA_OMP_CLAUSE_IF) \
+ | (1u << PRAGMA_OMP_CLAUSE_UNTIED) \
+ | (1u << PRAGMA_OMP_CLAUSE_DEFAULT) \
+ | (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (1u << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (1u << PRAGMA_OMP_CLAUSE_FINAL) \
+ | (1u << PRAGMA_OMP_CLAUSE_MERGEABLE))
+
+static tree
+c_parser_omp_task (location_t loc, c_parser *parser)
+{
+ tree clauses, block;
+
+ clauses = c_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK,
+ "#pragma omp task");
+
+ block = c_begin_omp_task ();
+ c_parser_statement (parser);
+ return c_finish_omp_task (loc, clauses, block);
+}
+
+/* OpenMP 3.0:
+ # pragma omp taskwait new-line
+*/
+
+static void
+c_parser_omp_taskwait (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+
+ c_finish_omp_taskwait (loc);
+}
+
+/* OpenMP 3.1:
+ # pragma omp taskyield new-line
+*/
+
+static void
+c_parser_omp_taskyield (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+
+ c_finish_omp_taskyield (loc);
+}
+
+/* Main entry point to parsing most OpenMP pragmas. */
+
+static void
+c_parser_omp_construct (c_parser *parser)
+{
+ enum pragma_kind p_kind;
+ location_t loc;
+ tree stmt;
+
+ loc = c_parser_peek_token (parser)->location;
+ p_kind = c_parser_peek_token (parser)->pragma_kind;
+ c_parser_consume_pragma (parser);
+
+ switch (p_kind)
+ {
+ case PRAGMA_OMP_ATOMIC:
+ c_parser_omp_atomic (loc, parser);
+ return;
+ case PRAGMA_OMP_CRITICAL:
+ stmt = c_parser_omp_critical (loc, parser);
+ break;
+ case PRAGMA_OMP_FOR:
+ stmt = c_parser_omp_for (loc, parser);
+ break;
+ case PRAGMA_OMP_MASTER:
+ stmt = c_parser_omp_master (loc, parser);
+ break;
+ case PRAGMA_OMP_ORDERED:
+ stmt = c_parser_omp_ordered (loc, parser);
+ break;
+ case PRAGMA_OMP_PARALLEL:
+ stmt = c_parser_omp_parallel (loc, parser);
+ break;
+ case PRAGMA_OMP_SECTIONS:
+ stmt = c_parser_omp_sections (loc, parser);
+ break;
+ case PRAGMA_OMP_SINGLE:
+ stmt = c_parser_omp_single (loc, parser);
+ break;
+ case PRAGMA_OMP_TASK:
+ stmt = c_parser_omp_task (loc, parser);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (stmt)
+ gcc_assert (EXPR_LOCATION (stmt) != UNKNOWN_LOCATION);
+}
+
+
+/* OpenMP 2.5:
+ # pragma omp threadprivate (variable-list) */
+
+static void
+c_parser_omp_threadprivate (c_parser *parser)
+{
+ tree vars, t;
+ location_t loc;
+
+ c_parser_consume_pragma (parser);
+ loc = c_parser_peek_token (parser)->location;
+ vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
+
+ /* Mark every variable in VARS to be assigned thread local storage. */
+ for (t = vars; t; t = TREE_CHAIN (t))
+ {
+ tree v = TREE_PURPOSE (t);
+
+ /* FIXME diagnostics: Ideally we should keep individual
+ locations for all the variables in the var list to make the
+ following errors more precise. Perhaps
+ c_parser_omp_var_list_parens() should construct a list of
+ locations to go along with the var list. */
+
+ /* If V had already been marked threadprivate, it doesn't matter
+ whether it had been used prior to this point. */
+ if (TREE_CODE (v) != VAR_DECL)
+ error_at (loc, "%qD is not a variable", v);
+ else if (TREE_USED (v) && !C_DECL_THREADPRIVATE_P (v))
+ error_at (loc, "%qE declared %<threadprivate%> after first use", v);
+ else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v))
+ error_at (loc, "automatic variable %qE cannot be %<threadprivate%>", v);
+ else if (TREE_TYPE (v) == error_mark_node)
+ ;
+ else if (! COMPLETE_TYPE_P (TREE_TYPE (v)))
+ error_at (loc, "%<threadprivate%> %qE has incomplete type", v);
+ else
+ {
+ if (! DECL_THREAD_LOCAL_P (v))
+ {
+ DECL_TLS_MODEL (v) = decl_default_tls_model (v);
+ /* If rtl has been already set for this var, call
+ make_decl_rtl once again, so that encode_section_info
+ has a chance to look at the new decl flags. */
+ if (DECL_RTL_SET_P (v))
+ make_decl_rtl (v);
+ }
+ C_DECL_THREADPRIVATE_P (v) = 1;
+ }
+ }
+
+ c_parser_skip_to_pragma_eol (parser);
+}
+
+/* Parse a transaction attribute (GCC Extension).
+
+ transaction-attribute:
+ attributes
+ [ [ any-word ] ]
+
+ The transactional memory language description is written for C++,
+ and uses the C++0x attribute syntax. For compatibility, allow the
+ bracket style for transactions in C as well. */
+
+static tree
+c_parser_transaction_attributes (c_parser *parser)
+{
+ tree attr_name, attr = NULL;
+
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ return c_parser_attributes (parser);
+
+ if (!c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ return NULL_TREE;
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>"))
+ goto error1;
+
+ attr_name = c_parser_attribute_any_word (parser);
+ if (attr_name)
+ {
+ c_parser_consume_token (parser);
+ attr = build_tree_list (attr_name, NULL_TREE);
+ }
+ else
+ c_parser_error (parser, "expected identifier");
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>");
+ error1:
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>");
+ return attr;
+}
+
+/* Parse a __transaction_atomic or __transaction_relaxed statement
+ (GCC Extension).
+
+ transaction-statement:
+ __transaction_atomic transaction-attribute[opt] compound-statement
+ __transaction_relaxed compound-statement
+
+ Note that the only valid attribute is: "outer".
+*/
+
+static tree
+c_parser_transaction (c_parser *parser, enum rid keyword)
+{
+ unsigned int old_in = parser->in_transaction;
+ unsigned int this_in = 1, new_in;
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree stmt, attrs;
+
+ gcc_assert ((keyword == RID_TRANSACTION_ATOMIC
+ || keyword == RID_TRANSACTION_RELAXED)
+ && c_parser_next_token_is_keyword (parser, keyword));
+ c_parser_consume_token (parser);
+
+ if (keyword == RID_TRANSACTION_RELAXED)
+ this_in |= TM_STMT_ATTR_RELAXED;
+ else
+ {
+ attrs = c_parser_transaction_attributes (parser);
+ if (attrs)
+ this_in |= parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER);
+ }
+
+ /* Keep track if we're in the lexical scope of an outer transaction. */
+ new_in = this_in | (old_in & TM_STMT_ATTR_OUTER);
+
+ parser->in_transaction = new_in;
+ stmt = c_parser_compound_statement (parser);
+ parser->in_transaction = old_in;
+
+ if (flag_tm)
+ stmt = c_finish_transaction (loc, stmt, this_in);
+ else
+ error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ?
+ "%<__transaction_atomic%> without transactional memory support enabled"
+ : "%<__transaction_relaxed %> "
+ "without transactional memory support enabled"));
+
+ return stmt;
+}
+
+/* Parse a __transaction_atomic or __transaction_relaxed expression
+ (GCC Extension).
+
+ transaction-expression:
+ __transaction_atomic ( expression )
+ __transaction_relaxed ( expression )
+*/
+
+static struct c_expr
+c_parser_transaction_expression (c_parser *parser, enum rid keyword)
+{
+ struct c_expr ret;
+ unsigned int old_in = parser->in_transaction;
+ unsigned int this_in = 1;
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree attrs;
+
+ gcc_assert ((keyword == RID_TRANSACTION_ATOMIC
+ || keyword == RID_TRANSACTION_RELAXED)
+ && c_parser_next_token_is_keyword (parser, keyword));
+ c_parser_consume_token (parser);
+
+ if (keyword == RID_TRANSACTION_RELAXED)
+ this_in |= TM_STMT_ATTR_RELAXED;
+ else
+ {
+ attrs = c_parser_transaction_attributes (parser);
+ if (attrs)
+ this_in |= parse_tm_stmt_attr (attrs, 0);
+ }
+
+ parser->in_transaction = this_in;
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ tree expr = c_parser_expression (parser).value;
+ ret.original_type = TREE_TYPE (expr);
+ ret.value = build1 (TRANSACTION_EXPR, ret.original_type, expr);
+ if (this_in & TM_STMT_ATTR_RELAXED)
+ TRANSACTION_EXPR_RELAXED (ret.value) = 1;
+ SET_EXPR_LOCATION (ret.value, loc);
+ ret.original_code = TRANSACTION_EXPR;
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ goto error;
+ }
+ }
+ else
+ {
+ error:
+ ret.value = error_mark_node;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ }
+ parser->in_transaction = old_in;
+
+ if (!flag_tm)
+ error_at (loc, (keyword == RID_TRANSACTION_ATOMIC ?
+ "%<__transaction_atomic%> without transactional memory support enabled"
+ : "%<__transaction_relaxed %> "
+ "without transactional memory support enabled"));
+
+ return ret;
+}
+
+/* Parse a __transaction_cancel statement (GCC Extension).
+
+ transaction-cancel-statement:
+ __transaction_cancel transaction-attribute[opt] ;
+
+ Note that the only valid attribute is "outer".
+*/
+
+static tree
+c_parser_transaction_cancel(c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree attrs;
+ bool is_outer = false;
+
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_TRANSACTION_CANCEL));
+ c_parser_consume_token (parser);
+
+ attrs = c_parser_transaction_attributes (parser);
+ if (attrs)
+ is_outer = (parse_tm_stmt_attr (attrs, TM_STMT_ATTR_OUTER) != 0);
+
+ if (!flag_tm)
+ {
+ error_at (loc, "%<__transaction_cancel%> without "
+ "transactional memory support enabled");
+ goto ret_error;
+ }
+ else if (parser->in_transaction & TM_STMT_ATTR_RELAXED)
+ {
+ error_at (loc, "%<__transaction_cancel%> within a "
+ "%<__transaction_relaxed%>");
+ goto ret_error;
+ }
+ else if (is_outer)
+ {
+ if ((parser->in_transaction & TM_STMT_ATTR_OUTER) == 0
+ && !is_tm_may_cancel_outer (current_function_decl))
+ {
+ error_at (loc, "outer %<__transaction_cancel%> not "
+ "within outer %<__transaction_atomic%>");
+ error_at (loc, " or a %<transaction_may_cancel_outer%> function");
+ goto ret_error;
+ }
+ }
+ else if (parser->in_transaction == 0)
+ {
+ error_at (loc, "%<__transaction_cancel%> not within "
+ "%<__transaction_atomic%>");
+ goto ret_error;
+ }
+
+ return add_stmt (build_tm_abort_call (loc, is_outer));
+
+ ret_error:
+ return build1 (NOP_EXPR, void_type_node, error_mark_node);
+}
+
+/* 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_alloc_c_parser ();
+ *the_parser = tparser;
+
+ /* Initialize EH, if we've been told to do so. */
+ if (flag_exceptions)
+ using_eh_for_cleanups ();
+
+ c_parser_translation_unit (the_parser);
+ the_parser = NULL;
+}
+
+#include "gt-c-c-parser.h"