]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
OpenMP: Add uses_allocators parser support to C/C++
authorChung-Lin Tang <cltang@baylibre.com>
Fri, 12 Dec 2025 20:20:33 +0000 (21:20 +0100)
committerTobias Burnus <tburnus@baylibre.com>
Fri, 12 Dec 2025 20:20:33 +0000 (21:20 +0100)
This is the parser part for C/C++, including early middle end bits,
but then stops with a 'sorry, unimplemented'. It also adds support
for omp_null_alloctor (6.0 clarificiation, is to be ignored). As
predefined allocators do not require any special handling in GCC,
those are ignored. Therefore, this patch fully supports
uses_allocators that only use predefined allocators - only printing
a sorry for those that use the (implicit) traits/memspace modifer.

(The parsing support for Fortran was added before; this patch just
adds omp_null_allocator support to Fortran. The sorry message for
Fortran is also still in the FE and not in gimplify.cc, but that
only make a difference for the original dump.)

Except for some minor fixes, this is the same patch as
https://gcc.gnu.org/pipermail/gcc-patches/2025-November/700345.html
with the middle-end + libgomp handling excluded. That patch in turn
is based on previous patches, the latest previous one was
https://gcc.gnu.org/pipermail/gcc-patches/2023-November/637415.html
and, in particular, the C/C++ parser style was updated following the
review comments. Also, more C++ template-handling fixes have been
applied.

gcc/c-family/ChangeLog:

* c-omp.cc (c_omp_split_clauses): Hande uses_allocators.
* c-pragma.h (enum pragma_omp_clause): Add
PRAGMA_OMP_CLAUSE_USES_ALLOCATORS.

gcc/c/ChangeLog:

* c-parser.cc (c_parser_omp_clause_uses_allocators): New function.
(c_parser_omp_clause_name, c_parser_omp_all_clauses,
OMP_TARGET_CLAUSE_MASK): Handle uses_allocators.
* c-typeck.cc (c_finish_omp_clauses): Likewise.

gcc/cp/ChangeLog:

* parser.cc (cp_parser_omp_clause_uses_allocators): New function.
(cp_parser_omp_clause_name, cp_parser_omp_all_clauses,
OMP_TARGET_CLAUSE_MASK): Handle uses_allocators.
* semantics.cc (finish_omp_clauses): Likewise.
* pt.cc (tsubst_omp_clauses): Likewise.

gcc/fortran/ChangeLog:

* openmp.cc (resolve_omp_clauses): Handle omp_null_allocator.
* trans-openmp.cc (gfc_trans_omp_clauses): Mention it in a comment.

gcc/ChangeLog:

* gimplify.cc (gimplify_scan_omp_clauses): Handle uses_allocators
by printing a 'sorry, unimplemented' and removing it.
* tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_USES_ALLOCATORS.
* tree.cc (omp_clause_num_ops, omp_clause_code_name): Likewise.
* tree-pretty-print.cc (dump_omp_clause): Handle it.
* tree.h (OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR,
OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE,
OMP_CLAUSE_USES_ALLOCATORS_TRAITS): New.

libgomp/ChangeLog:

* testsuite/libgomp.fortran/uses_allocators_1.f90: Add check for
omp_null_allocator.
* testsuite/libgomp.fortran/uses_allocators-7.f90: New test.

gcc/testsuite/ChangeLog:

* c-c++-common/gomp/uses_allocators-1.c: New test.
* c-c++-common/gomp/uses_allocators-2.c: New test.
* c-c++-common/gomp/uses_allocators-4.c: New test.
* c-c++-common/gomp/uses_allocators-7.c: New test.
* g++.dg/gomp/deprecate-2.C: New test.
* g++.dg/gomp/uses_allocators-1.C: New test.
* gcc.dg/gomp/deprecate-2.c: New test.

