[gcc r16-6071] OpenMP: Add uses_allocators parser support to C/C++
Tobias Burnus
burnus@gcc.gnu.org
Fri Dec 12 20:24:27 GMT 2025
https://gcc.gnu.org/g:0a01b42b22ebc629c74524d2773bb86d4a018ba6
commit r16-6071-g0a01b42b22ebc629c74524d2773bb86d4a018ba6
Author: Chung-Lin Tang <cltang@baylibre.com>
Date: Fri Dec 12 21:20:33 2025 +0100
OpenMP: Add uses_allocators parser support to C/C++
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>
Diff:
---
gcc/c-family/c-omp.cc | 1 +
gcc/c-family/c-pragma.h | 1 +
gcc/c/c-parser.cc | 236 ++++++++++++++++++++-
gcc/c/c-typeck.cc | 139 ++++++++++++
gcc/cp/parser.cc | 202 +++++++++++++++++-
gcc/cp/pt.cc | 8 +
gcc/cp/semantics.cc | 156 ++++++++++++++
gcc/fortran/openmp.cc | 1 +
gcc/fortran/trans-openmp.cc | 3 +-
gcc/gimplify.cc | 6 +
.../c-c++-common/gomp/uses_allocators-1.c | 48 +++++
.../c-c++-common/gomp/uses_allocators-2.c | 35 +++
.../c-c++-common/gomp/uses_allocators-4.c | 144 +++++++++++++
.../c-c++-common/gomp/uses_allocators-7.c | 83 ++++++++
gcc/testsuite/g++.dg/gomp/deprecate-2.C | 47 ++++
gcc/testsuite/g++.dg/gomp/uses_allocators-1.C | 105 +++++++++
gcc/testsuite/gcc.dg/gomp/deprecate-2.c | 47 ++++
gcc/tree-core.h | 3 +
gcc/tree-pretty-print.cc | 14 ++
gcc/tree.cc | 2 +
gcc/tree.h | 9 +
.../libgomp.fortran/uses_allocators-7.f90 | 58 +++++
.../libgomp.fortran/uses_allocators_1.f90 | 15 ++
23 files changed, 1360 insertions(+), 3 deletions(-)
diff --git a/gcc/c-family/c-omp.cc b/gcc/c-family/c-omp.cc
index e183c400652d..9dd0d1450dd8 100644
--- a/gcc/c-family/c-omp.cc
+++ b/gcc/c-family/c-omp.cc
@@ -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:
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index a61a2c7bec36..3dc02e77b9e8 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -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,
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index abe024c84b39..669af6573cae 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -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)
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 735cfc61d1e0..cab21e29004e 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -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 */
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 50a03a3d7973..a0acd9cf6f3e 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -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,
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ce30b5276638..341e5ab8808a 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -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)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 331db16f76de..e420fd4ebafb 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -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 */
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 31534ea0393a..68533a77882b 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -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")))
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 8eb4fc4bcc66..a07dc2ec0e98 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -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;
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 0023728ad8eb..28d7fa3516c2 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -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
index 000000000000..df82cbbcba9d
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/uses_allocators-1.c
@@ -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
index 000000000000..c766ea3559d0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/uses_allocators-2.c
@@ -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
index 000000000000..5f3650157fc4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/uses_allocators-4.c
@@ -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
index 000000000000..ce43d70ecf25
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/uses_allocators-7.c
@@ -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
index 000000000000..46d286141ef2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/deprecate-2.C
@@ -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
index 000000000000..79e51638534c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/uses_allocators-1.C
@@ -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
index 000000000000..46d286141ef2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/deprecate-2.c
@@ -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/tree-core.h b/gcc/tree-core.h
index 674d6ec8c7fb..7bdb474a2537 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -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
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index 12e093206833..15e7ead32e1b 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -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(");
{
diff --git a/gcc/tree.cc b/gcc/tree.cc
index 52fc83e3c07d..8dcb59dc8758 100644
--- a/gcc/tree.cc
+++ b/gcc/tree.cc
@@ -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
diff --git a/gcc/tree.h b/gcc/tree.h
index 56f4fc16dcd1..d25fc4316c7c 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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
index 000000000000..e5376e466666
--- /dev/null
+++ b/libgomp/testsuite/libgomp.fortran/uses_allocators-7.f90
@@ -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 }
diff --git a/libgomp/testsuite/libgomp.fortran/uses_allocators_1.f90 b/libgomp/testsuite/libgomp.fortran/uses_allocators_1.f90
index 46f18e20ed88..4c3b136d516f 100644
--- a/libgomp/testsuite/libgomp.fortran/uses_allocators_1.f90
+++ b/libgomp/testsuite/libgomp.fortran/uses_allocators_1.f90
@@ -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
More information about the Gcc-cvs
mailing list