aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
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
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')
-rw-r--r--gcc/c/c-decl.cc82
-rw-r--r--gcc/c/c-lang.cc2
-rw-r--r--gcc/c/c-lang.h10
-rw-r--r--gcc/c/c-objc-common.h2
-rw-r--r--gcc/c/c-parser.cc840
-rw-r--r--gcc/c/c-parser.h11
-rw-r--r--gcc/c/c-tree.def31
-rw-r--r--gcc/c/c-tree.h2
8 files changed, 933 insertions, 47 deletions
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 7a145be..33fb64d 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -61,6 +61,7 @@ along with GCC; see the file COPYING3. If not see
#include "context.h" /* For 'g'. */
#include "omp-general.h"
#include "omp-offload.h" /* For offload_vars. */
+#include "c-parser.h"
#include "tree-pretty-print.h"
@@ -157,9 +158,10 @@ static bool undef_nested_function;
the attribute lists. */
vec<c_omp_declare_target_attr, va_gc> *current_omp_declare_target_attribute;
-/* If non-zero, we are inside of
- #pragma omp begin assumes ... #pragma omp end assumes region. */
-int current_omp_begin_assumes;
+/* Vector of
+ #pragma omp begin assumes ... #pragma omp end assumes regions
+ we are in. */
+vec<c_omp_begin_assumes_data, va_gc> *current_omp_begin_assumes;
/* Each c_binding structure describes one binding of an identifier to
a decl. All the decls in a scope - irrespective of namespace - are
@@ -323,17 +325,46 @@ i_label_binding (tree node)
#define I_LABEL_DECL(node) \
(I_LABEL_BINDING(node) ? I_LABEL_BINDING(node)->decl : 0)
+/* Used by C_TOKEN_VEC tree. */
+struct GTY (()) c_tree_token_vec {
+ struct tree_base base;
+ vec<c_token, va_gc> *tokens;
+};
+
+STATIC_ASSERT (sizeof (c_tree_token_vec) == sizeof (c_tree_token_vec_struct));
+STATIC_ASSERT (offsetof (c_tree_token_vec, tokens)
+ == offsetof (c_tree_token_vec_struct, tokens));
+
/* The resulting tree type. */
-union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE + 2 * (TREE_CODE (&%h.generic) == C_TOKEN_VEC)"),
chain_next ("(union lang_tree_node *) c_tree_chain_next (&%h.generic)"))) lang_tree_node
{
union tree_node GTY ((tag ("0"),
desc ("tree_node_structure (&%h)")))
generic;
struct lang_identifier GTY ((tag ("1"))) identifier;
+ struct c_tree_token_vec GTY ((tag ("2"))) c_token_vec;
};
+/* Langhook for tree_size. */
+size_t
+c_tree_size (enum tree_code code)
+{
+ gcc_checking_assert (code >= NUM_TREE_CODES);
+ switch (code)
+ {
+ case C_TOKEN_VEC: return sizeof (c_tree_token_vec);
+ default:
+ switch (TREE_CODE_CLASS (code))
+ {
+ case tcc_declaration: return sizeof (tree_decl_non_common);
+ case tcc_type: return sizeof (tree_type_non_common);
+ default: gcc_unreachable ();
+ }
+ }
+}
+
/* Track bindings and other things that matter for goto warnings. For
efficiency, we do not gather all the decls at the point of
definition. Instead, we point into the bindings structure. As
@@ -5335,6 +5366,49 @@ c_decl_attributes (tree *node, tree attributes, int flags)
}
}
+ if (flag_openmp || flag_openmp_simd)
+ {
+ bool diagnosed = false;
+ for (tree *pa = &attributes; *pa; )
+ {
+ if (is_attribute_namespace_p ("omp", *pa))
+ {
+ tree name = get_attribute_name (*pa);
+ if (is_attribute_p ("directive", name)
+ || is_attribute_p ("sequence", name)
+ || is_attribute_p ("decl", name))
+ {
+ const char *p = NULL;
+ if (TREE_VALUE (*pa) == NULL_TREE)
+ p = IDENTIFIER_POINTER (name);
+ for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a))
+ {
+ tree d = TREE_VALUE (a);
+ gcc_assert (TREE_CODE (d) == C_TOKEN_VEC);
+/* if (TREE_PUBLIC (d)
+ && (VAR_P (*decl)
+ || TREE_CODE (*decl) == FUNCTION_DECL)
+ && c_maybe_parse_omp_decl (*decl, d))
+ continue; */
+ p = TREE_PUBLIC (d) ? "decl" : "directive";
+ }
+ if (p && !diagnosed)
+ {
+ error ("%<omp::%s%> not allowed to be specified in "
+ "this context", p);
+ diagnosed = true;
+ }
+ if (p)
+ {
+ *pa = TREE_CHAIN (*pa);
+ continue;
+ }
+ }
+ }
+ pa = &TREE_CHAIN (*pa);
+ }
+ }
+
/* Look up the current declaration with all the attributes merged
so far so that attributes on the current declaration that's
about to be pushed that conflict with the former can be detected,
diff --git a/gcc/c/c-lang.cc b/gcc/c/c-lang.cc
index b4e0c8c..ddfd3e8 100644
--- a/gcc/c/c-lang.cc
+++ b/gcc/c/c-lang.cc
@@ -25,6 +25,8 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
#include "langhooks-def.h"
#include "c-objc-common.h"
+#include "c-family/c-pragma.h"
+#include "c-parser.h"
enum c_language_kind c_language = clk_c;
diff --git a/gcc/c/c-lang.h b/gcc/c/c-lang.h
index 4fea118..09f4d40 100644
--- a/gcc/c/c-lang.h
+++ b/gcc/c/c-lang.h
@@ -61,15 +61,21 @@ struct GTY(()) language_function {
};
struct GTY(()) c_omp_declare_target_attr {
+ bool attr_syntax;
int device_type;
};
-/* If non-zero, implicit "omp declare target" attribute is added into the
+struct GTY(()) c_omp_begin_assumes_data {
+ bool attr_syntax;
+};
+
+/* If non-empty, implicit "omp declare target" attribute is added into the
attribute lists. */
extern GTY(()) vec<c_omp_declare_target_attr, va_gc>
*current_omp_declare_target_attribute;
/* Similarly whether we are in between #pragma omp begin assumes and
#pragma omp end assumes (and how many times when nested). */
-extern GTY(()) int current_omp_begin_assumes;
+extern GTY(()) vec<c_omp_begin_assumes_data, va_gc>
+ *current_omp_begin_assumes;
#endif /* ! GCC_C_LANG_H */
diff --git a/gcc/c/c-objc-common.h b/gcc/c/c-objc-common.h
index d31dacb..ede451c 100644
--- a/gcc/c/c-objc-common.h
+++ b/gcc/c/c-objc-common.h
@@ -26,6 +26,8 @@ along with GCC; see the file COPYING3. If not see
#undef LANG_HOOKS_IDENTIFIER_SIZE
#define LANG_HOOKS_IDENTIFIER_SIZE C_SIZEOF_STRUCT_LANG_IDENTIFIER
+#undef LANG_HOOKS_TREE_SIZE
+#define LANG_HOOKS_TREE_SIZE c_tree_size
#undef LANG_HOOKS_FINISH
#define LANG_HOOKS_FINISH c_common_finish
#undef LANG_HOOKS_OPTION_LANG_MASK
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)
diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h
index 545f0f4..f99d144 100644
--- a/gcc/c/c-parser.h
+++ b/gcc/c/c-parser.h
@@ -80,6 +80,17 @@ struct GTY (()) c_token {
}
};
+/* This should have the same layout as c_tree_token_vec
+ in c-decl.cc, but for GTY reasons with ObjC can't be
+ GTY itself. */
+struct c_tree_token_vec_struct {
+ struct tree_base base;
+ vec<c_token, va_gc> *tokens;
+};
+
+#define C_TOKEN_VEC_TOKENS(NODE) \
+ (((struct c_tree_token_vec_struct *) TREE_CHECK (NODE, C_TOKEN_VEC))->tokens)
+
/* The parser. */
struct c_parser;
diff --git a/gcc/c/c-tree.def b/gcc/c/c-tree.def
new file mode 100644
index 0000000..de955ac
--- /dev/null
+++ b/gcc/c/c-tree.def
@@ -0,0 +1,31 @@
+/* This file contains the definitions and documentation for the
+ additional tree codes used in the GNU C compiler (see tree.def
+ for the standard codes).
+ Copyright (C) 2023 Free Software Foundation, Inc.
+
+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/>. */
+
+/* Tree nodes used in the C frontend only, not shared with C++ frontend. */
+
+/* Used to represent a vector of tokens for deferred parsing. */
+DEFTREECODE (C_TOKEN_VEC, "c_token_vec", tcc_exceptional, 0)
+
+/*
+Local variables:
+mode:c
+End:
+*/
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 2664354..df6f1ce 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -596,6 +596,7 @@ enum c_inline_static_type {
/* in c-parser.cc */
+struct c_tree_token_vec;
extern void c_parse_init (void);
extern bool c_keyword_starts_typename (enum rid keyword);
@@ -719,6 +720,7 @@ extern struct c_declspecs *declspecs_add_addrspace (location_t,
extern struct c_declspecs *declspecs_add_alignas (location_t,
struct c_declspecs *, tree);
extern struct c_declspecs *finish_declspecs (struct c_declspecs *);
+extern size_t c_tree_size (enum tree_code);
/* in c-objc-common.cc */
extern bool c_objc_common_init (void);