Co-authored-by: Tobias Burnus <tburnus@baylibre.com>
Co-authored-by: Andrew Stubbs <ams@baylibre.com>
23 files changed:
gcc/c-family/c-omp.cc
gcc/c-family/c-pragma.h
gcc/c/c-parser.cc
gcc/c/c-typeck.cc
gcc/cp/parser.cc
gcc/cp/pt.cc
gcc/cp/semantics.cc
gcc/fortran/openmp.cc
gcc/fortran/trans-openmp.cc
gcc/gimplify.cc
gcc/testsuite/c-c++-common/gomp/uses_allocators-1.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/gomp/uses_allocators-2.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/gomp/uses_allocators-4.c [new file with mode: 0644]
gcc/testsuite/c-c++-common/gomp/uses_allocators-7.c [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/deprecate-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/uses_allocators-1.C [new file with mode: 0644]
gcc/testsuite/gcc.dg/gomp/deprecate-2.c [new file with mode: 0644]
gcc/tree-core.h
gcc/tree-pretty-print.cc
gcc/tree.cc
gcc/tree.h
libgomp/testsuite/libgomp.fortran/uses_allocators-7.f90 [new file with mode: 0644]
libgomp/testsuite/libgomp.fortran/uses_allocators_1.f90

index e183c400652d9cf3112b485b2051ef07279d40c9..9dd0d1450dd8383f15ded81f8cf55384e415e0cc 100644 (file)
@@ -2182,6 +2182,7 @@ c_omp_split_clauses (location_t loc, enum tree_code code,
        case OMP_CLAUSE_IS_DEVICE_PTR:
        case OMP_CLAUSE_HAS_DEVICE_ADDR:
        case OMP_CLAUSE_MAP:
+       case OMP_CLAUSE_USES_ALLOCATORS:
          s = C_OMP_CLAUSE_SPLIT_TARGET;
          break;
        case OMP_CLAUSE_DOACROSS:
index a61a2c7bec36c63af453a535c86e07754c9f33d8..3dc02e77b9e84d3c81012762606b1ccf34de61be 100644 (file)
@@ -175,6 +175,7 @@ enum pragma_omp_clause {
   PRAGMA_OMP_CLAUSE_USE,
   PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR,
   PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR,
+  PRAGMA_OMP_CLAUSE_USES_ALLOCATORS,
 
   /* Clauses for OpenACC.  */
   PRAGMA_OACC_CLAUSE_ASYNC,
index abe024c84b39ebb00b907bebc4db759d137a88f6..669af6573cae9e5bdf497792ae661fa5a6a5006b 100644 (file)
@@ -16589,6 +16589,8 @@ c_parser_omp_clause_name (c_parser *parser)
            result = PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR;
          else if (!strcmp ("use_device_ptr", p))
            result = PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR;
+         else if (!strcmp ("uses_allocators", p))
+           result = PRAGMA_OMP_CLAUSE_USES_ALLOCATORS;
          break;
        case 'v':
          if (!strcmp ("vector", p))
@@ -19562,6 +19564,233 @@ c_parser_omp_clause_allocate (c_parser *parser, tree list)
   return nl;
 }
 
+/* OpenMP 5.0:
+   uses_allocators ( allocator-list )
+
+   allocator-list:
+   allocator
+   allocator , allocator-list
+   allocator ( traits-array )
+   allocator ( traits-array ) , allocator-list
+
+   OpenMP 5.2:
+
+   uses_allocators ( modifier : allocator-list )
+   uses_allocators ( modifier , modifier : allocator-list )
+
+   modifier:
+   traits ( traits-array )
+   memspace ( mem-space-handle )  */
+
+static tree
+c_parser_omp_clause_uses_allocators (c_parser *parser, tree list)
+{
+  location_t clause_loc = c_parser_peek_token (parser)->location;
+  tree nl = list;
+  matching_parens parens;
+  if (!parens.require_open (parser))
+    return list;
+
+  bool has_modifiers = false;
+  bool seen_allocators = false;
+  tree memspace_expr = NULL_TREE;
+  tree traits_var = NULL_TREE;
+
+  if (c_parser_next_token_is (parser, CPP_NAME)
+      && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN)
+    {
+      unsigned int n = 3;
+      const char *p
+       = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      if ((strcmp (p, "traits") == 0 || strcmp (p, "memspace") == 0)
+         && c_parser_check_balanced_raw_token_sequence (parser, &n)
+         && (c_parser_peek_nth_token_raw (parser, n)->type
+             == CPP_CLOSE_PAREN))
+       {
+         if (c_parser_peek_nth_token_raw (parser, n + 1)->type
+             == CPP_COLON)
+           has_modifiers = true;
+         else if (c_parser_peek_nth_token_raw (parser, n + 1)->type
+                  == CPP_COMMA
+                  && (c_parser_peek_nth_token_raw (parser, n + 2)->type
+                      == CPP_NAME)
+                  && (c_parser_peek_nth_token_raw (parser, n + 3)->type
+                      == CPP_OPEN_PAREN))
+           {
+             c_token *tok = c_parser_peek_nth_token_raw (parser, n + 2);
+             const char *q = IDENTIFIER_POINTER (tok->value);
+             n += 4;
+             if ((strcmp (q, "traits") == 0
+                  || strcmp (q, "memspace") == 0)
+                 && c_parser_check_balanced_raw_token_sequence (parser, &n)
+                 && (c_parser_peek_nth_token_raw (parser, n)->type
+                     == CPP_CLOSE_PAREN))
+               {
+                 if (c_parser_peek_nth_token_raw (parser, n + 1)->type
+                     == CPP_COLON)
+                   has_modifiers = true;
+                 if ((c_parser_peek_nth_token_raw (parser, n + 1)->type
+                      == CPP_COMMA)
+                     && (c_parser_peek_nth_token_raw (parser, n + 2)->type
+                         == CPP_NAME))
+                   {
+                     c_token *tok
+                       = c_parser_peek_nth_token_raw (parser, n + 2);
+                     const char *m = IDENTIFIER_POINTER (tok->value);
+                     if (strcmp (p, m) == 0 || strcmp (q, m) == 0)
+                       {
+                         error_at (tok->location, "duplicate %qs modifier", m);
+                         goto end;
+                       }
+                   }
+               }
+           }
+       }
+      if (has_modifiers)
+       {
+         c_parser_consume_token (parser);
+         matching_parens parens2;
+         parens2.require_open (parser);
+         c_expr expr = c_parser_expr_no_commas (parser, NULL);
+         if (expr.value == error_mark_node)
+           ;
+         else if (strcmp (p, "traits") == 0)
+           {
+             traits_var = expr.value;
+             traits_var = c_fully_fold (traits_var, false, NULL);
+           }
+         else
+           {
+             memspace_expr = expr.value;
+             memspace_expr = c_fully_fold (memspace_expr, false, NULL);
+           }
+         parens2.skip_until_found_close (parser);
+         if (c_parser_next_token_is (parser, CPP_COMMA))
+           {
+             c_parser_consume_token (parser);
+             c_token *tok = c_parser_peek_token (parser);
+             const char *q = "";
+             if (c_parser_next_token_is (parser, CPP_NAME))
+               q = IDENTIFIER_POINTER (tok->value);
+             if (strcmp (q, "traits") != 0 && strcmp (q, "memspace") != 0)
+               {
+                 c_parser_error (parser, "expected %<traits%> or "
+                                 "%<memspace%>");
+                 parens.skip_until_found_close (parser);
+                 return list;
+               }
+             else if (strcmp (p, q) == 0)
+               {
+                 error_at (tok->location, "duplicate %qs modifier", p);
+                 parens.skip_until_found_close (parser);
+                 return list;
+               }
+             c_parser_consume_token (parser);
+             if (!parens2.require_open (parser))
+               {
+                 parens.skip_until_found_close (parser);
+                 return list;
+               }
+             expr = c_parser_expr_no_commas (parser, NULL);
+             if (strcmp (q, "traits") == 0)
+               {
+                 traits_var = expr.value;
+                 traits_var = c_fully_fold (traits_var, false, NULL);
+               }
+             else
+               {
+                 memspace_expr = expr.value;
+                 memspace_expr = c_fully_fold (memspace_expr, false, NULL);
+               }
+             parens2.skip_until_found_close (parser);
+           }
+         if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+           goto end;
+       }
+    }
+
+  while (c_parser_next_token_is (parser, CPP_NAME))
+    {
+      location_t alloc_loc = c_parser_peek_token (parser)->location;
+      c_token *tok = c_parser_peek_token (parser);
+      const char *tok_s = IDENTIFIER_POINTER (tok->value);
+      tree t = lookup_name (tok->value);
+      if (t == NULL_TREE)
+       {
+         undeclared_variable (tok->location, tok->value);
+         t = error_mark_node;
+       }
+      c_parser_consume_token (parser);
+
+      /* Legacy traits syntax.  */
+      tree legacy_traits = NULL_TREE;
+      if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+         && c_parser_peek_2nd_token (parser)->type == CPP_NAME
+         && c_parser_peek_nth_token_raw (parser, 3)->type == CPP_CLOSE_PAREN)
+       {
+         matching_parens parens2;
+         parens2.require_open (parser);
+         const char *tok_a
+           = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+         c_expr expr = c_parser_expr_no_commas (parser, NULL);
+         location_t close_loc = c_parser_peek_token (parser)->location;
+         parens2.skip_until_found_close (parser);
+
+         if (has_modifiers)
+           {
+             error_at (make_location (alloc_loc, alloc_loc, close_loc),
+                       "legacy %<%s(%s)%> traits syntax not allowed in "
+                       "%<uses_allocators%> clause when using modifiers",
+                       tok_s, tok_a);
+             goto end;
+           }
+         legacy_traits = c_fully_fold (expr.value, false, NULL);
+         if (legacy_traits == error_mark_node)
+           goto end;
+
+         gcc_rich_location richloc (make_location (alloc_loc, alloc_loc, close_loc));
+         if (nl == list)
+           {
+             /* Fixit only works well if it is the only first item.  */
+             richloc.add_fixit_replace (alloc_loc, "traits");
+             richloc.add_fixit_insert_after (close_loc, ": ");
+             richloc.add_fixit_insert_after (close_loc, tok_s);
+           }
+         warning_at (&richloc, OPT_Wdeprecated_openmp,
+                     "the specification of arguments to %<uses_allocators%> "
+                     "where each item is of the form %<allocator(traits)%> is "
+                     "deprecated since OpenMP 5.2");
+       }
+
+      if (seen_allocators && has_modifiers)
+       {
+         error_at (c_parser_peek_token (parser)->location,
+                   "%<uses_allocators%> clause only accepts a single "
+                   "allocator when using modifiers");
+         goto end;
+       }
+      seen_allocators = true;
+
+      tree c = build_omp_clause (clause_loc,
+                                OMP_CLAUSE_USES_ALLOCATORS);
+      OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (c) = t;
+      OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE (c) = memspace_expr;
+      OMP_CLAUSE_USES_ALLOCATORS_TRAITS (c) = (legacy_traits
+                                              ? legacy_traits : traits_var);
+      OMP_CLAUSE_CHAIN (c) = nl;
+      nl = c;
+
+      if (c_parser_next_token_is (parser, CPP_COMMA))
+       c_parser_consume_token (parser);
+      else
+       break;
+    }
+
+ end:
+  parens.skip_until_found_close (parser);
+  return nl;
+}
+
 /* OpenMP 4.0:
    linear ( variable-list )
    linear ( variable-list : expression )
@@ -22091,6 +22320,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
          clauses = c_parser_omp_clause_linear (parser, clauses);
          c_name = "linear";
          break;
+       case PRAGMA_OMP_CLAUSE_USES_ALLOCATORS:
+         clauses = c_parser_omp_clause_uses_allocators (parser, clauses);
+         c_name = "uses_allocators";
+         break;
        case PRAGMA_OMP_CLAUSE_AFFINITY:
          clauses = c_parser_omp_clause_affinity (parser, clauses);
          c_name = "affinity";
@@ -26941,7 +27174,8 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser,
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)          \
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)       \
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)      \
-       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT))
+       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \
+       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USES_ALLOCATORS))
 
 static bool
 c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p)
index 735cfc61d1e0ec0830e098dee4f429e001ff1240..cab21e29004e64e6247150691a130238097412b8 100644 (file)
@@ -17259,6 +17259,145 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
              break;
            }
          gcc_unreachable ();
+
+       case OMP_CLAUSE_USES_ALLOCATORS:
+         t = OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (c);
+         if (t == error_mark_node)
+           {
+             remove = true;
+             break;
+           }
+         if ((VAR_P (t) || TREE_CODE (t) == PARM_DECL)
+             && (bitmap_bit_p (&generic_head, DECL_UID (t))
+                 || bitmap_bit_p (&map_head, DECL_UID (t))
+                 || bitmap_bit_p (&firstprivate_head, DECL_UID (t))
+                 || bitmap_bit_p (&lastprivate_head, DECL_UID (t))))
+           {
+             error_at (OMP_CLAUSE_LOCATION (c),
+                       "%qE appears more than once in data clauses", t);
+             remove = true;
+             break;
+           }
+         else
+           bitmap_set_bit (&generic_head, DECL_UID (t));
+         if (TREE_CODE (TREE_TYPE (t)) != ENUMERAL_TYPE
+             || strcmp (IDENTIFIER_POINTER (TYPE_IDENTIFIER (TREE_TYPE (t))),
+                        "omp_allocator_handle_t") != 0)
+           {
+             error_at (OMP_CLAUSE_LOCATION (c),
+                       "allocator %qE must be of %<omp_allocator_handle_t%> "
+                       "type", t);
+             remove = true;
+             break;
+           }
+         tree init;
+         if (!DECL_P (t)
+             || (TREE_CODE (t) == CONST_DECL
+                 && ((init = DECL_INITIAL(t)) == nullptr
+                     || TREE_CODE (init) != INTEGER_CST
+                     || ((wi::to_widest (init) < 0
+                          || wi::to_widest (init) > GOMP_OMP_PREDEF_ALLOC_MAX)
+                         && (wi::to_widest (init) < GOMP_OMPX_PREDEF_ALLOC_MIN
+                             || (wi::to_widest (init)
+                                 > GOMP_OMPX_PREDEF_ALLOC_MAX))))))
+           {
+             remove = true;
+             error_at (OMP_CLAUSE_LOCATION (c),
+                       "allocator %qE must be either a variable or a "
+                       "predefined allocator", t);
+             break;
+           }
+         else if (TREE_CODE (t) == CONST_DECL)
+           {
+             /* omp_null_allocator is ignored and for predefined allocators,
+                not special handling is required; thus, remove them removed. */
+             remove = true;
+
+             if (OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE (c)
+                 || OMP_CLAUSE_USES_ALLOCATORS_TRAITS (c))
+               {
+                 error_at (OMP_CLAUSE_LOCATION (c),
+                           "modifiers cannot be used with predefined "
+                           "allocator %qE", t);
+                 break;
+               }
+           }
+         t = OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE (c);
+         if (t == error_mark_node)
+           {
+             remove = true;
+             break;
+           }
+         if (t != NULL_TREE
+             && ((TREE_CODE (t) != CONST_DECL && TREE_CODE (t) != INTEGER_CST)
+                 || TREE_CODE (TREE_TYPE (t)) != ENUMERAL_TYPE
+                 || strcmp (IDENTIFIER_POINTER (TYPE_IDENTIFIER (TREE_TYPE (t))),
+                            "omp_memspace_handle_t") != 0))
+           {
+             error_at (OMP_CLAUSE_LOCATION (c), "memspace modifier %qE must be"
+                       " constant enum of %<omp_memspace_handle_t%> type", t);
+             remove = true;
+             break;
+           }
+         t = OMP_CLAUSE_USES_ALLOCATORS_TRAITS (c);
+         if (t == error_mark_node)
+           {
+             remove = true;
+             break;
+           }
+         if (t != NULL_TREE
+             && t != error_mark_node
+             && (DECL_EXTERNAL (t)
+                 || TREE_CODE (t) == PARM_DECL))
+           {
+             error_at (OMP_CLAUSE_LOCATION (c), "traits array %qE must be "
+                       "defined in same scope as the construct on which the "
+                       "clause appears", t);
+             remove = true;
+           }
+         if (t != NULL_TREE)
+           {
+             bool type_err = false;
+
+             if (TREE_CODE (TREE_TYPE (t)) != ARRAY_TYPE
+                 || DECL_SIZE (t) == NULL_TREE
+                 || !COMPLETE_TYPE_P (TREE_TYPE (t)))
+               type_err = true;
+             else
+               {
+                 tree elem_t = TREE_TYPE (TREE_TYPE (t));
+                 if (TREE_CODE (elem_t) != RECORD_TYPE
+                     || strcmp (IDENTIFIER_POINTER (TYPE_IDENTIFIER (elem_t)),
+                                "omp_alloctrait_t") != 0
+                     || !TYPE_READONLY (elem_t))
+                   type_err = true;
+               }
+             if (type_err)
+               {
+                 if (t != error_mark_node)
+                   error_at (OMP_CLAUSE_LOCATION (c), "traits array %qE must "
+                             "be of %<const omp_alloctrait_t []%> type", t);
+                 else
+                   error_at (OMP_CLAUSE_LOCATION (c), "traits array must "
+                             "be of %<const omp_alloctrait_t []%> type");
+                 remove = true;
+               }
+             else
+               {
+                 tree cst_val = decl_constant_value_1 (t, true);
+                 if (cst_val == t)
+                   {
+                     error_at (OMP_CLAUSE_LOCATION (c), "traits array must be "
+                               "initialized with constants");
+
+                     remove = true;
+                   }
+               }
+           }
+         if (remove)
+           break;
+         pc = &OMP_CLAUSE_CHAIN (c);
+         continue;
        case OMP_CLAUSE_DEPEND:
          depend_clause = c;
          /* FALLTHRU */
