[05/12] OpenMP/C++: Enhance diagnostics of 'omp allocate' directive

Message ID 20260505151030.1749548-6-waffl3x@baylibre.com
State New
Headers
Series OpenMP/C++: 'allocate' directive |

Commit Message

Waffl3x May 5, 2026, 3:01 p.m. UTC
  Add diagnostics for multiple uses of a var in a single directive, uses of
parameters, vars in a different scope, and vars that are references.

Enhances diagnostics, as well as reporting a proper location in most cases.

gcc/cp/ChangeLog:

	* parser.cc (cp_parser_omp_allocate): Add diagnostics, wrap a
	location into allocator and alignment clause exprs.
	* semantics.cc: Include gcc-rich-location.h.
	(finish_omp_allocate): Improve and add diagnostics.

gcc/testsuite/ChangeLog:

	* c-c++-common/gomp/allocate-9.c: Remove xfails.
	* c-c++-common/gomp/allocate-19.c: Remove xfails.
	* c-c++-common/gomp/allocate-20.c: New test.
	* g++.dg/gomp/allocate-14.C: New test.
	* g++.dg/gomp/allocate-15.C: New test.
	* g++.dg/gomp/allocate-16.C: New test.
	* g++.dg/gomp/allocate-17.C: New test.
	* g++.dg/gomp/allocate-18.C: New test.
	* g++.dg/gomp/allocate-19.C: New test.
	* g++.dg/gomp/allocate-handles-1.C: Remove xfails.

Signed-off-by: Waffl3x <waffl3x@baylibre.com>
---
 gcc/cp/parser.cc                              |   76 +-
 gcc/cp/semantics.cc                           |   76 +-
 gcc/testsuite/c-c++-common/gomp/allocate-19.c |   10 +-
 gcc/testsuite/c-c++-common/gomp/allocate-20.c |  343 ++++++
 gcc/testsuite/c-c++-common/gomp/allocate-9.c  |   30 +-
 gcc/testsuite/g++.dg/gomp/allocate-14.C       | 1042 +++++++++++++++++
 gcc/testsuite/g++.dg/gomp/allocate-15.C       |   50 +
 gcc/testsuite/g++.dg/gomp/allocate-16.C       |  232 ++++
 gcc/testsuite/g++.dg/gomp/allocate-17.C       |  560 +++++++++
 gcc/testsuite/g++.dg/gomp/allocate-18.C       |  274 +++++
 gcc/testsuite/g++.dg/gomp/allocate-19.C       |  128 ++
 .../g++.dg/gomp/allocate-handles-1.C          |   34 +-
 12 files changed, 2810 insertions(+), 45 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/gomp/allocate-20.c
 create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-14.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-15.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-16.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-17.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-18.C
 create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-19.C
  

Patch

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