]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
openmp: Add support for omp::directive and omp::sequence attributes in C2X
authorJakub Jelinek <jakub@redhat.com>
Sat, 4 Nov 2023 08:09:08 +0000 (09:09 +0100)
committerJakub Jelinek <jakub@redhat.com>
Sat, 4 Nov 2023 08:09:08 +0000 (09:09 +0100)
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.

32 files changed:
gcc/c/c-decl.cc
gcc/c/c-lang.cc
gcc/c/c-lang.h
gcc/c/c-objc-common.h
gcc/c/c-parser.cc
gcc/c/c-parser.h
gcc/c/c-tree.def [new file with mode: 0644]
gcc/c/c-tree.h
gcc/cp/parser.cc
gcc/cp/parser.h
gcc/objc/objc-act.cc
gcc/objc/objc-act.h
gcc/objc/objc-lang.cc
gcc/testsuite/g++.dg/gomp/attrs-2.C
gcc/testsuite/gcc.dg/gomp/attrs-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-10.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-11.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-12.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-13.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-14.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-15.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-16.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-17.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-18.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-5.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-6.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-7.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-8.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/attrs-9.c [new file with mode: 0644]

index 7a145bed281f90f3fed474d65a95b3e6ba6a8956..33fb64db90d73d8be6413a951be796f6139c08f0 100644 (file)
@@ -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;
 \f
 /* 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,
index b4e0c8cfb8a2bac2bfe77ddbe7cc1faf00031bfd..ddfd3e80074a2012eb872643ba37dcaa088e60dc 100644 (file)
@@ -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;
 
index 4fea11855f1de53f77718f6097aa325cc6608814..09f4d40cda2d4a4d24423bb6136e12ae6321fe38 100644 (file)
@@ -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 */
index d31dacb9dd47bf46b0c36d9c791b2fad92656d72..ede451cef6bf8fbf44340fbe304b9526edb464e9 100644 (file)
@@ -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
index 5213a57a1eccf55d492b87e7468f1863002d64fc..20efd4d6e6b7eaf2f9bd3377eb3d2de94162d14a 100644 (file)
@@ -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)
index 545f0f4d9ebcbc70fc819f1ac6cd6ceb58bd94af..f99d14484da899005821609869d618370ce8cf5f 100644 (file)
@@ -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 (file)
index 0000000..de955ac
--- /dev/null
@@ -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:
+*/
index 2664354337bfdd19a39d8a56bbf501772db2e43c..df6f1cefd02afa30d90f7b71933ae7c61f993575 100644 (file)
@@ -596,6 +596,7 @@ enum c_inline_static_type {
 
 \f
 /* 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);
index 20e1836590653a666a0cddd12442279f6a88ad06..0fff9819a3a6b66fae57ec0a204f17a3d725f5f0 100644 (file)
@@ -43886,7 +43886,8 @@ cp_parser_omp_section_scan (cp_parser *parser, const char *directive,
       {
        tree first = cp_lexer_peek_nth_token (parser->lexer, i)->u.value;
        tree second = cp_lexer_peek_nth_token (parser->lexer, i + 2)->u.value;
-       if (strcmp (IDENTIFIER_POINTER (first), "directive"))
+       if (strcmp (IDENTIFIER_POINTER (first), "directive")
+           && strcmp (IDENTIFIER_POINTER (first), "__directive__"))
          continue;
        if (strcmp (IDENTIFIER_POINTER (second), directive) == 0)
          break;
index 9ba802194e45c401e314be8cb547080bb5ff8159..ee3afbaae04496d76abc014ab7a7cffed583a0bf 100644 (file)
@@ -408,7 +408,8 @@ struct GTY(()) cp_parser {
      identifiers) rather than an explicit template parameter list.  */
   bool fully_implicit_function_template_p;
 
-  /* TRUE if omp::directive or omp::sequence attributes may not appear.  */
+  /* TRUE if omp::directive, omp::decl or omp::sequence attributes may not
+     appear.  */
   bool omp_attrs_forbidden_p;
 
   /* Tracks the function's template parameter list when declaring a function
index 186a29cd27059d56cfabf66d18b12b130831bae6..fe19aa552779942ea1c7c0e768097732aa52f0c4 100644 (file)
@@ -10340,24 +10340,5 @@ objc_common_init_ts (void)
   MARK_TS_TYPED (PROPERTY_REF);
 }
 
-size_t
-objc_common_tree_size (enum tree_code code)
-{
-  switch (code)
-    {
-    case CLASS_METHOD_DECL:
-    case INSTANCE_METHOD_DECL:
-    case KEYWORD_DECL:
-    case PROPERTY_DECL:                        return sizeof (tree_decl_non_common);
-    case CLASS_INTERFACE_TYPE:
-    case CLASS_IMPLEMENTATION_TYPE:
-    case CATEGORY_INTERFACE_TYPE:
-    case CATEGORY_IMPLEMENTATION_TYPE:
-    case PROTOCOL_INTERFACE_TYPE:      return sizeof (tree_type_non_common);
-    default:
-      gcc_unreachable ();
-    }
-}
-
 
 #include "gt-objc-objc-act.h"
index e21ab52d8ca6d92748bcbbf7e0e200d896d89c0a..68f90296db33edcad7db75240f1da2e0c8ab3aa2 100644 (file)
@@ -738,8 +738,6 @@ struct objc_try_context
 
 extern tree objc_create_temporary_var (tree, const char *);
 
-size_t objc_common_tree_size (enum tree_code code);
-
 
 #define objc_is_object_id(TYPE) (OBJC_TYPE_NAME (TYPE) == objc_object_id)
 #define objc_is_class_id(TYPE) (OBJC_TYPE_NAME (TYPE) == objc_class_id)
index 89b3be48b9e75a1ba8accdde2f596bea6137a1eb..8e56de6a81cb8b254cb9ca5504fecedb6e8c3d7e 100644 (file)
@@ -44,8 +44,6 @@ enum c_language_kind c_language = clk_objc;
 #define LANG_HOOKS_GIMPLIFY_EXPR objc_gimplify_expr
 #undef LANG_HOOKS_INIT_TS
 #define LANG_HOOKS_INIT_TS objc_common_init_ts
-#undef LANG_HOOKS_TREE_SIZE
-#define LANG_HOOKS_TREE_SIZE objc_common_tree_size
 #undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE
 #define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE objc_get_sarif_source_language
 
index 7258d38c5a35a2244031d87f70ec351f80d27d9d..541afeb7ff4bb343e80ee338f1fa30b8b6a4c906 100644 (file)
@@ -1,4 +1,4 @@
-// { dg-do compile { target c++17 } }
+// { dg-do compile { target c++11 } }
 
 typedef enum omp_allocator_handle_t
 : __UINTPTR_TYPE__
@@ -162,7 +162,11 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s,
     private (p),firstprivate (f),if (parallel: i2),default(shared),shared(s),copyin(t),reduction(+:r),num_threads (nth),proc_bind(spread),
     lastprivate (l),allocate (f))]]
   {
+#if __cplusplus >= 201703L
     [[using omp:directive (section)]]
+#else
+    [[omp::directive (section)]]
+#endif
     {}
     [[omp::sequence (omp::directive (section))]]
     {}
@@ -176,11 +180,20 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s,
     {}
   }
   [[omp::directive (barrier)]];
+#if __cplusplus >= 201703L
   [[using omp:sequence (omp::directive (single, private (p),firstprivate (f),allocate (f),nowait))]]
+#else
+  [[omp::sequence (omp::directive (single, private (p),firstprivate (f),allocate (f),nowait))]]
+#endif
     ;
   [[omp::sequence (directive (barrier))]];
+#if __cplusplus >= 201703L
   [[using omp:sequence (directive (parallel, private (p)),
     omp::directive (single, copyprivate (p),firstprivate (f),allocate (f)))]]
+#else
+  [[omp::sequence (directive (parallel, private (p)),
+    omp::directive (single, copyprivate (p),firstprivate (f),allocate (f)))]]
+#endif
     p = 6;
   [[omp::directive (target parallel,
     device(d),map (tofrom: m),if (target: i1),private (p),firstprivate (f),defaultmap(tofrom: scalar),is_device_ptr (idp),
@@ -194,7 +207,13 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s,
     allocate (omp_default_mem_alloc:f),in_reduction(+:r2),has_device_addr (hda))]]
   for (int i = 0; i < 64; i++)
     ll++;
-  [[using omp:directive (target parallel for,
+  [[
+#if __cplusplus >= 201703L
+    using omp:
+#else
+    omp::
+#endif
+    directive (target parallel for,
     device(d),map (tofrom: m),if (target: i1),private (p),firstprivate (f),defaultmap(tofrom: scalar),is_device_ptr (idp),
     if (parallel: i2),default(shared),shared(s),reduction(+:r),num_threads (nth),proc_bind(spread),
     lastprivate (l),linear (ll:1),schedule(static, 4),collapse(1),nowait depend(inout: dd[0]),order(concurrent),
@@ -209,12 +228,24 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s,
     allocate (omp_default_mem_alloc:f),in_reduction(+:r2),has_device_addr (hda)))]]
   for (int i = 0; i < 64; i++)
     ll++;
-  [[using omp:sequence (directive (target teams,
+  [[
+#if __cplusplus >= 201703L
+    using omp:
+#else
+    omp::
+#endif
+    sequence (directive (target teams,
     device(d),map (tofrom: m),if (target: i1),private (p),firstprivate (f),defaultmap(tofrom: scalar),is_device_ptr (idp),
     shared(s),default(shared),reduction(+:r),num_teams(nte),thread_limit(tl),nowait,depend(inout: dd[0]),
     allocate (omp_default_mem_alloc:f),in_reduction(+:r2),has_device_addr (hda)))]]
     ;
-  [[using omp:sequence (directive (target,
+  [[
+#if __cplusplus >= 201703L
+    using omp:
+#else
+    omp::
+#endif
+    sequence (directive (target,
     device(d),map (tofrom: m),if (target: i1),private (p),firstprivate (f),defaultmap(tofrom: scalar),is_device_ptr (idp),
     nowait depend(inout: dd[0]),allocate (omp_default_mem_alloc:f),in_reduction(+:r2),has_device_addr(hda)))]]
     ;
@@ -266,7 +297,13 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s,
     order(concurrent),allocate (f)))]]
   for (int i = 0; i < 64; i++)
     ll++;
-  [[using omp:sequence (omp::directive (taskgroup, task_reduction(+:r), allocate (r)),
+  [[
+#if __cplusplus >= 201703L
+    using omp:
+#else
+    omp::
+#endif
+    sequence (omp::directive (taskgroup, task_reduction(+:r), allocate (r)),
     directive (taskloop simd,
     private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(i1),final(fi),mergeable,nogroup,priority (pp),
     safelen(8),simdlen(4),linear(ll: 1),aligned(q: 32),in_reduction(+:r),nontemporal(ntm),
@@ -321,7 +358,13 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s,
     lastprivate (l),schedule(static, 4),order(concurrent),allocate (omp_default_mem_alloc: f)))]]
   for (int i = 0; i < 64; i++)
     ll++;
-  [[using omp:sequence (directive (target),
+  [[
+#if __cplusplus >= 201703L
+    using omp:
+#else
+    omp::
+#endif
+    sequence (directive (target),
     directive (teams distribute parallel for simd,
     private(p),firstprivate (f),shared(s),default(shared),reduction(+:r),num_teams(nte),thread_limit(tl),
     collapse(1),dist_schedule(static, 16),
@@ -389,21 +432,39 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s,
     private (p),firstprivate (f),if (parallel: i2),default(shared),shared(s),reduction(+:r),
     num_threads (nth),proc_bind(spread),copyin(t),allocate (f))]]
     ;
-  [[using omp:sequence (directive (taskgroup, task_reduction (+:r2),allocate (r2)),
+  [[
+#if __cplusplus >= 201703L
+    using omp:
+#else
+    omp::
+#endif
+    sequence (directive (taskgroup, task_reduction (+:r2),allocate (r2)),
     omp::directive (master taskloop,
     private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied, if(taskloop: i1),final(fi),mergeable, priority (pp),
     reduction(default, +:r),in_reduction(+:r2),allocate (f)))]]
   for (int i = 0; i < 64; i++)
     ll++;
-  [[using omp:sequence (directive (taskgroup, task_reduction (+:r2),allocate (r2)),
+  [[
+#if __cplusplus >= 201703L
+    using omp:
+#else
+    omp::
+#endif
+    sequence (directive (taskgroup, task_reduction (+:r2),allocate (r2)),
     omp::directive (masked taskloop,
     private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied, if(taskloop: i1),final(fi),mergeable, priority (pp),
     reduction(default, +:r),in_reduction(+:r2),allocate (f),filter(d)))]]
   for (int i = 0; i < 64; i++)
     ll++;
+#if __cplusplus >= 201703L
   [[using omp:directive (master)]];
   [[using omp:directive (masked)]];
   [[using omp:directive (masked,filter(d))]];
+#else
+  [[omp::directive (master)]];
+  [[omp::directive (masked)]];
+  [[omp::directive (masked,filter(d))]];
+#endif
   [[omp::sequence (omp::directive (taskgroup task_reduction (+:r2),allocate (r2)),
     directive (master taskloop simd,
     private (p),firstprivate (f),lastprivate (l),shared (s),default(shared),grainsize (g),collapse(1),untied,if(taskloop: i1),if(simd: i2),final(fi),mergeable,priority (pp),
@@ -544,7 +605,11 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s,
   }
   [[omp::directive (critical (foobar),hint(omp_sync_hint_none))]]
   ;
+#if __cplusplus >= 201703L
   [[using omp:directive (taskwait, depend (inout: dd[0]))]]
+#else
+  [[omp::directive (taskwait, depend (inout: dd[0]))]]
+#endif
   ;
   [[omp::directive (taskgroup, task_reduction(+:r2),allocate (r2))]]
   ;
@@ -596,7 +661,13 @@ bar (int d, int m, int i1, int i2, int i3, int p, int *idp, int hda, int s,
   [[omp::directive (scope, private (p), firstprivate (f), reduction(+:r), nowait,
     allocate(omp_default_mem_alloc: r))]]
     ;
-  [[using omp:directive (scope, private (p), firstprivate (f), reduction(task, +:r),
+  [[
+#if __cplusplus >= 201703L
+    using omp:
+#else
+    omp ::
+#endif
+    directive (scope, private (p), firstprivate (f), reduction(task, +:r),
     allocate (omp_default_mem_alloc: f))]]
     ;
   extern int t2;
@@ -632,8 +703,13 @@ corge ()
   [[omp::directive (declare simd, simdlen(4),linear(l),aligned(p:4),uniform(p),inbranch),
     omp::directive (declare simd,simdlen(8),notinbranch)]]
   extern int corge3 (int l, int *p);
+#if __cplusplus >= 201703L
   [[using omp:directive (declare simd, simdlen(4),linear(l),aligned(p:4),uniform(p),inbranch),
     directive (declare simd, simdlen(8),notinbranch)]]
+#else
+  [[omp::directive (declare simd, simdlen(4),linear(l),aligned(p:4),uniform(p),inbranch),
+    omp :: directive (declare simd, simdlen(8),notinbranch)]]
+#endif
   extern int corge4 (int l, int *p);
   [[omp::sequence (directive (declare simd, simdlen(4),linear(l),aligned(p:4),uniform(p),inbranch),
     omp::directive (declare simd, simdlen(8),notinbranch))]]
@@ -658,7 +734,11 @@ garply (int a, int *c, int *d, int *e, int *f)
   for (i = 0; i < 64; i++)
     {
       a += c[i];
+#if __cplusplus >= 201703L
       [[using omp : sequence (sequence (directive (scan inclusive (a))))]]
+#else
+      [[omp:: sequence (sequence (directive (scan inclusive (a))))]]
+#endif
       d[i] = a;
     }
   return a;
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-1.c b/gcc/testsuite/gcc.dg/gomp/attrs-1.c
new file mode 100644 (file)
index 0000000..c7a5ae3
--- /dev/null
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+#include "../../g++.dg/gomp/attrs-1.C"
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-10.c b/gcc/testsuite/gcc.dg/gomp/attrs-10.c
new file mode 100644 (file)
index 0000000..a7723b5
--- /dev/null
@@ -0,0 +1,192 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x -ffat-lto-objects -fdump-tree-gimple" } */
+
+extern void abort ();
+
+[[omp::directive (declare simd, linear (l))]] extern int f1 (int l);
+extern int f2 (int), f3 [[omp::directive (declare simd, uniform (m))]] (int m), f4 (int), z;
+[[omp::directive (declare simd, linear (l), simdlen(4))]] extern int f5 [[omp::directive (declare simd uniform (l) simdlen (8) notinbranch)]] (int l);
+
+int
+f1 (int l)
+{
+  return l;
+}
+
+/* { dg-final { scan-assembler-times "_ZGVbM4l_f1:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVbN4l_f1:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcM4l_f1:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcN4l_f1:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdM8l_f1:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdN8l_f1:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeM16l_f1:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeN16l_f1:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+
+int
+f2 (int l)
+{
+  return l + 1;
+}
+
+/* { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]_f2:" { target { i?86-*-* x86_64-*-* } } } } */
+
+int
+f3 (int l)
+{
+  return l + 2;
+}
+
+/* { dg-final { scan-assembler-times "_ZGVbM4u_f3:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVbN4u_f3:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcM4u_f3:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcN4u_f3:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdM8u_f3:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdN8u_f3:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeM16u_f3:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeN16u_f3:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+
+int
+f4 (int l)
+{
+  return l + 3;
+}
+
+/* { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]_f4:" { target { i?86-*-* x86_64-*-* } } } } */
+
+int
+f5 (int l)
+{      /* { dg-warning "GCC does not currently support simdlen 8 for type 'int'" "" { target aarch64*-*-* } .-1 } */
+  return l + 4;
+}
+
+/* { dg-final { scan-assembler-times "_ZGVbM4l_f5:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVbN4l_f5:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcM4l_f5:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcN4l_f5:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdM4l_f5:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdN4l_f5:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeM4l_f5:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeN4l_f5:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVbN8u_f5:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcN8u_f5:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdN8u_f5:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeN8u_f5:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-not "_ZGV\[bcde]M8u_f5:" { target { i?86-*-* x86_64-*-* } } } } */
+
+[[omp::directive (declare simd, linear (l), simdlen(4), notinbranch),
+  omp::directive (declare simd, uniform (l), simdlen(4), inbranch)]]
+int
+f6 [[omp::sequence (directive (declare simd uniform (l) simdlen (8), notinbranch),
+                   omp::directive (declare simd linear (l) simdlen (8) inbranch))]] (int l)
+{      /* { dg-warning "GCC does not currently support simdlen 8 for type 'int'" "" { target aarch64*-*-* } .-2 } */
+  return l + 5;
+}
+
+/* { dg-final { scan-assembler-times "_ZGVbM4u_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVbN4l_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVbM8l_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVbN8u_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcM4u_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcN4l_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcM8l_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcN8u_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdM4u_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdN4l_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdM8l_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdN8u_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeM4u_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeN4l_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeM8l_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeN8u_f6:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-not "_ZGV\[bcde]M4l_f6:" { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-not "_ZGV\[bcde]N4u_f6:" { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-not "_ZGV\[bcde]M8u_f6:" { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-not "_ZGV\[bcde]N8l_f6:" { target { i?86-*-* x86_64-*-* } } } } */
+
+int
+f7 (int l)
+{
+  return l + 6;
+}
+
+/* { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]_f7:" { target { i?86-*-* x86_64-*-* } } } } */
+
+int
+f8 (int l)
+{
+  return l + 7;
+}
+
+/* { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]_f8:" { target { i?86-*-* x86_64-*-* } } } } */
+
+[[omp::sequence (omp::directive (declare variant (f7), match (construct={parallel})),
+                directive (declare simd uniform (l), simdlen(4)))]]
+int
+f9 [[omp::directive (declare simd uniform (l) simdlen (8)),
+     omp::directive (declare variant (f8) match (construct={parallel,for}))]] (int l)
+{      /* { dg-warning "GCC does not currently support simdlen 8 for type 'int'" "" { target aarch64*-*-* } .-2 } */
+  return l + 8;
+}
+
+/* { dg-final { scan-assembler-times "_ZGVbM4u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVbN4u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcM4u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcN4u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdM4u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdN4u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeM4u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeN4u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVbM8u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVbN8u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcM8u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcN8u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdM8u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdN8u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeM8u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeN8u_f9:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+
+int z;
+
+void
+test ()
+{
+  [[omp::directive (parallel)]]
+  if (f9 (3) != 9)
+    abort ();
+  [[omp::directive (parallel for)]]
+  for (int i = 0; i < 1; i++)
+    if (f9 (4) != 11)
+      abort ();
+  if (f9 (5) != 13)
+    abort ();
+}
+
+/* { dg-final { scan-tree-dump-times " = f7 \\\(3\\\);" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times " = f8 \\\(4\\\);" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times " = f9 \\\(5\\\);" 1 "gimple" } } */
+
+int
+f10 (int x)
+{
+  return x;
+}
+
+[[omp::directive (declare simd, notinbranch)]] int f10 (int);
+
+/* { dg-final { scan-assembler-times "_ZGVbN4v_f10:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcN4v_f10:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdN8v_f10:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeN16v_f10:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+
+int
+f11 (int x)
+{
+  return x + 1;
+}
+
+int f11 [[omp::directive (declare simd inbranch linear(x))]] (int x);
+
+/* { dg-final { scan-assembler-times "_ZGVbM4l_f11:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVcM4l_f11:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVdM8l_f11:" 1 { target { i?86-*-* x86_64-*-* } } } } */
+/* { dg-final { scan-assembler-times "_ZGVeM16l_f11:" 1 { target { i?86-*-* x86_64-*-* } } } } */
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-11.c b/gcc/testsuite/gcc.dg/gomp/attrs-11.c
new file mode 100644 (file)
index 0000000..335ff3e
--- /dev/null
@@ -0,0 +1,88 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x -Wno-attributes" } */
+
+void
+foo ()
+{
+  [[omp::directive (parallel)]] __asm ("");
+  __extension__ [[omp::directive (parallel)]] asm ("");                /* { dg-error "expected" } */
+  [[omp::directive (parallel)]] __label__ foo;                 /* { dg-error "expected" } */
+  [[omp::directive (parallel)]] static_assert (true, "");      /* { dg-error "expected" } */
+  [[omp::directive (parallel)]] int a = 5;                     /* { dg-error "not allowed to be specified in this context" } */
+  int b = 0;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic warning "-Wattributes"
+  [[omp::directive (parallel)]] l: b++;                                /* { dg-warning "'omp::directive' scoped attribute directive ignored" } */
+  switch (0)
+    {
+      [[omp::directive (parallel)]] case 6: break;             /* { dg-warning "'omp::directive' scoped attribute directive ignored" } */
+      [[omp::directive (parallel)]] default: break;            /* { dg-warning "'omp::directive' scoped attribute directive ignored" } */
+    }
+#pragma GCC diagnostic pop
+}
+
+void
+bar ()
+{
+  [[omp::directive (declare simd)]] int a;             /* { dg-error "not allowed to be specified in this context|not immediately followed by a function declaration or definition" } */
+  [[omp::directive (declare simd)]] int b, f1 (int);   /* { dg-error "not allowed to be specified in this context|not immediately followed by a function declaration or definition" } */
+  [[omp::directive (declare simd)]] int f2 (int), c;   /* { dg-error "not immediately followed by a function declaration or definition" } */
+  int d [[omp::directive (declare simd)]];             /* { dg-error "not immediately followed by a function declaration or definition" } */
+  int f3 [[omp::directive (declare simd)]] (int), f4 [[omp::directive (declare simd)]] (int);
+  __extension__ [[omp::directive (declare simd)]] int f5 (int);
+  __extension__ int f6 [[omp::directive (declare simd, notinbranch)]] (int);
+  #pragma omp declare simd notinbranch
+  [[omp::directive (declare simd inbranch)]] int f7 (int);     /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same declaration" } */
+  [[omp::directive (declare simd notinbranch)]]
+  #pragma omp declare simd inbranch    /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  int f8 (int);
+  static int t1, t2, t3, t4;
+  [[omp::directive (declare simd), omp::directive (foobar)]] int f9 (int);     /* { dg-error "unknown OpenMP directive name" } */
+                                                                               /* { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } */
+  [[omp::directive (foobar), omp::directive (declare simd)]] int f10 (int);    /* { dg-error "unknown OpenMP directive name" } */
+                                                                               /* { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } */
+  [[omp::directive (threadprivate (t1)), omp::directive (declare simd)]] int f10 (int);        /* { dg-error "'omp::directive' not allowed to be specified in this context" } */
+  [[omp::directive (declare simd), omp::directive (threadprivate (t2))]] int f11 (int);        /* { dg-error "'omp::directive' not allowed to be specified in this context" } */
+  int f12 [[omp::directive (declare simd), omp::directive (foobar)]] (int);    /* { dg-error "unknown OpenMP directive name" } */
+                                                                               /* { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } */
+  int f13 [[omp::directive (foobar), omp::directive (declare simd)]] (int);    /* { dg-error "unknown OpenMP directive name" } */
+                                                                               /* { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } */
+  int f14 [[omp::directive (threadprivate (t3)), omp::directive (declare simd)]] (int);        /* { dg-error "'omp::directive' not allowed to be specified in this context" } */
+  int f15 [[omp::directive (declare simd), omp::directive (threadprivate (t4))]] (int);        /* { dg-error "'omp::directive' not allowed to be specified in this context" } */
+}
+
+[[omp::directive (declare simd)]] int a;               /* { dg-error "not allowed to be specified in this context|not immediately followed by a function declaration or definition" } */
+[[omp::directive (declare simd)]] int b, f16 (int);    /* { dg-error "not allowed to be specified in this context|not immediately followed by a function declaration or definition" } */
+[[omp::directive (declare simd)]] int f17 (int), c;    /* { dg-error "not immediately followed by a function declaration or definition" } */
+int d [[omp::directive (declare simd)]];               /* { dg-error "not immediately followed by a function declaration or definition" } */
+int f18 [[omp::directive (declare simd)]] (int), f19 [[omp::directive (declare simd)]] (int);
+__extension__ [[omp::directive (declare simd)]] int f20 (int);
+__extension__ int f21 [[omp::directive (declare simd, notinbranch)]] (int);
+#pragma omp declare simd notinbranch
+[[omp::directive (declare simd inbranch)]] int f22 (int);      /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same declaration" } */
+[[omp::directive (declare simd notinbranch)]]
+#pragma omp declare simd inbranch      /* { dg-error "before '#pragma'" } */
+int f23 (int);                         /* { dg-error "not immediately followed by a function declaration or definition" "" { target *-*-* } .-1 } */
+int t5, t6, t7, t8;
+[[omp::directive (declare simd), omp::directive (foobar)]] int f24 (int);      /* { dg-error "unknown OpenMP directive name" } */
+                                                                               /* { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } */
+[[omp::directive (foobar), omp::directive (declare simd)]] int f25 (int);      /* { dg-error "unknown OpenMP directive name" } */
+                                                                               /* { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } */
+[[omp::directive (threadprivate (t5)), omp::directive (declare simd)]] int f26 (int);  /* { dg-error "'omp::directive' not allowed to be specified in this context" } */
+[[omp::directive (declare simd), omp::directive (threadprivate (t6))]] int f27 (int);  /* { dg-error "'omp::directive' not allowed to be specified in this context" } */
+int f28 [[omp::directive (declare simd), omp::directive (foobar)]] (int);      /* { dg-error "unknown OpenMP directive name" } */
+                                                                               /* { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } */
+int f29 [[omp::directive (foobar), omp::directive (declare simd)]] (int);      /* { dg-error "unknown OpenMP directive name" } */
+                                                                               /* { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 } */
+int f30 [[omp::directive (threadprivate (t7)), omp::directive (declare simd)]] (int);  /* { dg-error "'omp::directive' not allowed to be specified in this context" } */
+int f31 [[omp::directive (declare simd), omp::directive (threadprivate (t8))]] (int);  /* { dg-error "'omp::directive' not allowed to be specified in this context" } */
+
+void
+baz ()
+{
+  #pragma omp parallel
+  [[omp::directive (declare simd)]];                           /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  [[omp::directive (parallel)]]
+  #pragma omp declare simd     /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  extern int f34 (int);
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-12.c b/gcc/testsuite/gcc.dg/gomp/attrs-12.c
new file mode 100644 (file)
index 0000000..57c8fcf
--- /dev/null
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+#pragma omp declare target
+#pragma omp declare target
+[[omp::directive (declare target)]];
+int a;
+[[omp::directive (end declare target)]];
+#pragma omp end declare target
+#pragma omp end declare target
+[[omp::directive (declare target)]];
+int b;
+#pragma omp end declare target         /* { dg-error "'declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } */
+#pragma omp declare target
+int c;
+[[omp::directive (end declare target)]];/* { dg-error "'declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } */
+#pragma omp declare target
+[[omp::directive (declare target)]];
+int d;
+#pragma omp end declare target         /* { dg-error "'declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } */
+#pragma omp declare target
+int e;
+[[omp::directive (end declare target)]];/* { dg-error "'declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } */
+#pragma omp end declare target
+[[omp::directive (declare target)]];
+[[omp::directive (declare target)]];
+int f;
+#pragma omp end declare target         /* { dg-error "'declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } */
+#pragma omp declare target
+int g;
+[[omp::directive (end declare target)]];/* { dg-error "'declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } */
+[[omp::directive (end declare target)]];
+[[omp::directive (declare target)]];
+#pragma omp declare target
+int h;
+#pragma omp end declare target
+#pragma omp end declare target         /* { dg-error "'declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } */
+#pragma omp declare target
+[[omp::directive (declare target)]];
+int i;
+[[omp::directive (end declare target)]];
+[[omp::directive (end declare target)]];/* { dg-error "'declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } */
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-13.c b/gcc/testsuite/gcc.dg/gomp/attrs-13.c
new file mode 100644 (file)
index 0000000..ad8d9ae
--- /dev/null
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+[[omp::directive(error)]];                     /* { dg-error "'pragma omp error' encountered" } */
+[[omp::directive(error, at(compilation))]];    /* { dg-error "'pragma omp error' encountered" } */
+[[omp::directive(error severity(fatal))]];     /* { dg-error "'pragma omp error' encountered" } */
+[[omp::directive(error, message("my msg"))]];  /* { dg-error "'pragma omp error' encountered: my msg" } */
+[[omp::directive(error severity(warning)message("another message")at(compilation))]];  /* { dg-warning "'pragma omp error' encountered: another message" } */
+
+int
+foo (int i, int x)
+{
+  [[omp::directive(error)]];                   /* { dg-error "'pragma omp error' encountered" } */
+  [[omp::directive(error, at(compilation))]];  /* { dg-error "'pragma omp error' encountered" } */
+  [[omp::directive(error severity(fatal))]];   /* { dg-error "'pragma omp error' encountered" } */
+  [[omp::directive(error, message("42 / 1"))]];        /* { dg-error "'pragma omp error' encountered: 42 / 1" } */
+  [[omp::directive(error severity(warning) message("bar") at(compilation))]];  /* { dg-warning "'pragma omp error' encountered: bar" } */
+  if (x)
+    [[omp::directive(error)]];                 /* { dg-error "'pragma omp error' encountered" } */
+  i++;
+  if (x)
+    ;
+  else
+    [[omp::directive(error at(compilation))]]; /* { dg-error "'pragma omp error' encountered" } */
+  i++;
+  switch (0)
+    [[omp::directive(error, severity(fatal))]];        /* { dg-error "'pragma omp error' encountered" } */
+  while (0)
+    [[omp::directive(error, message("42 - 1"))]];      /* { dg-error "'pragma omp error' encountered: 42 - 1" } */
+  i++;
+  lab:
+  [[omp::directive(error, severity(warning) message("bar"), at(compilation))]];        /* { dg-warning "'pragma omp error' encountered: bar" } */
+  i++;
+  return i;
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-14.c b/gcc/testsuite/gcc.dg/gomp/attrs-14.c
new file mode 100644 (file)
index 0000000..1e462f2
--- /dev/null
@@ -0,0 +1,5 @@
+/* PR c++/102413 */
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+[[omp::directive(error]];      /* { dg-error "expected|declare" } */
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-15.c b/gcc/testsuite/gcc.dg/gomp/attrs-15.c
new file mode 100644 (file)
index 0000000..2af4b21
--- /dev/null
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+#pragma omp begin assumes absent (target)
+#pragma omp begin assumes absent (target)
+[[omp::directive (begin assumes absent (target))]];
+int a;
+[[omp::directive (end assumes)]];
+#pragma omp end assumes
+#pragma omp end assumes
+[[omp::directive (begin assumes absent (target))]];
+int b;
+#pragma omp end assumes                /* { dg-error "'begin assumes' in attribute syntax terminated with 'end assumes' in pragma syntax" } */
+#pragma omp begin assumes absent (target)
+int c;
+[[omp::directive (end assumes)]];/* { dg-error "'begin assumes' in pragma syntax terminated with 'end assumes' in attribute syntax" } */
+#pragma omp begin assumes absent (target)
+[[omp::directive (begin assumes absent (target))]];
+int d;
+#pragma omp end assumes                /* { dg-error "'begin assumes' in attribute syntax terminated with 'end assumes' in pragma syntax" } */
+#pragma omp begin assumes absent (target)
+int e;
+[[omp::directive (end assumes)]];/* { dg-error "'begin assumes' in pragma syntax terminated with 'end assumes' in attribute syntax" } */
+#pragma omp end assumes
+[[omp::directive (begin assumes absent (target))]];
+[[omp::directive (begin assumes absent (target))]];
+int f;
+#pragma omp end assumes                /* { dg-error "'begin assumes' in attribute syntax terminated with 'end assumes' in pragma syntax" } */
+#pragma omp begin assumes absent (target)
+int g;
+[[omp::directive (end assumes)]];/* { dg-error "'begin assumes' in pragma syntax terminated with 'end assumes' in attribute syntax" } */
+[[omp::directive (end assumes)]];
+[[omp::directive (begin assumes absent (target))]];
+#pragma omp begin assumes absent (target)
+int h;
+#pragma omp end assumes
+#pragma omp end assumes                /* { dg-error "'begin assumes' in attribute syntax terminated with 'end assumes' in pragma syntax" } */
+#pragma omp begin assumes absent (target)
+[[omp::directive (begin assumes absent (target))]];
+int i;
+[[omp::directive (end assumes)]];
+[[omp::directive (end assumes)]];/* { dg-error "'begin assumes' in pragma syntax terminated with 'end assumes' in attribute syntax" } */
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-16.c b/gcc/testsuite/gcc.dg/gomp/attrs-16.c
new file mode 100644 (file)
index 0000000..1d8e5bc
--- /dev/null
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+#include "../../g++.dg/gomp/attrs-16.C"
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-17.c b/gcc/testsuite/gcc.dg/gomp/attrs-17.c
new file mode 100644 (file)
index 0000000..5c9beb4
--- /dev/null
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+#include "../../g++.dg/gomp/attrs-17.C"
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-18.c b/gcc/testsuite/gcc.dg/gomp/attrs-18.c
new file mode 100644 (file)
index 0000000..ff88f1d
--- /dev/null
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+#pragma omp begin declare target
+#pragma omp begin declare target device_type (any)
+[[omp::directive (begin declare target, device_type (host))]];
+int a;
+[[omp::directive (end declare target)]];
+#pragma omp end declare target
+#pragma omp end declare target
+[[omp::directive (begin declare target device_type (nohost))]];
+int b;
+#pragma omp end declare target         /* { dg-error "'begin declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } */
+#pragma omp begin declare target
+int c;
+[[omp::directive (end declare target)]];/* { dg-error "'begin declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } */
+#pragma omp begin declare target device_type (host)
+[[omp::directive (begin declare target)]];
+int d;
+#pragma omp end declare target         /* { dg-error "'begin declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } */
+#pragma omp begin declare target
+int e;
+[[omp::directive (end declare target)]];/* { dg-error "'begin declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } */
+#pragma omp end declare target
+[[omp::directive (begin declare target device_type (any))]];
+[[omp::directive (begin declare target)]];
+int f;
+#pragma omp end declare target         /* { dg-error "'begin declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } */
+#pragma omp begin declare target
+int g;
+[[omp::directive (end declare target)]];/* { dg-error "'begin declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } */
+[[omp::directive (end declare target)]];
+[[omp::directive (begin declare target)]];
+#pragma omp begin declare target
+int h;
+#pragma omp end declare target
+#pragma omp end declare target         /* { dg-error "'begin declare target' in attribute syntax terminated with 'end declare target' in pragma syntax" } */
+#pragma omp begin declare target
+[[omp::directive (begin declare target)]];
+int i;
+[[omp::directive (end declare target)]];
+[[omp::directive (end declare target)]];/* { dg-error "'begin declare target' in pragma syntax terminated with 'end declare target' in attribute syntax" } */
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-2.c b/gcc/testsuite/gcc.dg/gomp/attrs-2.c
new file mode 100644 (file)
index 0000000..0677ba3
--- /dev/null
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+#include "../../g++.dg/gomp/attrs-2.C"
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-3.c b/gcc/testsuite/gcc.dg/gomp/attrs-3.c
new file mode 100644 (file)
index 0000000..5777d8d
--- /dev/null
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+int i;
+int t1, t2, t3, t4, t5, t6, t7;
+
+void
+foo ()
+{
+  [[omp::directive]];          /* { dg-error "'omp::directive' attribute requires argument" } */
+  [[omp::directive ()]];       /* { dg-error "expected OpenMP directive name" } */
+  [[omp::directive (nonexistent foobar)]];     /* { dg-error "unknown OpenMP directive name in 'omp::directive' attribute argument" } */
+  [[omp::sequence]];           /* { dg-error "'omp::sequence' attribute requires argument" } */
+  [[omp::sequence()]];         /* { dg-error "expected 'directive' or 'sequence'" } */
+  [[omp::sequence(foobar())]];         /* { dg-error "expected 'directive' or 'sequence'" } */
+  [[omp::sequence(omp::foobar())]];            /* { dg-error "expected 'directive' or 'sequence'" } */
+  [[omp::sequence(directive(taskwait), foobar())]];            /* { dg-error "expected 'directive' or 'sequence'" } */
+  [[omp::sequence(omp::directive(taskwait), omp::foobar())]];  /* { dg-error "expected 'directive' or 'sequence'" } */
+  [[omp::sequence(directive(taskwait) foobar())]];             /* { dg-error "expected '\\\)' before 'foobar'" } */
+  [[omp::sequence(directive)]];                /* { dg-error "expected '\\\(' before '\\\)' token" } */
+  [[omp::sequence(omp::sequence)]];    /* { dg-error "expected '\\\(' before '\\\)' token" } */
+  [[omp::directive (parallel), omp::directive (single)]]       /* { dg-error "OpenMP construct among 'omp::directive' attributes requires all 'omp::directive' attributes on the same statement to be in the same 'omp::sequence'" } */
+    ;
+  [[omp::directive (parallel)]]        /* { dg-error "OpenMP construct among 'omp::directive' attributes requires all 'omp::directive' attributes on the same statement to be in the same 'omp::sequence'" } */
+  [[omp::directive (single)]]
+    ;
+  [[omp::directive (taskwait), omp::directive (taskyield)]]    /* { dg-error "multiple OpenMP standalone directives among 'omp::directive' attributes must be all within the same 'omp::sequence'" } */
+    ;
+  [[omp::directive (taskwait)]]
+  [[omp::directive (taskyield)]]       /* { dg-error "multiple OpenMP standalone directives among 'omp::directive' attributes must be all within the same 'omp::sequence'" } */
+    ;
+  [[omp::directive (flush)]]   /* { dg-error "standalone OpenMP directives in 'omp::directive' attribute can only appear on an empty statement" } */
+    i++;
+  int [[omp::directive (threadprivate (t2))]] b;               /* { dg-warning "'omp::directive' scoped attribute directive ignored" } */
+  int *[[omp::directive (threadprivate (t3))]] c;              /* { dg-warning "'omp::directive' scoped attribute directive ignored" } */
+  typedef int T [[omp::directive (threadprivate (t5))]];       /* { dg-error "'omp::directive' not allowed to be specified in this context" } */
+  int e[10] [[omp::directive (threadprivate (t6))]];           /* { dg-warning "'omp::directive' scoped attribute directive ignored" } */
+  struct [[omp::directive (threadprivate (t7))]] S {};         /* { dg-warning "'omp::directive' scoped attribute directive ignored" } */
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-4.c b/gcc/testsuite/gcc.dg/gomp/attrs-4.c
new file mode 100644 (file)
index 0000000..73610db
--- /dev/null
@@ -0,0 +1,62 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+void
+foo (int x)
+{
+  [[omp::directive (parallel)]]
+  #pragma omp for                                              /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  for (int i = 0; i < 16; i++)
+    ;
+  [[omp::directive (barrier)]]                                 /* { dg-error "standalone OpenMP directives in 'omp::directive' attribute can only appear on an empty statement" } */
+  #pragma omp flush
+  ;
+  #pragma omp parallel
+  [[omp::directive (master)]]                                  /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  ;
+  #pragma omp teams
+  [[omp::sequence (directive (parallel), directive (master))]] /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  ;
+  #pragma omp task
+  [[omp::directive (flush)]]                                   /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  ;
+  #pragma omp master
+  [[omp::directive (flush)]]                                   /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  ;
+  #pragma omp for ordered
+  for (int i = 0; i < 16; i++)
+    #pragma omp ordered
+    [[omp::directive (flush)]]                                 /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+    ;
+  #pragma omp single
+  [[omp::directive (flush)]]                                   /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  ;
+  #pragma omp taskgroup
+  [[omp::directive (taskyield)]]                               /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  ;
+  #pragma omp target data map (tofrom: x)
+  [[omp::directive (flush)]]                                   /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  ;
+  #pragma omp target
+  [[omp::directive (teams)]]                                   /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  ;
+  [[omp::directive (parallel)]]
+  #pragma omp master                                           /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  [[omp::sequence (omp::directive (taskloop))]]                        /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  for (int i = 0; i < 16; i++)
+    ;
+  #pragma omp parallel
+  [[omp::directive (for)]]                                     /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  for (int i = 0; i < 16; i++)
+    ;
+  #pragma omp for
+  [[omp::directive (master)]]                                  /* { dg-error "for statement expected before '\\\[' token" } */
+  ;
+  #pragma omp target teams
+  [[omp::directive (parallel)]]                                        /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  ;
+  #pragma omp parallel master
+  [[omp::directive (taskloop)]]                                        /* { dg-error "mixing OpenMP directives with attribute and pragma syntax on the same statement" } */
+  for (int i = 0; i < 16; i++)
+    ;
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-5.c b/gcc/testsuite/gcc.dg/gomp/attrs-5.c
new file mode 100644 (file)
index 0000000..ef70363
--- /dev/null
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+#include "../../g++.dg/gomp/attrs-5.C"
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-6.c b/gcc/testsuite/gcc.dg/gomp/attrs-6.c
new file mode 100644 (file)
index 0000000..1f77585
--- /dev/null
@@ -0,0 +1,104 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+void
+foo ()
+{
+  int a[10] = {};
+  #pragma omp parallel sections
+  {
+    #pragma omp section
+    a[0]++;
+    [[omp::directive (section)]] {
+    a[1]++;
+    } [[omp::directive (section)]]
+    a[2]++;
+    #pragma omp section
+    { a[3]++; }
+  }
+  [[omp::directive (parallel sections)]]
+  {
+    #pragma omp section
+    a[0]++;
+    [[omp::directive (section)]] {
+    a[1]++;
+    } [[omp::directive (section)]]
+    a[2]++;
+    #pragma omp section
+    { a[3]++; }
+  }
+  #pragma omp parallel sections
+  {
+    #pragma omp section
+    a[0]++;
+    a[4]++;
+    l1: a[5]++;
+    if (a[5] == 42) goto l1;
+    [[omp::directive (section)]] {
+    a[1]++;
+    a[6]++;
+    } [[omp::directive (section)]]
+    a[2]++;
+    a[7]++;
+    #pragma omp section
+    { a[3]++; }
+    a[8]++;
+  }
+  [[omp::directive (parallel sections)]]
+  {
+    #pragma omp section
+    a[0]++;
+    a[4]++;
+    [[omp::directive (section)]] {
+    a[1]++;
+    a[5]++;
+    } [[omp::directive (section)]]
+    a[2]++;
+    l2: a[6]++;
+    if (a[6] == 42)
+      goto l2;
+    a[7]++;
+    #pragma omp section
+    a[8]++;
+    { a[3]++; }
+  }
+}
+
+int
+bar (int a, int *c, int *d, int *e, int *f)
+{
+  int i;
+  #pragma omp simd reduction (inscan, +: a)
+  for (i = 0; i < 64; i++)
+    {
+      d[i] = a;
+      [[omp::directive (scan, exclusive (a))]]
+      a += c[i];
+    }
+  [[omp::directive (simd reduction (inscan, +: a))]]
+  for (i = 0; i < 64; i++)
+    {
+      a += c[i];
+      #pragma omp scan inclusive (a)
+      d[i] = a;
+    }
+  #pragma omp simd reduction (inscan, +: a)
+  for (i = 0; i < 64; i++)
+    {
+      { int t = a;
+       d[i] = t; }
+      [[omp::directive (scan, exclusive (a))]]
+      { int u = c[i];
+       a += u; }
+    }
+  [[omp::directive (simd reduction (inscan, +: a))]]
+  for (i = 0; i < 64; i++)
+    {
+      { int t = c[i];
+       a += t; }
+      #pragma omp scan inclusive (a)
+      { int u = a;
+       d[i] = u; }
+    }
+  return a;
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-7.c b/gcc/testsuite/gcc.dg/gomp/attrs-7.c
new file mode 100644 (file)
index 0000000..36adbb6
--- /dev/null
@@ -0,0 +1,62 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+void
+foo ()
+{
+
+  [[omp::directive (parallel sections)]]
+  {
+    [[omp::directive (parallel)]];
+    [[omp::sequence (directive (section), directive (flush))]];                /* { dg-error "must be the only specified attribute on a statement" } */
+                                                                       /* { dg-error "expected '#pragma omp section' or '\\\}'" "" { target *-*-* } .-2 } */
+    [[omp::sequence (directive (flush), omp::directive (section))]];   /* { dg-error "must be the only specified attribute on a statement" } */
+    [[gnu::cold, omp::directive (section)]];                           /* { dg-error "must be the only specified attribute on a statement" } */
+    [[omp::directive (section)]] [[gnu::cold]];                                /* { dg-error "must be the only specified attribute on a statement" } */
+    [[omp::directive (section foo)]];                                  /* { dg-error "expected end of line before 'foo'" } */
+  }
+}
+
+int
+bar (int a, int *c, int *d, int *e, int *f)
+{
+  int i;
+  [[omp::directive (parallel for reduction (inscan, +: a))]]                           /* { dg-error "'a' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" } */
+  for (i = 0; i < 64; i++)
+    {
+      d[i] = a;
+      [[omp::sequence (omp::directive (parallel), omp::directive (scan, exclusive (a)))]]      /* { dg-error "must be the only specified attribute on a statement" } */
+      a += c[i];
+    }                                                                                  /* { dg-error "expected" } */
+  [[omp::directive (parallel for reduction (inscan, +: a))]]                           /* { dg-error "'a' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" } */
+  for (i = 0; i < 64; i++)
+    {
+      a += c[i];
+      [[omp::sequence (directive (scan inclusive (a)), directive (critical))]]         /* { dg-error "must be the only specified attribute on a statement" } */
+
+      d[i] = a;
+    }                                                                                  /* { dg-error "expected" } */
+  [[omp::directive (parallel for reduction (inscan, +: a))]]                           /* { dg-error "'a' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" } */
+  for (i = 0; i < 64; i++)
+    {
+      d[i] = a;
+      [[gnu::cold]] [[omp::directive (scan, exclusive (a))]]
+                                                                                       /* { dg-error "#pragma omp scan" "" { target *-*-* } .-1 } */
+      a += c[i];                                                                       /* { dg-warning "'cold' attribute ignored" } */
+    }                                                                                  /* { dg-error "expected" } */
+  [[omp::directive (parallel for reduction (inscan, +: a))]]                           /* { dg-error "'a' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" } */
+  for (i = 0; i < 64; i++)
+    {
+      d[i] = a;
+      [[omp::directive (scan, exclusive (a)), gnu::cold]]                              /* { dg-error "must be the only specified attribute on a statement" } */
+      a += c[i];
+    }                                                                                  /* { dg-error "expected" } */
+  [[omp::directive (parallel for reduction (inscan, +: a))]]                           /* { dg-error "'a' specified in 'inscan' 'reduction' clause but not in 'scan' directive clause" } */
+  for (i = 0; i < 64; i++)
+    {
+      d[i] = a;
+      [[omp::directive (scan)]]                                                                /* { dg-error "expected 'inclusive' or 'exclusive' clause before end of line" } */
+      a += c[i];
+    }
+  return a;
+}
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-8.c b/gcc/testsuite/gcc.dg/gomp/attrs-8.c
new file mode 100644 (file)
index 0000000..aba7b53
--- /dev/null
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+#include "../../g++.dg/gomp/attrs-8.C"
diff --git a/gcc/testsuite/gcc.dg/gomp/attrs-9.c b/gcc/testsuite/gcc.dg/gomp/attrs-9.c
new file mode 100644 (file)
index 0000000..013a1c4
--- /dev/null
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp -std=c2x" } */
+
+#include "../../g++.dg/gomp/attrs-9.C"