index 50a03a3d79739a898d6ce1557686bcdaeef805c7..a0acd9cf6f3eb95f356d6610b76d5326536fd7ee 100644 (file)
@@ -40221,6 +40221,8 @@ cp_parser_omp_clause_name (cp_parser *parser)
            result = PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR;
          else if (!strcmp ("use_device_ptr", p))
            result = PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR;
+         else if (!strcmp ("uses_allocators", p))
+           result = PRAGMA_OMP_CLAUSE_USES_ALLOCATORS;
          break;
        case 'v':
          if (!strcmp ("vector", p))
@@ -42779,6 +42781,199 @@ cp_parser_omp_clause_allocate (cp_parser *parser, tree list)
   return nlist;
 }
 
+/* OpenMP 5.0:
+   uses_allocators ( allocator-list )
+
+   allocator-list:
+   allocator
+   allocator , allocator-list
+   allocator ( traits-array )
+   allocator ( traits-array ) , allocator-list
+
+   OpenMP 5.2:
+
+   uses_allocators ( modifier : allocator-list )
+   uses_allocators ( modifier , modifier : allocator-list )
+
+   modifier:
+   traits ( traits-array )
+   memspace ( mem-space-handle )  */
+
+static tree
+cp_parser_omp_clause_uses_allocators (cp_parser *parser, tree list)
+{
+  location_t clause_loc
+    = cp_lexer_peek_token (parser->lexer)->location;
+  tree nl = list;
+  matching_parens parens;
+  if (!parens.require_open (parser))
+    return list;
+
+  bool has_modifiers = false;
+  bool seen_allocators = false;
+  tree memspace_expr = NULL_TREE;
+  tree traits_var = NULL_TREE;
+
+  cp_parser_parse_tentatively (parser);
+  bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
+  parser->colon_corrects_to_scope_p = false;
+
+  cp_token *dup_mod_tok = NULL;
+  for (int mod = 0; mod <= 2; mod++)
+    if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+       && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_PAREN))
+      {
+       cp_token *mod_tok = cp_lexer_peek_token (parser->lexer);
+       tree id = mod_tok->u.value;
+       const char *p = IDENTIFIER_POINTER (id);
+       if (strcmp (p, "traits") != 0 && strcmp (p, "memspace") != 0)
+         break;
+       cp_lexer_consume_token (parser->lexer);
+       matching_parens parens2;
+       if (!parens2.require_open (parser))
+         break;
+       tree t = cp_parser_assignment_expression (parser);
+       if (strcmp (p, "traits") == 0)
+         {
+           if (traits_var != NULL_TREE)
+             dup_mod_tok = mod_tok;
+           else
+             traits_var = t;
+         }
+       else
+         {
+           if (memspace_expr != NULL_TREE)
+             dup_mod_tok = mod_tok;
+           else
+             memspace_expr = t;
+         }
+       if (!parens2.require_close (parser))
+         break;
+       if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+         {
+           has_modifiers = true;
+           cp_lexer_consume_token (parser->lexer);
+           break;
+         }
+       if (/*mod != 0 || */ cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
+         break;
+       cp_lexer_consume_token (parser->lexer);
+      }
+    else
+      break;
+
+  if (!has_modifiers)
+    {
+      cp_parser_abort_tentative_parse (parser);
+      traits_var = NULL_TREE;
+      memspace_expr = NULL_TREE;
+    }
+  else
+    {
+      if (dup_mod_tok)
+       {
+         error_at (dup_mod_tok->location, "duplicate %qs modifier",
+                   IDENTIFIER_POINTER (dup_mod_tok->u.value));
+         cp_parser_parse_definitely (parser);
+         goto end;
+       }
+      cp_parser_parse_definitely (parser);
+    }
+  parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
+
+  while (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+    {
+      cp_token *tok = cp_lexer_peek_token (parser->lexer);
+      tree t;
+      t = cp_parser_lookup_name_simple (parser,
+                                       tok->u.value,
+                                       tok->location);
+      if (t == error_mark_node)
+       cp_parser_name_lookup_error (parser, tok->u.value, t, NLE_NULL,
+                                    tok->location);
+      cp_lexer_consume_token (parser->lexer);
+
+      /* Legacy traits syntax.  */
+      tree legacy_traits = NULL_TREE;
+      if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)
+         && cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME)
+         && cp_lexer_nth_token_is (parser->lexer, 3, CPP_CLOSE_PAREN))
+       {
+         matching_parens parens2;
+         parens2.require_open (parser);
+         cp_token *arg_tok = cp_lexer_peek_token (parser->lexer);
+
+         tree arg = cp_parser_lookup_name_simple (parser, arg_tok->u.value,
+                                                  arg_tok->location);
+         if (arg == error_mark_node)
+           cp_parser_name_lookup_error (parser, arg_tok->u.value, arg,
+                                        NLE_NULL, arg_tok->location);
+         cp_lexer_consume_token (parser->lexer);
+         location_t close_loc = cp_lexer_peek_token (parser->lexer)->location;
+         parens2.require_close (parser);
+
+         if (has_modifiers)
+           {
+             error_at (make_location (tok->location, tok->location, close_loc),
+                       "legacy %<%E(%E)%> traits syntax not allowed in "
+                       "%<uses_allocators%> clause when using modifiers",
+                       tok->u.value, arg_tok->u.value);
+             goto end;
+           }
+         legacy_traits = arg;
+         if (legacy_traits == error_mark_node)
+           goto end;
+         gcc_rich_location richloc (make_location (tok->location,
+                                                   tok->location, close_loc));
+         if (nl == list)
+           {
+             /* Fixit only works well if it is the first item.  */
+             richloc.add_fixit_replace (tok->location, "traits");
+             richloc.add_fixit_insert_after (close_loc, ": ");
+             richloc.add_fixit_insert_after (close_loc,
+                                             IDENTIFIER_POINTER (tok->u.value));
+           }
+         warning_at (&richloc, OPT_Wdeprecated_openmp,
+                     "the specification of arguments to %<uses_allocators%> "
+                     "where each item is of the form %<allocator(traits)%> is "
+                     "deprecated since OpenMP 5.2");
+       }
+
+      if (seen_allocators && has_modifiers)
+       {
+         error_at (cp_lexer_peek_token (parser->lexer)->location,
+                   "%<uses_allocators%> clause only accepts a single "
+                   "allocator when using modifiers");
+         goto end;
+       }
+      seen_allocators = true;
+
+      tree c = build_omp_clause (clause_loc,
+                                OMP_CLAUSE_USES_ALLOCATORS);
+      OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (c) = t;
+      OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE (c) = memspace_expr;
+      OMP_CLAUSE_USES_ALLOCATORS_TRAITS (c) = (legacy_traits
+                                              ? legacy_traits : traits_var);
+      OMP_CLAUSE_CHAIN (c) = nl;
+      nl = c;
+
+      if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
+       cp_lexer_consume_token (parser->lexer);
+      else
+       break;
+    }
+
+  if (!parens.require_close (parser))
+    goto end;
+  return nl;
+ end:
+  cp_parser_skip_to_closing_parenthesis (parser,
+                                        /*recovering=*/true,
+                                        /*or_comma=*/false,
+                                        /*consume_paren=*/true);
+  return nl;
+}
+
 /* OpenMP 2.5:
    lastprivate ( variable-list )
 
@@ -45447,6 +45642,10 @@ cp_parser_omp_all_clauses (cp_parser *parser, omp_clause_mask mask,
          clauses = cp_parser_omp_clause_allocate (parser, clauses);
          c_name = "allocate";
          break;
+       case PRAGMA_OMP_CLAUSE_USES_ALLOCATORS:
+         clauses = cp_parser_omp_clause_uses_allocators (parser, clauses);
+         c_name = "uses_allocators";
+         break;
        case PRAGMA_OMP_CLAUSE_LINEAR:
          {
            bool declare_simd = false;
@@ -50374,7 +50573,8 @@ cp_parser_omp_target_update (cp_parser *parser, cp_token *pragma_tok,
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_MAP)          \
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT)       \
        | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PRIVATE)      \
-       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT))
+       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \
+       | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USES_ALLOCATORS))
 
 static bool
 cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
index ce30b52766383d4fbe8dd66aec02cc7576e15bff..341e5ab8808a50094a635883e3e3d88285582e8a 100644 (file)
@@ -18296,6 +18296,14 @@ tsubst_omp_clauses (tree clauses, enum c_omp_region_type ort,
              = tsubst_stmt (OMP_CLAUSE_LINEAR_STEP (oc), args,
                             complain, in_decl);
          break;
+       case OMP_CLAUSE_USES_ALLOCATORS:
+         OMP_CLAUSE_OPERAND (nc, 0)
+           = tsubst_stmt (OMP_CLAUSE_OPERAND (oc, 0), args, complain, in_decl);
+         OMP_CLAUSE_OPERAND (nc, 1)
+           = tsubst_stmt (OMP_CLAUSE_OPERAND (oc, 1), args, complain, in_decl);
+         OMP_CLAUSE_OPERAND (nc, 2)
+           = tsubst_stmt (OMP_CLAUSE_OPERAND (oc, 2), args, complain, in_decl);
+         break;
        case OMP_CLAUSE_INIT:
          if (ort == C_ORT_OMP_INTEROP
              && OMP_CLAUSE_INIT_PREFER_TYPE (nc)
index 331db16f76dee08a6132c0e27ff71cf4de99d749..e420fd4ebafb9a24eac289d9a92dbc87a4e1f3db 100644 (file)
@@ -8888,6 +8888,162 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
              break;
            }
          gcc_unreachable ();
+       case OMP_CLAUSE_USES_ALLOCATORS:
+         t = OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (c);
+         t = convert_from_reference (t);
+         if (t == error_mark_node)
+           {
+             remove = true;
+             break;
+           }
+         if (DECL_P (t)
+             && (bitmap_bit_p (&generic_head, DECL_UID (t))
+                 || bitmap_bit_p (&firstprivate_head, DECL_UID (t))
+                 || bitmap_bit_p (&map_firstprivate_head, DECL_UID (t))))
+           {
+             error_at (OMP_CLAUSE_LOCATION (c),
+                       "%qE appears more than once in data clauses", t);
+             remove = true;
+           }
+         else if (DECL_P (t))
+           bitmap_set_bit (&generic_head, DECL_UID (t));
+         if (type_dependent_expression_p (t))
+           break;
+         if (TREE_CODE (t) == FIELD_DECL)
+           {
+             sorry_at (OMP_CLAUSE_LOCATION (c), "class member %qE not yet "
+                       "supported in %<uses_allocators%> clause", t);
+             remove = true;
+             break;
+           }
+         if (TREE_CODE (TREE_TYPE (t)) != ENUMERAL_TYPE
+             || strcmp (IDENTIFIER_POINTER (TYPE_IDENTIFIER (TREE_TYPE (t))),
+                        "omp_allocator_handle_t") != 0)
+           {
+             error_at (OMP_CLAUSE_LOCATION (c),
+                       "allocator %qE must be of %<omp_allocator_handle_t%> "
+                       "type", t);
+             remove = true;
+             break;
+           }
+         tree init;
+         if (TREE_CODE (t) == CONST_DECL)
+           init = DECL_INITIAL(t);
+         else
+           init = t;
+         if (!DECL_P (t)
+             && (init == NULL_TREE
+                 || TREE_CODE (init) != INTEGER_CST
+                 || ((wi::to_widest (init) < 0
+                      || wi::to_widest (init) > GOMP_OMP_PREDEF_ALLOC_MAX)
+                     && (wi::to_widest (init) < GOMP_OMPX_PREDEF_ALLOC_MIN
+                         || (wi::to_widest (init)
+                             > GOMP_OMPX_PREDEF_ALLOC_MAX)))))
+           {
+             remove = true;
+             error_at (OMP_CLAUSE_LOCATION (c),
+                       "allocator %qE must be either a variable or a "
+                       "predefined allocator", t);
+             break;
+           }
+         else if (TREE_CODE (t) == CONST_DECL)
+           {
+             /* omp_null_allocator is ignored and for predefined allocators,
+                not special handling is required; thus, remove them removed. */
+             remove = true;
+
+             if (OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE (c)
+                 || OMP_CLAUSE_USES_ALLOCATORS_TRAITS (c))
+               {
+                 error_at (OMP_CLAUSE_LOCATION (c),
+                           "modifiers cannot be used with predefined "
+                           "allocators");
+                 break;
+               }
+           }
+         t = OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE (c);
+         if (t == error_mark_node)
+           {
+             remove = true;
+             break;
+           }
+         if (t != NULL_TREE
+             && !type_dependent_expression_p (t)
+             && ((TREE_CODE (t) != CONST_DECL && TREE_CODE (t) != INTEGER_CST)
+                 || TREE_CODE (TREE_TYPE (t)) != ENUMERAL_TYPE
+                 || strcmp (IDENTIFIER_POINTER (TYPE_IDENTIFIER (TREE_TYPE (t))),
+                            "omp_memspace_handle_t") != 0))
+           {
+             error_at (OMP_CLAUSE_LOCATION (c), "memspace modifier %qE must be"
+                       " constant enum of %<omp_memspace_handle_t%> type", t);
+             remove = true;
+             break;
+           }
+         t = OMP_CLAUSE_USES_ALLOCATORS_TRAITS (c);
+         if (t == error_mark_node)
+           {
+             remove = true;
+             break;
+           }
+         if (type_dependent_expression_p (t))
+           break;
+         if (t != NULL_TREE
+             && t != error_mark_node
+             && !type_dependent_expression_p (t)
+             && (!DECL_P (t)
+                 ||  DECL_EXTERNAL (t)
+                 || TREE_CODE (t) == PARM_DECL))
+           {
+             error_at (OMP_CLAUSE_LOCATION (c), "traits array %qE must be "
+                       "defined in same scope as the construct on which the "
+                       "clause appears", t);
+             remove = true;
+           }
+         if (t != NULL_TREE)
+           {
+             bool type_err = false;
+
+             if (TREE_CODE (TREE_TYPE (t)) != ARRAY_TYPE
+                 || DECL_SIZE (t) == NULL_TREE
+                 || !COMPLETE_TYPE_P (TREE_TYPE (t)))
+               type_err = true;
+             else
+               {
+                 tree elem_t = TREE_TYPE (TREE_TYPE (t));
+                 if (TREE_CODE (elem_t) != RECORD_TYPE
+                     || strcmp (IDENTIFIER_POINTER (TYPE_IDENTIFIER (elem_t)),
+                                "omp_alloctrait_t") != 0
+                     || !TYPE_READONLY (elem_t))
+                   type_err = true;
+               }
+             if (type_err)
+               {
+                 error_at (OMP_CLAUSE_LOCATION (c), "traits array %qE must "
+                           "be of %<const omp_alloctrait_t []%> type", t);
+                 remove = true;
+               }
+             else if (TREE_CODE (array_type_nelts_top (TREE_TYPE (t)))
+                      != INTEGER_CST)
+               {
+                 error_at (OMP_CLAUSE_LOCATION (c), "variable length traits "
+                           "arrays are not supported");
+                 remove = true;
+               }
+             else
+               {
+                 tree cst_val = decl_constant_value (t);
+                 if (cst_val == t)
+                   {
+                     error_at (OMP_CLAUSE_LOCATION (c), "traits array must be "
+                               "initialized with constants");
+                     remove = true;
+                   }
+               }
+           }
+         if (remove)
+           break;
+         pc = &OMP_CLAUSE_CHAIN (c);
+         continue;
        case OMP_CLAUSE_DEPEND:
          depend_clause = c;
          /* FALLTHRU */
