aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c/c-parser.cc')
-rw-r--r--gcc/c/c-parser.cc23404
1 files changed, 23404 insertions, 0 deletions
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
new file mode 100644
index 0000000..20774f7
--- /dev/null
+++ b/gcc/c/c-parser.cc
@@ -0,0 +1,23404 @@
+/* Parser for C and Objective-C.
+ Copyright (C) 1987-2022 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"
+#define INCLUDE_MEMORY
+#include "system.h"
+#include "coretypes.h"
+#include "target.h"
+#include "function.h"
+#include "c-tree.h"
+#include "timevar.h"
+#include "stringpool.h"
+#include "cgraph.h"
+#include "attribs.h"
+#include "stor-layout.h"
+#include "varasm.h"
+#include "trans-mem.h"
+#include "c-family/c-pragma.h"
+#include "c-lang.h"
+#include "c-family/c-objc.h"
+#include "plugin.h"
+#include "omp-general.h"
+#include "omp-offload.h"
+#include "builtins.h"
+#include "gomp-constants.h"
+#include "c-family/c-indentation.h"
+#include "gimple-expr.h"
+#include "context.h"
+#include "gcc-rich-location.h"
+#include "c-parser.h"
+#include "gimple-parser.h"
+#include "read-rtl-function.h"
+#include "run-rtl-passes.h"
+#include "intl.h"
+#include "c-family/name-hint.h"
+#include "tree-iterator.h"
+#include "tree-pretty-print.h"
+#include "memmodel.h"
+#include "c-family/known-headers.h"
+
+/* We need to walk over decls with incomplete struct/union/enum types
+ after parsing the whole translation unit.
+ In finish_decl(), if the decl is static, has incomplete
+ struct/union/enum type, it is appended to incomplete_record_decls.
+ In c_parser_translation_unit(), we iterate over incomplete_record_decls
+ and report error if any of the decls are still incomplete. */
+
+vec<tree> incomplete_record_decls;
+
+void
+set_c_expr_source_range (c_expr *expr,
+ location_t start, location_t finish)
+{
+ expr->src_range.m_start = start;
+ expr->src_range.m_finish = finish;
+ if (expr->value)
+ set_source_range (expr->value, start, finish);
+}
+
+void
+set_c_expr_source_range (c_expr *expr,
+ source_range src_range)
+{
+ expr->src_range = src_range;
+ if (expr->value)
+ set_source_range (expr->value, src_range);
+}
+
+
+/* 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_cleared_vec_alloc<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;
+ }
+
+ for (i = 0; i < NUM_INT_N_ENTS; i++)
+ {
+ /* We always create the symbols but they aren't always supported. */
+ char name[50];
+ sprintf (name, "__int%d", int_n_data[i].bitsize);
+ id = get_identifier (name);
+ C_SET_RID_CODE (id, RID_FIRST_INT_N + i);
+ C_IS_RESERVED_WORD (id) = 1;
+
+ sprintf (name, "__int%d__", int_n_data[i].bitsize);
+ id = get_identifier (name);
+ C_SET_RID_CODE (id, RID_FIRST_INT_N + i);
+ C_IS_RESERVED_WORD (id) = 1;
+ }
+}
+
+/* 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. */
+struct GTY(()) c_parser {
+ /* The look-ahead tokens. */
+ c_token * GTY((skip)) tokens;
+ /* Buffer for look-ahead tokens. */
+ c_token tokens_buf[4];
+ /* How many look-ahead tokens are available (0 - 4, or
+ more if parsing from pre-lexed tokens). */
+ unsigned int tokens_avail;
+ /* Raw look-ahead tokens, used only for checking in Objective-C
+ whether '[[' starts attributes. */
+ vec<c_token, va_gc> *raw_tokens;
+ /* The number of raw look-ahead tokens that have since been fully
+ lexed. */
+ unsigned int raw_tokens_used;
+ /* 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 a translated, joined string (for an
+ initial #pragma pch_preprocess). Otherwise the parser is
+ responsible for concatenating strings and translating to the
+ execution character set as needed. */
+ BOOL_BITFIELD lex_joined_string : 1;
+ /* True if, when the parser is concatenating string literals, it
+ should translate them to the execution character set (false
+ inside attributes). */
+ BOOL_BITFIELD translate_strings_p : 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;
+
+ /* Whether we have just seen/constructed a string-literal. Set when
+ returning a string-literal from c_parser_string_literal. Reset
+ in consume_token. Useful when we get a parse error and see an
+ unknown token, which could have been a string-literal constant
+ macro. */
+ BOOL_BITFIELD seen_string_literal : 1;
+
+ /* Location of the last consumed token. */
+ location_t last_token_location;
+};
+
+/* Return a pointer to the Nth token in PARSERs tokens_buf. */
+
+c_token *
+c_parser_tokens_buf (c_parser *parser, unsigned n)
+{
+ return &parser->tokens_buf[n];
+}
+
+/* Return the error state of PARSER. */
+
+bool
+c_parser_error (c_parser *parser)
+{
+ return parser->error;
+}
+
+/* Set the error state of PARSER to ERR. */
+
+void
+c_parser_set_error (c_parser *parser, bool err)
+{
+ parser->error = err;
+}
+
+
+/* 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. If RAW,
+ context-sensitive postprocessing of the token is not done. */
+
+static void
+c_lex_one_token (c_parser *parser, c_token *token, bool raw = false)
+{
+ timevar_push (TV_LEX);
+
+ if (raw || vec_safe_length (parser->raw_tokens) == 0)
+ {
+ token->type = c_lex_with_flags (&token->value, &token->location,
+ &token->flags,
+ (parser->lex_joined_string
+ ? 0 : C_LEX_STRING_NO_JOIN));
+ token->id_kind = C_ID_NONE;
+ token->keyword = RID_MAX;
+ token->pragma_kind = PRAGMA_NONE;
+ }
+ else
+ {
+ /* Use a token previously lexed as a raw look-ahead token, and
+ complete the processing on it. */
+ *token = (*parser->raw_tokens)[parser->raw_tokens_used];
+ ++parser->raw_tokens_used;
+ if (parser->raw_tokens_used == vec_safe_length (parser->raw_tokens))
+ {
+ vec_free (parser->raw_tokens);
+ parser->raw_tokens_used = 0;
+ }
+ }
+
+ if (raw)
+ goto out;
+
+ 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)
+ {
+ addr_space_t as;
+ as = (addr_space_t) (rid_code - RID_FIRST_ADDR_SPACE);
+ targetm.addr_space.diagnose_usage (as, token->location);
+ 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;
+ case RID_SYNCHRONIZED: token->keyword = RID_AT_SYNCHRONIZED; 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;
+ }
+ out:
+ timevar_pop (TV_LEX);
+}
+
+/* Return a pointer to the next token from PARSER, reading it in if
+ necessary. */
+
+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 a pointer to the next-but-one token from PARSER, reading it
+ in if necessary. The next token is already read in. */
+
+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 a pointer to the Nth token from PARSER, reading it
+ in if necessary. The N-1th token is already read in. */
+
+c_token *
+c_parser_peek_nth_token (c_parser *parser, unsigned int n)
+{
+ /* N is 1-based, not zero-based. */
+ gcc_assert (n > 0);
+
+ if (parser->tokens_avail >= n)
+ return &parser->tokens[n - 1];
+ gcc_assert (parser->tokens_avail == n - 1);
+ c_lex_one_token (parser, &parser->tokens[n - 1]);
+ parser->tokens_avail = n;
+ return &parser->tokens[n - 1];
+}
+
+/* Return a pointer to the Nth token from PARSER, reading it in as a
+ raw look-ahead token if necessary. The N-1th token is already read
+ in. Raw look-ahead tokens remain available for when the non-raw
+ functions above are called. */
+
+c_token *
+c_parser_peek_nth_token_raw (c_parser *parser, unsigned int n)
+{
+ /* N is 1-based, not zero-based. */
+ gcc_assert (n > 0);
+
+ if (parser->tokens_avail >= n)
+ return &parser->tokens[n - 1];
+ unsigned int raw_len = vec_safe_length (parser->raw_tokens);
+ unsigned int raw_avail
+ = parser->tokens_avail + raw_len - parser->raw_tokens_used;
+ gcc_assert (raw_avail >= n - 1);
+ if (raw_avail >= n)
+ return &(*parser->raw_tokens)[parser->raw_tokens_used
+ + n - 1 - parser->tokens_avail];
+ vec_safe_reserve (parser->raw_tokens, 1);
+ parser->raw_tokens->quick_grow (raw_len + 1);
+ c_lex_one_token (parser, &(*parser->raw_tokens)[raw_len], true);
+ return &(*parser->raw_tokens)[raw_len];
+}
+
+bool
+c_keyword_starts_typename (enum rid keyword)
+{
+ switch (keyword)
+ {
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_SHORT:
+ case RID_SIGNED:
+ case RID_COMPLEX:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ CASE_RID_FLOATN_NX:
+ case RID_BOOL:
+ case RID_ENUM:
+ case RID_STRUCT:
+ case RID_UNION:
+ case RID_TYPEOF:
+ case RID_CONST:
+ case RID_ATOMIC:
+ case RID_VOLATILE:
+ case RID_RESTRICT:
+ case RID_ATTRIBUTE:
+ case RID_FRACT:
+ case RID_ACCUM:
+ case RID_SAT:
+ case RID_AUTO_TYPE:
+ case RID_ALIGNAS:
+ return true;
+ default:
+ if (keyword >= RID_FIRST_INT_N
+ && keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
+ && int_n_enabled_p[keyword - RID_FIRST_INT_N])
+ return true;
+ return false;
+ }
+}
+
+/* Return true if TOKEN can start a type name,
+ false otherwise. */
+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:
+ return c_keyword_starts_typename (token->keyword);
+ case CPP_LESS:
+ if (c_dialect_objc ())
+ return true;
+ return false;
+ default:
+ return false;
+ }
+}
+
+/* Return true if the next token from PARSER can start a type name,
+ false otherwise. 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:
+ case RID_ATOMIC:
+ 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 (not
+ including standard attributes), 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_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_FLOATN_NX:
+ 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:
+ case RID_ATOMIC:
+ case RID_AUTO_TYPE:
+ return true;
+ default:
+ if (token->keyword >= RID_FIRST_INT_N
+ && token->keyword < RID_FIRST_INT_N + NUM_INT_N_ENTS
+ && int_n_enabled_p[token->keyword - RID_FIRST_INT_N])
+ return true;
+ return false;
+ }
+ case CPP_LESS:
+ if (c_dialect_objc ())
+ return true;
+ return false;
+ default:
+ return false;
+ }
+}
+
+
+/* Return true if TOKEN can start declaration specifiers (not
+ including standard attributes) 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 (not including standard attributes), false
+ otherwise. */
+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 (not including standard attributes) or a static
+ assertion, false otherwise. */
+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. */
+
+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);
+ parser->last_token_location = parser->tokens[0].location;
+ if (parser->tokens != &parser->tokens_buf[0])
+ parser->tokens++;
+ else if (parser->tokens_avail >= 2)
+ {
+ parser->tokens[0] = parser->tokens[1];
+ if (parser->tokens_avail >= 3)
+ {
+ parser->tokens[1] = parser->tokens[2];
+ if (parser->tokens_avail >= 4)
+ parser->tokens[2] = parser->tokens[3];
+ }
+ }
+ parser->tokens_avail--;
+ parser->seen_string_literal = false;
+}
+
+/* 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 != &parser->tokens_buf[0])
+ parser->tokens++;
+ else if (parser->tokens_avail >= 2)
+ {
+ parser->tokens[0] = parser->tokens[1];
+ if (parser->tokens_avail >= 3)
+ parser->tokens[1] = parser->tokens[2];
+ }
+ parser->tokens_avail--;
+ parser->in_pragma = true;
+}
+
+/* Update the global input_location from TOKEN. */
+static inline void
+c_parser_set_source_position_from_token (c_token *token)
+{
+ if (token->type != CPP_EOF)
+ {
+ input_location = token->location;
+ }
+}
+
+/* Helper function for c_parser_error.
+ Having peeked a token of kind TOK1_KIND that might signify
+ a conflict marker, peek successor tokens to determine
+ if we actually do have a conflict marker.
+ Specifically, we consider a run of 7 '<', '=' or '>' characters
+ at the start of a line as a conflict marker.
+ These come through the lexer as three pairs and a single,
+ e.g. three CPP_LSHIFT ("<<") and a CPP_LESS ('<').
+ If it returns true, *OUT_LOC is written to with the location/range
+ of the marker. */
+
+static bool
+c_parser_peek_conflict_marker (c_parser *parser, enum cpp_ttype tok1_kind,
+ location_t *out_loc)
+{
+ c_token *token2 = c_parser_peek_2nd_token (parser);
+ if (token2->type != tok1_kind)
+ return false;
+ c_token *token3 = c_parser_peek_nth_token (parser, 3);
+ if (token3->type != tok1_kind)
+ return false;
+ c_token *token4 = c_parser_peek_nth_token (parser, 4);
+ if (token4->type != conflict_marker_get_final_tok_kind (tok1_kind))
+ return false;
+
+ /* It must be at the start of the line. */
+ location_t start_loc = c_parser_peek_token (parser)->location;
+ if (LOCATION_COLUMN (start_loc) != 1)
+ return false;
+
+ /* We have a conflict marker. Construct a location of the form:
+ <<<<<<<
+ ^~~~~~~
+ with start == caret, finishing at the end of the marker. */
+ location_t finish_loc = get_finish (token4->location);
+ *out_loc = make_location (start_loc, start_loc, finish_loc);
+
+ return true;
+}
+
+/* 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".
+
+ Use RICHLOC as the location of the diagnostic.
+
+ Do not issue a diagnostic if still recovering from an error.
+
+ Return true iff an error was actually emitted.
+
+ ??? 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 bool
+c_parser_error_richloc (c_parser *parser, const char *gmsgid,
+ rich_location *richloc)
+{
+ c_token *token = c_parser_peek_token (parser);
+ if (parser->error)
+ return false;
+ parser->error = true;
+ if (!gmsgid)
+ return false;
+
+ /* If this is actually a conflict marker, report it as such. */
+ if (token->type == CPP_LSHIFT
+ || token->type == CPP_RSHIFT
+ || token->type == CPP_EQ_EQ)
+ {
+ location_t loc;
+ if (c_parser_peek_conflict_marker (parser, token->type, &loc))
+ {
+ error_at (loc, "version control conflict marker in file");
+ return true;
+ }
+ }
+
+ /* If we were parsing a string-literal and there is an unknown name
+ token right after, then check to see if that could also have been
+ a literal string by checking the name against a list of known
+ standard string literal constants defined in header files. If
+ there is one, then add that as an hint to the error message. */
+ auto_diagnostic_group d;
+ name_hint h;
+ if (parser->seen_string_literal && token->type == CPP_NAME)
+ {
+ tree name = token->value;
+ const char *token_name = IDENTIFIER_POINTER (name);
+ const char *header_hint
+ = get_c_stdlib_header_for_string_macro_name (token_name);
+ if (header_hint != NULL)
+ h = name_hint (NULL, new suggest_missing_header (token->location,
+ token_name,
+ header_hint));
+ }
+
+ 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, richloc);
+ return true;
+}
+
+/* As c_parser_error_richloc, but issue the message at the
+ location of PARSER's next token, or at input_location
+ if the next token is EOF. */
+
+bool
+c_parser_error (c_parser *parser, const char *gmsgid)
+{
+ c_token *token = c_parser_peek_token (parser);
+ c_parser_set_source_position_from_token (token);
+ rich_location richloc (line_table, input_location);
+ return c_parser_error_richloc (parser, gmsgid, &richloc);
+}
+
+/* Some tokens naturally come in pairs e.g.'(' and ')'.
+ This class is for tracking such a matching pair of symbols.
+ In particular, it tracks the location of the first token,
+ so that if the second token is missing, we can highlight the
+ location of the first token when notifying the user about the
+ problem. */
+
+template <typename traits_t>
+class token_pair
+{
+ public:
+ /* token_pair's ctor. */
+ token_pair () : m_open_loc (UNKNOWN_LOCATION) {}
+
+ /* If the next token is the opening symbol for this pair, consume it and
+ return true.
+ Otherwise, issue an error and return false.
+ In either case, record the location of the opening token. */
+
+ bool require_open (c_parser *parser)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token)
+ m_open_loc = token->location;
+
+ return c_parser_require (parser, traits_t::open_token_type,
+ traits_t::open_gmsgid);
+ }
+
+ /* Consume the next token from PARSER, recording its location as
+ that of the opening token within the pair. */
+
+ void consume_open (c_parser *parser)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ gcc_assert (token->type == traits_t::open_token_type);
+ m_open_loc = token->location;
+ c_parser_consume_token (parser);
+ }
+
+ /* If the next token is the closing symbol for this pair, consume it
+ and return true.
+ Otherwise, issue an error, highlighting the location of the
+ corresponding opening token, and return false. */
+
+ bool require_close (c_parser *parser) const
+ {
+ return c_parser_require (parser, traits_t::close_token_type,
+ traits_t::close_gmsgid, m_open_loc);
+ }
+
+ /* Like token_pair::require_close, 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. */
+
+ void skip_until_found_close (c_parser *parser) const
+ {
+ c_parser_skip_until_found (parser, traits_t::close_token_type,
+ traits_t::close_gmsgid, m_open_loc);
+ }
+
+ private:
+ location_t m_open_loc;
+};
+
+/* Traits for token_pair<T> for tracking matching pairs of parentheses. */
+
+struct matching_paren_traits
+{
+ static const enum cpp_ttype open_token_type = CPP_OPEN_PAREN;
+ static const char * const open_gmsgid;
+ static const enum cpp_ttype close_token_type = CPP_CLOSE_PAREN;
+ static const char * const close_gmsgid;
+};
+
+const char * const matching_paren_traits::open_gmsgid = "expected %<(%>";
+const char * const matching_paren_traits::close_gmsgid = "expected %<)%>";
+
+/* "matching_parens" is a token_pair<T> class for tracking matching
+ pairs of parentheses. */
+
+typedef token_pair<matching_paren_traits> matching_parens;
+
+/* Traits for token_pair<T> for tracking matching pairs of braces. */
+
+struct matching_brace_traits
+{
+ static const enum cpp_ttype open_token_type = CPP_OPEN_BRACE;
+ static const char * const open_gmsgid;
+ static const enum cpp_ttype close_token_type = CPP_CLOSE_BRACE;
+ static const char * const close_gmsgid;
+};
+
+const char * const matching_brace_traits::open_gmsgid = "expected %<{%>";
+const char * const matching_brace_traits::close_gmsgid = "expected %<}%>";
+
+/* "matching_braces" is a token_pair<T> class for tracking matching
+ pairs of braces. */
+
+typedef token_pair<matching_brace_traits> matching_braces;
+
+/* Get a description of the matching symbol to TYPE e.g. "(" for
+ CPP_CLOSE_PAREN. */
+
+static const char *
+get_matching_symbol (enum cpp_ttype type)
+{
+ switch (type)
+ {
+ default:
+ gcc_unreachable ();
+ case CPP_CLOSE_PAREN:
+ return "(";
+ case CPP_CLOSE_BRACE:
+ return "{";
+ }
+}
+
+/* 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.
+
+ If MATCHING_LOCATION is not UNKNOWN_LOCATION, then highlight it
+ within any error as the location of an "opening" token matching
+ the close token TYPE (e.g. the location of the '(' when TYPE is
+ CPP_CLOSE_PAREN).
+
+ If TYPE_IS_UNIQUE is true (the default) then msgid describes exactly
+ one type (e.g. "expected %<)%>") and thus it may be reasonable to
+ attempt to generate a fix-it hint for the problem.
+ Otherwise msgid describes multiple token types (e.g.
+ "expected %<;%>, %<,%> or %<)%>"), and thus we shouldn't attempt to
+ generate a fix-it hint. */
+
+bool
+c_parser_require (c_parser *parser,
+ enum cpp_ttype type,
+ const char *msgid,
+ location_t matching_location,
+ bool type_is_unique)
+{
+ if (c_parser_next_token_is (parser, type))
+ {
+ c_parser_consume_token (parser);
+ return true;
+ }
+ else
+ {
+ location_t next_token_loc = c_parser_peek_token (parser)->location;
+ gcc_rich_location richloc (next_token_loc);
+
+ /* Potentially supply a fix-it hint, suggesting to add the
+ missing token immediately after the *previous* token.
+ This may move the primary location within richloc. */
+ if (!parser->error && type_is_unique)
+ maybe_suggest_missing_token_insertion (&richloc, type,
+ parser->last_token_location);
+
+ /* If matching_location != UNKNOWN_LOCATION, highlight it.
+ Attempt to consolidate diagnostics by printing it as a
+ secondary range within the main diagnostic. */
+ bool added_matching_location = false;
+ if (matching_location != UNKNOWN_LOCATION)
+ added_matching_location
+ = richloc.add_location_if_nearby (matching_location);
+
+ if (c_parser_error_richloc (parser, msgid, &richloc))
+ /* If we weren't able to consolidate matching_location, then
+ print it as a secondary diagnostic. */
+ if (matching_location != UNKNOWN_LOCATION && !added_matching_location)
+ inform (matching_location, "to match this %qs",
+ get_matching_symbol (type));
+
+ 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.
+
+ If MATCHING_LOCATION is not UNKNOWN_LOCATION, then highlight it
+ within any error as the location of an "opening" token matching
+ the close token TYPE (e.g. the location of the '(' when TYPE is
+ CPP_CLOSE_PAREN). */
+
+void
+c_parser_skip_until_found (c_parser *parser,
+ enum cpp_ttype type,
+ const char *msgid,
+ location_t matching_location)
+{
+ unsigned nesting_depth = 0;
+
+ if (c_parser_require (parser, type, msgid, matching_location))
+ 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, bool error_if_not_eol = true)
+{
+ gcc_assert (parser->in_pragma);
+ parser->in_pragma = false;
+
+ if (error_if_not_eol && c_parser_peek_token (parser)->type != CPP_PRAGMA_EOL)
+ c_parser_error (parser, "expected end of line");
+
+ cpp_ttype token_type;
+ do
+ {
+ c_token *token = c_parser_peek_token (parser);
+ token_type = token->type;
+ if (token_type == CPP_EOF)
+ break;
+ c_parser_consume_token (parser);
+ }
+ while (token_type != CPP_PRAGMA_EOL);
+
+ 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)
+ /* warn_c90_c99_compat has three states: -1/0/1, so we must
+ play tricks to properly restore it. */
+ | ((warn_c90_c99_compat == 1) << 7)
+ | ((warn_c90_c99_compat == -1) << 8)
+ /* Similarly for warn_c99_c11_compat. */
+ | ((warn_c99_c11_compat == 1) << 9)
+ | ((warn_c99_c11_compat == -1) << 10)
+ /* Similarly for warn_c11_c2x_compat. */
+ | ((warn_c11_c2x_compat == 1) << 11)
+ | ((warn_c11_c2x_compat == -1) << 12)
+ );
+ 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;
+ warn_c90_c99_compat = 0;
+ warn_c99_c11_compat = 0;
+ warn_c11_c2x_compat = 0;
+ return ret;
+}
+
+/* Restore the warning flags which are controlled by __extension__.
+ FLAGS is the return value from disable_extension_diagnostics. */
+
+static inline void
+restore_extension_diagnostics (int flags)
+{
+ cpp_opts->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;
+ /* See above for why is this needed. */
+ warn_c90_c99_compat = (flags >> 7) & 1 ? 1 : ((flags >> 8) & 1 ? -1 : 0);
+ warn_c99_c11_compat = (flags >> 9) & 1 ? 1 : ((flags >> 10) & 1 ? -1 : 0);
+ warn_c11_c2x_compat = (flags >> 11) & 1 ? 1 : ((flags >> 12) & 1 ? -1 : 0);
+}
+
+/* Helper data structure for parsing #pragma acc routine. */
+struct oacc_routine_data {
+ bool error_seen; /* Set if error has been reported. */
+ bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */
+ tree clauses;
+ location_t loc;
+};
+
+/* Used for parsing objc foreach statements. */
+static tree objc_foreach_break_label, objc_foreach_continue_label;
+
+static bool c_parser_nth_token_starts_std_attributes (c_parser *,
+ unsigned int);
+static tree c_parser_std_attribute_specifier_sequence (c_parser *);
+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 * = NULL,
+ vec<c_token> * = NULL,
+ bool have_attrs = false,
+ tree attrs = NULL,
+ struct oacc_routine_data * = NULL,
+ bool * = NULL);
+static void c_parser_static_assert_declaration_no_semi (c_parser *);
+static void c_parser_static_assert_declaration (c_parser *);
+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_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,
+ bool);
+static struct c_arg_info *c_parser_parms_list_declarator (c_parser *, tree,
+ tree, bool);
+static struct c_parm *c_parser_parameter_declaration (c_parser *, tree, bool);
+static tree c_parser_simple_asm_expr (c_parser *);
+static tree c_parser_gnu_attributes (c_parser *);
+static struct c_expr c_parser_initializer (c_parser *);
+static struct c_expr c_parser_braced_init (c_parser *, tree, bool,
+ struct obstack *);
+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 *, location_t * = NULL);
+static location_t c_parser_compound_statement_nostart (c_parser *);
+static void c_parser_label (c_parser *, tree);
+static void c_parser_statement (c_parser *, bool *, location_t * = NULL);
+static void c_parser_statement_after_labels (c_parser *, bool *,
+ vec<tree> * = NULL);
+static tree c_parser_c99_block_statement (c_parser *, bool *,
+ location_t * = NULL);
+static void c_parser_if_statement (c_parser *, bool *, vec<tree> *);
+static void c_parser_switch_statement (c_parser *, bool *);
+static void c_parser_while_statement (c_parser *, bool, unsigned short, bool *);
+static void c_parser_do_statement (c_parser *, bool, unsigned short);
+static void c_parser_for_statement (c_parser *, bool, unsigned short, bool *);
+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 *,
+ tree = NULL_TREE);
+static struct c_expr c_parser_conditional_expression (c_parser *,
+ struct c_expr *, tree);
+static struct c_expr c_parser_binary_expression (c_parser *, struct c_expr *,
+ tree);
+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 *, vec<location_t> *,
+ unsigned int * = NULL);
+static struct c_expr c_parser_has_attribute_expression (c_parser *);
+
+static void c_parser_oacc_declare (c_parser *);
+static void c_parser_oacc_enter_exit_data (c_parser *, bool);
+static void c_parser_oacc_update (c_parser *);
+static void c_parser_omp_construct (c_parser *, bool *);
+static void c_parser_omp_threadprivate (c_parser *);
+static void c_parser_omp_barrier (c_parser *);
+static void c_parser_omp_depobj (c_parser *);
+static void c_parser_omp_flush (c_parser *);
+static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code,
+ tree, tree *, bool *);
+static void c_parser_omp_taskwait (c_parser *);
+static void c_parser_omp_taskyield (c_parser *);
+static void c_parser_omp_cancel (c_parser *);
+static void c_parser_omp_nothing (c_parser *);
+
+enum pragma_context { pragma_external, pragma_struct, pragma_param,
+ pragma_stmt, pragma_compound };
+static bool c_parser_pragma (c_parser *, enum pragma_context, bool *);
+static bool c_parser_omp_cancellation_point (c_parser *, enum pragma_context);
+static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *);
+static void c_parser_omp_end_declare_target (c_parser *);
+static bool c_parser_omp_declare (c_parser *, enum pragma_context);
+static void c_parser_omp_requires (c_parser *);
+static bool c_parser_omp_error (c_parser *, enum pragma_context);
+static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *);
+static void c_parser_oacc_routine (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 *);
+static location_t c_parser_parse_rtl_body (c_parser *, char *);
+
+/* Parse a translation unit (C90 6.7, C99 6.9, C11 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));
+ }
+
+ unsigned int i;
+ tree decl;
+ FOR_EACH_VEC_ELT (incomplete_record_decls, i, decl)
+ if (DECL_SIZE (decl) == NULL_TREE && TREE_TYPE (decl) != error_mark_node)
+ error ("storage size of %q+D isn%'t known", decl);
+
+ if (current_omp_declare_target_attribute)
+ {
+ if (!errorcount)
+ error ("%<#pragma omp declare target%> without corresponding "
+ "%<#pragma omp end declare target%>");
+ current_omp_declare_target_attribute = 0;
+ }
+}
+
+/* Parse an external declaration (C90 6.7, C99 6.9, C11 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, NULL);
+ 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. */
+ /* FALLTHRU */
+ 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);
+ break;
+ }
+}
+
+static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token> *);
+static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
+
+/* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */
+
+static void
+add_debug_begin_stmt (location_t loc)
+{
+ /* Don't add DEBUG_BEGIN_STMTs outside of functions, see PR84721. */
+ if (!MAY_HAVE_DEBUG_MARKER_STMTS || !building_stmt_list_p ())
+ return;
+
+ tree stmt = build0 (DEBUG_BEGIN_STMT, void_type_node);
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+}
+
+/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
+ 6.7, 6.9.1, C11 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 (GNU or standard); otherwise they may not.
+ OBJC_FOREACH_OBJECT_DECLARATION can be used to get back the parsed
+ declaration when parsing an Objective-C foreach statement.
+ FALLTHRU_ATTR_P is used to signal whether this function parsed
+ "__attribute__((fallthrough));". ATTRS are any standard attributes
+ parsed in the caller (in contexts where such attributes had to be
+ parsed to determine whether what follows is a declaration or a
+ statement); HAVE_ATTRS says whether there were any such attributes
+ (even empty).
+
+ 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] gnu-attributes[opt]
+ declarator simple-asm-expr[opt] gnu-attributes[opt] = initializer
+
+ GNU extensions:
+
+ nested-function-definition:
+ declaration-specifiers declarator declaration-list[opt]
+ compound-statement
+
+ attribute ;
+
+ Objective-C:
+ gnu-attributes objc-class-definition
+ gnu-attributes objc-category-definition
+ gnu-attributes objc-protocol-definition
+
+ The simple-asm-expr and gnu-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
+
+ GIMPLE:
+
+ gimple-function-definition:
+ declaration-specifiers[opt] __GIMPLE (gimple-or-rtl-pass-list) declarator
+ declaration-list[opt] compound-statement
+
+ rtl-function-definition:
+ declaration-specifiers[opt] __RTL (gimple-or-rtl-pass-list) declarator
+ declaration-list[opt] compound-statement */
+
+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
+ /* = NULL */,
+ vec<c_token> *omp_declare_simd_clauses
+ /* = NULL */,
+ bool have_attrs /* = false */,
+ tree attrs /* = NULL_TREE */,
+ struct oacc_routine_data *oacc_routine_data
+ /* = NULL */,
+ bool *fallthru_attr_p /* = NULL */)
+{
+ 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;
+
+ add_debug_begin_stmt (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 ();
+
+ /* Handle any standard attributes parsed in the caller. */
+ if (have_attrs)
+ {
+ declspecs_add_attrs (here, specs, attrs);
+ specs->non_std_attrs_seen_p = false;
+ }
+
+ /* 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)))
+ {
+ tree name = c_parser_peek_token (parser)->value;
+
+ /* Issue a warning about NAME being an unknown type name, perhaps
+ with some kind of hint.
+ If the user forgot a "struct" etc, suggest inserting
+ it. Otherwise, attempt to look for misspellings. */
+ gcc_rich_location richloc (here);
+ if (tag_exists_p (RECORD_TYPE, name))
+ {
+ /* This is not C++ with its implicit typedef. */
+ richloc.add_fixit_insert_before ("struct ");
+ error_at (&richloc,
+ "unknown type name %qE;"
+ " use %<struct%> keyword to refer to the type",
+ name);
+ }
+ else if (tag_exists_p (UNION_TYPE, name))
+ {
+ richloc.add_fixit_insert_before ("union ");
+ error_at (&richloc,
+ "unknown type name %qE;"
+ " use %<union%> keyword to refer to the type",
+ name);
+ }
+ else if (tag_exists_p (ENUMERAL_TYPE, name))
+ {
+ richloc.add_fixit_insert_before ("enum ");
+ error_at (&richloc,
+ "unknown type name %qE;"
+ " use %<enum%> keyword to refer to the type",
+ name);
+ }
+ else
+ {
+ auto_diagnostic_group d;
+ name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_TYPENAME,
+ here);
+ if (const char *suggestion = hint.suggestion ())
+ {
+ richloc.add_fixit_replace (suggestion);
+ error_at (&richloc,
+ "unknown type name %qE; did you mean %qs?",
+ name, suggestion);
+ }
+ else
+ error_at (here, "unknown type name %qE", name);
+ }
+
+ /* 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;
+ }
+
+ /* When there are standard attributes at the start of the
+ declaration (to apply to the entity being declared), an
+ init-declarator-list or function definition must be present. */
+ if (c_parser_nth_token_starts_std_attributes (parser, 1))
+ have_attrs = true;
+
+ c_parser_declspecs (parser, specs, true, true, start_attr_ok,
+ true, true, start_attr_ok, true, 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);
+ bool auto_type_p = specs->typespec_word == cts_auto_type;
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ if (auto_type_p)
+ error_at (here, "%<__auto_type%> in empty declaration");
+ else if (specs->typespec_kind == ctsk_none
+ && attribute_fallthrough_p (specs->attrs))
+ {
+ if (fallthru_attr_p != NULL)
+ *fallthru_attr_p = true;
+ if (nested)
+ {
+ tree fn = build_call_expr_internal_loc (here, IFN_FALLTHROUGH,
+ void_type_node, 0);
+ add_stmt (fn);
+ }
+ else
+ pedwarn (here, OPT_Wattributes,
+ "%<fallthrough%> attribute at top level");
+ }
+ else if (empty_ok && !(have_attrs
+ && specs->non_std_attrs_seen_p))
+ shadow_tag (specs);
+ else
+ {
+ shadow_tag_warned (specs, 1);
+ pedwarn (here, 0, "empty declaration");
+ }
+ c_parser_consume_token (parser);
+ if (oacc_routine_data)
+ c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false);
+ 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 () && !auto_type_p)
+ {
+ /* 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;
+ }
+ }
+ else if (attribute_fallthrough_p (specs->attrs))
+ warning_at (here, OPT_Wattributes,
+ "%<fallthrough%> attribute not followed by %<;%>");
+
+ 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 = NULL_TREE;
+ /* 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)
+ {
+ if (omp_declare_simd_clauses)
+ c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE,
+ omp_declare_simd_clauses);
+ if (oacc_routine_data)
+ c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false);
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
+ if (auto_type_p && declarator->kind != cdk_id)
+ {
+ error_at (here,
+ "%<__auto_type%> requires a plain identifier"
+ " as declarator");
+ 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_gnu_attributes (parser);
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ /* This means there is an attribute specifier after
+ the declarator in a function definition. Provide
+ some more information for the user. */
+ error_at (here, "attributes should be specified before the "
+ "declarator in a function definition");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
+ }
+ if (c_parser_next_token_is (parser, CPP_EQ))
+ {
+ tree d;
+ struct c_expr init;
+ location_t init_loc;
+ c_parser_consume_token (parser);
+ if (auto_type_p)
+ {
+ init_loc = c_parser_peek_token (parser)->location;
+ rich_location richloc (line_table, init_loc);
+ start_init (NULL_TREE, asm_name, global_bindings_p (), &richloc);
+ /* A parameter is initialized, which is invalid. Don't
+ attempt to instrument the initializer. */
+ int flag_sanitize_save = flag_sanitize;
+ if (nested && !empty_ok)
+ flag_sanitize = 0;
+ init = c_parser_expr_no_commas (parser, NULL);
+ flag_sanitize = flag_sanitize_save;
+ if (TREE_CODE (init.value) == COMPONENT_REF
+ && DECL_C_BIT_FIELD (TREE_OPERAND (init.value, 1)))
+ error_at (here,
+ "%<__auto_type%> used with a bit-field"
+ " initializer");
+ init = convert_lvalue_to_rvalue (init_loc, init, true, true);
+ tree init_type = TREE_TYPE (init.value);
+ bool vm_type = variably_modified_type_p (init_type,
+ NULL_TREE);
+ if (vm_type)
+ init.value = save_expr (init.value);
+ finish_init ();
+ specs->typespec_kind = ctsk_typeof;
+ specs->locations[cdw_typedef] = init_loc;
+ specs->typedef_p = true;
+ specs->type = init_type;
+ if (vm_type)
+ {
+ bool maybe_const = true;
+ tree type_expr = c_fully_fold (init.value, false,
+ &maybe_const);
+ specs->expr_const_operands &= maybe_const;
+ if (specs->expr)
+ specs->expr = build2 (COMPOUND_EXPR,
+ TREE_TYPE (type_expr),
+ specs->expr, type_expr);
+ else
+ specs->expr = type_expr;
+ }
+ d = start_decl (declarator, specs, true,
+ chainon (postfix_attrs, all_prefix_attrs));
+ if (!d)
+ d = error_mark_node;
+ if (omp_declare_simd_clauses)
+ c_finish_omp_declare_simd (parser, d, NULL_TREE,
+ omp_declare_simd_clauses);
+ }
+ else
+ {
+ /* 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;
+ if (omp_declare_simd_clauses)
+ c_finish_omp_declare_simd (parser, d, NULL_TREE,
+ omp_declare_simd_clauses);
+ init_loc = c_parser_peek_token (parser)->location;
+ rich_location richloc (line_table, init_loc);
+ start_init (d, asm_name, global_bindings_p (), &richloc);
+ /* A parameter is initialized, which is invalid. Don't
+ attempt to instrument the initializer. */
+ int flag_sanitize_save = flag_sanitize;
+ if (TREE_CODE (d) == PARM_DECL)
+ flag_sanitize = 0;
+ init = c_parser_initializer (parser);
+ flag_sanitize = flag_sanitize_save;
+ finish_init ();
+ }
+ if (oacc_routine_data)
+ c_finish_oacc_routine (oacc_routine_data, d, false);
+ if (d != error_mark_node)
+ {
+ maybe_warn_string_init (init_loc, TREE_TYPE (d), init);
+ finish_decl (d, init_loc, init.value,
+ init.original_type, asm_name);
+ }
+ }
+ else
+ {
+ if (auto_type_p)
+ {
+ error_at (here,
+ "%<__auto_type%> requires an initialized "
+ "data declaration");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
+
+ location_t lastloc = UNKNOWN_LOCATION;
+ tree attrs = chainon (postfix_attrs, all_prefix_attrs);
+ tree d = start_decl (declarator, specs, false, attrs, &lastloc);
+ if (d && TREE_CODE (d) == FUNCTION_DECL)
+ {
+ /* Find the innermost declarator that is neither cdk_id
+ nor cdk_attrs. */
+ const struct c_declarator *decl = declarator;
+ const struct c_declarator *last_non_id_attrs = NULL;
+
+ while (decl)
+ switch (decl->kind)
+ {
+ case cdk_array:
+ case cdk_function:
+ case cdk_pointer:
+ last_non_id_attrs = decl;
+ decl = decl->declarator;
+ break;
+
+ case cdk_attrs:
+ decl = decl->declarator;
+ break;
+
+ case cdk_id:
+ decl = 0;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* If it exists and is cdk_function declaration whose
+ arguments have not been set yet, use its arguments. */
+ if (last_non_id_attrs
+ && last_non_id_attrs->kind == cdk_function)
+ {
+ tree parms = last_non_id_attrs->u.arg_info->parms;
+ if (DECL_ARGUMENTS (d) == NULL_TREE
+ && DECL_INITIAL (d) == NULL_TREE)
+ DECL_ARGUMENTS (d) = parms;
+
+ warn_parm_array_mismatch (lastloc, d, parms);
+ }
+ }
+ if (omp_declare_simd_clauses)
+ {
+ tree parms = NULL_TREE;
+ if (d && TREE_CODE (d) == FUNCTION_DECL)
+ {
+ struct c_declarator *ce = declarator;
+ while (ce != NULL)
+ if (ce->kind == cdk_function)
+ {
+ parms = ce->u.arg_info->parms;
+ break;
+ }
+ else
+ ce = ce->declarator;
+ }
+ if (parms)
+ temp_store_parm_decls (d, parms);
+ c_finish_omp_declare_simd (parser, d, parms,
+ omp_declare_simd_clauses);
+ if (parms)
+ temp_pop_parm_decls ();
+ }
+ if (oacc_routine_data)
+ c_finish_oacc_routine (oacc_routine_data, d, false);
+ 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))
+ {
+ if (auto_type_p)
+ {
+ error_at (here,
+ "%<__auto_type%> may only be used with"
+ " a single declarator");
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ all_prefix_attrs = chainon (c_parser_gnu_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 (auto_type_p)
+ {
+ error_at (here,
+ "%<__auto_type%> requires an initialized data declaration");
+ 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))
+ {
+ /* At this point we've consumed:
+ declaration-specifiers declarator
+ and the next token isn't CPP_EQ, CPP_COMMA, CPP_SEMICOLON,
+ RID_ASM, RID_ATTRIBUTE, or RID_IN,
+ but the
+ declaration-specifiers declarator
+ aren't grokkable as a function definition, so we have
+ an error. */
+ gcc_assert (!c_parser_next_token_is (parser, CPP_SEMICOLON));
+ if (c_parser_next_token_starts_declspecs (parser))
+ {
+ /* If we have
+ declaration-specifiers declarator decl-specs
+ then assume we have a missing semicolon, which would
+ give us:
+ declaration-specifiers declarator decl-specs
+ ^
+ ;
+ <~~~~~~~~~ declaration ~~~~~~~~~~>
+ Use c_parser_require to get an error with a fix-it hint. */
+ c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>");
+ parser->error = false;
+ }
+ else
+ {
+ /* 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;
+ auto_timevar at (g_timer, 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);
+ store_parm_decls ();
+ if (omp_declare_simd_clauses)
+ c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
+ omp_declare_simd_clauses);
+ if (oacc_routine_data)
+ c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
+ location_t startloc = c_parser_peek_token (parser)->location;
+ DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
+ = startloc;
+ location_t endloc = startloc;
+
+ /* If the definition was marked with __RTL, use the RTL parser now,
+ consuming the function body. */
+ if (specs->declspec_il == cdil_rtl)
+ {
+ endloc = c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass);
+
+ /* Normally, store_parm_decls sets next_is_function_body,
+ anticipating a function body. We need a push_scope/pop_scope
+ pair to flush out this state, or subsequent function parsing
+ will go wrong. */
+ push_scope ();
+ pop_scope ();
+
+ finish_function (endloc);
+ return;
+ }
+ /* If the definition was marked with __GIMPLE then parse the
+ function body as GIMPLE. */
+ else if (specs->declspec_il != cdil_none)
+ {
+ bool saved = in_late_binary_op;
+ in_late_binary_op = true;
+ c_parser_parse_gimple_body (parser, specs->gimple_or_rtl_pass,
+ specs->declspec_il,
+ specs->entry_bb_count);
+ in_late_binary_op = saved;
+ }
+ else
+ fnbody = c_parser_compound_statement (parser, &endloc);
+ tree fndecl = current_function_decl;
+ 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 (endloc);
+ c_pop_function_context ();
+ add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
+ }
+ else
+ {
+ if (fnbody)
+ add_stmt (fnbody);
+ finish_function (endloc);
+ }
+ /* Get rid of the empty stmt list for GIMPLE/RTL. */
+ if (specs->declspec_il != cdil_none)
+ DECL_SAVED_TREE (fndecl) = NULL_TREE;
+
+ 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)
+ symtab->finalize_toplevel_asm (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 )
+
+ C2X:
+ static_assert-declaration-no-semi:
+ _Static_assert ( constant-expression )
+*/
+
+static void
+c_parser_static_assert_declaration_no_semi (c_parser *parser)
+{
+ location_t assert_loc, value_loc;
+ tree value;
+ tree string = NULL_TREE;
+
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT));
+ assert_loc = c_parser_peek_token (parser)->location;
+ if (flag_isoc99)
+ pedwarn_c99 (assert_loc, OPT_Wpedantic,
+ "ISO C99 does not support %<_Static_assert%>");
+ else
+ pedwarn_c99 (assert_loc, OPT_Wpedantic,
+ "ISO C90 does not support %<_Static_assert%>");
+ c_parser_consume_token (parser);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return;
+ location_t value_tok_loc = c_parser_peek_token (parser)->location;
+ value = c_parser_expr_no_commas (parser, NULL).value;
+ value_loc = EXPR_LOC_OR_LOC (value, value_tok_loc);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ 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_string_literal (parser, false, true).value;
+ break;
+ default:
+ c_parser_error (parser, "expected string literal");
+ return;
+ }
+ }
+ else if (flag_isoc11)
+ /* If pedantic for pre-C11, the use of _Static_assert itself will
+ have been diagnosed, so do not also diagnose the use of this
+ new C2X feature of _Static_assert. */
+ pedwarn_c11 (assert_loc, OPT_Wpedantic,
+ "ISO C11 does not support omitting the string in "
+ "%<_Static_assert%>");
+ parens.require_close (parser);
+
+ 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);
+ /* Strip no-op conversions. */
+ STRIP_TYPE_NOPS (value);
+ 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))
+ {
+ if (string)
+ error_at (assert_loc, "static assertion failed: %E", string);
+ else
+ error_at (assert_loc, "static assertion failed");
+ }
+}
+
+/* Parse some declaration specifiers (possibly none) (C90 6.5, C99
+ 6.7, C11 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; alignment specifiers are
+ accepted iff ALIGNSPEC_OK; gnu-attributes are accepted at the start
+ iff START_ATTR_OK; __auto_type is accepted iff AUTO_TYPE_OK. In
+ addition to the syntax shown, standard attributes are accepted at
+ the start iff START_STD_ATTR_OK and at the end iff END_STD_ATTR_OK;
+ unlike gnu-attributes, they are not accepted in the middle of the
+ list. (This combines various different syntax productions in the C
+ standard, and in some cases gnu-attributes and standard attributes
+ at the start may already have been parsed before this function is
+ called.)
+
+ 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, C11 6.7.1:
+ storage-class-specifier:
+ typedef
+ extern
+ static
+ auto
+ register
+ _Thread_local
+
+ (_Thread_local is new in C11.)
+
+ C99 6.7.4, C11 6.7.4:
+ function-specifier:
+ inline
+ _Noreturn
+
+ (_Noreturn is new in C11.)
+
+ C90 6.5.2, C99 6.7.2, C11 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
+ atomic-type-specifier
+
+ (_Bool and _Complex are new in C99.)
+ (atomic-type-specifier is new in C11.)
+
+ C90 6.5.3, C99 6.7.3, C11 6.7.3:
+
+ type-qualifier:
+ const
+ restrict
+ volatile
+ address-space-qualifier
+ _Atomic
+
+ (restrict is new in C99.)
+ (_Atomic is new in C11.)
+
+ GNU extensions:
+
+ declaration-specifiers:
+ gnu-attributes declaration-specifiers[opt]
+
+ type-qualifier:
+ address-space
+
+ address-space:
+ identifier recognized by the target
+
+ storage-class-specifier:
+ __thread
+
+ type-specifier:
+ typeof-specifier
+ __auto_type
+ __intN
+ _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)
+
+ atomic-type-specifier
+ _Atomic ( type-name )
+
+ Objective-C:
+
+ type-specifier:
+ class-name objc-protocol-refs[opt]
+ typedef-name objc-protocol-refs
+ objc-protocol-refs
+*/
+
+void
+c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
+ bool scspec_ok, bool typespec_ok, bool start_attr_ok,
+ bool alignspec_ok, bool auto_type_ok,
+ bool start_std_attr_ok, bool end_std_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);
+
+ if (start_std_attr_ok
+ && c_parser_nth_token_starts_std_attributes (parser, 1))
+ {
+ gcc_assert (!specs->non_std_attrs_seen_p);
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree attrs = c_parser_std_attribute_specifier_sequence (parser);
+ declspecs_add_attrs (loc, specs, attrs);
+ specs->non_std_attrs_seen_p = false;
+ }
+
+ 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)
+ && !c_parser_next_token_is_keyword (parser, RID_ALIGNAS))
+ 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_at (loc, "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_AUTO_TYPE:
+ if (!auto_type_ok)
+ goto out;
+ /* Fall through. */
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_SHORT:
+ case RID_SIGNED:
+ case RID_COMPLEX:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ case RID_DFLOAT32:
+ case RID_DFLOAT64:
+ case RID_DFLOAT128:
+ CASE_RID_FLOATN_NX:
+ case RID_BOOL:
+ case RID_FRACT:
+ case RID_ACCUM:
+ case RID_SAT:
+ case RID_INT_N_0:
+ case RID_INT_N_1:
+ case RID_INT_N_2:
+ case RID_INT_N_3:
+ 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);
+ invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec);
+ 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_ATOMIC:
+ /* C parser handling of Objective-C constructs needs
+ checking for correct lvalue-to-rvalue conversions, and
+ the code in build_modify_expr handling various
+ Objective-C cases, and that in build_unary_op handling
+ Objective-C cases for increment / decrement, also needs
+ updating; uses of TYPE_MAIN_VARIANT in objc_compare_types
+ and objc_types_are_equivalent may also need updates. */
+ if (c_dialect_objc ())
+ sorry ("%<_Atomic%> in Objective-C");
+ if (flag_isoc99)
+ pedwarn_c99 (loc, OPT_Wpedantic,
+ "ISO C99 does not support the %<_Atomic%> qualifier");
+ else
+ pedwarn_c99 (loc, OPT_Wpedantic,
+ "ISO C90 does not support the %<_Atomic%> qualifier");
+ attrs_ok = true;
+ tree value;
+ value = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ if (typespec_ok && c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ /* _Atomic ( type-name ). */
+ seen_type = true;
+ c_parser_consume_token (parser);
+ struct c_type_name *type = c_parser_type_name (parser);
+ t.kind = ctsk_typeof;
+ t.spec = error_mark_node;
+ t.expr = NULL_TREE;
+ t.expr_const_operands = true;
+ if (type != NULL)
+ t.spec = groktypename (type, &t.expr,
+ &t.expr_const_operands);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ if (t.spec != error_mark_node)
+ {
+ if (TREE_CODE (t.spec) == ARRAY_TYPE)
+ error_at (loc, "%<_Atomic%>-qualified array type");
+ else if (TREE_CODE (t.spec) == FUNCTION_TYPE)
+ error_at (loc, "%<_Atomic%>-qualified function type");
+ else if (TYPE_QUALS (t.spec) != TYPE_UNQUALIFIED)
+ error_at (loc, "%<_Atomic%> applied to a qualified type");
+ else
+ t.spec = c_build_qualified_type (t.spec, TYPE_QUAL_ATOMIC);
+ }
+ declspecs_add_type (loc, specs, t);
+ }
+ else
+ declspecs_add_qual (loc, specs, value);
+ 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_gnu_attributes (parser);
+ declspecs_add_attrs (loc, specs, attrs);
+ break;
+ case RID_ALIGNAS:
+ if (!alignspec_ok)
+ goto out;
+ align = c_parser_alignas_specifier (parser);
+ declspecs_add_alignas (loc, specs, align);
+ break;
+ case RID_GIMPLE:
+ if (! flag_gimple)
+ error_at (loc, "%<__GIMPLE%> only valid with %<-fgimple%>");
+ c_parser_consume_token (parser);
+ specs->declspec_il = cdil_gimple;
+ specs->locations[cdw_gimple] = loc;
+ c_parser_gimple_or_rtl_pass_list (parser, specs);
+ break;
+ case RID_RTL:
+ c_parser_consume_token (parser);
+ specs->declspec_il = cdil_rtl;
+ specs->locations[cdw_rtl] = loc;
+ c_parser_gimple_or_rtl_pass_list (parser, specs);
+ break;
+ default:
+ goto out;
+ }
+ }
+ out:
+ if (end_std_attr_ok
+ && c_parser_nth_token_starts_std_attributes (parser, 1))
+ specs->postfix_attrs = c_parser_std_attribute_specifier_sequence (parser);
+}
+
+/* Parse an enum specifier (C90 6.5.2.2, C99 6.7.2.2, C11 6.7.2.2).
+
+ enum-specifier:
+ enum gnu-attributes[opt] identifier[opt] { enumerator-list }
+ gnu-attributes[opt]
+ enum gnu-attributes[opt] identifier[opt] { enumerator-list , }
+ gnu-attributes[opt]
+ enum gnu-attributes[opt] identifier
+
+ The form with trailing comma is new in C99. The forms with
+ gnu-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 attribute-specifier-sequence[opt]
+ enumeration-constant attribute-specifier-sequence[opt]
+ = constant-expression
+
+ GNU Extensions:
+
+ enumerator:
+ enumeration-constant attribute-specifier-sequence[opt] gnu-attributes[opt]
+ enumeration-constant attribute-specifier-sequence[opt] gnu-attributes[opt]
+ = constant-expression
+
+*/
+
+static struct c_typespec
+c_parser_enum_specifier (c_parser *parser)
+{
+ struct c_typespec ret;
+ bool have_std_attrs;
+ tree std_attrs = NULL_TREE;
+ 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));
+ c_parser_consume_token (parser);
+ have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1);
+ if (have_std_attrs)
+ std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+ attrs = c_parser_gnu_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))
+ {
+ /* Give a nicer error for "enum {}". */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)
+ && !parser->error)
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "empty enum is invalid");
+ parser->error = true;
+ }
+ else
+ 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);
+ /* Parse any specified attributes. */
+ tree std_attrs = NULL_TREE;
+ if (c_parser_nth_token_starts_std_attributes (parser, 1))
+ std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+ tree enum_attrs = chainon (std_attrs,
+ c_parser_gnu_attributes (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);
+ if (enum_attrs)
+ decl_attributes (&TREE_PURPOSE (enum_decl), enum_attrs, 0);
+ 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)
+ pedwarn_c90 (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_gnu_attributes (parser);
+ ret.spec = finish_enum (type, nreverse (values),
+ chainon (std_attrs,
+ 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;
+ }
+ /* Attributes may only appear when the members are defined or in
+ certain forward declarations (treat enum forward declarations in
+ GNU C analogously to struct and union forward declarations in
+ standard C). */
+ if (have_std_attrs && c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+ c_parser_error (parser, "expected %<;%>");
+ ret = parser_xref_tag (ident_loc, ENUMERAL_TYPE, ident, have_std_attrs,
+ std_attrs);
+ /* 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, C11 6.7.2.1).
+
+ struct-or-union-specifier:
+ struct-or-union attribute-specifier-sequence[opt] gnu-attributes[opt]
+ identifier[opt] { struct-contents } gnu-attributes[opt]
+ struct-or-union attribute-specifier-sequence[opt] gnu-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;
+ bool have_std_attrs;
+ tree std_attrs = NULL_TREE;
+ 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);
+ have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1);
+ if (have_std_attrs)
+ std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+ attrs = c_parser_gnu_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. */
+ class 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);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ 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;
+ }
+ parens.skip_until_found_close (parser);
+ 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))
+ {
+ location_t semicolon_loc
+ = c_parser_peek_token (parser)->location;
+ gcc_rich_location richloc (semicolon_loc);
+ richloc.add_fixit_remove ();
+ pedwarn (&richloc, 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_struct, NULL);
+ 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_gnu_attributes (parser);
+ ret.spec = finish_struct (struct_loc, type, nreverse (contents),
+ chainon (std_attrs,
+ 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;
+ }
+ /* Attributes may only appear when the members are defined or in
+ certain forward declarations. */
+ if (have_std_attrs && c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+ c_parser_error (parser, "expected %<;%>");
+ /* ??? Existing practice is that GNU attributes are ignored after
+ the struct or union keyword when not defining the members. */
+ ret = parser_xref_tag (ident_loc, code, ident, have_std_attrs, std_attrs);
+ return ret;
+}
+
+/* Parse a struct-declaration (C90 6.5.2.1, C99 6.7.2.1, C11 6.7.2.1),
+ *without* the trailing semicolon.
+
+ struct-declaration:
+ attribute-specifier-sequence[opt] specifier-qualifier-list
+ attribute-specifier-sequence[opt] struct-declarator-list
+ static_assert-declaration-no-semi
+
+ specifier-qualifier-list:
+ type-specifier specifier-qualifier-list[opt]
+ type-qualifier specifier-qualifier-list[opt]
+ alignment-specifier specifier-qualifier-list[opt]
+ gnu-attributes specifier-qualifier-list[opt]
+
+ struct-declarator-list:
+ struct-declarator
+ struct-declarator-list , gnu-attributes[opt] struct-declarator
+
+ struct-declarator:
+ declarator gnu-attributes[opt]
+ declarator[opt] : constant-expression gnu-attributes[opt]
+
+ GNU extensions:
+
+ struct-declaration:
+ __extension__ struct-declaration
+ specifier-qualifier-list
+
+ Unlike the ISO C syntax, semicolons are handled elsewhere. The use
+ of gnu-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;
+ /* Strictly by the standard, we shouldn't allow _Alignas here,
+ but it appears to have been intended to allow it there, so
+ we're keeping it as it is until WG14 reaches a conclusion
+ of N1731.
+ <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1731.pdf> */
+ c_parser_declspecs (parser, specs, false, true, true,
+ true, 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_gnu_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_gnu_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++;
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ 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);
+ }
+ parens.skip_until_found_close (parser);
+ 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_isoc99)
+ pedwarn_c99 (loc, OPT_Wpedantic,
+ "ISO C99 does not support %<_Alignas%>");
+ else
+ pedwarn_c99 (loc, OPT_Wpedantic,
+ "ISO C90 does not support %<_Alignas%>");
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ 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_sizeof_or_alignof_type (loc, groktypename (type, NULL, NULL),
+ false, true, 1);
+ }
+ else
+ ret = c_parser_expr_no_commas (parser, NULL).value;
+ parens.skip_until_found_close (parser);
+ return ret;
+}
+
+/* Parse a declarator, possibly an abstract declarator (C90 6.5.4,
+ 6.5.5, C99 6.7.5, 6.7.6, C11 6.7.6, 6.7.7). 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
+ ( gnu-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
+ gnu-attributes
+ type-qualifier-list type-qualifier
+ type-qualifier-list gnu-attributes
+
+ array-declarator:
+ [ type-qualifier-list[opt] assignment-expression[opt] ]
+ [ static type-qualifier-list[opt] assignment-expression ]
+ [ type-qualifier-list static assignment-expression ]
+ [ type-qualifier-list[opt] * ]
+
+ parameter-type-list:
+ parameter-list
+ parameter-list , ...
+
+ parameter-list:
+ parameter-declaration
+ parameter-list , parameter-declaration
+
+ parameter-declaration:
+ declaration-specifiers declarator gnu-attributes[opt]
+ declaration-specifiers abstract-declarator[opt] gnu-attributes[opt]
+
+ identifier-list:
+ identifier
+ identifier-list , identifier
+
+ abstract-declarator:
+ pointer
+ pointer[opt] direct-abstract-declarator
+
+ direct-abstract-declarator:
+ ( gnu-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 gnu-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. */
+
+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,
+ false, false, true, false, 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 gnu-attributes must be read. If a declaration
+ specifier or standard attributes follow, 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 gnu-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, gnu-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);
+ if (c_parser_nth_token_starts_std_attributes (parser, 1))
+ inner->u.id.attrs = c_parser_std_attribute_specifier_sequence (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)
+ && !c_parser_nth_token_starts_std_attributes (parser, 1))
+ {
+ struct c_declarator *inner = build_id_declarator (NULL_TREE);
+ inner->id_loc = c_parser_peek_token (parser)->location;
+ 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);
+ bool have_gnu_attrs = c_parser_next_token_is_keyword (parser,
+ RID_ATTRIBUTE);
+ attrs = c_parser_gnu_attributes (parser);
+ if (kind != C_DTR_NORMAL
+ && (c_parser_next_token_starts_declspecs (parser)
+ || (!have_gnu_attrs
+ && c_parser_nth_token_starts_std_attributes (parser, 1))
+ || c_parser_next_token_is (parser, CPP_CLOSE_PAREN)))
+ {
+ struct c_arg_info *args
+ = c_parser_parms_declarator (parser, kind == C_DTR_NORMAL,
+ attrs, have_gnu_attrs);
+ if (args == NULL)
+ return NULL;
+ else
+ {
+ inner = build_id_declarator (NULL_TREE);
+ if (!(args->types
+ && args->types != error_mark_node
+ && TREE_CODE (TREE_VALUE (args->types)) == IDENTIFIER_NODE)
+ && c_parser_nth_token_starts_std_attributes (parser, 1))
+ {
+ tree std_attrs
+ = c_parser_std_attribute_specifier_sequence (parser);
+ if (std_attrs)
+ inner = build_attrs_declarator (std_attrs, inner);
+ }
+ inner = build_function_declarator (args, inner);
+ 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)
+ && !c_parser_nth_token_starts_std_attributes (parser, 1))
+ {
+ 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;
+ struct c_expr dimen;
+ dimen.value = NULL_TREE;
+ dimen.original_code = ERROR_MARK;
+ dimen.original_type = NULL_TREE;
+ c_parser_consume_token (parser);
+ c_parser_declspecs (parser, quals_attrs, false, false, true,
+ false, false, false, false, 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,
+ false, false, false, false, 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);
+ }
+ else
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ {
+ dimen.value = 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.value = NULL_TREE;
+ star_seen = true;
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ star_seen = false;
+ dimen = c_parser_expr_no_commas (parser, NULL);
+ }
+ }
+ else
+ {
+ star_seen = false;
+ dimen = c_parser_expr_no_commas (parser, NULL);
+ }
+ }
+ 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.value)
+ dimen = convert_lvalue_to_rvalue (brace_loc, dimen, true, true);
+ declarator = build_array_declarator (brace_loc, dimen.value, quals_attrs,
+ static_seen, star_seen);
+ if (declarator == NULL)
+ return NULL;
+ if (c_parser_nth_token_starts_std_attributes (parser, 1))
+ {
+ tree std_attrs
+ = c_parser_std_attribute_specifier_sequence (parser);
+ if (std_attrs)
+ inner = build_attrs_declarator (std_attrs, inner);
+ }
+ 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);
+ bool have_gnu_attrs = c_parser_next_token_is_keyword (parser,
+ RID_ATTRIBUTE);
+ attrs = c_parser_gnu_attributes (parser);
+ args = c_parser_parms_declarator (parser, id_present, attrs,
+ have_gnu_attrs);
+ if (args == NULL)
+ return NULL;
+ else
+ {
+ if (!(args->types
+ && args->types != error_mark_node
+ && TREE_CODE (TREE_VALUE (args->types)) == IDENTIFIER_NODE)
+ && c_parser_nth_token_starts_std_attributes (parser, 1))
+ {
+ tree std_attrs
+ = c_parser_std_attribute_specifier_sequence (parser);
+ if (std_attrs)
+ inner = build_attrs_declarator (std_attrs, inner);
+ }
+ 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 gnu-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.
+ HAVE_GNU_ATTRS says whether any gnu-attributes (including empty
+ attributes) were present (in which case standard attributes cannot
+ occur). */
+
+static struct c_arg_info *
+c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs,
+ bool have_gnu_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
+ && c_parser_peek_2nd_token (parser)->type != CPP_KEYWORD)
+ {
+ 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, have_gnu_attrs);
+ pop_scope ();
+ return ret;
+ }
+}
+
+/* Parse a parameter list (possibly empty), including the closing
+ parenthesis but not the opening one. ATTRS are the gnu-attributes
+ at the start of the list; if HAVE_GNU_ATTRS, there were some such
+ attributes (possibly empty, in which case ATTRS is NULL_TREE),
+ which means standard attributes cannot start 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 have_gnu_attrs)
+{
+ 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 gnu-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,
+ have_gnu_attrs);
+ attrs = NULL_TREE;
+ have_gnu_attrs = false;
+ 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 ();
+ bool new_have_gnu_attrs
+ = c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE);
+ new_attrs = c_parser_gnu_attributes (parser);
+ return c_parser_parms_list_declarator (parser, new_attrs, expr,
+ new_have_gnu_attrs);
+ }
+ 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 %<)%>",
+ UNKNOWN_LOCATION, false))
+ {
+ 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 gnu-attributes at the
+ start of the declaration if it is the first parameter;
+ HAVE_GNU_ATTRS is true if there were any gnu-attributes there (even
+ empty) there. */
+
+static struct c_parm *
+c_parser_parameter_declaration (c_parser *parser, tree attrs,
+ bool have_gnu_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_param, NULL);
+
+ if (!c_parser_next_token_starts_declspecs (parser)
+ && !c_parser_nth_token_starts_std_attributes (parser, 1))
+ {
+ 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))
+ {
+ auto_diagnostic_group d;
+ name_hint hint = lookup_name_fuzzy (token->value,
+ FUZZY_LOOKUP_TYPENAME,
+ token->location);
+ if (const char *suggestion = hint.suggestion ())
+ {
+ gcc_rich_location richloc (token->location);
+ richloc.add_fixit_replace (suggestion);
+ error_at (&richloc,
+ "unknown type name %qE; did you mean %qs?",
+ token->value, suggestion);
+ }
+ else
+ error_at (token->location, "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;
+ }
+
+ location_t start_loc = c_parser_peek_token (parser)->location;
+
+ specs = build_null_declspecs ();
+ if (attrs)
+ {
+ declspecs_add_attrs (input_location, specs, attrs);
+ attrs = NULL_TREE;
+ }
+ c_parser_declspecs (parser, specs, true, true, true, true, false,
+ !have_gnu_attrs, 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_gnu_attributes (parser);
+
+ /* Generate a location for the parameter, ranging from the start of the
+ initial token to the end of the final token.
+
+ If we have a identifier, then use it for the caret location, e.g.
+
+ extern int callee (int one, int (*two)(int, int), float three);
+ ~~~~~~^~~~~~~~~~~~~~
+
+ otherwise, reuse the start location for the caret location e.g.:
+
+ extern int callee (int one, int (*)(int, int), float three);
+ ^~~~~~~~~~~~~~~~~
+ */
+ location_t end_loc = parser->last_token_location;
+
+ /* Find any cdk_id declarator; determine if we have an identifier. */
+ c_declarator *id_declarator = declarator;
+ while (id_declarator && id_declarator->kind != cdk_id)
+ id_declarator = id_declarator->declarator;
+ location_t caret_loc = (id_declarator->u.id.id
+ ? id_declarator->id_loc
+ : start_loc);
+ location_t param_loc = make_location (caret_loc, start_loc, end_loc);
+
+ return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs),
+ declarator, param_loc);
+}
+
+/* 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
+*/
+
+static tree
+c_parser_asm_string_literal (c_parser *parser)
+{
+ tree str;
+ int save_flag = warn_overlength_strings;
+ warn_overlength_strings = 0;
+ str = c_parser_string_literal (parser, false, false).value;
+ 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));
+ c_parser_consume_token (parser);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return NULL_TREE;
+ str = c_parser_asm_string_literal (parser);
+ if (!parens.require_close (parser))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return NULL_TREE;
+ }
+ return str;
+}
+
+static tree
+c_parser_gnu_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_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_FLOATN_NX:
+ case RID_BOOL:
+ case RID_FRACT:
+ case RID_ACCUM:
+ case RID_SAT:
+ case RID_TRANSACTION_ATOMIC:
+ case RID_TRANSACTION_CANCEL:
+ case RID_ATOMIC:
+ case RID_AUTO_TYPE:
+ case RID_INT_N_0:
+ case RID_INT_N_1:
+ case RID_INT_N_2:
+ case RID_INT_N_3:
+ 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 attribute arguments. This is a common form of syntax
+ covering all currently valid GNU and standard attributes.
+
+ gnu-attribute-arguments:
+ identifier
+ identifier , nonempty-expr-list
+ expr-list
+
+ where the "identifier" must not be declared as a type. ??? Why not
+ allow identifiers declared as types to start the arguments? */
+
+static tree
+c_parser_attribute_arguments (c_parser *parser, bool takes_identifier,
+ bool require_string, bool allow_empty_args)
+{
+ vec<tree, va_gc> *expr_list;
+ tree attr_args;
+ /* 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))
+ && (takes_identifier
+ || (c_dialect_objc ()
+ && c_parser_peek_token (parser)->id_kind
+ == C_ID_CLASSNAME)))
+ {
+ 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, 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))
+ {
+ if (!allow_empty_args)
+ error_at (c_parser_peek_token (parser)->location,
+ "parentheses must be omitted if "
+ "attribute argument list is empty");
+ attr_args = NULL_TREE;
+ }
+ else if (require_string)
+ {
+ /* The only valid argument for this attribute is a string
+ literal. Handle this specially here to avoid accepting
+ string literals with excess parentheses. */
+ tree string = c_parser_string_literal (parser, false, true).value;
+ attr_args = build_tree_list (NULL_TREE, string);
+ }
+ else
+ {
+ expr_list = c_parser_expr_list (parser, false, true,
+ NULL, NULL, NULL, NULL);
+ attr_args = build_tree_list_vec (expr_list);
+ release_tree_vector (expr_list);
+ }
+ }
+ return attr_args;
+}
+
+/* Parse (possibly empty) gnu-attributes. This is a GNU extension.
+
+ gnu-attributes:
+ empty
+ gnu-attributes gnu-attribute
+
+ gnu-attribute:
+ __attribute__ ( ( gnu-attribute-list ) )
+
+ gnu-attribute-list:
+ gnu-attrib
+ gnu-attribute_list , gnu-attrib
+
+ gnu-attrib:
+ empty
+ any-word
+ any-word ( gnu-attribute-arguments )
+
+ where "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?
+ When EXPECT_COMMA is true, expect the attribute to be preceded
+ by a comma and fail if it isn't.
+ When EMPTY_OK is true, allow and consume any number of consecutive
+ commas with no attributes in between. */
+
+static tree
+c_parser_gnu_attribute (c_parser *parser, tree attrs,
+ bool expect_comma = false, bool empty_ok = true)
+{
+ bool comma_first = c_parser_next_token_is (parser, CPP_COMMA);
+ if (!comma_first
+ && !c_parser_next_token_is (parser, CPP_NAME)
+ && !c_parser_next_token_is (parser, CPP_KEYWORD))
+ return NULL_TREE;
+
+ while (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ if (!empty_ok)
+ return attrs;
+ }
+
+ tree attr_name = c_parser_gnu_attribute_any_word (parser);
+ if (attr_name == NULL_TREE)
+ return NULL_TREE;
+
+ attr_name = canonicalize_attr_name (attr_name);
+ c_parser_consume_token (parser);
+
+ tree attr;
+ if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+ {
+ if (expect_comma && !comma_first)
+ {
+ /* A comma is missing between the last attribute on the chain
+ and this one. */
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return error_mark_node;
+ }
+ attr = build_tree_list (attr_name, NULL_TREE);
+ /* Add this attribute to the list. */
+ attrs = chainon (attrs, attr);
+ return attrs;
+ }
+ c_parser_consume_token (parser);
+
+ tree attr_args
+ = c_parser_attribute_arguments (parser,
+ attribute_takes_identifier_p (attr_name),
+ false, true);
+
+ attr = build_tree_list (attr_name, attr_args);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return error_mark_node;
+ }
+
+ if (expect_comma && !comma_first)
+ {
+ /* A comma is missing between the last attribute on the chain
+ and this one. */
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return error_mark_node;
+ }
+
+ /* Add this attribute to the list. */
+ attrs = chainon (attrs, attr);
+ return attrs;
+}
+
+static tree
+c_parser_gnu_attributes (c_parser *parser)
+{
+ tree attrs = NULL_TREE;
+ while (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ {
+ bool save_translate_strings_p = parser->translate_strings_p;
+ parser->translate_strings_p = false;
+ /* Consume the `__attribute__' keyword. */
+ c_parser_consume_token (parser);
+ /* Look for the two `(' tokens. */
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ parser->translate_strings_p = save_translate_strings_p;
+ return attrs;
+ }
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ parser->translate_strings_p = save_translate_strings_p;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return attrs;
+ }
+ /* Parse the attribute list. Require a comma between successive
+ (possibly empty) attributes. */
+ for (bool expect_comma = false; ; expect_comma = true)
+ {
+ /* Parse a single attribute. */
+ tree attr = c_parser_gnu_attribute (parser, attrs, expect_comma);
+ if (attr == error_mark_node)
+ return attrs;
+ if (!attr)
+ break;
+ attrs = attr;
+ }
+
+ /* Look for the two `)' tokens. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+ else
+ {
+ parser->translate_strings_p = save_translate_strings_p;
+ 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->translate_strings_p = save_translate_strings_p;
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return attrs;
+ }
+ parser->translate_strings_p = save_translate_strings_p;
+ }
+
+ return attrs;
+}
+
+/* Parse an optional balanced token sequence.
+
+ balanced-token-sequence:
+ balanced-token
+ balanced-token-sequence balanced-token
+
+ balanced-token:
+ ( balanced-token-sequence[opt] )
+ [ balanced-token-sequence[opt] ]
+ { balanced-token-sequence[opt] }
+ any token other than ()[]{}
+*/
+
+static void
+c_parser_balanced_token_sequence (c_parser *parser)
+{
+ while (true)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ switch (token->type)
+ {
+ case CPP_OPEN_BRACE:
+ {
+ matching_braces braces;
+ braces.consume_open (parser);
+ c_parser_balanced_token_sequence (parser);
+ braces.require_close (parser);
+ break;
+ }
+
+ case CPP_OPEN_PAREN:
+ {
+ matching_parens parens;
+ parens.consume_open (parser);
+ c_parser_balanced_token_sequence (parser);
+ parens.require_close (parser);
+ break;
+ }
+
+ case CPP_OPEN_SQUARE:
+ c_parser_consume_token (parser);
+ c_parser_balanced_token_sequence (parser);
+ c_parser_require (parser, CPP_CLOSE_SQUARE, "expected %<]%>");
+ break;
+
+ case CPP_CLOSE_BRACE:
+ case CPP_CLOSE_PAREN:
+ case CPP_CLOSE_SQUARE:
+ case CPP_EOF:
+ return;
+
+ case CPP_PRAGMA:
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser, false);
+ break;
+
+ default:
+ c_parser_consume_token (parser);
+ break;
+ }
+ }
+}
+
+/* Parse standard (C2X) attributes (including GNU attributes in the
+ gnu:: namespace).
+
+ attribute-specifier-sequence:
+ attribute-specifier-sequence[opt] attribute-specifier
+
+ attribute-specifier:
+ [ [ attribute-list ] ]
+
+ attribute-list:
+ attribute[opt]
+ attribute-list, attribute[opt]
+
+ attribute:
+ attribute-token attribute-argument-clause[opt]
+
+ attribute-token:
+ standard-attribute
+ attribute-prefixed-token
+
+ standard-attribute:
+ identifier
+
+ attribute-prefixed-token:
+ attribute-prefix :: identifier
+
+ attribute-prefix:
+ identifier
+
+ attribute-argument-clause:
+ ( balanced-token-sequence[opt] )
+
+ Keywords are accepted as identifiers for this purpose.
+*/
+
+static tree
+c_parser_std_attribute (c_parser *parser, bool for_tm)
+{
+ c_token *token = c_parser_peek_token (parser);
+ tree ns, name, attribute;
+
+ /* Parse the attribute-token. */
+ if (token->type != CPP_NAME && token->type != CPP_KEYWORD)
+ {
+ c_parser_error (parser, "expected identifier");
+ return error_mark_node;
+ }
+ name = canonicalize_attr_name (token->value);
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_SCOPE))
+ {
+ ns = name;
+ c_parser_consume_token (parser);
+ token = c_parser_peek_token (parser);
+ if (token->type != CPP_NAME && token->type != CPP_KEYWORD)
+ {
+ c_parser_error (parser, "expected identifier");
+ return error_mark_node;
+ }
+ name = canonicalize_attr_name (token->value);
+ c_parser_consume_token (parser);
+ }
+ else
+ ns = NULL_TREE;
+ attribute = build_tree_list (build_tree_list (ns, name), NULL_TREE);
+
+ /* Parse the arguments, if any. */
+ const attribute_spec *as = lookup_attribute_spec (TREE_PURPOSE (attribute));
+ if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+ goto out;
+ {
+ location_t open_loc = c_parser_peek_token (parser)->location;
+ matching_parens parens;
+ parens.consume_open (parser);
+ if ((as && as->max_length == 0)
+ /* Special-case the transactional-memory attribute "outer",
+ which is specially handled but not registered as an
+ attribute, to avoid allowing arbitrary balanced token
+ sequences as arguments. */
+ || is_attribute_p ("outer", name))
+ {
+ error_at (open_loc, "%qE attribute does not take any arguments", name);
+ parens.skip_until_found_close (parser);
+ return error_mark_node;
+ }
+ /* If this is a fake attribute created to handle -Wno-attributes,
+ we must skip parsing the arguments. */
+ if (as && !attribute_ignored_p (as))
+ {
+ bool takes_identifier
+ = (ns != NULL_TREE
+ && strcmp (IDENTIFIER_POINTER (ns), "gnu") == 0
+ && attribute_takes_identifier_p (name));
+ bool require_string
+ = (ns == NULL_TREE
+ && (strcmp (IDENTIFIER_POINTER (name), "deprecated") == 0
+ || strcmp (IDENTIFIER_POINTER (name), "nodiscard") == 0));
+ TREE_VALUE (attribute)
+ = c_parser_attribute_arguments (parser, takes_identifier,
+ require_string, false);
+ }
+ else
+ c_parser_balanced_token_sequence (parser);
+ parens.require_close (parser);
+ }
+ out:
+ if (ns == NULL_TREE && !for_tm && !as)
+ {
+ /* An attribute with standard syntax and no namespace specified
+ is a constraint violation if it is not one of the known
+ standard attributes. Diagnose it here with a pedwarn and
+ then discard it to prevent a duplicate warning later. */
+ pedwarn (input_location, OPT_Wattributes, "%qE attribute ignored",
+ name);
+ return error_mark_node;
+ }
+ return attribute;
+}
+
+static tree
+c_parser_std_attribute_specifier (c_parser *parser, bool for_tm)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>"))
+ return NULL_TREE;
+ if (!c_parser_require (parser, CPP_OPEN_SQUARE, "expected %<[%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>");
+ return NULL_TREE;
+ }
+ if (!for_tm)
+ pedwarn_c11 (loc, OPT_Wpedantic,
+ "ISO C does not support %<[[]]%> attributes before C2X");
+ tree attributes = NULL_TREE;
+ while (true)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_CLOSE_SQUARE)
+ break;
+ if (token->type == CPP_COMMA)
+ {
+ c_parser_consume_token (parser);
+ continue;
+ }
+ tree attribute = c_parser_std_attribute (parser, for_tm);
+ if (attribute != error_mark_node)
+ {
+ TREE_CHAIN (attribute) = attributes;
+ attributes = attribute;
+ }
+ if (c_parser_next_token_is_not (parser, CPP_COMMA))
+ break;
+ }
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>");
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE, "expected %<]%>");
+ return nreverse (attributes);
+}
+
+/* Look past an optional balanced token sequence of raw look-ahead
+ tokens starting with the *Nth token. *N is updated to point to the
+ following token. Return true if such a sequence was found, false
+ if the tokens parsed were not balanced. */
+
+static bool
+c_parser_check_balanced_raw_token_sequence (c_parser *parser, unsigned int *n)
+{
+ while (true)
+ {
+ c_token *token = c_parser_peek_nth_token_raw (parser, *n);
+ switch (token->type)
+ {
+ case CPP_OPEN_BRACE:
+ {
+ ++*n;
+ if (c_parser_check_balanced_raw_token_sequence (parser, n))
+ {
+ token = c_parser_peek_nth_token_raw (parser, *n);
+ if (token->type == CPP_CLOSE_BRACE)
+ ++*n;
+ else
+ return false;
+ }
+ else
+ return false;
+ break;
+ }
+
+ case CPP_OPEN_PAREN:
+ {
+ ++*n;
+ if (c_parser_check_balanced_raw_token_sequence (parser, n))
+ {
+ token = c_parser_peek_nth_token_raw (parser, *n);
+ if (token->type == CPP_CLOSE_PAREN)
+ ++*n;
+ else
+ return false;
+ }
+ else
+ return false;
+ break;
+ }
+
+ case CPP_OPEN_SQUARE:
+ {
+ ++*n;
+ if (c_parser_check_balanced_raw_token_sequence (parser, n))
+ {
+ token = c_parser_peek_nth_token_raw (parser, *n);
+ if (token->type == CPP_CLOSE_SQUARE)
+ ++*n;
+ else
+ return false;
+ }
+ else
+ return false;
+ break;
+ }
+
+ case CPP_CLOSE_BRACE:
+ case CPP_CLOSE_PAREN:
+ case CPP_CLOSE_SQUARE:
+ case CPP_EOF:
+ return true;
+
+ default:
+ ++*n;
+ break;
+ }
+ }
+}
+
+/* Return whether standard attributes start with the Nth token. */
+
+static bool
+c_parser_nth_token_starts_std_attributes (c_parser *parser, unsigned int n)
+{
+ if (!(c_parser_peek_nth_token (parser, n)->type == CPP_OPEN_SQUARE
+ && c_parser_peek_nth_token (parser, n + 1)->type == CPP_OPEN_SQUARE))
+ return false;
+ /* In C, '[[' must start attributes. In Objective-C, we need to
+ check whether '[[' is matched by ']]'. */
+ if (!c_dialect_objc ())
+ return true;
+ n += 2;
+ if (!c_parser_check_balanced_raw_token_sequence (parser, &n))
+ return false;
+ c_token *token = c_parser_peek_nth_token_raw (parser, n);
+ if (token->type != CPP_CLOSE_SQUARE)
+ return false;
+ token = c_parser_peek_nth_token_raw (parser, n + 1);
+ return token->type == CPP_CLOSE_SQUARE;
+}
+
+static tree
+c_parser_std_attribute_specifier_sequence (c_parser *parser)
+{
+ tree attributes = NULL_TREE;
+ do
+ {
+ tree attrs = c_parser_std_attribute_specifier (parser, false);
+ attributes = chainon (attributes, attrs);
+ }
+ while (c_parser_nth_token_starts_std_attributes (parser, 1));
+ return attributes;
+}
+
+/* Parse a type name (C90 6.5.5, C99 6.7.6, C11 6.7.7). ALIGNAS_OK
+ says whether alignment specifiers are OK (only in cases that might
+ be the type name of a compound literal).
+
+ type-name:
+ specifier-qualifier-list abstract-declarator[opt]
+*/
+
+struct c_type_name *
+c_parser_type_name (c_parser *parser, bool alignas_ok)
+{
+ 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, alignas_ok, false,
+ false, 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, C11 6.7.9).
+
+ 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, NULL);
+ 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 = convert_lvalue_to_rvalue (loc, ret, true, true);
+ return ret;
+ }
+}
+
+/* The location of the last comma within the current initializer list,
+ or UNKNOWN_LOCATION if not within one. */
+
+location_t last_init_list_comma;
+
+/* 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 obstack *outer_obstack)
+{
+ 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));
+ matching_braces braces;
+ braces.consume_open (parser);
+ if (nested_p)
+ {
+ finish_implicit_inits (brace_loc, outer_obstack);
+ push_init_level (brace_loc, 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))
+ {
+ last_init_list_comma = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ }
+ else
+ break;
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ break;
+ }
+ }
+ c_token *next_tok = c_parser_peek_token (parser);
+ if (next_tok->type != CPP_CLOSE_BRACE)
+ {
+ ret.set_error ();
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ braces.skip_until_found_close (parser);
+ pop_init_level (brace_loc, 0, &braced_init_obstack, last_init_list_comma);
+ obstack_free (&braced_init_obstack, NULL);
+ return ret;
+ }
+ location_t close_loc = next_tok->location;
+ c_parser_consume_token (parser);
+ ret = pop_init_level (brace_loc, 0, &braced_init_obstack, close_loc);
+ obstack_free (&braced_init_obstack, NULL);
+ set_c_expr_source_range (&ret, brace_loc, close_loc);
+ 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)->location,
+ c_parser_peek_token (parser)->value,
+ c_parser_peek_token (parser)->location,
+ 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 (des_loc, c_parser_peek_token (parser)->value,
+ c_parser_peek_token (parser)->location,
+ braced_init_obstack);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ struct c_expr init;
+ init.set_error ();
+ 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 (input_location, init, false,
+ braced_init_obstack);
+ return;
+ }
+ }
+ else
+ {
+ tree first, second;
+ location_t ellipsis_loc = UNKNOWN_LOCATION; /* Quiet warning. */
+ location_t array_index_loc = UNKNOWN_LOCATION;
+ /* ??? 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 = convert_lvalue_to_rvalue (exp_loc, next,
+ true, true);
+ 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);
+ array_index_loc = c_parser_peek_token (parser)->location;
+ 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 (array_index_loc, 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))
+ {
+ pedwarn_c90 (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.set_error ();
+ 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 (input_location, 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 ());
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_BRACE) && !after)
+ init = c_parser_braced_init (parser, NULL_TREE, true,
+ braced_init_obstack);
+ else
+ {
+ init = c_parser_expr_no_commas (parser, after);
+ if (init.value != NULL_TREE
+ && TREE_CODE (init.value) != STRING_CST
+ && TREE_CODE (init.value) != COMPOUND_LITERAL_EXPR)
+ init = convert_lvalue_to_rvalue (loc, init, true, true);
+ }
+ process_init_element (loc, init, false, braced_init_obstack);
+}
+
+/* Parse a compound statement (possibly a function body) (C90 6.6.2,
+ C99 6.8.2, C11 6.8.2, C2X 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:
+ label
+ 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 gnu-attributes on the label and
+ prefix gnu-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?
+
+ OpenACC:
+
+ block-item:
+ openacc-directive
+
+ openacc-directive:
+ update-directive
+
+ OpenMP:
+
+ block-item:
+ openmp-directive
+
+ openmp-directive:
+ barrier-directive
+ flush-directive
+ taskwait-directive
+ taskyield-directive
+ cancel-directive
+ cancellation-point-directive */
+
+static tree
+c_parser_compound_statement (c_parser *parser, location_t *endlocp)
+{
+ 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);
+ location_t end_loc = c_parser_compound_statement_nostart (parser);
+ if (endlocp)
+ *endlocp = end_loc;
+
+ 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 location_t
+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))
+ {
+ location_t endloc = c_parser_peek_token (parser)->location;
+ add_debug_begin_stmt (endloc);
+ c_parser_consume_token (parser);
+ return endloc;
+ }
+ 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");
+ location_t endloc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ return endloc;
+ }
+ while (c_parser_next_token_is_not (parser, CPP_CLOSE_BRACE))
+ {
+ location_t loc = c_parser_peek_token (parser)->location;
+ loc = expansion_point_location_if_in_system_header (loc);
+ /* Standard attributes may start a label, statement or declaration. */
+ bool have_std_attrs
+ = c_parser_nth_token_starts_std_attributes (parser, 1);
+ tree std_attrs = NULL_TREE;
+ if (have_std_attrs)
+ std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+ 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, std_attrs);
+ }
+ else if (c_parser_next_tokens_start_declaration (parser)
+ || (have_std_attrs
+ && c_parser_next_token_is (parser, CPP_SEMICOLON)))
+ {
+ if (last_label)
+ pedwarn_c11 (c_parser_peek_token (parser)->location, OPT_Wpedantic,
+ "a label can only be part of a statement and "
+ "a declaration is not a statement");
+
+ mark_valid_location_for_stdc_pragma (false);
+ bool fallthru_attr_p = false;
+ c_parser_declaration_or_fndef (parser, true, !have_std_attrs,
+ true, true, true, NULL,
+ NULL, have_std_attrs, std_attrs,
+ NULL, &fallthru_attr_p);
+
+ if (last_stmt && !fallthru_attr_p)
+ pedwarn_c90 (loc, OPT_Wdeclaration_after_statement,
+ "ISO C90 forbids mixed declarations and code");
+ last_stmt = fallthru_attr_p;
+ last_label = false;
+ }
+ 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. If standard attributes have already
+ been seen, it must start a statement, not a declaration,
+ but standard attributes starting a declaration may appear
+ after __extension__. */
+ 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 (!have_std_attrs
+ && (c_token_starts_declaration (c_parser_peek_2nd_token (parser))
+ || c_parser_nth_token_starts_std_attributes (parser, 2)))
+ {
+ 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);
+ /* Following the old parser, __extension__ does not
+ disable this diagnostic. */
+ restore_extension_diagnostics (ext);
+ if (last_stmt)
+ pedwarn_c90 (loc, 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))
+ {
+ if (have_std_attrs)
+ c_parser_error (parser, "expected declaration or statement");
+ /* 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,
+ last_label ? pragma_stmt : pragma_compound,
+ NULL))
+ 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 c_parser_peek_token (parser)->location;
+ }
+ 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 c_parser_peek_token (parser)->location;
+ }
+ else
+ {
+ error_at (loc, "%<else%> without a previous %<if%>");
+ c_parser_consume_token (parser);
+ continue;
+ }
+ }
+ else
+ {
+ statement:
+ c_warn_unused_attributes (std_attrs);
+ last_label = false;
+ last_stmt = true;
+ mark_valid_location_for_stdc_pragma (false);
+ c_parser_statement_after_labels (parser, NULL);
+ }
+
+ parser->error = false;
+ }
+ if (last_label)
+ pedwarn_c11 (label_loc, OPT_Wpedantic, "label at end of compound statement");
+ location_t endloc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ /* Restore the value we started with. */
+ mark_valid_location_for_stdc_pragma (save_valid_for_pragma);
+ return endloc;
+}
+
+/* Parse all consecutive labels, possibly preceded by standard
+ attributes. In this context, a statement is required, not a
+ declaration, so attributes must be followed by a statement that is
+ not just a semicolon. */
+
+static void
+c_parser_all_labels (c_parser *parser)
+{
+ tree std_attrs = NULL;
+ if (c_parser_nth_token_starts_std_attributes (parser, 1))
+ {
+ std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ c_parser_error (parser, "expected statement");
+ }
+ 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, std_attrs);
+ std_attrs = NULL;
+ if (c_parser_nth_token_starts_std_attributes (parser, 1))
+ {
+ std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ c_parser_error (parser, "expected statement");
+ }
+ }
+ if (std_attrs)
+ c_warn_unused_attributes (std_attrs);
+}
+
+/* Parse a label (C90 6.6.1, C99 6.8.1, C11 6.8.1).
+
+ label:
+ identifier : gnu-attributes[opt]
+ case constant-expression :
+ default :
+
+ GNU extensions:
+
+ label:
+ case constant-expression ... constant-expression :
+
+ The use of gnu-attributes on labels is a GNU extension. The syntax in
+ GNU C accepts any expressions without commas, non-constant
+ expressions being rejected later. Any standard
+ attribute-specifier-sequence before the first label has been parsed
+ in the caller, to distinguish statements from declarations. Any
+ attribute-specifier-sequence after the label is parsed in this
+ function. */
+static void
+c_parser_label (c_parser *parser, tree std_attrs)
+{
+ location_t loc1 = c_parser_peek_token (parser)->location;
+ tree label = NULL_TREE;
+
+ /* Remember whether this case or a user-defined label is allowed to fall
+ through to. */
+ bool fallthrough_p = c_parser_peek_token (parser)->flags & PREV_FALLTHROUGH;
+
+ 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_gnu_attributes (parser);
+ tlab = define_label (loc2, name);
+ if (tlab)
+ {
+ decl_attributes (&tlab, attrs, 0);
+ decl_attributes (&tlab, std_attrs, 0);
+ label = add_stmt (build_stmt (loc1, LABEL_EXPR, tlab));
+ }
+ if (attrs
+ && c_parser_next_tokens_start_declaration (parser))
+ warning_at (loc2, OPT_Wattributes, "GNU-style attribute between"
+ " label and declaration appertains to the label");
+ }
+ if (label)
+ {
+ if (TREE_CODE (label) == LABEL_EXPR)
+ FALLTHROUGH_LABEL_P (LABEL_EXPR_LABEL (label)) = fallthrough_p;
+ else
+ FALLTHROUGH_LABEL_P (CASE_LABEL (label)) = fallthrough_p;
+ }
+}
+
+/* Parse a statement (C90 6.6, C99 6.8, C11 6.8).
+
+ statement:
+ labeled-statement
+ attribute-specifier-sequence[opt] compound-statement
+ expression-statement
+ attribute-specifier-sequence[opt] selection-statement
+ attribute-specifier-sequence[opt] iteration-statement
+ attribute-specifier-sequence[opt] jump-statement
+
+ labeled-statement:
+ attribute-specifier-sequence[opt] label statement
+
+ expression-statement:
+ expression[opt] ;
+ attribute-specifier-sequence expression ;
+
+ 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:
+ attribute-specifier-sequence[opt] asm-statement
+
+ jump-statement:
+ goto * expression ;
+
+ expression-statement:
+ gnu-attributes ;
+
+ Objective-C:
+
+ statement:
+ attribute-specifier-sequence[opt] objc-throw-statement
+ attribute-specifier-sequence[opt] objc-try-catch-statement
+ attribute-specifier-sequence[opt] objc-synchronized-statement
+
+ objc-throw-statement:
+ @throw expression ;
+ @throw ;
+
+ OpenACC:
+
+ statement:
+ attribute-specifier-sequence[opt] openacc-construct
+
+ openacc-construct:
+ parallel-construct
+ kernels-construct
+ data-construct
+ loop-construct
+
+ parallel-construct:
+ parallel-directive structured-block
+
+ kernels-construct:
+ kernels-directive structured-block
+
+ data-construct:
+ data-directive structured-block
+
+ loop-construct:
+ loop-directive structured-block
+
+ OpenMP:
+
+ statement:
+ attribute-specifier-sequence[opt] openmp-construct
+
+ openmp-construct:
+ parallel-construct
+ for-construct
+ simd-construct
+ for-simd-construct
+ sections-construct
+ single-construct
+ parallel-for-construct
+ parallel-for-simd-construct
+ parallel-sections-construct
+ master-construct
+ critical-construct
+ atomic-construct
+ ordered-construct
+
+ parallel-construct:
+ parallel-directive structured-block
+
+ for-construct:
+ for-directive iteration-statement
+
+ simd-construct:
+ simd-directive iteration-statements
+
+ for-simd-construct:
+ for-simd-directive iteration-statements
+
+ sections-construct:
+ sections-directive section-scope
+
+ single-construct:
+ single-directive structured-block
+
+ parallel-for-construct:
+ parallel-for-directive iteration-statement
+
+ parallel-for-simd-construct:
+ parallel-for-simd-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:
+ attribute-specifier-sequence[opt] transaction-statement
+ attribute-specifier-sequence[opt] transaction-cancel-statement
+
+ IF_P is used to track whether there's a (possibly labeled) if statement
+ which is not enclosed in braces and has an else clause. This is used to
+ implement -Wparentheses. */
+
+static void
+c_parser_statement (c_parser *parser, bool *if_p, location_t *loc_after_labels)
+{
+ c_parser_all_labels (parser);
+ if (loc_after_labels)
+ *loc_after_labels = c_parser_peek_token (parser)->location;
+ c_parser_statement_after_labels (parser, if_p, NULL);
+}
+
+/* Parse a statement, other than a labeled statement. CHAIN is a vector
+ of if-else-if conditions. All labels and standard attributes have
+ been parsed in the caller.
+
+ IF_P is used to track whether there's a (possibly labeled) if statement
+ which is not enclosed in braces and has an else clause. This is used to
+ implement -Wparentheses. */
+
+static void
+c_parser_statement_after_labels (c_parser *parser, bool *if_p,
+ vec<tree> *chain)
+{
+ 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;
+ if (if_p != NULL)
+ *if_p = false;
+
+ if (c_parser_peek_token (parser)->type != CPP_OPEN_BRACE)
+ add_debug_begin_stmt (loc);
+
+ restart:
+ 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, if_p, chain);
+ break;
+ case RID_SWITCH:
+ c_parser_switch_statement (parser, if_p);
+ break;
+ case RID_WHILE:
+ c_parser_while_statement (parser, false, 0, if_p);
+ break;
+ case RID_DO:
+ c_parser_do_statement (parser, false, 0);
+ break;
+ case RID_FOR:
+ c_parser_for_statement (parser, false, 0, if_p);
+ 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))
+ {
+ struct c_expr val;
+
+ c_parser_consume_token (parser);
+ val = c_parser_expression (parser);
+ val = convert_lvalue_to_rvalue (loc, val, false, true);
+ 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, objc_foreach_continue_label, false);
+ goto expect_semicolon;
+ case RID_BREAK:
+ c_parser_consume_token (parser);
+ stmt = c_finish_bc_stmt (loc, objc_foreach_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
+ {
+ location_t xloc = c_parser_peek_token (parser)->location;
+ struct c_expr expr = c_parser_expression_conv (parser);
+ mark_exp_read (expr.value);
+ stmt = c_finish_return (EXPR_LOC_OR_LOC (expr.value, xloc),
+ 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
+ {
+ struct c_expr expr = c_parser_expression (parser);
+ expr = convert_lvalue_to_rvalue (loc, expr, false, false);
+ expr.value = c_fully_fold (expr.value, false, NULL);
+ stmt = objc_build_throw_stmt (loc, expr.value);
+ 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;
+ case RID_ATTRIBUTE:
+ {
+ /* Allow '__attribute__((fallthrough));'. */
+ tree attrs = c_parser_gnu_attributes (parser);
+ if (attribute_fallthrough_p (attrs))
+ {
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ tree fn = build_call_expr_internal_loc (loc,
+ IFN_FALLTHROUGH,
+ void_type_node, 0);
+ add_stmt (fn);
+ /* Eat the ';'. */
+ c_parser_consume_token (parser);
+ }
+ else
+ warning_at (loc, OPT_Wattributes,
+ "%<fallthrough%> attribute not followed "
+ "by %<;%>");
+ }
+ else if (attrs != NULL_TREE)
+ warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
+ " can be applied to a null statement");
+ 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:
+ if (!c_parser_pragma (parser, pragma_stmt, if_p))
+ goto restart;
+ 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 (EXPR_LOCATION (stmt) == UNKNOWN_LOCATION)
+ protected_set_expr_location (stmt, loc);
+
+ parser->in_if_block = in_if_block;
+}
+
+/* Parse the condition from an if, do, while or for statements. */
+
+static tree
+c_parser_condition (c_parser *parser)
+{
+ location_t loc = 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;
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return error_mark_node;
+ cond = c_parser_condition (parser);
+ parens.skip_until_found_close (parser);
+ return cond;
+}
+
+/* Parse a statement which is a block in C99.
+
+ IF_P is used to track whether there's a (possibly labeled) if statement
+ which is not enclosed in braces and has an else clause. This is used to
+ implement -Wparentheses. */
+
+static tree
+c_parser_c99_block_statement (c_parser *parser, bool *if_p,
+ location_t *loc_after_labels)
+{
+ tree block = c_begin_compound_stmt (flag_isoc99);
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_statement (parser, if_p, loc_after_labels);
+ 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.
+
+ IF_P is used to track whether there's a (possibly labeled) if statement
+ which is not enclosed in braces and has an else clause. This is used to
+ implement -Wparentheses. */
+
+static tree
+c_parser_if_body (c_parser *parser, bool *if_p,
+ const token_indent_info &if_tinfo)
+{
+ tree block = c_begin_compound_stmt (flag_isoc99);
+ location_t body_loc = c_parser_peek_token (parser)->location;
+ location_t body_loc_after_labels = UNKNOWN_LOCATION;
+ token_indent_info body_tinfo
+ = get_token_indent_info (c_parser_peek_token (parser));
+
+ c_parser_all_labels (parser);
+ 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
+ {
+ body_loc_after_labels = c_parser_peek_token (parser)->location;
+ c_parser_statement_after_labels (parser, if_p);
+ }
+
+ token_indent_info next_tinfo
+ = get_token_indent_info (c_parser_peek_token (parser));
+ warn_for_misleading_indentation (if_tinfo, body_tinfo, next_tinfo);
+ if (body_loc_after_labels != UNKNOWN_LOCATION
+ && next_tinfo.type != CPP_SEMICOLON)
+ warn_for_multistatement_macros (body_loc_after_labels, next_tinfo.location,
+ if_tinfo.location, RID_IF);
+
+ 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. CHAIN is a vector
+ of if-else-if conditions. */
+
+static tree
+c_parser_else_body (c_parser *parser, const token_indent_info &else_tinfo,
+ vec<tree> *chain)
+{
+ location_t body_loc = c_parser_peek_token (parser)->location;
+ tree block = c_begin_compound_stmt (flag_isoc99);
+ token_indent_info body_tinfo
+ = get_token_indent_info (c_parser_peek_token (parser));
+ location_t body_loc_after_labels = UNKNOWN_LOCATION;
+
+ c_parser_all_labels (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
+ {
+ if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ body_loc_after_labels = c_parser_peek_token (parser)->location;
+ c_parser_statement_after_labels (parser, NULL, chain);
+ }
+
+ token_indent_info next_tinfo
+ = get_token_indent_info (c_parser_peek_token (parser));
+ warn_for_misleading_indentation (else_tinfo, body_tinfo, next_tinfo);
+ if (body_loc_after_labels != UNKNOWN_LOCATION
+ && next_tinfo.type != CPP_SEMICOLON)
+ warn_for_multistatement_macros (body_loc_after_labels, next_tinfo.location,
+ else_tinfo.location, RID_ELSE);
+
+ return c_end_compound_stmt (body_loc, block, flag_isoc99);
+}
+
+/* We might need to reclassify any previously-lexed identifier, e.g.
+ when we've left a for loop with an if-statement without else in the
+ body - we might have used a wrong scope for the token. See PR67784. */
+
+static void
+c_parser_maybe_reclassify_token (c_parser *parser)
+{
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_token *token = c_parser_peek_token (parser);
+
+ if (token->id_kind != C_ID_CLASSNAME)
+ {
+ tree decl = lookup_name (token->value);
+
+ token->id_kind = C_ID_ID;
+ if (decl)
+ {
+ if (TREE_CODE (decl) == TYPE_DECL)
+ token->id_kind = C_ID_TYPENAME;
+ }
+ 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)
+ {
+ token->value = objc_interface_decl;
+ token->id_kind = C_ID_CLASSNAME;
+ }
+ }
+ }
+ }
+}
+
+/* Parse an if statement (C90 6.6.4, C99 6.8.4, C11 6.8.4).
+
+ if-statement:
+ if ( expression ) statement
+ if ( expression ) statement else statement
+
+ CHAIN is a vector of if-else-if conditions.
+ IF_P is used to track whether there's a (possibly labeled) if statement
+ which is not enclosed in braces and has an else clause. This is used to
+ implement -Wparentheses. */
+
+static void
+c_parser_if_statement (c_parser *parser, bool *if_p, vec<tree> *chain)
+{
+ tree block;
+ location_t loc;
+ tree cond;
+ bool nested_if = false;
+ tree first_body, second_body;
+ bool in_if_block;
+
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_IF));
+ token_indent_info if_tinfo
+ = get_token_indent_info (c_parser_peek_token (parser));
+ 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, &nested_if, if_tinfo);
+ parser->in_if_block = in_if_block;
+
+ if (warn_duplicated_cond)
+ warn_duplicated_cond_add_or_warn (EXPR_LOCATION (cond), cond, &chain);
+
+ if (c_parser_next_token_is_keyword (parser, RID_ELSE))
+ {
+ token_indent_info else_tinfo
+ = get_token_indent_info (c_parser_peek_token (parser));
+ c_parser_consume_token (parser);
+ if (warn_duplicated_cond)
+ {
+ if (c_parser_next_token_is_keyword (parser, RID_IF)
+ && chain == NULL)
+ {
+ /* We've got "if (COND) else if (COND2)". Start the
+ condition chain and add COND as the first element. */
+ chain = new vec<tree> ();
+ if (!CONSTANT_CLASS_P (cond) && !TREE_SIDE_EFFECTS (cond))
+ chain->safe_push (cond);
+ }
+ else if (!c_parser_next_token_is_keyword (parser, RID_IF))
+ /* This is if-else without subsequent if. Zap the condition
+ chain; we would have already warned at this point. */
+ vec_free (chain);
+ }
+ second_body = c_parser_else_body (parser, else_tinfo, chain);
+ /* Set IF_P to true to indicate that this if statement has an
+ else clause. This may trigger the Wparentheses warning
+ below when we get back up to the parent if statement. */
+ if (if_p != NULL)
+ *if_p = true;
+ }
+ else
+ {
+ second_body = NULL_TREE;
+
+ /* Diagnose an ambiguous else if if-then-else is nested inside
+ if-then. */
+ if (nested_if)
+ warning_at (loc, OPT_Wdangling_else,
+ "suggest explicit braces to avoid ambiguous %<else%>");
+
+ if (warn_duplicated_cond)
+ /* This if statement does not have an else clause. We don't
+ need the condition chain anymore. */
+ vec_free (chain);
+ }
+ c_finish_if_stmt (loc, cond, first_body, second_body);
+ add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
+
+ c_parser_maybe_reclassify_token (parser);
+}
+
+/* Parse a switch statement (C90 6.6.4, C99 6.8.4, C11 6.8.4).
+
+ switch-statement:
+ switch (expression) statement
+*/
+
+static void
+c_parser_switch_statement (c_parser *parser, bool *if_p)
+{
+ struct c_expr ce;
+ tree block, expr, body;
+ unsigned char save_in_statement;
+ 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);
+ bool explicit_cast_p = false;
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ switch_cond_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+ && c_token_starts_typename (c_parser_peek_2nd_token (parser)))
+ explicit_cast_p = true;
+ ce = c_parser_expression (parser);
+ ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, true);
+ expr = ce.value;
+ /* ??? expr has no valid location? */
+ parens.skip_until_found_close (parser);
+ }
+ else
+ {
+ switch_cond_loc = UNKNOWN_LOCATION;
+ expr = error_mark_node;
+ ce.original_type = error_mark_node;
+ }
+ c_start_switch (switch_loc, switch_cond_loc, expr, explicit_cast_p);
+ save_in_statement = in_statement;
+ in_statement |= IN_SWITCH_STMT;
+ location_t loc_after_labels;
+ bool open_brace_p = c_parser_peek_token (parser)->type == CPP_OPEN_BRACE;
+ body = c_parser_c99_block_statement (parser, if_p, &loc_after_labels);
+ location_t next_loc = c_parser_peek_token (parser)->location;
+ if (!open_brace_p && c_parser_peek_token (parser)->type != CPP_SEMICOLON)
+ warn_for_multistatement_macros (loc_after_labels, next_loc, switch_loc,
+ RID_SWITCH);
+ c_finish_switch (body, ce.original_type);
+ in_statement = save_in_statement;
+ add_stmt (c_end_compound_stmt (switch_loc, block, flag_isoc99));
+ c_parser_maybe_reclassify_token (parser);
+}
+
+/* Parse a while statement (C90 6.6.5, C99 6.8.5, C11 6.8.5).
+
+ while-statement:
+ while (expression) statement
+
+ IF_P is used to track whether there's a (possibly labeled) if statement
+ which is not enclosed in braces and has an else clause. This is used to
+ implement -Wparentheses. */
+
+static void
+c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
+ bool *if_p)
+{
+ tree block, cond, body;
+ unsigned char save_in_statement;
+ location_t loc;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE));
+ token_indent_info while_tinfo
+ = get_token_indent_info (c_parser_peek_token (parser));
+ 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);
+ if (ivdep && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_ivdep_kind),
+ integer_zero_node);
+ if (unroll && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_unroll_kind),
+ build_int_cst (integer_type_node, unroll));
+ save_in_statement = in_statement;
+ in_statement = IN_ITERATION_STMT;
+
+ token_indent_info body_tinfo
+ = get_token_indent_info (c_parser_peek_token (parser));
+
+ location_t loc_after_labels;
+ bool open_brace = c_parser_next_token_is (parser, CPP_OPEN_BRACE);
+ body = c_parser_c99_block_statement (parser, if_p, &loc_after_labels);
+ add_stmt (build_stmt (loc, WHILE_STMT, cond, body));
+ add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
+ c_parser_maybe_reclassify_token (parser);
+
+ token_indent_info next_tinfo
+ = get_token_indent_info (c_parser_peek_token (parser));
+ warn_for_misleading_indentation (while_tinfo, body_tinfo, next_tinfo);
+
+ if (next_tinfo.type != CPP_SEMICOLON && !open_brace)
+ warn_for_multistatement_macros (loc_after_labels, next_tinfo.location,
+ while_tinfo.location, RID_WHILE);
+
+ in_statement = save_in_statement;
+}
+
+/* Parse a do statement (C90 6.6.5, C99 6.8.5, C11 6.8.5).
+
+ do-statement:
+ do statement while ( expression ) ;
+*/
+
+static void
+c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll)
+{
+ tree block, cond, body;
+ unsigned char save_in_statement;
+ 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_in_statement = in_statement;
+ in_statement = IN_ITERATION_STMT;
+ body = c_parser_c99_block_statement (parser, NULL);
+ c_parser_require_keyword (parser, RID_WHILE, "expected %<while%>");
+ in_statement = save_in_statement;
+ cond = c_parser_paren_condition (parser);
+ if (ivdep && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_ivdep_kind),
+ integer_zero_node);
+ if (unroll && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_unroll_kind),
+ build_int_cst (integer_type_node, unroll));
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ c_parser_skip_to_end_of_block_or_statement (parser);
+
+ add_stmt (build_stmt (loc, DO_STMT, cond, body));
+ add_stmt (c_end_compound_stmt (loc, block, flag_isoc99));
+}
+
+/* Parse a for statement (C90 6.6.5, C99 6.8.5, C11 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 ';'.
+
+ IF_P is used to track whether there's a (possibly labeled) if statement
+ which is not enclosed in braces and has an else clause. This is used to
+ implement -Wparentheses. */
+
+static void
+c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
+ bool *if_p)
+{
+ tree block, cond, incr, body;
+ unsigned char save_in_statement;
+ tree save_objc_foreach_break_label, save_objc_foreach_continue_label;
+ /* 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 = loc;
+ bool is_foreach_statement = false;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR));
+ token_indent_info for_tinfo
+ = get_token_indent_info (c_parser_peek_token (parser));
+ 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;
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ /* 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_nth_token_starts_std_attributes (parser, 1))
+ {
+ 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))
+ || c_parser_nth_token_starts_std_attributes (parser, 2))
+ {
+ 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:
+ {
+ struct c_expr ce;
+ tree init_expression;
+ ce = c_parser_expression (parser);
+ init_expression = ce.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
+ {
+ ce = convert_lvalue_to_rvalue (loc, ce, true, false);
+ init_expression = ce.value;
+ 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))
+ {
+ if (ivdep)
+ {
+ c_parser_error (parser, "missing loop condition in loop "
+ "with %<GCC ivdep%> pragma");
+ cond = error_mark_node;
+ }
+ else if (unroll)
+ {
+ c_parser_error (parser, "missing loop condition in loop "
+ "with %<GCC unroll%> pragma");
+ cond = error_mark_node;
+ }
+ else
+ {
+ c_parser_consume_token (parser);
+ cond = NULL_TREE;
+ }
+ }
+ else
+ {
+ cond = c_parser_condition (parser);
+ c_parser_skip_until_found (parser, CPP_SEMICOLON,
+ "expected %<;%>");
+ }
+ if (ivdep && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_ivdep_kind),
+ integer_zero_node);
+ if (unroll && cond != error_mark_node)
+ cond = build3 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node,
+ annot_expr_unroll_kind),
+ build_int_cst (integer_type_node, unroll));
+ }
+ /* 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'. */
+ loc = c_parser_peek_token (parser)->location;
+ 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
+ {
+ struct c_expr ce = c_parser_expression (parser);
+ ce = convert_lvalue_to_rvalue (loc, ce, true, false);
+ incr = c_process_expr_stmt (loc, ce.value);
+ }
+ }
+ parens.skip_until_found_close (parser);
+ }
+ save_in_statement = in_statement;
+ if (is_foreach_statement)
+ {
+ in_statement = IN_OBJC_FOREACH;
+ save_objc_foreach_break_label = objc_foreach_break_label;
+ save_objc_foreach_continue_label = objc_foreach_continue_label;
+ objc_foreach_break_label = create_artificial_label (loc);
+ objc_foreach_continue_label = create_artificial_label (loc);
+ }
+ else
+ in_statement = IN_ITERATION_STMT;
+
+ token_indent_info body_tinfo
+ = get_token_indent_info (c_parser_peek_token (parser));
+
+ location_t loc_after_labels;
+ bool open_brace = c_parser_next_token_is (parser, CPP_OPEN_BRACE);
+ body = c_parser_c99_block_statement (parser, if_p, &loc_after_labels);
+
+ if (is_foreach_statement)
+ objc_finish_foreach_loop (for_loc, object_expression,
+ collection_expression, body,
+ objc_foreach_break_label,
+ objc_foreach_continue_label);
+ else
+ add_stmt (build_stmt (for_loc, FOR_STMT, NULL_TREE, cond, incr,
+ body, NULL_TREE));
+ add_stmt (c_end_compound_stmt (for_loc, block,
+ flag_isoc99 || c_dialect_objc ()));
+ c_parser_maybe_reclassify_token (parser);
+
+ token_indent_info next_tinfo
+ = get_token_indent_info (c_parser_peek_token (parser));
+ warn_for_misleading_indentation (for_tinfo, body_tinfo, next_tinfo);
+
+ if (next_tinfo.type != CPP_SEMICOLON && !open_brace)
+ warn_for_multistatement_macros (loc_after_labels, next_tinfo.location,
+ for_tinfo.location, RID_FOR);
+
+ in_statement = save_in_statement;
+ if (is_foreach_statement)
+ {
+ objc_foreach_break_label = save_objc_foreach_break_label;
+ objc_foreach_continue_label = save_objc_foreach_continue_label;
+ }
+}
+
+/* Parse an asm statement, a GNU extension. This is a full-blown asm
+ statement with inputs, outputs, clobbers, and volatile, inline, and goto
+ tags allowed.
+
+ asm-qualifier:
+ volatile
+ inline
+ goto
+
+ asm-qualifier-list:
+ asm-qualifier-list asm-qualifier
+ asm-qualifier
+
+ asm-statement:
+ asm asm-qualifier-list[opt] ( asm-argument ) ;
+
+ asm-argument:
+ asm-string-literal
+ asm-string-literal : asm-operands[opt]
+ asm-string-literal : asm-operands[opt] : asm-operands[opt]
+ asm-string-literal : asm-operands[opt] : asm-operands[opt] \
+ : asm-clobbers[opt]
+ asm-string-literal : : asm-operands[opt] : asm-clobbers[opt] \
+ : asm-goto-operands
+
+ The form with asm-goto-operands is valid if and only if the
+ asm-qualifier-list contains goto, and is the only allowed form in that case.
+ Duplicate asm-qualifiers are not allowed.
+
+ The :: token is considered equivalent to two consecutive : tokens. */
+
+static tree
+c_parser_asm_statement (c_parser *parser)
+{
+ tree str, outputs, inputs, clobbers, labels, ret;
+ bool simple;
+ 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);
+
+ /* Handle the asm-qualifier-list. */
+ location_t volatile_loc = UNKNOWN_LOCATION;
+ location_t inline_loc = UNKNOWN_LOCATION;
+ location_t goto_loc = UNKNOWN_LOCATION;
+ for (;;)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ location_t loc = token->location;
+ switch (token->keyword)
+ {
+ case RID_VOLATILE:
+ if (volatile_loc)
+ {
+ error_at (loc, "duplicate %<asm%> qualifier %qE", token->value);
+ inform (volatile_loc, "first seen here");
+ }
+ else
+ volatile_loc = loc;
+ c_parser_consume_token (parser);
+ continue;
+
+ case RID_INLINE:
+ if (inline_loc)
+ {
+ error_at (loc, "duplicate %<asm%> qualifier %qE", token->value);
+ inform (inline_loc, "first seen here");
+ }
+ else
+ inline_loc = loc;
+ c_parser_consume_token (parser);
+ continue;
+
+ case RID_GOTO:
+ if (goto_loc)
+ {
+ error_at (loc, "duplicate %<asm%> qualifier %qE", token->value);
+ inform (goto_loc, "first seen here");
+ }
+ else
+ goto_loc = loc;
+ c_parser_consume_token (parser);
+ continue;
+
+ case RID_CONST:
+ case RID_RESTRICT:
+ error_at (loc, "%qE is not a valid %<asm%> qualifier", token->value);
+ c_parser_consume_token (parser);
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ bool is_volatile = (volatile_loc != UNKNOWN_LOCATION);
+ bool is_inline = (inline_loc != UNKNOWN_LOCATION);
+ bool is_goto = (goto_loc != UNKNOWN_LOCATION);
+
+ ret = NULL;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ 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_next_token_is (parser, CPP_SCOPE))
+ {
+ ++section;
+ if (section == nsections)
+ {
+ c_parser_error (parser, "expected %<)%>");
+ goto error_close_paren;
+ }
+ c_parser_consume_token (parser);
+ }
+ else if (!c_parser_require (parser, CPP_COLON,
+ is_goto
+ ? G_("expected %<:%>")
+ : G_("expected %<:%> or %<)%>"),
+ UNKNOWN_LOCATION, is_goto))
+ 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_SCOPE)
+ && !c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ || section == 3)
+ switch (section)
+ {
+ case 0:
+ 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 (!parens.require_close (parser))
+ {
+ 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 (is_volatile,
+ build_asm_expr (asm_loc, str, outputs, inputs,
+ clobbers, labels, simple, is_inline));
+
+ error:
+ 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;
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return NULL_TREE;
+ expr = c_parser_expression (parser);
+ mark_exp_read (expr.value);
+ if (!parens.require_close (parser))
+ {
+ 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 a possibly concatenated sequence of string literals.
+ TRANSLATE says whether to translate them to the execution character
+ set; WIDE_OK says whether any kind of prefixed string literal is
+ permitted in this context. This code is based on that in
+ lex_string. */
+
+struct c_expr
+c_parser_string_literal (c_parser *parser, bool translate, bool wide_ok)
+{
+ struct c_expr ret;
+ size_t count;
+ struct obstack str_ob;
+ struct obstack loc_ob;
+ cpp_string str, istr, *strs;
+ c_token *tok;
+ location_t loc, last_tok_loc;
+ enum cpp_ttype type;
+ tree value, string_tree;
+
+ tok = c_parser_peek_token (parser);
+ loc = tok->location;
+ last_tok_loc = linemap_resolve_location (line_table, loc,
+ LRK_MACRO_DEFINITION_LOCATION,
+ NULL);
+ type = tok->type;
+ switch (type)
+ {
+ case CPP_STRING:
+ case CPP_WSTRING:
+ case CPP_STRING16:
+ case CPP_STRING32:
+ case CPP_UTF8STRING:
+ string_tree = tok->value;
+ break;
+
+ default:
+ c_parser_error (parser, "expected string literal");
+ ret.set_error ();
+ ret.value = NULL_TREE;
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL_TREE;
+ return ret;
+ }
+
+ /* Try to avoid the overhead of creating and destroying an obstack
+ for the common case of just one string. */
+ switch (c_parser_peek_2nd_token (parser)->type)
+ {
+ default:
+ c_parser_consume_token (parser);
+ str.text = (const unsigned char *) TREE_STRING_POINTER (string_tree);
+ str.len = TREE_STRING_LENGTH (string_tree);
+ count = 1;
+ strs = &str;
+ break;
+
+ case CPP_STRING:
+ case CPP_WSTRING:
+ case CPP_STRING16:
+ case CPP_STRING32:
+ case CPP_UTF8STRING:
+ gcc_obstack_init (&str_ob);
+ gcc_obstack_init (&loc_ob);
+ count = 0;
+ do
+ {
+ c_parser_consume_token (parser);
+ count++;
+ str.text = (const unsigned char *) TREE_STRING_POINTER (string_tree);
+ str.len = TREE_STRING_LENGTH (string_tree);
+ if (type != tok->type)
+ {
+ if (type == CPP_STRING)
+ type = tok->type;
+ else if (tok->type != CPP_STRING)
+ error ("unsupported non-standard concatenation "
+ "of string literals");
+ }
+ obstack_grow (&str_ob, &str, sizeof (cpp_string));
+ obstack_grow (&loc_ob, &last_tok_loc, sizeof (location_t));
+ tok = c_parser_peek_token (parser);
+ string_tree = tok->value;
+ last_tok_loc
+ = linemap_resolve_location (line_table, tok->location,
+ LRK_MACRO_DEFINITION_LOCATION, NULL);
+ }
+ while (tok->type == CPP_STRING
+ || tok->type == CPP_WSTRING
+ || tok->type == CPP_STRING16
+ || tok->type == CPP_STRING32
+ || tok->type == CPP_UTF8STRING);
+ strs = (cpp_string *) obstack_finish (&str_ob);
+ }
+
+ if (count > 1 && !in_system_header_at (input_location))
+ warning (OPT_Wtraditional,
+ "traditional C rejects string constant concatenation");
+
+ if ((type == CPP_STRING || wide_ok)
+ && ((translate
+ ? cpp_interpret_string : cpp_interpret_string_notranslate)
+ (parse_in, strs, count, &istr, type)))
+ {
+ value = build_string (istr.len, (const char *) istr.text);
+ free (CONST_CAST (unsigned char *, istr.text));
+ if (count > 1)
+ {
+ location_t *locs = (location_t *) obstack_finish (&loc_ob);
+ gcc_assert (g_string_concat_db);
+ g_string_concat_db->record_string_concatenation (count, locs);
+ }
+ }
+ else
+ {
+ if (type != CPP_STRING && !wide_ok)
+ {
+ error_at (loc, "a wide string is invalid in this context");
+ type = CPP_STRING;
+ }
+ /* Callers cannot generally handle error_mark_node in this
+ context, so return the empty string instead. An error has
+ been issued, either above or from cpp_interpret_string. */
+ switch (type)
+ {
+ default:
+ case CPP_STRING:
+ case CPP_UTF8STRING:
+ value = build_string (1, "");
+ break;
+ case CPP_STRING16:
+ value = build_string (TYPE_PRECISION (char16_type_node)
+ / TYPE_PRECISION (char_type_node),
+ "\0"); /* char16_t is 16 bits */
+ break;
+ case CPP_STRING32:
+ value = build_string (TYPE_PRECISION (char32_type_node)
+ / TYPE_PRECISION (char_type_node),
+ "\0\0\0"); /* char32_t is 32 bits */
+ break;
+ case CPP_WSTRING:
+ value = build_string (TYPE_PRECISION (wchar_type_node)
+ / TYPE_PRECISION (char_type_node),
+ "\0\0\0"); /* widest supported wchar_t
+ is 32 bits */
+ break;
+ }
+ }
+
+ switch (type)
+ {
+ default:
+ case CPP_STRING:
+ case CPP_UTF8STRING:
+ TREE_TYPE (value) = char_array_type_node;
+ break;
+ case CPP_STRING16:
+ TREE_TYPE (value) = char16_array_type_node;
+ break;
+ case CPP_STRING32:
+ TREE_TYPE (value) = char32_array_type_node;
+ break;
+ case CPP_WSTRING:
+ TREE_TYPE (value) = wchar_array_type_node;
+ }
+ value = fix_string_type (value);
+
+ if (count > 1)
+ {
+ obstack_free (&str_ob, 0);
+ obstack_free (&loc_ob, 0);
+ }
+
+ ret.value = value;
+ ret.original_code = STRING_CST;
+ ret.original_type = NULL_TREE;
+ set_c_expr_source_range (&ret, get_range_from_loc (line_table, loc));
+ parser->seen_string_literal = true;
+ return ret;
+}
+
+/* Parse an expression other than a compound expression; that is, an
+ assignment expression (C90 6.3.16, C99 6.5.16, C11 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,
+ tree omp_atomic_lhs)
+{
+ struct c_expr lhs, rhs, ret;
+ enum tree_code code;
+ location_t op_location, exp_location;
+ bool save_in_omp_for = c_in_omp_for;
+ c_in_omp_for = false;
+ gcc_assert (!after || c_dialect_objc ());
+ lhs = c_parser_conditional_expression (parser, after, omp_atomic_lhs);
+ 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:
+ c_in_omp_for = save_in_omp_for;
+ return lhs;
+ }
+ c_parser_consume_token (parser);
+ exp_location = c_parser_peek_token (parser)->location;
+ rhs = c_parser_expr_no_commas (parser, NULL);
+ rhs = convert_lvalue_to_rvalue (exp_location, rhs, true, true);
+
+ ret.value = build_modify_expr (op_location, lhs.value, lhs.original_type,
+ code, exp_location, rhs.value,
+ rhs.original_type);
+ set_c_expr_source_range (&ret, lhs.get_start (), rhs.get_finish ());
+ if (code == NOP_EXPR)
+ ret.original_code = MODIFY_EXPR;
+ else
+ {
+ suppress_warning (ret.value, OPT_Wparentheses);
+ ret.original_code = ERROR_MARK;
+ }
+ ret.original_type = NULL;
+ c_in_omp_for = save_in_omp_for;
+ return ret;
+}
+
+/* Parse a conditional expression (C90 6.3.15, C99 6.5.15, C11 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,
+ tree omp_atomic_lhs)
+{
+ struct c_expr cond, exp1, exp2, ret;
+ location_t start, cond_loc, colon_loc;
+
+ gcc_assert (!after || c_dialect_objc ());
+
+ cond = c_parser_binary_expression (parser, after, omp_atomic_lhs);
+
+ if (c_parser_next_token_is_not (parser, CPP_QUERY))
+ return cond;
+ if (cond.value != error_mark_node)
+ start = cond.get_start ();
+ else
+ start = UNKNOWN_LOCATION;
+ cond_loc = c_parser_peek_token (parser)->location;
+ cond = convert_lvalue_to_rvalue (cond_loc, cond, true, true);
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ tree eptype = NULL_TREE;
+
+ location_t middle_loc = c_parser_peek_token (parser)->location;
+ pedwarn (middle_loc, OPT_Wpedantic,
+ "ISO C forbids omitting the middle term of a %<?:%> expression");
+ if (TREE_CODE (cond.value) == EXCESS_PRECISION_EXPR)
+ {
+ eptype = TREE_TYPE (cond.value);
+ cond.value = TREE_OPERAND (cond.value, 0);
+ }
+ tree e = cond.value;
+ while (TREE_CODE (e) == COMPOUND_EXPR)
+ e = TREE_OPERAND (e, 1);
+ warn_for_omitted_condop (middle_loc, e);
+ /* Make sure first operand is calculated only once. */
+ exp1.value = save_expr (default_conversion (cond.value));
+ if (eptype)
+ exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value);
+ exp1.original_type = NULL;
+ exp1.src_range = cond.src_range;
+ 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.set_error ();
+ 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, NULL_TREE);
+ exp2 = convert_lvalue_to_rvalue (exp2_loc, exp2, true, true);
+ }
+ c_inhibit_evaluation_warnings -= cond.value == truthvalue_true_node;
+ location_t loc1 = make_location (exp1.get_start (), exp1.src_range);
+ location_t loc2 = make_location (exp2.get_start (), exp2.src_range);
+ if (__builtin_expect (omp_atomic_lhs != NULL, 0)
+ && (TREE_CODE (cond.value) == GT_EXPR
+ || TREE_CODE (cond.value) == LT_EXPR
+ || TREE_CODE (cond.value) == EQ_EXPR)
+ && c_tree_equal (exp2.value, omp_atomic_lhs)
+ && (c_tree_equal (TREE_OPERAND (cond.value, 0), omp_atomic_lhs)
+ || c_tree_equal (TREE_OPERAND (cond.value, 1), omp_atomic_lhs)))
+ ret.value = build3_loc (colon_loc, COND_EXPR, TREE_TYPE (omp_atomic_lhs),
+ cond.value, exp1.value, exp2.value);
+ else
+ ret.value
+ = build_conditional_expr (colon_loc, cond.value,
+ cond.original_code == C_MAYBE_CONST_EXPR,
+ exp1.value, exp1.original_type, loc1,
+ exp2.value, exp2.original_type, loc2);
+ 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);
+ }
+ set_c_expr_source_range (&ret, start, exp2.get_finish ());
+ 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, C11 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.
+
+ OMP_ATOMIC_LHS is NULL, unless parsing OpenMP #pragma omp atomic,
+ when it should be the unfolded lhs. In a valid OpenMP source,
+ one of the operands of the toplevel binary expression must be equal
+ to it. In that case, just return a build2 created binary operation
+ rather than result of parser_build_binary_op.
+
+ 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,
+ tree omp_atomic_lhs)
+{
+ /* 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;
+ /* The sizeof argument if expr.original_code == {PAREN_,}SIZEOF_EXPR. */
+ tree sizeof_arg;
+ } 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; \
+ case TRUNC_DIV_EXPR: \
+ if ((stack[sp - 1].expr.original_code == SIZEOF_EXPR \
+ || stack[sp - 1].expr.original_code == PAREN_SIZEOF_EXPR) \
+ && (stack[sp].expr.original_code == SIZEOF_EXPR \
+ || stack[sp].expr.original_code == PAREN_SIZEOF_EXPR)) \
+ { \
+ tree type0 = stack[sp - 1].sizeof_arg; \
+ tree type1 = stack[sp].sizeof_arg; \
+ tree first_arg = type0; \
+ if (!TYPE_P (type0)) \
+ type0 = TREE_TYPE (type0); \
+ if (!TYPE_P (type1)) \
+ type1 = TREE_TYPE (type1); \
+ if (POINTER_TYPE_P (type0) \
+ && comptypes (TREE_TYPE (type0), type1) \
+ && !(TREE_CODE (first_arg) == PARM_DECL \
+ && C_ARRAY_PARAMETER (first_arg) \
+ && warn_sizeof_array_argument)) \
+ { \
+ auto_diagnostic_group d; \
+ if (warning_at (stack[sp].loc, OPT_Wsizeof_pointer_div, \
+ "division %<sizeof (%T) / sizeof (%T)%> " \
+ "does not compute the number of array " \
+ "elements", \
+ type0, type1)) \
+ if (DECL_P (first_arg)) \
+ inform (DECL_SOURCE_LOCATION (first_arg), \
+ "first %<sizeof%> operand was declared here"); \
+ } \
+ else if (TREE_CODE (type0) == ARRAY_TYPE \
+ && !char_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (type0))) \
+ && stack[sp].expr.original_code != PAREN_SIZEOF_EXPR) \
+ maybe_warn_sizeof_array_div (stack[sp].loc, first_arg, type0, \
+ stack[sp].sizeof_arg, type1); \
+ } \
+ break; \
+ default: \
+ break; \
+ } \
+ stack[sp - 1].expr \
+ = convert_lvalue_to_rvalue (stack[sp - 1].loc, \
+ stack[sp - 1].expr, true, true); \
+ stack[sp].expr \
+ = convert_lvalue_to_rvalue (stack[sp].loc, \
+ stack[sp].expr, true, true); \
+ if (__builtin_expect (omp_atomic_lhs != NULL_TREE, 0) && sp == 1 \
+ && ((c_parser_next_token_is (parser, CPP_SEMICOLON) \
+ && ((1 << stack[sp].prec) \
+ & ((1 << PREC_BITOR) | (1 << PREC_BITXOR) \
+ | (1 << PREC_BITAND) | (1 << PREC_SHIFT) \
+ | (1 << PREC_ADD) | (1 << PREC_MULT) \
+ | (1 << PREC_EQ)))) \
+ || ((c_parser_next_token_is (parser, CPP_QUERY) \
+ || (omp_atomic_lhs == void_list_node \
+ && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))) \
+ && (stack[sp].prec == PREC_REL || stack[sp].prec == PREC_EQ)))\
+ && stack[sp].op != TRUNC_MOD_EXPR \
+ && stack[sp].op != GE_EXPR \
+ && stack[sp].op != LE_EXPR \
+ && stack[sp].op != NE_EXPR \
+ && stack[0].expr.value != error_mark_node \
+ && stack[1].expr.value != error_mark_node \
+ && (omp_atomic_lhs == void_list_node \
+ || c_tree_equal (stack[0].expr.value, omp_atomic_lhs) \
+ || c_tree_equal (stack[1].expr.value, omp_atomic_lhs) \
+ || (stack[sp].op == EQ_EXPR \
+ && c_parser_peek_2nd_token (parser)->keyword == RID_IF))) \
+ { \
+ tree t = make_node (stack[1].op); \
+ TREE_TYPE (t) = TREE_TYPE (stack[0].expr.value); \
+ TREE_OPERAND (t, 0) = stack[0].expr.value; \
+ TREE_OPERAND (t, 1) = stack[1].expr.value; \
+ stack[0].expr.value = t; \
+ } \
+ else \
+ stack[sp - 1].expr = parser_build_binary_op (stack[sp].loc, \
+ stack[sp].op, \
+ stack[sp - 1].expr, \
+ stack[sp].expr); \
+ sp--; \
+ } while (0)
+ gcc_assert (!after || c_dialect_objc ());
+ stack[0].loc = c_parser_peek_token (parser)->location;
+ stack[0].expr = c_parser_cast_expression (parser, after);
+ stack[0].prec = PREC_NONE;
+ stack[0].sizeof_arg = c_last_sizeof_arg;
+ sp = 0;
+ while (true)
+ {
+ enum c_parser_prec oprec;
+ enum tree_code ocode;
+ source_range src_range;
+ 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)
+ POP;
+ c_parser_consume_token (parser);
+ switch (ocode)
+ {
+ case TRUTH_ANDIF_EXPR:
+ src_range = stack[sp].expr.src_range;
+ stack[sp].expr
+ = convert_lvalue_to_rvalue (stack[sp].loc,
+ stack[sp].expr, true, true);
+ 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);
+ set_c_expr_source_range (&stack[sp].expr, src_range);
+ break;
+ case TRUTH_ORIF_EXPR:
+ src_range = stack[sp].expr.src_range;
+ stack[sp].expr
+ = convert_lvalue_to_rvalue (stack[sp].loc,
+ stack[sp].expr, true, true);
+ 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);
+ set_c_expr_source_range (&stack[sp].expr, src_range);
+ 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].sizeof_arg = c_last_sizeof_arg;
+ }
+ out:
+ while (sp > 0)
+ POP;
+ return stack[0].expr;
+#undef POP
+}
+
+/* Parse a cast expression (C90 6.3.4, C99 6.5.4, C11 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;
+ matching_parens parens;
+ parens.consume_open (parser);
+ type_name = c_parser_type_name (parser, true);
+ parens.skip_until_found_close (parser);
+ if (type_name == NULL)
+ {
+ ret.set_error ();
+ 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);
+ if (type_name->specs->alignas_p)
+ error_at (type_name->specs->locations[cdw_alignas],
+ "alignment specified for type name in cast");
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ expr = c_parser_cast_expression (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true);
+ }
+ ret.value = c_cast_expr (cast_loc, type_name, expr.value);
+ if (ret.value && expr.value)
+ set_c_expr_source_range (&ret, cast_loc, expr.get_finish ());
+ 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, C11 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;
+ location_t finish;
+ 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);
+ finish = op.get_finish ();
+ op = convert_lvalue_to_rvalue (exp_loc, op, true, true);
+ location_t combined_loc = make_location (op_loc, op_loc, finish);
+ ret.value = build_indirect_ref (combined_loc, op.value, RO_UNARY_STAR);
+ ret.src_range.m_start = op_loc;
+ ret.src_range.m_finish = finish;
+ return ret;
+ }
+ case CPP_PLUS:
+ if (!c_dialect_objc () && !in_system_header_at (input_location))
+ 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 = convert_lvalue_to_rvalue (exp_loc, op, true, true);
+ 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 = convert_lvalue_to_rvalue (exp_loc, op, true, true);
+ 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 = convert_lvalue_to_rvalue (exp_loc, op, true, true);
+ 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 = convert_lvalue_to_rvalue (exp_loc, op, true, true);
+ 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);
+ set_c_expr_source_range (&ret, op_loc,
+ c_parser_peek_token (parser)->get_finish ());
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ ret.set_error ();
+ }
+ 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_BUILTIN_HAS_ATTRIBUTE:
+ return c_parser_has_attribute_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;
+ struct c_expr result;
+ location_t expr_loc;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_SIZEOF));
+
+ location_t start;
+ location_t finish = UNKNOWN_LOCATION;
+
+ start = c_parser_peek_token (parser)->location;
+
+ 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;
+ matching_parens parens;
+ parens.consume_open (parser);
+ expr_loc = c_parser_peek_token (parser)->location;
+ type_name = c_parser_type_name (parser, true);
+ parens.skip_until_found_close (parser);
+ finish = parser->tokens_buf[0].location;
+ if (type_name == NULL)
+ {
+ struct c_expr ret;
+ c_inhibit_evaluation_warnings--;
+ in_sizeof--;
+ ret.set_error ();
+ 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);
+ finish = expr.get_finish ();
+ goto sizeof_expr;
+ }
+ /* sizeof ( type-name ). */
+ if (type_name->specs->alignas_p)
+ error_at (type_name->specs->locations[cdw_alignas],
+ "alignment specified for type name in %<sizeof%>");
+ c_inhibit_evaluation_warnings--;
+ in_sizeof--;
+ result = c_expr_sizeof_type (expr_loc, type_name);
+ }
+ else
+ {
+ expr_loc = c_parser_peek_token (parser)->location;
+ expr = c_parser_unary_expression (parser);
+ finish = expr.get_finish ();
+ 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");
+ result = c_expr_sizeof_expr (expr_loc, expr);
+ }
+ if (finish == UNKNOWN_LOCATION)
+ finish = start;
+ set_c_expr_source_range (&result, start, finish);
+ return result;
+}
+
+/* Parse an alignof expression. */
+
+static struct c_expr
+c_parser_alignof_expression (c_parser *parser)
+{
+ struct c_expr expr;
+ location_t start_loc = c_parser_peek_token (parser)->location;
+ location_t end_loc;
+ tree alignof_spelling = c_parser_peek_token (parser)->value;
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_ALIGNOF));
+ bool is_c11_alignof = strcmp (IDENTIFIER_POINTER (alignof_spelling),
+ "_Alignof") == 0;
+ /* 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 (is_c11_alignof)
+ {
+ if (flag_isoc99)
+ pedwarn_c99 (start_loc, OPT_Wpedantic, "ISO C99 does not support %qE",
+ alignof_spelling);
+ else
+ pedwarn_c99 (start_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;
+ matching_parens parens;
+ parens.consume_open (parser);
+ loc = c_parser_peek_token (parser)->location;
+ type_name = c_parser_type_name (parser, true);
+ end_loc = c_parser_peek_token (parser)->location;
+ parens.skip_until_found_close (parser);
+ if (type_name == NULL)
+ {
+ struct c_expr ret;
+ c_inhibit_evaluation_warnings--;
+ in_alignof--;
+ ret.set_error ();
+ 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 ). */
+ if (type_name->specs->alignas_p)
+ error_at (type_name->specs->locations[cdw_alignas],
+ "alignment specified for type name in %qE",
+ alignof_spelling);
+ c_inhibit_evaluation_warnings--;
+ in_alignof--;
+ ret.value = c_sizeof_or_alignof_type (loc, groktypename (type_name,
+ NULL, NULL),
+ false, is_c11_alignof, 1);
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ set_c_expr_source_range (&ret, start_loc, end_loc);
+ return ret;
+ }
+ else
+ {
+ struct c_expr ret;
+ expr = c_parser_unary_expression (parser);
+ end_loc = expr.src_range.m_finish;
+ alignof_expr:
+ mark_exp_read (expr.value);
+ c_inhibit_evaluation_warnings--;
+ in_alignof--;
+ if (is_c11_alignof)
+ pedwarn (start_loc,
+ OPT_Wpedantic, "ISO C does not allow %<%E (expression)%>",
+ alignof_spelling);
+ ret.value = c_alignof_expr (start_loc, expr.value);
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ set_c_expr_source_range (&ret, start_loc, end_loc);
+ return ret;
+ }
+}
+
+/* Parse the __builtin_has_attribute ([expr|type], attribute-spec)
+ expression. */
+
+static struct c_expr
+c_parser_has_attribute_expression (c_parser *parser)
+{
+ gcc_assert (c_parser_next_token_is_keyword (parser,
+ RID_BUILTIN_HAS_ATTRIBUTE));
+ location_t start = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+
+ c_inhibit_evaluation_warnings++;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ c_inhibit_evaluation_warnings--;
+ in_typeof--;
+
+ struct c_expr result;
+ result.set_error ();
+ result.original_code = ERROR_MARK;
+ result.original_type = NULL;
+ return result;
+ }
+
+ /* Treat the type argument the same way as in typeof for the purposes
+ of warnings. FIXME: Generalize this so the warning refers to
+ __builtin_has_attribute rather than typeof. */
+ in_typeof++;
+
+ /* The first operand: one of DECL, EXPR, or TYPE. */
+ tree oper = NULL_TREE;
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_id))
+ {
+ struct c_type_name *tname = c_parser_type_name (parser);
+ in_typeof--;
+ if (tname)
+ {
+ oper = groktypename (tname, NULL, NULL);
+ pop_maybe_used (variably_modified_type_p (oper, NULL_TREE));
+ }
+ }
+ else
+ {
+ struct c_expr cexpr = c_parser_expr_no_commas (parser, NULL);
+ c_inhibit_evaluation_warnings--;
+ in_typeof--;
+ if (cexpr.value != error_mark_node)
+ {
+ mark_exp_read (cexpr.value);
+ oper = cexpr.value;
+ tree etype = TREE_TYPE (oper);
+ bool was_vm = variably_modified_type_p (etype, NULL_TREE);
+ /* This is returned with the type so that when the type is
+ evaluated, this can be evaluated. */
+ if (was_vm)
+ oper = c_fully_fold (oper, false, NULL);
+ pop_maybe_used (was_vm);
+ }
+ }
+
+ struct c_expr result;
+ result.original_code = ERROR_MARK;
+ result.original_type = NULL;
+
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ /* Consume the closing parenthesis if that's the next token
+ in the likely case the built-in was invoked with fewer
+ than two arguments. */
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+ c_inhibit_evaluation_warnings--;
+ result.set_error ();
+ return result;
+ }
+
+ bool save_translate_strings_p = parser->translate_strings_p;
+
+ location_t atloc = c_parser_peek_token (parser)->location;
+ /* Parse a single attribute. Require no leading comma and do not
+ allow empty attributes. */
+ tree attr = c_parser_gnu_attribute (parser, NULL_TREE, false, false);
+
+ parser->translate_strings_p = save_translate_strings_p;
+
+ location_t finish = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+
+ result.set_error ();
+ return result;
+ }
+
+ if (!attr)
+ {
+ error_at (atloc, "expected identifier");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ result.set_error ();
+ return result;
+ }
+
+ result.original_code = INTEGER_CST;
+ result.original_type = boolean_type_node;
+
+ if (has_attribute (atloc, oper, attr, default_conversion))
+ result.value = boolean_true_node;
+ else
+ result.value = boolean_false_node;
+
+ set_c_expr_source_range (&result, start, finish);
+ return result;
+}
+
+/* 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. If it returns true,
+ *OUT_CLOSE_PAREN_LOC is written to with the location of the closing
+ parenthesis. */
+static bool
+c_parser_get_builtin_args (c_parser *parser, const char *bname,
+ vec<c_expr_t, va_gc> **ret_cexpr_list,
+ bool choose_expr_p,
+ location_t *out_close_paren_loc)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ vec<c_expr_t, va_gc> *cexpr_list;
+ c_expr_t expr;
+ bool saved_force_folding_builtin_constant_p;
+
+ *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))
+ {
+ *out_close_paren_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ return true;
+ }
+
+ saved_force_folding_builtin_constant_p
+ = force_folding_builtin_constant_p;
+ force_folding_builtin_constant_p |= choose_expr_p;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ force_folding_builtin_constant_p
+ = saved_force_folding_builtin_constant_p;
+ vec_alloc (cexpr_list, 1);
+ vec_safe_push (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);
+ vec_safe_push (cexpr_list, expr);
+ }
+
+ *out_close_paren_loc = c_parser_peek_token (parser)->location;
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ return false;
+
+ *ret_cexpr_list = cexpr_list;
+ return true;
+}
+
+/* This represents a single generic-association. */
+
+struct c_generic_association
+{
+ /* The location of the starting token of the type. */
+ location_t type_location;
+ /* The association's type, or NULL_TREE for 'default'. */
+ tree type;
+ /* The association's expression. */
+ struct c_expr expression;
+};
+
+/* Parse a generic-selection. (C11 6.5.1.1).
+
+ generic-selection:
+ _Generic ( assignment-expression , generic-assoc-list )
+
+ generic-assoc-list:
+ generic-association
+ generic-assoc-list , generic-association
+
+ generic-association:
+ type-name : assignment-expression
+ default : assignment-expression
+*/
+
+static struct c_expr
+c_parser_generic_selection (c_parser *parser)
+{
+ struct c_expr selector, error_expr;
+ tree selector_type;
+ struct c_generic_association matched_assoc;
+ int match_found = -1;
+ location_t generic_loc, selector_loc;
+
+ error_expr.original_code = ERROR_MARK;
+ error_expr.original_type = NULL;
+ error_expr.set_error ();
+ matched_assoc.type_location = UNKNOWN_LOCATION;
+ matched_assoc.type = NULL_TREE;
+ matched_assoc.expression = error_expr;
+
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_GENERIC));
+ generic_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ if (flag_isoc99)
+ pedwarn_c99 (generic_loc, OPT_Wpedantic,
+ "ISO C99 does not support %<_Generic%>");
+ else
+ pedwarn_c99 (generic_loc, OPT_Wpedantic,
+ "ISO C90 does not support %<_Generic%>");
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return error_expr;
+
+ c_inhibit_evaluation_warnings++;
+ selector_loc = c_parser_peek_token (parser)->location;
+ selector = c_parser_expr_no_commas (parser, NULL);
+ selector = default_function_array_conversion (selector_loc, selector);
+ c_inhibit_evaluation_warnings--;
+
+ if (selector.value == error_mark_node)
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return selector;
+ }
+ mark_exp_read (selector.value);
+ selector_type = TREE_TYPE (selector.value);
+ /* In ISO C terms, rvalues (including the controlling expression of
+ _Generic) do not have qualified types. */
+ if (TREE_CODE (selector_type) != ARRAY_TYPE)
+ selector_type = TYPE_MAIN_VARIANT (selector_type);
+ /* In ISO C terms, _Noreturn is not part of the type of expressions
+ such as &abort, but in GCC it is represented internally as a type
+ qualifier. */
+ if (FUNCTION_POINTER_TYPE_P (selector_type)
+ && TYPE_QUALS (TREE_TYPE (selector_type)) != TYPE_UNQUALIFIED)
+ selector_type
+ = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (selector_type)));
+
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return error_expr;
+ }
+
+ auto_vec<c_generic_association> associations;
+ while (1)
+ {
+ struct c_generic_association assoc, *iter;
+ unsigned int ix;
+ c_token *token = c_parser_peek_token (parser);
+
+ assoc.type_location = token->location;
+ if (token->type == CPP_KEYWORD && token->keyword == RID_DEFAULT)
+ {
+ c_parser_consume_token (parser);
+ assoc.type = NULL_TREE;
+ }
+ else
+ {
+ struct c_type_name *type_name;
+
+ type_name = c_parser_type_name (parser);
+ if (type_name == NULL)
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return error_expr;
+ }
+ assoc.type = groktypename (type_name, NULL, NULL);
+ if (assoc.type == error_mark_node)
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return error_expr;
+ }
+
+ if (TREE_CODE (assoc.type) == FUNCTION_TYPE)
+ error_at (assoc.type_location,
+ "%<_Generic%> association has function type");
+ else if (!COMPLETE_TYPE_P (assoc.type))
+ error_at (assoc.type_location,
+ "%<_Generic%> association has incomplete type");
+
+ if (variably_modified_type_p (assoc.type, NULL_TREE))
+ error_at (assoc.type_location,
+ "%<_Generic%> association has "
+ "variable length type");
+ }
+
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return error_expr;
+ }
+
+ assoc.expression = c_parser_expr_no_commas (parser, NULL);
+ if (assoc.expression.value == error_mark_node)
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return error_expr;
+ }
+
+ for (ix = 0; associations.iterate (ix, &iter); ++ix)
+ {
+ if (assoc.type == NULL_TREE)
+ {
+ if (iter->type == NULL_TREE)
+ {
+ error_at (assoc.type_location,
+ "duplicate %<default%> case in %<_Generic%>");
+ inform (iter->type_location, "original %<default%> is here");
+ }
+ }
+ else if (iter->type != NULL_TREE)
+ {
+ if (comptypes (assoc.type, iter->type))
+ {
+ error_at (assoc.type_location,
+ "%<_Generic%> specifies two compatible types");
+ inform (iter->type_location, "compatible type is here");
+ }
+ }
+ }
+
+ if (assoc.type == NULL_TREE)
+ {
+ if (match_found < 0)
+ {
+ matched_assoc = assoc;
+ match_found = associations.length ();
+ }
+ }
+ else if (comptypes (assoc.type, selector_type))
+ {
+ if (match_found < 0 || matched_assoc.type == NULL_TREE)
+ {
+ matched_assoc = assoc;
+ match_found = associations.length ();
+ }
+ else
+ {
+ error_at (assoc.type_location,
+ "%<_Generic%> selector matches multiple associations");
+ inform (matched_assoc.type_location,
+ "other match is here");
+ }
+ }
+
+ associations.safe_push (assoc);
+
+ if (c_parser_peek_token (parser)->type != CPP_COMMA)
+ break;
+ c_parser_consume_token (parser);
+ }
+
+ unsigned int ix;
+ struct c_generic_association *iter;
+ FOR_EACH_VEC_ELT (associations, ix, iter)
+ if (ix != (unsigned) match_found)
+ mark_exp_read (iter->expression.value);
+
+ if (!parens.require_close (parser))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return error_expr;
+ }
+
+ if (match_found < 0)
+ {
+ error_at (selector_loc, "%<_Generic%> selector of type %qT is not "
+ "compatible with any association",
+ selector_type);
+ return error_expr;
+ }
+
+ return matched_assoc.expression;
+}
+
+/* Check the validity of a function pointer argument *EXPR (argument
+ position POS) to __builtin_tgmath. Return the number of function
+ arguments if possibly valid; return 0 having reported an error if
+ not valid. */
+
+static unsigned int
+check_tgmath_function (c_expr *expr, unsigned int pos)
+{
+ tree type = TREE_TYPE (expr->value);
+ if (!FUNCTION_POINTER_TYPE_P (type))
+ {
+ error_at (expr->get_location (),
+ "argument %u of %<__builtin_tgmath%> is not a function pointer",
+ pos);
+ return 0;
+ }
+ type = TREE_TYPE (type);
+ if (!prototype_p (type))
+ {
+ error_at (expr->get_location (),
+ "argument %u of %<__builtin_tgmath%> is unprototyped", pos);
+ return 0;
+ }
+ if (stdarg_p (type))
+ {
+ error_at (expr->get_location (),
+ "argument %u of %<__builtin_tgmath%> has variable arguments",
+ pos);
+ return 0;
+ }
+ unsigned int nargs = 0;
+ function_args_iterator iter;
+ tree t;
+ FOREACH_FUNCTION_ARGS (type, t, iter)
+ {
+ if (t == void_type_node)
+ break;
+ nargs++;
+ }
+ if (nargs == 0)
+ {
+ error_at (expr->get_location (),
+ "argument %u of %<__builtin_tgmath%> has no arguments", pos);
+ return 0;
+ }
+ return nargs;
+}
+
+/* Ways in which a parameter or return value of a type-generic macro
+ may vary between the different functions the macro may call. */
+enum tgmath_parm_kind
+ {
+ tgmath_fixed, tgmath_real, tgmath_complex
+ };
+
+/* Helper function for c_parser_postfix_expression. Parse predefined
+ identifiers. */
+
+static struct c_expr
+c_parser_predefined_identifier (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ switch (c_parser_peek_token (parser)->keyword)
+ {
+ case RID_FUNCTION_NAME:
+ pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined "
+ "identifier", "__FUNCTION__");
+ break;
+ case RID_PRETTY_FUNCTION_NAME:
+ pedwarn (loc, OPT_Wpedantic, "ISO C does not support %qs predefined "
+ "identifier", "__PRETTY_FUNCTION__");
+ break;
+ case RID_C99_FUNCTION_NAME:
+ pedwarn_c90 (loc, OPT_Wpedantic, "ISO C90 does not support "
+ "%<__func__%> predefined identifier");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ struct c_expr expr;
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ expr.value = fname_decl (loc, c_parser_peek_token (parser)->keyword,
+ c_parser_peek_token (parser)->value);
+ set_c_expr_source_range (&expr, loc, loc);
+ c_parser_consume_token (parser);
+ return expr;
+}
+
+/* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2,
+ C11 6.5.1-6.5.2). Compound literals aren't handled here; callers have to
+ call c_parser_postfix_expression_after_paren_type on encountering them.
+
+ 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 )
+ generic-selection
+
+ 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_tgmath ( expr-list )
+ __builtin_complex ( assignment-expression , assignment-expression )
+ __builtin_shuffle ( assignment-expression , assignment-expression )
+ __builtin_shuffle ( assignment-expression ,
+ assignment-expression ,
+ assignment-expression, )
+ __builtin_convertvector ( assignment-expression , type-name )
+ __builtin_assoc_barrier ( 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;
+ source_range tok_range = c_parser_peek_token (parser)->get_range ();
+ 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;
+ set_c_expr_source_range (&expr, tok_range);
+ 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.set_error ();
+ }
+ break;
+ case CPP_CHAR:
+ case CPP_CHAR16:
+ case CPP_CHAR32:
+ case CPP_UTF8CHAR:
+ case CPP_WCHAR:
+ expr.value = c_parser_peek_token (parser)->value;
+ /* For the purpose of warning when a pointer is compared with
+ a zero character constant. */
+ expr.original_type = char_type_node;
+ set_c_expr_source_range (&expr, tok_range);
+ c_parser_consume_token (parser);
+ break;
+ case CPP_STRING:
+ case CPP_STRING16:
+ case CPP_STRING32:
+ case CPP_WSTRING:
+ case CPP_UTF8STRING:
+ expr = c_parser_string_literal (parser, parser->translate_strings_p,
+ true);
+ break;
+ case CPP_OBJC_STRING:
+ gcc_assert (c_dialect_objc ());
+ expr.value
+ = objc_build_string_object (c_parser_peek_token (parser)->value);
+ set_c_expr_source_range (&expr, tok_range);
+ 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);
+ set_c_expr_source_range (&expr, tok_range);
+ 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.set_error ();
+ break;
+ }
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ expr.set_error ();
+ break;
+ }
+ c_token *component_tok = c_parser_peek_token (parser);
+ component = component_tok->value;
+ location_t end_loc = component_tok->get_finish ();
+ c_parser_consume_token (parser);
+ expr.value = objc_build_class_component_ref (class_name,
+ component);
+ set_c_expr_source_range (&expr, loc, end_loc);
+ break;
+ }
+ default:
+ c_parser_error (parser, "expected expression");
+ expr.set_error ();
+ 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 we've not yet started the current function's statement list,
+ or we're in the parameter scope of an old-style function
+ declaration, statement expressions are not allowed. */
+ if (!building_stmt_list_p () || old_style_parameter_scope ())
+ {
+ 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.set_error ();
+ break;
+ }
+ stmt = c_begin_stmt_expr ();
+ c_parser_compound_statement_nostart (parser);
+ location_t close_loc = c_parser_peek_token (parser)->location;
+ 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);
+ set_c_expr_source_range (&expr, loc, close_loc);
+ mark_exp_read (expr.value);
+ }
+ else
+ {
+ /* A parenthesized expression. */
+ location_t loc_open_paren = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ expr = c_parser_expression (parser);
+ if (TREE_CODE (expr.value) == MODIFY_EXPR)
+ suppress_warning (expr.value, OPT_Wparentheses);
+ if (expr.original_code != C_MAYBE_CONST_EXPR
+ && expr.original_code != SIZEOF_EXPR)
+ expr.original_code = ERROR_MARK;
+ /* Remember that we saw ( ) around the sizeof. */
+ if (expr.original_code == SIZEOF_EXPR)
+ expr.original_code = PAREN_SIZEOF_EXPR;
+ /* Don't change EXPR.ORIGINAL_TYPE. */
+ location_t loc_close_paren = c_parser_peek_token (parser)->location;
+ set_c_expr_source_range (&expr, loc_open_paren, loc_close_paren);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>", loc_open_paren);
+ }
+ 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 = c_parser_predefined_identifier (parser);
+ break;
+ case RID_VA_ARG:
+ {
+ location_t start_loc = loc;
+ c_parser_consume_token (parser);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ expr.set_error ();
+ 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.set_error ();
+ break;
+ }
+ loc = c_parser_peek_token (parser)->location;
+ t1 = c_parser_type_name (parser);
+ location_t end_loc = c_parser_peek_token (parser)->get_finish ();
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ if (t1 == NULL)
+ {
+ expr.set_error ();
+ }
+ else
+ {
+ tree type_expr = NULL_TREE;
+ expr.value = c_build_va_arg (start_loc, e1.value, loc,
+ 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;
+ }
+ set_c_expr_source_range (&expr, start_loc, end_loc);
+ }
+ }
+ break;
+ case RID_OFFSETOF:
+ {
+ c_parser_consume_token (parser);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ expr.set_error ();
+ 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.set_error ();
+ 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))
+ {
+ c_token *comp_tok = c_parser_peek_token (parser);
+ offsetof_ref = build_component_ref
+ (loc, offsetof_ref, comp_tok->value, comp_tok->location);
+ 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;
+ }
+ c_token *comp_tok = c_parser_peek_token (parser);
+ offsetof_ref = build_component_ref
+ (loc, offsetof_ref, comp_tok->value,
+ comp_tok->location);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ struct c_expr ce;
+ tree idx;
+ loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ ce = c_parser_expression (parser);
+ ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+ idx = ce.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");
+ location_t end_loc = c_parser_peek_token (parser)->get_finish ();
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ expr.value = fold_offsetof (offsetof_ref);
+ set_c_expr_source_range (&expr, loc, end_loc);
+ }
+ break;
+ case RID_CHOOSE_EXPR:
+ {
+ vec<c_expr_t, va_gc> *cexpr_list;
+ c_expr_t *e1_p, *e2_p, *e3_p;
+ tree c;
+ location_t close_paren_loc;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_choose_expr",
+ &cexpr_list, true,
+ &close_paren_loc))
+ {
+ expr.set_error ();
+ break;
+ }
+
+ if (vec_safe_length (cexpr_list) != 3)
+ {
+ error_at (loc, "wrong number of arguments to "
+ "%<__builtin_choose_expr%>");
+ expr.set_error ();
+ 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;
+ set_c_expr_source_range (&expr, loc, close_paren_loc);
+ break;
+ }
+ case RID_TYPES_COMPATIBLE_P:
+ {
+ c_parser_consume_token (parser);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ expr.set_error ();
+ break;
+ }
+ t1 = c_parser_type_name (parser);
+ if (t1 == NULL)
+ {
+ expr.set_error ();
+ break;
+ }
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.set_error ();
+ break;
+ }
+ t2 = c_parser_type_name (parser);
+ if (t2 == NULL)
+ {
+ expr.set_error ();
+ break;
+ }
+ location_t close_paren_loc = c_parser_peek_token (parser)->location;
+ parens.skip_until_found_close (parser);
+ tree e1, e2;
+ e1 = groktypename (t1, NULL, NULL);
+ e2 = groktypename (t2, NULL, NULL);
+ if (e1 == error_mark_node || e2 == error_mark_node)
+ {
+ expr.set_error ();
+ break;
+ }
+
+ e1 = TYPE_MAIN_VARIANT (e1);
+ e2 = TYPE_MAIN_VARIANT (e2);
+
+ expr.value
+ = comptypes (e1, e2) ? integer_one_node : integer_zero_node;
+ set_c_expr_source_range (&expr, loc, close_paren_loc);
+ }
+ break;
+ case RID_BUILTIN_TGMATH:
+ {
+ vec<c_expr_t, va_gc> *cexpr_list;
+ location_t close_paren_loc;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_tgmath",
+ &cexpr_list, false,
+ &close_paren_loc))
+ {
+ expr.set_error ();
+ break;
+ }
+
+ if (vec_safe_length (cexpr_list) < 3)
+ {
+ error_at (loc, "too few arguments to %<__builtin_tgmath%>");
+ expr.set_error ();
+ break;
+ }
+
+ unsigned int i;
+ c_expr_t *p;
+ FOR_EACH_VEC_ELT (*cexpr_list, i, p)
+ *p = convert_lvalue_to_rvalue (loc, *p, true, true);
+ unsigned int nargs = check_tgmath_function (&(*cexpr_list)[0], 1);
+ if (nargs == 0)
+ {
+ expr.set_error ();
+ break;
+ }
+ if (vec_safe_length (cexpr_list) < nargs)
+ {
+ error_at (loc, "too few arguments to %<__builtin_tgmath%>");
+ expr.set_error ();
+ break;
+ }
+ unsigned int num_functions = vec_safe_length (cexpr_list) - nargs;
+ if (num_functions < 2)
+ {
+ error_at (loc, "too few arguments to %<__builtin_tgmath%>");
+ expr.set_error ();
+ break;
+ }
+
+ /* The first NUM_FUNCTIONS expressions are the function
+ pointers. The remaining NARGS expressions are the
+ arguments that are to be passed to one of those
+ functions, chosen following <tgmath.h> rules. */
+ for (unsigned int j = 1; j < num_functions; j++)
+ {
+ unsigned int this_nargs
+ = check_tgmath_function (&(*cexpr_list)[j], j + 1);
+ if (this_nargs == 0)
+ {
+ expr.set_error ();
+ goto out;
+ }
+ if (this_nargs != nargs)
+ {
+ error_at ((*cexpr_list)[j].get_location (),
+ "argument %u of %<__builtin_tgmath%> has "
+ "wrong number of arguments", j + 1);
+ expr.set_error ();
+ goto out;
+ }
+ }
+
+ /* The functions all have the same number of arguments.
+ Determine whether arguments and return types vary in
+ ways permitted for <tgmath.h> functions. */
+ /* The first entry in each of these vectors is for the
+ return type, subsequent entries for parameter
+ types. */
+ auto_vec<enum tgmath_parm_kind> parm_kind (nargs + 1);
+ auto_vec<tree> parm_first (nargs + 1);
+ auto_vec<bool> parm_complex (nargs + 1);
+ auto_vec<bool> parm_varies (nargs + 1);
+ tree first_type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[0].value));
+ tree first_ret = TYPE_MAIN_VARIANT (TREE_TYPE (first_type));
+ parm_first.quick_push (first_ret);
+ parm_complex.quick_push (TREE_CODE (first_ret) == COMPLEX_TYPE);
+ parm_varies.quick_push (false);
+ function_args_iterator iter;
+ tree t;
+ unsigned int argpos;
+ FOREACH_FUNCTION_ARGS (first_type, t, iter)
+ {
+ if (t == void_type_node)
+ break;
+ parm_first.quick_push (TYPE_MAIN_VARIANT (t));
+ parm_complex.quick_push (TREE_CODE (t) == COMPLEX_TYPE);
+ parm_varies.quick_push (false);
+ }
+ for (unsigned int j = 1; j < num_functions; j++)
+ {
+ tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value));
+ tree ret = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+ if (ret != parm_first[0])
+ {
+ parm_varies[0] = true;
+ if (!SCALAR_FLOAT_TYPE_P (parm_first[0])
+ && !COMPLEX_FLOAT_TYPE_P (parm_first[0]))
+ {
+ error_at ((*cexpr_list)[0].get_location (),
+ "invalid type-generic return type for "
+ "argument %u of %<__builtin_tgmath%>",
+ 1);
+ expr.set_error ();
+ goto out;
+ }
+ if (!SCALAR_FLOAT_TYPE_P (ret)
+ && !COMPLEX_FLOAT_TYPE_P (ret))
+ {
+ error_at ((*cexpr_list)[j].get_location (),
+ "invalid type-generic return type for "
+ "argument %u of %<__builtin_tgmath%>",
+ j + 1);
+ expr.set_error ();
+ goto out;
+ }
+ }
+ if (TREE_CODE (ret) == COMPLEX_TYPE)
+ parm_complex[0] = true;
+ argpos = 1;
+ FOREACH_FUNCTION_ARGS (type, t, iter)
+ {
+ if (t == void_type_node)
+ break;
+ t = TYPE_MAIN_VARIANT (t);
+ if (t != parm_first[argpos])
+ {
+ parm_varies[argpos] = true;
+ if (!SCALAR_FLOAT_TYPE_P (parm_first[argpos])
+ && !COMPLEX_FLOAT_TYPE_P (parm_first[argpos]))
+ {
+ error_at ((*cexpr_list)[0].get_location (),
+ "invalid type-generic type for "
+ "argument %u of argument %u of "
+ "%<__builtin_tgmath%>", argpos, 1);
+ expr.set_error ();
+ goto out;
+ }
+ if (!SCALAR_FLOAT_TYPE_P (t)
+ && !COMPLEX_FLOAT_TYPE_P (t))
+ {
+ error_at ((*cexpr_list)[j].get_location (),
+ "invalid type-generic type for "
+ "argument %u of argument %u of "
+ "%<__builtin_tgmath%>", argpos, j + 1);
+ expr.set_error ();
+ goto out;
+ }
+ }
+ if (TREE_CODE (t) == COMPLEX_TYPE)
+ parm_complex[argpos] = true;
+ argpos++;
+ }
+ }
+ enum tgmath_parm_kind max_variation = tgmath_fixed;
+ for (unsigned int j = 0; j <= nargs; j++)
+ {
+ enum tgmath_parm_kind this_kind;
+ if (parm_varies[j])
+ {
+ if (parm_complex[j])
+ max_variation = this_kind = tgmath_complex;
+ else
+ {
+ this_kind = tgmath_real;
+ if (max_variation != tgmath_complex)
+ max_variation = tgmath_real;
+ }
+ }
+ else
+ this_kind = tgmath_fixed;
+ parm_kind.quick_push (this_kind);
+ }
+ if (max_variation == tgmath_fixed)
+ {
+ error_at (loc, "function arguments of %<__builtin_tgmath%> "
+ "all have the same type");
+ expr.set_error ();
+ break;
+ }
+
+ /* Identify a parameter (not the return type) that varies,
+ including with complex types if any variation includes
+ complex types; there must be at least one such
+ parameter. */
+ unsigned int tgarg = 0;
+ for (unsigned int j = 1; j <= nargs; j++)
+ if (parm_kind[j] == max_variation)
+ {
+ tgarg = j;
+ break;
+ }
+ if (tgarg == 0)
+ {
+ error_at (loc, "function arguments of %<__builtin_tgmath%> "
+ "lack type-generic parameter");
+ expr.set_error ();
+ break;
+ }
+
+ /* Determine the type of the relevant parameter for each
+ function. */
+ auto_vec<tree> tg_type (num_functions);
+ for (unsigned int j = 0; j < num_functions; j++)
+ {
+ tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value));
+ argpos = 1;
+ FOREACH_FUNCTION_ARGS (type, t, iter)
+ {
+ if (argpos == tgarg)
+ {
+ tg_type.quick_push (TYPE_MAIN_VARIANT (t));
+ break;
+ }
+ argpos++;
+ }
+ }
+
+ /* Verify that the corresponding types are different for
+ all the listed functions. Also determine whether all
+ the types are complex, whether all the types are
+ standard or binary, and whether all the types are
+ decimal. */
+ bool all_complex = true;
+ bool all_binary = true;
+ bool all_decimal = true;
+ hash_set<tree> tg_types;
+ FOR_EACH_VEC_ELT (tg_type, i, t)
+ {
+ if (TREE_CODE (t) == COMPLEX_TYPE)
+ all_decimal = false;
+ else
+ {
+ all_complex = false;
+ if (DECIMAL_FLOAT_TYPE_P (t))
+ all_binary = false;
+ else
+ all_decimal = false;
+ }
+ if (tg_types.add (t))
+ {
+ error_at ((*cexpr_list)[i].get_location (),
+ "duplicate type-generic parameter type for "
+ "function argument %u of %<__builtin_tgmath%>",
+ i + 1);
+ expr.set_error ();
+ goto out;
+ }
+ }
+
+ /* Verify that other parameters and the return type whose
+ types vary have their types varying in the correct
+ way. */
+ for (unsigned int j = 0; j < num_functions; j++)
+ {
+ tree exp_type = tg_type[j];
+ tree exp_real_type = exp_type;
+ if (TREE_CODE (exp_type) == COMPLEX_TYPE)
+ exp_real_type = TREE_TYPE (exp_type);
+ tree type = TREE_TYPE (TREE_TYPE ((*cexpr_list)[j].value));
+ tree ret = TYPE_MAIN_VARIANT (TREE_TYPE (type));
+ if ((parm_kind[0] == tgmath_complex && ret != exp_type)
+ || (parm_kind[0] == tgmath_real && ret != exp_real_type))
+ {
+ error_at ((*cexpr_list)[j].get_location (),
+ "bad return type for function argument %u "
+ "of %<__builtin_tgmath%>", j + 1);
+ expr.set_error ();
+ goto out;
+ }
+ argpos = 1;
+ FOREACH_FUNCTION_ARGS (type, t, iter)
+ {
+ if (t == void_type_node)
+ break;
+ t = TYPE_MAIN_VARIANT (t);
+ if ((parm_kind[argpos] == tgmath_complex
+ && t != exp_type)
+ || (parm_kind[argpos] == tgmath_real
+ && t != exp_real_type))
+ {
+ error_at ((*cexpr_list)[j].get_location (),
+ "bad type for argument %u of "
+ "function argument %u of "
+ "%<__builtin_tgmath%>", argpos, j + 1);
+ expr.set_error ();
+ goto out;
+ }
+ argpos++;
+ }
+ }
+
+ /* The functions listed are a valid set of functions for a
+ <tgmath.h> macro to select between. Identify the
+ matching function, if any. First, the argument types
+ must be combined following <tgmath.h> rules. Integer
+ types are treated as _Decimal64 if any type-generic
+ argument is decimal, or if the only alternatives for
+ type-generic arguments are of decimal types, and are
+ otherwise treated as double (or _Complex double for
+ complex integer types, or _Float64 or _Complex _Float64
+ if all the return types are the same _FloatN or
+ _FloatNx type). After that adjustment, types are
+ combined following the usual arithmetic conversions.
+ If the function only accepts complex arguments, a
+ complex type is produced. */
+ bool arg_complex = all_complex;
+ bool arg_binary = all_binary;
+ bool arg_int_decimal = all_decimal;
+ for (unsigned int j = 1; j <= nargs; j++)
+ {
+ if (parm_kind[j] == tgmath_fixed)
+ continue;
+ c_expr_t *ce = &(*cexpr_list)[num_functions + j - 1];
+ tree type = TREE_TYPE (ce->value);
+ if (!INTEGRAL_TYPE_P (type)
+ && !SCALAR_FLOAT_TYPE_P (type)
+ && TREE_CODE (type) != COMPLEX_TYPE)
+ {
+ error_at (ce->get_location (),
+ "invalid type of argument %u of type-generic "
+ "function", j);
+ expr.set_error ();
+ goto out;
+ }
+ if (DECIMAL_FLOAT_TYPE_P (type))
+ {
+ arg_int_decimal = true;
+ if (all_complex)
+ {
+ error_at (ce->get_location (),
+ "decimal floating-point argument %u to "
+ "complex-only type-generic function", j);
+ expr.set_error ();
+ goto out;
+ }
+ else if (all_binary)
+ {
+ error_at (ce->get_location (),
+ "decimal floating-point argument %u to "
+ "binary-only type-generic function", j);
+ expr.set_error ();
+ goto out;
+ }
+ else if (arg_complex)
+ {
+ error_at (ce->get_location (),
+ "both complex and decimal floating-point "
+ "arguments to type-generic function");
+ expr.set_error ();
+ goto out;
+ }
+ else if (arg_binary)
+ {
+ error_at (ce->get_location (),
+ "both binary and decimal floating-point "
+ "arguments to type-generic function");
+ expr.set_error ();
+ goto out;
+ }
+ }
+ else if (TREE_CODE (type) == COMPLEX_TYPE)
+ {
+ arg_complex = true;
+ if (COMPLEX_FLOAT_TYPE_P (type))
+ arg_binary = true;
+ if (all_decimal)
+ {
+ error_at (ce->get_location (),
+ "complex argument %u to "
+ "decimal-only type-generic function", j);
+ expr.set_error ();
+ goto out;
+ }
+ else if (arg_int_decimal)
+ {
+ error_at (ce->get_location (),
+ "both complex and decimal floating-point "
+ "arguments to type-generic function");
+ expr.set_error ();
+ goto out;
+ }
+ }
+ else if (SCALAR_FLOAT_TYPE_P (type))
+ {
+ arg_binary = true;
+ if (all_decimal)
+ {
+ error_at (ce->get_location (),
+ "binary argument %u to "
+ "decimal-only type-generic function", j);
+ expr.set_error ();
+ goto out;
+ }
+ else if (arg_int_decimal)
+ {
+ error_at (ce->get_location (),
+ "both binary and decimal floating-point "
+ "arguments to type-generic function");
+ expr.set_error ();
+ goto out;
+ }
+ }
+ }
+ /* For a macro rounding its result to a narrower type, map
+ integer types to _Float64 not double if the return type
+ is a _FloatN or _FloatNx type. */
+ bool arg_int_float64 = false;
+ if (parm_kind[0] == tgmath_fixed
+ && SCALAR_FLOAT_TYPE_P (parm_first[0])
+ && float64_type_node != NULL_TREE)
+ for (unsigned int j = 0; j < NUM_FLOATN_NX_TYPES; j++)
+ if (parm_first[0] == FLOATN_TYPE_NODE (j))
+ {
+ arg_int_float64 = true;
+ break;
+ }
+ tree arg_real = NULL_TREE;
+ for (unsigned int j = 1; j <= nargs; j++)
+ {
+ if (parm_kind[j] == tgmath_fixed)
+ continue;
+ c_expr_t *ce = &(*cexpr_list)[num_functions + j - 1];
+ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (ce->value));
+ if (TREE_CODE (type) == COMPLEX_TYPE)
+ type = TREE_TYPE (type);
+ if (INTEGRAL_TYPE_P (type))
+ type = (arg_int_decimal
+ ? dfloat64_type_node
+ : arg_int_float64
+ ? float64_type_node
+ : double_type_node);
+ if (arg_real == NULL_TREE)
+ arg_real = type;
+ else
+ arg_real = common_type (arg_real, type);
+ if (arg_real == error_mark_node)
+ {
+ expr.set_error ();
+ goto out;
+ }
+ }
+ tree arg_type = (arg_complex
+ ? build_complex_type (arg_real)
+ : arg_real);
+
+ /* Look for a function to call with type-generic parameter
+ type ARG_TYPE. */
+ c_expr_t *fn = NULL;
+ for (unsigned int j = 0; j < num_functions; j++)
+ {
+ if (tg_type[j] == arg_type)
+ {
+ fn = &(*cexpr_list)[j];
+ break;
+ }
+ }
+ if (fn == NULL
+ && parm_kind[0] == tgmath_fixed
+ && SCALAR_FLOAT_TYPE_P (parm_first[0]))
+ {
+ /* Presume this is a macro that rounds its result to a
+ narrower type, and look for the first function with
+ at least the range and precision of the argument
+ type. */
+ for (unsigned int j = 0; j < num_functions; j++)
+ {
+ if (arg_complex
+ != (TREE_CODE (tg_type[j]) == COMPLEX_TYPE))
+ continue;
+ tree real_tg_type = (arg_complex
+ ? TREE_TYPE (tg_type[j])
+ : tg_type[j]);
+ if (DECIMAL_FLOAT_TYPE_P (arg_real)
+ != DECIMAL_FLOAT_TYPE_P (real_tg_type))
+ continue;
+ scalar_float_mode arg_mode
+ = SCALAR_FLOAT_TYPE_MODE (arg_real);
+ scalar_float_mode tg_mode
+ = SCALAR_FLOAT_TYPE_MODE (real_tg_type);
+ const real_format *arg_fmt = REAL_MODE_FORMAT (arg_mode);
+ const real_format *tg_fmt = REAL_MODE_FORMAT (tg_mode);
+ if (arg_fmt->b == tg_fmt->b
+ && arg_fmt->p <= tg_fmt->p
+ && arg_fmt->emax <= tg_fmt->emax
+ && (arg_fmt->emin - arg_fmt->p
+ >= tg_fmt->emin - tg_fmt->p))
+ {
+ fn = &(*cexpr_list)[j];
+ break;
+ }
+ }
+ }
+ if (fn == NULL)
+ {
+ error_at (loc, "no matching function for type-generic call");
+ expr.set_error ();
+ break;
+ }
+
+ /* Construct a call to FN. */
+ vec<tree, va_gc> *args;
+ vec_alloc (args, nargs);
+ vec<tree, va_gc> *origtypes;
+ vec_alloc (origtypes, nargs);
+ auto_vec<location_t> arg_loc (nargs);
+ for (unsigned int j = 0; j < nargs; j++)
+ {
+ c_expr_t *ce = &(*cexpr_list)[num_functions + j];
+ args->quick_push (ce->value);
+ arg_loc.quick_push (ce->get_location ());
+ origtypes->quick_push (ce->original_type);
+ }
+ expr.value = c_build_function_call_vec (loc, arg_loc, fn->value,
+ args, origtypes);
+ set_c_expr_source_range (&expr, loc, close_paren_loc);
+ break;
+ }
+ case RID_BUILTIN_CALL_WITH_STATIC_CHAIN:
+ {
+ vec<c_expr_t, va_gc> *cexpr_list;
+ c_expr_t *e2_p;
+ tree chain_value;
+ location_t close_paren_loc;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_call_with_static_chain",
+ &cexpr_list, false,
+ &close_paren_loc))
+ {
+ expr.set_error ();
+ break;
+ }
+ if (vec_safe_length (cexpr_list) != 2)
+ {
+ error_at (loc, "wrong number of arguments to "
+ "%<__builtin_call_with_static_chain%>");
+ expr.set_error ();
+ break;
+ }
+
+ expr = (*cexpr_list)[0];
+ e2_p = &(*cexpr_list)[1];
+ *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true);
+ chain_value = e2_p->value;
+ mark_exp_read (chain_value);
+
+ if (TREE_CODE (expr.value) != CALL_EXPR)
+ error_at (loc, "first argument to "
+ "%<__builtin_call_with_static_chain%> "
+ "must be a call expression");
+ else if (TREE_CODE (TREE_TYPE (chain_value)) != POINTER_TYPE)
+ error_at (loc, "second argument to "
+ "%<__builtin_call_with_static_chain%> "
+ "must be a pointer type");
+ else
+ CALL_EXPR_STATIC_CHAIN (expr.value) = chain_value;
+ set_c_expr_source_range (&expr, loc, close_paren_loc);
+ break;
+ }
+ case RID_BUILTIN_COMPLEX:
+ {
+ vec<c_expr_t, va_gc> *cexpr_list;
+ c_expr_t *e1_p, *e2_p;
+ location_t close_paren_loc;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_complex",
+ &cexpr_list, false,
+ &close_paren_loc))
+ {
+ expr.set_error ();
+ break;
+ }
+
+ if (vec_safe_length (cexpr_list) != 2)
+ {
+ error_at (loc, "wrong number of arguments to "
+ "%<__builtin_complex%>");
+ expr.set_error ();
+ break;
+ }
+
+ e1_p = &(*cexpr_list)[0];
+ e2_p = &(*cexpr_list)[1];
+
+ *e1_p = convert_lvalue_to_rvalue (loc, *e1_p, true, true);
+ if (TREE_CODE (e1_p->value) == EXCESS_PRECISION_EXPR)
+ e1_p->value = convert (TREE_TYPE (e1_p->value),
+ TREE_OPERAND (e1_p->value, 0));
+ *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true);
+ 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.set_error ();
+ 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.set_error ();
+ break;
+ }
+ pedwarn_c90 (loc, OPT_Wpedantic,
+ "ISO C90 does not support complex types");
+ expr.value = build2_loc (loc, COMPLEX_EXPR,
+ build_complex_type
+ (TYPE_MAIN_VARIANT
+ (TREE_TYPE (e1_p->value))),
+ e1_p->value, e2_p->value);
+ set_c_expr_source_range (&expr, loc, close_paren_loc);
+ break;
+ }
+ case RID_BUILTIN_SHUFFLE:
+ {
+ vec<c_expr_t, va_gc> *cexpr_list;
+ unsigned int i;
+ c_expr_t *p;
+ location_t close_paren_loc;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_shuffle",
+ &cexpr_list, false,
+ &close_paren_loc))
+ {
+ expr.set_error ();
+ break;
+ }
+
+ FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p)
+ *p = convert_lvalue_to_rvalue (loc, *p, true, true);
+
+ 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.set_error ();
+ }
+ set_c_expr_source_range (&expr, loc, close_paren_loc);
+ break;
+ }
+ case RID_BUILTIN_SHUFFLEVECTOR:
+ {
+ vec<c_expr_t, va_gc> *cexpr_list;
+ unsigned int i;
+ c_expr_t *p;
+ location_t close_paren_loc;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_get_builtin_args (parser,
+ "__builtin_shufflevector",
+ &cexpr_list, false,
+ &close_paren_loc))
+ {
+ expr.set_error ();
+ break;
+ }
+
+ FOR_EACH_VEC_SAFE_ELT (cexpr_list, i, p)
+ *p = convert_lvalue_to_rvalue (loc, *p, true, true);
+
+ if (vec_safe_length (cexpr_list) < 3)
+ {
+ error_at (loc, "wrong number of arguments to "
+ "%<__builtin_shuffle%>");
+ expr.set_error ();
+ }
+ else
+ {
+ auto_vec<tree, 16> mask;
+ for (i = 2; i < cexpr_list->length (); ++i)
+ mask.safe_push ((*cexpr_list)[i].value);
+ expr.value = c_build_shufflevector (loc, (*cexpr_list)[0].value,
+ (*cexpr_list)[1].value,
+ mask);
+ }
+ set_c_expr_source_range (&expr, loc, close_paren_loc);
+ break;
+ }
+ case RID_BUILTIN_CONVERTVECTOR:
+ {
+ location_t start_loc = loc;
+ c_parser_consume_token (parser);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ expr.set_error ();
+ break;
+ }
+ e1 = c_parser_expr_no_commas (parser, NULL);
+ mark_exp_read (e1.value);
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ expr.set_error ();
+ break;
+ }
+ loc = c_parser_peek_token (parser)->location;
+ t1 = c_parser_type_name (parser);
+ location_t end_loc = c_parser_peek_token (parser)->get_finish ();
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ if (t1 == NULL)
+ expr.set_error ();
+ else
+ {
+ tree type_expr = NULL_TREE;
+ expr.value = c_build_vec_convert (start_loc, e1.value, loc,
+ groktypename (t1, &type_expr,
+ NULL));
+ set_c_expr_source_range (&expr, start_loc, end_loc);
+ }
+ }
+ break;
+ case RID_BUILTIN_ASSOC_BARRIER:
+ {
+ location_t start_loc = loc;
+ c_parser_consume_token (parser);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ expr.set_error ();
+ break;
+ }
+ e1 = c_parser_expr_no_commas (parser, NULL);
+ mark_exp_read (e1.value);
+ location_t end_loc = c_parser_peek_token (parser)->get_finish ();
+ parens.skip_until_found_close (parser);
+ expr.value = build1_loc (loc, PAREN_EXPR, TREE_TYPE (e1.value),
+ e1.value);
+ set_c_expr_source_range (&expr, start_loc, end_loc);
+ }
+ break;
+ case RID_AT_SELECTOR:
+ {
+ gcc_assert (c_dialect_objc ());
+ c_parser_consume_token (parser);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ expr.set_error ();
+ break;
+ }
+ tree sel = c_parser_objc_selector_arg (parser);
+ location_t close_loc = c_parser_peek_token (parser)->location;
+ parens.skip_until_found_close (parser);
+ expr.value = objc_build_selector_expr (loc, sel);
+ set_c_expr_source_range (&expr, loc, close_loc);
+ }
+ break;
+ case RID_AT_PROTOCOL:
+ {
+ gcc_assert (c_dialect_objc ());
+ c_parser_consume_token (parser);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ expr.set_error ();
+ 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.set_error ();
+ break;
+ }
+ tree id = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ location_t close_loc = c_parser_peek_token (parser)->location;
+ parens.skip_until_found_close (parser);
+ expr.value = objc_build_protocol_expr (id);
+ set_c_expr_source_range (&expr, loc, close_loc);
+ }
+ break;
+ case RID_AT_ENCODE:
+ {
+ /* Extension to support C-structures in the archiver. */
+ gcc_assert (c_dialect_objc ());
+ c_parser_consume_token (parser);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ expr.set_error ();
+ break;
+ }
+ t1 = c_parser_type_name (parser);
+ if (t1 == NULL)
+ {
+ expr.set_error ();
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ break;
+ }
+ location_t close_loc = c_parser_peek_token (parser)->location;
+ parens.skip_until_found_close (parser);
+ tree type = groktypename (t1, NULL, NULL);
+ expr.value = objc_build_encode_expr (type);
+ set_c_expr_source_range (&expr, loc, close_loc);
+ }
+ break;
+ case RID_GENERIC:
+ expr = c_parser_generic_selection (parser);
+ break;
+ default:
+ c_parser_error (parser, "expected expression");
+ expr.set_error ();
+ 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);
+ location_t close_loc = c_parser_peek_token (parser)->location;
+ c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>");
+ expr.value = objc_build_message_expr (receiver, args);
+ set_c_expr_source_range (&expr, loc, close_loc);
+ break;
+ }
+ /* Else fall through to report error. */
+ /* FALLTHRU */
+ default:
+ c_parser_error (parser, "expected expression");
+ expr.set_error ();
+ break;
+ }
+ out:
+ return c_parser_postfix_expression_after_primary
+ (parser, EXPR_LOC_OR_LOC (expr.value, 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);
+ rich_location richloc (line_table, type_loc);
+ start_init (NULL_TREE, NULL, 0, &richloc);
+ 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, NULL);
+ finish_init ();
+ maybe_warn_string_init (type_loc, 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;
+ }
+
+ pedwarn_c90 (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;
+ unsigned int alignas_align = 0;
+ if (type != error_mark_node
+ && type_name->specs->align_log != -1)
+ {
+ alignas_align = 1U << type_name->specs->align_log;
+ if (alignas_align < min_align_of_type (type))
+ {
+ error_at (type_name->specs->locations[cdw_alignas],
+ "%<_Alignas%> specifiers cannot reduce "
+ "alignment of compound literal");
+ alignas_align = 0;
+ }
+ }
+ expr.value = build_compound_literal (start_loc, type, init.value, non_const,
+ alignas_align);
+ set_c_expr_source_range (&expr, init.src_range);
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ if (type != error_mark_node
+ && expr.value != error_mark_node
+ && 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;
+}
+
+/* Warn for patterns where abs-like function appears to be used incorrectly,
+ gracefully ignore any non-abs-like function. The warning location should
+ be LOC. FNDECL is the declaration of called function, it must be a
+ BUILT_IN_NORMAL function. ARG is the first and only argument of the
+ call. */
+
+static void
+warn_for_abs (location_t loc, tree fndecl, tree arg)
+{
+ /* Avoid warning in unreachable subexpressions. */
+ if (c_inhibit_evaluation_warnings)
+ return;
+
+ tree atype = TREE_TYPE (arg);
+
+ /* Casts from pointers (and thus arrays and fndecls) will generate
+ -Wint-conversion warnings. Most other wrong types hopefully lead to type
+ mismatch errors. TODO: Think about what to do with FIXED_POINT_TYPE_P
+ types and possibly other exotic types. */
+ if (!INTEGRAL_TYPE_P (atype)
+ && !SCALAR_FLOAT_TYPE_P (atype)
+ && TREE_CODE (atype) != COMPLEX_TYPE)
+ return;
+
+ enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+
+ switch (fcode)
+ {
+ case BUILT_IN_ABS:
+ case BUILT_IN_LABS:
+ case BUILT_IN_LLABS:
+ case BUILT_IN_IMAXABS:
+ if (!INTEGRAL_TYPE_P (atype))
+ {
+ if (SCALAR_FLOAT_TYPE_P (atype))
+ warning_at (loc, OPT_Wabsolute_value,
+ "using integer absolute value function %qD when "
+ "argument is of floating-point type %qT",
+ fndecl, atype);
+ else if (TREE_CODE (atype) == COMPLEX_TYPE)
+ warning_at (loc, OPT_Wabsolute_value,
+ "using integer absolute value function %qD when "
+ "argument is of complex type %qT", fndecl, atype);
+ else
+ gcc_unreachable ();
+ return;
+ }
+ if (TYPE_UNSIGNED (atype))
+ warning_at (loc, OPT_Wabsolute_value,
+ "taking the absolute value of unsigned type %qT "
+ "has no effect", atype);
+ break;
+
+ CASE_FLT_FN (BUILT_IN_FABS):
+ CASE_FLT_FN_FLOATN_NX (BUILT_IN_FABS):
+ if (!SCALAR_FLOAT_TYPE_P (atype)
+ || DECIMAL_FLOAT_MODE_P (TYPE_MODE (atype)))
+ {
+ if (INTEGRAL_TYPE_P (atype))
+ warning_at (loc, OPT_Wabsolute_value,
+ "using floating-point absolute value function %qD "
+ "when argument is of integer type %qT", fndecl, atype);
+ else if (DECIMAL_FLOAT_TYPE_P (atype))
+ warning_at (loc, OPT_Wabsolute_value,
+ "using floating-point absolute value function %qD "
+ "when argument is of decimal floating-point type %qT",
+ fndecl, atype);
+ else if (TREE_CODE (atype) == COMPLEX_TYPE)
+ warning_at (loc, OPT_Wabsolute_value,
+ "using floating-point absolute value function %qD when "
+ "argument is of complex type %qT", fndecl, atype);
+ else
+ gcc_unreachable ();
+ return;
+ }
+ break;
+
+ CASE_FLT_FN (BUILT_IN_CABS):
+ if (TREE_CODE (atype) != COMPLEX_TYPE)
+ {
+ if (INTEGRAL_TYPE_P (atype))
+ warning_at (loc, OPT_Wabsolute_value,
+ "using complex absolute value function %qD when "
+ "argument is of integer type %qT", fndecl, atype);
+ else if (SCALAR_FLOAT_TYPE_P (atype))
+ warning_at (loc, OPT_Wabsolute_value,
+ "using complex absolute value function %qD when "
+ "argument is of floating-point type %qT",
+ fndecl, atype);
+ else
+ gcc_unreachable ();
+
+ return;
+ }
+ break;
+
+ case BUILT_IN_FABSD32:
+ case BUILT_IN_FABSD64:
+ case BUILT_IN_FABSD128:
+ if (!DECIMAL_FLOAT_TYPE_P (atype))
+ {
+ if (INTEGRAL_TYPE_P (atype))
+ warning_at (loc, OPT_Wabsolute_value,
+ "using decimal floating-point absolute value "
+ "function %qD when argument is of integer type %qT",
+ fndecl, atype);
+ else if (SCALAR_FLOAT_TYPE_P (atype))
+ warning_at (loc, OPT_Wabsolute_value,
+ "using decimal floating-point absolute value "
+ "function %qD when argument is of floating-point "
+ "type %qT", fndecl, atype);
+ else if (TREE_CODE (atype) == COMPLEX_TYPE)
+ warning_at (loc, OPT_Wabsolute_value,
+ "using decimal floating-point absolute value "
+ "function %qD when argument is of complex type %qT",
+ fndecl, atype);
+ else
+ gcc_unreachable ();
+ return;
+ }
+ break;
+
+ default:
+ return;
+ }
+
+ if (!TYPE_ARG_TYPES (TREE_TYPE (fndecl)))
+ return;
+
+ tree ftype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
+ if (TREE_CODE (atype) == COMPLEX_TYPE)
+ {
+ gcc_assert (TREE_CODE (ftype) == COMPLEX_TYPE);
+ atype = TREE_TYPE (atype);
+ ftype = TREE_TYPE (ftype);
+ }
+
+ if (TYPE_PRECISION (ftype) < TYPE_PRECISION (atype))
+ warning_at (loc, OPT_Wabsolute_value,
+ "absolute value function %qD given an argument of type %qT "
+ "but has parameter of type %qT which may cause truncation "
+ "of value", fndecl, atype, ftype);
+}
+
+
+/* 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], comp_loc;
+ tree sizeof_arg[3];
+ unsigned int literal_zero_mask;
+ unsigned int i;
+ vec<tree, va_gc> *exprlist;
+ vec<tree, va_gc> *origtypes = NULL;
+ vec<location_t> arg_loc = vNULL;
+ location_t start;
+ location_t finish;
+
+ 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 %<]%>");
+ start = expr.get_start ();
+ finish = parser->tokens_buf[0].location;
+ expr.value = build_array_ref (op_loc, expr.value, idx);
+ set_c_expr_source_range (&expr, start, finish);
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ break;
+ case CPP_OPEN_PAREN:
+ /* Function call. */
+ {
+ matching_parens parens;
+ parens.consume_open (parser);
+ for (i = 0; i < 3; i++)
+ {
+ sizeof_arg[i] = NULL_TREE;
+ sizeof_arg_loc[i] = UNKNOWN_LOCATION;
+ }
+ literal_zero_mask = 0;
+ 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,
+ &arg_loc, &literal_zero_mask);
+ parens.skip_until_found_close (parser);
+ }
+ 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);
+ if (TREE_CODE (expr.value) == FUNCTION_DECL)
+ {
+ if (fndecl_built_in_p (expr.value, BUILT_IN_MEMSET)
+ && vec_safe_length (exprlist) == 3)
+ {
+ tree arg0 = (*exprlist)[0];
+ tree arg2 = (*exprlist)[2];
+ warn_for_memset (expr_loc, arg0, arg2, literal_zero_mask);
+ }
+ if (warn_absolute_value
+ && fndecl_built_in_p (expr.value, BUILT_IN_NORMAL)
+ && vec_safe_length (exprlist) == 1)
+ warn_for_abs (expr_loc, expr.value, (*exprlist)[0]);
+ }
+
+ start = expr.get_start ();
+ finish = parser->tokens_buf[0].get_finish ();
+ expr.value
+ = c_build_function_call_vec (expr_loc, arg_loc, expr.value,
+ exprlist, origtypes);
+ set_c_expr_source_range (&expr, start, finish);
+
+ expr.original_code = ERROR_MARK;
+ if (TREE_CODE (expr.value) == INTEGER_CST
+ && TREE_CODE (orig_expr.value) == FUNCTION_DECL
+ && fndecl_built_in_p (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);
+ }
+ arg_loc.release ();
+ 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))
+ {
+ c_token *comp_tok = c_parser_peek_token (parser);
+ ident = comp_tok->value;
+ comp_loc = comp_tok->location;
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ expr.set_error ();
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ return expr;
+ }
+ start = expr.get_start ();
+ finish = c_parser_peek_token (parser)->get_finish ();
+ c_parser_consume_token (parser);
+ expr.value = build_component_ref (op_loc, expr.value, ident,
+ comp_loc);
+ set_c_expr_source_range (&expr, start, finish);
+ 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 = convert_lvalue_to_rvalue (expr_loc, expr, true, false);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_token *comp_tok = c_parser_peek_token (parser);
+ ident = comp_tok->value;
+ comp_loc = comp_tok->location;
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ expr.set_error ();
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ return expr;
+ }
+ start = expr.get_start ();
+ finish = c_parser_peek_token (parser)->get_finish ();
+ c_parser_consume_token (parser);
+ expr.value = build_component_ref (op_loc,
+ build_indirect_ref (op_loc,
+ expr.value,
+ RO_ARROW),
+ ident, comp_loc);
+ set_c_expr_source_range (&expr, start, finish);
+ 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. */
+ start = expr.get_start ();
+ finish = c_parser_peek_token (parser)->get_finish ();
+ 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, false);
+ set_c_expr_source_range (&expr, start, finish);
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ break;
+ case CPP_MINUS_MINUS:
+ /* Postdecrement. */
+ start = expr.get_start ();
+ finish = c_parser_peek_token (parser)->get_finish ();
+ 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, false);
+ set_c_expr_source_range (&expr, start, finish);
+ expr.original_code = ERROR_MARK;
+ expr.original_type = NULL;
+ break;
+ default:
+ return expr;
+ }
+ }
+}
+
+/* Parse an expression (C90 6.3.17, C99 6.5.17, C11 6.5.17).
+
+ expression:
+ assignment-expression
+ expression , assignment-expression
+*/
+
+static struct c_expr
+c_parser_expression (c_parser *parser)
+{
+ location_t tloc = c_parser_peek_token (parser)->location;
+ struct c_expr expr;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ expr = convert_lvalue_to_rvalue (tloc, expr, true, false);
+ 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
+ || TREE_CODE (lhsval) == NOP_EXPR)
+ {
+ if (TREE_CODE (lhsval) == COMPOUND_EXPR)
+ lhsval = TREE_OPERAND (lhsval, 1);
+ else
+ lhsval = TREE_OPERAND (lhsval, 0);
+ }
+ if (DECL_P (lhsval) || handled_component_p (lhsval))
+ mark_exp_read (lhsval);
+ next = c_parser_expr_no_commas (parser, NULL);
+ next = convert_lvalue_to_rvalue (expr_loc, next, true, false);
+ 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 and
+ lvalues to rvalues. */
+
+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 = convert_lvalue_to_rvalue (loc, expr, true, false);
+ return expr;
+}
+
+/* Helper function of c_parser_expr_list. Check if IDXth (0 based)
+ argument is a literal zero alone and if so, set it in literal_zero_mask. */
+
+static inline void
+c_parser_check_literal_zero (c_parser *parser, unsigned *literal_zero_mask,
+ unsigned int idx)
+{
+ if (idx >= HOST_BITS_PER_INT)
+ return;
+
+ c_token *tok = c_parser_peek_token (parser);
+ switch (tok->type)
+ {
+ case CPP_NUMBER:
+ case CPP_CHAR:
+ case CPP_WCHAR:
+ case CPP_CHAR16:
+ case CPP_CHAR32:
+ case CPP_UTF8CHAR:
+ /* If a parameter is literal zero alone, remember it
+ for -Wmemset-transposed-args warning. */
+ if (integer_zerop (tok->value)
+ && !TREE_OVERFLOW (tok->value)
+ && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA
+ || c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_PAREN))
+ *literal_zero_mask |= 1U << idx;
+ default:
+ break;
+ }
+}
+
+/* Parse a non-empty list of expressions. If CONVERT_P, convert
+ functions and arrays to pointers and lvalues to rvalues. If
+ FOLD_P, fold the expressions. If LOCATIONS is non-NULL, save the
+ locations of function arguments into this vector.
+
+ 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<location_t> *locations,
+ unsigned int *literal_zero_mask)
+{
+ vec<tree, va_gc> *ret;
+ vec<tree, va_gc> *orig_types;
+ struct c_expr expr;
+ unsigned int idx = 0;
+
+ ret = make_tree_vector ();
+ if (p_orig_types == NULL)
+ orig_types = NULL;
+ else
+ orig_types = make_tree_vector ();
+
+ if (literal_zero_mask)
+ c_parser_check_literal_zero (parser, literal_zero_mask, 0);
+ expr = c_parser_expr_no_commas (parser, NULL);
+ if (convert_p)
+ expr = convert_lvalue_to_rvalue (expr.get_location (), expr, true, true);
+ 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 (locations)
+ locations->safe_push (expr.get_location ());
+ if (sizeof_arg != NULL
+ && (expr.original_code == SIZEOF_EXPR
+ || expr.original_code == PAREN_SIZEOF_EXPR))
+ {
+ sizeof_arg[0] = c_last_sizeof_arg;
+ sizeof_arg_loc[0] = c_last_sizeof_loc;
+ }
+ while (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ if (literal_zero_mask)
+ c_parser_check_literal_zero (parser, literal_zero_mask, idx + 1);
+ expr = c_parser_expr_no_commas (parser, NULL);
+ if (convert_p)
+ expr = convert_lvalue_to_rvalue (expr.get_location (), expr, true,
+ true);
+ 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 (locations)
+ locations->safe_push (expr.get_location ());
+ if (++idx < 3
+ && sizeof_arg != NULL
+ && (expr.original_code == SIZEOF_EXPR
+ || expr.original_code == PAREN_SIZEOF_EXPR))
+ {
+ sizeof_arg[idx] = c_last_sizeof_arg;
+ sizeof_arg_loc[idx] = c_last_sizeof_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;
+ location_t loc1 = c_parser_peek_token (parser)->location;
+ 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;
+ matching_parens parens;
+ parens.consume_open (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);
+ }
+ parens.skip_until_found_close (parser);
+ 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, loc1, 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, NULL);
+ 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, NULL);
+ 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);
+ 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_gnu_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
+ gnu-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))
+ {
+ matching_parens parens;
+ parens.consume_open (parser);
+ type = c_parser_objc_type_name (parser);
+ parens.skip_until_found_close (parser);
+ }
+ 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_gnu_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, false);
+ 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);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ 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, false);
+ if (parm == NULL)
+ parameter_declaration = error_mark_node;
+ else
+ parameter_declaration = grokparm (parm, NULL);
+ }
+ if (seen_open_paren)
+ parens.require_close (parser);
+ 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);
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ struct c_expr ce = c_parser_expression (parser);
+ ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+ expr = ce.value;
+ expr = c_fully_fold (expr, false, NULL);
+ parens.skip_until_found_close (parser);
+ }
+ 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
+ _Atomic
+
+ ??? Why this selection of keywords but not, for example, storage
+ class specifiers? */
+
+static tree
+c_parser_objc_selector (c_parser *parser)
+{
+ c_token *token = c_parser_peek_token (parser);
+ tree value = token->value;
+ if (token->type == CPP_NAME)
+ {
+ c_parser_consume_token (parser);
+ return value;
+ }
+ if (token->type != CPP_KEYWORD)
+ return NULL_TREE;
+ switch (token->keyword)
+ {
+ case RID_ENUM:
+ case RID_STRUCT:
+ case RID_UNION:
+ case RID_IF:
+ case RID_ELSE:
+ case RID_WHILE:
+ case RID_DO:
+ case RID_FOR:
+ case RID_SWITCH:
+ case RID_CASE:
+ case RID_DEFAULT:
+ case RID_BREAK:
+ case RID_CONTINUE:
+ case RID_RETURN:
+ case RID_GOTO:
+ case RID_ASM:
+ case RID_SIZEOF:
+ case RID_TYPEOF:
+ case RID_ALIGNOF:
+ case RID_UNSIGNED:
+ case RID_LONG:
+ case RID_CONST:
+ case RID_SHORT:
+ case RID_VOLATILE:
+ case RID_SIGNED:
+ case RID_RESTRICT:
+ case RID_COMPLEX:
+ case RID_IN:
+ case RID_OUT:
+ case RID_INOUT:
+ case RID_BYCOPY:
+ case RID_BYREF:
+ case RID_ONEWAY:
+ case RID_INT:
+ case RID_CHAR:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ CASE_RID_FLOATN_NX:
+ case RID_VOID:
+ case RID_BOOL:
+ case RID_ATOMIC:
+ case RID_AUTO_TYPE:
+ case RID_INT_N_0:
+ case RID_INT_N_1:
+ case RID_INT_N_2:
+ case RID_INT_N_3:
+ 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)
+ && c_parser_next_token_is_not (parser, CPP_SCOPE))
+ return sel;
+ while (true)
+ {
+ if (c_parser_next_token_is (parser, CPP_SCOPE))
+ {
+ c_parser_consume_token (parser);
+ list = chainon (list, build_tree_list (sel, NULL_TREE));
+ list = chainon (list, build_tree_list (NULL_TREE, NULL_TREE));
+ }
+ else
+ {
+ 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)
+ && c_parser_next_token_is_not (parser, CPP_SCOPE))
+ break;
+ }
+ return list;
+}
+
+/* Parse an objc-receiver.
+
+ objc-receiver:
+ expression
+ class-name
+ type-name
+*/
+
+static tree
+c_parser_objc_receiver (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ 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);
+ }
+ struct c_expr ce = c_parser_expression (parser);
+ ce = convert_lvalue_to_rvalue (loc, ce, false, false);
+ return c_fully_fold (ce.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, 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)
+{
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_AT_PROPERTY));
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser); /* Eat '@property'. */
+
+ /* Parse the optional attribute list.
+
+ A list of parsed, but not verified, attributes. */
+ vec<property_attribute_info *> prop_attr_list = vNULL;
+
+ bool syntax_error = false;
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ matching_parens parens;
+
+ location_t attr_start = c_parser_peek_token (parser)->location;
+ /* Eat the '(' */
+ parens.consume_open (parser);
+
+ /* Property attribute keywords are valid now. */
+ parser->objc_property_attr_context = true;
+
+ /* Allow @property (), with a warning. */
+ location_t attr_end = c_parser_peek_token (parser)->location;
+
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ location_t attr_comb = make_location (attr_end, attr_start, attr_end);
+ warning_at (attr_comb, OPT_Wattributes,
+ "empty property attribute list");
+ }
+ else
+ while (true)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ attr_start = token->location;
+ attr_end = get_finish (token->location);
+ location_t attr_comb = make_location (attr_start, attr_start,
+ attr_end);
+
+ if (token->type == CPP_CLOSE_PAREN || token->type == CPP_COMMA)
+ {
+ warning_at (attr_comb, OPT_Wattributes,
+ "missing property attribute");
+ if (token->type == CPP_CLOSE_PAREN)
+ break;
+ c_parser_consume_token (parser);
+ continue;
+ }
+
+ tree attr_name = NULL_TREE;
+ enum rid keyword = RID_MAX; /* Not a valid property attribute. */
+ bool add_at = false;
+ if (token->type == CPP_KEYWORD)
+ {
+ keyword = token->keyword;
+ if (OBJC_IS_AT_KEYWORD (keyword))
+ {
+ /* For '@' keywords the token value has the keyword,
+ prepend the '@' for diagnostics. */
+ attr_name = token->value;
+ add_at = true;
+ }
+ else
+ attr_name = ridpointers[(int)keyword];
+ }
+ else if (token->type == CPP_NAME)
+ attr_name = token->value;
+ c_parser_consume_token (parser);
+
+ enum objc_property_attribute_kind prop_kind
+ = objc_prop_attr_kind_for_rid (keyword);
+ property_attribute_info *prop
+ = new property_attribute_info (attr_name, attr_comb, prop_kind);
+ prop_attr_list.safe_push (prop);
+
+ tree meth_name;
+ switch (prop->prop_kind)
+ {
+ default: break;
+ case OBJC_PROPERTY_ATTR_UNKNOWN:
+ if (attr_name)
+ error_at (attr_comb, "unknown property attribute %<%s%s%>",
+ add_at ? "@" : "", IDENTIFIER_POINTER (attr_name));
+ else
+ error_at (attr_comb, "unknown property attribute");
+ prop->parse_error = syntax_error = true;
+ break;
+
+ case OBJC_PROPERTY_ATTR_GETTER:
+ case OBJC_PROPERTY_ATTR_SETTER:
+ if (c_parser_next_token_is_not (parser, CPP_EQ))
+ {
+ attr_comb = make_location (attr_end, attr_start, attr_end);
+ error_at (attr_comb, "expected %<=%> after Objective-C %qE",
+ attr_name);
+ prop->parse_error = syntax_error = true;
+ break;
+ }
+ token = c_parser_peek_token (parser);
+ attr_end = token->location;
+ c_parser_consume_token (parser); /* eat the = */
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ {
+ attr_comb = make_location (attr_end, attr_start, attr_end);
+ error_at (attr_comb, "expected %qE selector name",
+ attr_name);
+ prop->parse_error = syntax_error = true;
+ break;
+ }
+ /* Get the end of the method name, and consume the name. */
+ token = c_parser_peek_token (parser);
+ attr_end = get_finish (token->location);
+ meth_name = token->value;
+ c_parser_consume_token (parser);
+ if (prop->prop_kind == OBJC_PROPERTY_ATTR_SETTER)
+ {
+ if (c_parser_next_token_is_not (parser, CPP_COLON))
+ {
+ attr_comb = make_location (attr_end, attr_start,
+ attr_end);
+ error_at (attr_comb, "setter method names must"
+ " terminate with %<:%>");
+ prop->parse_error = syntax_error = true;
+ }
+ else
+ {
+ attr_end = get_finish (c_parser_peek_token
+ (parser)->location);
+ c_parser_consume_token (parser);
+ }
+ attr_comb = make_location (attr_start, attr_start,
+ attr_end);
+ }
+ else
+ attr_comb = make_location (attr_start, attr_start,
+ attr_end);
+ prop->ident = meth_name;
+ /* Updated location including all that was successfully
+ parsed. */
+ prop->prop_loc = attr_comb;
+ break;
+ }
+
+ /* If we see a comma here, then keep going - even if we already
+ saw a syntax error. For simple mistakes e.g. (asign, getter=x)
+ this makes a more useful output and avoid spurious warnings about
+ missing attributes that are, in fact, specified after the one with
+ the syntax error. */
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ parser->objc_property_attr_context = false;
+
+ if (syntax_error && c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+ /* We don't really want to chew the whole of the file looking for a
+ matching closing parenthesis, so we will try to read the decl and
+ let the error handling for that close out the statement. */
+ ;
+ else
+ syntax_error = false, parens.skip_until_found_close (parser);
+ }
+
+ /* '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 = c_parser_struct_declaration (parser);
+
+ if (properties == error_mark_node)
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, NULL);
+ else
+ {
+ 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),
+ prop_attr_list);
+ }
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+
+ while (!prop_attr_list.is_empty())
+ delete prop_attr_list.pop ();
+ prop_attr_list.release ();
+ 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);
+}
+
+
+/* Parse a pragma GCC ivdep. */
+
+static bool
+c_parse_pragma_ivdep (c_parser *parser)
+{
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+ return true;
+}
+
+/* Parse a pragma GCC unroll. */
+
+static unsigned short
+c_parser_pragma_unroll (c_parser *parser)
+{
+ unsigned short unroll;
+ c_parser_consume_pragma (parser);
+ location_t location = c_parser_peek_token (parser)->location;
+ tree expr = c_parser_expr_no_commas (parser, NULL).value;
+ mark_exp_read (expr);
+ expr = c_fully_fold (expr, false, NULL);
+ HOST_WIDE_INT lunroll = 0;
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (expr))
+ || TREE_CODE (expr) != INTEGER_CST
+ || (lunroll = tree_to_shwi (expr)) < 0
+ || lunroll >= USHRT_MAX)
+ {
+ error_at (location, "%<#pragma GCC unroll%> requires an"
+ " assignment-expression that evaluates to a non-negative"
+ " integral constant less than %u", USHRT_MAX);
+ unroll = 0;
+ }
+ else
+ {
+ unroll = (unsigned short)lunroll;
+ if (unroll == 0)
+ unroll = 1;
+ }
+
+ c_parser_skip_to_pragma_eol (parser);
+ return unroll;
+}
+
+/* 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, bool *if_p)
+{
+ unsigned int id;
+ const char *construct = NULL;
+
+ id = c_parser_peek_token (parser)->pragma_kind;
+ gcc_assert (id != PRAGMA_NONE);
+
+ switch (id)
+ {
+ case PRAGMA_OACC_DECLARE:
+ c_parser_oacc_declare (parser);
+ return false;
+
+ case PRAGMA_OACC_ENTER_DATA:
+ if (context != pragma_compound)
+ {
+ construct = "acc enter data";
+ in_compound:
+ if (context == pragma_stmt)
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "%<#pragma %s%> may only be used in compound "
+ "statements", construct);
+ c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+ return true;
+ }
+ goto bad_stmt;
+ }
+ c_parser_oacc_enter_exit_data (parser, true);
+ return false;
+
+ case PRAGMA_OACC_EXIT_DATA:
+ if (context != pragma_compound)
+ {
+ construct = "acc exit data";
+ goto in_compound;
+ }
+ c_parser_oacc_enter_exit_data (parser, false);
+ return false;
+
+ case PRAGMA_OACC_ROUTINE:
+ if (context != pragma_external)
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "%<#pragma acc routine%> must be at file scope");
+ c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+ return false;
+ }
+ c_parser_oacc_routine (parser, context);
+ return false;
+
+ case PRAGMA_OACC_UPDATE:
+ if (context != pragma_compound)
+ {
+ construct = "acc update";
+ goto in_compound;
+ }
+ c_parser_oacc_update (parser);
+ return false;
+
+ case PRAGMA_OMP_BARRIER:
+ if (context != pragma_compound)
+ {
+ construct = "omp barrier";
+ goto in_compound;
+ }
+ c_parser_omp_barrier (parser);
+ return false;
+
+ case PRAGMA_OMP_DEPOBJ:
+ if (context != pragma_compound)
+ {
+ construct = "omp depobj";
+ goto in_compound;
+ }
+ c_parser_omp_depobj (parser);
+ return false;
+
+ case PRAGMA_OMP_FLUSH:
+ if (context != pragma_compound)
+ {
+ construct = "omp flush";
+ goto in_compound;
+ }
+ c_parser_omp_flush (parser);
+ return false;
+
+ case PRAGMA_OMP_TASKWAIT:
+ if (context != pragma_compound)
+ {
+ construct = "omp taskwait";
+ goto in_compound;
+ }
+ c_parser_omp_taskwait (parser);
+ return false;
+
+ case PRAGMA_OMP_TASKYIELD:
+ if (context != pragma_compound)
+ {
+ construct = "omp taskyield";
+ goto in_compound;
+ }
+ c_parser_omp_taskyield (parser);
+ return false;
+
+ case PRAGMA_OMP_CANCEL:
+ if (context != pragma_compound)
+ {
+ construct = "omp cancel";
+ goto in_compound;
+ }
+ c_parser_omp_cancel (parser);
+ return false;
+
+ case PRAGMA_OMP_CANCELLATION_POINT:
+ return c_parser_omp_cancellation_point (parser, context);
+
+ case PRAGMA_OMP_THREADPRIVATE:
+ c_parser_omp_threadprivate (parser);
+ return false;
+
+ case PRAGMA_OMP_TARGET:
+ return c_parser_omp_target (parser, context, if_p);
+
+ case PRAGMA_OMP_END_DECLARE_TARGET:
+ c_parser_omp_end_declare_target (parser);
+ return false;
+
+ case PRAGMA_OMP_SCAN:
+ error_at (c_parser_peek_token (parser)->location,
+ "%<#pragma omp scan%> may only be used in "
+ "a loop construct with %<inscan%> %<reduction%> clause");
+ c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+ 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_OMP_DECLARE:
+ return c_parser_omp_declare (parser, context);
+
+ case PRAGMA_OMP_REQUIRES:
+ if (context != pragma_external)
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "%<#pragma omp requires%> may only be used at file scope");
+ c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+ return false;
+ }
+ c_parser_omp_requires (parser);
+ return false;
+
+ case PRAGMA_OMP_NOTHING:
+ c_parser_omp_nothing (parser);
+ return false;
+
+ case PRAGMA_OMP_ERROR:
+ return c_parser_omp_error (parser, context);
+
+ case PRAGMA_OMP_ORDERED:
+ return c_parser_omp_ordered (parser, context, if_p);
+
+ case PRAGMA_IVDEP:
+ {
+ const bool ivdep = c_parse_pragma_ivdep (parser);
+ unsigned short unroll;
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_UNROLL)
+ unroll = c_parser_pragma_unroll (parser);
+ else
+ unroll = 0;
+ if (!c_parser_next_token_is_keyword (parser, RID_FOR)
+ && !c_parser_next_token_is_keyword (parser, RID_WHILE)
+ && !c_parser_next_token_is_keyword (parser, RID_DO))
+ {
+ c_parser_error (parser, "for, while or do statement expected");
+ return false;
+ }
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ c_parser_for_statement (parser, ivdep, unroll, if_p);
+ else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
+ c_parser_while_statement (parser, ivdep, unroll, if_p);
+ else
+ c_parser_do_statement (parser, ivdep, unroll);
+ }
+ return true;
+
+ case PRAGMA_UNROLL:
+ {
+ unsigned short unroll = c_parser_pragma_unroll (parser);
+ bool ivdep;
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_IVDEP)
+ ivdep = c_parse_pragma_ivdep (parser);
+ else
+ ivdep = false;
+ if (!c_parser_next_token_is_keyword (parser, RID_FOR)
+ && !c_parser_next_token_is_keyword (parser, RID_WHILE)
+ && !c_parser_next_token_is_keyword (parser, RID_DO))
+ {
+ c_parser_error (parser, "for, while or do statement expected");
+ return false;
+ }
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ c_parser_for_statement (parser, ivdep, unroll, if_p);
+ else if (c_parser_next_token_is_keyword (parser, RID_WHILE))
+ c_parser_while_statement (parser, ivdep, unroll, if_p);
+ else
+ c_parser_do_statement (parser, ivdep, unroll);
+ }
+ return true;
+
+ 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;
+
+ case PRAGMA_OACC_WAIT:
+ if (context != pragma_compound)
+ {
+ construct = "acc wait";
+ goto in_compound;
+ }
+ /* FALL THROUGH. */
+
+ default:
+ if (id < PRAGMA_FIRST_EXTERNAL)
+ {
+ if (context != pragma_stmt && context != pragma_compound)
+ {
+ 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, if_p);
+ 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, location_t *loc)
+{
+ c_token *tok = c_parser_peek_token (the_parser);
+ enum cpp_ttype ret = tok->type;
+
+ *value = tok->value;
+ if (loc)
+ *loc = tok->location;
+
+ if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF)
+ ret = CPP_EOF;
+ else if (ret == CPP_STRING)
+ *value = c_parser_string_literal (the_parser, false, false).value;
+ 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;
+
+ parser->lex_joined_string = true;
+ 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);
+ parser->lex_joined_string = false;
+
+ if (name)
+ c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name));
+}
+
+/* OpenACC and OpenMP 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_AUTO))
+ result = PRAGMA_OACC_CLAUSE_AUTO;
+ else 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_keyword (parser, RID_FOR))
+ result = PRAGMA_OMP_CLAUSE_FOR;
+ 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 'a':
+ if (!strcmp ("affinity", p))
+ result = PRAGMA_OMP_CLAUSE_AFFINITY;
+ else if (!strcmp ("aligned", p))
+ result = PRAGMA_OMP_CLAUSE_ALIGNED;
+ else if (!strcmp ("allocate", p))
+ result = PRAGMA_OMP_CLAUSE_ALLOCATE;
+ else if (!strcmp ("async", p))
+ result = PRAGMA_OACC_CLAUSE_ASYNC;
+ else if (!strcmp ("attach", p))
+ result = PRAGMA_OACC_CLAUSE_ATTACH;
+ break;
+ case 'b':
+ if (!strcmp ("bind", p))
+ result = PRAGMA_OMP_CLAUSE_BIND;
+ break;
+ case 'c':
+ if (!strcmp ("collapse", p))
+ result = PRAGMA_OMP_CLAUSE_COLLAPSE;
+ else if (!strcmp ("copy", p))
+ result = PRAGMA_OACC_CLAUSE_COPY;
+ else if (!strcmp ("copyin", p))
+ result = PRAGMA_OMP_CLAUSE_COPYIN;
+ else if (!strcmp ("copyout", p))
+ result = PRAGMA_OACC_CLAUSE_COPYOUT;
+ else if (!strcmp ("copyprivate", p))
+ result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
+ else if (!strcmp ("create", p))
+ result = PRAGMA_OACC_CLAUSE_CREATE;
+ break;
+ case 'd':
+ if (!strcmp ("defaultmap", p))
+ result = PRAGMA_OMP_CLAUSE_DEFAULTMAP;
+ else if (!strcmp ("delete", p))
+ result = PRAGMA_OACC_CLAUSE_DELETE;
+ else if (!strcmp ("depend", p))
+ result = PRAGMA_OMP_CLAUSE_DEPEND;
+ else if (!strcmp ("detach", p))
+ result = PRAGMA_OACC_CLAUSE_DETACH;
+ else if (!strcmp ("device", p))
+ result = PRAGMA_OMP_CLAUSE_DEVICE;
+ else if (!strcmp ("deviceptr", p))
+ result = PRAGMA_OACC_CLAUSE_DEVICEPTR;
+ else if (!strcmp ("device_resident", p))
+ result = PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT;
+ else if (!strcmp ("device_type", p))
+ result = PRAGMA_OMP_CLAUSE_DEVICE_TYPE;
+ else if (!strcmp ("dist_schedule", p))
+ result = PRAGMA_OMP_CLAUSE_DIST_SCHEDULE;
+ break;
+ case 'f':
+ if (!strcmp ("filter", p))
+ result = PRAGMA_OMP_CLAUSE_FILTER;
+ else if (!strcmp ("final", p))
+ result = PRAGMA_OMP_CLAUSE_FINAL;
+ else if (!strcmp ("finalize", p))
+ result = PRAGMA_OACC_CLAUSE_FINALIZE;
+ else if (!strcmp ("firstprivate", p))
+ result = PRAGMA_OMP_CLAUSE_FIRSTPRIVATE;
+ else if (!strcmp ("from", p))
+ result = PRAGMA_OMP_CLAUSE_FROM;
+ break;
+ case 'g':
+ if (!strcmp ("gang", p))
+ result = PRAGMA_OACC_CLAUSE_GANG;
+ else if (!strcmp ("grainsize", p))
+ result = PRAGMA_OMP_CLAUSE_GRAINSIZE;
+ break;
+ case 'h':
+ if (!strcmp ("hint", p))
+ result = PRAGMA_OMP_CLAUSE_HINT;
+ else if (!strcmp ("host", p))
+ result = PRAGMA_OACC_CLAUSE_HOST;
+ break;
+ case 'i':
+ if (!strcmp ("if_present", p))
+ result = PRAGMA_OACC_CLAUSE_IF_PRESENT;
+ else if (!strcmp ("in_reduction", p))
+ result = PRAGMA_OMP_CLAUSE_IN_REDUCTION;
+ else if (!strcmp ("inbranch", p))
+ result = PRAGMA_OMP_CLAUSE_INBRANCH;
+ else if (!strcmp ("independent", p))
+ result = PRAGMA_OACC_CLAUSE_INDEPENDENT;
+ else if (!strcmp ("is_device_ptr", p))
+ result = PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR;
+ break;
+ case 'l':
+ if (!strcmp ("lastprivate", p))
+ result = PRAGMA_OMP_CLAUSE_LASTPRIVATE;
+ else if (!strcmp ("linear", p))
+ result = PRAGMA_OMP_CLAUSE_LINEAR;
+ else if (!strcmp ("link", p))
+ result = PRAGMA_OMP_CLAUSE_LINK;
+ break;
+ case 'm':
+ if (!strcmp ("map", p))
+ result = PRAGMA_OMP_CLAUSE_MAP;
+ else if (!strcmp ("mergeable", p))
+ result = PRAGMA_OMP_CLAUSE_MERGEABLE;
+ break;
+ case 'n':
+ if (!strcmp ("no_create", p))
+ result = PRAGMA_OACC_CLAUSE_NO_CREATE;
+ else if (!strcmp ("nogroup", p))
+ result = PRAGMA_OMP_CLAUSE_NOGROUP;
+ else if (!strcmp ("nohost", p))
+ result = PRAGMA_OACC_CLAUSE_NOHOST;
+ else if (!strcmp ("nontemporal", p))
+ result = PRAGMA_OMP_CLAUSE_NONTEMPORAL;
+ else if (!strcmp ("notinbranch", p))
+ result = PRAGMA_OMP_CLAUSE_NOTINBRANCH;
+ else if (!strcmp ("nowait", p))
+ result = PRAGMA_OMP_CLAUSE_NOWAIT;
+ else if (!strcmp ("num_gangs", p))
+ result = PRAGMA_OACC_CLAUSE_NUM_GANGS;
+ else if (!strcmp ("num_tasks", p))
+ result = PRAGMA_OMP_CLAUSE_NUM_TASKS;
+ else if (!strcmp ("num_teams", p))
+ result = PRAGMA_OMP_CLAUSE_NUM_TEAMS;
+ else if (!strcmp ("num_threads", p))
+ result = PRAGMA_OMP_CLAUSE_NUM_THREADS;
+ else if (!strcmp ("num_workers", p))
+ result = PRAGMA_OACC_CLAUSE_NUM_WORKERS;
+ break;
+ case 'o':
+ if (!strcmp ("ordered", p))
+ result = PRAGMA_OMP_CLAUSE_ORDERED;
+ else if (!strcmp ("order", p))
+ result = PRAGMA_OMP_CLAUSE_ORDER;
+ break;
+ case 'p':
+ if (!strcmp ("parallel", p))
+ result = PRAGMA_OMP_CLAUSE_PARALLEL;
+ else if (!strcmp ("present", p))
+ result = PRAGMA_OACC_CLAUSE_PRESENT;
+ /* As of OpenACC 2.5, these are now aliases of the non-present_or
+ clauses. */
+ else if (!strcmp ("present_or_copy", p)
+ || !strcmp ("pcopy", p))
+ result = PRAGMA_OACC_CLAUSE_COPY;
+ else if (!strcmp ("present_or_copyin", p)
+ || !strcmp ("pcopyin", p))
+ result = PRAGMA_OACC_CLAUSE_COPYIN;
+ else if (!strcmp ("present_or_copyout", p)
+ || !strcmp ("pcopyout", p))
+ result = PRAGMA_OACC_CLAUSE_COPYOUT;
+ else if (!strcmp ("present_or_create", p)
+ || !strcmp ("pcreate", p))
+ result = PRAGMA_OACC_CLAUSE_CREATE;
+ else if (!strcmp ("priority", p))
+ result = PRAGMA_OMP_CLAUSE_PRIORITY;
+ else if (!strcmp ("private", p))
+ result = PRAGMA_OMP_CLAUSE_PRIVATE;
+ else if (!strcmp ("proc_bind", p))
+ result = PRAGMA_OMP_CLAUSE_PROC_BIND;
+ break;
+ case 'r':
+ if (!strcmp ("reduction", p))
+ result = PRAGMA_OMP_CLAUSE_REDUCTION;
+ break;
+ case 's':
+ if (!strcmp ("safelen", p))
+ result = PRAGMA_OMP_CLAUSE_SAFELEN;
+ else if (!strcmp ("schedule", p))
+ result = PRAGMA_OMP_CLAUSE_SCHEDULE;
+ else if (!strcmp ("sections", p))
+ result = PRAGMA_OMP_CLAUSE_SECTIONS;
+ else if (!strcmp ("self", p)) /* "self" is a synonym for "host". */
+ result = PRAGMA_OACC_CLAUSE_HOST;
+ else if (!strcmp ("seq", p))
+ result = PRAGMA_OACC_CLAUSE_SEQ;
+ else if (!strcmp ("shared", p))
+ result = PRAGMA_OMP_CLAUSE_SHARED;
+ else if (!strcmp ("simd", p))
+ result = PRAGMA_OMP_CLAUSE_SIMD;
+ else if (!strcmp ("simdlen", p))
+ result = PRAGMA_OMP_CLAUSE_SIMDLEN;
+ break;
+ case 't':
+ if (!strcmp ("task_reduction", p))
+ result = PRAGMA_OMP_CLAUSE_TASK_REDUCTION;
+ else if (!strcmp ("taskgroup", p))
+ result = PRAGMA_OMP_CLAUSE_TASKGROUP;
+ else if (!strcmp ("thread_limit", p))
+ result = PRAGMA_OMP_CLAUSE_THREAD_LIMIT;
+ else if (!strcmp ("threads", p))
+ result = PRAGMA_OMP_CLAUSE_THREADS;
+ else if (!strcmp ("tile", p))
+ result = PRAGMA_OACC_CLAUSE_TILE;
+ else if (!strcmp ("to", p))
+ result = PRAGMA_OMP_CLAUSE_TO;
+ break;
+ case 'u':
+ if (!strcmp ("uniform", p))
+ result = PRAGMA_OMP_CLAUSE_UNIFORM;
+ else if (!strcmp ("untied", p))
+ result = PRAGMA_OMP_CLAUSE_UNTIED;
+ else if (!strcmp ("use_device", p))
+ result = PRAGMA_OACC_CLAUSE_USE_DEVICE;
+ else if (!strcmp ("use_device_addr", p))
+ result = PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR;
+ else if (!strcmp ("use_device_ptr", p))
+ result = PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR;
+ break;
+ case 'v':
+ if (!strcmp ("vector", p))
+ result = PRAGMA_OACC_CLAUSE_VECTOR;
+ else if (!strcmp ("vector_length", p))
+ result = PRAGMA_OACC_CLAUSE_VECTOR_LENGTH;
+ break;
+ case 'w':
+ if (!strcmp ("wait", p))
+ result = PRAGMA_OACC_CLAUSE_WAIT;
+ else if (!strcmp ("worker", p))
+ result = PRAGMA_OACC_CLAUSE_WORKER;
+ 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)
+{
+ if (tree c = omp_find_clause (clauses, code))
+ error_at (OMP_CLAUSE_LOCATION (c), "too many %qs clauses", name);
+}
+
+/* OpenACC 2.0
+ Parse wait clause or wait directive parameters. */
+
+static tree
+c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list)
+{
+ vec<tree, va_gc> *args;
+ tree t, args_tree;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ args = c_parser_expr_list (parser, false, true, NULL, NULL, NULL, NULL);
+ args_tree = build_tree_list_vec (args);
+
+ for (t = args_tree; t; t = TREE_CHAIN (t))
+ {
+ tree targ = TREE_VALUE (t);
+
+ if (targ != error_mark_node)
+ {
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (targ)))
+ {
+ c_parser_error (parser, "expression must be integral");
+ targ = error_mark_node;
+ }
+ else
+ {
+ tree c = build_omp_clause (clause_loc, OMP_CLAUSE_WAIT);
+
+ OMP_CLAUSE_DECL (c) = targ;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+ }
+ }
+
+ release_tree_vector (args);
+ parens.require_close (parser);
+ return list;
+}
+
+/* OpenACC 2.0, 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.
+
+ The optional ALLOW_DEREF argument is true if list items can use the deref
+ (->) operator. */
+
+struct omp_dim
+{
+ tree low_bound, length;
+ location_t loc;
+ bool no_colon;
+ omp_dim (tree lb, tree len, location_t lo, bool nc)
+ : low_bound (lb), length (len), loc (lo), no_colon (nc) {}
+};
+
+static tree
+c_parser_omp_variable_list (c_parser *parser,
+ location_t clause_loc,
+ enum omp_clause_code kind, tree list,
+ bool allow_deref = false)
+{
+ auto_vec<omp_dim> dims;
+ bool array_section_p;
+ auto_vec<c_token> tokens;
+ unsigned int tokens_avail = 0;
+ bool first = true;
+
+ while (1)
+ {
+ if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY)
+ {
+ if (c_parser_next_token_is_not (parser, CPP_NAME)
+ || c_parser_peek_token (parser)->id_kind != C_ID_ID)
+ {
+ struct c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ if (expr.value != error_mark_node)
+ {
+ tree u = build_omp_clause (clause_loc, kind);
+ OMP_CLAUSE_DECL (u) = expr.value;
+ OMP_CLAUSE_CHAIN (u) = list;
+ list = u;
+ }
+
+ if (c_parser_next_token_is_not (parser, CPP_COMMA))
+ break;
+
+ c_parser_consume_token (parser);
+ first = false;
+ continue;
+ }
+
+ tokens.truncate (0);
+ unsigned int nesting_depth = 0;
+ while (1)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ switch (token->type)
+ {
+ case CPP_EOF:
+ case CPP_PRAGMA_EOL:
+ break;
+ case CPP_OPEN_BRACE:
+ case CPP_OPEN_PAREN:
+ case CPP_OPEN_SQUARE:
+ ++nesting_depth;
+ goto add;
+ case CPP_CLOSE_BRACE:
+ case CPP_CLOSE_PAREN:
+ case CPP_CLOSE_SQUARE:
+ if (nesting_depth-- == 0)
+ break;
+ goto add;
+ case CPP_COMMA:
+ if (nesting_depth == 0)
+ break;
+ goto add;
+ default:
+ add:
+ tokens.safe_push (*token);
+ c_parser_consume_token (parser);
+ continue;
+ }
+ break;
+ }
+
+ /* Make sure nothing tries to read past the end of the tokens. */
+ c_token eof_token;
+ memset (&eof_token, 0, sizeof (eof_token));
+ eof_token.type = CPP_EOF;
+ tokens.safe_push (eof_token);
+ tokens.safe_push (eof_token);
+
+ tokens_avail = parser->tokens_avail;
+ gcc_assert (parser->tokens == &parser->tokens_buf[0]);
+ parser->tokens = tokens.address ();
+ parser->tokens_avail = tokens.length ();
+ }
+
+ tree t = NULL_TREE;
+
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_token (parser)->id_kind == C_ID_ID)
+ {
+ 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);
+ t = error_mark_node;
+ }
+
+ c_parser_consume_token (parser);
+ }
+ else if (c_parser_next_token_is (parser, CPP_KEYWORD)
+ && (c_parser_peek_token (parser)->keyword == RID_FUNCTION_NAME
+ || (c_parser_peek_token (parser)->keyword
+ == RID_PRETTY_FUNCTION_NAME)
+ || (c_parser_peek_token (parser)->keyword
+ == RID_C99_FUNCTION_NAME)))
+ t = c_parser_predefined_identifier (parser).value;
+ else
+ {
+ if (first)
+ c_parser_error (parser, "expected identifier");
+ break;
+ }
+
+ if (t == error_mark_node)
+ ;
+ else if (kind != 0)
+ {
+ switch (kind)
+ {
+ case OMP_CLAUSE__CACHE_:
+ /* The OpenACC cache directive explicitly only allows "array
+ elements or subarrays". */
+ if (c_parser_peek_token (parser)->type != CPP_OPEN_SQUARE)
+ {
+ c_parser_error (parser, "expected %<[%>");
+ t = error_mark_node;
+ break;
+ }
+ /* FALLTHROUGH */
+ case OMP_CLAUSE_MAP:
+ case OMP_CLAUSE_FROM:
+ case OMP_CLAUSE_TO:
+ start_component_ref:
+ while (c_parser_next_token_is (parser, CPP_DOT)
+ || (allow_deref
+ && c_parser_next_token_is (parser, CPP_DEREF)))
+ {
+ location_t op_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_DEREF))
+ t = build_simple_mem_ref (t);
+ c_parser_consume_token (parser);
+ if (!c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ t = error_mark_node;
+ break;
+ }
+
+ c_token *comp_tok = c_parser_peek_token (parser);
+ tree ident = comp_tok->value;
+ location_t comp_loc = comp_tok->location;
+ c_parser_consume_token (parser);
+ t = build_component_ref (op_loc, t, ident, comp_loc);
+ }
+ /* FALLTHROUGH */
+ case OMP_CLAUSE_AFFINITY:
+ case OMP_CLAUSE_DEPEND:
+ case OMP_CLAUSE_REDUCTION:
+ case OMP_CLAUSE_IN_REDUCTION:
+ case OMP_CLAUSE_TASK_REDUCTION:
+ array_section_p = false;
+ dims.truncate (0);
+ while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ {
+ location_t loc = UNKNOWN_LOCATION;
+ tree low_bound = NULL_TREE, length = NULL_TREE;
+ bool no_colon = false;
+
+ c_parser_consume_token (parser);
+ if (!c_parser_next_token_is (parser, CPP_COLON))
+ {
+ location_t expr_loc
+ = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expression (parser);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr,
+ false, true);
+ low_bound = expr.value;
+ loc = expr_loc;
+ }
+ if (c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ {
+ length = integer_one_node;
+ no_colon = true;
+ }
+ else
+ {
+ /* Look for `:'. */
+ if (!c_parser_require (parser, CPP_COLON,
+ "expected %<:%>"))
+ {
+ t = error_mark_node;
+ break;
+ }
+ array_section_p = true;
+ if (!c_parser_next_token_is (parser, CPP_CLOSE_SQUARE))
+ {
+ location_t expr_loc
+ = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expression (parser);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr,
+ false, true);
+ length = expr.value;
+ }
+ }
+ /* Look for the closing `]'. */
+ if (!c_parser_require (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>"))
+ {
+ t = error_mark_node;
+ break;
+ }
+
+ dims.safe_push (omp_dim (low_bound, length, loc, no_colon));
+ }
+
+ if (t != error_mark_node)
+ {
+ if ((kind == OMP_CLAUSE_MAP
+ || kind == OMP_CLAUSE_FROM
+ || kind == OMP_CLAUSE_TO)
+ && !array_section_p
+ && (c_parser_next_token_is (parser, CPP_DOT)
+ || (allow_deref
+ && c_parser_next_token_is (parser,
+ CPP_DEREF))))
+ {
+ for (unsigned i = 0; i < dims.length (); i++)
+ {
+ gcc_assert (dims[i].length == integer_one_node);
+ t = build_array_ref (dims[i].loc,
+ t, dims[i].low_bound);
+ }
+ goto start_component_ref;
+ }
+ else
+ for (unsigned i = 0; i < dims.length (); i++)
+ t = tree_cons (dims[i].low_bound, dims[i].length, t);
+ }
+
+ if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY)
+ && t != error_mark_node
+ && parser->tokens_avail != 2)
+ {
+ if (array_section_p)
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "expected %<)%> or %<,%>");
+ t = error_mark_node;
+ }
+ else
+ {
+ parser->tokens = tokens.address ();
+ parser->tokens_avail = tokens.length ();
+
+ t = c_parser_expr_no_commas (parser, NULL).value;
+ if (t != error_mark_node && parser->tokens_avail != 2)
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "expected %<)%> or %<,%>");
+ t = error_mark_node;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (t != error_mark_node)
+ {
+ 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);
+
+ if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY)
+ {
+ parser->tokens = &parser->tokens_buf[0];
+ parser->tokens_avail = tokens_avail;
+ }
+ if (c_parser_next_token_is_not (parser, CPP_COMMA))
+ break;
+
+ c_parser_consume_token (parser);
+ first = false;
+ }
+
+ return list;
+}
+
+/* Similarly, but expect leading and trailing parenthesis. This is a very
+ common case for OpenACC and OpenMP clauses. The optional ALLOW_DEREF
+ argument is true if list items can use the deref (->) operator. */
+
+static tree
+c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind,
+ tree list, bool allow_deref = false)
+{
+ /* The clauses location. */
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ list = c_parser_omp_variable_list (parser, loc, kind, list, allow_deref);
+ parens.skip_until_found_close (parser);
+ }
+ return list;
+}
+
+/* OpenACC 2.0:
+ copy ( variable-list )
+ copyin ( variable-list )
+ copyout ( variable-list )
+ create ( variable-list )
+ delete ( variable-list )
+ present ( variable-list )
+
+ OpenACC 2.6:
+ no_create ( variable-list )
+ attach ( variable-list )
+ detach ( variable-list ) */
+
+static tree
+c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind,
+ tree list)
+{
+ enum gomp_map_kind kind;
+ switch (c_kind)
+ {
+ case PRAGMA_OACC_CLAUSE_ATTACH:
+ kind = GOMP_MAP_ATTACH;
+ break;
+ case PRAGMA_OACC_CLAUSE_COPY:
+ kind = GOMP_MAP_TOFROM;
+ break;
+ case PRAGMA_OACC_CLAUSE_COPYIN:
+ kind = GOMP_MAP_TO;
+ break;
+ case PRAGMA_OACC_CLAUSE_COPYOUT:
+ kind = GOMP_MAP_FROM;
+ break;
+ case PRAGMA_OACC_CLAUSE_CREATE:
+ kind = GOMP_MAP_ALLOC;
+ break;
+ case PRAGMA_OACC_CLAUSE_DELETE:
+ kind = GOMP_MAP_RELEASE;
+ break;
+ case PRAGMA_OACC_CLAUSE_DETACH:
+ kind = GOMP_MAP_DETACH;
+ break;
+ case PRAGMA_OACC_CLAUSE_DEVICE:
+ kind = GOMP_MAP_FORCE_TO;
+ break;
+ case PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT:
+ kind = GOMP_MAP_DEVICE_RESIDENT;
+ break;
+ case PRAGMA_OACC_CLAUSE_HOST:
+ kind = GOMP_MAP_FORCE_FROM;
+ break;
+ case PRAGMA_OACC_CLAUSE_LINK:
+ kind = GOMP_MAP_LINK;
+ break;
+ case PRAGMA_OACC_CLAUSE_NO_CREATE:
+ kind = GOMP_MAP_IF_PRESENT;
+ break;
+ case PRAGMA_OACC_CLAUSE_PRESENT:
+ kind = GOMP_MAP_FORCE_PRESENT;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ tree nl, c;
+ nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_MAP, list, true);
+
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_SET_MAP_KIND (c, kind);
+
+ return nl;
+}
+
+/* OpenACC 2.0:
+ deviceptr ( variable-list ) */
+
+static tree
+c_parser_oacc_data_clause_deviceptr (c_parser *parser, tree list)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree vars, t;
+
+ /* Can't use OMP_CLAUSE_MAP here (that is, can't use the generic
+ c_parser_oacc_data_clause), as for PRAGMA_OACC_CLAUSE_DEVICEPTR,
+ variable-list must only allow for pointer variables. */
+ vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
+ for (t = vars; t && 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 (!VAR_P (v) && TREE_CODE (v) != PARM_DECL)
+ error_at (loc, "%qD is not a variable", v);
+ else if (TREE_TYPE (v) == error_mark_node)
+ ;
+ else if (!POINTER_TYPE_P (TREE_TYPE (v)))
+ error_at (loc, "%qD is not a pointer variable", v);
+
+ tree u = build_omp_clause (loc, OMP_CLAUSE_MAP);
+ OMP_CLAUSE_SET_MAP_KIND (u, GOMP_MAP_FORCE_DEVICEPTR);
+ OMP_CLAUSE_DECL (u) = v;
+ OMP_CLAUSE_CHAIN (u) = list;
+ list = u;
+ }
+
+ return list;
+}
+
+/* OpenACC 2.0, 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");
+ check_no_duplicate_clause (list, OMP_CLAUSE_TILE, "tile");
+
+ loc = c_parser_peek_token (parser)->location;
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ num = c_parser_expr_no_commas (parser, NULL).value;
+ parens.skip_until_found_close (parser);
+ }
+ if (num == error_mark_node)
+ return list;
+ mark_exp_read (num);
+ num = c_fully_fold (num, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (num))
+ || !tree_fits_shwi_p (num)
+ || (n = tree_to_shwi (num)) <= 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 ( none | shared )
+
+ OpenMP 5.1:
+ default ( private | firstprivate )
+
+ OpenACC:
+ default ( none | present ) */
+
+static tree
+c_parser_omp_clause_default (c_parser *parser, tree list, bool is_oacc)
+{
+ enum omp_clause_default_kind kind = OMP_CLAUSE_DEFAULT_UNSPECIFIED;
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree c;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ 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 'p':
+ if (is_oacc)
+ {
+ if (strcmp ("present", p) != 0)
+ goto invalid_kind;
+ kind = OMP_CLAUSE_DEFAULT_PRESENT;
+ }
+ else
+ {
+ if (strcmp ("private", p) != 0)
+ goto invalid_kind;
+ kind = OMP_CLAUSE_DEFAULT_PRIVATE;
+ }
+ break;
+
+ case 'f':
+ if (strcmp ("firstprivate", p) != 0 || is_oacc)
+ goto invalid_kind;
+ kind = OMP_CLAUSE_DEFAULT_FIRSTPRIVATE;
+ break;
+
+ case 's':
+ if (strcmp ("shared", p) != 0 || is_oacc)
+ goto invalid_kind;
+ kind = OMP_CLAUSE_DEFAULT_SHARED;
+ break;
+
+ default:
+ goto invalid_kind;
+ }
+
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ invalid_kind:
+ if (is_oacc)
+ c_parser_error (parser, "expected %<none%> or %<present%>");
+ else
+ c_parser_error (parser, "expected %<none%>, %<shared%>, "
+ "%<private%> or %<firstprivate%>");
+ }
+ parens.skip_until_found_close (parser);
+
+ 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))
+ {
+ matching_parens parens;
+ tree t, c;
+ if (!parens.require_open (parser))
+ t = error_mark_node;
+ else
+ {
+ location_t eloc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ t = convert_lvalue_to_rvalue (eloc, expr, true, true).value;
+ t = c_objc_common_truthvalue_conversion (eloc, t);
+ t = c_fully_fold (t, false, NULL);
+ parens.skip_until_found_close (parser);
+ }
+
+ 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;
+}
+
+/* OpenACC, OpenMP 2.5:
+ if ( expression )
+
+ OpenMP 4.5:
+ if ( directive-name-modifier : expression )
+
+ directive-name-modifier:
+ parallel | task | taskloop | target data | target | target update
+ | target enter data | target exit data
+
+ OpenMP 5.0:
+ directive-name-modifier:
+ ... | simd | cancel */
+
+static tree
+c_parser_omp_clause_if (c_parser *parser, tree list, bool is_omp)
+{
+ location_t location = c_parser_peek_token (parser)->location;
+ enum tree_code if_modifier = ERROR_MARK;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ if (is_omp && c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ int n = 2;
+ if (strcmp (p, "cancel") == 0)
+ if_modifier = VOID_CST;
+ else if (strcmp (p, "parallel") == 0)
+ if_modifier = OMP_PARALLEL;
+ else if (strcmp (p, "simd") == 0)
+ if_modifier = OMP_SIMD;
+ else if (strcmp (p, "task") == 0)
+ if_modifier = OMP_TASK;
+ else if (strcmp (p, "taskloop") == 0)
+ if_modifier = OMP_TASKLOOP;
+ else if (strcmp (p, "target") == 0)
+ {
+ if_modifier = OMP_TARGET;
+ if (c_parser_peek_2nd_token (parser)->type == CPP_NAME)
+ {
+ p = IDENTIFIER_POINTER (c_parser_peek_2nd_token (parser)->value);
+ if (strcmp ("data", p) == 0)
+ if_modifier = OMP_TARGET_DATA;
+ else if (strcmp ("update", p) == 0)
+ if_modifier = OMP_TARGET_UPDATE;
+ else if (strcmp ("enter", p) == 0)
+ if_modifier = OMP_TARGET_ENTER_DATA;
+ else if (strcmp ("exit", p) == 0)
+ if_modifier = OMP_TARGET_EXIT_DATA;
+ if (if_modifier != OMP_TARGET)
+ {
+ n = 3;
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ location_t loc = c_parser_peek_2nd_token (parser)->location;
+ error_at (loc, "expected %<data%>, %<update%>, %<enter%> "
+ "or %<exit%>");
+ if_modifier = ERROR_MARK;
+ }
+ if (if_modifier == OMP_TARGET_ENTER_DATA
+ || if_modifier == OMP_TARGET_EXIT_DATA)
+ {
+ if (c_parser_peek_2nd_token (parser)->type == CPP_NAME)
+ {
+ p = IDENTIFIER_POINTER
+ (c_parser_peek_2nd_token (parser)->value);
+ if (strcmp ("data", p) == 0)
+ n = 4;
+ }
+ if (n == 4)
+ c_parser_consume_token (parser);
+ else
+ {
+ location_t loc
+ = c_parser_peek_2nd_token (parser)->location;
+ error_at (loc, "expected %<data%>");
+ if_modifier = ERROR_MARK;
+ }
+ }
+ }
+ }
+ if (if_modifier != ERROR_MARK)
+ {
+ if (c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ {
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ if (n > 2)
+ {
+ location_t loc = c_parser_peek_2nd_token (parser)->location;
+ error_at (loc, "expected %<:%>");
+ }
+ if_modifier = ERROR_MARK;
+ }
+ }
+ }
+
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (loc, expr, true, true);
+ tree t = c_objc_common_truthvalue_conversion (loc, expr.value), c;
+ t = c_fully_fold (t, false, NULL);
+ parens.skip_until_found_close (parser);
+
+ for (c = list; c ; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IF)
+ {
+ if (if_modifier != ERROR_MARK
+ && OMP_CLAUSE_IF_MODIFIER (c) == if_modifier)
+ {
+ const char *p = NULL;
+ switch (if_modifier)
+ {
+ case VOID_CST: p = "cancel"; break;
+ case OMP_PARALLEL: p = "parallel"; break;
+ case OMP_SIMD: p = "simd"; break;
+ case OMP_TASK: p = "task"; break;
+ case OMP_TASKLOOP: p = "taskloop"; break;
+ case OMP_TARGET_DATA: p = "target data"; break;
+ case OMP_TARGET: p = "target"; break;
+ case OMP_TARGET_UPDATE: p = "target update"; break;
+ case OMP_TARGET_ENTER_DATA: p = "target enter data"; break;
+ case OMP_TARGET_EXIT_DATA: p = "target exit data"; break;
+ default: gcc_unreachable ();
+ }
+ error_at (location, "too many %<if%> clauses with %qs modifier",
+ p);
+ return list;
+ }
+ else if (OMP_CLAUSE_IF_MODIFIER (c) == if_modifier)
+ {
+ if (!is_omp)
+ error_at (location, "too many %<if%> clauses");
+ else
+ error_at (location, "too many %<if%> clauses without modifier");
+ return list;
+ }
+ else if (if_modifier == ERROR_MARK
+ || OMP_CLAUSE_IF_MODIFIER (c) == ERROR_MARK)
+ {
+ error_at (location, "if any %<if%> clause has modifier, then all "
+ "%<if%> clauses have to use modifier");
+ return list;
+ }
+ }
+
+ c = build_omp_clause (location, OMP_CLAUSE_IF);
+ OMP_CLAUSE_IF_MODIFIER (c) = if_modifier;
+ OMP_CLAUSE_IF_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 2.5:
+ lastprivate ( variable-list )
+
+ OpenMP 5.0:
+ lastprivate ( [ lastprivate-modifier : ] variable-list ) */
+
+static tree
+c_parser_omp_clause_lastprivate (c_parser *parser, tree list)
+{
+ /* The clauses location. */
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ if (c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ {
+ bool conditional = false;
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ {
+ const char *p
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "conditional") == 0)
+ {
+ conditional = true;
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ }
+ }
+ tree nlist = c_parser_omp_variable_list (parser, loc,
+ OMP_CLAUSE_LASTPRIVATE, list);
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+ if (conditional)
+ for (tree c = nlist; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_LASTPRIVATE_CONDITIONAL (c) = 1;
+ return nlist;
+ }
+ return 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;
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ tree c, t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+
+ parens.skip_until_found_close (parser);
+
+ 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));
+ protected_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 4.5:
+ num_tasks ( expression )
+
+ OpenMP 5.1:
+ num_tasks ( strict : expression ) */
+
+static tree
+c_parser_omp_clause_num_tasks (c_parser *parser, tree list)
+{
+ location_t num_tasks_loc = c_parser_peek_token (parser)->location;
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ bool strict = false;
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON
+ && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
+ "strict") == 0)
+ {
+ strict = true;
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ }
+
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ tree c, t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+
+ parens.skip_until_found_close (parser);
+
+ 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_tasks%> value must be positive");
+ t = integer_one_node;
+ }
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TASKS, "num_tasks");
+
+ c = build_omp_clause (num_tasks_loc, OMP_CLAUSE_NUM_TASKS);
+ OMP_CLAUSE_NUM_TASKS_EXPR (c) = t;
+ OMP_CLAUSE_NUM_TASKS_STRICT (c) = strict;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+/* OpenMP 4.5:
+ grainsize ( expression )
+
+ OpenMP 5.1:
+ grainsize ( strict : expression ) */
+
+static tree
+c_parser_omp_clause_grainsize (c_parser *parser, tree list)
+{
+ location_t grainsize_loc = c_parser_peek_token (parser)->location;
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ bool strict = false;
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON
+ && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
+ "strict") == 0)
+ {
+ strict = true;
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ }
+
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ tree c, t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+
+ parens.skip_until_found_close (parser);
+
+ 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, "%<grainsize%> value must be positive");
+ t = integer_one_node;
+ }
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_GRAINSIZE, "grainsize");
+
+ c = build_omp_clause (grainsize_loc, OMP_CLAUSE_GRAINSIZE);
+ OMP_CLAUSE_GRAINSIZE_EXPR (c) = t;
+ OMP_CLAUSE_GRAINSIZE_STRICT (c) = strict;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+/* OpenMP 4.5:
+ priority ( expression ) */
+
+static tree
+c_parser_omp_clause_priority (c_parser *parser, tree list)
+{
+ location_t priority_loc = c_parser_peek_token (parser)->location;
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ tree c, t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+
+ parens.skip_until_found_close (parser);
+
+ 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
+ non-negative. */
+ c = fold_build2_loc (expr_loc, LT_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, "%<priority%> value must be non-negative");
+ t = integer_one_node;
+ }
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_PRIORITY, "priority");
+
+ c = build_omp_clause (priority_loc, OMP_CLAUSE_PRIORITY);
+ OMP_CLAUSE_PRIORITY_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+/* OpenMP 4.5:
+ hint ( expression ) */
+
+static tree
+c_parser_omp_clause_hint (c_parser *parser, tree list)
+{
+ location_t hint_loc = c_parser_peek_token (parser)->location;
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ tree c, t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+ || TREE_CODE (t) != INTEGER_CST
+ || tree_int_cst_sgn (t) == -1)
+ {
+ c_parser_error (parser, "expected constant integer expression "
+ "with valid sync-hint value");
+ return list;
+ }
+ parens.skip_until_found_close (parser);
+ check_no_duplicate_clause (list, OMP_CLAUSE_HINT, "hint");
+
+ c = build_omp_clause (hint_loc, OMP_CLAUSE_HINT);
+ OMP_CLAUSE_HINT_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+/* OpenMP 5.1:
+ filter ( integer-expression ) */
+
+static tree
+c_parser_omp_clause_filter (c_parser *parser, tree list)
+{
+ location_t hint_loc = c_parser_peek_token (parser)->location;
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ tree c, t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ c_parser_error (parser, "expected integer expression");
+ return list;
+ }
+ parens.skip_until_found_close (parser);
+ check_no_duplicate_clause (list, OMP_CLAUSE_FILTER, "filter");
+
+ c = build_omp_clause (hint_loc, OMP_CLAUSE_FILTER);
+ OMP_CLAUSE_FILTER_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+/* OpenMP 4.5:
+ defaultmap ( tofrom : scalar )
+
+ OpenMP 5.0:
+ defaultmap ( implicit-behavior [ : variable-category ] ) */
+
+static tree
+c_parser_omp_clause_defaultmap (c_parser *parser, tree list)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree c;
+ const char *p;
+ enum omp_clause_defaultmap_kind behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT;
+ enum omp_clause_defaultmap_kind category
+ = OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+ if (c_parser_next_token_is_keyword (parser, RID_DEFAULT))
+ p = "default";
+ else if (!c_parser_next_token_is (parser, CPP_NAME))
+ {
+ invalid_behavior:
+ c_parser_error (parser, "expected %<alloc%>, %<to%>, %<from%>, "
+ "%<tofrom%>, %<firstprivate%>, %<none%> "
+ "or %<default%>");
+ goto out_err;
+ }
+ else
+ p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ switch (p[0])
+ {
+ case 'a':
+ if (strcmp ("alloc", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_ALLOC;
+ else
+ goto invalid_behavior;
+ break;
+
+ case 'd':
+ if (strcmp ("default", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_DEFAULT;
+ else
+ goto invalid_behavior;
+ break;
+
+ case 'f':
+ if (strcmp ("firstprivate", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_FIRSTPRIVATE;
+ else if (strcmp ("from", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_FROM;
+ else
+ goto invalid_behavior;
+ break;
+
+ case 'n':
+ if (strcmp ("none", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_NONE;
+ else
+ goto invalid_behavior;
+ break;
+
+ case 't':
+ if (strcmp ("tofrom", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_TOFROM;
+ else if (strcmp ("to", p) == 0)
+ behavior = OMP_CLAUSE_DEFAULTMAP_TO;
+ else
+ goto invalid_behavior;
+ break;
+
+ default:
+ goto invalid_behavior;
+ }
+ c_parser_consume_token (parser);
+
+ if (!c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ goto out_err;
+ if (!c_parser_next_token_is (parser, CPP_NAME))
+ {
+ invalid_category:
+ c_parser_error (parser, "expected %<scalar%>, %<aggregate%> or "
+ "%<pointer%>");
+ goto out_err;
+ }
+ p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ switch (p[0])
+ {
+ case 'a':
+ if (strcmp ("aggregate", p) == 0)
+ category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE;
+ else
+ goto invalid_category;
+ break;
+
+ case 'p':
+ if (strcmp ("pointer", p) == 0)
+ category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER;
+ else
+ goto invalid_category;
+ break;
+
+ case 's':
+ if (strcmp ("scalar", p) == 0)
+ category = OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR;
+ else
+ goto invalid_category;
+ break;
+
+ default:
+ goto invalid_category;
+ }
+
+ c_parser_consume_token (parser);
+ }
+ parens.skip_until_found_close (parser);
+
+ for (c = list; c ; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEFAULTMAP
+ && (category == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED
+ || OMP_CLAUSE_DEFAULTMAP_CATEGORY (c) == category
+ || (OMP_CLAUSE_DEFAULTMAP_CATEGORY (c)
+ == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED)))
+ {
+ enum omp_clause_defaultmap_kind cat = category;
+ location_t loc = OMP_CLAUSE_LOCATION (c);
+ if (cat == OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED)
+ cat = OMP_CLAUSE_DEFAULTMAP_CATEGORY (c);
+ p = NULL;
+ switch (cat)
+ {
+ case OMP_CLAUSE_DEFAULTMAP_CATEGORY_UNSPECIFIED:
+ p = NULL;
+ break;
+ case OMP_CLAUSE_DEFAULTMAP_CATEGORY_AGGREGATE:
+ p = "aggregate";
+ break;
+ case OMP_CLAUSE_DEFAULTMAP_CATEGORY_POINTER:
+ p = "pointer";
+ break;
+ case OMP_CLAUSE_DEFAULTMAP_CATEGORY_SCALAR:
+ p = "scalar";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ if (p)
+ error_at (loc, "too many %<defaultmap%> clauses with %qs category",
+ p);
+ else
+ error_at (loc, "too many %<defaultmap%> clauses with unspecified "
+ "category");
+ break;
+ }
+
+ c = build_omp_clause (loc, OMP_CLAUSE_DEFAULTMAP);
+ OMP_CLAUSE_DEFAULTMAP_SET_KIND (c, behavior, category);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+
+ out_err:
+ parens.skip_until_found_close (parser);
+ return list;
+}
+
+/* OpenACC 2.0:
+ use_device ( variable-list )
+
+ OpenMP 4.5:
+ use_device_ptr ( variable-list ) */
+
+static tree
+c_parser_omp_clause_use_device_ptr (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_USE_DEVICE_PTR,
+ list);
+}
+
+/* OpenMP 5.0:
+ use_device_addr ( variable-list ) */
+
+static tree
+c_parser_omp_clause_use_device_addr (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_USE_DEVICE_ADDR,
+ list);
+}
+
+/* OpenMP 4.5:
+ is_device_ptr ( variable-list ) */
+
+static tree
+c_parser_omp_clause_is_device_ptr (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_IS_DEVICE_PTR, list);
+}
+
+/* OpenACC:
+ num_gangs ( expression )
+ num_workers ( expression )
+ vector_length ( expression ) */
+
+static tree
+c_parser_oacc_single_int_clause (c_parser *parser, omp_clause_code code,
+ tree list)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expression (parser);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ tree c, t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+
+ parens.skip_until_found_close (parser);
+
+ if (t == error_mark_node)
+ return list;
+ else if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error_at (expr_loc, "%qs expression must be integral",
+ omp_clause_code_name[code]);
+ 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));
+ protected_set_expr_location (c, expr_loc);
+ if (c == boolean_true_node)
+ {
+ warning_at (expr_loc, 0,
+ "%qs value must be positive",
+ omp_clause_code_name[code]);
+ t = integer_one_node;
+ }
+
+ check_no_duplicate_clause (list, code, omp_clause_code_name[code]);
+
+ c = build_omp_clause (loc, code);
+ OMP_CLAUSE_OPERAND (c, 0) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenACC:
+
+ gang [( gang-arg-list )]
+ worker [( [num:] int-expr )]
+ vector [( [length:] int-expr )]
+
+ where gang-arg is one of:
+
+ [num:] int-expr
+ static: size-expr
+
+ and size-expr may be:
+
+ *
+ int-expr
+*/
+
+static tree
+c_parser_oacc_shape_clause (c_parser *parser, location_t loc,
+ omp_clause_code kind,
+ const char *str, tree list)
+{
+ const char *id = "num";
+ tree ops[2] = { NULL_TREE, NULL_TREE }, c;
+
+ if (kind == OMP_CLAUSE_VECTOR)
+ id = "length";
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ c_parser_consume_token (parser);
+
+ do
+ {
+ c_token *next = c_parser_peek_token (parser);
+ int idx = 0;
+
+ /* Gang static argument. */
+ if (kind == OMP_CLAUSE_GANG
+ && c_parser_next_token_is_keyword (parser, RID_STATIC))
+ {
+ c_parser_consume_token (parser);
+
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ goto cleanup_error;
+
+ idx = 1;
+ if (ops[idx] != NULL_TREE)
+ {
+ c_parser_error (parser, "too many %<static%> arguments");
+ goto cleanup_error;
+ }
+
+ /* Check for the '*' argument. */
+ if (c_parser_next_token_is (parser, CPP_MULT)
+ && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA
+ || c_parser_peek_2nd_token (parser)->type
+ == CPP_CLOSE_PAREN))
+ {
+ c_parser_consume_token (parser);
+ ops[idx] = integer_minus_one_node;
+
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ continue;
+ }
+ else
+ break;
+ }
+ }
+ /* Worker num: argument and vector length: arguments. */
+ else if (c_parser_next_token_is (parser, CPP_NAME)
+ && strcmp (id, IDENTIFIER_POINTER (next->value)) == 0
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ {
+ c_parser_consume_token (parser); /* id */
+ c_parser_consume_token (parser); /* ':' */
+ }
+
+ /* Now collect the actual argument. */
+ if (ops[idx] != NULL_TREE)
+ {
+ c_parser_error (parser, "unexpected argument");
+ goto cleanup_error;
+ }
+
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr cexpr = c_parser_expr_no_commas (parser, NULL);
+ cexpr = convert_lvalue_to_rvalue (expr_loc, cexpr, false, true);
+ tree expr = cexpr.value;
+ if (expr == error_mark_node)
+ goto cleanup_error;
+
+ expr = c_fully_fold (expr, false, NULL);
+
+ /* Attempt to statically determine when the number isn't a
+ positive integer. */
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (expr)))
+ {
+ c_parser_error (parser, "expected integer expression");
+ return list;
+ }
+
+ tree c = fold_build2_loc (expr_loc, LE_EXPR, boolean_type_node, expr,
+ build_int_cst (TREE_TYPE (expr), 0));
+ if (c == boolean_true_node)
+ {
+ warning_at (loc, 0,
+ "%qs value must be positive", str);
+ expr = integer_one_node;
+ }
+
+ ops[idx] = expr;
+
+ if (kind == OMP_CLAUSE_GANG
+ && c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ continue;
+ }
+ break;
+ }
+ while (1);
+
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ goto cleanup_error;
+ }
+
+ check_no_duplicate_clause (list, kind, str);
+
+ c = build_omp_clause (loc, kind);
+
+ if (ops[1])
+ OMP_CLAUSE_OPERAND (c, 1) = ops[1];
+
+ OMP_CLAUSE_OPERAND (c, 0) = ops[0];
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+
+ cleanup_error:
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0);
+ return list;
+}
+
+/* OpenACC 2.5:
+ auto
+ finalize
+ independent
+ nohost
+ seq */
+
+static tree
+c_parser_oacc_simple_clause (location_t loc, enum omp_clause_code code,
+ tree list)
+{
+ check_no_duplicate_clause (list, code, omp_clause_code_name[code]);
+
+ tree c = build_omp_clause (loc, code);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* OpenACC:
+ async [( int-expr )] */
+
+static tree
+c_parser_oacc_clause_async (c_parser *parser, tree list)
+{
+ tree c, t;
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ t = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL);
+
+ if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN)
+ {
+ c_parser_consume_token (parser);
+
+ t = c_parser_expr_no_commas (parser, NULL).value;
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ c_parser_error (parser, "expected integer expression");
+ else if (t == error_mark_node
+ || !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ return list;
+ }
+ else
+ t = c_fully_fold (t, false, NULL);
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_ASYNC, "async");
+
+ c = build_omp_clause (loc, OMP_CLAUSE_ASYNC);
+ OMP_CLAUSE_ASYNC_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+
+ return list;
+}
+
+/* OpenACC 2.0:
+ tile ( size-expr-list ) */
+
+static tree
+c_parser_oacc_clause_tile (c_parser *parser, tree list)
+{
+ tree c, expr = error_mark_node;
+ location_t loc;
+ tree tile = NULL_TREE;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_TILE, "tile");
+ 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 %<(%>"))
+ return list;
+
+ do
+ {
+ if (tile && !c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ return list;
+
+ if (c_parser_next_token_is (parser, CPP_MULT)
+ && (c_parser_peek_2nd_token (parser)->type == CPP_COMMA
+ || c_parser_peek_2nd_token (parser)->type == CPP_CLOSE_PAREN))
+ {
+ c_parser_consume_token (parser);
+ expr = integer_zero_node;
+ }
+ else
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr cexpr = c_parser_expr_no_commas (parser, NULL);
+ cexpr = convert_lvalue_to_rvalue (expr_loc, cexpr, false, true);
+ expr = cexpr.value;
+
+ if (expr == error_mark_node)
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return list;
+ }
+
+ expr = c_fully_fold (expr, false, NULL);
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (expr))
+ || !tree_fits_shwi_p (expr)
+ || tree_to_shwi (expr) <= 0)
+ {
+ error_at (expr_loc, "%<tile%> argument needs positive"
+ " integral constant");
+ expr = integer_zero_node;
+ }
+ }
+
+ tile = tree_cons (NULL_TREE, expr, tile);
+ }
+ while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN));
+
+ /* Consume the trailing ')'. */
+ c_parser_consume_token (parser);
+
+ c = build_omp_clause (loc, OMP_CLAUSE_TILE);
+ tile = nreverse (tile);
+ OMP_CLAUSE_TILE_LIST (c) = tile;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenACC:
+ wait [( int-expr-list )] */
+
+static tree
+c_parser_oacc_clause_wait (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+
+ if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN)
+ list = c_parser_oacc_wait_list (parser, clause_loc, list);
+ else
+ {
+ tree c = build_omp_clause (clause_loc, OMP_CLAUSE_WAIT);
+
+ OMP_CLAUSE_DECL (c) = build_int_cst (integer_type_node, GOMP_ASYNC_NOVAL);
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+
+/* OpenMP 5.0:
+ order ( concurrent )
+
+ OpenMP 5.1:
+ order ( order-modifier : concurrent )
+
+ order-modifier:
+ reproducible
+ unconstrained */
+
+static tree
+c_parser_omp_clause_order (c_parser *parser, tree list)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree c;
+ const char *p;
+ bool unconstrained = false;
+ bool reproducible = false;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ {
+ p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "unconstrained") == 0)
+ unconstrained = true;
+ else if (strcmp (p, "reproducible") == 0)
+ reproducible = true;
+ else
+ {
+ c_parser_error (parser, "expected %<reproducible%> or "
+ "%<unconstrained%>");
+ goto out_err;
+ }
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ }
+ if (!c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected %<concurrent%>");
+ goto out_err;
+ }
+ p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "concurrent") != 0)
+ {
+ c_parser_error (parser, "expected %<concurrent%>");
+ goto out_err;
+ }
+ c_parser_consume_token (parser);
+ parens.skip_until_found_close (parser);
+ check_no_duplicate_clause (list, OMP_CLAUSE_ORDER, "order");
+ c = build_omp_clause (loc, OMP_CLAUSE_ORDER);
+ OMP_CLAUSE_ORDER_UNCONSTRAINED (c) = unconstrained;
+ OMP_CLAUSE_ORDER_REPRODUCIBLE (c) = reproducible;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+
+ out_err:
+ parens.skip_until_found_close (parser);
+ return list;
+}
+
+
+/* OpenMP 5.0:
+ bind ( teams | parallel | thread ) */
+
+static tree
+c_parser_omp_clause_bind (c_parser *parser, tree list)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree c;
+ const char *p;
+ enum omp_clause_bind_kind kind = OMP_CLAUSE_BIND_THREAD;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+ if (!c_parser_next_token_is (parser, CPP_NAME))
+ {
+ invalid:
+ c_parser_error (parser,
+ "expected %<teams%>, %<parallel%> or %<thread%>");
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "teams") == 0)
+ kind = OMP_CLAUSE_BIND_TEAMS;
+ else if (strcmp (p, "parallel") == 0)
+ kind = OMP_CLAUSE_BIND_PARALLEL;
+ else if (strcmp (p, "thread") != 0)
+ goto invalid;
+ c_parser_consume_token (parser);
+ parens.skip_until_found_close (parser);
+ /* check_no_duplicate_clause (list, OMP_CLAUSE_BIND, "bind"); */
+ c = build_omp_clause (loc, OMP_CLAUSE_BIND);
+ OMP_CLAUSE_BIND_KIND (c) = kind;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+
+/* OpenMP 2.5:
+ ordered
+
+ OpenMP 4.5:
+ ordered ( constant-expression ) */
+
+static tree
+c_parser_omp_clause_ordered (c_parser *parser, tree list)
+{
+ check_no_duplicate_clause (list, OMP_CLAUSE_ORDERED, "ordered");
+
+ tree c, num = NULL_TREE;
+ HOST_WIDE_INT n;
+ location_t loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ matching_parens parens;
+ parens.consume_open (parser);
+ num = c_parser_expr_no_commas (parser, NULL).value;
+ parens.skip_until_found_close (parser);
+ }
+ if (num == error_mark_node)
+ return list;
+ if (num)
+ {
+ mark_exp_read (num);
+ num = c_fully_fold (num, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (num))
+ || !tree_fits_shwi_p (num)
+ || (n = tree_to_shwi (num)) <= 0
+ || (int) n != n)
+ {
+ error_at (loc, "ordered argument needs positive "
+ "constant integer expression");
+ return list;
+ }
+ }
+ c = build_omp_clause (loc, OMP_CLAUSE_ORDERED);
+ OMP_CLAUSE_ORDERED_EXPR (c) = num;
+ 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
+
+ OpenMP 4.0:
+
+ reduction-operator:
+ One of: + * - & ^ | && ||
+ identifier
+
+ OpenMP 5.0:
+ reduction ( reduction-modifier, reduction-operator : variable-list )
+ in_reduction ( reduction-operator : variable-list )
+ task_reduction ( reduction-operator : variable-list ) */
+
+static tree
+c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind,
+ bool is_omp, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ bool task = false;
+ bool inscan = false;
+ enum tree_code code = ERROR_MARK;
+ tree reduc_id = NULL_TREE;
+
+ if (kind == OMP_CLAUSE_REDUCTION && is_omp)
+ {
+ if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
+ {
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ }
+ else if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
+ {
+ const char *p
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "task") == 0)
+ task = true;
+ else if (strcmp (p, "inscan") == 0)
+ inscan = true;
+ if (task || inscan)
+ {
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ }
+ }
+ }
+
+ 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;
+ }
+ reduc_id = c_parser_peek_token (parser)->value;
+ break;
+ }
+ default:
+ c_parser_error (parser,
+ "expected %<+%>, %<*%>, %<-%>, %<&%>, "
+ "%<^%>, %<|%>, %<&&%>, %<||%> or identifier");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0);
+ return list;
+ }
+ c_parser_consume_token (parser);
+ reduc_id = c_omp_reduction_id (code, reduc_id);
+ if (c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ {
+ tree nl, c;
+
+ nl = c_parser_omp_variable_list (parser, clause_loc, kind, list);
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ {
+ tree d = OMP_CLAUSE_DECL (c), type;
+ if (TREE_CODE (d) != TREE_LIST)
+ type = TREE_TYPE (d);
+ else
+ {
+ int cnt = 0;
+ tree t;
+ for (t = d; TREE_CODE (t) == TREE_LIST; t = TREE_CHAIN (t))
+ cnt++;
+ type = TREE_TYPE (t);
+ while (cnt > 0)
+ {
+ if (TREE_CODE (type) != POINTER_TYPE
+ && TREE_CODE (type) != ARRAY_TYPE)
+ break;
+ type = TREE_TYPE (type);
+ cnt--;
+ }
+ }
+ while (TREE_CODE (type) == ARRAY_TYPE)
+ type = TREE_TYPE (type);
+ OMP_CLAUSE_REDUCTION_CODE (c) = code;
+ if (task)
+ OMP_CLAUSE_REDUCTION_TASK (c) = 1;
+ else if (inscan)
+ OMP_CLAUSE_REDUCTION_INSCAN (c) = 1;
+ if (code == ERROR_MARK
+ || !(INTEGRAL_TYPE_P (type)
+ || TREE_CODE (type) == REAL_TYPE
+ || TREE_CODE (type) == COMPLEX_TYPE))
+ OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)
+ = c_omp_reduction_lookup (reduc_id,
+ TYPE_MAIN_VARIANT (type));
+ }
+
+ list = nl;
+ }
+ parens.skip_until_found_close (parser);
+ }
+ return list;
+}
+
+/* OpenMP 2.5:
+ schedule ( schedule-kind )
+ schedule ( schedule-kind , expression )
+
+ schedule-kind:
+ static | dynamic | guided | runtime | auto
+
+ OpenMP 4.5:
+ schedule ( schedule-modifier : schedule-kind )
+ schedule ( schedule-modifier [ , schedule-modifier ] : schedule-kind , expression )
+
+ schedule-modifier:
+ simd
+ monotonic
+ nonmonotonic */
+
+static tree
+c_parser_omp_clause_schedule (c_parser *parser, tree list)
+{
+ tree c, t;
+ location_t loc = c_parser_peek_token (parser)->location;
+ int modifiers = 0, nmodifiers = 0;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ c = build_omp_clause (loc, OMP_CLAUSE_SCHEDULE);
+
+ location_t comma = UNKNOWN_LOCATION;
+ while (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ tree kind = c_parser_peek_token (parser)->value;
+ const char *p = IDENTIFIER_POINTER (kind);
+ if (strcmp ("simd", p) == 0)
+ OMP_CLAUSE_SCHEDULE_SIMD (c) = 1;
+ else if (strcmp ("monotonic", p) == 0)
+ modifiers |= OMP_CLAUSE_SCHEDULE_MONOTONIC;
+ else if (strcmp ("nonmonotonic", p) == 0)
+ modifiers |= OMP_CLAUSE_SCHEDULE_NONMONOTONIC;
+ else
+ break;
+ comma = UNKNOWN_LOCATION;
+ c_parser_consume_token (parser);
+ if (nmodifiers++ == 0
+ && c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ comma = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ c_parser_require (parser, CPP_COLON, "expected %<:%>");
+ break;
+ }
+ }
+ if (comma != UNKNOWN_LOCATION)
+ error_at (comma, "expected %<:%>");
+
+ if ((modifiers & (OMP_CLAUSE_SCHEDULE_MONOTONIC
+ | OMP_CLAUSE_SCHEDULE_NONMONOTONIC))
+ == (OMP_CLAUSE_SCHEDULE_MONOTONIC
+ | OMP_CLAUSE_SCHEDULE_NONMONOTONIC))
+ {
+ error_at (loc, "both %<monotonic%> and %<nonmonotonic%> modifiers "
+ "specified");
+ modifiers = 0;
+ }
+
+ 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;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (here, expr, false, true);
+ t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+
+ if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME)
+ error_at (here, "schedule %<runtime%> does not take "
+ "a %<chunk_size%> parameter");
+ else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO)
+ error_at (here,
+ "schedule %<auto%> does not take "
+ "a %<chunk_size%> parameter");
+ else if (TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE)
+ {
+ /* Attempt to statically determine when the number isn't
+ positive. */
+ tree s = fold_build2_loc (loc, LE_EXPR, boolean_type_node, t,
+ build_int_cst (TREE_TYPE (t), 0));
+ protected_set_expr_location (s, loc);
+ if (s == boolean_true_node)
+ {
+ warning_at (loc, 0,
+ "chunk size value must be positive");
+ t = integer_one_node;
+ }
+ OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t;
+ }
+ else
+ c_parser_error (parser, "expected integer expression");
+
+ parens.skip_until_found_close (parser);
+ }
+ else
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<,%> or %<)%>");
+
+ OMP_CLAUSE_SCHEDULE_KIND (c)
+ = (enum omp_clause_schedule_kind)
+ (OMP_CLAUSE_SCHEDULE_KIND (c) | modifiers);
+
+ 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;
+}
+
+/* OpenMP 4.0:
+ inbranch
+ notinbranch */
+
+static tree
+c_parser_omp_clause_branch (c_parser *parser ATTRIBUTE_UNUSED,
+ enum omp_clause_code code, tree list)
+{
+ check_no_duplicate_clause (list, code, omp_clause_code_name[code]);
+
+ tree c = build_omp_clause (c_parser_peek_token (parser)->location, code);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* OpenMP 4.0:
+ parallel
+ for
+ sections
+ taskgroup */
+
+static tree
+c_parser_omp_clause_cancelkind (c_parser *parser ATTRIBUTE_UNUSED,
+ enum omp_clause_code code, tree list)
+{
+ tree c = build_omp_clause (c_parser_peek_token (parser)->location, code);
+ OMP_CLAUSE_CHAIN (c) = list;
+
+ return c;
+}
+
+/* OpenMP 4.5:
+ nogroup */
+
+static tree
+c_parser_omp_clause_nogroup (c_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+ check_no_duplicate_clause (list, OMP_CLAUSE_NOGROUP, "nogroup");
+ tree c = build_omp_clause (c_parser_peek_token (parser)->location,
+ OMP_CLAUSE_NOGROUP);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 4.5:
+ simd
+ threads */
+
+static tree
+c_parser_omp_clause_orderedkind (c_parser *parser ATTRIBUTE_UNUSED,
+ enum omp_clause_code code, tree list)
+{
+ check_no_duplicate_clause (list, code, omp_clause_code_name[code]);
+ tree c = build_omp_clause (c_parser_peek_token (parser)->location, code);
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 4.0:
+ num_teams ( expression )
+
+ OpenMP 5.1:
+ num_teams ( expression : expression ) */
+
+static tree
+c_parser_omp_clause_num_teams (c_parser *parser, tree list)
+{
+ location_t num_teams_loc = c_parser_peek_token (parser)->location;
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ location_t upper_loc = c_parser_peek_token (parser)->location;
+ location_t lower_loc = UNKNOWN_LOCATION;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (upper_loc, expr, false, true);
+ tree c, upper = expr.value, lower = NULL_TREE;
+ upper = c_fully_fold (upper, false, NULL);
+
+ if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ c_parser_consume_token (parser);
+ lower_loc = upper_loc;
+ lower = upper;
+ upper_loc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (upper_loc, expr, false, true);
+ upper = expr.value;
+ upper = c_fully_fold (upper, false, NULL);
+ }
+
+ parens.skip_until_found_close (parser);
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (upper))
+ || (lower && !INTEGRAL_TYPE_P (TREE_TYPE (lower))))
+ {
+ c_parser_error (parser, "expected integer expression");
+ return list;
+ }
+
+ /* Attempt to statically determine when the number isn't positive. */
+ c = fold_build2_loc (upper_loc, LE_EXPR, boolean_type_node, upper,
+ build_int_cst (TREE_TYPE (upper), 0));
+ protected_set_expr_location (c, upper_loc);
+ if (c == boolean_true_node)
+ {
+ warning_at (upper_loc, 0, "%<num_teams%> value must be positive");
+ upper = integer_one_node;
+ }
+ if (lower)
+ {
+ c = fold_build2_loc (lower_loc, LE_EXPR, boolean_type_node, lower,
+ build_int_cst (TREE_TYPE (lower), 0));
+ protected_set_expr_location (c, lower_loc);
+ if (c == boolean_true_node)
+ {
+ warning_at (lower_loc, 0, "%<num_teams%> value must be positive");
+ lower = NULL_TREE;
+ }
+ else if (TREE_CODE (lower) == INTEGER_CST
+ && TREE_CODE (upper) == INTEGER_CST
+ && tree_int_cst_lt (upper, lower))
+ {
+ warning_at (lower_loc, 0, "%<num_teams%> lower bound %qE bigger "
+ "than upper bound %qE", lower, upper);
+ lower = NULL_TREE;
+ }
+ }
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_NUM_TEAMS, "num_teams");
+
+ c = build_omp_clause (num_teams_loc, OMP_CLAUSE_NUM_TEAMS);
+ OMP_CLAUSE_NUM_TEAMS_UPPER_EXPR (c) = upper;
+ OMP_CLAUSE_NUM_TEAMS_LOWER_EXPR (c) = lower;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+/* OpenMP 4.0:
+ thread_limit ( expression ) */
+
+static tree
+c_parser_omp_clause_thread_limit (c_parser *parser, tree list)
+{
+ location_t num_thread_limit_loc = c_parser_peek_token (parser)->location;
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ tree c, t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+
+ parens.skip_until_found_close (parser);
+
+ 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));
+ protected_set_expr_location (c, expr_loc);
+ if (c == boolean_true_node)
+ {
+ warning_at (expr_loc, 0, "%<thread_limit%> value must be positive");
+ t = integer_one_node;
+ }
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_THREAD_LIMIT,
+ "thread_limit");
+
+ c = build_omp_clause (num_thread_limit_loc, OMP_CLAUSE_THREAD_LIMIT);
+ OMP_CLAUSE_THREAD_LIMIT_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ list = c;
+ }
+
+ return list;
+}
+
+/* OpenMP 4.0:
+ aligned ( variable-list )
+ aligned ( variable-list : constant-expression ) */
+
+static tree
+c_parser_omp_clause_aligned (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ tree nl, c;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ nl = c_parser_omp_variable_list (parser, clause_loc,
+ OMP_CLAUSE_ALIGNED, list);
+
+ if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ c_parser_consume_token (parser);
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ tree alignment = expr.value;
+ alignment = c_fully_fold (alignment, false, NULL);
+ if (TREE_CODE (alignment) != INTEGER_CST
+ || !INTEGRAL_TYPE_P (TREE_TYPE (alignment))
+ || tree_int_cst_sgn (alignment) != 1)
+ {
+ error_at (clause_loc, "%<aligned%> clause alignment expression must "
+ "be positive constant integer expression");
+ alignment = NULL_TREE;
+ }
+
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = alignment;
+ }
+
+ parens.skip_until_found_close (parser);
+ return nl;
+}
+
+/* OpenMP 5.0:
+ allocate ( variable-list )
+ allocate ( expression : variable-list )
+
+ OpenMP 5.1:
+ allocate ( allocator-modifier : variable-list )
+ allocate ( allocator-modifier , allocator-modifier : variable-list )
+
+ allocator-modifier:
+ allocator ( expression )
+ align ( expression ) */
+
+static tree
+c_parser_omp_clause_allocate (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ tree nl, c;
+ tree allocator = NULL_TREE;
+ tree align = NULL_TREE;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ if ((c_parser_next_token_is_not (parser, CPP_NAME)
+ && c_parser_next_token_is_not (parser, CPP_KEYWORD))
+ || (c_parser_peek_2nd_token (parser)->type != CPP_COMMA
+ && c_parser_peek_2nd_token (parser)->type != CPP_CLOSE_PAREN))
+ {
+ bool has_modifiers = false;
+ tree orig_type = NULL_TREE;
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN)
+ {
+ unsigned int n = 3;
+ const char *p
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if ((strcmp (p, "allocator") == 0 || strcmp (p, "align") == 0)
+ && c_parser_check_balanced_raw_token_sequence (parser, &n)
+ && (c_parser_peek_nth_token_raw (parser, n)->type
+ == CPP_CLOSE_PAREN))
+ {
+ if (c_parser_peek_nth_token_raw (parser, n + 1)->type
+ == CPP_COLON)
+ has_modifiers = true;
+ else if (c_parser_peek_nth_token_raw (parser, n + 1)->type
+ == CPP_COMMA
+ && (c_parser_peek_nth_token_raw (parser, n + 2)->type
+ == CPP_NAME)
+ && (c_parser_peek_nth_token_raw (parser, n + 3)->type
+ == CPP_OPEN_PAREN))
+ {
+ c_token *tok = c_parser_peek_nth_token_raw (parser, n + 2);
+ const char *q = IDENTIFIER_POINTER (tok->value);
+ n += 4;
+ if ((strcmp (q, "allocator") == 0
+ || strcmp (q, "align") == 0)
+ && c_parser_check_balanced_raw_token_sequence (parser,
+ &n)
+ && (c_parser_peek_nth_token_raw (parser, n)->type
+ == CPP_CLOSE_PAREN)
+ && (c_parser_peek_nth_token_raw (parser, n + 1)->type
+ == CPP_COLON))
+ has_modifiers = true;
+ }
+ }
+ if (has_modifiers)
+ {
+ c_parser_consume_token (parser);
+ matching_parens parens2;;
+ parens2.require_open (parser);
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ if (strcmp (p, "allocator") == 0)
+ {
+ allocator = expr.value;
+ allocator = c_fully_fold (allocator, false, NULL);
+ orig_type = expr.original_type
+ ? expr.original_type : TREE_TYPE (allocator);
+ orig_type = TYPE_MAIN_VARIANT (orig_type);
+ }
+ else
+ {
+ align = expr.value;
+ align = c_fully_fold (align, false, NULL);
+ }
+ parens2.skip_until_found_close (parser);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ c_token *tok = c_parser_peek_token (parser);
+ const char *q = "";
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ q = IDENTIFIER_POINTER (tok->value);
+ if (strcmp (q, "allocator") != 0 && strcmp (q, "align") != 0)
+ {
+ c_parser_error (parser, "expected %<allocator%> or "
+ "%<align%>");
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ else if (strcmp (p, q) == 0)
+ {
+ error_at (tok->location, "duplicate %qs modifier", p);
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ c_parser_consume_token (parser);
+ if (!parens2.require_open (parser))
+ {
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ expr_loc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false,
+ true);
+ if (strcmp (q, "allocator") == 0)
+ {
+ allocator = expr.value;
+ allocator = c_fully_fold (allocator, false, NULL);
+ orig_type = expr.original_type
+ ? expr.original_type : TREE_TYPE (allocator);
+ orig_type = TYPE_MAIN_VARIANT (orig_type);
+ }
+ else
+ {
+ align = expr.value;
+ align = c_fully_fold (align, false, NULL);
+ }
+ parens2.skip_until_found_close (parser);
+ }
+ }
+ }
+ if (!has_modifiers)
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ allocator = expr.value;
+ allocator = c_fully_fold (allocator, false, NULL);
+ orig_type = expr.original_type
+ ? expr.original_type : TREE_TYPE (allocator);
+ orig_type = TYPE_MAIN_VARIANT (orig_type);
+ }
+ if (allocator
+ && (!INTEGRAL_TYPE_P (TREE_TYPE (allocator))
+ || TREE_CODE (orig_type) != ENUMERAL_TYPE
+ || (TYPE_NAME (orig_type)
+ != get_identifier ("omp_allocator_handle_t"))))
+ {
+ error_at (clause_loc, "%<allocate%> clause allocator expression "
+ "has type %qT rather than "
+ "%<omp_allocator_handle_t%>",
+ TREE_TYPE (allocator));
+ allocator = NULL_TREE;
+ }
+ if (align
+ && (!INTEGRAL_TYPE_P (TREE_TYPE (align))
+ || !tree_fits_uhwi_p (align)
+ || !integer_pow2p (align)))
+ {
+ error_at (clause_loc, "%<allocate%> clause %<align%> modifier "
+ "argument needs to be positive constant "
+ "power of two integer expression");
+ align = NULL_TREE;
+ }
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ {
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ }
+
+ nl = c_parser_omp_variable_list (parser, clause_loc,
+ OMP_CLAUSE_ALLOCATE, list);
+
+ if (allocator || align)
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ {
+ OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator;
+ OMP_CLAUSE_ALLOCATE_ALIGN (c) = align;
+ }
+
+ parens.skip_until_found_close (parser);
+ return nl;
+}
+
+/* OpenMP 4.0:
+ linear ( variable-list )
+ linear ( variable-list : expression )
+
+ OpenMP 4.5:
+ linear ( modifier ( variable-list ) )
+ linear ( modifier ( variable-list ) : expression ) */
+
+static tree
+c_parser_omp_clause_linear (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ tree nl, c, step;
+ enum omp_clause_linear_kind kind = OMP_CLAUSE_LINEAR_DEFAULT;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_token *tok = c_parser_peek_token (parser);
+ const char *p = IDENTIFIER_POINTER (tok->value);
+ if (strcmp ("val", p) == 0)
+ kind = OMP_CLAUSE_LINEAR_VAL;
+ if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN)
+ kind = OMP_CLAUSE_LINEAR_DEFAULT;
+ if (kind != OMP_CLAUSE_LINEAR_DEFAULT)
+ {
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ }
+ }
+
+ nl = c_parser_omp_variable_list (parser, clause_loc,
+ OMP_CLAUSE_LINEAR, list);
+
+ if (kind != OMP_CLAUSE_LINEAR_DEFAULT)
+ parens.skip_until_found_close (parser);
+
+ if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ c_parser_consume_token (parser);
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ step = expr.value;
+ step = c_fully_fold (step, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (step)))
+ {
+ error_at (clause_loc, "%<linear%> clause step expression must "
+ "be integral");
+ step = integer_one_node;
+ }
+
+ }
+ else
+ step = integer_one_node;
+
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ {
+ OMP_CLAUSE_LINEAR_STEP (c) = step;
+ OMP_CLAUSE_LINEAR_KIND (c) = kind;
+ }
+
+ parens.skip_until_found_close (parser);
+ return nl;
+}
+
+/* OpenMP 5.0:
+ nontemporal ( variable-list ) */
+
+static tree
+c_parser_omp_clause_nontemporal (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_NONTEMPORAL, list);
+}
+
+/* OpenMP 4.0:
+ safelen ( constant-expression ) */
+
+static tree
+c_parser_omp_clause_safelen (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ tree c, t;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+ if (TREE_CODE (t) != INTEGER_CST
+ || !INTEGRAL_TYPE_P (TREE_TYPE (t))
+ || tree_int_cst_sgn (t) != 1)
+ {
+ error_at (clause_loc, "%<safelen%> clause expression must "
+ "be positive constant integer expression");
+ t = NULL_TREE;
+ }
+
+ parens.skip_until_found_close (parser);
+ if (t == NULL_TREE || t == error_mark_node)
+ return list;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_SAFELEN, "safelen");
+
+ c = build_omp_clause (clause_loc, OMP_CLAUSE_SAFELEN);
+ OMP_CLAUSE_SAFELEN_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 4.0:
+ simdlen ( constant-expression ) */
+
+static tree
+c_parser_omp_clause_simdlen (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ tree c, t;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+ if (TREE_CODE (t) != INTEGER_CST
+ || !INTEGRAL_TYPE_P (TREE_TYPE (t))
+ || tree_int_cst_sgn (t) != 1)
+ {
+ error_at (clause_loc, "%<simdlen%> clause expression must "
+ "be positive constant integer expression");
+ t = NULL_TREE;
+ }
+
+ parens.skip_until_found_close (parser);
+ if (t == NULL_TREE || t == error_mark_node)
+ return list;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_SIMDLEN, "simdlen");
+
+ c = build_omp_clause (clause_loc, OMP_CLAUSE_SIMDLEN);
+ OMP_CLAUSE_SIMDLEN_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 4.5:
+ vec:
+ identifier [+/- integer]
+ vec , identifier [+/- integer]
+*/
+
+static tree
+c_parser_omp_clause_depend_sink (c_parser *parser, location_t clause_loc,
+ tree list)
+{
+ tree vec = NULL;
+ 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");
+ return list;
+ }
+
+ 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);
+ tree addend = NULL;
+
+ if (t == NULL_TREE)
+ {
+ undeclared_variable (c_parser_peek_token (parser)->location,
+ c_parser_peek_token (parser)->value);
+ t = error_mark_node;
+ }
+
+ c_parser_consume_token (parser);
+
+ bool neg = false;
+ if (c_parser_next_token_is (parser, CPP_MINUS))
+ neg = true;
+ else if (!c_parser_next_token_is (parser, CPP_PLUS))
+ {
+ addend = integer_zero_node;
+ neg = false;
+ goto add_to_vector;
+ }
+ c_parser_consume_token (parser);
+
+ if (c_parser_next_token_is_not (parser, CPP_NUMBER))
+ {
+ c_parser_error (parser, "expected integer");
+ return list;
+ }
+
+ addend = c_parser_peek_token (parser)->value;
+ if (TREE_CODE (addend) != INTEGER_CST)
+ {
+ c_parser_error (parser, "expected integer");
+ return list;
+ }
+ c_parser_consume_token (parser);
+
+ add_to_vector:
+ if (t != error_mark_node)
+ {
+ vec = tree_cons (addend, t, vec);
+ if (neg)
+ OMP_CLAUSE_DEPEND_SINK_NEGATIVE (vec) = 1;
+ }
+
+ if (c_parser_next_token_is_not (parser, CPP_COMMA)
+ || c_parser_peek_2nd_token (parser)->type != CPP_NAME
+ || c_parser_peek_2nd_token (parser)->id_kind != C_ID_ID)
+ break;
+
+ c_parser_consume_token (parser);
+ }
+
+ if (vec == NULL_TREE)
+ return list;
+
+ tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND);
+ OMP_CLAUSE_DEPEND_KIND (u) = OMP_CLAUSE_DEPEND_SINK;
+ OMP_CLAUSE_DECL (u) = nreverse (vec);
+ OMP_CLAUSE_CHAIN (u) = list;
+ return u;
+}
+
+/* OpenMP 5.0:
+ iterators ( iterators-definition )
+
+ iterators-definition:
+ iterator-specifier
+ iterator-specifier , iterators-definition
+
+ iterator-specifier:
+ identifier = range-specification
+ iterator-type identifier = range-specification
+
+ range-specification:
+ begin : end
+ begin : end : step */
+
+static tree
+c_parser_omp_iterators (c_parser *parser)
+{
+ tree ret = NULL_TREE, *last = &ret;
+ c_parser_consume_token (parser);
+
+ push_scope ();
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return error_mark_node;
+
+ do
+ {
+ tree iter_type = NULL_TREE, type_expr = NULL_TREE;
+ if (c_parser_next_tokens_start_typename (parser, cla_prefer_id))
+ {
+ struct c_type_name *type = c_parser_type_name (parser);
+ if (type != NULL)
+ iter_type = groktypename (type, &type_expr, NULL);
+ }
+ if (iter_type == NULL_TREE)
+ iter_type = integer_type_node;
+
+ location_t loc = c_parser_peek_token (parser)->location;
+ if (!c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected identifier");
+ break;
+ }
+
+ tree id = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ break;
+
+ location_t eloc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (eloc, expr, true, false);
+ tree begin = expr.value;
+
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ break;
+
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (eloc, expr, true, false);
+ tree end = expr.value;
+
+ tree step = integer_one_node;
+ if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ c_parser_consume_token (parser);
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (eloc, expr, true, false);
+ step = expr.value;
+ }
+
+ tree iter_var = build_decl (loc, VAR_DECL, id, iter_type);
+ DECL_ARTIFICIAL (iter_var) = 1;
+ DECL_CONTEXT (iter_var) = current_function_decl;
+ pushdecl (iter_var);
+
+ *last = make_tree_vec (6);
+ TREE_VEC_ELT (*last, 0) = iter_var;
+ TREE_VEC_ELT (*last, 1) = begin;
+ TREE_VEC_ELT (*last, 2) = end;
+ TREE_VEC_ELT (*last, 3) = step;
+ last = &TREE_CHAIN (*last);
+
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ continue;
+ }
+ break;
+ }
+ while (1);
+
+ parens.skip_until_found_close (parser);
+ return ret ? ret : error_mark_node;
+}
+
+/* OpenMP 5.0:
+ affinity ( [aff-modifier :] variable-list )
+ aff-modifier:
+ iterator ( iterators-definition ) */
+
+static tree
+c_parser_omp_clause_affinity (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ tree nl, iterators = NULL_TREE;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ bool parse_iter = ((strcmp ("iterator", p) == 0)
+ && (c_parser_peek_2nd_token (parser)->type
+ == CPP_OPEN_PAREN));
+ if (parse_iter)
+ {
+ unsigned n = 3;
+ parse_iter = (c_parser_check_balanced_raw_token_sequence (parser, &n)
+ && (c_parser_peek_nth_token_raw (parser, n)->type
+ == CPP_CLOSE_PAREN)
+ && (c_parser_peek_nth_token_raw (parser, n + 1)->type
+ == CPP_COLON));
+ }
+ if (parse_iter)
+ {
+ iterators = c_parser_omp_iterators (parser);
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ {
+ if (iterators)
+ pop_scope ();
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ }
+ }
+ nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_AFFINITY,
+ list);
+ if (iterators)
+ {
+ tree block = pop_scope ();
+ if (iterators != error_mark_node)
+ {
+ TREE_VEC_ELT (iterators, 5) = block;
+ for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_DECL (c) = build_tree_list (iterators,
+ OMP_CLAUSE_DECL (c));
+ }
+ }
+
+ parens.skip_until_found_close (parser);
+ return nl;
+}
+
+
+/* OpenMP 4.0:
+ depend ( depend-kind: variable-list )
+
+ depend-kind:
+ in | out | inout
+
+ OpenMP 4.5:
+ depend ( source )
+
+ depend ( sink : vec )
+
+ OpenMP 5.0:
+ depend ( depend-modifier , depend-kind: variable-list )
+
+ depend-kind:
+ in | out | inout | mutexinoutset | depobj
+
+ depend-modifier:
+ iterator ( iterators-definition ) */
+
+static tree
+c_parser_omp_clause_depend (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_LAST;
+ tree nl, c, iterators = NULL_TREE;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ do
+ {
+ if (c_parser_next_token_is_not (parser, CPP_NAME))
+ goto invalid_kind;
+
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp ("iterator", p) == 0 && iterators == NULL_TREE)
+ {
+ iterators = c_parser_omp_iterators (parser);
+ c_parser_require (parser, CPP_COMMA, "expected %<,%>");
+ continue;
+ }
+ if (strcmp ("in", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_IN;
+ else if (strcmp ("inout", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_INOUT;
+ else if (strcmp ("mutexinoutset", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET;
+ else if (strcmp ("out", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_OUT;
+ else if (strcmp ("depobj", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_DEPOBJ;
+ else if (strcmp ("sink", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_SINK;
+ else if (strcmp ("source", p) == 0)
+ kind = OMP_CLAUSE_DEPEND_SOURCE;
+ else
+ goto invalid_kind;
+ break;
+ }
+ while (1);
+
+ c_parser_consume_token (parser);
+
+ if (iterators
+ && (kind == OMP_CLAUSE_DEPEND_SOURCE || kind == OMP_CLAUSE_DEPEND_SINK))
+ {
+ pop_scope ();
+ error_at (clause_loc, "%<iterator%> modifier incompatible with %qs",
+ kind == OMP_CLAUSE_DEPEND_SOURCE ? "source" : "sink");
+ iterators = NULL_TREE;
+ }
+
+ if (kind == OMP_CLAUSE_DEPEND_SOURCE)
+ {
+ c = build_omp_clause (clause_loc, OMP_CLAUSE_DEPEND);
+ OMP_CLAUSE_DEPEND_KIND (c) = kind;
+ OMP_CLAUSE_DECL (c) = NULL_TREE;
+ OMP_CLAUSE_CHAIN (c) = list;
+ parens.skip_until_found_close (parser);
+ return c;
+ }
+
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ goto resync_fail;
+
+ if (kind == OMP_CLAUSE_DEPEND_SINK)
+ nl = c_parser_omp_clause_depend_sink (parser, clause_loc, list);
+ else
+ {
+ nl = c_parser_omp_variable_list (parser, clause_loc,
+ OMP_CLAUSE_DEPEND, list);
+
+ if (iterators)
+ {
+ tree block = pop_scope ();
+ if (iterators == error_mark_node)
+ iterators = NULL_TREE;
+ else
+ TREE_VEC_ELT (iterators, 5) = block;
+ }
+
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ {
+ OMP_CLAUSE_DEPEND_KIND (c) = kind;
+ if (iterators)
+ OMP_CLAUSE_DECL (c)
+ = build_tree_list (iterators, OMP_CLAUSE_DECL (c));
+ }
+ }
+
+ parens.skip_until_found_close (parser);
+ return nl;
+
+ invalid_kind:
+ c_parser_error (parser, "invalid depend kind");
+ resync_fail:
+ parens.skip_until_found_close (parser);
+ if (iterators)
+ pop_scope ();
+ return list;
+}
+
+/* OpenMP 4.0:
+ map ( map-kind: variable-list )
+ map ( variable-list )
+
+ map-kind:
+ alloc | to | from | tofrom
+
+ OpenMP 4.5:
+ map-kind:
+ alloc | to | from | tofrom | release | delete
+
+ map ( always [,] map-kind: variable-list )
+
+ OpenMP 5.0:
+ map ( [map-type-modifier[,] ...] map-kind: variable-list )
+
+ map-type-modifier:
+ always | close */
+
+static tree
+c_parser_omp_clause_map (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ enum gomp_map_kind kind = GOMP_MAP_TOFROM;
+ tree nl, c;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ int pos = 1;
+ int map_kind_pos = 0;
+ while (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_NAME)
+ {
+ if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COLON)
+ {
+ map_kind_pos = pos;
+ break;
+ }
+
+ if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COMMA)
+ pos++;
+ pos++;
+ }
+
+ int always_modifier = 0;
+ int close_modifier = 0;
+ for (int pos = 1; pos < map_kind_pos; ++pos)
+ {
+ c_token *tok = c_parser_peek_token (parser);
+
+ if (tok->type == CPP_COMMA)
+ {
+ c_parser_consume_token (parser);
+ continue;
+ }
+
+ const char *p = IDENTIFIER_POINTER (tok->value);
+ if (strcmp ("always", p) == 0)
+ {
+ if (always_modifier)
+ {
+ c_parser_error (parser, "too many %<always%> modifiers");
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ always_modifier++;
+ }
+ else if (strcmp ("close", p) == 0)
+ {
+ if (close_modifier)
+ {
+ c_parser_error (parser, "too many %<close%> modifiers");
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ close_modifier++;
+ }
+ else
+ {
+ c_parser_error (parser, "%<#pragma omp target%> with "
+ "modifier other than %<always%> or %<close%>"
+ "on %<map%> clause");
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+
+ c_parser_consume_token (parser);
+ }
+
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp ("alloc", p) == 0)
+ kind = GOMP_MAP_ALLOC;
+ else if (strcmp ("to", p) == 0)
+ kind = always_modifier ? GOMP_MAP_ALWAYS_TO : GOMP_MAP_TO;
+ else if (strcmp ("from", p) == 0)
+ kind = always_modifier ? GOMP_MAP_ALWAYS_FROM : GOMP_MAP_FROM;
+ else if (strcmp ("tofrom", p) == 0)
+ kind = always_modifier ? GOMP_MAP_ALWAYS_TOFROM : GOMP_MAP_TOFROM;
+ else if (strcmp ("release", p) == 0)
+ kind = GOMP_MAP_RELEASE;
+ else if (strcmp ("delete", p) == 0)
+ kind = GOMP_MAP_DELETE;
+ else
+ {
+ c_parser_error (parser, "invalid map kind");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return list;
+ }
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ }
+
+ nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list,
+ true);
+
+ for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_SET_MAP_KIND (c, kind);
+
+ parens.skip_until_found_close (parser);
+ return nl;
+}
+
+/* OpenMP 4.0:
+ device ( expression )
+
+ OpenMP 5.0:
+ device ( [device-modifier :] integer-expression )
+
+ device-modifier:
+ ancestor | device_num */
+
+static tree
+c_parser_omp_clause_device (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ location_t expr_loc;
+ c_expr expr;
+ tree c, t;
+ bool ancestor = false;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ {
+ c_token *tok = c_parser_peek_token (parser);
+ const char *p = IDENTIFIER_POINTER (tok->value);
+ if (strcmp ("ancestor", p) == 0)
+ {
+ /* A requires directive with the reverse_offload clause must be
+ specified. */
+ if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0)
+ {
+ error_at (tok->location, "%<ancestor%> device modifier not "
+ "preceded by %<requires%> directive "
+ "with %<reverse_offload%> clause");
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ ancestor = true;
+ }
+ else if (strcmp ("device_num", p) == 0)
+ ;
+ else
+ {
+ error_at (tok->location, "expected %<ancestor%> or %<device_num%>");
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ }
+
+ expr_loc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+
+ parens.skip_until_found_close (parser);
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ c_parser_error (parser, "expected integer expression");
+ return list;
+ }
+ if (ancestor && TREE_CODE (t) == INTEGER_CST && !integer_onep (t))
+ {
+ error_at (expr_loc, "the %<device%> clause expression must evaluate to "
+ "%<1%>");
+ return list;
+ }
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE, "device");
+
+ c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE);
+
+ OMP_CLAUSE_DEVICE_ID (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ OMP_CLAUSE_DEVICE_ANCESTOR (c) = ancestor;
+
+ list = c;
+ return list;
+}
+
+/* OpenMP 4.0:
+ dist_schedule ( static )
+ dist_schedule ( static , expression ) */
+
+static tree
+c_parser_omp_clause_dist_schedule (c_parser *parser, tree list)
+{
+ tree c, t = NULL_TREE;
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ if (!c_parser_next_token_is_keyword (parser, RID_STATIC))
+ {
+ c_parser_error (parser, "invalid dist_schedule kind");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ return list;
+ }
+
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ t = expr.value;
+ t = c_fully_fold (t, false, NULL);
+ parens.skip_until_found_close (parser);
+ }
+ else
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<,%> or %<)%>");
+
+ /* check_no_duplicate_clause (list, OMP_CLAUSE_DIST_SCHEDULE,
+ "dist_schedule"); */
+ if (omp_find_clause (list, OMP_CLAUSE_DIST_SCHEDULE))
+ warning_at (loc, 0, "too many %qs clauses", "dist_schedule");
+ if (t == error_mark_node)
+ return list;
+
+ c = build_omp_clause (loc, OMP_CLAUSE_DIST_SCHEDULE);
+ OMP_CLAUSE_DIST_SCHEDULE_CHUNK_EXPR (c) = t;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+}
+
+/* OpenMP 4.0:
+ proc_bind ( proc-bind-kind )
+
+ proc-bind-kind:
+ primary | master | close | spread
+ where OpenMP 5.1 added 'primary' and deprecated the alias 'master'. */
+
+static tree
+c_parser_omp_clause_proc_bind (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ enum omp_clause_proc_bind_kind kind;
+ tree c;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp ("primary", p) == 0)
+ kind = OMP_CLAUSE_PROC_BIND_PRIMARY;
+ else if (strcmp ("master", p) == 0)
+ kind = OMP_CLAUSE_PROC_BIND_MASTER;
+ else if (strcmp ("close", p) == 0)
+ kind = OMP_CLAUSE_PROC_BIND_CLOSE;
+ else if (strcmp ("spread", p) == 0)
+ kind = OMP_CLAUSE_PROC_BIND_SPREAD;
+ else
+ goto invalid_kind;
+ }
+ else
+ goto invalid_kind;
+
+ check_no_duplicate_clause (list, OMP_CLAUSE_PROC_BIND, "proc_bind");
+ c_parser_consume_token (parser);
+ parens.skip_until_found_close (parser);
+ c = build_omp_clause (clause_loc, OMP_CLAUSE_PROC_BIND);
+ OMP_CLAUSE_PROC_BIND_KIND (c) = kind;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+
+ invalid_kind:
+ c_parser_error (parser, "invalid proc_bind kind");
+ parens.skip_until_found_close (parser);
+ return list;
+}
+
+/* OpenMP 5.0:
+ device_type ( host | nohost | any ) */
+
+static tree
+c_parser_omp_clause_device_type (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ enum omp_clause_device_type_kind kind;
+ tree c;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp ("host", p) == 0)
+ kind = OMP_CLAUSE_DEVICE_TYPE_HOST;
+ else if (strcmp ("nohost", p) == 0)
+ kind = OMP_CLAUSE_DEVICE_TYPE_NOHOST;
+ else if (strcmp ("any", p) == 0)
+ kind = OMP_CLAUSE_DEVICE_TYPE_ANY;
+ else
+ goto invalid_kind;
+ }
+ else
+ goto invalid_kind;
+
+ /* check_no_duplicate_clause (list, OMP_CLAUSE_DEVICE_TYPE,
+ "device_type"); */
+ c_parser_consume_token (parser);
+ parens.skip_until_found_close (parser);
+ c = build_omp_clause (clause_loc, OMP_CLAUSE_DEVICE_TYPE);
+ OMP_CLAUSE_DEVICE_TYPE_KIND (c) = kind;
+ OMP_CLAUSE_CHAIN (c) = list;
+ return c;
+
+ invalid_kind:
+ c_parser_error (parser, "expected %<host%>, %<nohost%> or %<any%>");
+ parens.skip_until_found_close (parser);
+ return list;
+}
+
+/* OpenMP 4.0:
+ to ( variable-list ) */
+
+static tree
+c_parser_omp_clause_to (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO, list, true);
+}
+
+/* OpenMP 4.0:
+ from ( variable-list ) */
+
+static tree
+c_parser_omp_clause_from (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_FROM, list, true);
+}
+
+/* OpenMP 4.0:
+ uniform ( variable-list ) */
+
+static tree
+c_parser_omp_clause_uniform (c_parser *parser, tree list)
+{
+ /* The clauses location. */
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ list = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_UNIFORM,
+ list);
+ parens.skip_until_found_close (parser);
+ }
+ return list;
+}
+
+/* OpenMP 5.0:
+ detach ( event-handle ) */
+
+static tree
+c_parser_omp_clause_detach (c_parser *parser, tree list)
+{
+ matching_parens parens;
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+
+ if (!parens.require_open (parser))
+ return 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");
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+
+ 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);
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ c_parser_consume_token (parser);
+
+ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (t));
+ if (!INTEGRAL_TYPE_P (type)
+ || TREE_CODE (type) != ENUMERAL_TYPE
+ || TYPE_NAME (type) != get_identifier ("omp_event_handle_t"))
+ {
+ error_at (clause_loc, "%<detach%> clause event handle "
+ "has type %qT rather than "
+ "%<omp_event_handle_t%>",
+ type);
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+
+ tree u = build_omp_clause (clause_loc, OMP_CLAUSE_DETACH);
+ OMP_CLAUSE_DECL (u) = t;
+ OMP_CLAUSE_CHAIN (u) = list;
+ parens.skip_until_found_close (parser);
+ return u;
+}
+
+/* Parse all OpenACC clauses. The set clauses allowed by the directive
+ is a bitmask in MASK. Return the list of clauses found. */
+
+static tree
+c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask,
+ const char *where, bool finish_p = true)
+{
+ 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);
+
+ here = c_parser_peek_token (parser)->location;
+ c_kind = c_parser_omp_clause_name (parser);
+
+ switch (c_kind)
+ {
+ case PRAGMA_OACC_CLAUSE_ASYNC:
+ clauses = c_parser_oacc_clause_async (parser, clauses);
+ c_name = "async";
+ break;
+ case PRAGMA_OACC_CLAUSE_AUTO:
+ clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_AUTO,
+ clauses);
+ c_name = "auto";
+ break;
+ case PRAGMA_OACC_CLAUSE_ATTACH:
+ clauses = c_parser_oacc_data_clause (parser, c_kind, clauses);
+ c_name = "attach";
+ break;
+ case PRAGMA_OACC_CLAUSE_COLLAPSE:
+ clauses = c_parser_omp_clause_collapse (parser, clauses);
+ c_name = "collapse";
+ break;
+ case PRAGMA_OACC_CLAUSE_COPY:
+ clauses = c_parser_oacc_data_clause (parser, c_kind, clauses);
+ c_name = "copy";
+ break;
+ case PRAGMA_OACC_CLAUSE_COPYIN:
+ clauses = c_parser_oacc_data_clause (parser, c_kind, clauses);
+ c_name = "copyin";
+ break;
+ case PRAGMA_OACC_CLAUSE_COPYOUT:
+ clauses = c_parser_oacc_data_clause (parser, c_kind, clauses);
+ c_name = "copyout";
+ break;
+ case PRAGMA_OACC_CLAUSE_CREATE:
+ clauses = c_parser_oacc_data_clause (parser, c_kind, clauses);
+ c_name = "create";
+ break;
+ case PRAGMA_OACC_CLAUSE_DELETE:
+ clauses = c_parser_oacc_data_clause (parser, c_kind, clauses);
+ c_name = "delete";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEFAULT:
+ clauses = c_parser_omp_clause_default (parser, clauses, true);
+ c_name = "default";
+ break;
+ case PRAGMA_OACC_CLAUSE_DETACH:
+ clauses = c_parser_oacc_data_clause (parser, c_kind, clauses);
+ c_name = "detach";
+ break;
+ case PRAGMA_OACC_CLAUSE_DEVICE:
+ clauses = c_parser_oacc_data_clause (parser, c_kind, clauses);
+ c_name = "device";
+ break;
+ case PRAGMA_OACC_CLAUSE_DEVICEPTR:
+ clauses = c_parser_oacc_data_clause_deviceptr (parser, clauses);
+ c_name = "deviceptr";
+ break;
+ case PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT:
+ clauses = c_parser_oacc_data_clause (parser, c_kind, clauses);
+ c_name = "device_resident";
+ break;
+ case PRAGMA_OACC_CLAUSE_FINALIZE:
+ clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_FINALIZE,
+ clauses);
+ c_name = "finalize";
+ break;
+ case PRAGMA_OACC_CLAUSE_FIRSTPRIVATE:
+ clauses = c_parser_omp_clause_firstprivate (parser, clauses);
+ c_name = "firstprivate";
+ break;
+ case PRAGMA_OACC_CLAUSE_GANG:
+ c_name = "gang";
+ clauses = c_parser_oacc_shape_clause (parser, here, OMP_CLAUSE_GANG,
+ c_name, clauses);
+ break;
+ case PRAGMA_OACC_CLAUSE_HOST:
+ clauses = c_parser_oacc_data_clause (parser, c_kind, clauses);
+ c_name = "host";
+ break;
+ case PRAGMA_OACC_CLAUSE_IF:
+ clauses = c_parser_omp_clause_if (parser, clauses, false);
+ c_name = "if";
+ break;
+ case PRAGMA_OACC_CLAUSE_IF_PRESENT:
+ clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_IF_PRESENT,
+ clauses);
+ c_name = "if_present";
+ break;
+ case PRAGMA_OACC_CLAUSE_INDEPENDENT:
+ clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_INDEPENDENT,
+ clauses);
+ c_name = "independent";
+ break;
+ case PRAGMA_OACC_CLAUSE_LINK:
+ clauses = c_parser_oacc_data_clause (parser, c_kind, clauses);
+ c_name = "link";
+ break;
+ case PRAGMA_OACC_CLAUSE_NO_CREATE:
+ clauses = c_parser_oacc_data_clause (parser, c_kind, clauses);
+ c_name = "no_create";
+ break;
+ case PRAGMA_OACC_CLAUSE_NOHOST:
+ clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_NOHOST,
+ clauses);
+ c_name = "nohost";
+ break;
+ case PRAGMA_OACC_CLAUSE_NUM_GANGS:
+ clauses = c_parser_oacc_single_int_clause (parser,
+ OMP_CLAUSE_NUM_GANGS,
+ clauses);
+ c_name = "num_gangs";
+ break;
+ case PRAGMA_OACC_CLAUSE_NUM_WORKERS:
+ clauses = c_parser_oacc_single_int_clause (parser,
+ OMP_CLAUSE_NUM_WORKERS,
+ clauses);
+ c_name = "num_workers";
+ break;
+ case PRAGMA_OACC_CLAUSE_PRESENT:
+ clauses = c_parser_oacc_data_clause (parser, c_kind, clauses);
+ c_name = "present";
+ break;
+ case PRAGMA_OACC_CLAUSE_PRIVATE:
+ clauses = c_parser_omp_clause_private (parser, clauses);
+ c_name = "private";
+ break;
+ case PRAGMA_OACC_CLAUSE_REDUCTION:
+ clauses
+ = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION,
+ false, clauses);
+ c_name = "reduction";
+ break;
+ case PRAGMA_OACC_CLAUSE_SEQ:
+ clauses = c_parser_oacc_simple_clause (here, OMP_CLAUSE_SEQ,
+ clauses);
+ c_name = "seq";
+ break;
+ case PRAGMA_OACC_CLAUSE_TILE:
+ clauses = c_parser_oacc_clause_tile (parser, clauses);
+ c_name = "tile";
+ break;
+ case PRAGMA_OACC_CLAUSE_USE_DEVICE:
+ clauses = c_parser_omp_clause_use_device_ptr (parser, clauses);
+ c_name = "use_device";
+ break;
+ case PRAGMA_OACC_CLAUSE_VECTOR:
+ c_name = "vector";
+ clauses = c_parser_oacc_shape_clause (parser, here, OMP_CLAUSE_VECTOR,
+ c_name, clauses);
+ break;
+ case PRAGMA_OACC_CLAUSE_VECTOR_LENGTH:
+ clauses = c_parser_oacc_single_int_clause (parser,
+ OMP_CLAUSE_VECTOR_LENGTH,
+ clauses);
+ c_name = "vector_length";
+ break;
+ case PRAGMA_OACC_CLAUSE_WAIT:
+ clauses = c_parser_oacc_clause_wait (parser, clauses);
+ c_name = "wait";
+ break;
+ case PRAGMA_OACC_CLAUSE_WORKER:
+ c_name = "worker";
+ clauses = c_parser_oacc_shape_clause (parser, here, OMP_CLAUSE_WORKER,
+ c_name, clauses);
+ break;
+ default:
+ c_parser_error (parser, "expected %<#pragma acc%> clause");
+ goto saw_error;
+ }
+
+ first = false;
+
+ if (((mask >> c_kind) & 1) == 0)
+ {
+ /* 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);
+
+ if (finish_p)
+ return c_finish_omp_clauses (clauses, C_ORT_ACC);
+
+ return clauses;
+}
+
+/* Parse all OpenMP clauses. The set clauses allowed by the directive
+ is a bitmask in MASK. Return the list of clauses found.
+ FINISH_P set if c_finish_omp_clauses should be called.
+ NESTED non-zero if clauses should be terminated by closing paren instead
+ of end of pragma. If it is 2, additionally commas are required in between
+ the clauses. */
+
+static tree
+c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
+ const char *where, bool finish_p = true,
+ int nested = 0)
+{
+ 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 (nested && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ break;
+
+ if (!first)
+ {
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else if (nested == 2)
+ error_at (c_parser_peek_token (parser)->location,
+ "clauses in %<simd%> trait should be separated "
+ "by %<,%>");
+ }
+
+ here = c_parser_peek_token (parser)->location;
+ c_kind = c_parser_omp_clause_name (parser);
+
+ switch (c_kind)
+ {
+ case PRAGMA_OMP_CLAUSE_BIND:
+ clauses = c_parser_omp_clause_bind (parser, clauses);
+ c_name = "bind";
+ break;
+ 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, false);
+ c_name = "default";
+ break;
+ case PRAGMA_OMP_CLAUSE_DETACH:
+ clauses = c_parser_omp_clause_detach (parser, clauses);
+ c_name = "detach";
+ break;
+ case PRAGMA_OMP_CLAUSE_FILTER:
+ clauses = c_parser_omp_clause_filter (parser, clauses);
+ c_name = "filter";
+ 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_GRAINSIZE:
+ clauses = c_parser_omp_clause_grainsize (parser, clauses);
+ c_name = "grainsize";
+ break;
+ case PRAGMA_OMP_CLAUSE_HINT:
+ clauses = c_parser_omp_clause_hint (parser, clauses);
+ c_name = "hint";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEFAULTMAP:
+ clauses = c_parser_omp_clause_defaultmap (parser, clauses);
+ c_name = "defaultmap";
+ break;
+ case PRAGMA_OMP_CLAUSE_IF:
+ clauses = c_parser_omp_clause_if (parser, clauses, true);
+ c_name = "if";
+ break;
+ case PRAGMA_OMP_CLAUSE_IN_REDUCTION:
+ clauses
+ = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_IN_REDUCTION,
+ true, clauses);
+ c_name = "in_reduction";
+ 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_TASKS:
+ clauses = c_parser_omp_clause_num_tasks (parser, clauses);
+ c_name = "num_tasks";
+ 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_ORDER:
+ clauses = c_parser_omp_clause_order (parser, clauses);
+ c_name = "order";
+ break;
+ case PRAGMA_OMP_CLAUSE_ORDERED:
+ clauses = c_parser_omp_clause_ordered (parser, clauses);
+ c_name = "ordered";
+ break;
+ case PRAGMA_OMP_CLAUSE_PRIORITY:
+ clauses = c_parser_omp_clause_priority (parser, clauses);
+ c_name = "priority";
+ 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, OMP_CLAUSE_REDUCTION,
+ true, 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_TASK_REDUCTION:
+ clauses
+ = c_parser_omp_clause_reduction (parser, OMP_CLAUSE_TASK_REDUCTION,
+ true, clauses);
+ c_name = "task_reduction";
+ break;
+ case PRAGMA_OMP_CLAUSE_UNTIED:
+ clauses = c_parser_omp_clause_untied (parser, clauses);
+ c_name = "untied";
+ break;
+ case PRAGMA_OMP_CLAUSE_INBRANCH:
+ clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_INBRANCH,
+ clauses);
+ c_name = "inbranch";
+ break;
+ case PRAGMA_OMP_CLAUSE_NONTEMPORAL:
+ clauses = c_parser_omp_clause_nontemporal (parser, clauses);
+ c_name = "nontemporal";
+ break;
+ case PRAGMA_OMP_CLAUSE_NOTINBRANCH:
+ clauses = c_parser_omp_clause_branch (parser, OMP_CLAUSE_NOTINBRANCH,
+ clauses);
+ c_name = "notinbranch";
+ break;
+ case PRAGMA_OMP_CLAUSE_PARALLEL:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_PARALLEL,
+ clauses);
+ c_name = "parallel";
+ if (!first)
+ {
+ clause_not_first:
+ error_at (here, "%qs must be the first clause of %qs",
+ c_name, where);
+ clauses = prev;
+ }
+ break;
+ case PRAGMA_OMP_CLAUSE_FOR:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_FOR,
+ clauses);
+ c_name = "for";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_SECTIONS:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_SECTIONS,
+ clauses);
+ c_name = "sections";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_TASKGROUP:
+ clauses
+ = c_parser_omp_clause_cancelkind (parser, OMP_CLAUSE_TASKGROUP,
+ clauses);
+ c_name = "taskgroup";
+ if (!first)
+ goto clause_not_first;
+ break;
+ case PRAGMA_OMP_CLAUSE_LINK:
+ clauses
+ = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_LINK, clauses);
+ c_name = "link";
+ break;
+ case PRAGMA_OMP_CLAUSE_TO:
+ if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK)) != 0)
+ clauses
+ = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO_DECLARE,
+ clauses);
+ else
+ clauses = c_parser_omp_clause_to (parser, clauses);
+ c_name = "to";
+ break;
+ case PRAGMA_OMP_CLAUSE_FROM:
+ clauses = c_parser_omp_clause_from (parser, clauses);
+ c_name = "from";
+ break;
+ case PRAGMA_OMP_CLAUSE_UNIFORM:
+ clauses = c_parser_omp_clause_uniform (parser, clauses);
+ c_name = "uniform";
+ break;
+ case PRAGMA_OMP_CLAUSE_NUM_TEAMS:
+ clauses = c_parser_omp_clause_num_teams (parser, clauses);
+ c_name = "num_teams";
+ break;
+ case PRAGMA_OMP_CLAUSE_THREAD_LIMIT:
+ clauses = c_parser_omp_clause_thread_limit (parser, clauses);
+ c_name = "thread_limit";
+ break;
+ case PRAGMA_OMP_CLAUSE_ALIGNED:
+ clauses = c_parser_omp_clause_aligned (parser, clauses);
+ c_name = "aligned";
+ break;
+ case PRAGMA_OMP_CLAUSE_ALLOCATE:
+ clauses = c_parser_omp_clause_allocate (parser, clauses);
+ c_name = "allocate";
+ break;
+ case PRAGMA_OMP_CLAUSE_LINEAR:
+ clauses = c_parser_omp_clause_linear (parser, clauses);
+ c_name = "linear";
+ break;
+ case PRAGMA_OMP_CLAUSE_AFFINITY:
+ clauses = c_parser_omp_clause_affinity (parser, clauses);
+ c_name = "affinity";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEPEND:
+ clauses = c_parser_omp_clause_depend (parser, clauses);
+ c_name = "depend";
+ break;
+ case PRAGMA_OMP_CLAUSE_MAP:
+ clauses = c_parser_omp_clause_map (parser, clauses);
+ c_name = "map";
+ break;
+ case PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR:
+ clauses = c_parser_omp_clause_use_device_ptr (parser, clauses);
+ c_name = "use_device_ptr";
+ break;
+ case PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR:
+ clauses = c_parser_omp_clause_use_device_addr (parser, clauses);
+ c_name = "use_device_addr";
+ break;
+ case PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR:
+ clauses = c_parser_omp_clause_is_device_ptr (parser, clauses);
+ c_name = "is_device_ptr";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEVICE:
+ clauses = c_parser_omp_clause_device (parser, clauses);
+ c_name = "device";
+ break;
+ case PRAGMA_OMP_CLAUSE_DIST_SCHEDULE:
+ clauses = c_parser_omp_clause_dist_schedule (parser, clauses);
+ c_name = "dist_schedule";
+ break;
+ case PRAGMA_OMP_CLAUSE_PROC_BIND:
+ clauses = c_parser_omp_clause_proc_bind (parser, clauses);
+ c_name = "proc_bind";
+ break;
+ case PRAGMA_OMP_CLAUSE_DEVICE_TYPE:
+ clauses = c_parser_omp_clause_device_type (parser, clauses);
+ c_name = "device_type";
+ break;
+ case PRAGMA_OMP_CLAUSE_SAFELEN:
+ clauses = c_parser_omp_clause_safelen (parser, clauses);
+ c_name = "safelen";
+ break;
+ case PRAGMA_OMP_CLAUSE_SIMDLEN:
+ clauses = c_parser_omp_clause_simdlen (parser, clauses);
+ c_name = "simdlen";
+ break;
+ case PRAGMA_OMP_CLAUSE_NOGROUP:
+ clauses = c_parser_omp_clause_nogroup (parser, clauses);
+ c_name = "nogroup";
+ break;
+ case PRAGMA_OMP_CLAUSE_THREADS:
+ clauses
+ = c_parser_omp_clause_orderedkind (parser, OMP_CLAUSE_THREADS,
+ clauses);
+ c_name = "threads";
+ break;
+ case PRAGMA_OMP_CLAUSE_SIMD:
+ clauses
+ = c_parser_omp_clause_orderedkind (parser, OMP_CLAUSE_SIMD,
+ clauses);
+ c_name = "simd";
+ break;
+ default:
+ c_parser_error (parser, "expected %<#pragma omp%> clause");
+ goto saw_error;
+ }
+
+ first = false;
+
+ if (((mask >> c_kind) & 1) == 0)
+ {
+ /* 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:
+ if (!nested)
+ c_parser_skip_to_pragma_eol (parser);
+
+ if (finish_p)
+ {
+ if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)) != 0)
+ return c_finish_omp_clauses (clauses, C_ORT_OMP_DECLARE_SIMD);
+ return c_finish_omp_clauses (clauses, C_ORT_OMP);
+ }
+
+ return clauses;
+}
+
+/* OpenACC 2.0, 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, bool *if_p)
+{
+ tree stmt = push_stmt_list ();
+ c_parser_statement (parser, if_p);
+ return pop_stmt_list (stmt);
+}
+
+/* OpenACC 2.0:
+ # pragma acc cache (variable-list) new-line
+
+ LOC is the location of the #pragma token.
+*/
+
+static tree
+c_parser_oacc_cache (location_t loc, c_parser *parser)
+{
+ tree stmt, clauses;
+
+ clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE__CACHE_, NULL);
+ clauses = c_finish_omp_clauses (clauses, C_ORT_ACC);
+
+ c_parser_skip_to_pragma_eol (parser);
+
+ stmt = make_node (OACC_CACHE);
+ TREE_TYPE (stmt) = void_type_node;
+ OACC_CACHE_CLAUSES (stmt) = clauses;
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+
+ return stmt;
+}
+
+/* OpenACC 2.0:
+ # pragma acc data oacc-data-clause[optseq] new-line
+ structured-block
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OACC_DATA_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT))
+
+static tree
+c_parser_oacc_data (location_t loc, c_parser *parser, bool *if_p)
+{
+ tree stmt, clauses, block;
+
+ clauses = c_parser_oacc_all_clauses (parser, OACC_DATA_CLAUSE_MASK,
+ "#pragma acc data");
+
+ block = c_begin_omp_parallel ();
+ add_stmt (c_parser_omp_structured_block (parser, if_p));
+
+ stmt = c_finish_oacc_data (loc, clauses, block);
+
+ return stmt;
+}
+
+/* OpenACC 2.0:
+ # pragma acc declare oacc-data-clause[optseq] new-line
+*/
+
+#define OACC_DECLARE_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE_RESIDENT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_LINK) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT))
+
+static void
+c_parser_oacc_declare (c_parser *parser)
+{
+ location_t pragma_loc = c_parser_peek_token (parser)->location;
+ tree clauses, stmt, t, decl;
+
+ bool error = false;
+
+ c_parser_consume_pragma (parser);
+
+ clauses = c_parser_oacc_all_clauses (parser, OACC_DECLARE_CLAUSE_MASK,
+ "#pragma acc declare");
+ if (!clauses)
+ {
+ error_at (pragma_loc,
+ "no valid clauses specified in %<#pragma acc declare%>");
+ return;
+ }
+
+ for (t = clauses; t; t = OMP_CLAUSE_CHAIN (t))
+ {
+ location_t loc = OMP_CLAUSE_LOCATION (t);
+ decl = OMP_CLAUSE_DECL (t);
+ if (!DECL_P (decl))
+ {
+ error_at (loc, "array section in %<#pragma acc declare%>");
+ error = true;
+ continue;
+ }
+
+ switch (OMP_CLAUSE_MAP_KIND (t))
+ {
+ case GOMP_MAP_FIRSTPRIVATE_POINTER:
+ case GOMP_MAP_ALLOC:
+ case GOMP_MAP_TO:
+ case GOMP_MAP_FORCE_DEVICEPTR:
+ case GOMP_MAP_DEVICE_RESIDENT:
+ break;
+
+ case GOMP_MAP_LINK:
+ if (!global_bindings_p ()
+ && (TREE_STATIC (decl)
+ || !DECL_EXTERNAL (decl)))
+ {
+ error_at (loc,
+ "%qD must be a global variable in "
+ "%<#pragma acc declare link%>",
+ decl);
+ error = true;
+ continue;
+ }
+ break;
+
+ default:
+ if (global_bindings_p ())
+ {
+ error_at (loc, "invalid OpenACC clause at file scope");
+ error = true;
+ continue;
+ }
+ if (DECL_EXTERNAL (decl))
+ {
+ error_at (loc,
+ "invalid use of %<extern%> variable %qD "
+ "in %<#pragma acc declare%>", decl);
+ error = true;
+ continue;
+ }
+ else if (TREE_PUBLIC (decl))
+ {
+ error_at (loc,
+ "invalid use of %<global%> variable %qD "
+ "in %<#pragma acc declare%>", decl);
+ error = true;
+ continue;
+ }
+ break;
+ }
+
+ if (!c_check_in_current_scope (decl))
+ {
+ error_at (loc,
+ "%qD must be a variable declared in the same scope as "
+ "%<#pragma acc declare%>", decl);
+ error = true;
+ continue;
+ }
+
+ if (lookup_attribute ("omp declare target", DECL_ATTRIBUTES (decl))
+ || lookup_attribute ("omp declare target link",
+ DECL_ATTRIBUTES (decl)))
+ {
+ error_at (loc, "variable %qD used more than once with "
+ "%<#pragma acc declare%>", decl);
+ error = true;
+ continue;
+ }
+
+ if (!error)
+ {
+ tree id;
+
+ if (OMP_CLAUSE_MAP_KIND (t) == GOMP_MAP_LINK)
+ id = get_identifier ("omp declare target link");
+ else
+ id = get_identifier ("omp declare target");
+
+ DECL_ATTRIBUTES (decl)
+ = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (decl));
+
+ if (global_bindings_p ())
+ {
+ symtab_node *node = symtab_node::get (decl);
+ if (node != NULL)
+ {
+ node->offloadable = 1;
+ if (ENABLE_OFFLOADING)
+ {
+ g->have_offload = true;
+ if (is_a <varpool_node *> (node))
+ vec_safe_push (offload_vars, decl);
+ }
+ }
+ }
+ }
+ }
+
+ if (error || global_bindings_p ())
+ return;
+
+ stmt = make_node (OACC_DECLARE);
+ TREE_TYPE (stmt) = void_type_node;
+ OACC_DECLARE_CLAUSES (stmt) = clauses;
+ SET_EXPR_LOCATION (stmt, pragma_loc);
+
+ add_stmt (stmt);
+
+ return;
+}
+
+/* OpenACC 2.0:
+ # pragma acc enter data oacc-enter-data-clause[optseq] new-line
+
+ or
+
+ # pragma acc exit data oacc-exit-data-clause[optseq] new-line
+
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OACC_ENTER_DATA_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) )
+
+#define OACC_EXIT_DATA_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DELETE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DETACH) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FINALIZE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) )
+
+static void
+c_parser_oacc_enter_exit_data (c_parser *parser, bool enter)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree clauses, stmt;
+ const char *p = "";
+
+ c_parser_consume_pragma (parser);
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ }
+
+ if (strcmp (p, "data") != 0)
+ {
+ error_at (loc, "expected %<data%> after %<#pragma acc %s%>",
+ enter ? "enter" : "exit");
+ parser->error = true;
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+
+ if (enter)
+ clauses = c_parser_oacc_all_clauses (parser, OACC_ENTER_DATA_CLAUSE_MASK,
+ "#pragma acc enter data");
+ else
+ clauses = c_parser_oacc_all_clauses (parser, OACC_EXIT_DATA_CLAUSE_MASK,
+ "#pragma acc exit data");
+
+ if (omp_find_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE)
+ {
+ error_at (loc, "%<#pragma acc %s data%> has no data movement clause",
+ enter ? "enter" : "exit");
+ return;
+ }
+
+ stmt = enter ? make_node (OACC_ENTER_DATA) : make_node (OACC_EXIT_DATA);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_STANDALONE_CLAUSES (stmt) = clauses;
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+}
+
+
+/* OpenACC 2.0:
+ # pragma acc host_data oacc-data-clause[optseq] new-line
+ structured-block
+*/
+
+#define OACC_HOST_DATA_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_USE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF_PRESENT) )
+
+static tree
+c_parser_oacc_host_data (location_t loc, c_parser *parser, bool *if_p)
+{
+ tree stmt, clauses, block;
+
+ clauses = c_parser_oacc_all_clauses (parser, OACC_HOST_DATA_CLAUSE_MASK,
+ "#pragma acc host_data");
+
+ block = c_begin_omp_parallel ();
+ add_stmt (c_parser_omp_structured_block (parser, if_p));
+ stmt = c_finish_oacc_host_data (loc, clauses, block);
+ return stmt;
+}
+
+
+/* OpenACC 2.0:
+
+ # pragma acc loop oacc-loop-clause[optseq] new-line
+ structured-block
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OACC_LOOP_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COLLAPSE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_GANG) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WORKER) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_AUTO) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_INDEPENDENT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_TILE) )
+static tree
+c_parser_oacc_loop (location_t loc, c_parser *parser, char *p_name,
+ omp_clause_mask mask, tree *cclauses, bool *if_p)
+{
+ bool is_parallel = ((mask >> PRAGMA_OACC_CLAUSE_REDUCTION) & 1) == 1;
+
+ strcat (p_name, " loop");
+ mask |= OACC_LOOP_CLAUSE_MASK;
+
+ tree clauses = c_parser_oacc_all_clauses (parser, mask, p_name,
+ cclauses == NULL);
+ if (cclauses)
+ {
+ clauses = c_oacc_split_loop_clauses (clauses, cclauses, is_parallel);
+ if (*cclauses)
+ *cclauses = c_finish_omp_clauses (*cclauses, C_ORT_ACC);
+ if (clauses)
+ clauses = c_finish_omp_clauses (clauses, C_ORT_ACC);
+ }
+
+ tree block = c_begin_compound_stmt (true);
+ tree stmt = c_parser_omp_for_loop (loc, parser, OACC_LOOP, clauses, NULL,
+ if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return stmt;
+}
+
+/* OpenACC 2.0:
+ # pragma acc kernels oacc-kernels-clause[optseq] new-line
+ structured-block
+
+ or
+
+ # pragma acc parallel oacc-parallel-clause[optseq] new-line
+ structured-block
+
+ OpenACC 2.6:
+
+ # pragma acc serial oacc-serial-clause[optseq] new-line
+ structured-block
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OACC_KERNELS_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) )
+
+#define OACC_PARALLEL_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_GANGS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NUM_WORKERS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR_LENGTH) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) )
+
+#define OACC_SERIAL_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ATTACH) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPY) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYIN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_COPYOUT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_CREATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEFAULT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICEPTR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NO_CREATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_PRESENT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) )
+
+static tree
+c_parser_oacc_compute (location_t loc, c_parser *parser,
+ enum pragma_kind p_kind, char *p_name, bool *if_p)
+{
+ omp_clause_mask mask;
+ enum tree_code code;
+ switch (p_kind)
+ {
+ case PRAGMA_OACC_KERNELS:
+ strcat (p_name, " kernels");
+ mask = OACC_KERNELS_CLAUSE_MASK;
+ code = OACC_KERNELS;
+ break;
+ case PRAGMA_OACC_PARALLEL:
+ strcat (p_name, " parallel");
+ mask = OACC_PARALLEL_CLAUSE_MASK;
+ code = OACC_PARALLEL;
+ break;
+ case PRAGMA_OACC_SERIAL:
+ strcat (p_name, " serial");
+ mask = OACC_SERIAL_CLAUSE_MASK;
+ code = OACC_SERIAL;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "loop") == 0)
+ {
+ c_parser_consume_token (parser);
+ tree block = c_begin_omp_parallel ();
+ tree clauses;
+ c_parser_oacc_loop (loc, parser, p_name, mask, &clauses, if_p);
+ return c_finish_omp_construct (loc, code, block, clauses);
+ }
+ }
+
+ tree clauses = c_parser_oacc_all_clauses (parser, mask, p_name);
+
+ tree block = c_begin_omp_parallel ();
+ add_stmt (c_parser_omp_structured_block (parser, if_p));
+
+ return c_finish_omp_construct (loc, code, block, clauses);
+}
+
+/* OpenACC 2.0:
+ # pragma acc routine oacc-routine-clause[optseq] new-line
+ function-definition
+
+ # pragma acc routine ( name ) oacc-routine-clause[optseq] new-line
+*/
+
+#define OACC_ROUTINE_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_GANG) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WORKER) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_VECTOR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_SEQ) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_NOHOST) )
+
+/* Parse an OpenACC routine directive. For named directives, we apply
+ immediately to the named function. For unnamed ones we then parse
+ a declaration or definition, which must be for a function. */
+
+static void
+c_parser_oacc_routine (c_parser *parser, enum pragma_context context)
+{
+ gcc_checking_assert (context == pragma_external);
+
+ oacc_routine_data data;
+ data.error_seen = false;
+ data.fndecl_seen = false;
+ data.loc = c_parser_peek_token (parser)->location;
+
+ c_parser_consume_pragma (parser);
+
+ /* Look for optional '( name )'. */
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ c_parser_consume_token (parser); /* '(' */
+
+ tree decl = NULL_TREE;
+ c_token *name_token = c_parser_peek_token (parser);
+ location_t name_loc = name_token->location;
+ if (name_token->type == CPP_NAME
+ && (name_token->id_kind == C_ID_ID
+ || name_token->id_kind == C_ID_TYPENAME))
+ {
+ decl = lookup_name (name_token->value);
+ if (!decl)
+ error_at (name_loc,
+ "%qE has not been declared", name_token->value);
+ c_parser_consume_token (parser);
+ }
+ else
+ c_parser_error (parser, "expected function name");
+
+ if (!decl
+ || !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return;
+ }
+
+ data.clauses
+ = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK,
+ "#pragma acc routine");
+ /* The clauses are in reverse order; fix that to make later diagnostic
+ emission easier. */
+ data.clauses = nreverse (data.clauses);
+
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ {
+ error_at (name_loc, "%qD does not refer to a function", decl);
+ return;
+ }
+
+ c_finish_oacc_routine (&data, decl, false);
+ }
+ else /* No optional '( name )'. */
+ {
+ data.clauses
+ = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK,
+ "#pragma acc routine");
+ /* The clauses are in reverse order; fix that to make later diagnostic
+ emission easier. */
+ data.clauses = nreverse (data.clauses);
+
+ /* Emit a helpful diagnostic if there's another pragma following this
+ one. Also don't allow a static assertion declaration, as in the
+ following we'll just parse a *single* "declaration or function
+ definition", and the static assertion counts an one. */
+ if (c_parser_next_token_is (parser, CPP_PRAGMA)
+ || c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
+ {
+ error_at (data.loc,
+ "%<#pragma acc routine%> not immediately followed by"
+ " function declaration or definition");
+ /* ..., and then just keep going. */
+ return;
+ }
+
+ /* We only have to consider the pragma_external case here. */
+ if (c_parser_next_token_is (parser, CPP_KEYWORD)
+ && c_parser_peek_token (parser)->keyword == RID_EXTENSION)
+ {
+ int ext = disable_extension_diagnostics ();
+ do
+ c_parser_consume_token (parser);
+ while (c_parser_next_token_is (parser, CPP_KEYWORD)
+ && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
+ c_parser_declaration_or_fndef (parser, true, true, true, false, true,
+ NULL, NULL, false, NULL, &data);
+ restore_extension_diagnostics (ext);
+ }
+ else
+ c_parser_declaration_or_fndef (parser, true, true, true, false, true,
+ NULL, NULL, false, NULL, &data);
+ }
+}
+
+/* Finalize an OpenACC routine pragma, applying it to FNDECL.
+ IS_DEFN is true if we're applying it to the definition. */
+
+static void
+c_finish_oacc_routine (struct oacc_routine_data *data, tree fndecl,
+ bool is_defn)
+{
+ /* Keep going if we're in error reporting mode. */
+ if (data->error_seen
+ || fndecl == error_mark_node)
+ return;
+
+ if (data->fndecl_seen)
+ {
+ error_at (data->loc,
+ "%<#pragma acc routine%> not immediately followed by"
+ " a single function declaration or definition");
+ data->error_seen = true;
+ return;
+ }
+ if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL)
+ {
+ error_at (data->loc,
+ "%<#pragma acc routine%> not immediately followed by"
+ " function declaration or definition");
+ data->error_seen = true;
+ return;
+ }
+
+ int compatible
+ = oacc_verify_routine_clauses (fndecl, &data->clauses, data->loc,
+ "#pragma acc routine");
+ if (compatible < 0)
+ {
+ data->error_seen = true;
+ return;
+ }
+ if (compatible > 0)
+ {
+ }
+ else
+ {
+ if (TREE_USED (fndecl) || (!is_defn && DECL_SAVED_TREE (fndecl)))
+ {
+ error_at (data->loc,
+ TREE_USED (fndecl)
+ ? G_("%<#pragma acc routine%> must be applied before use")
+ : G_("%<#pragma acc routine%> must be applied before"
+ " definition"));
+ data->error_seen = true;
+ return;
+ }
+
+ /* Set the routine's level of parallelism. */
+ tree dims = oacc_build_routine_dims (data->clauses);
+ oacc_replace_fn_attrib (fndecl, dims);
+
+ /* Add an "omp declare target" attribute. */
+ DECL_ATTRIBUTES (fndecl)
+ = tree_cons (get_identifier ("omp declare target"),
+ data->clauses, DECL_ATTRIBUTES (fndecl));
+ }
+
+ /* Remember that we've used this "#pragma acc routine". */
+ data->fndecl_seen = true;
+}
+
+/* OpenACC 2.0:
+ # pragma acc update oacc-update-clause[optseq] new-line
+*/
+
+#define OACC_UPDATE_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_HOST) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_IF_PRESENT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_WAIT) )
+
+static void
+c_parser_oacc_update (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ c_parser_consume_pragma (parser);
+
+ tree clauses = c_parser_oacc_all_clauses (parser, OACC_UPDATE_CLAUSE_MASK,
+ "#pragma acc update");
+ if (omp_find_clause (clauses, OMP_CLAUSE_MAP) == NULL_TREE)
+ {
+ error_at (loc,
+ "%<#pragma acc update%> must contain at least one "
+ "%<device%> or %<host%> or %<self%> clause");
+ return;
+ }
+
+ if (parser->error)
+ return;
+
+ tree stmt = make_node (OACC_UPDATE);
+ TREE_TYPE (stmt) = void_type_node;
+ OACC_UPDATE_CLAUSES (stmt) = clauses;
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+}
+
+/* OpenACC 2.0:
+ # pragma acc wait [(intseq)] oacc-wait-clause[optseq] new-line
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OACC_WAIT_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OACC_CLAUSE_ASYNC) )
+
+static tree
+c_parser_oacc_wait (location_t loc, c_parser *parser, char *p_name)
+{
+ tree clauses, list = NULL_TREE, stmt = NULL_TREE;
+
+ if (c_parser_peek_token (parser)->type == CPP_OPEN_PAREN)
+ list = c_parser_oacc_wait_list (parser, loc, list);
+
+ strcpy (p_name, " wait");
+ clauses = c_parser_oacc_all_clauses (parser, OACC_WAIT_CLAUSE_MASK, p_name);
+ stmt = c_finish_oacc_wait (loc, list, clauses);
+ add_stmt (stmt);
+
+ return stmt;
+}
+
+/* OpenMP 5.0:
+ # pragma omp allocate (list) [allocator(allocator)] */
+
+static void
+c_parser_omp_allocate (location_t loc, c_parser *parser)
+{
+ tree allocator = NULL_TREE;
+ tree nl = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ALLOCATE, NULL_TREE);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ matching_parens parens;
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ c_parser_consume_token (parser);
+ if (strcmp ("allocator", p) != 0)
+ error_at (c_parser_peek_token (parser)->location,
+ "expected %<allocator%>");
+ else if (parens.require_open (parser))
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ allocator = expr.value;
+ allocator = c_fully_fold (allocator, false, NULL);
+ tree orig_type
+ = expr.original_type ? expr.original_type : TREE_TYPE (allocator);
+ orig_type = TYPE_MAIN_VARIANT (orig_type);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (allocator))
+ || TREE_CODE (orig_type) != ENUMERAL_TYPE
+ || TYPE_NAME (orig_type)
+ != get_identifier ("omp_allocator_handle_t"))
+ {
+ error_at (expr_loc, "%<allocator%> clause allocator expression "
+ "has type %qT rather than "
+ "%<omp_allocator_handle_t%>",
+ TREE_TYPE (allocator));
+ allocator = NULL_TREE;
+ }
+ parens.skip_until_found_close (parser);
+ }
+ }
+ c_parser_skip_to_pragma_eol (parser);
+
+ if (allocator)
+ for (tree c = nl; c != NULL_TREE; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator;
+
+ sorry_at (loc, "%<#pragma omp allocate%> not yet supported");
+}
+
+/* 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 = expression-stmt
+ capture-block:
+ { v = x; update-stmt; } | { update-stmt; v = x; }
+
+ OpenMP 4.0:
+ update-stmt:
+ expression-stmt | x = x binop expr | x = expr binop x
+ capture-stmt:
+ v = update-stmt
+ capture-block:
+ { v = x; update-stmt; } | { update-stmt; v = x; } | { v = x; x = expr; }
+
+ OpenMP 5.1:
+ # pragma omp atomic compare new-line
+ conditional-update-atomic
+
+ # pragma omp atomic compare capture new-line
+ conditional-update-capture-atomic
+
+ conditional-update-atomic:
+ cond-expr-stmt | cond-update-stmt
+ cond-expr-stmt:
+ x = expr ordop x ? expr : x;
+ x = x ordop expr ? expr : x;
+ x = x == e ? d : x;
+ cond-update-stmt:
+ if (expr ordop x) { x = expr; }
+ if (x ordop expr) { x = expr; }
+ if (x == e) { x = d; }
+ ordop:
+ <, >
+ conditional-update-capture-atomic:
+ v = cond-expr-stmt
+ { v = x; cond-expr-stmt }
+ { cond-expr-stmt v = x; }
+ { v = x; cond-update-stmt }
+ { cond-update-stmt v = x; }
+ if (x == e) { x = d; } else { v = x; }
+ { r = x == e; if (r) { x = d; } }
+ { r = x == e; if (r) { x = d; } else { v = x; } }
+
+ where x, r and v are lvalue expressions with scalar type,
+ expr, e and d are expressions with scalar type and e might be
+ the same as v.
+
+ LOC is the location of the #pragma token. */
+
+static void
+c_parser_omp_atomic (location_t loc, c_parser *parser, bool openacc)
+{
+ tree lhs = NULL_TREE, rhs = NULL_TREE, v = NULL_TREE, r = NULL_TREE;
+ tree lhs1 = NULL_TREE, rhs1 = NULL_TREE;
+ tree stmt, orig_lhs, unfolded_lhs = NULL_TREE, unfolded_lhs1 = NULL_TREE;
+ enum tree_code code = ERROR_MARK, opcode = NOP_EXPR;
+ enum omp_memory_order memory_order = OMP_MEMORY_ORDER_UNSPECIFIED;
+ struct c_expr expr;
+ location_t eloc;
+ bool structured_block = false;
+ bool swapped = false;
+ bool non_lvalue_p;
+ bool first = true;
+ tree clauses = NULL_TREE;
+ bool capture = false;
+ bool compare = false;
+ bool weak = false;
+ enum omp_memory_order fail = OMP_MEMORY_ORDER_UNSPECIFIED;
+ bool no_semicolon = false;
+ bool extra_scope = false;
+
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ if (!first
+ && c_parser_next_token_is (parser, CPP_COMMA)
+ && c_parser_peek_2nd_token (parser)->type == CPP_NAME)
+ c_parser_consume_token (parser);
+
+ first = false;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ location_t cloc = c_parser_peek_token (parser)->location;
+ enum tree_code new_code = ERROR_MARK;
+ enum omp_memory_order new_memory_order
+ = OMP_MEMORY_ORDER_UNSPECIFIED;
+ bool new_capture = false;
+ bool new_compare = false;
+ bool new_weak = false;
+ enum omp_memory_order new_fail = OMP_MEMORY_ORDER_UNSPECIFIED;
+
+ if (!strcmp (p, "read"))
+ new_code = OMP_ATOMIC_READ;
+ else if (!strcmp (p, "write"))
+ new_code = NOP_EXPR;
+ else if (!strcmp (p, "update"))
+ new_code = OMP_ATOMIC;
+ else if (openacc && !strcmp (p, "capture"))
+ new_code = OMP_ATOMIC_CAPTURE_NEW;
+ else if (openacc)
+ {
+ p = NULL;
+ error_at (cloc, "expected %<read%>, %<write%>, %<update%>, "
+ "or %<capture%> clause");
+ }
+ else if (!strcmp (p, "capture"))
+ new_capture = true;
+ else if (!strcmp (p, "compare"))
+ new_compare = true;
+ else if (!strcmp (p, "weak"))
+ new_weak = true;
+ else if (!strcmp (p, "fail"))
+ {
+ matching_parens parens;
+
+ c_parser_consume_token (parser);
+ if (!parens.require_open (parser))
+ continue;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *q
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (!strcmp (q, "seq_cst"))
+ new_fail = OMP_MEMORY_ORDER_SEQ_CST;
+ else if (!strcmp (q, "acquire"))
+ new_fail = OMP_MEMORY_ORDER_ACQUIRE;
+ else if (!strcmp (q, "relaxed"))
+ new_fail = OMP_MEMORY_ORDER_RELAXED;
+ }
+
+ if (new_fail != OMP_MEMORY_ORDER_UNSPECIFIED)
+ {
+ c_parser_consume_token (parser);
+ if (fail != OMP_MEMORY_ORDER_UNSPECIFIED)
+ error_at (cloc, "too many %qs clauses", "fail");
+ else
+ fail = new_fail;
+ }
+ else
+ c_parser_error (parser, "expected %<seq_cst%>, %<acquire%> "
+ "or %<relaxed%>");
+ parens.skip_until_found_close (parser);
+ continue;
+ }
+ else if (!strcmp (p, "seq_cst"))
+ new_memory_order = OMP_MEMORY_ORDER_SEQ_CST;
+ else if (!strcmp (p, "acq_rel"))
+ new_memory_order = OMP_MEMORY_ORDER_ACQ_REL;
+ else if (!strcmp (p, "release"))
+ new_memory_order = OMP_MEMORY_ORDER_RELEASE;
+ else if (!strcmp (p, "acquire"))
+ new_memory_order = OMP_MEMORY_ORDER_ACQUIRE;
+ else if (!strcmp (p, "relaxed"))
+ new_memory_order = OMP_MEMORY_ORDER_RELAXED;
+ else if (!strcmp (p, "hint"))
+ {
+ c_parser_consume_token (parser);
+ clauses = c_parser_omp_clause_hint (parser, clauses);
+ continue;
+ }
+ else
+ {
+ p = NULL;
+ error_at (cloc, "expected %<read%>, %<write%>, %<update%>, "
+ "%<capture%>, %<compare%>, %<weak%>, %<fail%>, "
+ "%<seq_cst%>, %<acq_rel%>, %<release%>, "
+ "%<relaxed%> or %<hint%> clause");
+ }
+ if (p)
+ {
+ if (new_code != ERROR_MARK)
+ {
+ /* OpenACC permits 'update capture'. */
+ if (openacc
+ && code == OMP_ATOMIC
+ && new_code == OMP_ATOMIC_CAPTURE_NEW)
+ code = new_code;
+ else if (code != ERROR_MARK)
+ error_at (cloc, "too many atomic clauses");
+ else
+ code = new_code;
+ }
+ else if (new_memory_order != OMP_MEMORY_ORDER_UNSPECIFIED)
+ {
+ if (memory_order != OMP_MEMORY_ORDER_UNSPECIFIED)
+ error_at (cloc, "too many memory order clauses");
+ else
+ memory_order = new_memory_order;
+ }
+ else if (new_capture)
+ {
+ if (capture)
+ error_at (cloc, "too many %qs clauses", "capture");
+ else
+ capture = true;
+ }
+ else if (new_compare)
+ {
+ if (compare)
+ error_at (cloc, "too many %qs clauses", "compare");
+ else
+ compare = true;
+ }
+ else if (new_weak)
+ {
+ if (weak)
+ error_at (cloc, "too many %qs clauses", "weak");
+ else
+ weak = true;
+ }
+ c_parser_consume_token (parser);
+ continue;
+ }
+ }
+ break;
+ }
+ c_parser_skip_to_pragma_eol (parser);
+
+ if (code == ERROR_MARK)
+ code = OMP_ATOMIC;
+ if (capture)
+ {
+ if (code != OMP_ATOMIC)
+ error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> "
+ "clauses", "capture");
+ else
+ code = OMP_ATOMIC_CAPTURE_NEW;
+ }
+ if (compare && code != OMP_ATOMIC && code != OMP_ATOMIC_CAPTURE_NEW)
+ {
+ error_at (loc, "%qs clause is incompatible with %<read%> or %<write%> "
+ "clauses", "compare");
+ compare = false;
+ }
+ if (fail != OMP_MEMORY_ORDER_UNSPECIFIED && !compare)
+ {
+ error_at (loc, "%qs clause requires %qs clause", "fail", "compare");
+ fail = OMP_MEMORY_ORDER_UNSPECIFIED;
+ }
+ if (weak && !compare)
+ {
+ error_at (loc, "%qs clause requires %qs clause", "weak", "compare");
+ weak = false;
+ }
+ if (openacc)
+ memory_order = OMP_MEMORY_ORDER_RELAXED;
+ else if (memory_order == OMP_MEMORY_ORDER_UNSPECIFIED)
+ {
+ omp_requires_mask
+ = (enum omp_requires) (omp_requires_mask
+ | OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED);
+ switch ((enum omp_memory_order)
+ (omp_requires_mask & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER))
+ {
+ case OMP_MEMORY_ORDER_UNSPECIFIED:
+ case OMP_MEMORY_ORDER_RELAXED:
+ memory_order = OMP_MEMORY_ORDER_RELAXED;
+ break;
+ case OMP_MEMORY_ORDER_SEQ_CST:
+ memory_order = OMP_MEMORY_ORDER_SEQ_CST;
+ break;
+ case OMP_MEMORY_ORDER_ACQ_REL:
+ switch (code)
+ {
+ case OMP_ATOMIC_READ:
+ memory_order = OMP_MEMORY_ORDER_ACQUIRE;
+ break;
+ case NOP_EXPR: /* atomic write */
+ memory_order = OMP_MEMORY_ORDER_RELEASE;
+ break;
+ default:
+ memory_order = OMP_MEMORY_ORDER_ACQ_REL;
+ break;
+ }
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ }
+ else
+ switch (code)
+ {
+ case OMP_ATOMIC_READ:
+ if (memory_order == OMP_MEMORY_ORDER_RELEASE)
+ {
+ error_at (loc, "%<#pragma omp atomic read%> incompatible with "
+ "%<release%> clause");
+ memory_order = OMP_MEMORY_ORDER_SEQ_CST;
+ }
+ else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL)
+ memory_order = OMP_MEMORY_ORDER_ACQUIRE;
+ break;
+ case NOP_EXPR: /* atomic write */
+ if (memory_order == OMP_MEMORY_ORDER_ACQUIRE)
+ {
+ error_at (loc, "%<#pragma omp atomic write%> incompatible with "
+ "%<acquire%> clause");
+ memory_order = OMP_MEMORY_ORDER_SEQ_CST;
+ }
+ else if (memory_order == OMP_MEMORY_ORDER_ACQ_REL)
+ memory_order = OMP_MEMORY_ORDER_RELEASE;
+ break;
+ default:
+ break;
+ }
+ if (fail != OMP_MEMORY_ORDER_UNSPECIFIED)
+ memory_order
+ = (enum omp_memory_order) (memory_order
+ | (fail << OMP_FAIL_MEMORY_ORDER_SHIFT));
+
+ switch (code)
+ {
+ case OMP_ATOMIC_READ:
+ case NOP_EXPR: /* atomic write */
+ v = c_parser_cast_expression (parser, NULL).value;
+ non_lvalue_p = !lvalue_p (v);
+ v = c_fully_fold (v, false, NULL, true);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (non_lvalue_p)
+ v = non_lvalue (v);
+ 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;
+ lhs = c_fully_fold (lhs, false, NULL);
+ if (lhs == error_mark_node)
+ goto saw_error;
+ }
+ else
+ {
+ lhs = c_parser_cast_expression (parser, NULL).value;
+ non_lvalue_p = !lvalue_p (lhs);
+ lhs = c_fully_fold (lhs, false, NULL, true);
+ if (lhs == error_mark_node)
+ goto saw_error;
+ if (non_lvalue_p)
+ lhs = non_lvalue (lhs);
+ }
+ 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 if (compare
+ && c_parser_next_token_is_keyword (parser, RID_IF))
+ break;
+ else
+ {
+ v = c_parser_cast_expression (parser, NULL).value;
+ non_lvalue_p = !lvalue_p (v);
+ v = c_fully_fold (v, false, NULL, true);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (non_lvalue_p)
+ v = non_lvalue (v);
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ if (compare && c_parser_next_token_is_keyword (parser, RID_IF))
+ {
+ eloc = c_parser_peek_token (parser)->location;
+ error_at (eloc, "expected expression");
+ goto saw_error;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* For structured_block case we don't know yet whether
+ old or new x should be captured. */
+restart:
+ if (compare && c_parser_next_token_is_keyword (parser, RID_IF))
+ {
+ c_parser_consume_token (parser);
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ goto saw_error;
+ eloc = c_parser_peek_token (parser)->location;
+ c_expr cmp_expr;
+ if (r)
+ {
+ cmp_expr = c_parser_cast_expression (parser, NULL);
+ cmp_expr = default_function_array_conversion (eloc, cmp_expr);
+ }
+ else
+ cmp_expr = c_parser_binary_expression (parser, NULL, void_list_node);
+ parens.skip_until_found_close (parser);
+ if (cmp_expr.value == error_mark_node)
+ goto saw_error;
+ if (r)
+ {
+ if (!c_tree_equal (cmp_expr.value, unfolded_lhs))
+ goto bad_if;
+ cmp_expr.value = rhs1;
+ rhs1 = NULL_TREE;
+ gcc_assert (TREE_CODE (cmp_expr.value) == EQ_EXPR);
+ }
+ if (TREE_CODE (cmp_expr.value) == EQ_EXPR)
+ ;
+ else if (!structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc),
+ "expected %<==%> comparison in %<if%> condition");
+ goto saw_error;
+ }
+ else if (TREE_CODE (cmp_expr.value) != GT_EXPR
+ && TREE_CODE (cmp_expr.value) != LT_EXPR)
+ {
+ error_at (EXPR_LOC_OR_LOC (cmp_expr.value, eloc),
+ "expected %<==%>, %<<%> or %<>%> comparison in %<if%> "
+ "condition");
+ goto saw_error;
+ }
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ goto saw_error;
+
+ extra_scope = true;
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_cast_expression (parser, NULL);
+ lhs = expr.value;
+ expr = default_function_array_conversion (eloc, expr);
+ unfolded_lhs = expr.value;
+ lhs = c_fully_fold (lhs, false, NULL, true);
+ orig_lhs = lhs;
+ if (lhs == error_mark_node)
+ goto saw_error;
+ if (!lvalue_p (unfolded_lhs))
+ lhs = non_lvalue (lhs);
+ if (!c_parser_next_token_is (parser, CPP_EQ))
+ {
+ c_parser_error (parser, "expected %<=%>");
+ goto saw_error;
+ }
+ c_parser_consume_token (parser);
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expr_no_commas (parser, NULL);
+ rhs1 = expr.value;
+
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ goto saw_error;
+
+ if (!c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"))
+ goto saw_error;
+
+ extra_scope = false;
+ no_semicolon = true;
+
+ if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), unfolded_lhs))
+ {
+ if (TREE_CODE (cmp_expr.value) == EQ_EXPR)
+ {
+ opcode = COND_EXPR;
+ rhs = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1),
+ false, NULL, true);
+ rhs1 = c_fully_fold (rhs1, false, NULL, true);
+ }
+ else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), rhs1))
+ {
+ opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR
+ ? MIN_EXPR : MAX_EXPR);
+ rhs = c_fully_fold (rhs1, false, NULL, true);
+ rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 0),
+ false, NULL, true);
+ }
+ else
+ goto bad_if;
+ }
+ else if (TREE_CODE (cmp_expr.value) == EQ_EXPR)
+ goto bad_if;
+ else if (c_tree_equal (TREE_OPERAND (cmp_expr.value, 1), unfolded_lhs)
+ && c_tree_equal (TREE_OPERAND (cmp_expr.value, 0), rhs1))
+ {
+ opcode = (TREE_CODE (cmp_expr.value) == GT_EXPR
+ ? MAX_EXPR : MIN_EXPR);
+ rhs = c_fully_fold (rhs1, false, NULL, true);
+ rhs1 = c_fully_fold (TREE_OPERAND (cmp_expr.value, 1),
+ false, NULL, true);
+ }
+ else
+ {
+ bad_if:
+ c_parser_error (parser,
+ "invalid form of %<#pragma omp atomic compare%>");
+ goto saw_error;
+ }
+
+ if (c_parser_next_token_is_keyword (parser, RID_ELSE))
+ {
+ if (code != OMP_ATOMIC_CAPTURE_NEW
+ || (structured_block && r == NULL_TREE)
+ || TREE_CODE (cmp_expr.value) != EQ_EXPR)
+ {
+ eloc = c_parser_peek_token (parser)->location;
+ error_at (eloc, "unexpected %<else%>");
+ goto saw_error;
+ }
+
+ c_parser_consume_token (parser);
+
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ goto saw_error;
+
+ extra_scope = true;
+ v = c_parser_cast_expression (parser, NULL).value;
+ non_lvalue_p = !lvalue_p (v);
+ v = c_fully_fold (v, false, NULL, true);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (non_lvalue_p)
+ v = non_lvalue (v);
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+
+ expr = c_parser_expr_no_commas (parser, NULL);
+
+ if (!c_tree_equal (expr.value, unfolded_lhs))
+ goto bad_if;
+
+ if (!c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ goto saw_error;
+
+ if (!c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>"))
+ goto saw_error;
+
+ extra_scope = false;
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ if (r == NULL_TREE)
+ /* Signal to c_finish_omp_atomic that in
+ if (x == e) { x = d; } else { v = x; }
+ case the store to v should be conditional. */
+ r = void_list_node;
+ }
+ else if (code == OMP_ATOMIC_CAPTURE_NEW && !structured_block)
+ {
+ c_parser_require_keyword (parser, RID_ELSE, "expected %<else%>");
+ goto saw_error;
+ }
+ else if (code == OMP_ATOMIC_CAPTURE_NEW
+ && r != NULL_TREE
+ && v == NULL_TREE)
+ code = OMP_ATOMIC;
+ goto stmt_done;
+ }
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_cast_expression (parser, NULL);
+ lhs = expr.value;
+ expr = default_function_array_conversion (eloc, expr);
+ unfolded_lhs = expr.value;
+ lhs = c_fully_fold (lhs, false, NULL, true);
+ orig_lhs = lhs;
+ switch (TREE_CODE (lhs))
+ {
+ invalid_compare:
+ error_at (eloc, "invalid form of %<pragma omp atomic compare%>");
+ /* FALLTHRU */
+ case ERROR_MARK:
+ saw_error:
+ c_parser_skip_to_end_of_block_or_statement (parser);
+ if (extra_scope && c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ c_parser_consume_token (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);
+ unfolded_lhs = NULL_TREE;
+ opcode = PLUS_EXPR;
+ rhs = integer_one_node;
+ if (compare)
+ goto invalid_compare;
+ 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);
+ unfolded_lhs = NULL_TREE;
+ opcode = MINUS_EXPR;
+ rhs = integer_one_node;
+ if (compare)
+ goto invalid_compare;
+ 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);
+ unfolded_lhs = NULL_TREE;
+ opcode = NOP_EXPR;
+ if (code == OMP_ATOMIC_CAPTURE_NEW
+ && !structured_block
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ if (compare)
+ goto invalid_compare;
+ 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);
+ unfolded_lhs = NULL_TREE;
+ opcode = NOP_EXPR;
+ if (code == OMP_ATOMIC_CAPTURE_NEW
+ && !structured_block
+ && TREE_CODE (orig_lhs) == COMPOUND_EXPR)
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ if (compare)
+ goto invalid_compare;
+ break;
+ }
+ }
+ /* FALLTHRU */
+ default:
+ if (!lvalue_p (unfolded_lhs))
+ lhs = non_lvalue (lhs);
+ if (compare && !c_parser_next_token_is (parser, CPP_EQ))
+ {
+ c_parser_error (parser, "expected %<=%>");
+ goto saw_error;
+ }
+ 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:
+ c_parser_consume_token (parser);
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expr_no_commas (parser, NULL, unfolded_lhs);
+ rhs1 = expr.value;
+ switch (TREE_CODE (rhs1))
+ {
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case RDIV_EXPR:
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case LSHIFT_EXPR:
+ case RSHIFT_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ if (compare)
+ break;
+ if (c_tree_equal (TREE_OPERAND (rhs1, 0), unfolded_lhs))
+ {
+ opcode = TREE_CODE (rhs1);
+ rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL,
+ true);
+ rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL,
+ true);
+ goto stmt_done;
+ }
+ if (c_tree_equal (TREE_OPERAND (rhs1, 1), unfolded_lhs))
+ {
+ opcode = TREE_CODE (rhs1);
+ rhs = c_fully_fold (TREE_OPERAND (rhs1, 0), false, NULL,
+ true);
+ rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL,
+ true);
+ swapped = !commutative_tree_code (opcode);
+ goto stmt_done;
+ }
+ break;
+ case COND_EXPR:
+ if (!compare)
+ break;
+ if (TREE_CODE (TREE_OPERAND (rhs1, 0)) != GT_EXPR
+ && TREE_CODE (TREE_OPERAND (rhs1, 0)) != LT_EXPR
+ && TREE_CODE (TREE_OPERAND (rhs1, 0)) != EQ_EXPR)
+ break;
+ if (!TREE_OPERAND (rhs1, 1))
+ break;
+ if (!c_tree_equal (TREE_OPERAND (rhs1, 2), unfolded_lhs))
+ break;
+ if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0),
+ unfolded_lhs))
+ {
+ if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR)
+ {
+ opcode = COND_EXPR;
+ rhs = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1,
+ 0), 1),
+ false, NULL, true);
+ rhs1 = c_fully_fold (TREE_OPERAND (rhs1, 1), false,
+ NULL, true);
+ goto stmt_done;
+ }
+ if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1),
+ TREE_OPERAND (rhs1, 1)))
+ {
+ opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR
+ ? MIN_EXPR : MAX_EXPR);
+ rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL,
+ true);
+ rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1,
+ 0), 0),
+ false, NULL, true);
+ goto stmt_done;
+ }
+ }
+ else if (TREE_CODE (TREE_OPERAND (rhs1, 0)) == EQ_EXPR)
+ break;
+ else if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 1),
+ unfolded_lhs))
+ {
+ if (c_tree_equal (TREE_OPERAND (TREE_OPERAND (rhs1, 0), 0),
+ TREE_OPERAND (rhs1, 1)))
+ {
+ opcode = (TREE_CODE (TREE_OPERAND (rhs1, 0)) == GT_EXPR
+ ? MAX_EXPR : MIN_EXPR);
+ rhs = c_fully_fold (TREE_OPERAND (rhs1, 1), false, NULL,
+ true);
+ rhs1 = c_fully_fold (TREE_OPERAND (TREE_OPERAND (rhs1,
+ 0), 1),
+ false, NULL, true);
+ goto stmt_done;
+ }
+ }
+ break;
+ case EQ_EXPR:
+ if (!compare
+ || code != OMP_ATOMIC_CAPTURE_NEW
+ || !structured_block
+ || v
+ || r)
+ break;
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON)
+ && c_parser_peek_2nd_token (parser)->keyword == RID_IF)
+ {
+ r = lhs;
+ lhs = NULL_TREE;
+ c_parser_consume_token (parser);
+ goto restart;
+ }
+ break;
+ case ERROR_MARK:
+ goto saw_error;
+ default:
+ break;
+ }
+ if (c_parser_peek_token (parser)->type == CPP_SEMICOLON)
+ {
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW)
+ {
+ code = OMP_ATOMIC_CAPTURE_OLD;
+ v = lhs;
+ lhs = NULL_TREE;
+ expr = default_function_array_read_conversion (eloc, expr);
+ unfolded_lhs1 = expr.value;
+ lhs1 = c_fully_fold (unfolded_lhs1, false, NULL, true);
+ rhs1 = NULL_TREE;
+ c_parser_consume_token (parser);
+ goto restart;
+ }
+ if (structured_block && !compare)
+ {
+ opcode = NOP_EXPR;
+ expr = default_function_array_read_conversion (eloc, expr);
+ rhs = c_fully_fold (expr.value, false, NULL, true);
+ rhs1 = NULL_TREE;
+ goto stmt_done;
+ }
+ }
+ c_parser_error (parser, "invalid form of %<#pragma omp atomic%>");
+ goto saw_error;
+ 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);
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_expression (parser);
+ expr = default_function_array_read_conversion (eloc, expr);
+ rhs = expr.value;
+ rhs = c_fully_fold (rhs, false, NULL, true);
+ break;
+ }
+stmt_done:
+ if (structured_block && code == OMP_ATOMIC_CAPTURE_NEW && r == NULL_TREE)
+ {
+ if (!no_semicolon
+ && !c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ goto saw_error;
+ no_semicolon = false;
+ v = c_parser_cast_expression (parser, NULL).value;
+ non_lvalue_p = !lvalue_p (v);
+ v = c_fully_fold (v, false, NULL, true);
+ if (v == error_mark_node)
+ goto saw_error;
+ if (non_lvalue_p)
+ v = non_lvalue (v);
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ goto saw_error;
+ eloc = c_parser_peek_token (parser)->location;
+ expr = c_parser_cast_expression (parser, NULL);
+ lhs1 = expr.value;
+ expr = default_function_array_read_conversion (eloc, expr);
+ unfolded_lhs1 = expr.value;
+ lhs1 = c_fully_fold (lhs1, false, NULL, true);
+ if (lhs1 == error_mark_node)
+ goto saw_error;
+ if (!lvalue_p (unfolded_lhs1))
+ lhs1 = non_lvalue (lhs1);
+ }
+ if (structured_block)
+ {
+ if (!no_semicolon)
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ c_parser_require (parser, CPP_CLOSE_BRACE, "expected %<}%>");
+ }
+done:
+ if (weak && opcode != COND_EXPR)
+ {
+ error_at (loc, "%<weak%> clause requires atomic equality comparison");
+ weak = false;
+ }
+ if (unfolded_lhs && unfolded_lhs1
+ && !c_tree_equal (unfolded_lhs, unfolded_lhs1))
+ {
+ error ("%<#pragma omp atomic capture%> uses two different "
+ "expressions for memory");
+ stmt = error_mark_node;
+ }
+ else
+ stmt = c_finish_omp_atomic (loc, code, opcode, lhs, rhs, v, lhs1, rhs1, r,
+ swapped, memory_order, weak);
+ if (stmt != error_mark_node)
+ add_stmt (stmt);
+
+ if (!structured_block && !no_semicolon)
+ 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
+
+ OpenMP 4.5:
+ # pragma omp critical [(name) [hint(expression)]] new-line
+
+ LOC is the location of the #pragma itself. */
+
+#define OMP_CRITICAL_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HINT) )
+
+static tree
+c_parser_omp_critical (location_t loc, c_parser *parser, bool *if_p)
+{
+ tree stmt, name = NULL_TREE, clauses = NULL_TREE;
+
+ 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");
+
+ if (c_parser_next_token_is (parser, CPP_COMMA)
+ && c_parser_peek_2nd_token (parser)->type == CPP_NAME)
+ c_parser_consume_token (parser);
+ }
+ clauses = c_parser_omp_all_clauses (parser, OMP_CRITICAL_CLAUSE_MASK,
+ "#pragma omp critical");
+ stmt = c_parser_omp_structured_block (parser, if_p);
+ return c_finish_omp_critical (loc, stmt, name, clauses);
+}
+
+/* OpenMP 5.0:
+ # pragma omp depobj ( depobj ) depobj-clause new-line
+
+ depobj-clause:
+ depend (dependence-type : locator)
+ destroy
+ update (dependence-type)
+
+ dependence-type:
+ in
+ out
+ inout
+ mutexinout */
+
+static void
+c_parser_omp_depobj (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+
+ tree depobj = c_parser_expr_no_commas (parser, NULL).value;
+ if (depobj != error_mark_node)
+ {
+ if (!lvalue_p (depobj))
+ {
+ error_at (EXPR_LOC_OR_LOC (depobj, loc),
+ "%<depobj%> expression is not lvalue expression");
+ depobj = error_mark_node;
+ }
+ else
+ {
+ tree addr = build_unary_op (EXPR_LOC_OR_LOC (depobj, loc), ADDR_EXPR,
+ depobj, false);
+ if (addr == error_mark_node)
+ depobj = error_mark_node;
+ else
+ depobj = build_indirect_ref (EXPR_LOC_OR_LOC (depobj, loc),
+ addr, RO_UNARY_STAR);
+ }
+ }
+
+ parens.skip_until_found_close (parser);
+ tree clause = NULL_TREE;
+ enum omp_clause_depend_kind kind = OMP_CLAUSE_DEPEND_SOURCE;
+ location_t c_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ c_parser_consume_token (parser);
+ if (!strcmp ("depend", p))
+ {
+ clause = c_parser_omp_clause_depend (parser, NULL_TREE);
+ clause = c_finish_omp_clauses (clause, C_ORT_OMP);
+ if (!clause)
+ clause = error_mark_node;
+ }
+ else if (!strcmp ("destroy", p))
+ kind = OMP_CLAUSE_DEPEND_LAST;
+ else if (!strcmp ("update", p))
+ {
+ matching_parens c_parens;
+ if (c_parens.require_open (parser))
+ {
+ location_t c2_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p2
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ c_parser_consume_token (parser);
+ if (!strcmp ("in", p2))
+ kind = OMP_CLAUSE_DEPEND_IN;
+ else if (!strcmp ("out", p2))
+ kind = OMP_CLAUSE_DEPEND_OUT;
+ else if (!strcmp ("inout", p2))
+ kind = OMP_CLAUSE_DEPEND_INOUT;
+ else if (!strcmp ("mutexinoutset", p2))
+ kind = OMP_CLAUSE_DEPEND_MUTEXINOUTSET;
+ }
+ if (kind == OMP_CLAUSE_DEPEND_SOURCE)
+ {
+ clause = error_mark_node;
+ error_at (c2_loc, "expected %<in%>, %<out%>, %<inout%> or "
+ "%<mutexinoutset%>");
+ }
+ c_parens.skip_until_found_close (parser);
+ }
+ else
+ clause = error_mark_node;
+ }
+ }
+ if (!clause && kind == OMP_CLAUSE_DEPEND_SOURCE)
+ {
+ clause = error_mark_node;
+ error_at (c_loc, "expected %<depend%>, %<destroy%> or %<update%> clause");
+ }
+ c_parser_skip_to_pragma_eol (parser);
+
+ c_finish_omp_depobj (loc, depobj, kind, clause);
+}
+
+
+/* OpenMP 2.5:
+ # pragma omp flush flush-vars[opt] new-line
+
+ flush-vars:
+ ( variable-list )
+
+ OpenMP 5.0:
+ # pragma omp flush memory-order-clause new-line */
+
+static void
+c_parser_omp_flush (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ enum memmodel mo = MEMMODEL_LAST;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (!strcmp (p, "seq_cst"))
+ mo = MEMMODEL_SEQ_CST;
+ else if (!strcmp (p, "acq_rel"))
+ mo = MEMMODEL_ACQ_REL;
+ else if (!strcmp (p, "release"))
+ mo = MEMMODEL_RELEASE;
+ else if (!strcmp (p, "acquire"))
+ mo = MEMMODEL_ACQUIRE;
+ else
+ error_at (c_parser_peek_token (parser)->location,
+ "expected %<seq_cst%>, %<acq_rel%>, %<release%> or "
+ "%<acquire%>");
+ c_parser_consume_token (parser);
+ }
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ if (mo != MEMMODEL_LAST)
+ error_at (c_parser_peek_token (parser)->location,
+ "%<flush%> list specified together with memory order "
+ "clause");
+ 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, mo);
+}
+
+/* Parse an OpenMP structured block sequence. KIND is the corresponding
+ separating directive. */
+
+static tree
+c_parser_omp_structured_block_sequence (c_parser *parser,
+ enum pragma_kind kind)
+{
+ tree stmt = push_stmt_list ();
+ c_parser_statement (parser, NULL);
+ do
+ {
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ break;
+ if (c_parser_next_token_is (parser, CPP_EOF))
+ break;
+
+ if (kind != PRAGMA_NONE
+ && c_parser_peek_token (parser)->pragma_kind == kind)
+ break;
+ c_parser_statement (parser, NULL);
+ }
+ while (1);
+ return pop_stmt_list (stmt);
+}
+
+/* OpenMP 5.0:
+
+ scan-loop-body:
+ { structured-block scan-directive structured-block } */
+
+static void
+c_parser_omp_scan_loop_body (c_parser *parser, bool open_brace_parsed)
+{
+ tree substmt;
+ location_t loc;
+ tree clauses = NULL_TREE;
+
+ loc = c_parser_peek_token (parser)->location;
+ if (!open_brace_parsed
+ && !c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ {
+ /* Avoid skipping until the end of the block. */
+ parser->error = false;
+ return;
+ }
+
+ substmt = c_parser_omp_structured_block_sequence (parser, PRAGMA_OMP_SCAN);
+ substmt = build2 (OMP_SCAN, void_type_node, substmt, NULL_TREE);
+ SET_EXPR_LOCATION (substmt, loc);
+ add_stmt (substmt);
+
+ loc = c_parser_peek_token (parser)->location;
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SCAN)
+ {
+ enum omp_clause_code clause = OMP_CLAUSE_ERROR;
+
+ c_parser_consume_pragma (parser);
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "inclusive") == 0)
+ clause = OMP_CLAUSE_INCLUSIVE;
+ else if (strcmp (p, "exclusive") == 0)
+ clause = OMP_CLAUSE_EXCLUSIVE;
+ }
+ if (clause != OMP_CLAUSE_ERROR)
+ {
+ c_parser_consume_token (parser);
+ clauses = c_parser_omp_var_list_parens (parser, clause, NULL_TREE);
+ }
+ else
+ c_parser_error (parser, "expected %<inclusive%> or "
+ "%<exclusive%> clause");
+ c_parser_skip_to_pragma_eol (parser);
+ }
+ else
+ error ("expected %<#pragma omp scan%>");
+
+ clauses = c_finish_omp_clauses (clauses, C_ORT_OMP);
+ substmt = c_parser_omp_structured_block_sequence (parser, PRAGMA_NONE);
+ substmt = build2 (OMP_SCAN, void_type_node, substmt, clauses);
+ SET_EXPR_LOCATION (substmt, loc);
+ add_stmt (substmt);
+
+ c_parser_skip_until_found (parser, CPP_CLOSE_BRACE,
+ "expected %<}%>");
+}
+
+/* Parse the restricted form of loop statements allowed by OpenACC and 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 "acc" or "omp" in "#pragma acc" or "#pragma omp",
+ respectively. */
+
+static tree
+c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
+ tree clauses, tree *cclauses, bool *if_p)
+{
+ tree decl, cond, incr, body, init, stmt, cl;
+ unsigned char save_in_statement;
+ tree declv, condv, incrv, initv, ret = NULL_TREE;
+ tree pre_body = NULL_TREE, this_pre_body;
+ tree ordered_cl = NULL_TREE;
+ bool fail = false, open_brace_parsed = false;
+ int i, collapse = 1, ordered = 0, count, nbraces = 0;
+ location_t for_loc;
+ bool tiling = false;
+ bool inscan = false;
+ 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_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl));
+ else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_TILE)
+ {
+ tiling = true;
+ collapse = list_length (OMP_CLAUSE_TILE_LIST (cl));
+ }
+ else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_ORDERED
+ && OMP_CLAUSE_ORDERED_EXPR (cl))
+ {
+ ordered_cl = cl;
+ ordered = tree_to_shwi (OMP_CLAUSE_ORDERED_EXPR (cl));
+ }
+ else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_REDUCTION
+ && OMP_CLAUSE_REDUCTION_INSCAN (cl)
+ && (code == OMP_SIMD || code == OMP_FOR))
+ inscan = true;
+
+ if (ordered && ordered < collapse)
+ {
+ error_at (OMP_CLAUSE_LOCATION (ordered_cl),
+ "%<ordered%> clause parameter is less than %<collapse%>");
+ OMP_CLAUSE_ORDERED_EXPR (ordered_cl)
+ = build_int_cst (NULL_TREE, collapse);
+ ordered = collapse;
+ }
+ if (ordered)
+ {
+ for (tree *pc = &clauses; *pc; )
+ if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_LINEAR)
+ {
+ error_at (OMP_CLAUSE_LOCATION (*pc),
+ "%<linear%> clause may not be specified together "
+ "with %<ordered%> clause with a parameter");
+ *pc = OMP_CLAUSE_CHAIN (*pc);
+ }
+ else
+ pc = &OMP_CLAUSE_CHAIN (*pc);
+ }
+
+ gcc_assert (tiling || (collapse >= 1 && ordered >= 0));
+ count = ordered ? ordered : collapse;
+
+ declv = make_tree_vec (count);
+ initv = make_tree_vec (count);
+ condv = make_tree_vec (count);
+ incrv = make_tree_vec (count);
+
+ 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);
+
+ /* Forbid break/continue in the loop initializer, condition, and
+ increment expressions. */
+ save_in_statement = in_statement;
+ in_statement = IN_OMP_BLOCK;
+
+ for (i = 0; i < count; i++)
+ {
+ int bracecount = 0;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ 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));
+ this_pre_body = push_stmt_list ();
+ c_in_omp_for = true;
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true);
+ c_in_omp_for = false;
+ if (this_pre_body)
+ {
+ this_pre_body = pop_stmt_list (this_pre_body);
+ if (pre_body)
+ {
+ tree t = pre_body;
+ pre_body = push_stmt_list ();
+ add_stmt (t);
+ add_stmt (this_pre_body);
+ pre_body = pop_stmt_list (pre_body);
+ }
+ else
+ pre_body = this_pre_body;
+ }
+ 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);
+ c_in_omp_for = true;
+ init = build_modify_expr (init_loc, decl, decl_exp.original_type,
+ NOP_EXPR, init_loc, init_exp.value,
+ init_exp.original_type);
+ c_in_omp_for = false;
+ 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;
+ c_in_omp_for = true;
+ struct c_expr cond_expr
+ = c_parser_binary_expression (parser, NULL, NULL_TREE);
+ c_in_omp_for = false;
+
+ cond = cond_expr.value;
+ cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
+ switch (cond_expr.original_code)
+ {
+ case GT_EXPR:
+ case GE_EXPR:
+ case LT_EXPR:
+ case LE_EXPR:
+ break;
+ case NE_EXPR:
+ if (code != OACC_LOOP)
+ break;
+ /* FALLTHRU. */
+ 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);
+ }
+ parens.skip_until_found_close (parser);
+
+ 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 == count - 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;
+ count = 0;
+ break;
+ }
+ }
+ while (1);
+
+ nbraces += bracecount;
+ }
+
+ if (nbraces)
+ if_p = NULL;
+
+ in_statement = IN_OMP_FOR;
+ body = push_stmt_list ();
+
+ if (inscan)
+ c_parser_omp_scan_loop_body (parser, open_brace_parsed);
+ else 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_p));
+
+ body = pop_stmt_list (body);
+ in_statement = save_in_statement;
+
+ 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)
+ {
+ c_in_omp_for = true;
+ stmt = c_finish_omp_for (loc, code, declv, NULL, initv, condv,
+ incrv, body, pre_body, true);
+ c_in_omp_for = false;
+
+ /* Check for iterators appearing in lb, b or incr expressions. */
+ if (stmt && !c_omp_check_loop_iv (stmt, declv, NULL))
+ stmt = NULL_TREE;
+
+ if (stmt)
+ {
+ add_stmt (stmt);
+
+ for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++)
+ {
+ tree init = TREE_VEC_ELT (OMP_FOR_INIT (stmt), i);
+ gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
+ tree decl = TREE_OPERAND (init, 0);
+ tree cond = TREE_VEC_ELT (OMP_FOR_COND (stmt), i);
+ gcc_assert (COMPARISON_CLASS_P (cond));
+ gcc_assert (TREE_OPERAND (cond, 0) == decl);
+
+ tree op0 = TREE_OPERAND (init, 1);
+ if (!OMP_FOR_NON_RECTANGULAR (stmt)
+ || TREE_CODE (op0) != TREE_VEC)
+ TREE_OPERAND (init, 1) = c_fully_fold (op0, false, NULL);
+ else
+ {
+ TREE_VEC_ELT (op0, 1)
+ = c_fully_fold (TREE_VEC_ELT (op0, 1), false, NULL);
+ TREE_VEC_ELT (op0, 2)
+ = c_fully_fold (TREE_VEC_ELT (op0, 2), false, NULL);
+ }
+
+ tree op1 = TREE_OPERAND (cond, 1);
+ if (!OMP_FOR_NON_RECTANGULAR (stmt)
+ || TREE_CODE (op1) != TREE_VEC)
+ TREE_OPERAND (cond, 1) = c_fully_fold (op1, false, NULL);
+ else
+ {
+ TREE_VEC_ELT (op1, 1)
+ = c_fully_fold (TREE_VEC_ELT (op1, 1), false, NULL);
+ TREE_VEC_ELT (op1, 2)
+ = c_fully_fold (TREE_VEC_ELT (op1, 2), false, NULL);
+ }
+ }
+
+ if (cclauses != NULL
+ && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL)
+ {
+ tree *c;
+ for (c = &cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL]; *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 < count; i++)
+ if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c))
+ break;
+ if (i == count)
+ 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
+ {
+ /* Move lastprivate (decl) clause to OMP_FOR_CLAUSES. */
+ tree l = *c;
+ *c = OMP_CLAUSE_CHAIN (*c);
+ if (code == OMP_SIMD)
+ {
+ OMP_CLAUSE_CHAIN (l)
+ = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+ cclauses[C_OMP_CLAUSE_SPLIT_FOR] = l;
+ }
+ else
+ {
+ OMP_CLAUSE_CHAIN (l) = clauses;
+ clauses = l;
+ }
+ }
+ }
+ }
+ 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;
+}
+
+/* Helper function for OpenMP parsing, split clauses and call
+ finish_omp_clauses on each of the set of clauses afterwards. */
+
+static void
+omp_split_clauses (location_t loc, enum tree_code code,
+ omp_clause_mask mask, tree clauses, tree *cclauses)
+{
+ int i;
+ c_omp_split_clauses (loc, code, mask, clauses, cclauses);
+ for (i = 0; i < C_OMP_CLAUSE_SPLIT_COUNT; i++)
+ if (cclauses[i])
+ cclauses[i] = c_finish_omp_clauses (cclauses[i],
+ i == C_OMP_CLAUSE_SPLIT_TARGET
+ ? C_ORT_OMP_TARGET : C_ORT_OMP);
+}
+
+/* OpenMP 5.0:
+ #pragma omp loop loop-clause[optseq] new-line
+ for-loop
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OMP_LOOP_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_BIND) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER))
+
+static tree
+c_parser_omp_loop (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses,
+ bool *if_p)
+{
+ tree block, clauses, ret;
+
+ strcat (p_name, " loop");
+ mask |= OMP_LOOP_CLAUSE_MASK;
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_LOOP, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_LOOP];
+ }
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_LOOP, clauses, cclauses, if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
+/* OpenMP 4.0:
+ #pragma omp simd simd-clause[optseq] new-line
+ for-loop
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OMP_SIMD_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SAFELEN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NONTEMPORAL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER))
+
+static tree
+c_parser_omp_simd (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses,
+ bool *if_p)
+{
+ tree block, clauses, ret;
+
+ strcat (p_name, " simd");
+ mask |= OMP_SIMD_CLAUSE_MASK;
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_SIMD, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_SIMD];
+ tree c = omp_find_clause (cclauses[C_OMP_CLAUSE_SPLIT_FOR],
+ OMP_CLAUSE_ORDERED);
+ if (c && OMP_CLAUSE_ORDERED_EXPR (c))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<ordered%> clause with parameter may not be specified "
+ "on %qs construct", p_name);
+ OMP_CLAUSE_ORDERED_EXPR (c) = NULL_TREE;
+ }
+ }
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_SIMD, clauses, cclauses, if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
+/* OpenMP 2.5:
+ #pragma omp for for-clause[optseq] new-line
+ for-loop
+
+ OpenMP 4.0:
+ #pragma omp for simd for-simd-clause[optseq] new-line
+ for-loop
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OMP_FOR_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SCHEDULE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER))
+
+static tree
+c_parser_omp_for (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses,
+ bool *if_p)
+{
+ tree block, clauses, ret;
+
+ strcat (p_name, " for");
+ mask |= OMP_FOR_CLAUSE_MASK;
+ /* parallel for{, simd} disallows nowait clause, but for
+ target {teams distribute ,}parallel for{, simd} it should be accepted. */
+ if (cclauses && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) == 0)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
+ /* Composite distribute parallel for{, simd} disallows ordered clause. */
+ if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDERED);
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (strcmp (p, "simd") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_simd (loc, parser, p_name, mask, cclauses,
+ if_p);
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL_TREE)
+ return ret;
+ ret = make_node (OMP_FOR);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_FOR_BODY (ret) = block;
+ OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+ SET_EXPR_LOCATION (ret, loc);
+ add_stmt (ret);
+ return ret;
+ }
+ }
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return NULL_TREE;
+ }
+
+ /* Composite distribute parallel for disallows linear clause. */
+ if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR);
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_FOR, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_FOR];
+ }
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_FOR, clauses, cclauses, if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
+static tree c_parser_omp_taskloop (location_t, c_parser *, char *,
+ omp_clause_mask, tree *, bool *);
+
+/* 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,
+ char *p_name, omp_clause_mask mask, tree *cclauses,
+ bool *if_p)
+{
+ tree block, clauses, ret;
+
+ strcat (p_name, " master");
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (strcmp (p, "taskloop") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses,
+ if_p);
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses,
+ if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL_TREE)
+ return ret;
+ ret = c_finish_omp_master (loc, block);
+ OMP_MASTER_COMBINED (ret) = 1;
+ return ret;
+ }
+ }
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return NULL_TREE;
+ }
+
+ if (cclauses)
+ {
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, false);
+ omp_split_clauses (loc, OMP_MASTER, mask, clauses, cclauses);
+ }
+ else
+ c_parser_skip_to_pragma_eol (parser);
+
+ return c_finish_omp_master (loc, c_parser_omp_structured_block (parser,
+ if_p));
+}
+
+/* OpenMP 5.1:
+ # pragma omp masked masked-clauses new-line
+ structured-block
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OMP_MASKED_CLAUSE_MASK \
+ (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FILTER)
+
+static tree
+c_parser_omp_masked (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses,
+ bool *if_p)
+{
+ tree block, clauses, ret;
+
+ strcat (p_name, " masked");
+ mask |= OMP_MASKED_CLAUSE_MASK;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (strcmp (p, "taskloop") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses,
+ if_p);
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_taskloop (loc, parser, p_name, mask, cclauses,
+ if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL_TREE)
+ return ret;
+ ret = c_finish_omp_masked (loc, block,
+ cclauses[C_OMP_CLAUSE_SPLIT_MASKED]);
+ OMP_MASKED_COMBINED (ret) = 1;
+ return ret;
+ }
+ }
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return NULL_TREE;
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_MASKED, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_MASKED];
+ }
+
+ return c_finish_omp_masked (loc, c_parser_omp_structured_block (parser,
+ if_p),
+ clauses);
+}
+
+/* OpenMP 2.5:
+ # pragma omp ordered new-line
+ structured-block
+
+ OpenMP 4.5:
+ # pragma omp ordered ordered-clauses new-line
+ structured-block
+
+ # pragma omp ordered depend-clauses new-line */
+
+#define OMP_ORDERED_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREADS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMD))
+
+#define OMP_ORDERED_DEPEND_CLAUSE_MASK \
+ (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)
+
+static bool
+c_parser_omp_ordered (c_parser *parser, enum pragma_context context,
+ bool *if_p)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+
+ if (context != pragma_stmt && context != pragma_compound)
+ {
+ c_parser_error (parser, "expected declaration specifiers");
+ c_parser_skip_to_pragma_eol (parser, false);
+ return false;
+ }
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (!strcmp ("depend", p))
+ {
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return false;
+ }
+ if (context == pragma_stmt)
+ {
+ error_at (loc,
+ "%<#pragma omp ordered%> with %<depend%> clause may "
+ "only be used in compound statements");
+ c_parser_skip_to_pragma_eol (parser, false);
+ return true;
+ }
+
+ tree clauses
+ = c_parser_omp_all_clauses (parser,
+ OMP_ORDERED_DEPEND_CLAUSE_MASK,
+ "#pragma omp ordered");
+ c_finish_omp_ordered (loc, clauses, NULL_TREE);
+ return false;
+ }
+ }
+
+ tree clauses = c_parser_omp_all_clauses (parser, OMP_ORDERED_CLAUSE_MASK,
+ "#pragma omp ordered");
+
+ if (!flag_openmp /* flag_openmp_simd */
+ && omp_find_clause (clauses, OMP_CLAUSE_SIMD) == NULL_TREE)
+ return false;
+
+ c_finish_omp_ordered (loc, clauses,
+ c_parser_omp_structured_block (parser, if_p));
+ return true;
+}
+
+/* OpenMP 2.5:
+
+ section-scope:
+ { section-sequence }
+
+ section-sequence:
+ section-directive[opt] structured-block
+ section-sequence section-directive structured-block
+
+ OpenMP 5.1 allows structured-block-sequence instead of 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 = c_parser_omp_structured_block_sequence (parser,
+ PRAGMA_OMP_SECTION);
+ 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_sequence (parser,
+ PRAGMA_OMP_SECTION);
+ 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 \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_sections (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses)
+{
+ tree block, clauses, ret;
+
+ strcat (p_name, " sections");
+ mask |= OMP_SECTIONS_CLAUSE_MASK;
+ if (cclauses)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT);
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_SECTIONS, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_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 omp parallel parallel-clause[optseq] new-line
+ structured-block
+ # pragma omp parallel for parallel-for-clause[optseq] new-line
+ structured-block
+ # pragma omp parallel sections parallel-sections-clause[optseq] new-line
+ structured-block
+
+ OpenMP 4.0:
+ # pragma omp parallel for simd parallel-for-simd-clause[optseq] new-line
+ structured-block
+
+ LOC is the location of the #pragma token.
+*/
+
+#define OMP_PARALLEL_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PROC_BIND))
+
+static tree
+c_parser_omp_parallel (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses,
+ bool *if_p)
+{
+ tree stmt, clauses, block;
+
+ strcat (p_name, " parallel");
+ mask |= OMP_PARALLEL_CLAUSE_MASK;
+ /* #pragma omp target parallel{, for, for simd} disallow copyin clause. */
+ if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)) != 0
+ && (mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) == 0)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYIN);
+
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_for (loc, parser, p_name, mask, cclauses, if_p);
+ block = c_begin_omp_parallel ();
+ tree ret = c_parser_omp_for (loc, parser, p_name, mask, cclauses, if_p);
+ stmt
+ = c_finish_omp_parallel (loc, cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ if (ret == NULL_TREE)
+ return ret;
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
+ }
+ /* When combined with distribute, parallel has to be followed by for.
+ #pragma omp target parallel is allowed though. */
+ else if (cclauses
+ && (mask & (OMP_CLAUSE_MASK_1
+ << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)) != 0)
+ {
+ error_at (loc, "expected %<for%> after %qs", p_name);
+ c_parser_skip_to_pragma_eol (parser);
+ return NULL_TREE;
+ }
+ else if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (cclauses == NULL && strcmp (p, "masked") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_masked (loc, parser, p_name, mask, cclauses,
+ if_p);
+ block = c_begin_omp_parallel ();
+ tree ret = c_parser_omp_masked (loc, parser, p_name, mask, cclauses,
+ if_p);
+ stmt = c_finish_omp_parallel (loc,
+ cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ if (ret == NULL)
+ return ret;
+ /* masked does have just filter clause, but during gimplification
+ isn't represented by a gimplification omp context, so for
+ #pragma omp parallel masked don't set OMP_PARALLEL_COMBINED,
+ so that
+ #pragma omp parallel masked
+ #pragma omp taskloop simd lastprivate (x)
+ isn't confused with
+ #pragma omp parallel masked taskloop simd lastprivate (x) */
+ if (OMP_MASKED_COMBINED (ret))
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
+ }
+ else if (cclauses == NULL && strcmp (p, "master") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_master (loc, parser, p_name, mask, cclauses,
+ if_p);
+ block = c_begin_omp_parallel ();
+ tree ret = c_parser_omp_master (loc, parser, p_name, mask, cclauses,
+ if_p);
+ stmt = c_finish_omp_parallel (loc,
+ cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ if (ret == NULL)
+ return ret;
+ /* master doesn't have any clauses and during gimplification
+ isn't represented by a gimplification omp context, so for
+ #pragma omp parallel master don't set OMP_PARALLEL_COMBINED,
+ so that
+ #pragma omp parallel master
+ #pragma omp taskloop simd lastprivate (x)
+ isn't confused with
+ #pragma omp parallel master taskloop simd lastprivate (x) */
+ if (OMP_MASTER_COMBINED (ret))
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
+ }
+ else if (strcmp (p, "loop") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_loop (loc, parser, p_name, mask, cclauses,
+ if_p);
+ block = c_begin_omp_parallel ();
+ tree ret = c_parser_omp_loop (loc, parser, p_name, mask, cclauses,
+ if_p);
+ stmt
+ = c_finish_omp_parallel (loc,
+ cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ if (ret == NULL_TREE)
+ return ret;
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
+ }
+ else if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return NULL_TREE;
+ }
+ else if (cclauses == NULL && strcmp (p, "sections") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ block = c_begin_omp_parallel ();
+ c_parser_omp_sections (loc, parser, p_name, mask, cclauses);
+ stmt = c_finish_omp_parallel (loc,
+ cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL],
+ block);
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
+ }
+ }
+ else if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return NULL_TREE;
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_PARALLEL, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL];
+ }
+
+ block = c_begin_omp_parallel ();
+ c_parser_statement (parser, if_p);
+ stmt = c_finish_omp_parallel (loc, clauses, block);
+
+ 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 \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COPYPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_single (location_t loc, c_parser *parser, bool *if_p)
+{
+ 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, if_p);
+
+ return add_stmt (stmt);
+}
+
+/* OpenMP 5.1:
+ # pragma omp scope scope-clause[optseq] new-line
+ structured-block
+
+ LOC is the location of the #pragma.
+*/
+
+#define OMP_SCOPE_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static tree
+c_parser_omp_scope (location_t loc, c_parser *parser, bool *if_p)
+{
+ tree stmt = make_node (OMP_SCOPE);
+ SET_EXPR_LOCATION (stmt, loc);
+ TREE_TYPE (stmt) = void_type_node;
+
+ OMP_SCOPE_CLAUSES (stmt)
+ = c_parser_omp_all_clauses (parser, OMP_SCOPE_CLAUSE_MASK,
+ "#pragma omp scope");
+ OMP_SCOPE_BODY (stmt) = c_parser_omp_structured_block (parser, if_p);
+
+ 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 \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DETACH) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_AFFINITY))
+
+static tree
+c_parser_omp_task (location_t loc, c_parser *parser, bool *if_p)
+{
+ 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, if_p);
+ return c_finish_omp_task (loc, clauses, block);
+}
+
+/* OpenMP 3.0:
+ # pragma omp taskwait new-line
+
+ OpenMP 5.0:
+ # pragma omp taskwait taskwait-clause[optseq] new-line
+*/
+
+#define OMP_TASKWAIT_CLAUSE_MASK \
+ (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND)
+
+static void
+c_parser_omp_taskwait (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+
+ tree clauses
+ = c_parser_omp_all_clauses (parser, OMP_TASKWAIT_CLAUSE_MASK,
+ "#pragma omp taskwait");
+
+ if (clauses)
+ {
+ tree stmt = make_node (OMP_TASK);
+ TREE_TYPE (stmt) = void_node;
+ OMP_TASK_CLAUSES (stmt) = clauses;
+ OMP_TASK_BODY (stmt) = NULL_TREE;
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+ }
+ else
+ 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);
+}
+
+/* OpenMP 4.0:
+ # pragma omp taskgroup new-line
+
+ OpenMP 5.0:
+ # pragma omp taskgroup taskgroup-clause[optseq] new-line
+*/
+
+#define OMP_TASKGROUP_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASK_REDUCTION))
+
+static tree
+c_parser_omp_taskgroup (location_t loc, c_parser *parser, bool *if_p)
+{
+ tree clauses = c_parser_omp_all_clauses (parser, OMP_TASKGROUP_CLAUSE_MASK,
+ "#pragma omp taskgroup");
+
+ tree body = c_parser_omp_structured_block (parser, if_p);
+ return c_finish_omp_taskgroup (loc, body, clauses);
+}
+
+/* OpenMP 4.0:
+ # pragma omp cancel cancel-clause[optseq] new-line
+
+ LOC is the location of the #pragma.
+*/
+
+#define OMP_CANCEL_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF))
+
+static void
+c_parser_omp_cancel (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ c_parser_consume_pragma (parser);
+ tree clauses = c_parser_omp_all_clauses (parser, OMP_CANCEL_CLAUSE_MASK,
+ "#pragma omp cancel");
+
+ c_finish_omp_cancel (loc, clauses);
+}
+
+/* OpenMP 4.0:
+ # pragma omp cancellation point cancelpt-clause[optseq] new-line
+
+ LOC is the location of the #pragma.
+*/
+
+#define OMP_CANCELLATION_POINT_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARALLEL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FOR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SECTIONS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TASKGROUP))
+
+static bool
+c_parser_omp_cancellation_point (c_parser *parser, enum pragma_context context)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree clauses;
+ bool point_seen = false;
+
+ c_parser_consume_pragma (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "point") == 0)
+ {
+ c_parser_consume_token (parser);
+ point_seen = true;
+ }
+ }
+ if (!point_seen)
+ {
+ c_parser_error (parser, "expected %<point%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return false;
+ }
+
+ if (context != pragma_compound)
+ {
+ if (context == pragma_stmt)
+ error_at (loc,
+ "%<#pragma %s%> may only be used in compound statements",
+ "omp cancellation point");
+ else
+ c_parser_error (parser, "expected declaration specifiers");
+ c_parser_skip_to_pragma_eol (parser, false);
+ return true;
+ }
+
+ clauses
+ = c_parser_omp_all_clauses (parser, OMP_CANCELLATION_POINT_CLAUSE_MASK,
+ "#pragma omp cancellation point");
+
+ c_finish_omp_cancellation_point (loc, clauses);
+ return true;
+}
+
+/* OpenMP 4.0:
+ #pragma omp distribute distribute-clause[optseq] new-line
+ for-loop */
+
+#define OMP_DISTRIBUTE_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DIST_SCHEDULE)\
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ORDER))
+
+static tree
+c_parser_omp_distribute (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses,
+ bool *if_p)
+{
+ tree clauses, block, ret;
+
+ strcat (p_name, " distribute");
+ mask |= OMP_DISTRIBUTE_CLAUSE_MASK;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ bool simd = false;
+ bool parallel = false;
+
+ if (strcmp (p, "simd") == 0)
+ simd = true;
+ else
+ parallel = strcmp (p, "parallel") == 0;
+ if (parallel || simd)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+ c_parser_consume_token (parser);
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ if (simd)
+ return c_parser_omp_simd (loc, parser, p_name, mask, cclauses,
+ if_p);
+ else
+ return c_parser_omp_parallel (loc, parser, p_name, mask,
+ cclauses, if_p);
+ }
+ block = c_begin_compound_stmt (true);
+ if (simd)
+ ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses,
+ if_p);
+ else
+ ret = c_parser_omp_parallel (loc, parser, p_name, mask, cclauses,
+ if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL)
+ return ret;
+ ret = make_node (OMP_DISTRIBUTE);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_FOR_BODY (ret) = block;
+ OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE];
+ SET_EXPR_LOCATION (ret, loc);
+ add_stmt (ret);
+ return ret;
+ }
+ }
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return NULL_TREE;
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_DISTRIBUTE, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_DISTRIBUTE];
+ }
+
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_DISTRIBUTE, clauses, NULL,
+ if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
+/* OpenMP 4.0:
+ # pragma omp teams teams-clause[optseq] new-line
+ structured-block */
+
+#define OMP_TEAMS_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TEAMS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT))
+
+static tree
+c_parser_omp_teams (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses,
+ bool *if_p)
+{
+ tree clauses, block, ret;
+
+ strcat (p_name, " teams");
+ mask |= OMP_TEAMS_CLAUSE_MASK;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "distribute") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_distribute (loc, parser, p_name, mask,
+ cclauses, if_p);
+ block = c_begin_omp_parallel ();
+ ret = c_parser_omp_distribute (loc, parser, p_name, mask, cclauses,
+ if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL)
+ return ret;
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+ ret = make_node (OMP_TEAMS);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_TEAMS_CLAUSES (ret) = clauses;
+ OMP_TEAMS_BODY (ret) = block;
+ OMP_TEAMS_COMBINED (ret) = 1;
+ SET_EXPR_LOCATION (ret, loc);
+ return add_stmt (ret);
+ }
+ else if (strcmp (p, "loop") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+
+ c_parser_consume_token (parser);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_loop (loc, parser, p_name, mask, cclauses,
+ if_p);
+ block = c_begin_omp_parallel ();
+ ret = c_parser_omp_loop (loc, parser, p_name, mask, cclauses, if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL)
+ return ret;
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+ ret = make_node (OMP_TEAMS);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_TEAMS_CLAUSES (ret) = clauses;
+ OMP_TEAMS_BODY (ret) = block;
+ OMP_TEAMS_COMBINED (ret) = 1;
+ SET_EXPR_LOCATION (ret, loc);
+ return add_stmt (ret);
+ }
+ }
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return NULL_TREE;
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_TEAMS, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+ }
+
+ tree stmt = make_node (OMP_TEAMS);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_TEAMS_CLAUSES (stmt) = clauses;
+ block = c_begin_omp_parallel ();
+ add_stmt (c_parser_omp_structured_block (parser, if_p));
+ OMP_TEAMS_BODY (stmt) = c_end_compound_stmt (loc, block, true);
+ SET_EXPR_LOCATION (stmt, loc);
+
+ return add_stmt (stmt);
+}
+
+/* OpenMP 4.0:
+ # pragma omp target data target-data-clause[optseq] new-line
+ structured-block */
+
+#define OMP_TARGET_DATA_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR))
+
+static tree
+c_parser_omp_target_data (location_t loc, c_parser *parser, bool *if_p)
+{
+ tree clauses
+ = c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
+ "#pragma omp target data");
+ c_omp_adjust_map_clauses (clauses, false);
+ int map_seen = 0;
+ for (tree *pc = &clauses; *pc;)
+ {
+ if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
+ switch (OMP_CLAUSE_MAP_KIND (*pc))
+ {
+ case GOMP_MAP_TO:
+ case GOMP_MAP_ALWAYS_TO:
+ case GOMP_MAP_FROM:
+ case GOMP_MAP_ALWAYS_FROM:
+ case GOMP_MAP_TOFROM:
+ case GOMP_MAP_ALWAYS_TOFROM:
+ case GOMP_MAP_ALLOC:
+ map_seen = 3;
+ break;
+ case GOMP_MAP_FIRSTPRIVATE_POINTER:
+ case GOMP_MAP_ALWAYS_POINTER:
+ case GOMP_MAP_ATTACH_DETACH:
+ break;
+ default:
+ map_seen |= 1;
+ error_at (OMP_CLAUSE_LOCATION (*pc),
+ "%<#pragma omp target data%> with map-type other "
+ "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
+ "on %<map%> clause");
+ *pc = OMP_CLAUSE_CHAIN (*pc);
+ continue;
+ }
+ else if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_PTR
+ || OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_USE_DEVICE_ADDR)
+ map_seen = 3;
+ pc = &OMP_CLAUSE_CHAIN (*pc);
+ }
+
+ if (map_seen != 3)
+ {
+ if (map_seen == 0)
+ error_at (loc,
+ "%<#pragma omp target data%> must contain at least "
+ "one %<map%>, %<use_device_ptr%> or %<use_device_addr%> "
+ "clause");
+ return NULL_TREE;
+ }
+
+ tree stmt = make_node (OMP_TARGET_DATA);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_TARGET_DATA_CLAUSES (stmt) = clauses;
+ keep_next_level ();
+ tree block = c_begin_compound_stmt (true);
+ add_stmt (c_parser_omp_structured_block (parser, if_p));
+ OMP_TARGET_DATA_BODY (stmt) = c_end_compound_stmt (loc, block, true);
+
+ SET_EXPR_LOCATION (stmt, loc);
+ return add_stmt (stmt);
+}
+
+/* OpenMP 4.0:
+ # pragma omp target update target-update-clause[optseq] new-line */
+
+#define OMP_TARGET_UPDATE_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FROM) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static bool
+c_parser_omp_target_update (location_t loc, c_parser *parser,
+ enum pragma_context context)
+{
+ if (context == pragma_stmt)
+ {
+ error_at (loc, "%<#pragma %s%> may only be used in compound statements",
+ "omp target update");
+ c_parser_skip_to_pragma_eol (parser, false);
+ return true;
+ }
+
+ tree clauses
+ = c_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK,
+ "#pragma omp target update");
+ if (omp_find_clause (clauses, OMP_CLAUSE_TO) == NULL_TREE
+ && omp_find_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE)
+ {
+ error_at (loc,
+ "%<#pragma omp target update%> must contain at least one "
+ "%<from%> or %<to%> clauses");
+ return false;
+ }
+
+ tree stmt = make_node (OMP_TARGET_UPDATE);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_TARGET_UPDATE_CLAUSES (stmt) = clauses;
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+ return false;
+}
+
+/* OpenMP 4.5:
+ # pragma omp target enter data target-data-clause[optseq] new-line */
+
+#define OMP_TARGET_ENTER_DATA_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static bool
+c_parser_omp_target_enter_data (location_t loc, c_parser *parser,
+ enum pragma_context context)
+{
+ bool data_seen = false;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "data") == 0)
+ {
+ c_parser_consume_token (parser);
+ data_seen = true;
+ }
+ }
+ if (!data_seen)
+ {
+ c_parser_error (parser, "expected %<data%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return false;
+ }
+
+ if (context == pragma_stmt)
+ {
+ error_at (loc, "%<#pragma %s%> may only be used in compound statements",
+ "omp target enter data");
+ c_parser_skip_to_pragma_eol (parser, false);
+ return true;
+ }
+
+ tree clauses
+ = c_parser_omp_all_clauses (parser, OMP_TARGET_ENTER_DATA_CLAUSE_MASK,
+ "#pragma omp target enter data");
+ c_omp_adjust_map_clauses (clauses, false);
+ int map_seen = 0;
+ for (tree *pc = &clauses; *pc;)
+ {
+ if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
+ switch (OMP_CLAUSE_MAP_KIND (*pc))
+ {
+ case GOMP_MAP_TO:
+ case GOMP_MAP_ALWAYS_TO:
+ case GOMP_MAP_ALLOC:
+ map_seen = 3;
+ break;
+ case GOMP_MAP_FIRSTPRIVATE_POINTER:
+ case GOMP_MAP_ALWAYS_POINTER:
+ case GOMP_MAP_ATTACH_DETACH:
+ break;
+ default:
+ map_seen |= 1;
+ error_at (OMP_CLAUSE_LOCATION (*pc),
+ "%<#pragma omp target enter data%> with map-type other "
+ "than %<to%> or %<alloc%> on %<map%> clause");
+ *pc = OMP_CLAUSE_CHAIN (*pc);
+ continue;
+ }
+ pc = &OMP_CLAUSE_CHAIN (*pc);
+ }
+
+ if (map_seen != 3)
+ {
+ if (map_seen == 0)
+ error_at (loc,
+ "%<#pragma omp target enter data%> must contain at least "
+ "one %<map%> clause");
+ return true;
+ }
+
+ tree stmt = make_node (OMP_TARGET_ENTER_DATA);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_TARGET_ENTER_DATA_CLAUSES (stmt) = clauses;
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+ return true;
+}
+
+/* OpenMP 4.5:
+ # pragma omp target exit data target-data-clause[optseq] new-line */
+
+#define OMP_TARGET_EXIT_DATA_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT))
+
+static bool
+c_parser_omp_target_exit_data (location_t loc, c_parser *parser,
+ enum pragma_context context)
+{
+ bool data_seen = false;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "data") == 0)
+ {
+ c_parser_consume_token (parser);
+ data_seen = true;
+ }
+ }
+ if (!data_seen)
+ {
+ c_parser_error (parser, "expected %<data%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return false;
+ }
+
+ if (context == pragma_stmt)
+ {
+ error_at (loc, "%<#pragma %s%> may only be used in compound statements",
+ "omp target exit data");
+ c_parser_skip_to_pragma_eol (parser, false);
+ return true;
+ }
+
+ tree clauses
+ = c_parser_omp_all_clauses (parser, OMP_TARGET_EXIT_DATA_CLAUSE_MASK,
+ "#pragma omp target exit data");
+ c_omp_adjust_map_clauses (clauses, false);
+ int map_seen = 0;
+ for (tree *pc = &clauses; *pc;)
+ {
+ if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
+ switch (OMP_CLAUSE_MAP_KIND (*pc))
+ {
+ case GOMP_MAP_FROM:
+ case GOMP_MAP_ALWAYS_FROM:
+ case GOMP_MAP_RELEASE:
+ case GOMP_MAP_DELETE:
+ map_seen = 3;
+ break;
+ case GOMP_MAP_FIRSTPRIVATE_POINTER:
+ case GOMP_MAP_ALWAYS_POINTER:
+ case GOMP_MAP_ATTACH_DETACH:
+ break;
+ default:
+ map_seen |= 1;
+ error_at (OMP_CLAUSE_LOCATION (*pc),
+ "%<#pragma omp target exit data%> with map-type other "
+ "than %<from%>, %<release%> or %<delete%> on %<map%>"
+ " clause");
+ *pc = OMP_CLAUSE_CHAIN (*pc);
+ continue;
+ }
+ pc = &OMP_CLAUSE_CHAIN (*pc);
+ }
+
+ if (map_seen != 3)
+ {
+ if (map_seen == 0)
+ error_at (loc,
+ "%<#pragma omp target exit data%> must contain at least one "
+ "%<map%> clause");
+ return true;
+ }
+
+ tree stmt = make_node (OMP_TARGET_EXIT_DATA);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_TARGET_EXIT_DATA_CLAUSES (stmt) = clauses;
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+ return true;
+}
+
+/* OpenMP 4.0:
+ # pragma omp target target-clause[optseq] new-line
+ structured-block */
+
+#define OMP_TARGET_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULTMAP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR))
+
+static bool
+c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ tree *pc = NULL, stmt, block;
+
+ if (context != pragma_stmt && context != pragma_compound)
+ {
+ c_parser_error (parser, "expected declaration specifiers");
+ c_parser_skip_to_pragma_eol (parser);
+ return false;
+ }
+
+ if (flag_openmp)
+ omp_requires_mask
+ = (enum omp_requires) (omp_requires_mask | OMP_REQUIRES_TARGET_USED);
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ enum tree_code ccode = ERROR_MARK;
+
+ if (strcmp (p, "teams") == 0)
+ ccode = OMP_TEAMS;
+ else if (strcmp (p, "parallel") == 0)
+ ccode = OMP_PARALLEL;
+ else if (strcmp (p, "simd") == 0)
+ ccode = OMP_SIMD;
+ if (ccode != ERROR_MARK)
+ {
+ tree cclauses[C_OMP_CLAUSE_SPLIT_COUNT];
+ char p_name[sizeof ("#pragma omp target teams distribute "
+ "parallel for simd")];
+
+ c_parser_consume_token (parser);
+ strcpy (p_name, "#pragma omp target");
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ tree stmt;
+ switch (ccode)
+ {
+ case OMP_TEAMS:
+ stmt = c_parser_omp_teams (loc, parser, p_name,
+ OMP_TARGET_CLAUSE_MASK,
+ cclauses, if_p);
+ break;
+ case OMP_PARALLEL:
+ stmt = c_parser_omp_parallel (loc, parser, p_name,
+ OMP_TARGET_CLAUSE_MASK,
+ cclauses, if_p);
+ break;
+ case OMP_SIMD:
+ stmt = c_parser_omp_simd (loc, parser, p_name,
+ OMP_TARGET_CLAUSE_MASK,
+ cclauses, if_p);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ return stmt != NULL_TREE;
+ }
+ keep_next_level ();
+ tree block = c_begin_compound_stmt (true), ret;
+ switch (ccode)
+ {
+ case OMP_TEAMS:
+ ret = c_parser_omp_teams (loc, parser, p_name,
+ OMP_TARGET_CLAUSE_MASK, cclauses,
+ if_p);
+ break;
+ case OMP_PARALLEL:
+ ret = c_parser_omp_parallel (loc, parser, p_name,
+ OMP_TARGET_CLAUSE_MASK, cclauses,
+ if_p);
+ break;
+ case OMP_SIMD:
+ ret = c_parser_omp_simd (loc, parser, p_name,
+ OMP_TARGET_CLAUSE_MASK, cclauses,
+ if_p);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL_TREE)
+ return false;
+ if (ccode == OMP_TEAMS)
+ /* For combined target teams, ensure the num_teams and
+ thread_limit clause expressions are evaluated on the host,
+ before entering the target construct. */
+ for (tree c = cclauses[C_OMP_CLAUSE_SPLIT_TEAMS];
+ c; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS
+ || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_THREAD_LIMIT)
+ for (int i = 0;
+ i <= (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_NUM_TEAMS); ++i)
+ if (OMP_CLAUSE_OPERAND (c, i)
+ && TREE_CODE (OMP_CLAUSE_OPERAND (c, i)) != INTEGER_CST)
+ {
+ tree expr = OMP_CLAUSE_OPERAND (c, i);
+ tree tmp = create_tmp_var_raw (TREE_TYPE (expr));
+ expr = build4 (TARGET_EXPR, TREE_TYPE (expr), tmp,
+ expr, NULL_TREE, NULL_TREE);
+ add_stmt (expr);
+ OMP_CLAUSE_OPERAND (c, i) = expr;
+ tree tc = build_omp_clause (OMP_CLAUSE_LOCATION (c),
+ OMP_CLAUSE_FIRSTPRIVATE);
+ OMP_CLAUSE_DECL (tc) = tmp;
+ OMP_CLAUSE_CHAIN (tc)
+ = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
+ cclauses[C_OMP_CLAUSE_SPLIT_TARGET] = tc;
+ }
+ tree stmt = make_node (OMP_TARGET);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_TARGET_CLAUSES (stmt) = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
+ c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true);
+ OMP_TARGET_BODY (stmt) = block;
+ OMP_TARGET_COMBINED (stmt) = 1;
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+ pc = &OMP_TARGET_CLAUSES (stmt);
+ goto check_clauses;
+ }
+ else if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return false;
+ }
+ else if (strcmp (p, "data") == 0)
+ {
+ c_parser_consume_token (parser);
+ c_parser_omp_target_data (loc, parser, if_p);
+ return true;
+ }
+ else if (strcmp (p, "enter") == 0)
+ {
+ c_parser_consume_token (parser);
+ return c_parser_omp_target_enter_data (loc, parser, context);
+ }
+ else if (strcmp (p, "exit") == 0)
+ {
+ c_parser_consume_token (parser);
+ return c_parser_omp_target_exit_data (loc, parser, context);
+ }
+ else if (strcmp (p, "update") == 0)
+ {
+ c_parser_consume_token (parser);
+ return c_parser_omp_target_update (loc, parser, context);
+ }
+ }
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return false;
+ }
+
+ stmt = make_node (OMP_TARGET);
+ TREE_TYPE (stmt) = void_type_node;
+
+ OMP_TARGET_CLAUSES (stmt)
+ = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
+ "#pragma omp target", false);
+ for (tree c = OMP_TARGET_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION)
+ {
+ tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
+ OMP_CLAUSE_DECL (nc) = OMP_CLAUSE_DECL (c);
+ OMP_CLAUSE_SET_MAP_KIND (nc, GOMP_MAP_ALWAYS_TOFROM);
+ OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c);
+ OMP_CLAUSE_CHAIN (c) = nc;
+ }
+ OMP_TARGET_CLAUSES (stmt)
+ = c_finish_omp_clauses (OMP_TARGET_CLAUSES (stmt), C_ORT_OMP_TARGET);
+ c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true);
+
+ pc = &OMP_TARGET_CLAUSES (stmt);
+ keep_next_level ();
+ block = c_begin_compound_stmt (true);
+ add_stmt (c_parser_omp_structured_block (parser, if_p));
+ OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true);
+
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+
+check_clauses:
+ while (*pc)
+ {
+ if (OMP_CLAUSE_CODE (*pc) == OMP_CLAUSE_MAP)
+ switch (OMP_CLAUSE_MAP_KIND (*pc))
+ {
+ case GOMP_MAP_TO:
+ case GOMP_MAP_ALWAYS_TO:
+ case GOMP_MAP_FROM:
+ case GOMP_MAP_ALWAYS_FROM:
+ case GOMP_MAP_TOFROM:
+ case GOMP_MAP_ALWAYS_TOFROM:
+ case GOMP_MAP_ALLOC:
+ case GOMP_MAP_FIRSTPRIVATE_POINTER:
+ case GOMP_MAP_ALWAYS_POINTER:
+ case GOMP_MAP_ATTACH_DETACH:
+ break;
+ default:
+ error_at (OMP_CLAUSE_LOCATION (*pc),
+ "%<#pragma omp target%> with map-type other "
+ "than %<to%>, %<from%>, %<tofrom%> or %<alloc%> "
+ "on %<map%> clause");
+ *pc = OMP_CLAUSE_CHAIN (*pc);
+ continue;
+ }
+ pc = &OMP_CLAUSE_CHAIN (*pc);
+ }
+ cfun->has_omp_target = true;
+ return true;
+}
+
+/* OpenMP 4.0:
+ # pragma omp declare simd declare-simd-clauses[optseq] new-line
+
+ OpenMP 5.0:
+ # pragma omp declare variant (identifier) match(context-selector) new-line
+ */
+
+#define OMP_DECLARE_SIMD_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SIMDLEN) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINEAR) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALIGNED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INBRANCH) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOTINBRANCH))
+
+static void
+c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
+{
+ c_token *token = c_parser_peek_token (parser);
+ gcc_assert (token->type == CPP_NAME);
+ tree kind = token->value;
+ gcc_assert (strcmp (IDENTIFIER_POINTER (kind), "simd") == 0
+ || strcmp (IDENTIFIER_POINTER (kind), "variant") == 0);
+
+ auto_vec<c_token> clauses;
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+ clauses.safe_push (*token);
+ c_parser_consume_token (parser);
+ }
+ clauses.safe_push (*c_parser_peek_token (parser));
+ c_parser_skip_to_pragma_eol (parser);
+
+ while (c_parser_next_token_is (parser, CPP_PRAGMA))
+ {
+ if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_DECLARE
+ || c_parser_peek_2nd_token (parser)->type != CPP_NAME
+ || c_parser_peek_2nd_token (parser)->value != kind)
+ {
+ error ("%<#pragma omp declare %s%> must be followed by "
+ "function declaration or definition or another "
+ "%<#pragma omp declare %s%>",
+ IDENTIFIER_POINTER (kind), IDENTIFIER_POINTER (kind));
+ return;
+ }
+ c_parser_consume_pragma (parser);
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+ clauses.safe_push (*token);
+ c_parser_consume_token (parser);
+ }
+ clauses.safe_push (*c_parser_peek_token (parser));
+ c_parser_skip_to_pragma_eol (parser);
+ }
+
+ /* Make sure nothing tries to read past the end of the tokens. */
+ c_token eof_token;
+ memset (&eof_token, 0, sizeof (eof_token));
+ eof_token.type = CPP_EOF;
+ clauses.safe_push (eof_token);
+ clauses.safe_push (eof_token);
+
+ switch (context)
+ {
+ case pragma_external:
+ if (c_parser_next_token_is (parser, CPP_KEYWORD)
+ && c_parser_peek_token (parser)->keyword == RID_EXTENSION)
+ {
+ int ext = disable_extension_diagnostics ();
+ do
+ c_parser_consume_token (parser);
+ while (c_parser_next_token_is (parser, CPP_KEYWORD)
+ && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
+ c_parser_declaration_or_fndef (parser, true, true, true, false, true,
+ NULL, &clauses);
+ restore_extension_diagnostics (ext);
+ }
+ else
+ c_parser_declaration_or_fndef (parser, true, true, true, false, true,
+ NULL, &clauses);
+ break;
+ case pragma_struct:
+ case pragma_param:
+ case pragma_stmt:
+ error ("%<#pragma omp declare %s%> must be followed by "
+ "function declaration or definition",
+ IDENTIFIER_POINTER (kind));
+ break;
+ case pragma_compound:
+ if (c_parser_next_token_is (parser, CPP_KEYWORD)
+ && c_parser_peek_token (parser)->keyword == RID_EXTENSION)
+ {
+ int ext = disable_extension_diagnostics ();
+ do
+ c_parser_consume_token (parser);
+ while (c_parser_next_token_is (parser, CPP_KEYWORD)
+ && c_parser_peek_token (parser)->keyword == RID_EXTENSION);
+ if (c_parser_next_tokens_start_declaration (parser))
+ {
+ c_parser_declaration_or_fndef (parser, true, true, true, true,
+ true, NULL, &clauses);
+ restore_extension_diagnostics (ext);
+ break;
+ }
+ restore_extension_diagnostics (ext);
+ }
+ else if (c_parser_next_tokens_start_declaration (parser))
+ {
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true,
+ NULL, &clauses);
+ break;
+ }
+ error ("%<#pragma omp declare %s%> must be followed by "
+ "function declaration or definition",
+ IDENTIFIER_POINTER (kind));
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+static const char *const omp_construct_selectors[] = {
+ "simd", "target", "teams", "parallel", "for", NULL };
+static const char *const omp_device_selectors[] = {
+ "kind", "isa", "arch", NULL };
+static const char *const omp_implementation_selectors[] = {
+ "vendor", "extension", "atomic_default_mem_order", "unified_address",
+ "unified_shared_memory", "dynamic_allocators", "reverse_offload", NULL };
+static const char *const omp_user_selectors[] = {
+ "condition", NULL };
+
+/* OpenMP 5.0:
+
+ trait-selector:
+ trait-selector-name[([trait-score:]trait-property[,trait-property[,...]])]
+
+ trait-score:
+ score(score-expression) */
+
+static tree
+c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
+{
+ tree ret = NULL_TREE;
+ do
+ {
+ tree selector;
+ if (c_parser_next_token_is (parser, CPP_KEYWORD)
+ || c_parser_next_token_is (parser, CPP_NAME))
+ selector = c_parser_peek_token (parser)->value;
+ else
+ {
+ c_parser_error (parser, "expected trait selector name");
+ return error_mark_node;
+ }
+
+ tree properties = NULL_TREE;
+ const char *const *selectors = NULL;
+ bool allow_score = true;
+ bool allow_user = false;
+ int property_limit = 0;
+ enum { CTX_PROPERTY_NONE, CTX_PROPERTY_USER, CTX_PROPERTY_NAME_LIST,
+ CTX_PROPERTY_ID, CTX_PROPERTY_EXPR,
+ CTX_PROPERTY_SIMD } property_kind = CTX_PROPERTY_NONE;
+ switch (IDENTIFIER_POINTER (set)[0])
+ {
+ case 'c': /* construct */
+ selectors = omp_construct_selectors;
+ allow_score = false;
+ property_limit = 1;
+ property_kind = CTX_PROPERTY_SIMD;
+ break;
+ case 'd': /* device */
+ selectors = omp_device_selectors;
+ allow_score = false;
+ allow_user = true;
+ property_limit = 3;
+ property_kind = CTX_PROPERTY_NAME_LIST;
+ break;
+ case 'i': /* implementation */
+ selectors = omp_implementation_selectors;
+ allow_user = true;
+ property_limit = 3;
+ property_kind = CTX_PROPERTY_NAME_LIST;
+ break;
+ case 'u': /* user */
+ selectors = omp_user_selectors;
+ property_limit = 1;
+ property_kind = CTX_PROPERTY_EXPR;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ for (int i = 0; ; i++)
+ {
+ if (selectors[i] == NULL)
+ {
+ if (allow_user)
+ {
+ property_kind = CTX_PROPERTY_USER;
+ break;
+ }
+ else
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "selector %qs not allowed for context selector "
+ "set %qs", IDENTIFIER_POINTER (selector),
+ IDENTIFIER_POINTER (set));
+ c_parser_consume_token (parser);
+ return error_mark_node;
+ }
+ }
+ if (i == property_limit)
+ property_kind = CTX_PROPERTY_NONE;
+ if (strcmp (selectors[i], IDENTIFIER_POINTER (selector)) == 0)
+ break;
+ }
+ if (property_kind == CTX_PROPERTY_NAME_LIST
+ && IDENTIFIER_POINTER (set)[0] == 'i'
+ && strcmp (IDENTIFIER_POINTER (selector),
+ "atomic_default_mem_order") == 0)
+ property_kind = CTX_PROPERTY_ID;
+
+ c_parser_consume_token (parser);
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ if (property_kind == CTX_PROPERTY_NONE)
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "selector %qs does not accept any properties",
+ IDENTIFIER_POINTER (selector));
+ return error_mark_node;
+ }
+
+ matching_parens parens;
+ parens.require_open (parser);
+
+ c_token *token = c_parser_peek_token (parser);
+ if (allow_score
+ && c_parser_next_token_is (parser, CPP_NAME)
+ && strcmp (IDENTIFIER_POINTER (token->value), "score") == 0
+ && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN)
+ {
+ c_parser_consume_token (parser);
+
+ matching_parens parens2;
+ parens2.require_open (parser);
+ tree score = c_parser_expr_no_commas (parser, NULL).value;
+ parens2.skip_until_found_close (parser);
+ c_parser_require (parser, CPP_COLON, "expected %<:%>");
+ if (score != error_mark_node)
+ {
+ mark_exp_read (score);
+ score = c_fully_fold (score, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (score))
+ || TREE_CODE (score) != INTEGER_CST)
+ error_at (token->location, "score argument must be "
+ "constant integer expression");
+ else if (tree_int_cst_sgn (score) < 0)
+ error_at (token->location, "score argument must be "
+ "non-negative");
+ else
+ properties = tree_cons (get_identifier (" score"),
+ score, properties);
+ }
+ token = c_parser_peek_token (parser);
+ }
+
+ switch (property_kind)
+ {
+ tree t;
+ case CTX_PROPERTY_USER:
+ do
+ {
+ t = c_parser_expr_no_commas (parser, NULL).value;
+ if (TREE_CODE (t) == STRING_CST)
+ properties = tree_cons (NULL_TREE, t, properties);
+ else if (t != error_mark_node)
+ {
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+ || !tree_fits_shwi_p (t))
+ error_at (token->location, "property must be "
+ "constant integer expression or string "
+ "literal");
+ else
+ properties = tree_cons (NULL_TREE, t, properties);
+ }
+ else
+ return error_mark_node;
+
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ while (1);
+ break;
+ case CTX_PROPERTY_ID:
+ if (c_parser_next_token_is (parser, CPP_KEYWORD)
+ || c_parser_next_token_is (parser, CPP_NAME))
+ {
+ tree prop = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ properties = tree_cons (prop, NULL_TREE, properties);
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ return error_mark_node;
+ }
+ break;
+ case CTX_PROPERTY_NAME_LIST:
+ do
+ {
+ tree prop = NULL_TREE, value = NULL_TREE;
+ if (c_parser_next_token_is (parser, CPP_KEYWORD)
+ || c_parser_next_token_is (parser, CPP_NAME))
+ {
+ prop = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ }
+ else if (c_parser_next_token_is (parser, CPP_STRING))
+ value = c_parser_string_literal (parser, false,
+ false).value;
+ else
+ {
+ c_parser_error (parser, "expected identifier or "
+ "string literal");
+ return error_mark_node;
+ }
+
+ properties = tree_cons (prop, value, properties);
+
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ while (1);
+ break;
+ case CTX_PROPERTY_EXPR:
+ t = c_parser_expr_no_commas (parser, NULL).value;
+ if (t != error_mark_node)
+ {
+ mark_exp_read (t);
+ t = c_fully_fold (t, false, NULL);
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+ || !tree_fits_shwi_p (t))
+ error_at (token->location, "property must be "
+ "constant integer expression");
+ else
+ properties = tree_cons (NULL_TREE, t, properties);
+ }
+ else
+ return error_mark_node;
+ break;
+ case CTX_PROPERTY_SIMD:
+ if (parms == NULL_TREE)
+ {
+ error_at (token->location, "properties for %<simd%> "
+ "selector may not be specified in "
+ "%<metadirective%>");
+ return error_mark_node;
+ }
+ tree c;
+ c = c_parser_omp_all_clauses (parser,
+ OMP_DECLARE_SIMD_CLAUSE_MASK,
+ "simd", true, 2);
+ c = c_omp_declare_simd_clauses_to_numbers (parms
+ == error_mark_node
+ ? NULL_TREE : parms,
+ c);
+ properties = c;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ parens.skip_until_found_close (parser);
+ properties = nreverse (properties);
+ }
+ else if (property_kind == CTX_PROPERTY_NAME_LIST
+ || property_kind == CTX_PROPERTY_ID
+ || property_kind == CTX_PROPERTY_EXPR)
+ {
+ c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>");
+ return error_mark_node;
+ }
+
+ ret = tree_cons (selector, properties, ret);
+
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ while (1);
+
+ return nreverse (ret);
+}
+
+/* OpenMP 5.0:
+
+ trait-set-selector[,trait-set-selector[,...]]
+
+ trait-set-selector:
+ trait-set-selector-name = { trait-selector[, trait-selector[, ...]] }
+
+ trait-set-selector-name:
+ constructor
+ device
+ implementation
+ user */
+
+static tree
+c_parser_omp_context_selector_specification (c_parser *parser, tree parms)
+{
+ tree ret = NULL_TREE;
+ do
+ {
+ const char *setp = "";
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ setp = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ switch (setp[0])
+ {
+ case 'c':
+ if (strcmp (setp, "construct") == 0)
+ setp = NULL;
+ break;
+ case 'd':
+ if (strcmp (setp, "device") == 0)
+ setp = NULL;
+ break;
+ case 'i':
+ if (strcmp (setp, "implementation") == 0)
+ setp = NULL;
+ break;
+ case 'u':
+ if (strcmp (setp, "user") == 0)
+ setp = NULL;
+ break;
+ default:
+ break;
+ }
+ if (setp)
+ {
+ c_parser_error (parser, "expected %<construct%>, %<device%>, "
+ "%<implementation%> or %<user%>");
+ return error_mark_node;
+ }
+
+ tree set = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ return error_mark_node;
+
+ matching_braces braces;
+ if (!braces.require_open (parser))
+ return error_mark_node;
+
+ tree selectors = c_parser_omp_context_selector (parser, set, parms);
+ if (selectors == error_mark_node)
+ ret = error_mark_node;
+ else if (ret != error_mark_node)
+ ret = tree_cons (set, selectors, ret);
+
+ braces.skip_until_found_close (parser);
+
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ while (1);
+
+ if (ret == error_mark_node)
+ return ret;
+ return nreverse (ret);
+}
+
+/* Finalize #pragma omp declare variant after FNDECL has been parsed, and put
+ that into "omp declare variant base" attribute. */
+
+static void
+c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
+{
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ {
+ fail:
+ c_parser_skip_to_pragma_eol (parser, false);
+ return;
+ }
+
+ 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");
+ goto fail;
+ }
+
+ c_token *token = c_parser_peek_token (parser);
+ tree variant = lookup_name (token->value);
+
+ if (variant == NULL_TREE)
+ {
+ undeclared_variable (token->location, token->value);
+ variant = error_mark_node;
+ }
+
+ c_parser_consume_token (parser);
+
+ parens.require_close (parser);
+
+ const char *clause = "";
+ location_t match_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ clause = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (clause, "match"))
+ {
+ c_parser_error (parser, "expected %<match%>");
+ goto fail;
+ }
+
+ c_parser_consume_token (parser);
+
+ if (!parens.require_open (parser))
+ goto fail;
+
+ if (parms == NULL_TREE)
+ parms = error_mark_node;
+
+ tree ctx = c_parser_omp_context_selector_specification (parser, parms);
+ if (ctx == error_mark_node)
+ goto fail;
+ ctx = omp_check_context_selector (match_loc, ctx);
+ if (ctx != error_mark_node && variant != error_mark_node)
+ {
+ if (TREE_CODE (variant) != FUNCTION_DECL)
+ {
+ error_at (token->location, "variant %qD is not a function", variant);
+ variant = error_mark_node;
+ }
+ else if (omp_get_context_selector (ctx, "construct", "simd") == NULL_TREE
+ && !comptypes (TREE_TYPE (fndecl), TREE_TYPE (variant)))
+ {
+ error_at (token->location, "variant %qD and base %qD have "
+ "incompatible types", variant, fndecl);
+ variant = error_mark_node;
+ }
+ else if (fndecl_built_in_p (variant)
+ && (strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)),
+ "__builtin_", strlen ("__builtin_")) == 0
+ || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)),
+ "__sync_", strlen ("__sync_")) == 0
+ || strncmp (IDENTIFIER_POINTER (DECL_NAME (variant)),
+ "__atomic_", strlen ("__atomic_")) == 0))
+ {
+ error_at (token->location, "variant %qD is a built-in", variant);
+ variant = error_mark_node;
+ }
+ if (variant != error_mark_node)
+ {
+ C_DECL_USED (variant) = 1;
+ tree construct = omp_get_context_selector (ctx, "construct", NULL);
+ omp_mark_declare_variant (match_loc, variant, construct);
+ if (omp_context_selector_matches (ctx))
+ {
+ tree attr
+ = tree_cons (get_identifier ("omp declare variant base"),
+ build_tree_list (variant, ctx),
+ DECL_ATTRIBUTES (fndecl));
+ DECL_ATTRIBUTES (fndecl) = attr;
+ }
+ }
+ }
+
+ parens.require_close (parser);
+ c_parser_skip_to_pragma_eol (parser);
+}
+
+/* Finalize #pragma omp declare simd or #pragma omp declare variant
+ clauses after FNDECL has been parsed, and put that into "omp declare simd"
+ or "omp declare variant base" attribute. */
+
+static void
+c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
+ vec<c_token> *pclauses)
+{
+ vec<c_token> &clauses = *pclauses;
+
+ /* Normally first token is CPP_NAME "simd" or "variant". CPP_EOF there
+ indicates error has been reported and CPP_PRAGMA that
+ c_finish_omp_declare_simd has already processed the tokens. */
+ if (clauses.exists () && clauses[0].type == CPP_EOF)
+ return;
+ const char *kind = "simd";
+ if (clauses.exists ()
+ && (clauses[0].type == CPP_NAME || clauses[0].type == CPP_PRAGMA))
+ kind = IDENTIFIER_POINTER (clauses[0].value);
+ gcc_assert (strcmp (kind, "simd") == 0 || strcmp (kind, "variant") == 0);
+ if (fndecl == NULL_TREE || TREE_CODE (fndecl) != FUNCTION_DECL)
+ {
+ error ("%<#pragma omp declare %s%> not immediately followed by "
+ "a function declaration or definition", kind);
+ clauses[0].type = CPP_EOF;
+ return;
+ }
+ if (clauses.exists () && clauses[0].type != CPP_NAME)
+ {
+ error_at (DECL_SOURCE_LOCATION (fndecl),
+ "%<#pragma omp declare %s%> not immediately followed by "
+ "a single function declaration or definition", kind);
+ clauses[0].type = CPP_EOF;
+ return;
+ }
+
+ if (parms == NULL_TREE)
+ parms = DECL_ARGUMENTS (fndecl);
+
+ unsigned int tokens_avail = parser->tokens_avail;
+ gcc_assert (parser->tokens == &parser->tokens_buf[0]);
+
+ parser->tokens = clauses.address ();
+ parser->tokens_avail = clauses.length ();
+
+ /* c_parser_omp_declare_simd pushed 2 extra CPP_EOF tokens at the end. */
+ while (parser->tokens_avail > 3)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ gcc_assert (token->type == CPP_NAME
+ && strcmp (IDENTIFIER_POINTER (token->value), kind) == 0);
+ c_parser_consume_token (parser);
+ parser->in_pragma = true;
+
+ if (strcmp (kind, "simd") == 0)
+ {
+ tree c;
+ c = c_parser_omp_all_clauses (parser, OMP_DECLARE_SIMD_CLAUSE_MASK,
+ "#pragma omp declare simd");
+ c = c_omp_declare_simd_clauses_to_numbers (parms, c);
+ if (c != NULL_TREE)
+ c = tree_cons (NULL_TREE, c, NULL_TREE);
+ c = build_tree_list (get_identifier ("omp declare simd"), c);
+ TREE_CHAIN (c) = DECL_ATTRIBUTES (fndecl);
+ DECL_ATTRIBUTES (fndecl) = c;
+ }
+ else
+ {
+ gcc_assert (strcmp (kind, "variant") == 0);
+ c_finish_omp_declare_variant (parser, fndecl, parms);
+ }
+ }
+
+ parser->tokens = &parser->tokens_buf[0];
+ parser->tokens_avail = tokens_avail;
+ if (clauses.exists ())
+ clauses[0].type = CPP_PRAGMA;
+}
+
+
+/* OpenMP 4.0:
+ # pragma omp declare target new-line
+ declarations and definitions
+ # pragma omp end declare target new-line
+
+ OpenMP 4.5:
+ # pragma omp declare target ( extended-list ) new-line
+
+ # pragma omp declare target declare-target-clauses[seq] new-line */
+
+#define OMP_DECLARE_TARGET_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_TO) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LINK) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE))
+
+static void
+c_parser_omp_declare_target (c_parser *parser)
+{
+ tree clauses = NULL_TREE;
+ int device_type = 0;
+ bool only_device_type = true;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ clauses = c_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK,
+ "#pragma omp declare target");
+ else if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ clauses = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_TO_DECLARE,
+ clauses);
+ clauses = c_finish_omp_clauses (clauses, C_ORT_OMP);
+ c_parser_skip_to_pragma_eol (parser);
+ }
+ else
+ {
+ c_parser_skip_to_pragma_eol (parser);
+ current_omp_declare_target_attribute++;
+ return;
+ }
+ for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE)
+ device_type |= OMP_CLAUSE_DEVICE_TYPE_KIND (c);
+ for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
+ {
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEVICE_TYPE)
+ continue;
+ tree t = OMP_CLAUSE_DECL (c), id;
+ tree at1 = lookup_attribute ("omp declare target", DECL_ATTRIBUTES (t));
+ tree at2 = lookup_attribute ("omp declare target link",
+ DECL_ATTRIBUTES (t));
+ only_device_type = false;
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINK)
+ {
+ id = get_identifier ("omp declare target link");
+ std::swap (at1, at2);
+ }
+ else
+ id = get_identifier ("omp declare target");
+ if (at2)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qD specified both in declare target %<link%> and %<to%>"
+ " clauses", t);
+ continue;
+ }
+ if (!at1)
+ {
+ DECL_ATTRIBUTES (t) = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t));
+ if (TREE_CODE (t) != FUNCTION_DECL && !is_global_var (t))
+ continue;
+
+ symtab_node *node = symtab_node::get (t);
+ if (node != NULL)
+ {
+ node->offloadable = 1;
+ if (ENABLE_OFFLOADING)
+ {
+ g->have_offload = true;
+ if (is_a <varpool_node *> (node))
+ vec_safe_push (offload_vars, t);
+ }
+ }
+ }
+ if (TREE_CODE (t) != FUNCTION_DECL)
+ continue;
+ if ((device_type & OMP_CLAUSE_DEVICE_TYPE_HOST) != 0)
+ {
+ tree at3 = lookup_attribute ("omp declare target host",
+ DECL_ATTRIBUTES (t));
+ if (at3 == NULL_TREE)
+ {
+ id = get_identifier ("omp declare target host");
+ DECL_ATTRIBUTES (t)
+ = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t));
+ }
+ }
+ if ((device_type & OMP_CLAUSE_DEVICE_TYPE_NOHOST) != 0)
+ {
+ tree at3 = lookup_attribute ("omp declare target nohost",
+ DECL_ATTRIBUTES (t));
+ if (at3 == NULL_TREE)
+ {
+ id = get_identifier ("omp declare target nohost");
+ DECL_ATTRIBUTES (t)
+ = tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t));
+ }
+ }
+ }
+ if (device_type && only_device_type)
+ warning_at (OMP_CLAUSE_LOCATION (clauses), 0,
+ "directive with only %<device_type%> clauses ignored");
+}
+
+static void
+c_parser_omp_end_declare_target (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_NAME)
+ && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
+ "declare") == 0)
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME)
+ && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
+ "target") == 0)
+ c_parser_consume_token (parser);
+ else
+ {
+ c_parser_error (parser, "expected %<target%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+ }
+ else
+ {
+ c_parser_error (parser, "expected %<declare%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+ c_parser_skip_to_pragma_eol (parser);
+ if (!current_omp_declare_target_attribute)
+ error_at (loc, "%<#pragma omp end declare target%> without corresponding "
+ "%<#pragma omp declare target%>");
+ else
+ current_omp_declare_target_attribute--;
+}
+
+
+/* OpenMP 4.0
+ #pragma omp declare reduction (reduction-id : typename-list : expression) \
+ initializer-clause[opt] new-line
+
+ initializer-clause:
+ initializer (omp_priv = initializer)
+ initializer (function-name (argument-list)) */
+
+static void
+c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context)
+{
+ unsigned int tokens_avail = 0, i;
+ vec<tree> types = vNULL;
+ vec<c_token> clauses = vNULL;
+ enum tree_code reduc_code = ERROR_MARK;
+ tree reduc_id = NULL_TREE;
+ tree type;
+ location_t rloc = c_parser_peek_token (parser)->location;
+
+ if (context == pragma_struct || context == pragma_param)
+ {
+ error ("%<#pragma omp declare reduction%> not at file or block scope");
+ goto fail;
+ }
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ goto fail;
+
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_PLUS:
+ reduc_code = PLUS_EXPR;
+ break;
+ case CPP_MULT:
+ reduc_code = MULT_EXPR;
+ break;
+ case CPP_MINUS:
+ reduc_code = MINUS_EXPR;
+ break;
+ case CPP_AND:
+ reduc_code = BIT_AND_EXPR;
+ break;
+ case CPP_XOR:
+ reduc_code = BIT_XOR_EXPR;
+ break;
+ case CPP_OR:
+ reduc_code = BIT_IOR_EXPR;
+ break;
+ case CPP_AND_AND:
+ reduc_code = TRUTH_ANDIF_EXPR;
+ break;
+ case CPP_OR_OR:
+ reduc_code = TRUTH_ORIF_EXPR;
+ break;
+ case CPP_NAME:
+ const char *p;
+ p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "min") == 0)
+ {
+ reduc_code = MIN_EXPR;
+ break;
+ }
+ if (strcmp (p, "max") == 0)
+ {
+ reduc_code = MAX_EXPR;
+ break;
+ }
+ reduc_id = c_parser_peek_token (parser)->value;
+ break;
+ default:
+ c_parser_error (parser,
+ "expected %<+%>, %<*%>, %<-%>, %<&%>, "
+ "%<^%>, %<|%>, %<&&%>, %<||%> or identifier");
+ goto fail;
+ }
+
+ tree orig_reduc_id, reduc_decl;
+ orig_reduc_id = reduc_id;
+ reduc_id = c_omp_reduction_id (reduc_code, reduc_id);
+ reduc_decl = c_omp_reduction_decl (reduc_id);
+ c_parser_consume_token (parser);
+
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ goto fail;
+
+ while (true)
+ {
+ location_t loc = c_parser_peek_token (parser)->location;
+ struct c_type_name *ctype = c_parser_type_name (parser);
+ if (ctype != NULL)
+ {
+ type = groktypename (ctype, NULL, NULL);
+ if (type == error_mark_node)
+ ;
+ else if ((INTEGRAL_TYPE_P (type)
+ || TREE_CODE (type) == REAL_TYPE
+ || TREE_CODE (type) == COMPLEX_TYPE)
+ && orig_reduc_id == NULL_TREE)
+ error_at (loc, "predeclared arithmetic type in "
+ "%<#pragma omp declare reduction%>");
+ else if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == ARRAY_TYPE)
+ error_at (loc, "function or array type in "
+ "%<#pragma omp declare reduction%>");
+ else if (TYPE_ATOMIC (type))
+ error_at (loc, "%<_Atomic%> qualified type in "
+ "%<#pragma omp declare reduction%>");
+ else if (TYPE_QUALS_NO_ADDR_SPACE (type))
+ error_at (loc, "const, volatile or restrict qualified type in "
+ "%<#pragma omp declare reduction%>");
+ else
+ {
+ tree t;
+ for (t = DECL_INITIAL (reduc_decl); t; t = TREE_CHAIN (t))
+ if (comptypes (TREE_PURPOSE (t), type))
+ {
+ error_at (loc, "redeclaration of %qs "
+ "%<#pragma omp declare reduction%> for "
+ "type %qT",
+ IDENTIFIER_POINTER (reduc_id)
+ + sizeof ("omp declare reduction ") - 1,
+ type);
+ location_t ploc
+ = DECL_SOURCE_LOCATION (TREE_VEC_ELT (TREE_VALUE (t),
+ 0));
+ error_at (ploc, "previous %<#pragma omp declare "
+ "reduction%>");
+ break;
+ }
+ if (t == NULL_TREE)
+ types.safe_push (type);
+ }
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>")
+ || types.is_empty ())
+ {
+ fail:
+ clauses.release ();
+ types.release ();
+ while (true)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF || token->type == CPP_PRAGMA_EOL)
+ break;
+ c_parser_consume_token (parser);
+ }
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+
+ if (types.length () > 1)
+ {
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ goto fail;
+ clauses.safe_push (*token);
+ c_parser_consume_token (parser);
+ }
+ clauses.safe_push (*c_parser_peek_token (parser));
+ c_parser_skip_to_pragma_eol (parser);
+
+ /* Make sure nothing tries to read past the end of the tokens. */
+ c_token eof_token;
+ memset (&eof_token, 0, sizeof (eof_token));
+ eof_token.type = CPP_EOF;
+ clauses.safe_push (eof_token);
+ clauses.safe_push (eof_token);
+ }
+
+ int errs = errorcount;
+ FOR_EACH_VEC_ELT (types, i, type)
+ {
+ tokens_avail = parser->tokens_avail;
+ gcc_assert (parser->tokens == &parser->tokens_buf[0]);
+ if (!clauses.is_empty ())
+ {
+ parser->tokens = clauses.address ();
+ parser->tokens_avail = clauses.length ();
+ parser->in_pragma = true;
+ }
+
+ bool nested = current_function_decl != NULL_TREE;
+ if (nested)
+ c_push_function_context ();
+ tree fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
+ reduc_id, default_function_type);
+ current_function_decl = fndecl;
+ allocate_struct_function (fndecl, true);
+ push_scope ();
+ tree stmt = push_stmt_list ();
+ /* Intentionally BUILTINS_LOCATION, so that -Wshadow doesn't
+ warn about these. */
+ tree omp_out = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ get_identifier ("omp_out"), type);
+ DECL_ARTIFICIAL (omp_out) = 1;
+ DECL_CONTEXT (omp_out) = fndecl;
+ pushdecl (omp_out);
+ tree omp_in = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ get_identifier ("omp_in"), type);
+ DECL_ARTIFICIAL (omp_in) = 1;
+ DECL_CONTEXT (omp_in) = fndecl;
+ pushdecl (omp_in);
+ struct c_expr combiner = c_parser_expression (parser);
+ struct c_expr initializer;
+ tree omp_priv = NULL_TREE, omp_orig = NULL_TREE;
+ bool bad = false;
+ initializer.set_error ();
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ bad = true;
+ else if (c_parser_next_token_is (parser, CPP_NAME)
+ && strcmp (IDENTIFIER_POINTER
+ (c_parser_peek_token (parser)->value),
+ "initializer") == 0)
+ {
+ c_parser_consume_token (parser);
+ pop_scope ();
+ push_scope ();
+ omp_priv = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ get_identifier ("omp_priv"), type);
+ DECL_ARTIFICIAL (omp_priv) = 1;
+ DECL_INITIAL (omp_priv) = error_mark_node;
+ DECL_CONTEXT (omp_priv) = fndecl;
+ pushdecl (omp_priv);
+ omp_orig = build_decl (BUILTINS_LOCATION, VAR_DECL,
+ get_identifier ("omp_orig"), type);
+ DECL_ARTIFICIAL (omp_orig) = 1;
+ DECL_CONTEXT (omp_orig) = fndecl;
+ pushdecl (omp_orig);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ bad = true;
+ else if (!c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_parser_error (parser, "expected %<omp_priv%> or "
+ "function-name");
+ bad = true;
+ }
+ else if (strcmp (IDENTIFIER_POINTER
+ (c_parser_peek_token (parser)->value),
+ "omp_priv") != 0)
+ {
+ if (c_parser_peek_2nd_token (parser)->type != CPP_OPEN_PAREN
+ || c_parser_peek_token (parser)->id_kind != C_ID_ID)
+ {
+ c_parser_error (parser, "expected function-name %<(%>");
+ bad = true;
+ }
+ else
+ initializer = c_parser_postfix_expression (parser);
+ if (initializer.value
+ && TREE_CODE (initializer.value) == CALL_EXPR)
+ {
+ int j;
+ tree c = initializer.value;
+ for (j = 0; j < call_expr_nargs (c); j++)
+ {
+ tree a = CALL_EXPR_ARG (c, j);
+ STRIP_NOPS (a);
+ if (TREE_CODE (a) == ADDR_EXPR
+ && TREE_OPERAND (a, 0) == omp_priv)
+ break;
+ }
+ if (j == call_expr_nargs (c))
+ error ("one of the initializer call arguments should be "
+ "%<&omp_priv%>");
+ }
+ }
+ else
+ {
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_EQ, "expected %<=%>"))
+ bad = true;
+ else
+ {
+ tree st = push_stmt_list ();
+ location_t loc = c_parser_peek_token (parser)->location;
+ rich_location richloc (line_table, loc);
+ start_init (omp_priv, NULL_TREE, 0, &richloc);
+ struct c_expr init = c_parser_initializer (parser);
+ finish_init ();
+ finish_decl (omp_priv, loc, init.value,
+ init.original_type, NULL_TREE);
+ pop_stmt_list (st);
+ }
+ }
+ if (!bad
+ && !c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ bad = true;
+ }
+
+ if (!bad)
+ {
+ c_parser_skip_to_pragma_eol (parser);
+
+ tree t = tree_cons (type, make_tree_vec (omp_priv ? 6 : 3),
+ DECL_INITIAL (reduc_decl));
+ DECL_INITIAL (reduc_decl) = t;
+ DECL_SOURCE_LOCATION (omp_out) = rloc;
+ TREE_VEC_ELT (TREE_VALUE (t), 0) = omp_out;
+ TREE_VEC_ELT (TREE_VALUE (t), 1) = omp_in;
+ TREE_VEC_ELT (TREE_VALUE (t), 2) = combiner.value;
+ walk_tree (&combiner.value, c_check_omp_declare_reduction_r,
+ &TREE_VEC_ELT (TREE_VALUE (t), 0), NULL);
+ if (omp_priv)
+ {
+ DECL_SOURCE_LOCATION (omp_priv) = rloc;
+ TREE_VEC_ELT (TREE_VALUE (t), 3) = omp_priv;
+ TREE_VEC_ELT (TREE_VALUE (t), 4) = omp_orig;
+ TREE_VEC_ELT (TREE_VALUE (t), 5) = initializer.value;
+ walk_tree (&initializer.value, c_check_omp_declare_reduction_r,
+ &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL);
+ walk_tree (&DECL_INITIAL (omp_priv),
+ c_check_omp_declare_reduction_r,
+ &TREE_VEC_ELT (TREE_VALUE (t), 3), NULL);
+ }
+ }
+
+ pop_stmt_list (stmt);
+ pop_scope ();
+ if (cfun->language != NULL)
+ {
+ ggc_free (cfun->language);
+ cfun->language = NULL;
+ }
+ set_cfun (NULL);
+ current_function_decl = NULL_TREE;
+ if (nested)
+ c_pop_function_context ();
+
+ if (!clauses.is_empty ())
+ {
+ parser->tokens = &parser->tokens_buf[0];
+ parser->tokens_avail = tokens_avail;
+ }
+ if (bad)
+ goto fail;
+ if (errs != errorcount)
+ break;
+ }
+
+ clauses.release ();
+ types.release ();
+}
+
+
+/* OpenMP 4.0
+ #pragma omp declare simd declare-simd-clauses[optseq] new-line
+ #pragma omp declare reduction (reduction-id : typename-list : expression) \
+ initializer-clause[opt] new-line
+ #pragma omp declare target new-line
+
+ OpenMP 5.0
+ #pragma omp declare variant (identifier) match (context-selector) */
+
+static bool
+c_parser_omp_declare (c_parser *parser, enum pragma_context context)
+{
+ c_parser_consume_pragma (parser);
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "simd") == 0)
+ {
+ /* c_parser_consume_token (parser); done in
+ c_parser_omp_declare_simd. */
+ c_parser_omp_declare_simd (parser, context);
+ return true;
+ }
+ if (strcmp (p, "reduction") == 0)
+ {
+ c_parser_consume_token (parser);
+ c_parser_omp_declare_reduction (parser, context);
+ return false;
+ }
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return false;
+ }
+ if (strcmp (p, "target") == 0)
+ {
+ c_parser_consume_token (parser);
+ c_parser_omp_declare_target (parser);
+ return false;
+ }
+ if (strcmp (p, "variant") == 0)
+ {
+ /* c_parser_consume_token (parser); done in
+ c_parser_omp_declare_simd. */
+ c_parser_omp_declare_simd (parser, context);
+ return true;
+ }
+ }
+
+ c_parser_error (parser, "expected %<simd%>, %<reduction%>, "
+ "%<target%> or %<variant%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return false;
+}
+
+/* OpenMP 5.0
+ #pragma omp requires clauses[optseq] new-line */
+
+static void
+c_parser_omp_requires (c_parser *parser)
+{
+ bool first = true;
+ enum omp_requires new_req = (enum omp_requires) 0;
+
+ c_parser_consume_pragma (parser);
+
+ location_t loc = c_parser_peek_token (parser)->location;
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ if (!first
+ && c_parser_next_token_is (parser, CPP_COMMA)
+ && c_parser_peek_2nd_token (parser)->type == CPP_NAME)
+ c_parser_consume_token (parser);
+
+ first = false;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ location_t cloc = c_parser_peek_token (parser)->location;
+ enum omp_requires this_req = (enum omp_requires) 0;
+
+ if (!strcmp (p, "unified_address"))
+ this_req = OMP_REQUIRES_UNIFIED_ADDRESS;
+ else if (!strcmp (p, "unified_shared_memory"))
+ this_req = OMP_REQUIRES_UNIFIED_SHARED_MEMORY;
+ else if (!strcmp (p, "dynamic_allocators"))
+ this_req = OMP_REQUIRES_DYNAMIC_ALLOCATORS;
+ else if (!strcmp (p, "reverse_offload"))
+ this_req = OMP_REQUIRES_REVERSE_OFFLOAD;
+ else if (!strcmp (p, "atomic_default_mem_order"))
+ {
+ c_parser_consume_token (parser);
+
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ tree v = c_parser_peek_token (parser)->value;
+ p = IDENTIFIER_POINTER (v);
+
+ if (!strcmp (p, "seq_cst"))
+ this_req
+ = (enum omp_requires) OMP_MEMORY_ORDER_SEQ_CST;
+ else if (!strcmp (p, "relaxed"))
+ this_req
+ = (enum omp_requires) OMP_MEMORY_ORDER_RELAXED;
+ else if (!strcmp (p, "acq_rel"))
+ this_req
+ = (enum omp_requires) OMP_MEMORY_ORDER_ACQ_REL;
+ }
+ if (this_req == 0)
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "expected %<seq_cst%>, %<relaxed%> or "
+ "%<acq_rel%>");
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_EOF:
+ case CPP_PRAGMA_EOL:
+ case CPP_CLOSE_PAREN:
+ break;
+ default:
+ if (c_parser_peek_2nd_token (parser)->type
+ == CPP_CLOSE_PAREN)
+ c_parser_consume_token (parser);
+ break;
+ }
+ }
+ else
+ c_parser_consume_token (parser);
+
+ parens.skip_until_found_close (parser);
+ if (this_req == 0)
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return;
+ }
+ }
+ p = NULL;
+ }
+ else
+ {
+ error_at (cloc, "expected %<unified_address%>, "
+ "%<unified_shared_memory%>, "
+ "%<dynamic_allocators%>, "
+ "%<reverse_offload%> "
+ "or %<atomic_default_mem_order%> clause");
+ c_parser_skip_to_pragma_eol (parser, false);
+ return;
+ }
+ if (p && this_req != OMP_REQUIRES_DYNAMIC_ALLOCATORS)
+ sorry_at (cloc, "%qs clause on %<requires%> directive not "
+ "supported yet", p);
+ if (p)
+ c_parser_consume_token (parser);
+ if (this_req)
+ {
+ if ((this_req & ~OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0)
+ {
+ if ((this_req & new_req) != 0)
+ error_at (cloc, "too many %qs clauses", p);
+ if (this_req != OMP_REQUIRES_DYNAMIC_ALLOCATORS
+ && (omp_requires_mask & OMP_REQUIRES_TARGET_USED) != 0)
+ error_at (cloc, "%qs clause used lexically after first "
+ "target construct or offloading API", p);
+ }
+ else if ((new_req & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0)
+ {
+ error_at (cloc, "too many %qs clauses",
+ "atomic_default_mem_order");
+ this_req = (enum omp_requires) 0;
+ }
+ else if ((omp_requires_mask
+ & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER) != 0)
+ {
+ error_at (cloc, "more than one %<atomic_default_mem_order%>"
+ " clause in a single compilation unit");
+ this_req
+ = (enum omp_requires)
+ (omp_requires_mask
+ & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER);
+ }
+ else if ((omp_requires_mask
+ & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER_USED) != 0)
+ error_at (cloc, "%<atomic_default_mem_order%> clause used "
+ "lexically after first %<atomic%> construct "
+ "without memory order clause");
+ new_req = (enum omp_requires) (new_req | this_req);
+ omp_requires_mask
+ = (enum omp_requires) (omp_requires_mask | this_req);
+ continue;
+ }
+ }
+ break;
+ }
+ c_parser_skip_to_pragma_eol (parser);
+
+ if (new_req == 0)
+ error_at (loc, "%<pragma omp requires%> requires at least one clause");
+}
+
+/* Helper function for c_parser_omp_taskloop.
+ Disallow zero sized or potentially zero sized task reductions. */
+
+static tree
+c_finish_taskloop_clauses (tree clauses)
+{
+ tree *pc = &clauses;
+ for (tree c = clauses; c; c = *pc)
+ {
+ bool remove = false;
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
+ {
+ tree type = strip_array_types (TREE_TYPE (OMP_CLAUSE_DECL (c)));
+ if (integer_zerop (TYPE_SIZE_UNIT (type)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "zero sized type %qT in %<reduction%> clause", type);
+ remove = true;
+ }
+ else if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "variable sized type %qT in %<reduction%> clause",
+ type);
+ remove = true;
+ }
+ }
+ if (remove)
+ *pc = OMP_CLAUSE_CHAIN (c);
+ else
+ pc = &OMP_CLAUSE_CHAIN (c);
+ }
+ return clauses;
+}
+
+/* OpenMP 4.5:
+ #pragma omp taskloop taskloop-clause[optseq] new-line
+ for-loop
+
+ #pragma omp taskloop simd taskloop-simd-clause[optseq] new-line
+ for-loop */
+
+#define OMP_TASKLOOP_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_SHARED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_LASTPRIVATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEFAULT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_GRAINSIZE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_TASKS) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_COLLAPSE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNTIED) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IF) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FINAL) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MERGEABLE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIORITY) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_ALLOCATE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_REDUCTION) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION))
+
+static tree
+c_parser_omp_taskloop (location_t loc, c_parser *parser,
+ char *p_name, omp_clause_mask mask, tree *cclauses,
+ bool *if_p)
+{
+ tree clauses, block, ret;
+
+ strcat (p_name, " taskloop");
+ mask |= OMP_TASKLOOP_CLAUSE_MASK;
+ /* #pragma omp parallel master taskloop{, simd} disallow in_reduction
+ clause. */
+ if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NUM_THREADS)) != 0)
+ mask &= ~(OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION);
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+
+ if (strcmp (p, "simd") == 0)
+ {
+ tree cclauses_buf[C_OMP_CLAUSE_SPLIT_COUNT];
+ if (cclauses == NULL)
+ cclauses = cclauses_buf;
+ c_parser_consume_token (parser);
+ if (!flag_openmp) /* flag_openmp_simd */
+ return c_parser_omp_simd (loc, parser, p_name, mask, cclauses,
+ if_p);
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_simd (loc, parser, p_name, mask, cclauses, if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ if (ret == NULL)
+ return ret;
+ ret = make_node (OMP_TASKLOOP);
+ TREE_TYPE (ret) = void_type_node;
+ OMP_FOR_BODY (ret) = block;
+ OMP_FOR_CLAUSES (ret) = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP];
+ OMP_FOR_CLAUSES (ret)
+ = c_finish_taskloop_clauses (OMP_FOR_CLAUSES (ret));
+ SET_EXPR_LOCATION (ret, loc);
+ add_stmt (ret);
+ return ret;
+ }
+ }
+ if (!flag_openmp) /* flag_openmp_simd */
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return NULL_TREE;
+ }
+
+ clauses = c_parser_omp_all_clauses (parser, mask, p_name, cclauses == NULL);
+ if (cclauses)
+ {
+ omp_split_clauses (loc, OMP_TASKLOOP, mask, clauses, cclauses);
+ clauses = cclauses[C_OMP_CLAUSE_SPLIT_TASKLOOP];
+ }
+
+ clauses = c_finish_taskloop_clauses (clauses);
+ block = c_begin_compound_stmt (true);
+ ret = c_parser_omp_for_loop (loc, parser, OMP_TASKLOOP, clauses, NULL, if_p);
+ block = c_end_compound_stmt (loc, block, true);
+ add_stmt (block);
+
+ return ret;
+}
+
+/* OpenMP 5.1
+ #pragma omp nothing new-line */
+
+static void
+c_parser_omp_nothing (c_parser *parser)
+{
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser);
+}
+
+/* OpenMP 5.1
+ #pragma omp error clauses[optseq] new-line */
+
+static bool
+c_parser_omp_error (c_parser *parser, enum pragma_context context)
+{
+ int at_compilation = -1;
+ int severity_fatal = -1;
+ tree message = NULL_TREE;
+ bool first = true;
+ bool bad = false;
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ c_parser_consume_pragma (parser);
+
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ if (!first
+ && c_parser_next_token_is (parser, CPP_COMMA)
+ && c_parser_peek_2nd_token (parser)->type == CPP_NAME)
+ c_parser_consume_token (parser);
+
+ first = false;
+
+ if (!c_parser_next_token_is (parser, CPP_NAME))
+ break;
+
+ const char *p
+ = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ location_t cloc = c_parser_peek_token (parser)->location;
+ static const char *args[] = {
+ "execution", "compilation", "warning", "fatal"
+ };
+ int *v = NULL;
+ int idx = 0, n = -1;
+ tree m = NULL_TREE;
+
+ if (!strcmp (p, "at"))
+ v = &at_compilation;
+ else if (!strcmp (p, "severity"))
+ {
+ v = &severity_fatal;
+ idx += 2;
+ }
+ else if (strcmp (p, "message"))
+ {
+ error_at (cloc,
+ "expected %<at%>, %<severity%> or %<message%> clause");
+ c_parser_skip_to_pragma_eol (parser, false);
+ return false;
+ }
+
+ c_parser_consume_token (parser);
+
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ if (v == NULL)
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, true, true);
+ m = convert (const_string_type_node, expr.value);
+ m = c_fully_fold (m, false, NULL);
+ }
+ else
+ {
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ tree val = c_parser_peek_token (parser)->value;
+ const char *q = IDENTIFIER_POINTER (val);
+
+ if (!strcmp (q, args[idx]))
+ n = 0;
+ else if (!strcmp (q, args[idx + 1]))
+ n = 1;
+ }
+ if (n == -1)
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "expected %qs or %qs", args[idx], args[idx + 1]);
+ bad = true;
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_EOF:
+ case CPP_PRAGMA_EOL:
+ case CPP_CLOSE_PAREN:
+ break;
+ default:
+ if (c_parser_peek_2nd_token (parser)->type
+ == CPP_CLOSE_PAREN)
+ c_parser_consume_token (parser);
+ break;
+ }
+ }
+ else
+ c_parser_consume_token (parser);
+ }
+
+ parens.skip_until_found_close (parser);
+
+ if (v == NULL)
+ {
+ if (message)
+ {
+ error_at (cloc, "too many %qs clauses", p);
+ bad = true;
+ }
+ else
+ message = m;
+ }
+ else if (n != -1)
+ {
+ if (*v != -1)
+ {
+ error_at (cloc, "too many %qs clauses", p);
+ bad = true;
+ }
+ else
+ *v = n;
+ }
+ }
+ else
+ bad = true;
+ }
+ c_parser_skip_to_pragma_eol (parser);
+ if (bad)
+ return true;
+
+ if (at_compilation == -1)
+ at_compilation = 1;
+ if (severity_fatal == -1)
+ severity_fatal = 1;
+ if (!at_compilation)
+ {
+ if (context != pragma_compound)
+ {
+ error_at (loc, "%<#pragma omp error%> with %<at(execution)%> clause "
+ "may only be used in compound statements");
+ return true;
+ }
+ tree fndecl
+ = builtin_decl_explicit (severity_fatal ? BUILT_IN_GOMP_ERROR
+ : BUILT_IN_GOMP_WARNING);
+ if (!message)
+ message = build_zero_cst (const_string_type_node);
+ tree stmt = build_call_expr_loc (loc, fndecl, 2, message,
+ build_all_ones_cst (size_type_node));
+ add_stmt (stmt);
+ return true;
+ }
+ const char *msg = NULL;
+ if (message)
+ {
+ msg = c_getstr (message);
+ if (msg == NULL)
+ msg = _("<message unknown at compile time>");
+ }
+ if (msg)
+ emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0,
+ "%<pragma omp error%> encountered: %s", msg);
+ else
+ emit_diagnostic (severity_fatal ? DK_ERROR : DK_WARNING, loc, 0,
+ "%<pragma omp error%> encountered");
+ return false;
+}
+
+/* Main entry point to parsing most OpenMP pragmas. */
+
+static void
+c_parser_omp_construct (c_parser *parser, bool *if_p)
+{
+ enum pragma_kind p_kind;
+ location_t loc;
+ tree stmt;
+ char p_name[sizeof "#pragma omp teams distribute parallel for simd"];
+ omp_clause_mask mask (0);
+
+ 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_OACC_ATOMIC:
+ c_parser_omp_atomic (loc, parser, true);
+ return;
+ case PRAGMA_OACC_CACHE:
+ strcpy (p_name, "#pragma acc");
+ stmt = c_parser_oacc_cache (loc, parser);
+ break;
+ case PRAGMA_OACC_DATA:
+ stmt = c_parser_oacc_data (loc, parser, if_p);
+ break;
+ case PRAGMA_OACC_HOST_DATA:
+ stmt = c_parser_oacc_host_data (loc, parser, if_p);
+ break;
+ case PRAGMA_OACC_KERNELS:
+ case PRAGMA_OACC_PARALLEL:
+ case PRAGMA_OACC_SERIAL:
+ strcpy (p_name, "#pragma acc");
+ stmt = c_parser_oacc_compute (loc, parser, p_kind, p_name, if_p);
+ break;
+ case PRAGMA_OACC_LOOP:
+ strcpy (p_name, "#pragma acc");
+ stmt = c_parser_oacc_loop (loc, parser, p_name, mask, NULL, if_p);
+ break;
+ case PRAGMA_OACC_WAIT:
+ strcpy (p_name, "#pragma wait");
+ stmt = c_parser_oacc_wait (loc, parser, p_name);
+ break;
+ case PRAGMA_OMP_ALLOCATE:
+ c_parser_omp_allocate (loc, parser);
+ return;
+ case PRAGMA_OMP_ATOMIC:
+ c_parser_omp_atomic (loc, parser, false);
+ return;
+ case PRAGMA_OMP_CRITICAL:
+ stmt = c_parser_omp_critical (loc, parser, if_p);
+ break;
+ case PRAGMA_OMP_DISTRIBUTE:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_distribute (loc, parser, p_name, mask, NULL, if_p);
+ break;
+ case PRAGMA_OMP_FOR:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_for (loc, parser, p_name, mask, NULL, if_p);
+ break;
+ case PRAGMA_OMP_LOOP:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_loop (loc, parser, p_name, mask, NULL, if_p);
+ break;
+ case PRAGMA_OMP_MASKED:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_masked (loc, parser, p_name, mask, NULL, if_p);
+ break;
+ case PRAGMA_OMP_MASTER:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_master (loc, parser, p_name, mask, NULL, if_p);
+ break;
+ case PRAGMA_OMP_PARALLEL:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL, if_p);
+ break;
+ case PRAGMA_OMP_SCOPE:
+ stmt = c_parser_omp_scope (loc, parser, if_p);
+ break;
+ case PRAGMA_OMP_SECTIONS:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_sections (loc, parser, p_name, mask, NULL);
+ break;
+ case PRAGMA_OMP_SIMD:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_simd (loc, parser, p_name, mask, NULL, if_p);
+ break;
+ case PRAGMA_OMP_SINGLE:
+ stmt = c_parser_omp_single (loc, parser, if_p);
+ break;
+ case PRAGMA_OMP_TASK:
+ stmt = c_parser_omp_task (loc, parser, if_p);
+ break;
+ case PRAGMA_OMP_TASKGROUP:
+ stmt = c_parser_omp_taskgroup (loc, parser, if_p);
+ break;
+ case PRAGMA_OMP_TASKLOOP:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_taskloop (loc, parser, p_name, mask, NULL, if_p);
+ break;
+ case PRAGMA_OMP_TEAMS:
+ strcpy (p_name, "#pragma omp");
+ stmt = c_parser_omp_teams (loc, parser, p_name, mask, NULL, if_p);
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (stmt && stmt != error_mark_node)
+ 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 (!VAR_P (v))
+ 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 (! is_global_var (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))
+ {
+ set_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:
+ gnu-attributes
+ attribute-specifier
+*/
+
+static tree
+c_parser_transaction_attributes (c_parser *parser)
+{
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ return c_parser_gnu_attributes (parser);
+
+ if (!c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ return NULL_TREE;
+ return c_parser_std_attribute_specifier (parser, true);
+}
+
+/* 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;
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ 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 (!parens.require_close (parser))
+ {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ goto error;
+ }
+ }
+ else
+ {
+ error:
+ ret.set_error ();
+ 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"));
+
+ set_c_expr_source_range (&ret, loc, loc);
+
+ 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%> 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);
+ tparser.translate_strings_p = true;
+ tparser.tokens = &tparser.tokens_buf[0];
+ the_parser = &tparser;
+
+ if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS)
+ c_parser_pragma_pch_preprocess (&tparser);
+ else
+ c_common_no_more_pch ();
+
+ the_parser = ggc_alloc<c_parser> ();
+ *the_parser = tparser;
+ if (tparser.tokens == &tparser.tokens_buf[0])
+ the_parser->tokens = &the_parser->tokens_buf[0];
+
+ /* 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;
+}
+
+/* Parse the body of a function declaration marked with "__RTL".
+
+ The RTL parser works on the level of characters read from a
+ FILE *, whereas c_parser works at the level of tokens.
+ Square this circle by consuming all of the tokens up to and
+ including the closing brace, recording the start/end of the RTL
+ fragment, and reopening the file and re-reading the relevant
+ lines within the RTL parser.
+
+ This requires the opening and closing braces of the C function
+ to be on separate lines from the RTL they wrap.
+
+ Take ownership of START_WITH_PASS, if non-NULL. */
+
+location_t
+c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass)
+{
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ {
+ free (start_with_pass);
+ return c_parser_peek_token (parser)->location;
+ }
+
+ location_t start_loc = c_parser_peek_token (parser)->location;
+
+ /* Consume all tokens, up to the closing brace, handling
+ matching pairs of braces in the rtl dump. */
+ int num_open_braces = 1;
+ while (1)
+ {
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_OPEN_BRACE:
+ num_open_braces++;
+ break;
+ case CPP_CLOSE_BRACE:
+ if (--num_open_braces == 0)
+ goto found_closing_brace;
+ break;
+ case CPP_EOF:
+ error_at (start_loc, "no closing brace");
+ free (start_with_pass);
+ return c_parser_peek_token (parser)->location;
+ default:
+ break;
+ }
+ c_parser_consume_token (parser);
+ }
+
+ found_closing_brace:
+ /* At the closing brace; record its location. */
+ location_t end_loc = c_parser_peek_token (parser)->location;
+
+ /* Consume the closing brace. */
+ c_parser_consume_token (parser);
+
+ /* Invoke the RTL parser. */
+ if (!read_rtl_function_body_from_file_range (start_loc, end_loc))
+ {
+ free (start_with_pass);
+ return end_loc;
+ }
+
+ /* Run the backend on the cfun created above, transferring ownership of
+ START_WITH_PASS. */
+ run_rtl_passes (start_with_pass);
+ return end_loc;
+}
+
+#include "gt-c-c-parser.h"