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


Reply via email to