index 31534ea0393a71d98bf4d95ef3e562529eb92a29..68533a77882bd24dc5a57ed383a189a4f9ba1ec2 100644 (file)
@@ -10133,6 +10133,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
                               "%<omp_allocator_handle_kind%>", n->sym->name,
                               &n->where);
                  else if (n->sym->attr.flavor != FL_VARIABLE
+                          && strcmp (n->sym->name, "omp_null_allocator") != 0
                           && ((!startswith (n->sym->name, "omp_")
                                && !startswith (n->sym->name, "ompx_"))
                               || !endswith (n->sym->name, "_mem_alloc")))
index 8eb4fc4bcc6610dd4da309639826229e92710d85..a07dc2ec0e98f7c9ceb724b8d92f01c426885ccc 100644 (file)
@@ -5093,7 +5093,8 @@ gfc_trans_omp_clauses (stmtblock_t *block, gfc_omp_clauses *clauses,
            }
          break;
        case OMP_LIST_USES_ALLOCATORS:
-         /* Ignore pre-defined allocators as no special treatment is needed. */
+         /* Ignore omp_null_allocator and pre-defined allocators as no
+            special treatment is needed. */
          for (; n != NULL; n = n->next)
            if (n->sym->attr.flavor == FL_VARIABLE)
              break;
