aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-parser.cc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2023-11-04 09:09:08 +0100
committerJakub Jelinek <jakub@redhat.com>2023-11-04 09:09:08 +0100
commit40b9af020fc2842b4e22ae06742088815400631e (patch)
treebe3a513ca58aad599180e0752e46cb4412cc7217 /gcc/c/c-parser.cc
parent8d22ac6a18cf542cd541c06b2a7df8fdd293946d (diff)
downloadgcc-40b9af020fc2842b4e22ae06742088815400631e.zip
gcc-40b9af020fc2842b4e22ae06742088815400631e.tar.gz
gcc-40b9af020fc2842b4e22ae06742088815400631e.tar.bz2
openmp: Add support for omp::directive and omp::sequence attributes in C2X
The following patch adds support for attribute syntax which we have in C++11 and above since GCC 12 also for C, where OpenMP standard is going to add it in OpenMP 6.0. 2023-11-04 Jakub Jelinek <jakub@redhat.com> gcc/c/ * c-tree.def: New file. * c-tree.h (struct c_tree_token_vec): Forward declare. (c_tree_size): Declare. * c-lang.h (struct c_omp_declare_target_attr): Add attr_syntax member. (struct c_omp_begin_assumes_data): New type. (current_omp_begin_assumes): Change type from int to vec<c_omp_begin_assumes_data, va_gc> *. * c-lang.cc: Include c-family/c-pragma.h and c-parser.h. * c-parser.h (struct c_tree_token_vec_struct): New type. (C_TOKEN_VEC_TOKENS): New macro. * c-parser.cc (struct c_parser): Add omp_attrs_forbidden_p and in_omp_attribute_pragma members. (c_parser_skip_until_found): Handle CPP_PRAGMA_EOL when parser->in_omp_attribute_pragma. (c_parser_skip_to_pragma_eol): Likewise. (c_parser_translation_unit): Adjust for current_omp_begin_assumes being a vector rather than counter. (c_parser_declaration_or_fndef): Handle omp::directive and omp::sequence attributes on attribute declaration and declare simd or declare variant directives in those on function declarations. (c_parser_check_balanced_raw_token_sequence): Forward declare. (c_parser_omp_directive_args, c_parser_omp_sequence_args): New functions. (c_parser_std_attribute): Handle omp::directive and omp::sequence attributes. (struct c_omp_attribute_data): New type. (c_parser_handle_statement_omp_attributes, c_parser_handle_directive_omp_attributes): New functions. (c_parser_compound_statement_nostart): Handle omp::directive and omp::sequence attributes on statements. Formatting fix. (c_parser_all_labels): Handle omp::directive and omp::sequence attributes on statements. (c_parser_statement): Clear parser->omp_attrs_forbidden_p. (c_parser_omp_variable_list): Handle parser->tokens != &parser->tokens_buf[0] by saving/restoring it. (c_parser_omp_structured_block): Set parser->omp_attrs_forbidden_p. (c_parser_omp_section_scan): New function. (c_parser_omp_structured_block_sequence, c_parser_omp_sections_scope): Use it. (c_parser_omp_parallel): Set parser->omp_attrs_forbidden_p. (c_parser_omp_task): Likewise. (c_parser_omp_declare_simd): Handle function declaration after std attributes. (c_finish_omp_declare_simd): Don't assert all kinds are the same. (c_parser_omp_declare_target): Also push attr_syntax flag. (c_parser_omp_begin): Likewise. Adjust for current_omp_begin_assumes type change. (c_parser_omp_end): Adjust for current_omp_begin_assumes type change. Diagnose mixing of attribute vs. pragma syntax on end assumes or end declare target. (c_parser_omp_declare_reduction): Handle parser->tokens != &parser->tokens_buf[0] by saving/restoring it. * c-decl.cc: Include c-parser.h. (current_omp_begin_assumes): Change type from int to vec<c_omp_begin_assumes_data, va_gc> *. (struct c_tree_token_vec): New type. Add static assertions for sizeof and offsetof. (union lang_tree_node): Add c_token_vec member and adjust GTY desc for it. (c_tree_size): New function. (c_decl_attributes): Diagnose invalid omp::directive attribute uses. * c-objc-common.h (LANG_HOOKS_TREE_SIZE): Redefine. gcc/cp/ * parser.h (struct cp_parser): Adjust comment on omp_attrs_forbidden_p member. * parser.cc (cp_parser_omp_section_scan): Allow __directive__ spelling. gcc/objc/ * objc-act.h (objc_common_tree_size): Remove. * objc-act.cc (objc_common_tree_size): Remove. * objc-lang.cc (LANG_HOOKS_TREE_SIZE): Remove. gcc/testsuite/ * gcc.dg/gomp/attrs-1.c: New test. * gcc.dg/gomp/attrs-2.c: New test. * gcc.dg/gomp/attrs-3.c: New test. * gcc.dg/gomp/attrs-4.c: New test. * gcc.dg/gomp/attrs-5.c: New test. * gcc.dg/gomp/attrs-6.c: New test. * gcc.dg/gomp/attrs-7.c: New test. * gcc.dg/gomp/attrs-8.c: New test. * gcc.dg/gomp/attrs-9.c: New test. * gcc.dg/gomp/attrs-10.c: New test. * gcc.dg/gomp/attrs-11.c: New test. * gcc.dg/gomp/attrs-12.c: New test. * gcc.dg/gomp/attrs-13.c: New test. * gcc.dg/gomp/attrs-14.c: New test. * gcc.dg/gomp/attrs-15.c: New test. * gcc.dg/gomp/attrs-16.c: New test. * gcc.dg/gomp/attrs-17.c: New test. * gcc.dg/gomp/attrs-18.c: New test. * g++.dg/gomp/attrs-2.C: Enable for c++11 rather than just c++17. Avoid using omp : syntax for c++11, c++14 and c.
Diffstat (limited to 'gcc/c/c-parser.cc')
-rw-r--r--gcc/c/c-parser.cc840
1 files changed, 799 insertions, 41 deletions
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 5213a57..20efd4d 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -247,12 +247,21 @@ struct GTY(()) c_parser {
macro. */
BOOL_BITFIELD seen_string_literal : 1;
+ /* TRUE if omp::directive, omp::decl or omp::sequence attributes may not
+ appear. */
+ BOOL_BITFIELD omp_attrs_forbidden_p : 1;
+
/* Location of the last consumed token. */
location_t last_token_location;
/* Holds state for parsing collapsed OMP_FOR loops. Managed by
c_parser_omp_for_loop. */
struct omp_for_parse_data * GTY((skip)) omp_for_parse_state;
+
+ /* If we're in the context of OpenMP directives written as C23
+ attributes turned into pragma, vector of tokens created from that,
+ otherwise NULL. */
+ vec<c_token, va_gc> *in_omp_attribute_pragma;
};
/* Return a pointer to the Nth token in PARSERs tokens_buf. */
@@ -1288,7 +1297,19 @@ c_parser_skip_until_found (c_parser *parser,
unsigned nesting_depth = 0;
if (c_parser_require (parser, type, msgid, matching_location))
- return;
+ {
+ if (UNLIKELY (type == CPP_PRAGMA_EOL) && parser->in_omp_attribute_pragma)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ {
+ parser->tokens = &parser->tokens_buf[0];
+ parser->tokens_avail = token->flags;
+ parser->in_omp_attribute_pragma = NULL;
+ }
+ }
+ return;
+ }
/* Skip tokens until the desired token is found. */
while (true)
@@ -1299,6 +1320,17 @@ c_parser_skip_until_found (c_parser *parser,
if (token->type == type && !nesting_depth)
{
c_parser_consume_token (parser);
+ if (UNLIKELY (type == CPP_PRAGMA_EOL)
+ && parser->in_omp_attribute_pragma)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ {
+ parser->tokens = &parser->tokens_buf[0];
+ parser->tokens_avail = token->flags;
+ parser->in_omp_attribute_pragma = NULL;
+ }
+ }
break;
}
@@ -1383,6 +1415,17 @@ c_parser_skip_to_pragma_eol (c_parser *parser, bool error_if_not_eol = true)
}
while (token_type != CPP_PRAGMA_EOL);
+ if (parser->in_omp_attribute_pragma)
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_EOF)
+ {
+ parser->tokens = &parser->tokens_buf[0];
+ parser->tokens_avail = token->flags;
+ parser->in_omp_attribute_pragma = NULL;
+ }
+ }
+
parser->error = false;
}
@@ -1581,6 +1624,8 @@ static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
tree attrs = NULL,
struct oacc_routine_data * = NULL,
bool * = NULL);
+static bool c_parser_handle_statement_omp_attributes (c_parser *, tree &,
+ bool *);
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 *);
@@ -1871,12 +1916,12 @@ c_parser_translation_unit (c_parser *parser)
"#pragma omp end declare target");
vec_safe_truncate (current_omp_declare_target_attribute, 0);
}
- if (current_omp_begin_assumes)
+ if (vec_safe_length (current_omp_begin_assumes))
{
if (!errorcount)
error ("%qs without corresponding %qs",
"#pragma omp begin assumes", "#pragma omp end assumes");
- current_omp_begin_assumes = 0;
+ vec_safe_truncate (current_omp_begin_assumes, 0);
}
#if ENABLE_ANALYZER
@@ -1999,6 +2044,8 @@ c_parser_external_declaration (c_parser *parser)
}
}
+static void c_parser_handle_directive_omp_attributes (tree &, vec<c_token> *&,
+ vec<c_token> *);
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);
@@ -2301,6 +2348,22 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
bool handled_assume = false;
+ if (specs->attrs
+ && !nested
+ && specs->typespec_kind == ctsk_none
+ && c_parser_handle_statement_omp_attributes (parser, specs->attrs,
+ NULL))
+ {
+ if (specs->attrs)
+ c_warn_unused_attributes (specs->attrs);
+ while (parser->in_omp_attribute_pragma)
+ {
+ gcc_assert (c_parser_next_token_is (parser, CPP_PRAGMA));
+ c_parser_pragma (parser, pragma_external, NULL);
+ }
+ c_parser_consume_token (parser);
+ return;
+ }
if (specs->typespec_kind == ctsk_none
&& lookup_attribute ("gnu", "assume", specs->attrs))
{
@@ -2440,6 +2503,10 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
warning_at (here, OPT_Wattributes,
"%<assume%> attribute not followed by %<;%>");
+ auto_vec<c_token> omp_declare_simd_attr_clauses;
+ c_parser_handle_directive_omp_attributes (specs->attrs,
+ omp_declare_simd_clauses,
+ &omp_declare_simd_attr_clauses);
pending_xref_error ();
prefix_attrs = specs->attrs;
all_prefix_attrs = prefix_attrs;
@@ -2451,6 +2518,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
timevar_id_t tv;
tree fnbody = NULL_TREE;
tree underspec_name = NULL_TREE;
+ auto_vec<c_token> omp_dsimd_idattr_clauses;
/* 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
@@ -2468,6 +2536,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
c_parser_skip_to_end_of_block_or_statement (parser);
return;
}
+ if (flag_openmp || flag_openmp_simd)
+ {
+ struct c_declarator *d = declarator;
+ while (d->kind != cdk_id)
+ d = d->declarator;
+ vec<c_token> *dummy = NULL;
+ c_parser_handle_directive_omp_attributes (d->u.id.attrs, dummy,
+ &omp_dsimd_idattr_clauses);
+ }
if (gnu_auto_type_p && declarator->kind != cdk_id)
{
error_at (here,
@@ -2607,6 +2684,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
if (omp_declare_simd_clauses)
c_finish_omp_declare_simd (parser, d, NULL_TREE,
omp_declare_simd_clauses);
+ if (!omp_dsimd_idattr_clauses.is_empty ())
+ c_finish_omp_declare_simd (parser, d, NULL_TREE,
+ &omp_dsimd_idattr_clauses);
}
else
{
@@ -2628,6 +2708,10 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
if (!specs->constexpr_p && omp_declare_simd_clauses)
c_finish_omp_declare_simd (parser, d, NULL_TREE,
omp_declare_simd_clauses);
+ if (!specs->constexpr_p
+ && !omp_dsimd_idattr_clauses.is_empty ())
+ c_finish_omp_declare_simd (parser, d, NULL_TREE,
+ &omp_dsimd_idattr_clauses);
start_init (d, asm_name,
TREE_STATIC (d) || specs->constexpr_p,
specs->constexpr_p, &richloc);
@@ -2646,6 +2730,10 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
if (omp_declare_simd_clauses)
c_finish_omp_declare_simd (parser, d, NULL_TREE,
omp_declare_simd_clauses);
+ if (!specs->constexpr_p
+ && !omp_dsimd_idattr_clauses.is_empty ())
+ c_finish_omp_declare_simd (parser, d, NULL_TREE,
+ &omp_dsimd_idattr_clauses);
}
finish_init ();
}
@@ -2715,7 +2803,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
warn_parm_array_mismatch (lastloc, d, parms);
}
}
- if (omp_declare_simd_clauses)
+ if (omp_declare_simd_clauses
+ || !omp_dsimd_idattr_clauses.is_empty ())
{
tree parms = NULL_TREE;
if (d && TREE_CODE (d) == FUNCTION_DECL)
@@ -2732,8 +2821,13 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
}
if (parms)
temp_store_parm_decls (d, parms);
- c_finish_omp_declare_simd (parser, d, parms,
- omp_declare_simd_clauses);
+ if (omp_declare_simd_clauses)
+ c_finish_omp_declare_simd (parser, d, parms,
+ omp_declare_simd_clauses);
+ if (!specs->constexpr_p
+ && !omp_dsimd_idattr_clauses.is_empty ())
+ c_finish_omp_declare_simd (parser, d, parms,
+ &omp_dsimd_idattr_clauses);
if (parms)
temp_pop_parm_decls ();
}
@@ -2878,6 +2972,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
if (omp_declare_simd_clauses)
c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
omp_declare_simd_clauses);
+ if (!omp_dsimd_idattr_clauses.is_empty ())
+ c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
+ &omp_dsimd_idattr_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;
@@ -5430,6 +5527,134 @@ c_parser_balanced_token_sequence (c_parser *parser)
}
}
+static bool c_parser_check_balanced_raw_token_sequence (c_parser *,
+ unsigned int *);
+
+/* Parse arguments of omp::directive or omp::decl attribute.
+
+ directive-name ,[opt] clause-list[opt]
+
+ For directive just remember the tokens in a vector for subsequent
+ parsing. */
+
+static void
+c_parser_omp_directive_args (c_parser *parser, tree attribute, bool decl_p)
+{
+ unsigned int n = 1;
+ c_token *first = c_parser_peek_token (parser);
+ if (!c_parser_check_balanced_raw_token_sequence (parser, &n)
+ || (c_parser_peek_nth_token_raw (parser, n)->type
+ != CPP_CLOSE_PAREN))
+ {
+ c_parser_balanced_token_sequence (parser);
+ TREE_VALUE (attribute) = NULL_TREE;
+ return;
+ }
+ if (n == 1)
+ {
+ error_at (first->location, "expected OpenMP directive name");
+ TREE_VALUE (attribute) = NULL_TREE;
+ return;
+ }
+ vec<c_token, va_gc> *v;
+ vec_alloc (v, n - 1);
+ for (--n; n; --n)
+ {
+ c_token *tok = c_parser_peek_token (parser);
+ v->quick_push (*tok);
+ c_parser_consume_token (parser);
+ }
+ tree arg = make_node (C_TOKEN_VEC);
+ C_TOKEN_VEC_TOKENS (arg) = v;
+ if (decl_p)
+ TREE_PUBLIC (arg) = 1;
+ TREE_VALUE (attribute) = tree_cons (NULL_TREE, arg, TREE_VALUE (attribute));
+}
+
+/* Parse arguments of omp::sequence attribute.
+
+ omp::[opt] directive-attr [ , omp::[opt] directive-attr ]... */
+
+static void
+c_parser_omp_sequence_args (c_parser *parser, tree attribute)
+{
+ do
+ {
+ c_token *token = c_parser_peek_token (parser);
+ if (token->type == CPP_NAME
+ && strcmp (IDENTIFIER_POINTER (token->value), "omp") == 0
+ && c_parser_peek_2nd_token (parser)->type == CPP_SCOPE)
+ {
+ c_parser_consume_token (parser);
+ c_parser_consume_token (parser);
+ token = c_parser_peek_token (parser);
+ }
+ bool directive = false;
+ const char *p;
+ if (token->type != CPP_NAME)
+ p = "";
+ else
+ p = IDENTIFIER_POINTER (token->value);
+ if (strcmp (p, "directive") == 0)
+ directive = true;
+ else if (strcmp (p, "sequence") != 0)
+ {
+ error_at (token->location, "expected %<directive%> or %<sequence%>");
+ unsigned nesting_depth = 0;
+
+ while (true)
+ {
+ /* Peek at the next token. */
+ token = c_parser_peek_token (parser);
+ /* If we've reached the token we want, consume it and stop. */
+ if ((token->type == CPP_CLOSE_PAREN || token->type == CPP_COMMA)
+ && !nesting_depth)
+ break;
+ /* If we've run out of tokens, stop. */
+ if (token->type == CPP_EOF)
+ break;
+ if (token->type == CPP_PRAGMA_EOL && parser->in_pragma)
+ break;
+ 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);
+ }
+ if (c_parser_next_token_is_not (parser, CPP_COMMA))
+ break;
+ c_parser_consume_token (parser);
+ continue;
+ }
+ c_parser_consume_token (parser);
+ matching_parens parens;
+ if (parens.require_open (parser))
+ {
+ if (directive)
+ c_parser_omp_directive_args (parser, attribute, false);
+ else
+ c_parser_omp_sequence_args (parser, attribute);
+ parens.skip_until_found_close (parser);
+ if (c_parser_next_token_is_not (parser, CPP_COMMA))
+ break;
+ c_parser_consume_token (parser);
+ }
+ else if (c_parser_next_token_is_not (parser, CPP_COMMA))
+ break;
+ else
+ c_parser_consume_token (parser);
+ }
+ while (1);
+}
+
/* Parse standard (C2X) attributes (including GNU attributes in the
gnu:: namespace).
@@ -5512,7 +5737,19 @@ c_parser_std_attribute (c_parser *parser, bool for_tm,
/* 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;
+ {
+ if ((flag_openmp || flag_openmp_simd)
+ && ns
+ && is_attribute_p ("omp", ns)
+ && (is_attribute_p ("directive", name)
+ || is_attribute_p ("sequence", name)
+ || is_attribute_p ("decl", name)))
+ {
+ error ("%<omp::%E%> attribute requires argument", name);
+ return error_mark_node;
+ }
+ goto out;
+ }
{
location_t open_loc = c_parser_peek_token (parser)->location;
matching_parens parens;
@@ -5549,7 +5786,37 @@ c_parser_std_attribute (c_parser *parser, bool for_tm,
require_string, assume_attr, false);
}
else
- c_parser_balanced_token_sequence (parser);
+ {
+ if ((flag_openmp || flag_openmp_simd)
+ && ns
+ && is_attribute_p ("omp", ns))
+ {
+ if (is_attribute_p ("directive", name))
+ {
+ c_parser_omp_directive_args (parser, attribute, false);
+ parens.skip_until_found_close (parser);
+ return attribute;
+ }
+/* else if (is_attribute_p ("decl", name))
+ {
+ TREE_VALUE (TREE_PURPOSE (attribute))
+ = get_identifier ("directive");
+ c_parser_omp_directive_args (parser, attribute, true);
+ parens.skip_until_found_close (parser);
+ return attribute;
+ } */
+ else if (is_attribute_p ("sequence", name))
+ {
+ TREE_VALUE (TREE_PURPOSE (attribute))
+ = get_identifier ("directive");
+ c_parser_omp_sequence_args (parser, attribute);
+ parens.skip_until_found_close (parser);
+ TREE_VALUE (attribute) = nreverse (TREE_VALUE (attribute));
+ return attribute;
+ }
+ }
+ c_parser_balanced_token_sequence (parser);
+ }
parens.require_close (parser);
}
out:
@@ -6322,6 +6589,350 @@ add_structured_block_stmt (tree sl)
add_stmt (build1 (OMP_STRUCTURED_BLOCK, void_type_node, sl));
}
+struct c_omp_attribute_data
+{
+ vec<c_token, va_gc> *tokens;
+ const c_omp_directive *dir;
+ c_omp_directive_kind kind;
+};
+
+/* Handle omp::directive and omp::sequence attributes in ATTRS
+ (if any) at the start of a statement or in attribute-declaration. */
+
+static bool
+c_parser_handle_statement_omp_attributes (c_parser *parser, tree &attrs,
+ bool *have_std_attrs)
+{
+ if (!flag_openmp && !flag_openmp_simd)
+ return false;
+
+ auto_vec<c_omp_attribute_data, 16> vd;
+ int cnt = 0;
+ int tokens = 0;
+ bool bad = false;
+ for (tree *pa = &attrs; *pa; )
+ if (is_attribute_namespace_p ("omp", *pa)
+ && is_attribute_p ("directive", get_attribute_name (*pa)))
+ {
+ cnt++;
+ for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a))
+ {
+ tree d = TREE_VALUE (a);
+ gcc_assert (TREE_CODE (d) == C_TOKEN_VEC);
+ vec<c_token, va_gc> *toks = C_TOKEN_VEC_TOKENS (d);
+ c_token *first = toks->address ();
+ c_token *last = first + toks->length ();
+ if (parser->omp_attrs_forbidden_p)
+ {
+ error_at (first->location,
+ "mixing OpenMP directives with attribute and pragma "
+ "syntax on the same statement");
+ parser->omp_attrs_forbidden_p = false;
+ bad = true;
+ }
+ else if (TREE_PUBLIC (d))
+ {
+ error_at (first->location,
+ "OpenMP %<omp::decl%> attribute on a statement");
+ bad = true;
+ }
+ const char *directive[3] = {};
+ for (int i = 0; i < 3; i++)
+ {
+ tree id = NULL_TREE;
+ if (first + i == last)
+ break;
+ if (first[i].type == CPP_NAME)
+ id = first[i].value;
+ else if (first[i].type == CPP_KEYWORD)
+ id = ridpointers[(int) first[i].keyword];
+ else
+ break;
+ directive[i] = IDENTIFIER_POINTER (id);
+ }
+ const c_omp_directive *dir = NULL;
+ if (directive[0])
+ dir = c_omp_categorize_directive (directive[0], directive[1],
+ directive[2]);
+ if (dir == NULL)
+ {
+ error_at (first->location,
+ "unknown OpenMP directive name in %qs attribute "
+ "argument",
+ TREE_PUBLIC (d) ? "omp::decl" : "omp::directive");
+ continue;
+ }
+ c_omp_directive_kind kind = dir->kind;
+ if (dir->id == PRAGMA_OMP_ORDERED)
+ {
+ /* ordered is C_OMP_DIR_CONSTRUCT only if it doesn't contain
+ depend/doacross clause. */
+ if (directive[1]
+ && (strcmp (directive[1], "depend") == 0
+ || strcmp (directive[1], "doacross") == 0))
+ kind = C_OMP_DIR_STANDALONE;
+ else if (first + 2 < last
+ && first[1].type == CPP_COMMA
+ && first[2].type == CPP_NAME
+ && (strcmp (IDENTIFIER_POINTER (first[2].value),
+ "depend") == 0
+ || strcmp (IDENTIFIER_POINTER (first[2].value),
+ "doacross") == 0))
+ kind = C_OMP_DIR_STANDALONE;
+ }
+ else if (dir->id == PRAGMA_OMP_ERROR)
+ {
+ /* error with at(execution) clause is C_OMP_DIR_STANDALONE. */
+ int paren_depth = 0;
+ for (int i = 1; first + i < last; i++)
+ if (first[i].type == CPP_OPEN_PAREN)
+ paren_depth++;
+ else if (first[i].type == CPP_CLOSE_PAREN)
+ paren_depth--;
+ else if (paren_depth == 0
+ && first + i + 2 < last
+ && first[i].type == CPP_NAME
+ && first[i + 1].type == CPP_OPEN_PAREN
+ && first[i + 2].type == CPP_NAME
+ && !strcmp (IDENTIFIER_POINTER (first[i].value),
+ "at")
+ && !strcmp (IDENTIFIER_POINTER (first[i
+ + 2].value),
+ "execution"))
+ {
+ kind = C_OMP_DIR_STANDALONE;
+ break;
+ }
+ }
+ c_omp_attribute_data v = { toks, dir, kind };
+ vd.safe_push (v);
+ if (flag_openmp || dir->simd)
+ tokens += (last - first) + 1;
+ }
+ c_omp_attribute_data v = {};
+ vd.safe_push (v);
+ *pa = TREE_CHAIN (*pa);
+ }
+ else
+ pa = &TREE_CHAIN (*pa);
+
+ if (bad)
+ {
+ fail:
+ if (have_std_attrs && attrs == NULL)
+ *have_std_attrs = false;
+ return false;
+ }
+
+ unsigned int i;
+ c_omp_attribute_data *v;
+ c_omp_attribute_data *construct_seen = nullptr;
+ c_omp_attribute_data *standalone_seen = nullptr;
+ c_omp_attribute_data *prev_standalone_seen = nullptr;
+ FOR_EACH_VEC_ELT (vd, i, v)
+ if (v->tokens)
+ {
+ if (v->kind == C_OMP_DIR_CONSTRUCT && !construct_seen)
+ construct_seen = v;
+ else if (v->kind == C_OMP_DIR_STANDALONE && !standalone_seen)
+ standalone_seen = v;
+ }
+ else
+ {
+ if (standalone_seen && !prev_standalone_seen)
+ {
+ prev_standalone_seen = standalone_seen;
+ standalone_seen = nullptr;
+ }
+ }
+
+ if (cnt > 1 && construct_seen)
+ {
+ error_at ((*construct_seen->tokens)[0].location,
+ "OpenMP construct among %<omp::directive%> attributes"
+ " requires all %<omp::directive%> attributes on the"
+ " same statement to be in the same %<omp::sequence%>");
+ goto fail;
+ }
+ if (cnt > 1 && standalone_seen && prev_standalone_seen)
+ {
+ error_at ((*standalone_seen->tokens)[0].location,
+ "multiple OpenMP standalone directives among"
+ " %<omp::directive%> attributes must be all within the"
+ " same %<omp::sequence%>");
+ goto fail;
+ }
+
+ if (prev_standalone_seen)
+ standalone_seen = prev_standalone_seen;
+ if (standalone_seen
+ && !c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ error_at (standalone_seen->tokens->address ()->location,
+ "standalone OpenMP directives in %<omp::directive%> attribute"
+ " can only appear on an empty statement");
+ goto fail;
+ }
+ if (cnt && c_parser_next_token_is (parser, CPP_PRAGMA))
+ {
+ c_token *token = c_parser_peek_token (parser);
+ enum pragma_kind kind = token->pragma_kind;
+ if (kind >= PRAGMA_OMP__START_ && kind <= PRAGMA_OMP__LAST_)
+ {
+ error_at (token->location,
+ "mixing OpenMP directives with attribute and pragma "
+ "syntax on the same statement");
+ goto fail;
+ }
+ }
+
+ if (!tokens)
+ return false;
+
+ unsigned int tokens_avail = parser->tokens_avail;
+ gcc_assert (parser->tokens == &parser->tokens_buf[0]);
+
+ tokens++;
+ vec<c_token, va_gc> *toks = NULL;
+ vec_safe_reserve (toks, tokens, true);
+ FOR_EACH_VEC_ELT (vd, i, v)
+ {
+ if (!v->tokens)
+ continue;
+ if (!flag_openmp && !v->dir->simd)
+ continue;
+ c_token *first = v->tokens->address ();
+ c_token *last = first + v->tokens->length ();
+ c_token tok = {};
+ tok.type = CPP_PRAGMA;
+ tok.keyword = RID_MAX;
+ tok.pragma_kind = pragma_kind (v->dir->id);
+ tok.location = first->location;
+ toks->quick_push (tok);
+ while (++first < last)
+ toks->quick_push (*first);
+ tok = {};
+ tok.type = CPP_PRAGMA_EOL;
+ tok.keyword = RID_MAX;
+ tok.location = last[-1].location;
+ toks->quick_push (tok);
+ }
+
+ c_token tok = {};
+ tok.type = CPP_EOF;
+ tok.keyword = RID_MAX;
+ tok.location = toks->last ().location;
+ tok.flags = tokens_avail;
+ toks->quick_push (tok);
+
+ parser->tokens = toks->address ();
+ parser->tokens_avail = tokens;
+ parser->in_omp_attribute_pragma = toks;
+ return true;
+}
+
+/* Handle omp::directive and omp::sequence attributes in ATTRS
+ (if any) at the start or after declaration-id of a declaration. */
+
+static void
+c_parser_handle_directive_omp_attributes (tree &attrs,
+ vec<c_token> *&pragma_clauses,
+ vec<c_token> *attr_clauses)
+{
+ if (!flag_openmp && !flag_openmp_simd)
+ return;
+
+ for (tree *pa = &attrs; *pa; )
+ if (is_attribute_namespace_p ("omp", *pa)
+ && is_attribute_p ("directive", get_attribute_name (*pa)))
+ {
+ int cnt = 0;
+ for (tree *pa2 = &TREE_VALUE (*pa); *pa2; )
+ {
+ tree a = *pa2;
+ tree d = TREE_VALUE (a);
+ gcc_assert (TREE_CODE (d) == C_TOKEN_VEC);
+ vec<c_token, va_gc> *toks = C_TOKEN_VEC_TOKENS (d);
+ c_token *first = toks->address ();
+ c_token *last = first + toks->length ();
+ const char *directive[3] = {};
+ for (int i = 0; i < 3; i++)
+ {
+ tree id = NULL_TREE;
+ if (first + i == last)
+ break;
+ if (first[i].type == CPP_NAME)
+ id = first[i].value;
+ else if (first[i].type == CPP_KEYWORD)
+ id = ridpointers[(int) first[i].keyword];
+ else
+ break;
+ directive[i] = IDENTIFIER_POINTER (id);
+ }
+ const c_omp_directive *dir = NULL;
+ if (directive[0])
+ dir = c_omp_categorize_directive (directive[0], directive[1],
+ directive[2]);
+ if (dir == NULL)
+ {
+ error_at (first->location,
+ "unknown OpenMP directive name in "
+ "%qs attribute argument",
+ TREE_PUBLIC (d) ? "omp::decl" : "omp::directive");
+ *pa2 = TREE_CHAIN (a);
+ }
+ else if (dir->id == PRAGMA_OMP_DECLARE
+ && (strcmp (directive[1], "simd") == 0
+ || strcmp (directive[1], "variant") == 0))
+ {
+ if (pragma_clauses)
+ {
+ error_at (first->location,
+ "mixing OpenMP directives with attribute and "
+ "pragma syntax on the same declaration");
+ for (pa = &attrs; *pa; )
+ if (is_attribute_namespace_p ("omp", *pa)
+ && is_attribute_p ("directive",
+ get_attribute_name (*pa)))
+ *pa = TREE_CHAIN (*pa);
+ else
+ pa = &TREE_CHAIN (*pa);
+ return;
+ }
+ ++cnt;
+ attr_clauses->reserve (attr_clauses->length ()
+ + toks->length () + 2);
+ for (++first; first < last; ++first)
+ attr_clauses->quick_push (*first);
+ c_token tok = {};
+ tok.type = CPP_PRAGMA_EOL;
+ tok.keyword = RID_MAX;
+ tok.location = last[-1].location;
+ attr_clauses->quick_push (tok);
+ *pa2 = TREE_CHAIN (a);
+ }
+ else
+ pa2 = &TREE_CHAIN (a);
+ }
+ if (cnt && TREE_VALUE (*pa) == NULL_TREE)
+ *pa = TREE_CHAIN (*pa);
+ else
+ pa = &TREE_CHAIN (*pa);
+ }
+ else
+ pa = &TREE_CHAIN (*pa);
+ if (attr_clauses->length ())
+ {
+ c_token tok = {};
+ tok.type = CPP_EOF;
+ tok.keyword = RID_MAX;
+ tok.location = attr_clauses->last ().location;
+ attr_clauses->quick_push (tok);
+ attr_clauses->quick_push (tok);
+ pragma_clauses = attr_clauses;
+ }
+}
+
/* 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). */
@@ -6495,7 +7106,10 @@ c_parser_compound_statement_nostart (c_parser *parser)
}
else if (c_parser_next_tokens_start_declaration (parser)
|| (have_std_attrs
- && c_parser_next_token_is (parser, CPP_SEMICOLON)))
+ && !c_parser_handle_statement_omp_attributes
+ (parser, std_attrs, &have_std_attrs)
+ && c_parser_next_token_is (parser, CPP_SEMICOLON)
+ && (have_std_attrs = true)))
{
if (last_label)
pedwarn_c11 (c_parser_peek_token (parser)->location, OPT_Wpedantic,
@@ -6569,8 +7183,10 @@ c_parser_compound_statement_nostart (c_parser *parser)
}
else if (c_parser_next_token_is (parser, CPP_PRAGMA))
{
- if (have_std_attrs)
+ if (have_std_attrs && !parser->in_omp_attribute_pragma)
c_parser_error (parser, "expected declaration or statement");
+ else if (std_attrs)
+ c_warn_unused_attributes (std_attrs);
/* 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
@@ -6588,7 +7204,7 @@ c_parser_compound_statement_nostart (c_parser *parser)
check_omp_intervening_code (parser);
}
if (omp_for_parse_state)
- omp_for_parse_state->want_nested_loop = want_nested_loop;
+ omp_for_parse_state->want_nested_loop = want_nested_loop;
}
else if (c_parser_next_token_is (parser, CPP_EOF))
{
@@ -6666,13 +7282,10 @@ c_parser_compound_statement_nostart (c_parser *parser)
static void
c_parser_all_labels (c_parser *parser)
{
+ bool have_std_attrs;
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");
- }
+ if ((have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1)))
+ std_attrs = c_parser_std_attribute_specifier_sequence (parser);
while (c_parser_next_token_is_keyword (parser, RID_CASE)
|| c_parser_next_token_is_keyword (parser, RID_DEFAULT)
|| (c_parser_next_token_is (parser, CPP_NAME)
@@ -6680,15 +7293,20 @@ c_parser_all_labels (c_parser *parser)
{
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 ((have_std_attrs = c_parser_nth_token_starts_std_attributes (parser,
+ 1)))
+ std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+ }
+ if (std_attrs
+ && (!c_parser_handle_statement_omp_attributes (parser, std_attrs, &have_std_attrs)
+ || std_attrs))
+ {
+ if (have_std_attrs && c_parser_next_token_is (parser, CPP_SEMICOLON))
+ c_parser_error (parser, "expected statement");
+ c_warn_unused_attributes (std_attrs);
}
- if (std_attrs)
- c_warn_unused_attributes (std_attrs);
+ else if (have_std_attrs && c_parser_next_token_is (parser, CPP_SEMICOLON))
+ c_parser_error (parser, "expected statement");
}
/* Parse a label (C90 6.6.1, C99 6.8.1, C11 6.8.1).
@@ -6935,6 +7553,7 @@ 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;
+ parser->omp_attrs_forbidden_p = false;
c_parser_statement_after_labels (parser, if_p, NULL);
}
@@ -14206,6 +14825,7 @@ c_parser_omp_variable_list (c_parser *parser,
bool array_section_p;
auto_vec<c_token> tokens;
unsigned int tokens_avail = 0;
+ c_token *saved_tokens = NULL;
bool first = true;
while (1)
@@ -14285,8 +14905,8 @@ c_parser_omp_variable_list (c_parser *parser,
tokens.safe_push (eof_token);
tokens.safe_push (eof_token);
+ saved_tokens = parser->tokens;
tokens_avail = parser->tokens_avail;
- gcc_assert (parser->tokens == &parser->tokens_buf[0]);
parser->tokens = tokens.address ();
parser->tokens_avail = tokens.length ();
}
@@ -14503,7 +15123,7 @@ c_parser_omp_variable_list (c_parser *parser,
if (kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY)
{
- parser->tokens = &parser->tokens_buf[0];
+ parser->tokens = saved_tokens;
parser->tokens_avail = tokens_avail;
}
if (c_parser_next_token_is_not (parser, CPP_COMMA))
@@ -18677,6 +19297,7 @@ static tree
c_parser_omp_structured_block (c_parser *parser, bool *if_p)
{
tree stmt = push_stmt_list ();
+ parser->omp_attrs_forbidden_p = true;
c_parser_statement (parser, if_p);
return pop_stmt_list (stmt);
}
@@ -20786,6 +21407,79 @@ c_parser_omp_flush (c_parser *parser)
c_finish_omp_flush (loc, mo);
}
+/* Return true if next tokens contain a standard attribute that contains
+ omp::directive (DIRECTIVE). */
+
+static bool
+c_parser_omp_section_scan (c_parser *parser, const char *directive,
+ bool tentative)
+{
+ if (!c_parser_nth_token_starts_std_attributes (parser, 1))
+ return false;
+ unsigned int n = 3;
+ 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);
+ if (token->type != CPP_CLOSE_SQUARE)
+ return false;
+ if (n < 9)
+ return false;
+ if (c_parser_peek_nth_token_raw (parser, 3)->type == CPP_NAME
+ && c_parser_peek_nth_token_raw (parser, 4)->type == CPP_OPEN_PAREN
+ && c_parser_peek_nth_token_raw (parser, 5)->type == CPP_NAME)
+ {
+ tree first = c_parser_peek_nth_token_raw (parser, 3)->value;
+ tree second = c_parser_peek_nth_token_raw (parser, 5)->value;
+ if (strcmp (IDENTIFIER_POINTER (first), "directive")
+ && strcmp (IDENTIFIER_POINTER (first), "__directive__"))
+ return false;
+ if (strcmp (IDENTIFIER_POINTER (second), directive))
+ return false;
+ }
+ if (tentative)
+ return true;
+ location_t first_loc = c_parser_peek_token (parser)->location;
+ location_t last_loc = c_parser_peek_nth_token_raw (parser, n + 1)->location;
+ location_t middle_loc = UNKNOWN_LOCATION;
+ tree std_attrs = c_parser_std_attribute_specifier_sequence (parser);
+ bool seen = false;
+ int cnt = 0;
+ for (tree attr = std_attrs; attr; attr = TREE_CHAIN (attr))
+ if (is_attribute_namespace_p ("omp", attr)
+ && is_attribute_p ("directive", get_attribute_name (attr)))
+ {
+ for (tree a = TREE_VALUE (attr); a; a = TREE_CHAIN (a))
+ {
+ tree d = TREE_VALUE (a);
+ gcc_assert (TREE_CODE (d) == C_TOKEN_VEC);
+ c_token *first = C_TOKEN_VEC_TOKENS (d)->address ();
+ cnt++;
+ if (first->type == CPP_NAME
+ && strcmp (IDENTIFIER_POINTER (first->value),
+ directive) == 0)
+ {
+ seen = true;
+ if (middle_loc == UNKNOWN_LOCATION)
+ middle_loc = first->location;
+ }
+ }
+ }
+ if (!seen)
+ return false;
+ if (cnt != 1 || TREE_CHAIN (std_attrs))
+ {
+ error_at (make_location (first_loc, last_loc, middle_loc),
+ "%<[[omp::directive(%s)]]%> must be the only specified "
+ "attribute on a statement", directive);
+ return false;
+ }
+ c_parser_handle_statement_omp_attributes (parser, std_attrs, NULL);
+ return true;
+}
+
/* Parse an OpenMP structured block sequence. KIND is the corresponding
separating directive. */
@@ -20805,6 +21499,13 @@ c_parser_omp_structured_block_sequence (c_parser *parser,
if (kind != PRAGMA_NONE
&& c_parser_peek_token (parser)->pragma_kind == kind)
break;
+
+ if (kind != PRAGMA_NONE
+ && c_parser_omp_section_scan (parser,
+ kind == PRAGMA_OMP_SCAN
+ ? "scan" : "section", false))
+ break;
+
c_parser_statement (parser, NULL);
}
while (1);
@@ -21794,7 +22495,8 @@ c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser)
stmt = push_stmt_list ();
- if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION)
+ if (c_parser_peek_token (parser)->pragma_kind != PRAGMA_OMP_SECTION
+ && !c_parser_omp_section_scan (parser, "section", true))
{
substmt = c_parser_omp_structured_block_sequence (parser,
PRAGMA_OMP_SECTION);
@@ -21811,6 +22513,7 @@ c_parser_omp_sections_scope (location_t sections_loc, c_parser *parser)
break;
loc = c_parser_peek_token (parser)->location;
+ c_parser_omp_section_scan (parser, "section", false);
if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_SECTION)
{
c_parser_consume_pragma (parser);
@@ -22072,6 +22775,7 @@ c_parser_omp_parallel (location_t loc, c_parser *parser,
}
block = c_begin_omp_parallel ();
+ parser->omp_attrs_forbidden_p = true;
c_parser_statement (parser, if_p);
stmt = c_finish_omp_parallel (loc, clauses, block);
@@ -22167,6 +22871,7 @@ c_parser_omp_task (location_t loc, c_parser *parser, bool *if_p)
"#pragma omp task");
block = c_begin_omp_task ();
+ parser->omp_attrs_forbidden_p = true;
c_parser_statement (parser, if_p);
return c_finish_omp_task (loc, clauses, block);
}
@@ -23205,6 +23910,13 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
IDENTIFIER_POINTER (kind));
break;
case pragma_compound:
+ bool have_std_attrs;
+ tree std_attrs;
+ 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);
+ else
+ std_attrs = NULL_TREE;
if (c_parser_next_token_is (parser, CPP_KEYWORD)
&& c_parser_peek_token (parser)->keyword == RID_EXTENSION)
{
@@ -23213,10 +23925,12 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
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))
+ 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, NULL, &clauses);
+ true, NULL, &clauses,
+ have_std_attrs, std_attrs);
restore_extension_diagnostics (ext);
break;
}
@@ -23225,7 +23939,8 @@ c_parser_omp_declare_simd (c_parser *parser, enum pragma_context context)
else if (c_parser_next_tokens_start_declaration (parser))
{
c_parser_declaration_or_fndef (parser, true, true, true, true, true,
- NULL, &clauses);
+ NULL, &clauses, have_std_attrs,
+ std_attrs);
break;
}
error ("%<#pragma omp declare %s%> must be followed by "
@@ -23753,8 +24468,8 @@ c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
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);
+ gcc_assert (token->type == CPP_NAME);
+ kind = IDENTIFIER_POINTER (token->value);
c_parser_consume_token (parser);
parser->in_pragma = true;
@@ -23820,8 +24535,9 @@ c_parser_omp_declare_target (c_parser *parser)
}
else
{
+ bool attr_syntax = parser->in_omp_attribute_pragma != NULL;
c_parser_skip_to_pragma_eol (parser);
- c_omp_declare_target_attr attr = { -1 };
+ c_omp_declare_target_attr attr = { attr_syntax, -1 };
vec_safe_push (current_omp_declare_target_attribute, attr);
return;
}
@@ -23928,6 +24644,7 @@ c_parser_omp_begin (c_parser *parser)
if (strcmp (p, "target") == 0)
{
c_parser_consume_token (parser);
+ bool attr_syntax = parser->in_omp_attribute_pragma != NULL;
tree clauses
= c_parser_omp_all_clauses (parser,
OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK,
@@ -23936,7 +24653,7 @@ c_parser_omp_begin (c_parser *parser)
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);
- c_omp_declare_target_attr attr = { device_type };
+ c_omp_declare_target_attr attr = { attr_syntax, device_type };
vec_safe_push (current_omp_declare_target_attribute, attr);
}
else
@@ -23948,8 +24665,10 @@ c_parser_omp_begin (c_parser *parser)
else if (strcmp (p, "assumes") == 0)
{
c_parser_consume_token (parser);
+ bool attr_syntax = parser->in_omp_attribute_pragma != NULL;
c_parser_omp_assumption_clauses (parser, false);
- current_omp_begin_assumes++;
+ struct c_omp_begin_assumes_data a = { attr_syntax };
+ vec_safe_push (current_omp_begin_assumes, a);
}
else
{
@@ -23985,23 +24704,61 @@ c_parser_omp_end (c_parser *parser)
c_parser_skip_to_pragma_eol (parser);
return;
}
+ bool attr_syntax = parser->in_omp_attribute_pragma != NULL;
c_parser_skip_to_pragma_eol (parser);
if (!vec_safe_length (current_omp_declare_target_attribute))
error_at (loc, "%<#pragma omp end declare target%> without "
"corresponding %<#pragma omp declare target%> or "
"%<#pragma omp begin declare target%>");
else
- current_omp_declare_target_attribute->pop ();
+ {
+ c_omp_declare_target_attr
+ a = current_omp_declare_target_attribute->pop ();
+ if (a.attr_syntax != attr_syntax)
+ {
+ if (a.attr_syntax)
+ error_at (loc,
+ "%qs in attribute syntax terminated "
+ "with %qs in pragma syntax",
+ a.device_type >= 0 ? "begin declare target"
+ : "declare target",
+ "end declare target");
+ else
+ error_at (loc,
+ "%qs in pragma syntax terminated "
+ "with %qs in attribute syntax",
+ a.device_type >= 0 ? "begin declare target"
+ : "declare target",
+ "end declare target");
+ }
+ }
}
else if (strcmp (p, "assumes") == 0)
{
c_parser_consume_token (parser);
+ bool attr_syntax = parser->in_omp_attribute_pragma != NULL;
c_parser_skip_to_pragma_eol (parser);
- if (!current_omp_begin_assumes)
+ if (!vec_safe_length (current_omp_begin_assumes))
error_at (loc, "%qs without corresponding %qs",
"#pragma omp end assumes", "#pragma omp begin assumes");
else
- current_omp_begin_assumes--;
+ {
+ c_omp_begin_assumes_data
+ a = current_omp_begin_assumes->pop ();
+ if (a.attr_syntax != attr_syntax)
+ {
+ if (a.attr_syntax)
+ error_at (loc,
+ "%qs in attribute syntax terminated "
+ "with %qs in pragma syntax",
+ "begin assumes", "end assumes");
+ else
+ error_at (loc,
+ "%qs in pragma syntax terminated "
+ "with %qs in attribute syntax",
+ "begin assumes", "end assumes");
+ }
+ }
}
else
{
@@ -24022,6 +24779,7 @@ static void
c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context)
{
unsigned int tokens_avail = 0, i;
+ c_token *saved_tokens = NULL;
vec<tree> types = vNULL;
vec<c_token> clauses = vNULL;
enum tree_code reduc_code = ERROR_MARK;
@@ -24192,8 +24950,8 @@ c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context)
int errs = errorcount;
FOR_EACH_VEC_ELT (types, i, type)
{
+ saved_tokens = parser->tokens;
tokens_avail = parser->tokens_avail;
- gcc_assert (parser->tokens == &parser->tokens_buf[0]);
if (!clauses.is_empty ())
{
parser->tokens = clauses.address ();
@@ -24354,7 +25112,7 @@ c_parser_omp_declare_reduction (c_parser *parser, enum pragma_context context)
if (!clauses.is_empty ())
{
- parser->tokens = &parser->tokens_buf[0];
+ parser->tokens = saved_tokens;
parser->tokens_avail = tokens_avail;
}
if (bad)