Add diagnostics for multiple uses of a var in a single directive, uses of
parameters, vars in a different scope, and vars that are references.
Enhances diagnostics, as well as reporting a proper location in most cases.
gcc/cp/ChangeLog:
* parser.cc (cp_parser_omp_allocate): Add diagnostics, wrap a
location into allocator and alignment clause exprs.
* semantics.cc: Include gcc-rich-location.h.
(finish_omp_allocate): Improve and add diagnostics.
gcc/testsuite/ChangeLog:
* c-c++-common/gomp/allocate-9.c: Remove xfails.
* c-c++-common/gomp/allocate-19.c: Remove xfails.
* c-c++-common/gomp/allocate-20.c: New test.
* g++.dg/gomp/allocate-14.C: New test.
* g++.dg/gomp/allocate-15.C: New test.
* g++.dg/gomp/allocate-16.C: New test.
* g++.dg/gomp/allocate-17.C: New test.
* g++.dg/gomp/allocate-18.C: New test.
* g++.dg/gomp/allocate-19.C: New test.
* g++.dg/gomp/allocate-handles-1.C: Remove xfails.
Signed-off-by: Waffl3x <[email protected]>
---
gcc/cp/parser.cc | 76 +-
gcc/cp/semantics.cc | 76 +-
gcc/testsuite/c-c++-common/gomp/allocate-19.c | 10 +-
gcc/testsuite/c-c++-common/gomp/allocate-20.c | 343 ++++++
gcc/testsuite/c-c++-common/gomp/allocate-9.c | 30 +-
gcc/testsuite/g++.dg/gomp/allocate-14.C | 1042 +++++++++++++++++
gcc/testsuite/g++.dg/gomp/allocate-15.C | 50 +
gcc/testsuite/g++.dg/gomp/allocate-16.C | 232 ++++
gcc/testsuite/g++.dg/gomp/allocate-17.C | 560 +++++++++
gcc/testsuite/g++.dg/gomp/allocate-18.C | 274 +++++
gcc/testsuite/g++.dg/gomp/allocate-19.C | 128 ++
.../g++.dg/gomp/allocate-handles-1.C | 34 +-
12 files changed, 2810 insertions(+), 45 deletions(-)
create mode 100644 gcc/testsuite/c-c++-common/gomp/allocate-20.c
create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-14.C
create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-15.C
create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-16.C
create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-17.C
create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-18.C
create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-19.C
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 2cec22a9386..924e52da6ea 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -47186,7 +47186,31 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token
*pragma_tok)
{
tree nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL_TREE);
+ /* Make diagnostics emit in forward order. */
+ nl = nreverse (nl);
+
+ const tree directive_ctx = current_scope ();
{
+ auto var_is_in_scope = [&] (tree var_decl)
+ {
+ /* (OpenMP 6.0 311:11-12) An allocate directive must appear in the same
+ scope as the declarations of each of its list items and must follow
+ all such declarations.
+
+ Note that it states declarations, not definitions, thus we can rely
+ on VAR_DECL's CP_DECL_CONTEXT. This will correctly reject an
+ allocate directive applied to a definition in a different scope. */
+ if (!DECL_DECLARES_FUNCTION_P (directive_ctx))
+ return CP_DECL_CONTEXT (var_decl) == directive_ctx;
+ /* This is O(n^2), caching names during traversal might be better. */
+ for (tree block_var = current_binding_level->names;
+ block_var != NULL_TREE;
+ block_var = DECL_CHAIN (block_var))
+ if (block_var == var_decl)
+ return true;
+ return false;
+ };
+ hash_map<tree, location_t> seen_args;
/* The head might have an error and need to be removed. */
tree *chain = &nl;
for (tree node = nl; node != NULL_TREE; node = TREE_CHAIN (node))
@@ -47195,6 +47219,52 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token
*pragma_tok)
const tree arg_loc_wrapper = TREE_VALUE (node);
const location_t arg_loc = EXPR_LOCATION (arg_loc_wrapper);
+ gcc_assert (var && var != error_mark_node);
+ /* Diagnose duplicate vars passed to the allocate directive. */
+ if (location_t const *const orig_loc = seen_args.get (var))
+ {
+ auto_diagnostic_group d;
+ /* If we could just get the location of the comma a fixit
+ hint would be viable here. */
+ error_at (arg_loc,
+ "%qD already appeared as list item in this directive",
+ var);
+ inform (*orig_loc, "appeared first here");
+ /* Remove the node. */
+ *chain = TREE_CHAIN (node);
+ continue;
+ }
+ seen_args.put (var, arg_loc);
+
+ /* Diagnose parameters passed to the allocate directive. */
+ if (TREE_CODE (var) == PARM_DECL)
+ {
+ auto_diagnostic_group d;
+ error_at (arg_loc,
+ "function parameter %qD may not appear as list item in "
+ "an %<allocate%> directive", var);
+ inform (DECL_SOURCE_LOCATION (var),
+ "parameter %qD declared here", var);
+ /* Remove the node. */
+ *chain = TREE_CHAIN (node);
+ continue;
+ }
+
+ /* Do this before checking if the var was used in another allocate
+ directive, as the latter diagnostic implies that removing the var
+ from the previous directive would fix the problem. */
+ if (!var_is_in_scope (var))
+ {
+ auto_diagnostic_group d;
+ error_at (arg_loc,
+ "%<allocate%> directive must be in the same scope as "
+ "%qD", var);
+ inform (DECL_SOURCE_LOCATION (var), "declared here");
+ /* Remove the node. */
+ *chain = TREE_CHAIN (node);
+ continue;
+ }
+
tree attr = lookup_attribute ("omp allocate",
DECL_ATTRIBUTES (var));
if (attr)
@@ -47284,6 +47354,7 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token
*pragma_tok)
if (!parens.require_open (parser))
break;
cp_expr expr = cp_parser_assignment_expression (parser);
+ expr.maybe_add_location_wrapper ();
if (p[2] == 'i' && alignment)
{
error_at (cloc, "too many %qs clauses", "align");
@@ -47302,11 +47373,14 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token
*pragma_tok)
} while (true);
cp_parser_require_pragma_eol (parser, pragma_tok);
+ /* We can still diagnose some things about allocator/alignment even if nl
+ is NULL_TREE. */
+
finish_omp_allocate (pragma_tok->location,
nl,
allocator,
alignment,
- current_scope ());
+ directive_ctx);
}
/* OpenMP 2.5:
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index ac81bbe9317..00c09e119c8 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimplify.h"
#include "contracts.h"
#include "c-family/c-pragma.h"
+#include "gcc-rich-location.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
@@ -12393,6 +12394,62 @@ finish_omp_allocate (const location_t loc, const tree
var_list,
} (); /* IILE. */
const bool any_static_vars = any_of_vars (tree_static_p);
+ /* Create an auto_diagnostic_group before calling this. */
+ const auto emit_diag_for_var_group
+ = [] (const var_predicate pred,
+ void (*diag_fn)(rich_location *, const char *, ...),
+ const char *msg,
+ const const_tree var_list)
+ {
+ auto next_match = [&pred] (const_tree first)
+ {
+ const_tree vn = first;
+ for (; vn != NULL_TREE; vn = TREE_CHAIN (vn))
+ if (TREE_PURPOSE (vn) != error_mark_node
+ && pred (TREE_PURPOSE (vn)))
+ return vn;
+ return vn;
+ };
+ gcc_assert (var_list != NULL_TREE);
+ const const_tree first_node = next_match (var_list);
+ gcc_assert (first_node != NULL_TREE);
+
+ gcc_rich_location rich_loc (EXPR_LOCATION (TREE_VALUE (first_node)));
+ /* Don't add another range for the first node. */
+ for (const_tree vn = next_match (TREE_CHAIN (first_node));
+ vn != NULL_TREE;
+ vn = next_match (TREE_CHAIN (vn)))
+ rich_loc.add_range (EXPR_LOCATION (TREE_VALUE (vn)));
+ diag_fn (&rich_loc, msg);
+
+ const_tree vn = first_node;
+ for (; vn != NULL_TREE; vn = next_match (TREE_CHAIN (vn)))
+ inform (DECL_SOURCE_LOCATION (TREE_PURPOSE (vn)),
+ "%qD declared here", TREE_PURPOSE (vn));
+ };
+
+ /* Defer error marking vars until after other diagnostics are done, we might
+ still need access to them when diagnosing the allocator clause. */
+ hash_set<tree> deferred_erroneous_var_nodes;
+
+ const auto ref_var_p
+ = [] (const_tree t) -> bool { return TYPE_REF_P (TREE_TYPE (t)); };
+ if (any_of_vars (ref_var_p))
+ {
+ auto_diagnostic_group d;
+ emit_diag_for_var_group (ref_var_p,
+ &error_at,
+ G_("variables with reference type may not "
+ "appear in an %<allocate%> directive"),
+ var_list);
+ for (tree vn = var_list; vn != NULL_TREE; vn = TREE_CHAIN (vn))
+ {
+ if (!ref_var_p (TREE_PURPOSE (vn)))
+ continue;
+ deferred_erroneous_var_nodes.add (vn);
+ }
+ }
+
/* (OpenMP 5.2, 174:15) Type: expression of integer type
Properties: constant, positive */
const tree align = [&align_in] ()
@@ -12449,9 +12506,12 @@ finish_omp_allocate (const location_t loc, const tree
var_list,
allocator values. */
const auto emit_diag_for_static_vars = [&] ()
{
- inform (UNKNOWN_LOCATION,
- "because one or more variables with static storage duration "
- "appear in the %<allocate%> directive");
+ emit_diag_for_var_group (tree_static_p,
+ &inform,
+ G_("because one or more variables with "
+ "static storage duration appear "
+ "in the %<allocate%> directive"),
+ var_list);
};
if (alloc_in == NULL_TREE)
{
@@ -12496,10 +12556,12 @@ finish_omp_allocate (const location_t loc, const tree
var_list,
return cached_alloc_type;
}
auto_diagnostic_group d;
- error_at (EXPR_LOCATION (alloc_in),
+ gcc_rich_location loc (EXPR_LOCATION (alloc_in));
+ maybe_add_include_fixit (&loc, "<omp.h>", false);
+ error_at (&loc,
"%<allocator%> clause requires a valid declaration "
"of %<omp_allocator_handle_t%>");
- inform (EXPR_LOCATION (alloc_in),
+ inform (&loc,
"%<omp_allocator_handle_t%> is defined in header "
"%<<omp.h>%>; this is probably fixable by adding "
"%<#include <omp.h>%>");
@@ -12642,6 +12704,10 @@ finish_omp_allocate (const location_t loc, const tree
var_list,
TREE_PURPOSE (node) = error_mark_node;
};
+ for (tree vn = var_list; vn != NULL_TREE; vn = TREE_CHAIN (vn))
+ if (deferred_erroneous_var_nodes.contains (vn))
+ finalize_var_node_with_error (vn);
+
/* Even if there have been errors, save the current state, there might be
more to diagnose on a later instantiation. */
if (processing_template_decl)
diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-19.c
b/gcc/testsuite/c-c++-common/gomp/allocate-19.c
index cabd3875d1e..61d1f7ba4b7 100644
--- a/gcc/testsuite/c-c++-common/gomp/allocate-19.c
+++ b/gcc/testsuite/c-c++-common/gomp/allocate-19.c
@@ -56,19 +56,17 @@ get ()
return &A1[q];
}
-static int invalid1, okay1, invalid2, invalid3; /* { dg-note "'invalid\[123\]'
declared here" "" { target c++ xfail c++ } } */
+static int invalid1, okay1, invalid2, invalid3; /* { dg-note "'invalid\[123\]'
declared here" "" { target c++ } } */
#pragma omp allocate(invalid1) align(128) allocator(ompx_gnu_pinned_bogus_1)
/* { dg-error "'allocator' clause requires a predefined allocator as 'invalid1'
is static" "" { target c } } */
/* { dg-error "'allocator' clause requires a constant predefined allocator" ""
{ target c++ } .-1 } */
-/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ xfail c++ } .-2 } */
+/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ } .-2 } */
/* { dg-note "expression evaluates to '9'" "" { target c++ } .-3 } */
#pragma omp allocate(okay1) align(128) allocator(ompx_gnu_pinned_mem_alloc)
/* Okay */
#pragma omp allocate(invalid2) align(128) allocator(ompx_gnu_pinned_bogus_2)
/* { dg-error "'allocator' clause requires a predefined allocator as 'invalid2'
is static" "" { target c } } */
/* { dg-error "'allocator' clause requires a constant predefined allocator" ""
{ target c++ } .-1 } */
-/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ xfail c++ } .-2 } */
+/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ } .-2 } */
/* { dg-note "expression evaluates to '199'" "" { target c++ } .-3 } */
#pragma omp allocate(invalid3) align(128) allocator(ompx_gnu_pinned_bogus_3)
/* { dg-error "'allocator' clause requires a predefined allocator as 'invalid3'
is static" "" { target c } } */
/* { dg-error "'allocator' clause requires a constant predefined allocator" ""
{ target c++ } .-1 } */
-/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ xfail c++ } .-2 } */
+/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ } .-2 } */
/* { dg-note "expression evaluates to '2001'" "" { target c++ } .-3 } */
-
-/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ } 0 } */
diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-20.c
b/gcc/testsuite/c-c++-common/gomp/allocate-20.c
new file mode 100644
index 00000000000..604e4847a92
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/allocate-20.c
@@ -0,0 +1,343 @@
+#include "allocate-allocator-handle.h"
+
+#pragma omp allocate() allocator(omp_default_mem_alloc)
+/* { dg-error "expected identifier before '\\\)' token" "" { target c } .-1 }
*/
+/* { dg-error "expected unqualified-id before '\\\)' token" "" { target c++ }
.-2 } */
+
+/* The following tests are broken up into multiple lines to verify they refer
+ to the correct use of the variable, this seems to be the easiest way.
+ C does not currently refer to the correct line. */
+int g;
+/* { dg-error "'g' already appeared as list item in an 'allocate' directive"
"" { target c } .+1 } */
+#pragma omp allocate(\
+g,\
+g,\
+g,\
+g,\
+g) allocator(omp_default_mem_alloc)
+/* { dg-note "appeared first here" "" { target c++ } .-5 } */
+/* { dg-error "'g' already appeared as list item in this directive" "" {
target c++ } .-5 } */
+/* { dg-error "'g' already appeared as list item in this directive" "" {
target c++ } .-5 } */
+/* { dg-error "'g' already appeared as list item in this directive" "" {
target c++ } .-5 } */
+/* { dg-error "'g' already appeared as list item in this directive" "" {
target c++ } .-5 } */
+
+int g0_0;
+int g0_1;
+/* { dg-error "'g0_0' already appeared as list item in an 'allocate'
directive" "" { target c } .+1 } */
+#pragma omp allocate(\
+g0_0,\
+g0_1,\
+g0_0,\
+g0_0) allocator(omp_default_mem_alloc)
+/* { dg-note "appeared first here" "" { target c++ } .-4 } */
+/* { dg-error "'g0_0' already appeared as list item in this directive" "" {
target c++ } .-3 } */
+/* { dg-error "'g0_0' already appeared as list item in this directive" "" {
target c++ } .-3 } */
+
+int g1_0;
+int g1_1;
+/* { dg-error "'g1_0' already appeared as list item in an 'allocate'
directive" "" { target c } .+2 } */
+/* { dg-error "'g1_1' already appeared as list item in an 'allocate'
directive" "" { target c } .+1 } */
+#pragma omp allocate(\
+g1_1,\
+g1_0,\
+g1_1,\
+g1_0,\
+g1_0,\
+g1_1) allocator(omp_default_mem_alloc)
+/* { dg-note "appeared first here" "" { target c++ } .-6 } */
+/* { dg-note "appeared first here" "" { target c++ } .-6 } */
+/* { dg-error "'g1_1' already appeared as list item in this directive" "" {
target c++ } .-6 } */
+/* { dg-error "'g1_0' already appeared as list item in this directive" "" {
target c++ } .-6 } */
+/* { dg-error "'g1_0' already appeared as list item in this directive" "" {
target c++ } .-6 } */
+/* { dg-error "'g1_1' already appeared as list item in this directive" "" {
target c++ } .-6 } */
+
+void f()
+{
+ int v;
+ /* { dg-error "'v' already appeared as list item in an 'allocate' directive"
"" { target c} .+1 } */
+ #pragma omp allocate(\
+ v,\
+ v,\
+ v,\
+ v,\
+ v)
+ /* { dg-note "appeared first here" "" { target c++ } .-5 } */
+ /* { dg-error "'v' already appeared as list item in this directive" "" {
target c++ } .-5 } */
+ /* { dg-error "'v' already appeared as list item in this directive" "" {
target c++ } .-5 } */
+ /* { dg-error "'v' already appeared as list item in this directive" "" {
target c++ } .-5 } */
+ /* { dg-error "'v' already appeared as list item in this directive" "" {
target c++ } .-5 } */
+
+ int v0_0;
+ int v0_1;
+ /* { dg-error "'v0_0' already appeared as list item in an 'allocate'
directive" "" { target c } .+1 } */
+ #pragma omp allocate(\
+ v0_0,\
+ v0_1,\
+ v0_0,\
+ v0_0)
+ /* { dg-note "appeared first here" "" { target c++ } .-4 } */
+ /* { dg-error "'v0_0' already appeared as list item in this directive" "" {
target c++ } .-3 } */
+ /* { dg-error "'v0_0' already appeared as list item in this directive" "" {
target c++ } .-3 } */
+
+ int v1_0;
+ int v1_1;
+ /* { dg-error "'v1_0' already appeared as list item in an 'allocate'
directive" "" { target c } .+2 } */
+ /* { dg-error "'v1_1' already appeared as list item in an 'allocate'
directive" "" { target c } .+1 } */
+ #pragma omp allocate(\
+ v1_1,\
+ v1_0,\
+ v1_1,\
+ v1_0,\
+ v1_0,\
+ v1_1)
+ /* { dg-note "appeared first here" "" { target c++ } .-6 } */
+ /* { dg-note "appeared first here" "" { target c++ } .-6 } */
+ /* { dg-error "'v1_1' already appeared as list item in this directive" "" {
target c++ } .-6 } */
+ /* { dg-error "'v1_0' already appeared as list item in this directive" "" {
target c++ } .-6 } */
+ /* { dg-error "'v1_0' already appeared as list item in this directive" "" {
target c++ } .-6 } */
+ /* { dg-error "'v1_1' already appeared as list item in this directive" "" {
target c++ } .-6 } */
+}
+
+void f_with_parm(int p) /* { dg-note "parameter 'p' declared here" "" { target
c++ } } */
+{
+ #pragma omp allocate(p)
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c } .+1 } */
+ #pragma omp allocate(\
+ p,\
+ p,\
+ p)
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c++ } .-3 } */
+ /* { dg-note "appeared first here" "" { target c++ } .-4 } */
+ /* { dg-error "'p' already appeared as list item in this directive" "" {
target c++ } .-4 } */
+ /* { dg-error "'p' already appeared as list item in this directive" "" {
target c++ } .-4 } */
+
+ int v;
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c } .+2 } */
+ /* { dg-error "'v' already appeared as list item in an 'allocate' directive"
"" { target c } .+1 } */
+ #pragma omp allocate(\
+ v,\
+ p,\
+ v,\
+ v,\
+ p,\
+ v,\
+ v)
+ /* { dg-note "appeared first here" "" { target c++ } .-7 } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c++ } .-7 } */
+ /* { dg-note "appeared first here" "" { target c++ } .-8 } */
+ /* { dg-error "'v' already appeared as list item in this directive" "" {
target c++ } .-8 } */
+ /* { dg-error "'v' already appeared as list item in this directive" "" {
target c++ } .-8 } */
+ /* { dg-error "'p' already appeared as list item in this directive" "" {
target c++ } .-8 } */
+ /* { dg-error "'v' already appeared as list item in this directive" "" {
target c++ } .-8 } */
+ /* { dg-error "'v' already appeared as list item in this directive" "" {
target c++ } .-8 } */
+
+ int v0_0;
+ int v0_1;
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c } .+2 } */
+ /* { dg-error "'v0_0' already appeared as list item in an 'allocate'
directive" "" { target c } .+1 } */
+ #pragma omp allocate(\
+ p,\
+ v0_0,\
+ v0_1,\
+ v0_0,\
+ v0_0)
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c++ } .-5 } */
+ /* { dg-note "appeared first here" "" { target c++ } .-5 } */
+ /* { dg-error "'v0_0' already appeared as list item in this directive" "" {
target c++ } .-4 } */
+ /* { dg-error "'v0_0' already appeared as list item in this directive" "" {
target c++ } .-4 } */
+
+ int v1_0;
+ int v1_1;
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c } .+3 } */
+ /* { dg-error "'v1_0' already appeared as list item in an 'allocate'
directive" "" { target c } .+2 } */
+ /* { dg-error "'v1_1' already appeared as list item in an 'allocate'
directive" "" { target c } .+1 } */
+ #pragma omp allocate(\
+ v1_1,\
+ p,\
+ v1_0,\
+ v1_1,\
+ v1_0,\
+ p,\
+ v1_0,\
+ v1_1,\
+ p)
+ /* { dg-note "appeared first here" "" { target c++ } .-9 } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c++ } .-9 } */
+ /* { dg-note "appeared first here" "" { target c++ } .-10 } */
+ /* { dg-note "appeared first here" "" { target c++ } .-10 } */
+ /* { dg-error "'v1_1' already appeared as list item in this directive" "" {
target c++ } .-10 } */
+ /* { dg-error "'v1_0' already appeared as list item in this directive" "" {
target c++ } .-10 } */
+ /* { dg-error "'p' already appeared as list item in this directive" "" {
target c++ } .-10 } */
+ /* { dg-error "'v1_0' already appeared as list item in this directive" "" {
target c++ } .-10 } */
+ /* { dg-error "'v1_1' already appeared as list item in this directive" "" {
target c++ } .-10 } */
+ /* { dg-error "'p' already appeared as list item in this directive" "" {
target c++ } .-10 } */
+}
+
+/* Valid var used in allocator clause diagnostics.
+ (No diagnostic should be emitted related to 'alloc') */
+
+void f_with_parm_and_allocator0(int p) /* { dg-note "parameter 'p' declared
here" "" { target c++ } } */
+{
+ omp_allocator_handle_t alloc = omp_default_mem_alloc;
+ #pragma omp allocate(p) allocator(alloc)
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c } .+1 } */
+ #pragma omp allocate(\
+ p,\
+ p,\
+ p) allocator(alloc)
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c++ } .-3 } */
+ /* { dg-note "appeared first here" "" { target c++ } .-4 } */
+ /* { dg-error "'p' already appeared as list item in this directive" "" {
target c++ } .-4 } */
+ /* { dg-error "'p' already appeared as list item in this directive" "" {
target c++ } .-4 } */
+
+ int v;
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c } .+2 } */
+ /* { dg-error "'v' already appeared as list item in an 'allocate' directive"
"" { target c } .+1 } */
+ #pragma omp allocate(\
+ v,\
+ p,\
+ v,\
+ v,\
+ p,\
+ v,\
+ v) allocator(alloc)
+ /* { dg-note "appeared first here" "" { target c++ } .-7 } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c++ } .-7 } */
+ /* { dg-note "appeared first here" "" { target c++ } .-8 } */
+ /* { dg-error "'v' already appeared as list item in this directive" "" {
target c++ } .-8 } */
+ /* { dg-error "'v' already appeared as list item in this directive" "" {
target c++ } .-8 } */
+ /* { dg-error "'p' already appeared as list item in this directive" "" {
target c++ } .-8 } */
+ /* { dg-error "'v' already appeared as list item in this directive" "" {
target c++ } .-8 } */
+ /* { dg-error "'v' already appeared as list item in this directive" "" {
target c++ } .-8 } */
+
+ int v0_0;
+ int v0_1;
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c } .+2 } */
+ /* { dg-error "'v0_0' already appeared as list item in an 'allocate'
directive" "" { target c } .+1 } */
+ #pragma omp allocate(\
+ p,\
+ v0_0,\
+ v0_1,\
+ v0_0,\
+ v0_0) allocator(alloc)
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c++ } .-5 } */
+ /* { dg-note "appeared first here" "" { target c++ } .-5 } */
+ /* { dg-error "'v0_0' already appeared as list item in this directive" "" {
target c++ } .-4 } */
+ /* { dg-error "'v0_0' already appeared as list item in this directive" "" {
target c++ } .-4 } */
+
+ int v1_0;
+ int v1_1;
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c } .+3 } */
+ /* { dg-error "'v1_0' already appeared as list item in an 'allocate'
directive" "" { target c } .+2 } */
+ /* { dg-error "'v1_1' already appeared as list item in an 'allocate'
directive" "" { target c } .+1 } */
+ #pragma omp allocate(\
+ v1_1,\
+ p,\
+ v1_0,\
+ v1_1,\
+ v1_0,\
+ p,\
+ v1_0,\
+ v1_1,\
+ p) allocator(alloc)
+ /* { dg-note "appeared first here" "" { target c++ } .-9 } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c++ } .-9 } */
+ /* { dg-note "appeared first here" "" { target c++ } .-10 } */
+ /* { dg-note "appeared first here" "" { target c++ } .-10 } */
+ /* { dg-error "'v1_1' already appeared as list item in this directive" "" {
target c++ } .-10 } */
+ /* { dg-error "'v1_0' already appeared as list item in this directive" "" {
target c++ } .-10 } */
+ /* { dg-error "'p' already appeared as list item in this directive" "" {
target c++ } .-10 } */
+ /* { dg-error "'v1_0' already appeared as list item in this directive" "" {
target c++ } .-10 } */
+ /* { dg-error "'v1_1' already appeared as list item in this directive" "" {
target c++ } .-10 } */
+ /* { dg-error "'p' already appeared as list item in this directive" "" {
target c++ } .-10 } */
+}
+
+/* Var used in allocator clause diagnostics. Tests that invalid vars passed
+ into the allocate directive are not considered and bogus/repeat diagnostics
+ are not emitted. */
+
+void f_with_parm_and_allocator1(int p) /* { dg-note "parameter 'p' declared
here" "" { target c++ } } */
+{
+ int v0; /* { dg-note "to be allocated variable declared here" "" { xfail c++
} } */
+ omp_allocator_handle_t alloc0 = omp_default_mem_alloc; /* { dg-note
"declared here" "" { xfail c++ } } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c } .+2 } */
+ /* { dg-error "variable 'alloc0' used in the 'allocator' clause must be
declared before 'v0'" "" { target c } .+1 } */
+ #pragma omp allocate(\
+ p,\
+ v0)\
+ allocator(alloc0)
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c++ } .-3 } */
+ /* { dg-error "variable 'alloc0' used in the 'allocator' clause must be
declared before 'v0'" "" { target c++ xfail c++ } .-2 } */
+
+ int v1; /* { dg-note "declared here" } */
+ {
+ omp_allocator_handle_t alloc1 = omp_default_mem_alloc;
+ int v2;
+ /* { dg-error "'allocate' directive must be in the same scope as 'v1'" ""
{ target c } .+1 } */
+ #pragma omp allocate(\
+ v1,\
+ v2\
+ ) allocator(alloc1)
+ /* { dg-error "'allocate' directive must be in the same scope as 'v1'" ""
{ target c++ } .-3 } */
+ }
+ {
+ int v3; /* { dg-note "to be allocated variable declared here" "" { xfail
c++ } } */
+ omp_allocator_handle_t alloc2 = omp_default_mem_alloc; /* { dg-note
"declared here" "" { xfail c++ } } */
+ /* { dg-error "variable 'alloc2' used in the 'allocator' clause must be
declared before 'v3'" "" { target c } .+2 } */
+ /* { dg-error "'allocate' directive must be in the same scope as 'v1'" ""
{ target c } .+1 } */
+ #pragma omp allocate(\
+ v1,\
+ v3\
+ ) allocator(alloc2)
+ /* { dg-error "'allocate' directive must be in the same scope as 'v1'" ""
{ target c++ } .-3 } */
+ /* { dg-error "variable 'alloc2' used in the 'allocator' clause must be
declared before 'v3'" "" { target c++ xfail c++ } .-2 } */
+ }
+}
+
+/* First argument valid.
+ These cases could still be fleshed out a bit more, there was original a typo
+ that caused diagnostics to always refer to the first argument of the
+ directive in the C++ front end, these tests are for that case. */
+
+void first_valid0()
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ int v;
+ /* { dg-error "'allocate' directive must be in the same scope as 'a'" "" {
target c } .+1 } */
+ #pragma omp allocate(\
+ v,\
+ a) /* { dg-error "'allocate' directive must be in the same scope as 'a'"
"" { target c++ } } */
+ }
+}
+
+void first_valid1(int p) /* { dg-note "parameter 'p' declared here" "" {
target c++ } } */
+{
+ int v;
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c } .+1 } */
+ #pragma omp allocate(\
+ v,\
+ p) /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c++ } } */
+}
+
+void first_valid2(int p) /* { dg-note "parameter 'p' declared here" "" {
target c++ } } */
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ int v;
+ /* { dg-error "'allocate' directive must be in the same scope as 'a'" "" {
target c } .+2 } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c } .+1 } */
+ #pragma omp allocate(\
+ v,\
+ a,\
+ p)
+ /* { dg-error "'allocate' directive must be in the same scope as 'a'" "" {
target c++ } .-2 } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target c++ } .-2 } */
+ }
+}
+
+/* Missing cases that contain undeclared variables. */
diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-9.c
b/gcc/testsuite/c-c++-common/gomp/allocate-9.c
index 52bae8c9a6a..872f7956cdd 100644
--- a/gcc/testsuite/c-c++-common/gomp/allocate-9.c
+++ b/gcc/testsuite/c-c++-common/gomp/allocate-9.c
@@ -5,7 +5,7 @@ static int A2[5] = {1,2,3,4,5};
static int A3[5] = {1,2,3,4,5};
static int A4[5] = {1,2,3,4,5}; /* { dg-line A4_decl } */
static int A5[5] = {1,2,3,4,5}; /* { dg-line A5_decl } */
-int B, C, C2, D; /* { dg-note "declared here" "" { xfail c++ } } */
+int B, C, C2, D; /* { dg-note "declared here" } */
/* If the following fails because of added predefined allocators, please update
- include/gomp-constants.h's GOMP_OMP_PREDEF_ALLOC_MAX or
GOMP_OMPX_PREDEF_ALLOC_MAX
@@ -18,9 +18,9 @@ int B, C, C2, D; /* { dg-note "declared here" "" { xfail c++
} } */
#pragma omp allocate(A1) align(32) allocator((omp_allocator_handle_t) 9)
/* { dg-error "'allocator' clause requires a predefined allocator as 'A1' is
static" "" { target c } .-1 } */
/* { dg-error "'allocator' clause requires a constant predefined allocator" ""
{ target c++ } .-2 } */
-/* { dg-message "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ xfail c++ } .-3 } */
+/* { dg-message "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ } .-3 } */
/* { dg-message "expression evaluates to '9'" "" { target c++ } .-4 } */
-/* { dg-note "'A1' declared here" "" { target c++ xfail c++ } A_decl } */
+/* { dg-note "'A1' declared here" "" { target c++ } A_decl } */
// typo in allocator name:
#pragma omp allocate(A2) allocator(omp_low_latency_mem_alloc)
/* { dg-error "'omp_low_latency_mem_alloc' undeclared here \\(not in a
function\\); did you mean 'omp_low_lat_mem_alloc'\\?" "" { target c } .-1 } */
@@ -35,8 +35,8 @@ int B, C, C2, D; /* { dg-note "declared here" "" { xfail c++
} } */
#pragma omp allocate(A4) align(32)
/* { dg-error "'allocator' clause required for static variable 'A4'" "" {
target c } .-1 } */
/* { dg-error "'allocator' clause must be specified" "" { target c++ } .-2 } */
-/* { dg-message "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ xfail c++ } .-3 } */
-/* { dg-note "'A4' declared here" "" { target c++ xfail c++ } A4_decl } */
+/* { dg-message "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ } .-3 } */
+/* { dg-note "'A4' declared here" "" { target c++ } A4_decl } */
/* "expression in the clause must be a constant expression that evaluates to
one of the
predefined memory allocator values -> omp_low_lat_mem_alloc" */
@@ -49,9 +49,9 @@ int B, C, C2, D; /* { dg-note "declared here" "" { xfail c++
} } */
#pragma omp allocate(A5) align(32) allocator(omp_null_allocator)
/* { dg-error "'allocator' clause requires a predefined allocator as 'A5' is
static" "" { target c } .-1 } */
/* { dg-error "'allocator' clause requires a constant predefined allocator" ""
{ target c++ } .-2 } */
-/* { dg-message "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ xfail c++ } .-3 } */
+/* { dg-message "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ } .-3 } */
/* { dg-message "expression evaluates to '0'" "" { target c++ } .-4 } */
-/* { dg-note "'A5' declared here" "" { target c++ xfail c++ } A5_decl } */
+/* { dg-note "'A5' declared here" "" { target c++ } A5_decl } */
#pragma omp allocate(C2) align(32) allocator(omp_large_cap_mem_alloc)
@@ -59,7 +59,7 @@ int B, C, C2, D; /* { dg-note "declared here" "" { xfail c++
} } */
// allocate directive in same TU
int f()
{
- #pragma omp allocate(D) align(32) allocator(omp_large_cap_mem_alloc) /* {
dg-error "'allocate' directive must be in the same scope as 'D'" "" { xfail c++
} } */
+ #pragma omp allocate(D) align(32) allocator(omp_large_cap_mem_alloc) /* {
dg-error "'allocate' directive must be in the same scope as 'D'" } */
return A1[0];
}
@@ -71,29 +71,29 @@ int g()
/* { dg-note "'a2' previously appeared here" "" { target c++ } .-2 } */
{
int c2=3;
- #pragma omp allocate(c2, b2) /* { dg-error "'allocate' directive must be
in the same scope as 'b2'" "" { xfail c++ } } */
-/* { dg-note "declared here" "" { target *-*-* xfail c++ } g_a2_b2_decl } */
+ #pragma omp allocate(c2, b2) /* { dg-error "'allocate' directive must be
in the same scope as 'b2'" } */
+/* { dg-note "declared here" "" { target *-*-* } g_a2_b2_decl } */
return c2+a2+b2;
}
}
int h(int q)
{
- #pragma omp allocate(q) /* { dg-error "function parameter 'q' may not
appear as list item in an 'allocate' directive" "" { xfail c++ } } */
-/* { dg-note "parameter 'q' declared here" "" { target c++ xfail c++ } .-3 } */
+ #pragma omp allocate(q) /* { dg-error "function parameter 'q' may not
appear as list item in an 'allocate' directive" } */
+/* { dg-note "parameter 'q' declared here" "" { target c++ } .-3 } */
return q;
}
int
k ()
{
- static int var3 = 8; /* { dg-note "'var3' declared here" "" { target c++
xfail c++ } } */
+ static int var3 = 8; /* { dg-note "'var3' declared here" "" { target c++ } }
*/
#pragma omp allocate(var3) allocator((omp_allocator_handle_t)-1L)
/* { dg-error "'allocator' clause requires a predefined allocator as 'var3'
is static" "" { target c } .-1 } */
/* { dg-error "'allocator' clause requires a constant predefined allocator"
"" { target c++ } .-2 } */
- /* { dg-message "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ xfail c++ } .-3 } */
+ /* { dg-message "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target c++ } .-3 } */
/* { dg-message "expression evaluates to '\\d+'" "" { target c++ } .-4 } */
return var3;
}
-/* { dg-bogus "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail c++ } 0 } */
+/* { dg-bogus "because one or more variables with static storage duration
appear in the 'allocate' directive" 0 } */
diff --git a/gcc/testsuite/g++.dg/gomp/allocate-14.C
b/gcc/testsuite/g++.dg/gomp/allocate-14.C
new file mode 100644
index 00000000000..d40288d957d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/allocate-14.C
@@ -0,0 +1,1042 @@
+#include "allocate-allocator-handle.h"
+
+/* Diagnostics for invalid cases, including a number of negative cases that
+ should not be diagnosed. */
+
+/****************************************************
+ * Reference variable used in an allocate directive *
+ ****************************************************/
+
+void ref_var()
+{
+ int a = 42;
+ int& ref = a; /* { dg-note "'ref' declared here" } */
+ #pragma omp allocate(ref) /* { dg-error "variables with reference type may
not appear in an 'allocate' directive" } */
+}
+
+template<typename>
+void ref_var_templ_not_instantiated()
+{
+ int a = 42;
+ int& ref = a; /* { dg-note "'ref' declared here" } */
+ #pragma omp allocate(ref) /* { dg-error "variables with reference type may
not appear in an 'allocate' directive" } */
+}
+
+template<typename T>
+void dependent_ref_var_templ_not_instantiated()
+{
+ T a = 42;
+ T& t = a; /* { dg-note "'t' declared here" } */
+ #pragma omp allocate(t) /* { dg-error "variables with reference type may not
appear in an 'allocate' directive" } */
+}
+
+template<typename T>
+void dependent_var_templ_not_instantiated()
+{
+ T t = 42;
+ #pragma omp allocate(t)
+}
+
+template<typename T>
+void dependent_var_templ_0()
+{
+ T t = 42;
+ #pragma omp allocate(t)
+}
+
+template<typename T>
+void dependent_var_templ_1()
+{
+ T t = 42; /* { dg-note "'t' declared here" } */
+ #pragma omp allocate(t) /* { dg-error "variables with reference type may not
appear in an 'allocate' directive" } */
+}
+
+template<typename T>
+void dependent_var_templ_2()
+{
+ int a;
+ T t = a; /* { dg-note "'t' declared here" } */
+ #pragma omp allocate(t) /* { dg-error "variables with reference type may not
appear in an 'allocate' directive" } */
+}
+
+void instantiate_var_templ()
+{
+ dependent_var_templ_0<int>(); /* { dg-bogus "required from here" } */
+ dependent_var_templ_1<int>(); /* { dg-bogus "required from here" } */
+ dependent_var_templ_1<int const&>(); /* { dg-message "required from here" }
*/
+ dependent_var_templ_2<int>(); /* { dg-bogus "required from here" } */
+ dependent_var_templ_2<int&>(); /* { dg-message "required from here" } */
+ dependent_var_templ_2<int const&>(); /* { dg-message "required from here" }
*/
+}
+
+
+/****************************
+ * Invalid allocator clause *
+ ****************************/
+
+template<omp_allocator_handle_t Alloc>
+void nttp_allocator()
+{
+ int a;
+ #pragma omp allocate(a) allocator(Alloc)
+}
+
+template<omp_allocator_handle_t Alloc>
+void nttp_allocator_uninstantiated()
+{
+ int a;
+ #pragma omp allocate(a) allocator(Alloc)
+}
+
+template<int Alloc>
+void nttp_wrong_type_allocator_uninstantiated()
+{
+ int a;
+ #pragma omp allocate(a) allocator(Alloc) /* { dg-error "invalid conversion
from 'int' to 'omp_allocator_handle_t'" "" { xfail *-*-* } } */
+}
+
+template<typename AllocT, AllocT Alloc>
+void nttp_dependent_type_allocator()
+{
+ int a;
+ #pragma omp allocate(a) allocator(Alloc) /* { dg-error "invalid conversion
from 'int' to 'omp_allocator_handle_t'" } */
+}
+
+template<typename AllocT, AllocT Alloc>
+void nttp_dependent_type_allocator_uninstantiated()
+{
+ int a;
+ #pragma omp allocate(a) allocator(Alloc)
+}
+
+void instantiate_nttp_allocator()
+{
+ nttp_allocator<omp_default_mem_alloc>(); /* { dg-bogus "required from here"
} */
+ nttp_dependent_type_allocator<omp_allocator_handle_t,
omp_default_mem_alloc>(); /* { dg-bogus "required from here" } */
+ nttp_dependent_type_allocator<int, 5>(); /* { dg-message "required from
here" } */
+}
+
+template<omp_allocator_handle_t Alloc>
+void nttp_allocator_static()
+{
+ static int a; /* { dg-note "'a' declared here" } */
+ #pragma omp allocate(a) allocator(Alloc)
+ /* { dg-error "'allocator' clause requires a constant predefined allocator"
"" { xfail *-*-* } .-1 } */
+ /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target *-*-* } .-2 } */
+ /* { dg-note "expression evaluates to '1024'" "" { xfail *-*-* } .-3 }*/
+}
+
+template<omp_allocator_handle_t Alloc>
+void nttp_allocator_uninstantiated_static()
+{
+ static int a;
+ #pragma omp allocate(a) allocator(Alloc)
+}
+
+template<int Alloc>
+void nttp_wrong_type_allocator_uninstantiated_static()
+{
+ static int a;
+ #pragma omp allocate(a) allocator(Alloc) /* { dg-error "invalid conversion
from 'int' to 'omp_allocator_handle_t'" "" { xfail *-*-* } } */
+}
+
+template<typename AllocT, AllocT Alloc>
+void nttp_dependent_type_allocator_static_0()
+{
+ static int a; /* { dg-note "'a' declared here" } */
+ #pragma omp allocate(a) allocator(Alloc)
+ /* { dg-error "'allocator' clause requires a constant predefined allocator"
"" { xfail *-*-* } .-1 } */
+ /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target *-*-* } .-2 } */
+ /* { dg-note "expression evaluates to '1024'" "" { xfail *-*-* } .-3 }*/
+}
+
+template<typename AllocT, AllocT Alloc>
+void nttp_dependent_type_allocator_static_1()
+{
+ static int a;
+ #pragma omp allocate(a) allocator(Alloc) /* { dg-error "invalid conversion
from 'int' to 'omp_allocator_handle_t'" } */
+}
+
+template<typename AllocT, AllocT Alloc>
+void nttp_dependent_type_allocator_uninstantiated_static()
+{
+ static int a;
+ #pragma omp allocate(a) allocator(Alloc)
+}
+
+#define DEFINITELY_NOT_PREDEFINED static_cast<omp_allocator_handle_t>(1024)
+
+void instantiate_nttp_allocator_static()
+{
+ nttp_allocator_static<omp_default_mem_alloc>(); /* { dg-bogus "required from
here" } */
+ nttp_allocator_static<DEFINITELY_NOT_PREDEFINED>(); /* { dg-message
"required from here" } */
+ nttp_dependent_type_allocator_static_0<omp_allocator_handle_t,
omp_default_mem_alloc>(); /* { dg-bogus "required from here" } */
+ nttp_dependent_type_allocator_static_0<omp_allocator_handle_t,
DEFINITELY_NOT_PREDEFINED>(); /* { dg-message "required from here" } */
+ nttp_dependent_type_allocator_static_1<int, 1>(); /* { dg-message "required
from here" } */
+}
+
+#undef DEFINITELY_NOT_PREDEFINED
+
+
+template<typename AllocT>
+void templ_allocator_param_0(AllocT alloc)
+{
+ int a;
+ #pragma omp allocate(a) allocator(alloc)
+}
+
+template<typename AllocT>
+void templ_allocator_param_1(AllocT alloc)
+{
+ int a;
+ #pragma omp allocate(a) allocator(alloc) /* { dg-error "invalid conversion
from 'int' to 'omp_allocator_handle_t'" } */
+}
+
+template<typename AllocT>
+void templ_allocator_param_uninstantiated(AllocT alloc)
+{
+ int a;
+ #pragma omp allocate(a) allocator(alloc)
+}
+
+void instantiate_templ_allocator_param()
+{
+ templ_allocator_param_0(omp_default_mem_alloc); /* { dg-bogus "required from
here" } */
+ templ_allocator_param_1(omp_default_mem_alloc); /* { dg-bogus "required from
here" } */
+ templ_allocator_param_1(0); /* { dg-message "required from here" } */
+}
+
+
+template<typename>
+void missing_allocator_clause_uninstantiated()
+{
+ static int a; /* { dg-note "'a' declared here" } */
+ #pragma omp allocate(a)
+ /* { dg-error "'allocator' clause must be specified" "" { target *-*-* } .-1
} */
+ /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target *-*-* } .-2 }*/
+}
+
+/* Cases that are never constant omp_allocator_handle_t expressions (and are
required to be) */
+
+template<typename>
+void allocator_param_static_uninstantiated(omp_allocator_handle_t alloc)
+{
+ static int a; /* { dg-note "'a' declared here" "" { xfail *-*-* } } */
+ #pragma omp allocate(a) allocator(alloc)
+ /* { dg-error "'alloc' is not a constant expression" "" { xfail *-*-* } .-1
}*/
+ /* { dg-error "'allocator' clause requires a constant predefined allocator"
"" { xfail *-*-* } .-2 } */
+ /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail *-*-* } .-3 }*/
+}
+
+template<typename>
+void allocator_var_static_uninstantiated()
+{
+ omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note
"'omp_allocator_handle_t alloc' is not const" "" { xfail *-*-* } } */
+ static int a; /* { dg-note "'a' declared here" "" { xfail *-*-* } } */
+ #pragma omp allocate(a) allocator(alloc)
+ /* { dg-error "the value of 'alloc' is not usable in a constant expression"
"" { xfail *-*-* } .-1 }*/
+ /* { dg-error "'allocator' clause requires a constant predefined allocator"
"" { xfail *-*-* } .-2 } */
+ /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail *-*-* } .-3 }*/
+}
+
+/* While weird, there are inputs for AllocT that are well-formed here,
+ therefore these cases can not be diagnosed until instantiation. */
+
+template<typename AllocT>
+void templ_allocator_param_static_uninstantiated(AllocT alloc)
+{
+ static int a;
+ #pragma omp allocate(a) allocator(alloc) /* { dg-bogus "" } */
+}
+
+template<typename AllocT>
+void templ_allocator_var_static_uninstantiated()
+{
+ AllocT alloc = omp_default_mem_alloc;
+ static int a;
+ #pragma omp allocate(a) allocator(alloc) /* { dg-bogus "" } */
+}
+
+
+/************************
+ * Invalid align clause *
+ ************************/
+
+template<int Align>
+void nttp_align()
+{
+ int a;
+ #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument
needs to be positive constant power of two integer expression" "" { xfail *-*-*
} } */
+}
+
+template<int Align>
+void nttp_align_uninstantiated()
+{
+ int a;
+ #pragma omp allocate(a) align(Align)
+}
+
+template<int* Align>
+void nttp_wrong_type_align_uninstantiated()
+{
+ int a;
+ #pragma omp allocate(a) align(Align)
+ /* { dg-error "could not convert 'Align' from '\[^\n\r\]+' to '\[^\n\r\]+'"
"" { xfail *-*-* } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-2 } */
+}
+
+template<typename AlignT, AlignT Align>
+void nttp_dependent_type_align_0()
+{
+ int a;
+ #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument
needs to be positive constant power of two integer expression" "" { xfail *-*-*
} } */
+}
+
+template<typename AlignT, AlignT Align>
+void nttp_dependent_type_align_1()
+{
+ int a;
+ #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument
needs to be positive constant power of two integer expression" "" { xfail *-*-*
} } */
+}
+
+template<typename AlignT, AlignT Align>
+void nttp_dependent_type_align_uninstantiated()
+{
+ int a;
+ #pragma omp allocate(a) align(Align)
+}
+
+void instantiate_nttp_align()
+{
+ nttp_align<32>();
+ nttp_align<42>(); /* { dg-message "required from here" } */
+ nttp_dependent_type_align_0<int, 32>(); /* { dg-bogus "required from here" }
*/
+ nttp_dependent_type_align_0<int, 42>(); /* { dg-message "required from here"
} */
+ nttp_dependent_type_align_1<int, 32>(); /* { dg-bogus "required from here" }
*/
+ /* We just need any non integer NTTP that is valid in c++98, a fptr fits the
bill. */
+ nttp_dependent_type_align_1<void(*)(), instantiate_nttp_align>(); /* {
dg-message "required from here" } */
+ /* { dg-error "could not convert 'instantiate_nttp_align' from 'void
\\(\\*\\)\\(\\)' to '\[^\n\r\]+'" "Bugged location, see comment" { target *-*-*
} .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "Bugged location, see comment" { target *-*-* } .-2
} */
+ /* { dg-error "conversion from 'void \\(\\*\\)\\(\\)' to '\[^\n\r\]+' in a
converted constant expression" "Bugged location, see comment" { target *-*-* }
.-3 } */
+ /* I believe this diagnostic is bugged, it should refer to where the
+ expression is used, not where it originated from. This isn't a bug for
+ this feature though so I'm making the test case work around it,
+ when this bug is fixed this test case, and the xfail in the test case in
+ nttp_dependent_type_align_1 can be remove. */
+}
+
+/* Cases that are never constant integer expressions (always required for the
align clause.) */
+
+template<typename>
+void align_param_uninstantiated(int align)
+{
+ int a;
+ #pragma omp allocate(a) align(align)
+ /* { dg-error "'align' is not a constant expression" "" { xfail *-*-* } .-1
}*/
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-2 } */
+}
+
+template<typename>
+void align_var_uninstantiated()
+{
+ int align = 32; /* { dg-note "'int align' is not const" "" { xfail *-*-* } }
*/
+ int a;
+ #pragma omp allocate(a) align(align)
+ /* { dg-error "the value of 'align' is not usable in a constant expression"
"" { xfail *-*-* } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-2 } */
+}
+
+/* While weird, there are inputs for AlignT that are well-formed here,
+ therefore these cases can not be diagnosed until instantiation. */
+
+template<typename AlignT>
+void templ_align_param_uninstantiated(AlignT align)
+{
+ int a;
+ #pragma omp allocate(a) align(align) /* { dg-bogus "" } */
+}
+
+template<typename AlignT>
+void templ_align_var_uninstantiated()
+{
+ AlignT align = 32;
+ int a;
+ #pragma omp allocate(a) align(align) /* { dg-bogus "" } */
+}
+
+
+
+/***************
+ * Mixed cases *
+ ***************/
+
+template<typename Var,
+ typename AllocT, AllocT Alloc,
+ typename AlignT, AlignT Align>
+void all_dependent_uninstantiated()
+{
+ int b = 42;
+ Var a = b;
+ #pragma omp allocate(a) allocator(Alloc) align(Align)
+}
+
+template<typename Var,
+ typename AllocT, AllocT Alloc,
+ typename AlignT, AlignT Align>
+void all_dependent_valid()
+{
+ int b = 42;
+ Var a = b;
+ #pragma omp allocate(a) allocator(Alloc) align(Align)
+}
+
+template<typename Var,
+ typename AllocT, AllocT Alloc,
+ typename AlignT, AlignT Align>
+void all_dependent_0()
+{
+ int b = 42;
+ Var a = b; /* { dg-note "'a' declared here" } */
+ #pragma omp allocate(a) allocator(Alloc) align(Align)
+ /* { dg-error "variables with reference type may not appear in an 'allocate'
directive" "" { target *-*-* } .-1 } */
+}
+
+template<typename Var,
+ typename AllocT, AllocT Alloc,
+ typename AlignT, AlignT Align>
+void all_dependent_1()
+{
+ int b = 42;
+ Var a = b;
+ #pragma omp allocate(a) allocator(Alloc) align(Align)
+ /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" ""
{ target *-*-* } .-1 } */
+}
+
+template<typename Var,
+ typename AllocT, AllocT Alloc,
+ typename AlignT, AlignT Align>
+void all_dependent_2()
+{
+ int b = 42;
+ Var a = b;
+ #pragma omp allocate(a) allocator(Alloc) align(Align)
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-1 } */
+}
+
+template<typename Var,
+ typename AllocT, AllocT Alloc,
+ typename AlignT, AlignT Align>
+void all_dependent_3()
+{
+ int b = 42;
+ Var a = b; /* { dg-note "'a' declared here" } */
+ #pragma omp allocate(a) allocator(Alloc) align(Align)
+ /* { dg-error "variables with reference type may not appear in an 'allocate'
directive" "" { target *-*-* } .-1 } */
+ /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" ""
{ target *-*-* } .-2 } */
+}
+
+template<typename Var,
+ typename AllocT, AllocT Alloc,
+ typename AlignT, AlignT Align>
+void all_dependent_4()
+{
+ int b = 42;
+ Var a = b; /* { dg-note "'a' declared here" } */
+ #pragma omp allocate(a) allocator(Alloc) align(Align)
+ /* { dg-error "variables with reference type may not appear in an 'allocate'
directive" "" { target *-*-* } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-2 } */
+}
+
+template<typename Var,
+ typename AllocT, AllocT Alloc,
+ typename AlignT, AlignT Align>
+void all_dependent_5()
+{
+ int b = 42;
+ Var a = b;
+ #pragma omp allocate(a) allocator(Alloc) align(Align)
+ /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" ""
{ target *-*-* } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-2 } */
+}
+
+template<typename Var,
+ typename AllocT, AllocT Alloc,
+ typename AlignT, AlignT Align>
+void all_dependent_6()
+{
+ int b = 42;
+ Var a = b; /* { dg-note "'a' declared here" } */
+ #pragma omp allocate(a) allocator(Alloc) align(Align)
+ /* { dg-error "variables with reference type may not appear in an 'allocate'
directive" "" { target *-*-* } .-1 } */
+ /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" ""
{ target *-*-* } .-2 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-3 } */
+}
+
+void instantiate_all_dependent()
+{
+ all_dependent_valid<int, omp_allocator_handle_t, omp_default_mem_alloc, int,
32>();
+ /* Don't test the type mismatch for the align clause here, it's diagnostic
+ location is buggy, and the error message is the same. We just really want
+ to test that we aren't emitting bogus errors when multiple things are
+ dependent, so it's unnecessary to test that case again. */
+ all_dependent_0<int, omp_allocator_handle_t, omp_default_mem_alloc, int,
32>(); /* { dg-bogus "required from here" } */
+ all_dependent_0<int&, omp_allocator_handle_t, omp_default_mem_alloc, int,
32>(); /* { dg-message "required from here" } */
+
+ all_dependent_1<int, omp_allocator_handle_t, omp_default_mem_alloc, int,
32>(); /* { dg-bogus "required from here" } */
+ all_dependent_1<int, int, 1, int, 32>(); /* { dg-message "required from
here" } */
+
+ all_dependent_2<int, omp_allocator_handle_t, omp_default_mem_alloc, int,
32>(); /* { dg-bogus "required from here" } */
+ all_dependent_2<int, omp_allocator_handle_t, omp_default_mem_alloc, int,
42>(); /* { dg-message "required from here" } */
+
+ all_dependent_3<int, omp_allocator_handle_t, omp_default_mem_alloc, int,
32>(); /* { dg-bogus "required from here" } */
+ all_dependent_3<int&, int, 1, int, 32>(); /* { dg-message "required from
here" } */
+
+ all_dependent_4<int, omp_allocator_handle_t, omp_default_mem_alloc, int,
32>(); /* { dg-bogus "required from here" } */
+ all_dependent_4<int&, omp_allocator_handle_t, omp_default_mem_alloc, int,
42>(); /* { dg-message "required from here" } */
+
+ all_dependent_5<int, omp_allocator_handle_t, omp_default_mem_alloc, int,
32>(); /* { dg-bogus "required from here" } */
+ all_dependent_5<int, int, 1, int, 42>(); /* { dg-message "required from
here" } */
+
+ all_dependent_6<int, omp_allocator_handle_t, omp_default_mem_alloc, int,
32>(); /* { dg-bogus "required from here" } */
+ all_dependent_6<int&, int, 1, int, 42>(); /* { dg-message "required from
here" } */
+}
+
+/* We are missing combined cases for static var used in the allocate directive,
+ but it should be fine, the combined cases immediately above are probably
+ overkill as it is. */
+
+
+/******************************
+ * Invalid allocate directive *
+ ******************************/
+
+/* We are only testing that we gracefully handle an empty list of vars. */
+
+void no_parens()
+{
+ #pragma omp allocate /* { dg-error "expected '\\\(' before end of line" } */
+}
+
+template<typename>
+void templ_no_parens()
+{
+ #pragma omp allocate /* { dg-error "expected '\\\(' before end of line" } */
+}
+template void templ_no_parens<void>();
+
+template<typename>
+void templ_no_parens_uninstantiated()
+{
+ #pragma omp allocate /* { dg-error "expected '\\\(' before end of line" } */
+}
+
+void no_vars()
+{
+ #pragma omp allocate() /* { dg-error "expected unqualified-id before '\\\)'
token" } */
+}
+
+template<typename>
+void templ_no_vars()
+{
+ #pragma omp allocate() /* { dg-error "expected unqualified-id before '\\\)'
token" } */
+}
+template void templ_no_vars<void>();
+
+template<typename>
+void templ_no_vars_uninstantiated()
+{
+ #pragma omp allocate() /* { dg-error "expected unqualified-id before '\\\)'
token" } */
+}
+
+/* We can't diagnose anything about the allocator clause if we have no
+ variables, but we do need to make sure we don't crash. */
+
+void no_vars_allocator()
+{
+ #pragma omp allocate() allocator(omp_default_mem_alloc) /* { dg-error
"expected unqualified-id before '\\\)' token" } */
+}
+
+template<typename>
+void templ_no_vars_allocator()
+{
+ #pragma omp allocate() allocator(omp_default_mem_alloc) /* { dg-error
"expected unqualified-id before '\\\)' token" } */
+}
+template void templ_no_vars_allocator<void>();
+
+template<typename>
+void templ_no_vars_allocator_uninstantiated()
+{
+ #pragma omp allocate() allocator(omp_default_mem_alloc) /* { dg-error
"expected unqualified-id before '\\\)' token" } */
+}
+
+/* We can still diagnose errors about the align clause without any vars. */
+
+void no_vars_invalid_align()
+{
+ #pragma omp allocate() align(42) /* { dg-error "expected unqualified-id
before '\\\)' token" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { target *-*-* } .-1 } */
+}
+
+template<typename>
+void templ_no_vars_invalid_align()
+{
+ #pragma omp allocate() align(42) /* { dg-error "expected unqualified-id
before '\\\)' token" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { target *-*-* } .-1 } */
+}
+template void templ_no_vars_invalid_align<void>();
+
+template<typename>
+void templ_no_vars_invalid_align_uninstantiated()
+{
+ #pragma omp allocate() align(42) /* { dg-error "expected unqualified-id
before '\\\)' token" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-1 } */
+}
+
+template<int Align>
+void templ_no_vars_dep_align()
+{
+ #pragma omp allocate() align(Align) /* { dg-error "expected unqualified-id
before '\\\)' token" } */
+}
+template void templ_no_vars_dep_align<32>();
+
+template<int Align>
+void templ_no_vars_dep_align_invalid()
+{
+ #pragma omp allocate() align(Align) /* { dg-error "expected unqualified-id
before '\\\)' token" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-1 } */
+}
+template void templ_no_vars_dep_align_invalid<42>();
+
+template<int Align>
+void templ_no_vars_dep_align_uninstantiated()
+{
+ #pragma omp allocate() align(Align) /* { dg-error "expected unqualified-id
before '\\\)' token" } */
+}
+
+/*********************************
+ * All vars in directive invalid *
+ *********************************/
+
+void invalid_vars_param(int p) /* { dg-note "parameter 'p' declared here" } */
+{
+ #pragma omp allocate(p) /* { dg-error "function parameter 'p' may not appear
as list item in an 'allocate' directive" } */
+}
+
+template<typename>
+void templ_invalid_vars_param(int p) /* { dg-note "parameter 'p' declared
here" } */
+{
+ #pragma omp allocate(p) /* { dg-error "function parameter 'p' may not appear
as list item in an 'allocate' directive" } */
+}
+template void templ_invalid_vars_param<void>(int);
+
+template<typename>
+void templ_invalid_vars_param_uninstantiated(int p) /* { dg-note "parameter
'p' declared here" } */
+{
+ #pragma omp allocate(p) /* { dg-error "function parameter 'p' may not appear
as list item in an 'allocate' directive" } */
+}
+
+void invalid_vars_out_of_scope()
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a) /* { dg-error "'allocate' directive must be in the
same scope as 'a'" } */
+ }
+}
+
+template<typename>
+void templ_invalid_vars_out_of_scope()
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a) /* { dg-error "'allocate' directive must be in the
same scope as 'a'" } */
+ }
+}
+template void templ_invalid_vars_out_of_scope<void>();
+
+template<typename>
+void templ_invalid_vars_out_of_scope_uninstantiated()
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a) /* { dg-error "'allocate' directive must be in the
same scope as 'a'" } */
+ }
+}
+
+void invalid_vars_out_of_scope_and_param(int p) /* { dg-note "parameter 'p'
declared here" } */
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a, p) /* { dg-error "'allocate' directive must be in
the same scope as 'a'" } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ }
+}
+
+template<typename>
+void templ_invalid_vars_out_of_scope_and_param(int p) /* { dg-note "parameter
'p' declared here" } */
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a, p) /* { dg-error "'allocate' directive must be in
the same scope as 'a'" } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ }
+}
+template void templ_invalid_vars_out_of_scope_and_param<void>(int);
+
+template<typename>
+void templ_invalid_vars_out_of_scope_and_param_uninstantiated(int p) /* {
dg-note "parameter 'p' declared here" } */
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a, p) /* { dg-error "'allocate' directive must be in
the same scope as 'a'" } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ }
+}
+
+/* Same as above, we can't diagnose anything about the allocator clause if we
+ have no variables, but we do need to make sure we don't crash. */
+
+void invalid_vars_param_allocator(int p) /* { dg-note "parameter 'p' declared
here" } */
+{
+ #pragma omp allocate(p) allocator(omp_default_mem_alloc) /* { dg-error
"function parameter 'p' may not appear as list item in an 'allocate' directive"
} */
+}
+
+template<typename>
+void templ_invalid_vars_param_allocator(int p) /* { dg-note "parameter 'p'
declared here" } */
+{
+ #pragma omp allocate(p) allocator(omp_default_mem_alloc) /* { dg-error
"function parameter 'p' may not appear as list item in an 'allocate' directive"
} */
+}
+template void templ_invalid_vars_param_allocator<void>(int);
+
+template<typename>
+void templ_invalid_vars_param_allocator_uninstantiated(int p) /* { dg-note
"parameter 'p' declared here" } */
+{
+ #pragma omp allocate(p) allocator(omp_default_mem_alloc) /* { dg-error
"function parameter 'p' may not appear as list item in an 'allocate' directive"
} */
+}
+
+void invalid_vars_out_of_scope_allocator()
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a) allocator(omp_default_mem_alloc) /* { dg-error
"'allocate' directive must be in the same scope as 'a'" } */
+ }
+}
+
+template<typename>
+void templ_invalid_vars_out_of_scope_allocator()
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a) allocator(omp_default_mem_alloc) /* { dg-error
"'allocate' directive must be in the same scope as 'a'" } */
+ }
+}
+template void templ_invalid_vars_out_of_scope_allocator<void>();
+
+template<typename>
+void templ_invalid_vars_out_of_scope_allocator_uninstantiated()
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a) allocator(omp_default_mem_alloc) /* { dg-error
"'allocate' directive must be in the same scope as 'a'" } */
+ }
+}
+
+void invalid_vars_out_of_scope_and_param_allocator(int p) /* { dg-note
"parameter 'p' declared here" } */
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a, p) allocator(omp_default_mem_alloc) /* { dg-error
"'allocate' directive must be in the same scope as 'a'" } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ }
+}
+
+template<typename>
+void templ_invalid_vars_out_of_scope_and_param_allocator(int p) /* { dg-note
"parameter 'p' declared here" } */
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a, p) allocator(omp_default_mem_alloc) /* { dg-error
"'allocate' directive must be in the same scope as 'a'" } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ }
+}
+template void templ_invalid_vars_out_of_scope_and_param_allocator<void>(int);
+
+template<typename>
+void templ_invalid_vars_out_of_scope_and_param_allocator_uninstantiated(int p)
/* { dg-note "parameter 'p' declared here" } */
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a, p) allocator(omp_default_mem_alloc) /* { dg-error
"'allocate' directive must be in the same scope as 'a'" } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ }
+}
+
+/* Invalid vars with non-dependent invalid align */
+
+void invalid_vars_param_align_invalid(int p) /* { dg-note "parameter 'p'
declared here" } */
+{
+ #pragma omp allocate(p) align(42) /* { dg-error "function parameter 'p' may
not appear as list item in an 'allocate' directive" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { target *-*-* } .-1 } */
+}
+
+template<typename>
+void templ_invalid_vars_param_align_invalid(int p) /* { dg-note "parameter 'p'
declared here" } */
+{
+ #pragma omp allocate(p) align(42) /* { dg-error "function parameter 'p' may
not appear as list item in an 'allocate' directive" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { target *-*-* } .-1 } */
+}
+template void templ_invalid_vars_param_align_invalid<void>(int);
+
+template<typename>
+void templ_invalid_vars_param_align_invalid_uninstantiated(int p) /* { dg-note
"parameter 'p' declared here" } */
+{
+ #pragma omp allocate(p) align(42) /* { dg-error "function parameter 'p' may
not appear as list item in an 'allocate' directive" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-1 } */
+}
+
+void invalid_vars_out_of_scope_align_invalid()
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a) align(42) /* { dg-error "'allocate' directive must
be in the same scope as 'a'" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { target *-*-* } .-1 } */
+ }
+}
+
+template<typename>
+void templ_invalid_vars_out_of_scope_align_invalid()
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a) align(42) /* { dg-error "'allocate' directive must
be in the same scope as 'a'" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { target *-*-* } .-1 } */
+ }
+}
+template void templ_invalid_vars_out_of_scope_align_invalid<void>();
+
+template<typename>
+void templ_invalid_vars_out_of_scope_align_invalid_uninstantiated()
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a) align(42) /* { dg-error "'allocate' directive must
be in the same scope as 'a'" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-1 } */
+ }
+}
+
+void invalid_vars_out_of_scope_and_param_align_invalid(int p) /* { dg-note
"parameter 'p' declared here" } */
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a, p) align(42) /* { dg-error "'allocate' directive
must be in the same scope as 'a'" } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { target *-*-* } .-2 } */
+ }
+}
+
+template<typename>
+void templ_invalid_vars_out_of_scope_and_param_align_invalid(int p) /* {
dg-note "parameter 'p' declared here" } */
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a, p) align(42) /* { dg-error "'allocate' directive
must be in the same scope as 'a'" } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { target *-*-* } .-2 } */
+ }
+}
+template void
templ_invalid_vars_out_of_scope_and_param_align_invalid<void>(int);
+
+template<typename>
+void
templ_invalid_vars_out_of_scope_and_param_align_invalid_uninstantiated(int p)
/* { dg-note "parameter 'p' declared here" } */
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a, p) align(42) /* { dg-error "'allocate' directive
must be in the same scope as 'a'" } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-2 } */
+ }
+}
+
+
+/* Param (dependent align) */
+
+template<int Align>
+void templ_invalid_vars_param_dependent_align_uninstantiated(int p) /* {
dg-note "parameter 'p' declared here" } */
+{
+ #pragma omp allocate(p) align(Align) /* { dg-error "function parameter 'p'
may not appear as list item in an 'allocate' directive" } */
+}
+
+template<int Align>
+void templ_invalid_vars_param_dependent_align(int p) /* { dg-note "parameter
'p' declared here" } */
+{
+ #pragma omp allocate(p) align(Align) /* { dg-error "function parameter 'p'
may not appear as list item in an 'allocate' directive" } */
+}
+template void templ_invalid_vars_param_dependent_align<32>(int);
+
+template<int Align>
+void templ_invalid_vars_param_dependent_align_invalid(int p) /* { dg-note
"parameter 'p' declared here" } */
+{
+ #pragma omp allocate(p) align(Align) /* { dg-error "function parameter 'p'
may not appear as list item in an 'allocate' directive" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-1 } */
+}
+template void templ_invalid_vars_param_dependent_align_invalid<42>(int);
+
+
+/* Out of scope (dependent align) */
+
+template<int Align>
+void templ_invalid_vars_out_of_scope_dependent_align_uninstantiated()
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a) align(Align) /* { dg-error "'allocate' directive
must be in the same scope as 'a'" } */
+ }
+}
+
+template<int Align>
+void templ_invalid_vars_out_of_scope_dependent_align()
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a) align(Align) /* { dg-error "'allocate' directive
must be in the same scope as 'a'" } */
+ }
+}
+template void templ_invalid_vars_out_of_scope_dependent_align<32>();
+
+template<int Align>
+void templ_invalid_vars_out_of_scope_dependent_align_invalid()
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a) align(Align) /* { dg-error "'allocate' directive
must be in the same scope as 'a'" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-1 } */
+ }
+}
+template void templ_invalid_vars_out_of_scope_dependent_align_invalid<42>();
+
+
+/* Param and out of scope (dependent align) */
+
+template<int Align>
+void
templ_invalid_vars_out_of_scope_and_param_dependent_align_uninstantiated(int p)
/* { dg-note "parameter 'p' declared here" } */
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a, p) align(Align) /* { dg-error "'allocate'
directive must be in the same scope as 'a'" } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ }
+}
+
+template<int Align>
+void templ_invalid_vars_out_of_scope_and_param_dependent_align(int p) /* {
dg-note "parameter 'p' declared here" } */
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a, p) align(Align) /* { dg-error "'allocate'
directive must be in the same scope as 'a'" } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ }
+}
+template void
templ_invalid_vars_out_of_scope_and_param_dependent_align<32>(int);
+
+template<int Align>
+void templ_invalid_vars_out_of_scope_and_param_dependent_align_invalid(int p)
/* { dg-note "parameter 'p' declared here" } */
+{
+ int a; /* { dg-note "declared here" } */
+ {
+ #pragma omp allocate(a, p) align(Align) /* { dg-error "'allocate'
directive must be in the same scope as 'a'" } */
+ /* { dg-error "function parameter 'p' may not appear as list item in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-2 } */
+ }
+}
+template void
templ_invalid_vars_out_of_scope_and_param_dependent_align_invalid<42>(int);
+
+
+
+/****************************************************
+ * uses of var in multiple directives in a template *
+ ****************************************************/
+
+/* We are missing a lot of cases here but testing all of them shouldn't be
+ necessary. Uses of variables in multiple directives are diagnosed during
+ parsing so templates shouldn't change anything. This is of course as long
+ as we don't change that, and these cases should be enough to deter anyone
+ from doing so. */
+
+template<typename>
+void multiple_uses_non_dependent_directive_uninstantiated()
+{
+ int a;
+ #pragma omp allocate(a) /* { dg-note "'a' previously appeared here" } */
+ #pragma omp allocate(a) /* { dg-error "'a' already appeared as list item in
an 'allocate' directive" } */
+}
+
+template<typename>
+void multiple_uses_non_dependent_directive()
+{
+ int a;
+ #pragma omp allocate(a) /* { dg-note "'a' previously appeared here" } */
+ #pragma omp allocate(a) /* { dg-error "'a' already appeared as list item in
an 'allocate' directive" } */
+}
+template void multiple_uses_non_dependent_directive<void>();
+
+
+template<int Align>
+void multiple_uses_dep_directive_before_align_uninstantiated()
+{
+ int a;
+ #pragma omp allocate(a) align(Align) /* { dg-note "'a' previously appeared
here" } */
+ #pragma omp allocate(a) /* { dg-error "'a' already appeared as list item in
an 'allocate' directive" } */
+}
+
+template<int Align>
+void multiple_uses_dep_directive_before_valid_align()
+{
+ int a;
+ #pragma omp allocate(a) align(Align) /* { dg-note "'a' previously appeared
here" } */
+ #pragma omp allocate(a) /* { dg-error "'a' already appeared as list item in
an 'allocate' directive" } */
+}
+template void multiple_uses_dep_directive_before_valid_align<32>();
+
+template<int Align>
+void multiple_uses_dep_directive_before_invalid_align()
+{
+ int a;
+ #pragma omp allocate(a) align(Align) /* { dg-note "'a' previously appeared
here" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-1 } */
+ #pragma omp allocate(a) /* { dg-error "'a' already appeared as list item in
an 'allocate' directive" } */
+}
+template void multiple_uses_dep_directive_before_invalid_align<42>();
+
+
+/* Dependent directive after the independent one. */
+
+template<int Align>
+void multiple_uses_dep_directive_after_align_uninstantiated()
+{
+ int a;
+ #pragma omp allocate(a) /* { dg-note "'a' previously appeared here" } */
+ #pragma omp allocate(a) align(Align) /* { dg-error "'a' already appeared as
list item in an 'allocate' directive" } */
+}
+
+template<int Align>
+void multiple_uses_dep_directive_after_valid_align()
+{
+ int a;
+ #pragma omp allocate(a) /* { dg-note "'a' previously appeared here" } */
+ #pragma omp allocate(a) align(Align) /* { dg-error "'a' already appeared as
list item in an 'allocate' directive" } */
+}
+template void multiple_uses_dep_directive_after_valid_align<32>();
+
+template<int Align>
+void multiple_uses_dep_directive_after_invalid_align()
+{
+ int a;
+ #pragma omp allocate(a) /* { dg-note "'a' previously appeared here" } */
+ #pragma omp allocate(a) align(Align) /* { dg-error "'a' already appeared as
list item in an 'allocate' directive" } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-1 } */
+}
+template void multiple_uses_dep_directive_after_invalid_align<42>();
+
+/* These are fixed by the later location wrapping patch. */
+/* { dg-bogus "'align' clause argument needs to be positive constant power of
two integer expression" "" { xfail *-*-* } 0 } */
+/* { dg-bogus "'allocator' clause requires a constant predefined allocator" ""
{ xfail *-*-* } 0 } */
+/* { dg-bogus "expression evaluates to '1024'" "" { xfail *-*-* } 0 } */
diff --git a/gcc/testsuite/g++.dg/gomp/allocate-15.C
b/gcc/testsuite/g++.dg/gomp/allocate-15.C
new file mode 100644
index 00000000000..605e10e477f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/allocate-15.C
@@ -0,0 +1,50 @@
+/* { dg-do compile { target c++11 } } */
+
+/* Diagnostics for rvalue reference vars used in an allocate directive. */
+
+void rref_var()
+{
+ int&& ref = 42; /* { dg-note "'ref' declared here" } */
+ #pragma omp allocate(ref) /* { dg-error "variables with reference type may
not appear in an 'allocate' directive" } */
+}
+
+void const_rref_var()
+{
+ int const&& ref = 42; /* { dg-note "'ref' declared here" } */
+ #pragma omp allocate(ref) /* { dg-error "variables with reference type may
not appear in an 'allocate' directive" } */
+}
+
+template<typename>
+void rref_var_templ_not_instantiated()
+{
+ int&& ref = 42; /* { dg-note "'ref' declared here" } */
+ #pragma omp allocate(ref) /* { dg-error "variables with reference type may
not appear in an 'allocate' directive" } */
+}
+
+template<typename>
+void const_rref_var_templ_not_instantiated()
+{
+ int const&& ref = 42; /* { dg-note "'ref' declared here" } */
+ #pragma omp allocate(ref) /* { dg-error "variables with reference type may
not appear in an 'allocate' directive" } */
+}
+
+template<typename T>
+void dependent_rref_var_templ_not_instantiated()
+{
+ T&& t = 42; /* { dg-note "'t' declared here" } */
+ #pragma omp allocate(t) /* { dg-error "variables with reference type may not
appear in an 'allocate' directive" } */
+}
+
+template<typename T>
+void dependent_var_templ()
+{
+ T t = 42; /* { dg-note "'t' declared here" } */
+ #pragma omp allocate(t) /* { dg-error "variables with reference type may not
appear in an 'allocate' directive" } */
+}
+void instantiate_var_templ()
+{
+ dependent_var_templ<int>(); /* { dg-bogus "required from here" } */
+ dependent_var_templ<int&&>(); /* { dg-message "required from here" } */
+ dependent_var_templ<int const&&>(); /* { dg-message "required from here" } */
+}
+
diff --git a/gcc/testsuite/g++.dg/gomp/allocate-16.C
b/gcc/testsuite/g++.dg/gomp/allocate-16.C
new file mode 100644
index 00000000000..7258d8c1c3c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/allocate-16.C
@@ -0,0 +1,232 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-ice "" { c++17 } } */
+#include "allocate-allocator-handle.h"
+
+/* Incorrect use of lambda captures in a directive or clause.
+ There are a few cases in here that are impacted by the bug with implicit
+ constexpr functions. */
+
+/* These errors (specifically in capture_used_in_directive) really could be
better. */
+
+void capture_used_in_directive()
+{
+ int a = 42;
+ auto cl = [a](){ /* { dg-note "declared here" } */
+ #pragma omp allocate(a) /* { dg-error "'allocate' directive must be in the
same scope as 'a'" } */
+ };
+}
+
+template<typename>
+void capture_used_in_directive_templ_uninstantiated()
+{
+ int a = 42;
+ auto cl = [a](){ /* { dg-note "declared here" } */
+ #pragma omp allocate(a) /* { dg-error "'allocate' directive must be in the
same scope as 'a'" } */
+ };
+}
+
+template<typename>
+void capture_used_in_directive_templ()
+{
+ int a = 42;
+ auto cl = [a](){ /* { dg-note "declared here" } */
+ #pragma omp allocate(a) /* { dg-error "'allocate' directive must be in the
same scope as 'a'" } */
+ };
+}
+
+void instantiate_capture_used_in_directive()
+{
+ capture_used_in_directive_templ<void>();
+}
+
+
+
+void capture_used_in_allocator_clause_static_var()
+{
+ omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note
"'omp_allocator_handle_t alloc' is not const" } */
+ auto cl = [alloc](){
+ static int a = 42; /* { dg-note "'a' declared here" } */
+ int b = 42; /* { dg-bogus "'b' declared here" } */
+ static int c = 42; /* { dg-note "'c' declared here" } */
+ int d = 42; /* { dg-bogus "'d' declared here" } */
+ #pragma omp allocate(a, b, c, d) allocator(alloc)
+ /* { dg-error "the value of 'alloc' is not usable in a constant
expression" "" { target *-*-* } .-1 } */
+ /* { dg-error "'allocator' clause requires a constant predefined
allocator" "" { target *-*-* } .-2 } */
+ /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target *-*-* } .-3 } */
+ };
+}
+
+template<typename>
+void capture_used_in_allocator_clause_static_var_templ_uninstantiated()
+{
+ omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note
"'omp_allocator_handle_t alloc' is not const" "" { xfail *-*-* } } */
+ auto cl = [alloc](){
+ static int a = 42; /* { dg-note "'a' declared here" "" { xfail *-*-* } } */
+ int b = 42; /* { dg-bogus "'b' declared here" } */
+ static int c = 42; /* { dg-note "'c' declared here" "" { xfail *-*-* } } */
+ int d = 42; /* { dg-bogus "'d' declared here" } */
+ #pragma omp allocate(a, b, c, d) allocator(alloc)
+ /* { dg-error "the value of 'alloc' is not usable in a constant
expression" "" { xfail *-*-* } .-1 } */
+ /* { dg-error "'allocator' clause requires a constant predefined
allocator" "" { xfail *-*-* } .-2 } */
+ /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail *-*-* } .-3 } */
+ };
+}
+/* This case can't be diagnosed, there exists a T where alloc is a converted
+ constant expression of type omp_allocator_handle_t. This is demonstrated
+ below in dependent_capture_used_in_allocator_clause_static_var_templ_valid.
*/
+template<typename T>
+void
dependent_capture_used_in_allocator_clause_static_var_templ_uninstantiated()
+{
+ T alloc = omp_default_mem_alloc; /* { dg-bogus "" } */
+ auto cl = [alloc](){
+ static int a = 42; /* { dg-bogus "'a' declared here" } */
+ static int c = 42; /* { dg-bogus "'c' declared here" } */
+ #pragma omp allocate(a, c) allocator(alloc)
+ /* { dg-bogus "the value of 'alloc' is not usable in a constant
expression" "" { target *-*-* } .-1 } */
+ /* { dg-bogus "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target *-*-* } .-2 } */
+ };
+}
+
+template<typename>
+void capture_used_in_allocator_clause_static_var_templ()
+{
+ omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note
"'omp_allocator_handle_t alloc' is not const" "" { xfail c++17 } } */
+ auto cl = [alloc](){
+ static int a = 42; /* { dg-note "'a' declared here" "" { xfail c++17 } } */
+ int b = 42; /* { dg-bogus "'b' declared here" } */
+ static int c = 42; /* { dg-note "'c' declared here" "" { xfail c++17 } } */
+ int d = 42; /* { dg-bogus "'d' declared here" } */
+ #pragma omp allocate(a, b, c, d) allocator(alloc)
+ /* { dg-error "the value of 'alloc' is not usable in a constant
expression" "" { xfail c++17 } .-1 }*/
+ /* { dg-error "'allocator' clause requires a constant predefined
allocator" "" { xfail c++17 } .-2 } */
+ /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail c++17 } .-3 } */
+ };
+}
+
+template<typename T>
+void dependent_capture_used_in_allocator_clause_static_var_templ()
+{
+ T alloc = omp_default_mem_alloc; /* { dg-note "'omp_allocator_handle_t
alloc' is not const" "" { xfail c++17 } } */
+ auto cl = [alloc](){
+ static int a = 42; /* { dg-note "'a' declared here" "" { xfail c++17 } } */
+ int b = 42; /* { dg-bogus "'b' declared here" } */
+ static int c = 42; /* { dg-note "'c' declared here" "" { xfail c++17 } } */
+ int d = 42; /* { dg-bogus "'d' declared here" } */
+ #pragma omp allocate(a, b, c, d) allocator(alloc)
+ /* { dg-error "the value of 'alloc' is not usable in a constant
expression" "" { xfail c++17 } .-1 } */
+ /* { dg-error "'allocator' clause requires a constant predefined
allocator" "" { xfail c++17 } .-2 } */
+ /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail c++17 } .-3 } */
+ };
+}
+
+template<typename T>
+void dependent_capture_used_in_allocator_clause_static_var_templ_valid()
+{
+ T alloc = omp_default_mem_alloc; /* { dg-bogus "" } */
+ auto cl = [alloc](){
+ static int a = 42; /* { dg-bogus "" } */
+ static int c = 42; /* { dg-bogus "" } */
+ #pragma omp allocate(a, c) allocator(alloc)
+ /* { dg-bogus "the value of 'alloc' is not usable in a constant
expression" "" { target *-*-* } .-1 } */
+ /* { dg-bogus "'allocator' clause requires a constant predefined
allocator" "" { target *-*-* } .-2 } */
+ };
+}
+
+void instantiate_capture_used_in_allocator_clause_static_var()
+{
+ capture_used_in_allocator_clause_static_var_templ<void>();
+
dependent_capture_used_in_allocator_clause_static_var_templ<omp_allocator_handle_t>();
+
+ struct S {
+ constexpr S (omp_allocator_handle_t) {}
+ constexpr operator omp_allocator_handle_t () const { return
omp_default_mem_alloc; }
+ };
+ dependent_capture_used_in_allocator_clause_static_var_templ_valid<S> ();
+ dependent_capture_used_in_allocator_clause_static_var_templ_valid<const
omp_allocator_handle_t> ();
+}
+
+
+
+void capture_used_in_align_clause()
+{
+ int align = 32; /* { dg-note "'int align' is not const" } */
+ auto cl = [align](){
+ int a;
+ #pragma omp allocate(a) align(align)
+ /* { dg-error "the value of 'align' is not usable in a constant
expression" "" { target *-*-* } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { target *-*-* } .-2 } */
+ };
+}
+
+template<typename>
+void capture_used_in_align_clause_templ_uninstantiated()
+{
+ int align = 32; /* { dg-note "'int align' is not const" "" { xfail *-*-* } }
*/
+ auto cl = [align](){
+ /* { dg-bogus "the value of 'align' is not usable in a constant expression"
"" { target *-*-* } .-1 } */
+ int a;
+ #pragma omp allocate(a) align(align)
+ /* { dg-error "the value of 'align' is not usable in a constant
expression" "" { xfail *-*-* } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { xfail *-*-* } .-2 } */
+ };
+}
+
+/* This case can't be diagnosed, there exists a T where align is a converted
+ constant expression of long unsigned int. This is demonstrated
+ below in dependent_capture_used_in_align_clause_templ_valid. */
+template<typename T>
+void dependent_capture_used_in_align_clause_templ_uninstantiated()
+{
+ T align = 32; /* { dg-bogus "" } */
+ auto cl = [align](){
+ int a;
+ #pragma omp allocate(a) align(align) /* { dg-bogus "" } */
+ };
+}
+
+template<typename>
+void capture_used_in_align_clause_templ()
+{
+ int align = 32; /* { dg-note "'int align' is not const" "" { xfail c++17 } }
*/
+ auto cl = [align](){
+ int a;
+ #pragma omp allocate(a) align(align)
+ /* { dg-error "the value of 'align' is not usable in a constant
expression" "" { target *-*-* xfail c++17 } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { target *-*-* xfail c++17 } .-2 } */
+ };
+}
+
+template<typename T>
+void dependent_capture_used_in_align_clause_templ()
+{
+ T align = 32; /* { dg-note "'int align' is not const" "" { xfail c++17 } } */
+ auto cl = [align](){
+ int a;
+ #pragma omp allocate(a) align(align)
+ /* { dg-error "the value of 'align' is not usable in a constant
expression" "" { target *-*-* xfail c++17 } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant power
of two integer expression" "" { target *-*-* xfail c++17 } .-2 } */
+ };
+}
+
+template<typename T>
+void dependent_capture_used_in_align_clause_templ_valid()
+{
+ T align = 32; /* { dg-bogus "" } */
+ auto cl = [align](){
+ int a;
+ #pragma omp allocate(a) align(align) /* { dg-bogus "" } */
+ };
+}
+
+void instantiate_capture_used_in_align()
+{
+ capture_used_in_align_clause_templ<void>();
+ dependent_capture_used_in_align_clause_templ<int>();
+
+ struct S {
+ constexpr S (int) {}
+ constexpr operator unsigned int () const { return 32; }
+ };
+ dependent_capture_used_in_align_clause_templ_valid<S> ();
+ dependent_capture_used_in_align_clause_templ_valid<const int> ();
+}
diff --git a/gcc/testsuite/g++.dg/gomp/allocate-17.C
b/gcc/testsuite/g++.dg/gomp/allocate-17.C
new file mode 100644
index 00000000000..e265ecdd1e7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/allocate-17.C
@@ -0,0 +1,560 @@
+/* { dg-do compile { target c++17 } } */
+
+/* Nested lambdas. */
+
+#include "allocate-allocator-handle.h"
+
+template<int Align>
+auto lambda_0_valid()
+{
+ return [](auto p0){
+ return [](auto p1){
+ return [](auto p2){
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b;
+ #pragma omp allocate(a) align(Align) allocator(p2)
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<int Align>
+auto lambda_0_bad_align()
+{
+ return [](auto p0){
+ return [](auto p1){
+ return [](auto p2){
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b;
+ #pragma omp allocate(a) align(Align) allocator(p2)
+ /* { dg-error "'align' clause argument needs to be positive constant
power of two integer expression" "" { xfail *-*-* } .-1 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<int Align>
+auto lambda_0_ref_in_directive()
+{
+ return [](auto p0){
+ return [](auto p1){
+ return [](auto p2){
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b; /* { dg-message "'a' declared here" } */
+ #pragma omp allocate(a) align(Align) allocator(p2)
+ /* { dg-error "variables with reference type may not appear in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+
+template<int Align>
+auto lambda_0_invalid_allocator()
+{
+ return [](auto p0){
+ return [](auto p1){
+ return [](auto p2){
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b;
+ #pragma omp allocate(a) align(Align) allocator(p2)
+ /* { dg-error "invalid conversion from 'int' to
'omp_allocator_handle_t'" "" { target *-*-* } .-1 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<int Align>
+auto lambda_0_all()
+{
+ return [](auto p0){
+ return [](auto p1){
+ return [](auto p2){
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b; /* { dg-message "'a' declared here" } */
+ #pragma omp allocate(a) align(Align) allocator(p2)
+ /* { dg-error "variables with reference type may not appear in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant
power of two integer expression" "" { xfail *-*-* } .-2 } */
+ /* { dg-error "invalid conversion from 'int' to
'omp_allocator_handle_t'" "" { target *-*-* } .-3 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<int Align>
+auto lambda_0_wrong_align_partially_instantiated()
+{
+ return [](auto p0){
+ return [](auto p1){
+ return [](auto p2){
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b;
+ #pragma omp allocate(a) align(Align) allocator(p2)
+ /* { dg-error "'align' clause argument needs to be positive constant
power of two integer expression" "" { xfail *-*-* } .-1 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<int Align>
+auto lambda_0_invalid_allocator_partially_instantiated()
+{
+ return [](auto p0){
+ return [](auto p1){
+ return [](auto p2){
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b;
+ #pragma omp allocate(a) align(Align) allocator(p2)
+ /* { dg-error "invalid conversion from 'int' to
'omp_allocator_handle_t'" "" { xfail *-*-* } .-1 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+void instantiate_lambdas_0()
+{
+ {
+ auto c0 = lambda_0_valid<32>();
+ auto c1 = c0(0);
+ auto c2 = c1(0);
+ auto c3 = c2(omp_default_mem_alloc);
+ c3(0);
+ }
+ {
+ auto c0 = lambda_0_bad_align<30>(); /* { dg-message "required from here"
"" { xfail *-*-* } } */
+ auto c1 = c0(0); /* { dg-bogus "required from here" } */
+ auto c2 = c1(0); /* { dg-bogus "required from here" } */
+ auto c3 = c2(omp_default_mem_alloc); /* { dg-bogus "required from here" }
*/
+ c3(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */
+ }
+ {
+ auto c0 = lambda_0_ref_in_directive<32>();
+ auto c1 = c0(0);
+ auto c2 = c1(0);
+ auto c3 = c2(omp_default_mem_alloc);
+ int a = 0;
+ c3.operator()<int&>(a); /* { dg-message "required from here" } */
+ }
+ {
+ auto c0 = lambda_0_invalid_allocator<32>();
+ auto c1 = c0(0);
+ auto c2 = c1(0);
+ auto c3 = c2(0); /* { dg-message "required from here" "" { xfail *-*-* } }
*/
+ c3(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */
+ }
+ {
+ auto c0 = lambda_0_all<30>(); /* { dg-message "required from here" "" {
xfail *-*-* } } */
+ auto c1 = c0(0); /* { dg-bogus "required from here" } */
+ auto c2 = c1(0); /* { dg-bogus "required from here" } */
+ auto c3 = c2(0); /* { dg-message "required from here" "" { xfail *-*-* } }
*/
+ int a = 0;
+ c3.operator()<int&>(a); /* { dg-message "required from here" } */
+ }
+ {
+ auto c = lambda_0_wrong_align_partially_instantiated<30>(); /* {
dg-message "required from here" "" { xfail *-*-* } } */
+ }
+ {
+ auto c0 = lambda_0_invalid_allocator_partially_instantiated<32>();
+ auto c1 = c0(0);
+ auto c2 = c1(0);
+ auto c3 = c2(0); /* { dg-message "required from here" "" { xfail *-*-* } }
*/
+ }
+}
+
+
+
+template<int Align>
+auto lambda_1_valid()
+{
+ return [](auto p0){
+ int a = 42;
+ #pragma omp allocate(a) align(Align)
+ return [](auto p1){
+ int a = 42;
+ #pragma omp allocate(a) align(Align)
+ return [](auto p2){
+ int a = 42;
+ #pragma omp allocate(a) align(Align)
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b;
+ #pragma omp allocate(a) align(Align) allocator(p2)
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<int Align>
+auto lambda_1_bad_align()
+{
+ return [](auto p0){
+ int a = 42;
+ #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause
argument needs to be positive constant power of two integer expression" "" {
xfail *-*-* } } */
+ return [](auto p1){
+ int a = 42;
+ #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause
argument needs to be positive constant power of two integer expression" "" {
xfail *-*-* } } */
+ return [](auto p2){
+ int a = 42;
+ #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause
argument needs to be positive constant power of two integer expression" "" {
xfail *-*-* } } */
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b;
+ #pragma omp allocate(a) align(Align) allocator(p2)
+ /* { dg-error "'align' clause argument needs to be positive constant
power of two integer expression" "" { xfail *-*-* } .-1 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<int Align>
+auto lambda_1_ref_in_directive()
+{
+ return [](auto p0){
+ int a = 42;
+ #pragma omp allocate(a) align(Align)
+ return [](auto p1){
+ int a = 42;
+ #pragma omp allocate(a) align(Align)
+ return [](auto p2){
+ int a = 42;
+ #pragma omp allocate(a) align(Align)
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b; /* { dg-message "'a' declared here" } */
+ #pragma omp allocate(a) align(Align) allocator(p2)
+ /* { dg-error "variables with reference type may not appear in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<int Align>
+auto lambda_1_invalid_allocator()
+{
+ return [](auto p0){
+ int a = 42;
+ #pragma omp allocate(a) align(Align)
+ return [](auto p1){
+ int a = 42;
+ #pragma omp allocate(a) align(Align)
+ return [](auto p2){
+ int a = 42;
+ #pragma omp allocate(a) align(Align)
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b;
+ #pragma omp allocate(a) align(Align) allocator(p2)
+ /* { dg-error "invalid conversion from 'int' to
'omp_allocator_handle_t'" "" { target *-*-* } .-1 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<int Align>
+auto lambda_1_all()
+{
+ return [](auto p0){
+ int a = 42;
+ #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause
argument needs to be positive constant power of two integer expression" "" {
xfail *-*-* } } */
+ return [](auto p1){
+ int a = 42;
+ #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause
argument needs to be positive constant power of two integer expression" "" {
xfail *-*-* } } */
+ return [](auto p2){
+ int a = 42;
+ #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause
argument needs to be positive constant power of two integer expression" "" {
xfail *-*-* } } */
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b; /* { dg-message "'a' declared here" } */
+ #pragma omp allocate(a) align(Align) allocator(p2)
+ /* { dg-error "variables with reference type may not appear in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ /* { dg-error "'align' clause argument needs to be positive constant
power of two integer expression" "" { xfail *-*-* } .-2 } */
+ /* { dg-error "invalid conversion from 'int' to
'omp_allocator_handle_t'" "" { target *-*-* } .-3 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<int Align>
+auto lambda_1_wrong_align_partially_instantiated()
+{
+ return [](auto p0){
+ int a = 42;
+ #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause
argument needs to be positive constant power of two integer expression" "" {
xfail *-*-* } } */
+ return [](auto p1){
+ int a = 42;
+ #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause
argument needs to be positive constant power of two integer expression" "" {
xfail *-*-* } } */
+ return [](auto p2){
+ int a = 42;
+ #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause
argument needs to be positive constant power of two integer expression" "" {
xfail *-*-* } } */
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b;
+ #pragma omp allocate(a) align(Align) allocator(p2) /* { dg-error
"'align' clause argument needs to be positive constant power of two integer
expression" "" { xfail *-*-* } } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<int Align>
+auto lambda_1_invalid_allocator_partially_instantiated()
+{
+ return [](auto p0){
+ int a = 42;
+ #pragma omp allocate(a) align(Align)
+ return [](auto p1){
+ int a = 42;
+ #pragma omp allocate(a) align(Align)
+ return [](auto p2){
+ int a = 42;
+ #pragma omp allocate(a) align(Align)
+ return [p2](auto p3){
+ int b = 42;
+ decltype(p3) a = b;
+ #pragma omp allocate(a) align(Align) allocator(p2)
+ /* { dg-error "invalid conversion from 'int' to
'omp_allocator_handle_t'" "" { xfail *-*-* } .-1 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+void instantiate_lambdas_1()
+{
+ {
+ auto c0 = lambda_1_valid<32>();
+ auto c1 = c0(0);
+ auto c2 = c1(0);
+ auto c3 = c2(omp_default_mem_alloc);
+ c3(0);
+ }
+ {
+ auto c0 = lambda_1_bad_align<30>(); /* { dg-message "required from here"
"" { xfail *-*-* } } */
+ auto c1 = c0(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */
+ auto c2 = c1(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */
+ auto c3 = c2(omp_default_mem_alloc); /* { dg-bogus "required from here" ""
{ xfail *-*-* } } */
+ c3(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */
+ }
+ {
+ auto c0 = lambda_1_ref_in_directive<32>();
+ auto c1 = c0(0);
+ auto c2 = c1(0);
+ auto c3 = c2(omp_default_mem_alloc);
+ int a = 0;
+ c3.operator()<int&>(a); /* { dg-message "required from here" } */
+ }
+ {
+ auto c0 = lambda_1_invalid_allocator<32>();
+ auto c1 = c0(0);
+ auto c2 = c1(0);
+ auto c3 = c2(0); /* { dg-message "required from here" "" { xfail *-*-* } }
*/
+ c3(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */
+ }
+ {
+ auto c0 = lambda_1_all<30>(); /* { dg-message "required from here" "" {
xfail *-*-* } } */
+ auto c1 = c0(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */
+ auto c2 = c1(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */
+ auto c3 = c2(0); /* { dg-message "required from here" } */
+ int a = 0;
+ c3.operator()<int&>(a); /* { dg-message "required from here" } */
+ }
+ {
+ auto c = lambda_1_wrong_align_partially_instantiated<30>(); /* {
dg-message "required from here" "" { xfail *-*-* } } */
+ }
+ {
+ auto c0 = lambda_1_invalid_allocator_partially_instantiated<32>();
+ auto c1 = c0(0);
+ auto c2 = c1(0);
+ auto c3 = c2(0); /* { dg-message "required from here" "" { xfail *-*-* } }
*/
+ }
+}
+
+
+
+template<typename T>
+auto lambda_2_0_valid()
+{
+ return [](auto){
+ return [](auto){
+ return [](auto){
+ return [](auto){
+ int b = 42;
+ T a = b;
+ #pragma omp allocate(a)
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<typename T>
+auto lambda_2_0_invalid()
+{
+ return [](auto){
+ return [](auto){
+ return [](auto){
+ return [](auto){
+ int b = 42;
+ T a = b; /* { dg-message "'a' declared here" } */
+ #pragma omp allocate(a)
+ /* { dg-error "variables with reference type may not appear in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<typename T>
+auto lambda_2_0_invalid_partially_instantiated()
+{
+ return [](auto){
+ return [](auto){
+ return [](auto){
+ return [](auto){
+ int b = 42;
+ T a = b; /* { dg-message "'a' declared here" } */
+ #pragma omp allocate(a)
+ /* { dg-error "variables with reference type may not appear in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<typename>
+auto lambda_2_1_valid()
+{
+ return [](auto){
+ return [](auto){
+ return [](auto p2){
+ using type = decltype(p2);
+ return [](auto){
+ int b = 42;
+ type a = b;
+ #pragma omp allocate(a)
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<typename>
+auto lambda_2_1_invalid()
+{
+ return [](auto){
+ return [](auto){
+ return [](auto p2){
+ using type = decltype(p2);
+ return [](auto){
+ int b = 42;
+ type a = b; /* { dg-message "'a' declared here" } */
+ #pragma omp allocate(a)
+ /* { dg-error "variables with reference type may not appear in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+template<typename>
+auto lambda_2_1_invalid_partially_instantiated()
+{
+ return [](auto){
+ return [](auto){
+ return [](auto p2){
+ using type = decltype(p2);
+ return [](auto){
+ int b = 42;
+ type a = b; /* { dg-message "'a' declared here" } */
+ #pragma omp allocate(a)
+ /* { dg-error "variables with reference type may not appear in an
'allocate' directive" "" { target *-*-* } .-1 } */
+ return a;
+ };
+ };
+ };
+ };
+}
+
+void instantiate_lambdas_2()
+{
+ {
+ auto c0 = lambda_2_0_valid<int>();
+ auto c1 = c0(0);
+ auto c2 = c1(0);
+ auto c3 = c2(0);
+ c3(0);
+ }
+ {
+ auto c0 = lambda_2_0_invalid<int&>(); /* { dg-message "required from here"
} */
+ auto c1 = c0(0); /* { dg-bogus "required from here" } */
+ auto c2 = c1(0); /* { dg-bogus "required from here" } */
+ auto c3 = c2(0); /* { dg-bogus "required from here" } */
+ c3(0); /* { dg-bogus "required from here" } */
+ }
+ {
+ auto c0 = lambda_2_0_invalid_partially_instantiated<int&>(); /* {
dg-message "required from here" } */
+ }
+ {
+ auto c0 = lambda_2_1_valid<void>();
+ auto c1 = c0(0);
+ auto c2 = c1(0);
+ auto c3 = c2(0);
+ c3(0);
+ }
+ {
+ auto c0 = lambda_2_1_invalid<void>();
+ auto c1 = c0(0);
+ auto c2 = c1(0);
+ int a = 0;
+ auto c3 = c2.operator()<int&>(a); /* { dg-message "required from here" } */
+ c3(0); /* { dg-bogus "required from here" } */
+ }
+ {
+ auto c0 = lambda_2_1_invalid_partially_instantiated<void>();
+ auto c1 = c0(0);
+ auto c2 = c1(0);
+ int a = 0;
+ auto c3 = c2.operator()<int&>(a); /* { dg-message "required from here" } */
+ }
+}
+
+/* This is fixed by the later location wrapping patch. */
+/* { dg-bogus "'align' clause argument needs to be positive constant power of
two integer expression" "" { xfail *-*-* } 0 } */
diff --git a/gcc/testsuite/g++.dg/gomp/allocate-18.C
b/gcc/testsuite/g++.dg/gomp/allocate-18.C
new file mode 100644
index 00000000000..3a04bbe8bcd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/allocate-18.C
@@ -0,0 +1,274 @@
+/* { dg-do compile { target c++17 } } */
+
+/* OpenMP allocate directive in constant expressions where execution does not
+ pass through the allocation of the variable in the directive.
+ Lambdas, both implicit and explicit constexpr,
+ in a function and in a function template.
+
+ These cases will be valid if/when OpenMP relaxes restrictions on directives
+ in constexpr functions. It might make sense to only allow this behavior in
+ c++23 though.
+
+ Constexpr lambdas are only permitted in c++17, it doesn't make sense to test
+ anything prior than that.
+
+ NOTE: The error messages for the cases that are not explicitly declared
+ constexpr are probably not what we want, we likely want something stating
+ that the calls are not usable in a constant expression because of the use of
+ an OpenMP directive. */
+
+void do_constexpr_lambda()
+{
+ auto cl = [](bool b) constexpr {
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+ };
+ constexpr int v0 = cl(true); /* { dg-error
"'do_constexpr_lambda\\\(\\\)::<lambda\\\(bool\\\)>' called in a constant
expression" "" { xfail *-*-* } } */
+
+ constexpr int v1 = [](bool b) constexpr {
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+ }(true);
+}
+
+void do_constexpr_generic_lambda()
+{
+ auto cl = [](auto b) constexpr {
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+ };
+ constexpr int v0 = cl(true); /* { dg-error
"'do_constexpr_generic_lambda\\\(\\\)::<lambda\\\(bool\\\)>' called in a
constant expression" "" { xfail *-*-* } } */
+
+ constexpr int v1 = [](auto b) constexpr {
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+ }(true);
+}
+
+void do_lambda()
+{
+ auto cl = [](bool b){
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+ };
+ constexpr int v0 = cl(true); /* { dg-error
"'do_lambda\\\(\\\)::<lambda\\\(bool\\\)>' called in a constant expression" ""
{ xfail *-*-* } } */
+
+ constexpr int v1 = [](bool b){
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+ }(true);
+}
+
+void do_generic_lambda()
+{
+ auto cl = [](auto b){
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+ };
+ constexpr int v0 = cl(true); /* { dg-error
"'do_generic_lambda\\\(\\\)::<lambda\\\(bool\\\)>' called in a constant
expression" "" { xfail *-*-* } } */
+
+ constexpr int v1 = [](auto b){
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+ }(true);
+}
+
+template<typename>
+void do_constexpr_lambda_templ_uninstantiated()
+{
+ auto cl = [](bool b) constexpr {
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+ };
+ constexpr int v0 = cl(true); /* { dg-error "called in a constant expression"
"" { xfail *-*-* } } */
+
+ constexpr int v1 = [](bool b) constexpr {
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+ }(true);
+}
+
+template<typename>
+void do_constexpr_generic_lambda_templ_uninstantiated()
+{
+ auto cl = [](auto b) constexpr {
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+ };
+ constexpr int v0 = cl(true); /* { dg-error "called in a constant expression"
"" { xfail *-*-* } } */
+
+ constexpr int v1 = [](auto b) constexpr {
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+ }(true);
+}
+
+template<typename>
+void do_lambda_templ_uninstantiated()
+{
+ auto cl = [](bool b){
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+ };
+ constexpr int v0 = cl(true); /* { dg-error "called in a constant expression"
"" { xfail *-*-* } } */
+
+ constexpr int v1 = [](bool b){
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+ }(true);
+}
+
+template<typename>
+void do_generic_lambda_templ_uninstantiated()
+{
+ auto cl = [](auto b){
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+ };
+ constexpr int v0 = cl(true); /* { dg-error "called in a constant expression"
"" { xfail *-*-* } } */
+
+ constexpr int v1 = [](auto b){
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+ }(true);
+}
+
+
+template<typename>
+void do_constexpr_lambda_templ()
+{
+ auto cl = [](bool b) constexpr {
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+ };
+ constexpr int v0 = cl(true); /* { dg-error
"'do_constexpr_lambda_templ<void>\\\(\\\)::<lambda\\\(bool\\\)>' called in a
constant expression" "" { xfail *-*-* } } */
+
+ constexpr int v1 = [](bool b) constexpr {
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+ }(true);
+}
+template void do_constexpr_lambda_templ<void>();
+
+template<typename>
+void do_constexpr_generic_lambda_templ()
+{
+ auto cl = [](auto b) constexpr {
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+ };
+ constexpr int v0 = cl(true); /* { dg-error
"'do_constexpr_lambda_templ<void>\\\(\\\)::<lambda\\\(bool\\\)>' called in a
constant expression" "" { xfail *-*-* } } */
+
+ constexpr int v1 = [](auto b) constexpr {
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+ }(true);
+}
+template void do_constexpr_generic_lambda_templ<void>();
+
+template<typename>
+void do_lambda_templ()
+{
+ auto cl = [](bool b){
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+ };
+ constexpr int v0 = cl(true); /* { dg-error
"'do_lambda_templ<void>\\\(\\\)::<lambda\\\(bool\\\)>' called in a constant
expression" "" { xfail *-*-* } } */
+
+ constexpr int v1 = [](bool b){
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+ }(true);
+}
+template void do_lambda_templ<void>();
+
+template<typename>
+void do_generic_lambda_templ()
+{
+ auto cl = [](auto b){
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+ };
+ constexpr int v0 = cl(true); /* { dg-error
"'do_generic_lambda_templ<void>\\\(\\\)::<lambda\\\(bool\\\)>' called in a
constant expression" "" { xfail *-*-* } } */
+
+ constexpr int v1 = [](auto b){
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+ }(true);
+}
+template void do_generic_lambda_templ<void>();
+
+/* Missing cases where the lambda/lambda body is dependent on the outer
+ template params. */
diff --git a/gcc/testsuite/g++.dg/gomp/allocate-19.C
b/gcc/testsuite/g++.dg/gomp/allocate-19.C
new file mode 100644
index 00000000000..e99106893da
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/allocate-19.C
@@ -0,0 +1,128 @@
+/* { dg-do compile { target c++14 } } */
+/* { dg-additional-options "-fimplicit-constexpr" } */
+
+/* OpenMP allocate directive in constant expressions where execution does not
+ pass through the allocation of the variable in the directive.
+ Regular functions and function templates,
+ constexpr and inline with -fimplicit-constexpr.
+
+ These cases will be valid if/when OpenMP relaxes restrictions on directives
+ in constexpr functions. It might make sense to only allow this behavior in
+ c++23 though.
+
+ It doesn't make sense to test these cases in c++11 as constexpr functions
+ are far more limited, and are diagnosed completely differently.
+
+ Even though -fimplicit-constexpr is an extension, its behavior is similar to
+ lambdas in c++17, so I am including tests for it.
+ See allocate-18.C for test cases involving lambdas.
+
+ NOTE: The error messages for the inline cases are are probably not what we
+ want, we likely want something stating that the calls are not usable in a
+ constant expression because of the use of an OpenMP directive. */
+
+constexpr int f_constexpr(bool b)
+{
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+}
+constexpr int g_cx_0 = f_constexpr(true); /* { dg-error "'constexpr int
f_constexpr\\\(bool\\\)' called in a constant expression" "" { xfail *-*-* } }
*/
+
+template<typename>
+constexpr int f_constexpr_templ_uninstantiated(bool b)
+{
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+}
+
+template<typename>
+constexpr int f_constexpr_templ(bool b)
+{
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+}
+constexpr int g_cx_1 = f_constexpr_templ<void>(true); /* { dg-error
"'constexpr int f_constexpr_templ\\\(bool\\\) \\\[with <template-parameter-1-1>
= void\\\]' called in a constant expression" "" { xfail *-*-* } } */
+
+template<typename B>
+constexpr int f_constexpr_dep_parm_templ_uninstantiated(B b)
+{
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+}
+
+template<typename B>
+constexpr int f_constexpr_dep_parm_templ(B b)
+{
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" } */
+ return a;
+}
+constexpr int g_cx_2 = f_constexpr_dep_parm_templ(true); /* { dg-error
"'constexpr int f_constexpr_dep_parm_templ\\\(bool\\\) \\\[with
<template-parameter-1-1> = bool\\\]' called in a constant expression" "" {
xfail *-*-* } } */
+
+
+
+inline int f_inline(bool b)
+{
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+}
+constexpr int g_inline_0 = f_inline(true); /* { dg-error "'int
f_inline\\\(bool\\\)' called in a constant expression" "" { xfail *-*-* } } */
+
+template<typename>
+inline int f_inline_templ_uninstantiated(bool b)
+{
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+}
+
+template<typename>
+inline int f_inline_templ(bool b)
+{
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+}
+constexpr int g_inline_1 = f_inline_templ<void>(true); /* { dg-error "'int
f_inline_templ\\\(bool\\\) \\\[with <template-parameter-1-1> = void\\\]' called
in a constant expression" "" { xfail *-*-* } } */
+
+template<typename B>
+inline int f_inline_dep_parm_templ_uninstantiated(B b)
+{
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+}
+
+template<typename B>
+inline int f_inline_dep_parm_templ(B b)
+{
+ if (b)
+ return 42;
+ int a = 42;
+ #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in
'constexpr' functions" "" { xfail *-*-* } } */
+ return a;
+}
+constexpr int g_inline_2 = f_inline_dep_parm_templ(true); /* { dg-error "'int
f_inline_deb_parm_templ\\\(bool\\\) \\\[with <template-parameter-1-1> =
bool\\\]' called in a constant expression" "" { xfail *-*-* } } */
diff --git a/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C
b/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C
index c0c59a30a3c..786c2f5550e 100644
--- a/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C
+++ b/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C
@@ -15,49 +15,47 @@
#define GOMP_OMPX_PREDEF_ALLOC_MIN 200
#define GOMP_OMPX_PREDEF_ALLOC_MAX 201
-int g0 = 42; /* { dg-note "'g0' declared here" "" { xfail *-*-* } } */
+int g0 = 42; /* { dg-note "'g0' declared here" } */
#pragma omp allocate(g0) allocator(omp_null_allocator)
/* { dg-error "'allocator' clause requires a constant predefined allocator" ""
{ target *-*-* } .-1 } */
-/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */
+/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target *-*-* } .-2 } */
/* { dg-note "expression evaluates to '0'" "" { target *-*-* } .-3 } */
-int g1 = 42; /* { dg-note "'g1' declared here" "" { xfail *-*-* } }*/
+int g1 = 42; /* { dg-note "'g1' declared here" } */
#pragma omp allocate(g1)
allocator(static_cast<omp_allocator_handle_t>(GOMP_OMP_PREDEF_ALLOC_MAX + 1))
/* { dg-error "'allocator' clause requires a constant predefined allocator"
"If this test fails because of added predefined allocators please ensure
everything is updated accordingly, see this test case for more information" {
target *-*-* } .-1 } */
-/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */
+/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target *-*-* } .-2 } */
/* { dg-note "expression evaluates to '9'" "" { target *-*-* } .-3 } */
-int g2 = 42; /* { dg-note "'g2' declared here" "" { xfail *-*-* } }*/
+int g2 = 42; /* { dg-note "'g2' declared here" } */
#pragma omp allocate(g2)
allocator(static_cast<omp_allocator_handle_t>(GOMP_OMPX_PREDEF_ALLOC_MIN - 1))
/* { dg-error "'allocator' clause requires a constant predefined allocator" ""
{ target *-*-* } .-1 } */
-/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */
+/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target *-*-* } .-2 } */
/* { dg-note "expression evaluates to '199'" "" { target *-*-* } .-3 } */
-int g3 = 42; /* { dg-note "'g3' declared here" "" { xfail *-*-* } }*/
+int g3 = 42; /* { dg-note "'g3' declared here" } */
#pragma omp allocate(g3)
allocator(static_cast<omp_allocator_handle_t>(GOMP_OMPX_PREDEF_ALLOC_MAX + 1))
/* { dg-error "'allocator' clause requires a constant predefined allocator"
"If this test fails because of added predefined allocators please ensure
everything is updated accordingly, see this test case for more information" {
target *-*-* } .-1 } */
-/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */
+/* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target *-*-* } .-2 } */
/* { dg-note "expression evaluates to '202'" "" { target *-*-* } .-3 } */
void test_predefined_allocs()
{
- static int a0 = 42; /* { dg-note "'a0' declared here" "" { xfail *-*-* } }*/
+ static int a0 = 42; /* { dg-note "'a0' declared here" }*/
#pragma omp allocate(a0) allocator(omp_null_allocator)
/* { dg-error "'allocator' clause requires a constant predefined allocator"
"" { target *-*-* } .-1 } */
- /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */
+ /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target *-*-* } .-2 } */
/* { dg-note "expression evaluates to '0'" "" { target *-*-* } .-3 } */
- static int a1 = 42; /* { dg-note "'a1' declared here" "" { xfail *-*-* } }*/
+ static int a1 = 42; /* { dg-note "'a1' declared here" }*/
#pragma omp allocate(a1)
allocator(static_cast<omp_allocator_handle_t>(GOMP_OMP_PREDEF_ALLOC_MAX + 1))
/* { dg-error "'allocator' clause requires a constant predefined allocator"
"If this test fails because of added predefined allocators please ensure
everything is updated accordingly, see this test case for more information" {
target *-*-* } .-1 } */
- /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */
+ /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target *-*-* } .-2 } */
/* { dg-note "expression evaluates to '9'" "" { target *-*-* } .-3 } */
- static int a2 = 42; /* { dg-note "'a2' declared here" "" { xfail *-*-* } }*/
+ static int a2 = 42; /* { dg-note "'a2' declared here" }*/
#pragma omp allocate(a2)
allocator(static_cast<omp_allocator_handle_t>(GOMP_OMPX_PREDEF_ALLOC_MIN - 1))
/* { dg-error "'allocator' clause requires a constant predefined allocator"
"" { target *-*-* } .-1 } */
- /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */
+ /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target *-*-* } .-2 } */
/* { dg-note "expression evaluates to '199'" "" { target *-*-* } .-3 } */
- static int a3 = 42; /* { dg-note "'a3' declared here" "" { xfail *-*-* } }*/
+ static int a3 = 42; /* { dg-note "'a3' declared here" }*/
#pragma omp allocate(a3)
allocator(static_cast<omp_allocator_handle_t>(GOMP_OMPX_PREDEF_ALLOC_MAX + 1))
/* { dg-error "'allocator' clause requires a constant predefined allocator"
"If this test fails because of added predefined allocators please ensure
everything is updated accordingly, see this test case for more information" {
target *-*-* } .-1 } */
- /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */
+ /* { dg-note "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { target *-*-* } .-2 } */
/* { dg-note "expression evaluates to '202'" "" { target *-*-* } .-3 } */
}
-
-/* { dg-bogus "because one or more variables with static storage duration
appear in the 'allocate' directive" "" { xfail c++ } 0 }*/
--
2.54.0