index 0023728ad8eb5f1f333611670bfb801f297a271d..28d7fa3516c256ac2509df9cb6149a808ce6a3c3 100644 (file)
@@ -14858,6 +14858,11 @@ gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
          nowait = 1;
          break;
 
+       case OMP_CLAUSE_USES_ALLOCATORS:
+         sorry_at (OMP_CLAUSE_LOCATION (c), "%<uses_allocators%> clause");
+         remove = 1;
+         break;
+
        case OMP_CLAUSE_ORDERED:
        case OMP_CLAUSE_UNTIED:
        case OMP_CLAUSE_COLLAPSE:
@@ -16366,6 +16371,7 @@ end_adjust_omp_map_clause:
        case OMP_CLAUSE_FINALIZE:
        case OMP_CLAUSE_INCLUSIVE:
        case OMP_CLAUSE_EXCLUSIVE:
+       case OMP_CLAUSE_USES_ALLOCATORS:
          break;
 
        case OMP_CLAUSE_NOHOST:
diff --git a/gcc/testsuite/c-c++-common/gomp/uses_allocators-1.c b/gcc/testsuite/c-c++-common/gomp/uses_allocators-1.c
new file mode 100644 (file)
index 0000000..df82cbb
--- /dev/null
@@ -0,0 +1,48 @@
+typedef enum omp_allocator_handle_t
+#if __cplusplus >= 201103L
+: __UINTPTR_TYPE__
+#endif
+{
+  omp_default_mem_alloc = 1,
+  omp_low_lat_mem_alloc = 5,
+  __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+typedef struct omp_alloctrait_t
+{
+  int key;
+  int value;
+} omp_alloctrait_t;
+
+extern void *omp_alloc (__SIZE_TYPE__, omp_allocator_handle_t);
+
+void
+f (omp_allocator_handle_t my_alloc)
+{
+  #pragma omp target
+  {
+    int a; /* { dg-error "'my_alloc' in 'allocator' clause inside a target region must be specified in an 'uses_allocators' clause on the 'target' directive" "not yet implemented" { xfail *-*-* } } */
+    #pragma omp allocate(a) allocator(my_alloc) /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } }  */
+    a  = 5;
+    void *prt = omp_alloc(32, my_alloc);
+    #pragma omp parallel allocate(allocator(my_alloc) : a) firstprivate(a) /* { dg-error "allocator 'my_alloc' in 'allocate' clause inside a target region must be specified in an 'uses_allocators' clause on the 'target' directive" "not yet implemented" { xfail *-*-* } } */
+      a = 7;
+  }
+}
+
+void
+g (omp_allocator_handle_t my_alloc)
+{
+  /* The following defines a default-mem-space allocator with no extra traits. */
+  #pragma omp target uses_allocators(my_alloc)
+  {
+    int a;
+    #pragma omp allocate(a) allocator(my_alloc)  /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } }  */
+    a  = 5;
+    void *prt = omp_alloc(32, my_alloc);
+    #pragma omp parallel allocate(allocator(my_alloc) : a) firstprivate(a)
+      a = 7;
+  }
+}
+
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target *-*-* } 37 }
diff --git a/gcc/testsuite/c-c++-common/gomp/uses_allocators-2.c b/gcc/testsuite/c-c++-common/gomp/uses_allocators-2.c
new file mode 100644 (file)
index 0000000..c766ea3
--- /dev/null
@@ -0,0 +1,35 @@
+typedef enum omp_allocator_handle_t
+#if __cplusplus >= 201103L
+: __UINTPTR_TYPE__
+#endif
+{
+  omp_default_mem_alloc = 1,
+  omp_low_lat_mem_alloc = 5,
+  __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+typedef struct omp_alloctrait_t
+{
+  int key;
+  int value;
+} omp_alloctrait_t;
+
+void
+f ()
+{
+   omp_alloctrait_t trait[1] = {{1,1}};
+   omp_allocator_handle_t my_alloc;
+   #pragma omp target uses_allocators(traits(trait) : my_alloc)  /* { dg-error "traits array 'trait' must be of 'const omp_alloctrait_t \\\[\\\]' type" } */
+     ;
+}
+
+void
+g ()
+{
+   const omp_alloctrait_t trait[1] = {{1,1}};
+   omp_allocator_handle_t my_alloc;
+   #pragma omp target uses_allocators(traits(trait) : my_alloc)
+     ;
+}
+
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target *-*-* } 31 }
diff --git a/gcc/testsuite/c-c++-common/gomp/uses_allocators-4.c b/gcc/testsuite/c-c++-common/gomp/uses_allocators-4.c
new file mode 100644 (file)
index 0000000..5f36501
--- /dev/null
@@ -0,0 +1,144 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-Wno-deprecated-openmp" } */
+
+//#include <omp.h>
+
+typedef __UINTPTR_TYPE__ omp_uintptr_t;
+
+#if __cplusplus >= 201103L
+# define __GOMP_UINTPTR_T_ENUM : omp_uintptr_t
+#else
+# define __GOMP_UINTPTR_T_ENUM
+#endif
+
+typedef enum omp_memspace_handle_t __GOMP_UINTPTR_T_ENUM
+{
+  omp_default_mem_space = 0,
+  omp_large_cap_mem_space = 1,
+  omp_const_mem_space = 2,
+  omp_high_bw_mem_space = 3,
+  omp_low_lat_mem_space = 4,
+  ompx_gnu_managed_mem_space = 200,
+  __omp_memspace_handle_t_max__ = __UINTPTR_MAX__
+} omp_memspace_handle_t;
+
+typedef enum omp_allocator_handle_t __GOMP_UINTPTR_T_ENUM
+{
+  omp_null_allocator = 0,
+  omp_default_mem_alloc = 1,
+  omp_large_cap_mem_alloc = 2,
+  omp_const_mem_alloc = 3,
+  omp_high_bw_mem_alloc = 4,
+  omp_low_lat_mem_alloc = 5,
+  omp_cgroup_mem_alloc = 6,
+  omp_pteam_mem_alloc = 7,
+  omp_thread_mem_alloc = 8,
+  ompx_gnu_pinned_mem_alloc = 200,
+  ompx_gnu_managed_mem_alloc = 201,
+  __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+typedef enum omp_alloctrait_key_t
+{
+  omp_atk_sync_hint = 1,
+  omp_atk_alignment = 2,
+  omp_atk_access = 3,
+  omp_atk_pool_size = 4,
+  omp_atk_fallback = 5,
+  omp_atk_fb_data = 6,
+  omp_atk_pinned = 7,
+  omp_atk_partition = 8
+} omp_alloctrait_key_t;
+
+typedef enum omp_alloctrait_value_t
+{
+  omp_atv_default = (__UINTPTR_TYPE__) -1,
+  omp_atv_false = 0,
+  omp_atv_true = 1,
+  omp_atv_contended = 3,
+  omp_atv_uncontended = 4,
+  omp_atv_serialized = 5,
+  omp_atv_private = 6,
+  omp_atv_all = 7,
+  omp_atv_thread = 8,
+  omp_atv_pteam = 9,
+  omp_atv_cgroup = 10,
+  omp_atv_default_mem_fb = 11,
+  omp_atv_null_fb = 12,
+  omp_atv_abort_fb = 13,
+  omp_atv_allocator_fb = 14,
+  omp_atv_environment = 15,
+  omp_atv_nearest = 16,
+  omp_atv_blocked = 17,
+  omp_atv_interleaved = 18
+} omp_alloctrait_value_t;
+
+typedef struct omp_alloctrait_t
+{
+  omp_alloctrait_key_t key;
+  omp_uintptr_t value;
+} omp_alloctrait_t;
+
+omp_alloctrait_key_t k;
+omp_alloctrait_value_t v;
+
+int f (const omp_alloctrait_t arg_traits[], int n)
+{
+  omp_allocator_handle_t foo, bar;
+  const omp_alloctrait_t traits_array[] = { { omp_atk_pinned,    omp_atv_true },
+                                           { omp_atk_partition, omp_atv_nearest } };
+  extern const omp_alloctrait_t ex_traits[2];
+  extern const omp_alloctrait_t ex2_traits[];
+#ifndef __cplusplus
+  const omp_alloctrait_t vla_traits[n] = {};  /* Not useful, but shouldn't crash.  */
+#else
+  const omp_alloctrait_t vla_traits[n] = { { omp_atk_pinned,    omp_atv_true },
+                                          { omp_atk_partition, omp_atv_nearest } };
+#endif
+
+  #pragma omp target uses_allocators (baz) /* { dg-error "'baz' undeclared .first use in this function." "" { target c } } */
+    ;                                      /* { dg-error "'baz' has not been declared" "" { target c++ } .-1 } */
+  #pragma omp target uses_allocators (foo (xyz)) /* { dg-error "'xyz' undeclared .first use in this function." "" { target c } } */
+    ;                                            /* { dg-error "'xyz' has not been declared" "" { target c++ } .-1 } */
+  #pragma omp target uses_allocators (foo (traits_array), baz (traits_array)) /* { dg-error "'baz' has not been declared" "" { target c++ } } */
+    ;
+  #pragma omp target uses_allocators (foo (arg_traits)) /* { dg-error "traits array 'arg_traits' must be defined in same scope as the construct on which the clause appears" } */
+    ;                                                   /* { dg-error "traits array 'arg_traits' must be of 'const omp_alloctrait_t \\\[\\\]' type" "" { target *-*-* } .-1 } */
+  #pragma omp target uses_allocators (foo (ex_traits)) /* { dg-error "traits array 'ex_traits' must be defined in same scope as the construct on which the clause appears" } */
+    ;                                                  /* { dg-error "traits array must be initialized with constants" "" { target *-*-* } .-1 } */
+  #pragma omp target uses_allocators (foo (ex2_traits)) /* { dg-error "traits array 'ex2_traits' must be defined in same scope as the construct on which the clause appears" } */
+    ;                                                   /* { dg-error "traits array 'ex2_traits' must be of 'const omp_alloctrait_t \\\[\\\]' type" "" { target *-*-* } .-1 } */
+  #pragma omp target uses_allocators (foo (vla_traits)) /* { dg-error "variable length traits arrays are not supported" "" { target c++ } } */
+    ;
+  #pragma omp target uses_allocators (memspace(omp_no_such_space) : foo) /* { dg-error "'omp_no_such_space' undeclared .first use in this function." "" { target c } } */
+    ;                                                                    /* { dg-error "'omp_no_such_space' was not declared in this scope" "" { target c++ } .-1 } */
+  #pragma omp target uses_allocators (memspace(1) : foo) /* { dg-error "memspace modifier '1' must be constant enum of 'omp_memspace_handle_t' type" } */
+    ;
+  #pragma omp target uses_allocators (memspace(omp_no_such_space) : foo, bar) /* { dg-error "'uses_allocators' clause only accepts a single allocator when using modifiers" } */
+    ;                                                                         /* { dg-error "memspace modifier 'omp_no_such_space' must be constant enum of 'omp_memspace_handle_t' type" "" { target c++ } .-1 } */
+  #pragma omp target uses_allocators (traits(xyz) : bar) /* { dg-error "'xyz' was not declared in this scope" "" { target c++ } } */
+    ;
+  #pragma omp target uses_allocators (memspace(omp_high_bw_mem_space), traits(traits_array), memspace (omp_no_such_space) : bar) /* { dg-error "duplicate 'memspace' modifier" "" { target c } } */
+    ;                                                                                                                            /* { dg-error "expected '\\\)' before 'memspace" "" { target c } .-1 } */
+                                                                                                                                 /* { dg-error "duplicate 'memspace' modifier" "" { target c++ } .-2 } */
+  #pragma omp target uses_allocators (traitz(traits_array), memspace(omp_high_bw_mem_space) : bar) /* { dg-error "'traitz' undeclared .first use in this function." "" { target c } } */
+    ;                                                                                              /* { dg-error "'memspace' undeclared .first use in this function." "" { target c } .-1 } */
+                                                                                                   /* { dg-error "'traitz' has not been declared" "" { target c++ } .-2 } */
+                                                                                                   /* { dg-error "'memspace' has not been declared" "" { target c++ } .-3 } */
+                                                                                                   /* { dg-error "expected '\\\)' before ':' token" "" { target *-*-* } .-4 } */
+  #pragma omp target uses_allocators (omp_null_allocator)
+    ;
+  #pragma omp target uses_allocators (memspace(omp_high_bw_mem_space) : foo, bar) /* { dg-error "'uses_allocators' clause only accepts a single allocator when using modifiers" } */
+    ;
+  #pragma omp target uses_allocators (memspace(omp_high_bw_mem_space) : foo(foo_traits)) /* { dg-error "'foo_traits' undeclared .first use in this function.; did you mean 'vla_traits'." "" { target c } } */
+    ;                                                                                    /* { dg-error "'foo_traits' has not been declared" "" { target c++ } .-1 } */
+                                                                                         /* { dg-error "legacy 'foo\\\(foo_traits\\\)' traits syntax not allowed in 'uses_allocators' clause when using modifiers" "" { target *-*-* } .-2 } */
+  return 0;
+}
+
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target *-*-* } 103 }
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target c } 111 }
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target c } 113 }
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target c } 117 }
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target c } 119 }
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target *-*-* } 131 }
diff --git a/gcc/testsuite/c-c++-common/gomp/uses_allocators-7.c b/gcc/testsuite/c-c++-common/gomp/uses_allocators-7.c
new file mode 100644 (file)
index 0000000..ce43d70
--- /dev/null
@@ -0,0 +1,83 @@
+// { dg-do compile }
+
+//#include <omp.h>
+
+typedef __UINTPTR_TYPE__ omp_uintptr_t;
+
+#if __cplusplus >= 201103L
+# define __GOMP_UINTPTR_T_ENUM : omp_uintptr_t
+#else
+# define __GOMP_UINTPTR_T_ENUM
+#endif
+
+typedef enum omp_memspace_handle_t __GOMP_UINTPTR_T_ENUM
+{
+  omp_default_mem_space = 0,
+  omp_large_cap_mem_space = 1,
+  omp_const_mem_space = 2,
+  omp_high_bw_mem_space = 3,
+  omp_low_lat_mem_space = 4,
+  ompx_gnu_managed_mem_space = 200,
+  __omp_memspace_handle_t_max__ = __UINTPTR_MAX__
+} omp_memspace_handle_t;
+
+typedef enum omp_allocator_handle_t __GOMP_UINTPTR_T_ENUM
+{
+  omp_null_allocator = 0,
+  omp_default_mem_alloc = 1,
+  omp_large_cap_mem_alloc = 2,
+  omp_const_mem_alloc = 3,
+  omp_high_bw_mem_alloc = 4,
+  omp_low_lat_mem_alloc = 5,
+  omp_cgroup_mem_alloc = 6,
+  omp_pteam_mem_alloc = 7,
+  omp_thread_mem_alloc = 8,
+  ompx_gnu_pinned_mem_alloc = 200,
+  ompx_gnu_managed_mem_alloc = 201,
+  __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+typedef struct omp_alloctrait_t
+{
+//  omp_alloctrait_key_t key;
+//  omp_uintptr_t value;
+} omp_alloctrait_t;
+
+
+void f()
+{
+ omp_allocator_handle_t my;
+ struct t {
+   omp_allocator_handle_t a1;
+ } s;
+
+const omp_allocator_handle_t my3 = (omp_allocator_handle_t) 300;
+omp_allocator_handle_t my4[1];
+const omp_alloctrait_t t[] = {};
+ #pragma omp target uses_allocators(my, omp_default_mem_alloc, omp_null_allocator)  // OK
+   ;
+ #pragma omp target uses_allocators(my) firstprivate(my) // { dg-error "'my' appears more than once in data clauses" }
+   ;
+ #pragma omp target private(my) uses_allocators(my) // { dg-error "'my' appears more than once in data clauses" }
+   ;
+ #pragma omp target uses_allocators(my3)
+   ;
+ #pragma omp target uses_allocators(s.a1)
+   // { dg-error "expected '\\)' before '\\.' token" "" { target *-*-* } .-1 }
+   // { dg-error "allocator 's' must be of 'omp_allocator_handle_t' type" "" { target *-*-* } .-2 }
+   ;
+ #pragma omp target uses_allocators(my4)
+   // { dg-error "allocator 'my4' must be of 'omp_allocator_handle_t' type" "" { target *-*-* } .-1 }
+   ;
+ #pragma omp target uses_allocators(my4[0])
+   // { dg-error "expected '\\)' before '\\\[' token" "" { target *-*-* } .-1 }
+   // { dg-error "allocator 'my4' must be of 'omp_allocator_handle_t' type" "" { target *-*-* } .-2 }
+   ;
+ #pragma omp target uses_allocators(memspace(omp_default_mem_space) : my, my(t)) // { dg-error "legacy 'my\\(t\\)' traits syntax not allowed in 'uses_allocators' clause when using modifiers" }
+   ;
+}
+
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target *-*-* } 57 }
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target *-*-* } 61 }
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target *-*-* } 63 }
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target *-*-* } 76 }
diff --git a/gcc/testsuite/g++.dg/gomp/deprecate-2.C b/gcc/testsuite/g++.dg/gomp/deprecate-2.C
new file mode 100644 (file)
index 0000000..46d2861
--- /dev/null
@@ -0,0 +1,47 @@
+/* { dg-additional-options "-fdiagnostics-show-caret -Wdeprecated-openmp" } */
+
+typedef enum omp_allocator_handle_t
+#if __cplusplus >= 201103L
+: __UINTPTR_TYPE__
+#endif
+{
+  __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+typedef struct omp_alloctrait_t
+{
+  int key;
+  int value;
+} omp_alloctrait_t;
+
+
+void f()
+{
+  omp_allocator_handle_t myalloc;
+  const omp_alloctrait_t mytraits[] = {};
+  #pragma omp target uses_allocators(myalloc(mytraits))
+/* { dg-begin-multiline-output "" }
+   #pragma omp target uses_allocators(myalloc(mytraits))
+                                      ^~~~~~~~~~~~~~~~~
+                                      -------
+                                      traits           : myalloc
+   { dg-end-multiline-output "" } */
+   ;
+
+// { dg-warning "38: the specification of arguments to 'uses_allocators' where each item is of the form 'allocator\\(traits\\)' is deprecated since OpenMP 5.2 \\\[-Wdeprecated-openmp\\\]" "" { target *-*-* }  22 }
+
+
+  #pragma omp target uses_allocators  (  myalloc  (  mytraits  )  )
+/* { dg-begin-multiline-output "" }
+   #pragma omp target uses_allocators  (  myalloc  (  mytraits  )  )
+                                          ^~~~~~~~~~~~~~~~~~~~~~~
+                                          -------
+                                          traits                 : myalloc
+   { dg-end-multiline-output "" } */
+   ;
+
+// { dg-warning "42: the specification of arguments to 'uses_allocators' where each item is of the form 'allocator\\(traits\\)' is deprecated since OpenMP 5.2 \\\[-Wdeprecated-openmp\\\]" "" { target *-*-* }  34 }
+}
+
+// { dg-excess-errors "sorry, unimplemented: 'uses_allocators' clause" }
+// { dg-excess-errors "sorry, unimplemented: 'uses_allocators' clause" }
diff --git a/gcc/testsuite/g++.dg/gomp/uses_allocators-1.C b/gcc/testsuite/g++.dg/gomp/uses_allocators-1.C
new file mode 100644 (file)
index 0000000..79e5163
--- /dev/null
@@ -0,0 +1,105 @@
+// { dg-do compile }
+/* { dg-additional-options "-Wno-deprecated-openmp" } */
+
+//#include <omp.h>
+
+typedef __UINTPTR_TYPE__ omp_uintptr_t;
+
+#if __cplusplus >= 201103L
+# define __GOMP_UINTPTR_T_ENUM : omp_uintptr_t
+#else
+# define __GOMP_UINTPTR_T_ENUM
+#endif
+
+typedef enum omp_memspace_handle_t __GOMP_UINTPTR_T_ENUM
+{
+  omp_default_mem_space = 0,
+  omp_large_cap_mem_space = 1,
+  omp_const_mem_space = 2,
+  omp_high_bw_mem_space = 3,
+  omp_low_lat_mem_space = 4,
+  ompx_gnu_managed_mem_space = 200,
+  __omp_memspace_handle_t_max__ = __UINTPTR_MAX__
+} omp_memspace_handle_t;
+
+typedef enum omp_allocator_handle_t __GOMP_UINTPTR_T_ENUM
+{
+  omp_null_allocator = 0,
+  omp_default_mem_alloc = 1,
+  omp_large_cap_mem_alloc = 2,
+  omp_const_mem_alloc = 3,
+  omp_high_bw_mem_alloc = 4,
+  omp_low_lat_mem_alloc = 5,
+  omp_cgroup_mem_alloc = 6,
+  omp_pteam_mem_alloc = 7,
+  omp_thread_mem_alloc = 8,
+  ompx_gnu_pinned_mem_alloc = 200,
+  ompx_gnu_managed_mem_alloc = 201,
+  __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+typedef struct omp_alloctrait_t
+{
+//  omp_alloctrait_key_t key;
+//  omp_uintptr_t value;
+} omp_alloctrait_t;
+
+
+template<typename TH, TH alloc>
+void f()
+{
+ #pragma omp target uses_allocators(alloc)
+   ;
+}
+
+template<typename TH, typename TT>
+void g(TT trait, TH alloc)
+{
+ #pragma omp target uses_allocators(alloc)
+   ;
+ #pragma omp target uses_allocators(alloc(trait))
+   // { dg-error "traits array 'trait' must be defined in same scope as the construct on which the clause appears" "" { target *-*-* } .-1 }
+   // { dg-error "traits array 'trait' must be of 'const omp_alloctrait_t \\\[\\\]' type" "" { target *-*-* } .-2 }
+   ;
+}
+
+void use()
+{
+  omp_allocator_handle_t my;
+  static const omp_alloctrait_t t[] = {};
+
+  f<omp_allocator_handle_t, omp_null_allocator>(); // OK
+  f<omp_allocator_handle_t, omp_default_mem_alloc>(); // OK
+
+  g<omp_allocator_handle_t, const omp_alloctrait_t[]>(t, my); // 't'/traits not in the same scope
+}
+
+template<typename TH, TH alloc>
+void f2()
+{
+ #pragma omp target uses_allocators(alloc)
+   // { dg-error "allocator '\\(omp_allocator_handle_t\\)300' must be either a variable or a predefined allocator" "" { target *-*-* } .-1 }
+   ;
+}
+
+template<typename TH, typename TT>
+void g2(TH alloc)
+{
+ TT t = {};
+ #pragma omp target uses_allocators(alloc(t))
+   ;
+}
+
+void use2()
+{
+  omp_allocator_handle_t my;
+  const omp_allocator_handle_t wrong = (omp_allocator_handle_t) 300;
+
+  f2<omp_allocator_handle_t, wrong>(); // 300 is not a predefined allocator
+
+  g2<omp_allocator_handle_t, const omp_alloctrait_t[]>(my); // OK
+}
+
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target *-*-* } 51 }
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target *-*-* } 58 }
+// { dg-message "sorry, unimplemented: 'uses_allocators' clause" "" { target *-*-* } 89 }
diff --git a/gcc/testsuite/gcc.dg/gomp/deprecate-2.c b/gcc/testsuite/gcc.dg/gomp/deprecate-2.c
new file mode 100644 (file)
index 0000000..46d2861
--- /dev/null
@@ -0,0 +1,47 @@
+/* { dg-additional-options "-fdiagnostics-show-caret -Wdeprecated-openmp" } */
+
+typedef enum omp_allocator_handle_t
+#if __cplusplus >= 201103L
+: __UINTPTR_TYPE__
+#endif
+{
+  __omp_allocator_handle_t_max__ = __UINTPTR_MAX__
+} omp_allocator_handle_t;
+
+typedef struct omp_alloctrait_t
+{
+  int key;
+  int value;
+} omp_alloctrait_t;
+
+
+void f()
+{
+  omp_allocator_handle_t myalloc;
+  const omp_alloctrait_t mytraits[] = {};
+  #pragma omp target uses_allocators(myalloc(mytraits))
+/* { dg-begin-multiline-output "" }
+   #pragma omp target uses_allocators(myalloc(mytraits))
+                                      ^~~~~~~~~~~~~~~~~
+                                      -------
+                                      traits           : myalloc
+   { dg-end-multiline-output "" } */
+   ;
+
+// { dg-warning "38: the specification of arguments to 'uses_allocators' where each item is of the form 'allocator\\(traits\\)' is deprecated since OpenMP 5.2 \\\[-Wdeprecated-openmp\\\]" "" { target *-*-* }  22 }
+
+
+  #pragma omp target uses_allocators  (  myalloc  (  mytraits  )  )
+/* { dg-begin-multiline-output "" }
+   #pragma omp target uses_allocators  (  myalloc  (  mytraits  )  )
+                                          ^~~~~~~~~~~~~~~~~~~~~~~
+                                          -------
+                                          traits                 : myalloc
+   { dg-end-multiline-output "" } */
+   ;
+
+// { dg-warning "42: the specification of arguments to 'uses_allocators' where each item is of the form 'allocator\\(traits\\)' is deprecated since OpenMP 5.2 \\\[-Wdeprecated-openmp\\\]" "" { target *-*-* }  34 }
+}
+
+// { dg-excess-errors "sorry, unimplemented: 'uses_allocators' clause" }
+// { dg-excess-errors "sorry, unimplemented: 'uses_allocators' clause" }
index 674d6ec8c7fbe23343ff837b85f679b223bf3b97..7bdb474a2537a99adf7569ecf15ed6451508a225 100644 (file)
@@ -598,6 +598,9 @@ enum omp_clause_code {
 
   /* OpenMP clause: dyn_groupprivate ( [fallback (...)] : integer-expression).  */
   OMP_CLAUSE_DYN_GROUPPRIVATE,
+
+  /* OpenMP clause: uses_allocators.  */
+  OMP_CLAUSE_USES_ALLOCATORS,
 };
 
 #undef DEFTREESTRUCT
