[gcc/devel/omp/gcc-16] OpenMP/C++: Enhance diagnostics of 'omp allocate' directive

Sandra Loosemore via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
https://gcc.gnu.org/g:8e1139958c39419e960c22454d737f83db0d8baf

commit 8e1139958c39419e960c22454d737f83db0d8baf
Author: Waffl3x <[email protected]>
Date:   Tue May 5 09:01:58 2026 -0600

    OpenMP/C++: Enhance diagnostics of 'omp allocate' directive
    
    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-21.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]>

Diff:
---
 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-21.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 +++
 gcc/testsuite/g++.dg/gomp/allocate-handles-1.C |   34 +-
 12 files changed, 2810 insertions(+), 45 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 8ef12516b068..33c5d0d6122e 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -47496,7 +47496,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))
@@ -47505,6 +47529,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)
@@ -47594,6 +47664,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");
@@ -47612,11 +47683,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 66dd2e075877..338c0f556c3c 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
@@ -12659,6 +12660,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] ()
@@ -12715,9 +12772,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)
 	{
@@ -12762,10 +12822,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>%>");
@@ -12908,6 +12970,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 cabd3875d1e2..61d1f7ba4b74 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-21.c b/gcc/testsuite/c-c++-common/gomp/allocate-21.c
new file mode 100644
index 000000000000..604e4847a928
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/allocate-21.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 52bae8c9a6a0..872f7956cddc 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 000000000000..d40288d957d5
--- /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 000000000000..605e10e477f8
--- /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 000000000000..7258d8c1c3cb
--- /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 000000000000..e265ecdd1e74
--- /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 000000000000..3a04bbe8bcd4
--- /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 000000000000..e99106893da4
--- /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 c0c59a30a3c7..786c2f5550e2 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 }*/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.