index 12e093206833b88e8d271b104fc6f63d8468a0a7..15e7ead32e1b4543b76b5e3760fe2bb2964a0e2a 100644 (file)
@@ -907,6 +907,20 @@ dump_omp_clause (pretty_printer *pp, tree clause, int spc, dump_flags_t flags)
       pp_right_paren (pp);
       break;
 
+    case OMP_CLAUSE_USES_ALLOCATORS:
+      pp_string (pp, "uses_allocators(");
+      dump_generic_node (pp, OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (clause),
+                        spc, flags, false);
+      pp_string (pp, ": memspace(");
+      dump_generic_node (pp, OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE (clause),
+                        spc, flags, false);
+      pp_string (pp, "), traits(");
+      dump_generic_node (pp, OMP_CLAUSE_USES_ALLOCATORS_TRAITS (clause),
+                        spc, flags, false);
+      pp_right_paren (pp);
+      pp_right_paren (pp);
+      break;
+
     case OMP_CLAUSE_AFFINITY:
       pp_string (pp, "affinity(");
       {
index 52fc83e3c07d86770d5b4dda8ec0347b105d8fc9..8dcb59dc875845ac1d8505f91a8c52f512c0dffe 100644 (file)
@@ -399,6 +399,7 @@ unsigned const char omp_clause_num_ops[] =
   1, /* OMP_CLAUSE_NOVARIANTS */
   1, /* OMP_CLAUSE_NOCONTEXT */
   1, /* OMP_CLAUSE_DYN_GROUPPRIVATE  */
+  3, /* OMP_CLAUSE_USES_ALLOCATORS */
 };
 
 const char * const omp_clause_code_name[] =
@@ -503,6 +504,7 @@ const char * const omp_clause_code_name[] =
   "novariants",
   "nocontext",
   "dyn_groupprivate",
+  "uses_allocators",
 };
 
 /* Unless specific to OpenACC, we tend to internally maintain OpenMP-centric
index 56f4fc16dcd198e56a709f639768f7a1251bfc5c..d25fc4316c7c379e44ff4ab110fa93d7ab56773f 100644 (file)
@@ -2065,6 +2065,15 @@ class auto_suppress_location_wrappers
 #define OMP_CLAUSE_ALLOCATE_COMBINED(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ALLOCATE)->base.public_flag)
 
+#define OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_USES_ALLOCATORS), 0)
+
+#define OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_USES_ALLOCATORS), 1)
+
+#define OMP_CLAUSE_USES_ALLOCATORS_TRAITS(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_USES_ALLOCATORS), 2)
+
 #define OMP_CLAUSE_NUM_TEAMS_UPPER_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_NUM_TEAMS), 0)
 
diff --git a/libgomp/testsuite/libgomp.fortran/uses_allocators-7.f90 b/libgomp/testsuite/libgomp.fortran/uses_allocators-7.f90
new file mode 100644 (file)
index 0000000..e5376e4
--- /dev/null
@@ -0,0 +1,58 @@
+! { dg-additional-options "-fdump-tree-gimple" }
+
+program main
+  use iso_c_binding
+  use omp_lib
+  implicit none (type, external)
+  integer :: x, xbuf(10)
+  integer(c_intptr_t) :: iptr
+  integer(omp_allocator_handle_kind) :: my_alloc
+  type(omp_alloctrait), parameter :: trait(*) = [omp_alloctrait(omp_atk_alignment, 128)]
+
+  !$omp target uses_allocators(omp_low_lat_mem_alloc) map(tofrom: x, xbuf) defaultmap(none)
+    !$omp parallel allocate(allocator(omp_low_lat_mem_alloc), align(128): x, xbuf) if(.false.) firstprivate(x, xbuf)
+      if (mod (TRANSFER (loc(x), iptr), 128) /= 0) &
+        stop 1
+      if (mod (TRANSFER (loc(xbuf), iptr), 128) /= 0) &
+        stop 2
+    !$omp end parallel
+  !$omp end target
+
+  my_alloc = transfer(int(z'ABCD', omp_allocator_handle_kind), my_alloc)
+
+  !$omp target uses_allocators(traits(trait): my_alloc) defaultmap(none) map(tofrom: x, xbuf) 
+    !$omp parallel allocate(allocator(my_alloc): x, xbuf) if(.false.) firstprivate(x, xbuf)
+      if (mod (TRANSFER (loc(x), iptr), 128) /= 0) &
+        stop 3
+      if (mod (TRANSFER (loc(xbuf), iptr), 128) /= 0) &
+        stop 4
+    !$omp end parallel
+  !$omp end target
+
+  if (transfer(my_alloc, 0_omp_allocator_handle_kind) /= int(z'ABCD', omp_allocator_handle_kind)) &
+    stop 5
+
+  ! The following creates an allocator with empty traits + default mem space.
+  !$omp target uses_allocators(my_alloc) map(tofrom: x, xbuf) defaultmap(none)
+    !$omp parallel allocate(allocator(my_alloc), align(128): x, xbuf) if(.false.) firstprivate(x, xbuf)
+      if (mod (TRANSFER (loc(x), iptr), 128) /= 0) &
+        stop 6
+      if (mod (TRANSFER (loc(xbuf), iptr), 128) /= 0) &
+        stop 7
+    !$omp end parallel
+  !$omp end target
+
+  if (transfer(my_alloc, 0_omp_allocator_handle_kind) /= int(z'ABCD', omp_allocator_handle_kind)) &
+    stop 8
+end
+
+
+! FIXME ENABLE: 'dg FIXME final' -> 'dg-final'
+! { dg  FIXME  final { scan-tree-dump-times "#pragma omp target .*private\\(my_alloc\\).*uses_allocators\\(my_alloc: memspace\\(\\), traits\\(trait\\)\\)" 1 "gimple" } }
+! { dg  FIXME  final { scan-tree-dump-times "#pragma omp target .*private\\(my_alloc\\).*uses_allocators\\(my_alloc: memspace\\(\\), traits\\(\\)\\)" 1 "gimple" } }
+
+! FIXME ENABLE code above for "gimple" once it has been implemented:
+! { dg-message "sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces" "" { target *-*-* } 23 }
+! { dg-message "sorry, unimplemented: 'uses_allocators' clause with traits and memory spaces" "" { target *-*-* } 36 }
+! { dg-bogus "'my_alloc' not specified in enclosing 'target'" "bogus issue because clause is ignored" { xfail *-*-* } 24 }
+! { dg-bogus "'my_alloc' not specified in enclosing 'target'" "bogus issue because clause is ignored" { xfail *-*-* } 37 }
index 46f18e20ed88a4e15a1e7870199be1b6e2b5816e..4c3b136d516f73adff2697893ea68b70116b9724 100644 (file)
@@ -167,3 +167,18 @@ subroutine traits_checks
   !$omp target uses_allocators(a1 (trait3))  ! { dg-error "Traits array 'trait3' in USES_ALLOCATORS .1. must be a one-dimensional named constant array of type 'omp_alloctrait'" }
   block; end block
 end
+
+subroutine null_allocator_ok
+  use omp_lib
+  implicit none
+  integer(omp_allocator_handle_kind) ::  my, my2
+  integer(omp_allocator_handle_kind), parameter ::  my3 = -9
+  !$omp target uses_allocators(my, my2) ! OK -> default settings
+  block; end block
+  !$omp target uses_allocators(my3) ! { dg-error "'my3' at .1. in USES_ALLOCATORS must either a variable or a predefined allocator" }
+  block; end block
+  !$omp target uses_allocators(omp_default_mem_alloc, omp_null_allocator) ! OK -> omp_null_allocator
+  block; end block
+  !$omp target uses_allocators(my, omp_null_allocator) firstprivate(my) ! { dg-error "Symbol 'my' present on both data and map clauses" }
+  block; end block
+end