get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.2/patches/2233047/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2233047,
    "url": "http://patchwork.ozlabs.org/api/1.2/patches/2233047/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260505151030.1749548-6-waffl3x@baylibre.com/",
    "project": {
        "id": 17,
        "url": "http://patchwork.ozlabs.org/api/1.2/projects/17/?format=api",
        "name": "GNU Compiler Collection",
        "link_name": "gcc",
        "list_id": "gcc-patches.gcc.gnu.org",
        "list_email": "gcc-patches@gcc.gnu.org",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260505151030.1749548-6-waffl3x@baylibre.com>",
    "list_archive_url": null,
    "date": "2026-05-05T15:01:58",
    "name": "[05/12] OpenMP/C++: Enhance diagnostics of 'omp allocate' directive",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "c7c8d83631c418107d808c7c0e27c0f6d3b026ba",
    "submitter": {
        "id": 90070,
        "url": "http://patchwork.ozlabs.org/api/1.2/people/90070/?format=api",
        "name": "Waffl3x",
        "email": "waffl3x@baylibre.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260505151030.1749548-6-waffl3x@baylibre.com/mbox/",
    "series": [
        {
            "id": 502853,
            "url": "http://patchwork.ozlabs.org/api/1.2/series/502853/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=502853",
            "date": "2026-05-05T15:01:54",
            "name": "OpenMP/C++: 'allocate' directive",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/502853/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2233047/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2233047/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "gcc-patches@gcc.gnu.org"
        ],
        "Delivered-To": [
            "patchwork-incoming@legolas.ozlabs.org",
            "gcc-patches@gcc.gnu.org"
        ],
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=baylibre-com.20251104.gappssmtp.com\n header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256\n header.s=20251104 header.b=q6XQnOzD;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)",
            "sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=baylibre-com.20251104.gappssmtp.com\n header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256\n header.s=20251104 header.b=q6XQnOzD",
            "sourceware.org;\n dmarc=none (p=none dis=none) header.from=baylibre.com",
            "sourceware.org; spf=pass smtp.mailfrom=baylibre.com",
            "server2.sourceware.org;\n arc=none smtp.remote-ip=2607:f8b0:4864:20::435"
        ],
        "Received": [
            "from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g92BX0kTrz1yJx\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 06 May 2026 01:15:16 +1000 (AEST)",
            "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 001874BA79B9\n\tfor <incoming@patchwork.ozlabs.org>; Tue,  5 May 2026 15:15:13 +0000 (GMT)",
            "from mail-pf1-x435.google.com (mail-pf1-x435.google.com\n [IPv6:2607:f8b0:4864:20::435])\n by sourceware.org (Postfix) with ESMTPS id 605A94BA900F\n for <gcc-patches@gcc.gnu.org>; Tue,  5 May 2026 15:10:43 +0000 (GMT)",
            "by mail-pf1-x435.google.com with SMTP id\n d2e1a72fcca58-835451c5debso112985b3a.2\n for <gcc-patches@gcc.gnu.org>; Tue, 05 May 2026 08:10:43 -0700 (PDT)",
            "from waffl3x-prestige.lan ([2001:56a:f98a:b800:1f67:ce08:3cbd:86b8])\n by smtp.gmail.com with ESMTPSA id\n d2e1a72fcca58-83965645140sm2674956b3a.12.2026.05.05.08.10.40\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Tue, 05 May 2026 08:10:40 -0700 (PDT)"
        ],
        "DKIM-Filter": [
            "OpenDKIM Filter v2.11.0 sourceware.org 001874BA79B9",
            "OpenDKIM Filter v2.11.0 sourceware.org 605A94BA900F"
        ],
        "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 605A94BA900F",
        "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 605A94BA900F",
        "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993843; cv=none;\n b=V/ELmwiH7kLQ08may0R+6nNy2+If9YLeJXHJ7EM7G3TtLXJi/qkqYpn94gJcc9SpVVJrImDA1YiZIDoisgyRLH7/fYDHPGdtX1BiNrZryeO+1mmpy3nO7yZfhYyNN8uBITgdz/HSiJVmmIoCmMK4ssV3CJXyzT69zSTtA9F8G0Q=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1777993843; c=relaxed/simple;\n bh=sF4fV1bDevpXE0R5B1P3u9c74/6q8mKpOtGtykmvCtM=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=Arye+rJ74xqqwXl0XTehlBUs1jsyXXKQepuef6btiDWqH/iSLDRqFdnm55oKaojJIiZyE1vmVTTHYic7OLE5CYR5UE9G+KT79d8/EEo9pyM11/UQmljxMF1grfR8vRV4hz526scRC8+YjUF3devtzGHwG14KxcSQw6rKh3ODq60=",
        "ARC-Authentication-Results": "i=1; server2.sourceware.org",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=baylibre-com.20251104.gappssmtp.com; s=20251104; t=1777993842;\n x=1778598642;\n darn=gcc.gnu.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=gqRopMsDKtwE2JgA2ANfgdHhULzFdSfyUcM770uho5I=;\n b=q6XQnOzDTyACSEKmsS4oG1JUlPDuuAmi+4vP5Jh95OiwNf3tc5JhIkFqZuzR/eHOAi\n Kqr2CCPgGd5UVFhX4YkJSP46Jlp8hD5cht0atKsxDeMHM/MLZHg24KSlZFtihxRE1VTL\n O3Jun5fJ1Xz1tDxlOeljx1txXBeSFOKCwQFSGEKS5yFQYCxQCozXo1E4aZmVGO20dWX0\n Ms00WfhycXkW+HsUh3zW7jfjuWmeJ7h3Rnn45PcxSO40TB5L0AaoSWnEDKQ82Kbl5p+g\n At08gFlzJ4MSuYvmsZtrJmckxIHEP61iGq2bn8t3PLNJh9FIAWH0jyei1JoVor1eoGiD\n EUXA==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1777993842; x=1778598642;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=gqRopMsDKtwE2JgA2ANfgdHhULzFdSfyUcM770uho5I=;\n b=rMs1W+1ElcxhzSPtMYpPbwqQ+9djj4/lWX2U6Gt4orxzIebYb3SGw0I0PSdqLcJrMB\n S40APle9Qezb7MYSJHjNAp1+1ZMsgDgsSvu3W5VZBLfzPnybnlGSCBxjgMo+bvYxWMqB\n YNNhpztPgnGIjEezAcmFIpaX8p5xy3FLzum7YE+6LCI3RCJjMa3W4LaPsUmmr/M5sDz3\n 9XDgr4PP/xV9GcWweWg71rkMkHLLS2zf/0S3IaPDWid7soLTkyKJvQYC3aa4XRh8WUfY\n BjS4pTx7osJZk6C3vJ8T8ccRqZ5A1Xi7nY6QUhpfWuaue74/JHWZgwDgFFBhC9jtNPTc\n DxZw==",
        "X-Gm-Message-State": "AOJu0YwrNjgUk9NYTrTUvN6fl54s4pUVPQEc1nTePdNyvPY7TegdUw84\n XVxxP10VcKUDhF37Z352L1yEvFPsIFbvkz5Jc9Cj+Cokx5wZ449jViYH9EyLo1uf67C+d+AL9J3\n KsIG3",
        "X-Gm-Gg": "AeBDieuEW60AyFxn56BZY2Ns7VWpCs2v3HUTQpDomQHYcBW0u5SBZC256xc0OOOZDcB\n Smgc4mBGQ/WuQjxWY+/CJGnHDv9gQ/qO/XQX2VA2SyM8LMJHdfNmLqWvveUdxBJ5tdtTu9HvfDr\n VeV1dxeDPMmY3koV30G34+oXF8thljqPG+PBZWZL8Bz2wWaRptv/YGZQn2m/Sg9XzTR/ujqH7JD\n AFuD669ICBH+Jt0uszooDPDxxA4GaOzAia7l3184opuO44iI6xXpTAKbNw5sxnnC1ynwTQ0elCm\n aP4/Je1RfZS7uiD+gMLB5Nfp3wyFVK4DtwJ6Cb8y0du+fJuau+sA0PDnaocz4A+QdFSSYzAgcjj\n t8yjgJJmohverpQQw9iS825xN7+Zhewxu9iYe2tm6UqxYy4+PKaTmhn09xqfg8TGJfVoMxxmWTT\n I72zBRrPl2ahtusg0hEvrV8lJrUhcmx238G81+9ZucH8aM+xSXZQ==",
        "X-Received": "by 2002:a05:6a00:e18:b0:82f:6a82:4231 with SMTP id\n d2e1a72fcca58-8352d14842cmr7303425b3a.1.1777993841214;\n Tue, 05 May 2026 08:10:41 -0700 (PDT)",
        "From": "Waffl3x <waffl3x@baylibre.com>",
        "To": "gcc-patches@gcc.gnu.org",
        "Cc": "Waffl3x <waffl3x@baylibre.com>",
        "Subject": "[PATCH 05/12] OpenMP/C++: Enhance diagnostics of 'omp allocate'\n directive",
        "Date": "Tue,  5 May 2026 09:01:58 -0600",
        "Message-ID": "<20260505151030.1749548-6-waffl3x@baylibre.com>",
        "X-Mailer": "git-send-email 2.54.0",
        "In-Reply-To": "<20260505151030.1749548-1-waffl3x@baylibre.com>",
        "References": "\n <CAH+W3Ppbho4pj6W-rWk4mMssrttOjt7aNco-oWW5Sw5f5Yx2GA@mail.gmail.com>\n <20260505151030.1749548-1-waffl3x@baylibre.com>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit",
        "X-BeenThere": "gcc-patches@gcc.gnu.org",
        "X-Mailman-Version": "2.1.30",
        "Precedence": "list",
        "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>",
        "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>",
        "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>",
        "List-Post": "<mailto:gcc-patches@gcc.gnu.org>",
        "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>",
        "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>",
        "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"
    },
    "content": "Add diagnostics for multiple uses of a var in a single directive, uses of\nparameters, vars in a different scope, and vars that are references.\n\nEnhances diagnostics, as well as reporting a proper location in most cases.\n\ngcc/cp/ChangeLog:\n\n\t* parser.cc (cp_parser_omp_allocate): Add diagnostics, wrap a\n\tlocation into allocator and alignment clause exprs.\n\t* semantics.cc: Include gcc-rich-location.h.\n\t(finish_omp_allocate): Improve and add diagnostics.\n\ngcc/testsuite/ChangeLog:\n\n\t* c-c++-common/gomp/allocate-9.c: Remove xfails.\n\t* c-c++-common/gomp/allocate-19.c: Remove xfails.\n\t* c-c++-common/gomp/allocate-20.c: New test.\n\t* g++.dg/gomp/allocate-14.C: New test.\n\t* g++.dg/gomp/allocate-15.C: New test.\n\t* g++.dg/gomp/allocate-16.C: New test.\n\t* g++.dg/gomp/allocate-17.C: New test.\n\t* g++.dg/gomp/allocate-18.C: New test.\n\t* g++.dg/gomp/allocate-19.C: New test.\n\t* g++.dg/gomp/allocate-handles-1.C: Remove xfails.\n\nSigned-off-by: Waffl3x <waffl3x@baylibre.com>\n---\n gcc/cp/parser.cc                              |   76 +-\n gcc/cp/semantics.cc                           |   76 +-\n gcc/testsuite/c-c++-common/gomp/allocate-19.c |   10 +-\n gcc/testsuite/c-c++-common/gomp/allocate-20.c |  343 ++++++\n gcc/testsuite/c-c++-common/gomp/allocate-9.c  |   30 +-\n gcc/testsuite/g++.dg/gomp/allocate-14.C       | 1042 +++++++++++++++++\n gcc/testsuite/g++.dg/gomp/allocate-15.C       |   50 +\n gcc/testsuite/g++.dg/gomp/allocate-16.C       |  232 ++++\n gcc/testsuite/g++.dg/gomp/allocate-17.C       |  560 +++++++++\n gcc/testsuite/g++.dg/gomp/allocate-18.C       |  274 +++++\n gcc/testsuite/g++.dg/gomp/allocate-19.C       |  128 ++\n .../g++.dg/gomp/allocate-handles-1.C          |   34 +-\n 12 files changed, 2810 insertions(+), 45 deletions(-)\n create mode 100644 gcc/testsuite/c-c++-common/gomp/allocate-20.c\n create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-14.C\n create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-15.C\n create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-16.C\n create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-17.C\n create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-18.C\n create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-19.C",
    "diff": "diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc\nindex 2cec22a9386..924e52da6ea 100644\n--- a/gcc/cp/parser.cc\n+++ b/gcc/cp/parser.cc\n@@ -47186,7 +47186,31 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok)\n {\n   tree nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL_TREE);\n \n+  /* Make diagnostics emit in forward order.  */\n+  nl = nreverse (nl);\n+\n+  const tree directive_ctx = current_scope ();\n   {\n+    auto var_is_in_scope = [&] (tree var_decl)\n+      {\n+\t/* (OpenMP 6.0 311:11-12) An allocate directive must appear in the same\n+\t   scope as the declarations of each of its list items and must follow\n+\t   all such declarations.\n+\n+\t   Note that it states declarations, not definitions, thus we can rely\n+\t   on VAR_DECL's CP_DECL_CONTEXT.  This will correctly reject an\n+\t   allocate directive applied to a definition in a different scope.  */\n+\tif (!DECL_DECLARES_FUNCTION_P (directive_ctx))\n+\t  return CP_DECL_CONTEXT (var_decl) == directive_ctx;\n+\t/* This is O(n^2), caching names during traversal might be better.  */\n+\tfor (tree block_var = current_binding_level->names;\n+\t     block_var != NULL_TREE;\n+\t     block_var = DECL_CHAIN (block_var))\n+\t  if (block_var == var_decl)\n+\t    return true;\n+\treturn false;\n+      };\n+    hash_map<tree, location_t> seen_args;\n     /* The head might have an error and need to be removed.  */\n     tree *chain = &nl;\n     for (tree node = nl; node != NULL_TREE; node = TREE_CHAIN (node))\n@@ -47195,6 +47219,52 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok)\n \tconst tree arg_loc_wrapper = TREE_VALUE (node);\n \tconst location_t arg_loc = EXPR_LOCATION (arg_loc_wrapper);\n \n+\tgcc_assert (var && var != error_mark_node);\n+\t/* Diagnose duplicate vars passed to the allocate directive.  */\n+\tif (location_t const *const orig_loc = seen_args.get (var))\n+\t  {\n+\t    auto_diagnostic_group d;\n+\t    /* If we could just get the location of the comma a fixit\n+\t       hint would be viable here.  */\n+\t    error_at (arg_loc,\n+\t\t      \"%qD already appeared as list item in this directive\",\n+\t\t      var);\n+\t    inform (*orig_loc, \"appeared first here\");\n+\t    /* Remove the node.  */\n+\t    *chain = TREE_CHAIN (node);\n+\t    continue;\n+\t  }\n+\tseen_args.put (var, arg_loc);\n+\n+\t/* Diagnose parameters passed to the allocate directive.  */\n+\tif (TREE_CODE (var) == PARM_DECL)\n+\t  {\n+\t    auto_diagnostic_group d;\n+\t    error_at (arg_loc,\n+\t\t      \"function parameter %qD may not appear as list item in \"\n+\t\t      \"an %<allocate%> directive\", var);\n+\t    inform (DECL_SOURCE_LOCATION (var),\n+\t\t    \"parameter %qD declared here\", var);\n+\t    /* Remove the node.  */\n+\t    *chain = TREE_CHAIN (node);\n+\t    continue;\n+\t  }\n+\n+\t/* Do this before checking if the var was used in another allocate\n+\t   directive, as the latter diagnostic implies that removing the var\n+\t   from the previous directive would fix the problem.  */\n+\tif (!var_is_in_scope (var))\n+\t  {\n+\t    auto_diagnostic_group d;\n+\t    error_at (arg_loc,\n+\t\t      \"%<allocate%> directive must be in the same scope as \"\n+\t\t      \"%qD\", var);\n+\t    inform (DECL_SOURCE_LOCATION (var), \"declared here\");\n+\t    /* Remove the node.  */\n+\t    *chain = TREE_CHAIN (node);\n+\t    continue;\n+\t  }\n+\n \ttree attr = lookup_attribute (\"omp allocate\",\n \t\t\t\t      DECL_ATTRIBUTES (var));\n \tif (attr)\n@@ -47284,6 +47354,7 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok)\n       if (!parens.require_open (parser))\n \tbreak;\n       cp_expr expr = cp_parser_assignment_expression (parser);\n+      expr.maybe_add_location_wrapper ();\n       if (p[2] == 'i' && alignment)\n \t{\n \t  error_at (cloc, \"too many %qs clauses\", \"align\");\n@@ -47302,11 +47373,14 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok)\n     } while (true);\n   cp_parser_require_pragma_eol (parser, pragma_tok);\n \n+  /* We can still diagnose some things about allocator/alignment even if nl\n+     is NULL_TREE.  */\n+\n   finish_omp_allocate (pragma_tok->location,\n \t\t       nl,\n \t\t       allocator,\n \t\t       alignment,\n-\t\t       current_scope ());\n+\t\t       directive_ctx);\n }\n \n /* OpenMP 2.5:\ndiff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc\nindex ac81bbe9317..00c09e119c8 100644\n--- a/gcc/cp/semantics.cc\n+++ b/gcc/cp/semantics.cc\n@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3.  If not see\n #include \"gimplify.h\"\n #include \"contracts.h\"\n #include \"c-family/c-pragma.h\"\n+#include \"gcc-rich-location.h\"\n \n /* There routines provide a modular interface to perform many parsing\n    operations.  They may therefore be used during actual parsing, or\n@@ -12393,6 +12394,62 @@ finish_omp_allocate (const location_t loc, const tree var_list,\n     } (); /* IILE.  */\n   const bool any_static_vars = any_of_vars (tree_static_p);\n \n+  /* Create an auto_diagnostic_group before calling this.  */\n+  const auto emit_diag_for_var_group\n+    = [] (const var_predicate pred,\n+\t  void (*diag_fn)(rich_location *, const char *, ...),\n+\t  const char *msg,\n+\t  const const_tree var_list)\n+\t{\n+\t  auto next_match = [&pred] (const_tree first)\n+\t    {\n+\t      const_tree vn = first;\n+\t      for (; vn != NULL_TREE; vn = TREE_CHAIN (vn))\n+\t\tif (TREE_PURPOSE (vn) != error_mark_node\n+\t\t    && pred (TREE_PURPOSE (vn)))\n+\t\t  return vn;\n+\t      return vn;\n+\t    };\n+\t  gcc_assert (var_list != NULL_TREE);\n+\t  const const_tree first_node = next_match (var_list);\n+\t  gcc_assert (first_node != NULL_TREE);\n+\n+\t  gcc_rich_location rich_loc (EXPR_LOCATION (TREE_VALUE (first_node)));\n+\t  /* Don't add another range for the first node.  */\n+\t  for (const_tree vn = next_match (TREE_CHAIN (first_node));\n+\t       vn != NULL_TREE;\n+\t       vn = next_match (TREE_CHAIN (vn)))\n+\t    rich_loc.add_range (EXPR_LOCATION (TREE_VALUE (vn)));\n+\t  diag_fn (&rich_loc, msg);\n+\n+\t  const_tree vn = first_node;\n+\t  for (; vn != NULL_TREE; vn = next_match (TREE_CHAIN (vn)))\n+\t    inform (DECL_SOURCE_LOCATION (TREE_PURPOSE (vn)),\n+\t\t    \"%qD declared here\", TREE_PURPOSE (vn));\n+\t};\n+\n+  /* Defer error marking vars until after other diagnostics are done, we might\n+     still need access to them when diagnosing the allocator clause.  */\n+  hash_set<tree> deferred_erroneous_var_nodes;\n+\n+  const auto ref_var_p\n+    = [] (const_tree t) -> bool { return TYPE_REF_P (TREE_TYPE (t)); };\n+  if (any_of_vars (ref_var_p))\n+    {\n+      auto_diagnostic_group d;\n+      emit_diag_for_var_group (ref_var_p,\n+\t\t\t       &error_at,\n+\t\t\t       G_(\"variables with reference type may not \"\n+\t\t\t\t  \"appear in an %<allocate%> directive\"),\n+\t\t\t       var_list);\n+      for (tree vn = var_list; vn != NULL_TREE; vn = TREE_CHAIN (vn))\n+\t{\n+\t  if (!ref_var_p (TREE_PURPOSE (vn)))\n+\t    continue;\n+\t  deferred_erroneous_var_nodes.add (vn);\n+\t}\n+    }\n+\n   /* (OpenMP 5.2, 174:15) Type: expression of integer type\n \t\t\t  Properties: constant, positive  */\n   const tree align = [&align_in] ()\n@@ -12449,9 +12506,12 @@ finish_omp_allocate (const location_t loc, const tree var_list,\n \t allocator values.  */\n       const auto emit_diag_for_static_vars = [&] ()\n \t{\n-\t  inform (UNKNOWN_LOCATION,\n-\t\t  \"because one or more variables with static storage duration \"\n-\t\t  \"appear in the %<allocate%> directive\");\n+\t  emit_diag_for_var_group (tree_static_p,\n+\t\t\t\t   &inform,\n+\t\t\t\t   G_(\"because one or more variables with \"\n+\t\t\t\t      \"static storage duration appear \"\n+\t\t\t\t      \"in the %<allocate%> directive\"),\n+\t\t\t\t   var_list);\n \t};\n       if (alloc_in == NULL_TREE)\n \t{\n@@ -12496,10 +12556,12 @@ finish_omp_allocate (const location_t loc, const tree var_list,\n \t\t  return cached_alloc_type;\n \t\t}\n \t      auto_diagnostic_group d;\n-\t      error_at (EXPR_LOCATION (alloc_in),\n+\t      gcc_rich_location loc (EXPR_LOCATION (alloc_in));\n+\t      maybe_add_include_fixit (&loc, \"<omp.h>\", false);\n+\t      error_at (&loc,\n \t\t\t\"%<allocator%> clause requires a valid declaration \"\n \t\t\t\"of %<omp_allocator_handle_t%>\");\n-\t      inform (EXPR_LOCATION (alloc_in),\n+\t      inform (&loc,\n \t\t      \"%<omp_allocator_handle_t%> is defined in header \"\n \t\t      \"%<<omp.h>%>; this is probably fixable by adding \"\n \t\t      \"%<#include <omp.h>%>\");\n@@ -12642,6 +12704,10 @@ finish_omp_allocate (const location_t loc, const tree var_list,\n       TREE_PURPOSE (node) = error_mark_node;\n     };\n \n+  for (tree vn = var_list; vn != NULL_TREE; vn = TREE_CHAIN (vn))\n+    if (deferred_erroneous_var_nodes.contains (vn))\n+      finalize_var_node_with_error (vn);\n+\n   /* Even if there have been errors, save the current state, there might be\n      more to diagnose on a later instantiation.  */\n   if (processing_template_decl)\ndiff --git a/gcc/testsuite/c-c++-common/gomp/allocate-19.c b/gcc/testsuite/c-c++-common/gomp/allocate-19.c\nindex cabd3875d1e..61d1f7ba4b7 100644\n--- a/gcc/testsuite/c-c++-common/gomp/allocate-19.c\n+++ b/gcc/testsuite/c-c++-common/gomp/allocate-19.c\n@@ -56,19 +56,17 @@ get ()\n   return &A1[q];\n }\n \n-static int invalid1, okay1, invalid2, invalid3; /* { dg-note \"'invalid\\[123\\]' declared here\" \"\" { target c++ xfail c++ } } */\n+static int invalid1, okay1, invalid2, invalid3; /* { dg-note \"'invalid\\[123\\]' declared here\" \"\" { target c++ } } */\n #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 } }  */\n /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { target c++ } .-1 } */\n-/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ xfail c++ } .-2 } */\n+/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ } .-2 } */\n /* { dg-note \"expression evaluates to '9'\" \"\" { target c++ } .-3 } */\n #pragma omp allocate(okay1) align(128) allocator(ompx_gnu_pinned_mem_alloc)  /* Okay */\n #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 } }  */\n /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { target c++ } .-1 } */\n-/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ xfail c++ } .-2 } */\n+/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ } .-2 } */\n /* { dg-note \"expression evaluates to '199'\" \"\" { target c++ } .-3 } */\n #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 } }  */\n /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { target c++ } .-1 } */\n-/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ xfail c++ } .-2 } */\n+/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ } .-2 } */\n /* { dg-note \"expression evaluates to '2001'\" \"\" { target c++ } .-3 } */\n-\n-/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ } 0 } */\ndiff --git a/gcc/testsuite/c-c++-common/gomp/allocate-20.c b/gcc/testsuite/c-c++-common/gomp/allocate-20.c\nnew file mode 100644\nindex 00000000000..604e4847a92\n--- /dev/null\n+++ b/gcc/testsuite/c-c++-common/gomp/allocate-20.c\n@@ -0,0 +1,343 @@\n+#include \"allocate-allocator-handle.h\"\n+\n+#pragma omp allocate() allocator(omp_default_mem_alloc)\n+/* { dg-error \"expected identifier before '\\\\\\)' token\" \"\" { target c } .-1 } */\n+/* { dg-error \"expected unqualified-id before '\\\\\\)' token\" \"\" { target c++ } .-2 } */\n+\n+/* The following tests are broken up into multiple lines to verify they refer\n+   to the correct use of the variable, this seems to be the easiest way.\n+   C does not currently refer to the correct line.  */\n+int g;\n+/* { dg-error \"'g' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+#pragma omp allocate(\\\n+g,\\\n+g,\\\n+g,\\\n+g,\\\n+g) allocator(omp_default_mem_alloc)\n+/* { dg-note \"appeared first here\" \"\" { target c++ } .-5 } */\n+/* { dg-error \"'g' already appeared as list item in this directive\" \"\" { target c++ } .-5 } */\n+/* { dg-error \"'g' already appeared as list item in this directive\" \"\" { target c++ } .-5 } */\n+/* { dg-error \"'g' already appeared as list item in this directive\" \"\" { target c++ } .-5 } */\n+/* { dg-error \"'g' already appeared as list item in this directive\" \"\" { target c++ } .-5 } */\n+\n+int g0_0;\n+int g0_1;\n+/* { dg-error \"'g0_0' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+#pragma omp allocate(\\\n+g0_0,\\\n+g0_1,\\\n+g0_0,\\\n+g0_0) allocator(omp_default_mem_alloc)\n+/* { dg-note \"appeared first here\" \"\" { target c++ } .-4 } */\n+/* { dg-error \"'g0_0' already appeared as list item in this directive\" \"\" { target c++ } .-3 } */\n+/* { dg-error \"'g0_0' already appeared as list item in this directive\" \"\" { target c++ } .-3 } */\n+\n+int g1_0;\n+int g1_1;\n+/* { dg-error \"'g1_0' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+2 } */\n+/* { dg-error \"'g1_1' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+#pragma omp allocate(\\\n+g1_1,\\\n+g1_0,\\\n+g1_1,\\\n+g1_0,\\\n+g1_0,\\\n+g1_1) allocator(omp_default_mem_alloc)\n+/* { dg-note \"appeared first here\" \"\" { target c++ } .-6 } */\n+/* { dg-note \"appeared first here\" \"\" { target c++ } .-6 } */\n+/* { dg-error \"'g1_1' already appeared as list item in this directive\" \"\" { target c++ } .-6 } */\n+/* { dg-error \"'g1_0' already appeared as list item in this directive\" \"\" { target c++ } .-6 } */\n+/* { dg-error \"'g1_0' already appeared as list item in this directive\" \"\" { target c++ } .-6 } */\n+/* { dg-error \"'g1_1' already appeared as list item in this directive\" \"\" { target c++ } .-6 } */\n+\n+void f()\n+{\n+  int v;\n+  /* { dg-error \"'v' already appeared as list item in an 'allocate' directive\" \"\" { target c} .+1 } */\n+  #pragma omp allocate(\\\n+  v,\\\n+  v,\\\n+  v,\\\n+  v,\\\n+  v)\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-5 } */\n+  /* { dg-error \"'v' already appeared as list item in this directive\" \"\" { target c++ } .-5 } */\n+  /* { dg-error \"'v' already appeared as list item in this directive\" \"\" { target c++ } .-5 } */\n+  /* { dg-error \"'v' already appeared as list item in this directive\" \"\" { target c++ } .-5 } */\n+  /* { dg-error \"'v' already appeared as list item in this directive\" \"\" { target c++ } .-5 } */\n+\n+  int v0_0;\n+  int v0_1;\n+  /* { dg-error \"'v0_0' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+  #pragma omp allocate(\\\n+  v0_0,\\\n+  v0_1,\\\n+  v0_0,\\\n+  v0_0)\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-4 } */\n+  /* { dg-error \"'v0_0' already appeared as list item in this directive\" \"\" { target c++ } .-3 } */\n+  /* { dg-error \"'v0_0' already appeared as list item in this directive\" \"\" { target c++ } .-3 } */\n+\n+  int v1_0;\n+  int v1_1;\n+  /* { dg-error \"'v1_0' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+2 } */\n+  /* { dg-error \"'v1_1' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+  #pragma omp allocate(\\\n+  v1_1,\\\n+  v1_0,\\\n+  v1_1,\\\n+  v1_0,\\\n+  v1_0,\\\n+  v1_1)\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-6 } */\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-6 } */\n+  /* { dg-error \"'v1_1' already appeared as list item in this directive\" \"\" { target c++ } .-6 } */\n+  /* { dg-error \"'v1_0' already appeared as list item in this directive\" \"\" { target c++ } .-6 } */\n+  /* { dg-error \"'v1_0' already appeared as list item in this directive\" \"\" { target c++ } .-6 } */\n+  /* { dg-error \"'v1_1' already appeared as list item in this directive\" \"\" { target c++ } .-6 } */\n+}\n+\n+void f_with_parm(int p) /* { dg-note \"parameter 'p' declared here\" \"\" { target c++ } } */\n+{\n+  #pragma omp allocate(p)\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+  #pragma omp allocate(\\\n+  p,\\\n+  p,\\\n+  p)\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c++ } .-3 } */\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-4 } */\n+  /* { dg-error \"'p' already appeared as list item in this directive\" \"\" { target c++ } .-4 } */\n+  /* { dg-error \"'p' already appeared as list item in this directive\" \"\" { target c++ } .-4 } */\n+\n+  int v;\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c } .+2 } */\n+  /* { dg-error \"'v' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+  #pragma omp allocate(\\\n+  v,\\\n+  p,\\\n+  v,\\\n+  v,\\\n+  p,\\\n+  v,\\\n+  v)\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-7 } */\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c++ } .-7 } */\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-8 } */\n+  /* { dg-error \"'v' already appeared as list item in this directive\" \"\" { target c++ } .-8 } */\n+  /* { dg-error \"'v' already appeared as list item in this directive\" \"\" { target c++ } .-8 } */\n+  /* { dg-error \"'p' already appeared as list item in this directive\" \"\" { target c++ } .-8 } */\n+  /* { dg-error \"'v' already appeared as list item in this directive\" \"\" { target c++ } .-8 } */\n+  /* { dg-error \"'v' already appeared as list item in this directive\" \"\" { target c++ } .-8 } */\n+\n+  int v0_0;\n+  int v0_1;\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c } .+2 } */\n+  /* { dg-error \"'v0_0' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+  #pragma omp allocate(\\\n+  p,\\\n+  v0_0,\\\n+  v0_1,\\\n+  v0_0,\\\n+  v0_0)\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c++ } .-5 } */\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-5 } */\n+  /* { dg-error \"'v0_0' already appeared as list item in this directive\" \"\" { target c++ } .-4 } */\n+  /* { dg-error \"'v0_0' already appeared as list item in this directive\" \"\" { target c++ } .-4 } */\n+\n+  int v1_0;\n+  int v1_1;\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c } .+3 } */\n+  /* { dg-error \"'v1_0' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+2 } */\n+  /* { dg-error \"'v1_1' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+  #pragma omp allocate(\\\n+  v1_1,\\\n+  p,\\\n+  v1_0,\\\n+  v1_1,\\\n+  v1_0,\\\n+  p,\\\n+  v1_0,\\\n+  v1_1,\\\n+  p)\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-9 } */\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c++ } .-9 } */\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-10 } */\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-10 } */\n+  /* { dg-error \"'v1_1' already appeared as list item in this directive\" \"\" { target c++ } .-10 } */\n+  /* { dg-error \"'v1_0' already appeared as list item in this directive\" \"\" { target c++ } .-10 } */\n+  /* { dg-error \"'p' already appeared as list item in this directive\" \"\" { target c++ } .-10 } */\n+  /* { dg-error \"'v1_0' already appeared as list item in this directive\" \"\" { target c++ } .-10 } */\n+  /* { dg-error \"'v1_1' already appeared as list item in this directive\" \"\" { target c++ } .-10 } */\n+  /* { dg-error \"'p' already appeared as list item in this directive\" \"\" { target c++ } .-10 } */\n+}\n+\n+/* Valid var used in allocator clause diagnostics.\n+   (No diagnostic should be emitted related to 'alloc')  */\n+\n+void f_with_parm_and_allocator0(int p) /* { dg-note \"parameter 'p' declared here\" \"\" { target c++ } } */\n+{\n+  omp_allocator_handle_t alloc = omp_default_mem_alloc;\n+  #pragma omp allocate(p) allocator(alloc)\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+  #pragma omp allocate(\\\n+  p,\\\n+  p,\\\n+  p) allocator(alloc)\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c++ } .-3 } */\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-4 } */\n+  /* { dg-error \"'p' already appeared as list item in this directive\" \"\" { target c++ } .-4 } */\n+  /* { dg-error \"'p' already appeared as list item in this directive\" \"\" { target c++ } .-4 } */\n+\n+  int v;\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c } .+2 } */\n+  /* { dg-error \"'v' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+  #pragma omp allocate(\\\n+  v,\\\n+  p,\\\n+  v,\\\n+  v,\\\n+  p,\\\n+  v,\\\n+  v) allocator(alloc)\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-7 } */\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c++ } .-7 } */\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-8 } */\n+  /* { dg-error \"'v' already appeared as list item in this directive\" \"\" { target c++ } .-8 } */\n+  /* { dg-error \"'v' already appeared as list item in this directive\" \"\" { target c++ } .-8 } */\n+  /* { dg-error \"'p' already appeared as list item in this directive\" \"\" { target c++ } .-8 } */\n+  /* { dg-error \"'v' already appeared as list item in this directive\" \"\" { target c++ } .-8 } */\n+  /* { dg-error \"'v' already appeared as list item in this directive\" \"\" { target c++ } .-8 } */\n+\n+  int v0_0;\n+  int v0_1;\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c } .+2 } */\n+  /* { dg-error \"'v0_0' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+  #pragma omp allocate(\\\n+  p,\\\n+  v0_0,\\\n+  v0_1,\\\n+  v0_0,\\\n+  v0_0) allocator(alloc)\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c++ } .-5 } */\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-5 } */\n+  /* { dg-error \"'v0_0' already appeared as list item in this directive\" \"\" { target c++ } .-4 } */\n+  /* { dg-error \"'v0_0' already appeared as list item in this directive\" \"\" { target c++ } .-4 } */\n+\n+  int v1_0;\n+  int v1_1;\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c } .+3 } */\n+  /* { dg-error \"'v1_0' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+2 } */\n+  /* { dg-error \"'v1_1' already appeared as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+  #pragma omp allocate(\\\n+  v1_1,\\\n+  p,\\\n+  v1_0,\\\n+  v1_1,\\\n+  v1_0,\\\n+  p,\\\n+  v1_0,\\\n+  v1_1,\\\n+  p) allocator(alloc)\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-9 } */\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c++ } .-9 } */\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-10 } */\n+  /* { dg-note \"appeared first here\" \"\" { target c++ } .-10 } */\n+  /* { dg-error \"'v1_1' already appeared as list item in this directive\" \"\" { target c++ } .-10 } */\n+  /* { dg-error \"'v1_0' already appeared as list item in this directive\" \"\" { target c++ } .-10 } */\n+  /* { dg-error \"'p' already appeared as list item in this directive\" \"\" { target c++ } .-10 } */\n+  /* { dg-error \"'v1_0' already appeared as list item in this directive\" \"\" { target c++ } .-10 } */\n+  /* { dg-error \"'v1_1' already appeared as list item in this directive\" \"\" { target c++ } .-10 } */\n+  /* { dg-error \"'p' already appeared as list item in this directive\" \"\" { target c++ } .-10 } */\n+}\n+\n+/* Var used in allocator clause diagnostics.  Tests that invalid vars passed\n+   into the allocate directive are not considered and bogus/repeat diagnostics\n+   are not emitted.  */\n+\n+void f_with_parm_and_allocator1(int p) /* { dg-note \"parameter 'p' declared here\" \"\" { target c++ } } */\n+{\n+  int v0; /* { dg-note \"to be allocated variable declared here\" \"\" { xfail c++ } } */\n+  omp_allocator_handle_t alloc0 = omp_default_mem_alloc; /* { dg-note \"declared here\" \"\" { xfail c++ } } */\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c } .+2 } */\n+  /* { dg-error \"variable 'alloc0' used in the 'allocator' clause must be declared before 'v0'\" \"\" { target c } .+1 } */\n+  #pragma omp allocate(\\\n+  p,\\\n+  v0)\\\n+  allocator(alloc0)\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c++ } .-3 } */\n+  /* { dg-error \"variable 'alloc0' used in the 'allocator' clause must be declared before 'v0'\" \"\" { target c++ xfail c++ } .-2 } */\n+\n+  int v1; /* { dg-note \"declared here\" } */\n+  {\n+    omp_allocator_handle_t alloc1 = omp_default_mem_alloc;\n+    int v2;\n+    /* { dg-error \"'allocate' directive must be in the same scope as 'v1'\" \"\" { target c } .+1 } */\n+    #pragma omp allocate(\\\n+    v1,\\\n+    v2\\\n+    ) allocator(alloc1)\n+    /* { dg-error \"'allocate' directive must be in the same scope as 'v1'\" \"\" { target c++ } .-3 } */\n+  }\n+  {\n+    int v3; /* { dg-note \"to be allocated variable declared here\" \"\" { xfail c++ } } */\n+    omp_allocator_handle_t alloc2 = omp_default_mem_alloc; /* { dg-note \"declared here\" \"\" { xfail c++ } } */\n+    /* { dg-error \"variable 'alloc2' used in the 'allocator' clause must be declared before 'v3'\" \"\" { target c } .+2 } */\n+    /* { dg-error \"'allocate' directive must be in the same scope as 'v1'\" \"\" { target c } .+1 } */\n+    #pragma omp allocate(\\\n+    v1,\\\n+    v3\\\n+    ) allocator(alloc2)\n+    /* { dg-error \"'allocate' directive must be in the same scope as 'v1'\" \"\" { target c++ } .-3 } */\n+    /* { dg-error \"variable 'alloc2' used in the 'allocator' clause must be declared before 'v3'\" \"\" { target c++ xfail c++ } .-2 } */\n+  }\n+}\n+\n+/* First argument valid.\n+   These cases could still be fleshed out a bit more, there was original a typo\n+   that caused diagnostics to always refer to the first argument of the\n+   directive in the C++ front end, these tests are for that case.  */\n+\n+void first_valid0()\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    int v;\n+    /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" \"\" { target c } .+1 } */\n+    #pragma omp allocate(\\\n+    v,\\\n+    a) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" \"\" { target c++ } } */\n+  }\n+}\n+\n+void first_valid1(int p) /* { dg-note \"parameter 'p' declared here\" \"\" { target c++ } } */\n+{\n+  int v;\n+  /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+  #pragma omp allocate(\\\n+  v,\\\n+  p) /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c++ } } */\n+}\n+\n+void first_valid2(int p) /* { dg-note \"parameter 'p' declared here\" \"\" { target c++ } } */\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    int v;\n+    /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" \"\" { target c } .+2 } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c } .+1 } */\n+    #pragma omp allocate(\\\n+    v,\\\n+    a,\\\n+    p)\n+    /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" \"\" { target c++ } .-2 } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target c++ } .-2 } */\n+  }\n+}\n+\n+/* Missing cases that contain undeclared variables.  */\ndiff --git a/gcc/testsuite/c-c++-common/gomp/allocate-9.c b/gcc/testsuite/c-c++-common/gomp/allocate-9.c\nindex 52bae8c9a6a..872f7956cdd 100644\n--- a/gcc/testsuite/c-c++-common/gomp/allocate-9.c\n+++ b/gcc/testsuite/c-c++-common/gomp/allocate-9.c\n@@ -5,7 +5,7 @@ static int A2[5] = {1,2,3,4,5};\n static int A3[5] = {1,2,3,4,5};\n static int A4[5] = {1,2,3,4,5}; /* { dg-line A4_decl } */\n static int A5[5] = {1,2,3,4,5}; /* { dg-line A5_decl } */\n-int B, C, C2, D; /* { dg-note \"declared here\" \"\" { xfail c++ } } */\n+int B, C, C2, D; /* { dg-note \"declared here\" } */\n \n /* If the following fails because of added predefined allocators, please update\n    - include/gomp-constants.h's GOMP_OMP_PREDEF_ALLOC_MAX or GOMP_OMPX_PREDEF_ALLOC_MAX\n@@ -18,9 +18,9 @@ int B, C, C2, D; /* { dg-note \"declared here\" \"\" { xfail c++ } } */\n #pragma omp allocate(A1) align(32) allocator((omp_allocator_handle_t) 9)\n /* { dg-error \"'allocator' clause requires a predefined allocator as 'A1' is static\" \"\" { target c } .-1 } */\n /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { target c++ } .-2 } */\n-/* { dg-message \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ xfail c++ } .-3 } */\n+/* { dg-message \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ } .-3 } */\n /* { dg-message \"expression evaluates to '9'\" \"\" { target c++ } .-4 } */\n-/* { dg-note \"'A1' declared here\" \"\" { target c++ xfail c++ } A_decl } */\n+/* { dg-note \"'A1' declared here\" \"\" { target c++ } A_decl } */\n // typo in allocator name:\n #pragma omp allocate(A2) allocator(omp_low_latency_mem_alloc)\n /* { dg-error \"'omp_low_latency_mem_alloc' undeclared here \\\\(not in a function\\\\); did you mean 'omp_low_lat_mem_alloc'\\\\?\" \"\" { target c } .-1 } */\n@@ -35,8 +35,8 @@ int B, C, C2, D; /* { dg-note \"declared here\" \"\" { xfail c++ } } */\n #pragma omp allocate(A4) align(32)\n /* { dg-error \"'allocator' clause required for static variable 'A4'\" \"\" { target c } .-1 } */\n /* { dg-error \"'allocator' clause must be specified\" \"\" { target c++ } .-2 } */\n-/* { dg-message \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ xfail c++ } .-3 } */\n-/* { dg-note \"'A4' declared here\" \"\" { target c++ xfail c++ } A4_decl } */\n+/* { dg-message \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ } .-3 } */\n+/* { dg-note \"'A4' declared here\" \"\" { target c++ } A4_decl } */\n \n /* \"expression in the clause must be a constant expression that evaluates to one of the\n    predefined memory allocator values -> omp_low_lat_mem_alloc\"  */\n@@ -49,9 +49,9 @@ int B, C, C2, D; /* { dg-note \"declared here\" \"\" { xfail c++ } } */\n #pragma omp allocate(A5) align(32) allocator(omp_null_allocator)\n /* { dg-error \"'allocator' clause requires a predefined allocator as 'A5' is static\" \"\" { target c } .-1 } */\n /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { target c++ } .-2 } */\n-/* { dg-message \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ xfail c++ } .-3 } */\n+/* { dg-message \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ } .-3 } */\n /* { dg-message \"expression evaluates to '0'\" \"\" { target c++ } .-4 } */\n-/* { dg-note \"'A5' declared here\" \"\" { target c++ xfail c++ } A5_decl } */\n+/* { dg-note \"'A5' declared here\" \"\" { target c++ } A5_decl } */\n \n #pragma omp allocate(C2) align(32) allocator(omp_large_cap_mem_alloc)\n \n@@ -59,7 +59,7 @@ int B, C, C2, D; /* { dg-note \"declared here\" \"\" { xfail c++ } } */\n // allocate directive in same TU\n int f()\n {\n-  #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++ } } */\n+  #pragma omp allocate(D) align(32) allocator(omp_large_cap_mem_alloc) /* { dg-error \"'allocate' directive must be in the same scope as 'D'\" } */\n   return A1[0];\n }\n \n@@ -71,29 +71,29 @@ int g()\n /* { dg-note \"'a2' previously appeared here\" \"\" { target c++ } .-2 } */\n   {\n     int c2=3;\n-    #pragma omp allocate(c2, b2) /* { dg-error \"'allocate' directive must be in the same scope as 'b2'\" \"\" { xfail c++ } } */\n-/* { dg-note \"declared here\" \"\" { target *-*-* xfail c++ } g_a2_b2_decl } */\n+    #pragma omp allocate(c2, b2) /* { dg-error \"'allocate' directive must be in the same scope as 'b2'\" } */\n+/* { dg-note \"declared here\" \"\" { target *-*-* } g_a2_b2_decl } */\n     return c2+a2+b2;\n   }\n }\n \n int h(int q)\n {\n-  #pragma omp allocate(q)  /* { dg-error \"function parameter 'q' may not appear as list item in an 'allocate' directive\" \"\" { xfail c++ } } */\n-/* { dg-note \"parameter 'q' declared here\" \"\" { target c++ xfail c++ } .-3 } */\n+  #pragma omp allocate(q)  /* { dg-error \"function parameter 'q' may not appear as list item in an 'allocate' directive\" } */\n+/* { dg-note \"parameter 'q' declared here\" \"\" { target c++ } .-3 } */\n   return q;\n }\n \n int\n k ()\n {\n-  static int var3 = 8; /* { dg-note \"'var3' declared here\" \"\" { target c++ xfail c++ } } */\n+  static int var3 = 8; /* { dg-note \"'var3' declared here\" \"\" { target c++ } } */\n   #pragma omp allocate(var3) allocator((omp_allocator_handle_t)-1L)\n   /* { dg-error \"'allocator' clause requires a predefined allocator as 'var3' is static\" \"\" { target c } .-1 } */\n   /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { target c++ } .-2 } */\n-  /* { dg-message \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ xfail c++ } .-3 } */\n+  /* { dg-message \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target c++ } .-3 } */\n   /* { dg-message \"expression evaluates to '\\\\d+'\" \"\" { target c++ } .-4 } */\n   return var3;\n }\n \n-/* { dg-bogus \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail c++ } 0 } */\n+/* { dg-bogus \"because one or more variables with static storage duration appear in the 'allocate' directive\" 0 } */\ndiff --git a/gcc/testsuite/g++.dg/gomp/allocate-14.C b/gcc/testsuite/g++.dg/gomp/allocate-14.C\nnew file mode 100644\nindex 00000000000..d40288d957d\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/gomp/allocate-14.C\n@@ -0,0 +1,1042 @@\n+#include \"allocate-allocator-handle.h\"\n+\n+/* Diagnostics for invalid cases, including a number of negative cases that\n+   should not be diagnosed.  */\n+\n+/****************************************************\n+ * Reference variable used in an allocate directive *\n+ ****************************************************/\n+\n+void ref_var()\n+{\n+  int a = 42;\n+  int& ref = a; /* { dg-note \"'ref' declared here\" } */\n+  #pragma omp allocate(ref) /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" } */\n+}\n+\n+template<typename>\n+void ref_var_templ_not_instantiated()\n+{\n+  int a = 42;\n+  int& ref = a; /* { dg-note \"'ref' declared here\" } */\n+  #pragma omp allocate(ref) /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" } */\n+}\n+\n+template<typename T>\n+void dependent_ref_var_templ_not_instantiated()\n+{\n+  T a = 42;\n+  T& t = a; /* { dg-note \"'t' declared here\" } */\n+  #pragma omp allocate(t) /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" } */\n+}\n+\n+template<typename T>\n+void dependent_var_templ_not_instantiated()\n+{\n+  T t = 42;\n+  #pragma omp allocate(t)\n+}\n+\n+template<typename T>\n+void dependent_var_templ_0()\n+{\n+  T t = 42;\n+  #pragma omp allocate(t)\n+}\n+\n+template<typename T>\n+void dependent_var_templ_1()\n+{\n+  T t = 42; /* { dg-note \"'t' declared here\" } */\n+  #pragma omp allocate(t) /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" } */\n+}\n+\n+template<typename T>\n+void dependent_var_templ_2()\n+{\n+  int a;\n+  T t = a; /* { dg-note \"'t' declared here\" } */\n+  #pragma omp allocate(t) /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" } */\n+}\n+\n+void instantiate_var_templ()\n+{\n+  dependent_var_templ_0<int>(); /* { dg-bogus \"required from here\" } */\n+  dependent_var_templ_1<int>(); /* { dg-bogus \"required from here\" } */\n+  dependent_var_templ_1<int const&>(); /* { dg-message \"required from here\" } */\n+  dependent_var_templ_2<int>(); /* { dg-bogus \"required from here\" } */\n+  dependent_var_templ_2<int&>(); /* { dg-message \"required from here\" } */\n+  dependent_var_templ_2<int const&>(); /* { dg-message \"required from here\" } */\n+}\n+\n+\n+/****************************\n+ * Invalid allocator clause *\n+ ****************************/\n+\n+template<omp_allocator_handle_t Alloc>\n+void nttp_allocator()\n+{\n+  int a;\n+  #pragma omp allocate(a) allocator(Alloc)\n+}\n+\n+template<omp_allocator_handle_t Alloc>\n+void nttp_allocator_uninstantiated()\n+{\n+  int a;\n+  #pragma omp allocate(a) allocator(Alloc)\n+}\n+\n+template<int Alloc>\n+void nttp_wrong_type_allocator_uninstantiated()\n+{\n+  int a;\n+  #pragma omp allocate(a) allocator(Alloc) /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" \"\" { xfail *-*-* } } */\n+}\n+\n+template<typename AllocT, AllocT Alloc>\n+void nttp_dependent_type_allocator()\n+{\n+  int a;\n+  #pragma omp allocate(a) allocator(Alloc) /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" } */\n+}\n+\n+template<typename AllocT, AllocT Alloc>\n+void nttp_dependent_type_allocator_uninstantiated()\n+{\n+  int a;\n+  #pragma omp allocate(a) allocator(Alloc)\n+}\n+\n+void instantiate_nttp_allocator()\n+{\n+  nttp_allocator<omp_default_mem_alloc>(); /* { dg-bogus \"required from here\" } */\n+  nttp_dependent_type_allocator<omp_allocator_handle_t, omp_default_mem_alloc>(); /* { dg-bogus \"required from here\" } */\n+  nttp_dependent_type_allocator<int, 5>(); /* { dg-message \"required from here\" } */\n+}\n+\n+template<omp_allocator_handle_t Alloc>\n+void nttp_allocator_static()\n+{\n+  static int a; /* { dg-note \"'a' declared here\" } */\n+  #pragma omp allocate(a) allocator(Alloc)\n+  /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { xfail *-*-* } .-1 } */\n+  /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target *-*-* } .-2 } */\n+  /* { dg-note \"expression evaluates to '1024'\" \"\" { xfail *-*-* } .-3 }*/\n+}\n+\n+template<omp_allocator_handle_t Alloc>\n+void nttp_allocator_uninstantiated_static()\n+{\n+  static int a;\n+  #pragma omp allocate(a) allocator(Alloc)\n+}\n+\n+template<int Alloc>\n+void nttp_wrong_type_allocator_uninstantiated_static()\n+{\n+  static int a;\n+  #pragma omp allocate(a) allocator(Alloc) /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" \"\" { xfail *-*-* } } */\n+}\n+\n+template<typename AllocT, AllocT Alloc>\n+void nttp_dependent_type_allocator_static_0()\n+{\n+  static int a; /* { dg-note \"'a' declared here\" } */\n+  #pragma omp allocate(a) allocator(Alloc)\n+  /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { xfail *-*-* } .-1 } */\n+  /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target *-*-* } .-2 } */\n+  /* { dg-note \"expression evaluates to '1024'\" \"\" { xfail *-*-* } .-3 }*/\n+}\n+\n+template<typename AllocT, AllocT Alloc>\n+void nttp_dependent_type_allocator_static_1()\n+{\n+  static int a;\n+  #pragma omp allocate(a) allocator(Alloc) /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" } */\n+}\n+\n+template<typename AllocT, AllocT Alloc>\n+void nttp_dependent_type_allocator_uninstantiated_static()\n+{\n+  static int a;\n+  #pragma omp allocate(a) allocator(Alloc)\n+}\n+\n+#define DEFINITELY_NOT_PREDEFINED static_cast<omp_allocator_handle_t>(1024)\n+\n+void instantiate_nttp_allocator_static()\n+{\n+  nttp_allocator_static<omp_default_mem_alloc>(); /* { dg-bogus \"required from here\" } */\n+  nttp_allocator_static<DEFINITELY_NOT_PREDEFINED>(); /* { dg-message \"required from here\" } */\n+  nttp_dependent_type_allocator_static_0<omp_allocator_handle_t, omp_default_mem_alloc>(); /* { dg-bogus \"required from here\" } */\n+  nttp_dependent_type_allocator_static_0<omp_allocator_handle_t, DEFINITELY_NOT_PREDEFINED>(); /* { dg-message \"required from here\" } */\n+  nttp_dependent_type_allocator_static_1<int, 1>(); /* { dg-message \"required from here\" } */\n+}\n+\n+#undef DEFINITELY_NOT_PREDEFINED\n+\n+\n+template<typename AllocT>\n+void templ_allocator_param_0(AllocT alloc)\n+{\n+  int a;\n+  #pragma omp allocate(a) allocator(alloc)\n+}\n+\n+template<typename AllocT>\n+void templ_allocator_param_1(AllocT alloc)\n+{\n+  int a;\n+  #pragma omp allocate(a) allocator(alloc) /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" } */\n+}\n+\n+template<typename AllocT>\n+void templ_allocator_param_uninstantiated(AllocT alloc)\n+{\n+  int a;\n+  #pragma omp allocate(a) allocator(alloc)\n+}\n+\n+void instantiate_templ_allocator_param()\n+{\n+  templ_allocator_param_0(omp_default_mem_alloc); /* { dg-bogus \"required from here\" } */\n+  templ_allocator_param_1(omp_default_mem_alloc); /* { dg-bogus \"required from here\" } */\n+  templ_allocator_param_1(0); /* { dg-message \"required from here\" } */\n+}\n+\n+\n+template<typename>\n+void missing_allocator_clause_uninstantiated()\n+{\n+  static int a; /* { dg-note \"'a' declared here\" } */\n+  #pragma omp allocate(a)\n+  /* { dg-error \"'allocator' clause must be specified\" \"\" { target *-*-* } .-1 } */\n+  /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target *-*-* } .-2 }*/\n+}\n+\n+/* Cases that are never constant omp_allocator_handle_t expressions (and are required to be) */\n+\n+template<typename>\n+void allocator_param_static_uninstantiated(omp_allocator_handle_t alloc)\n+{\n+  static int a; /* { dg-note \"'a' declared here\" \"\" { xfail *-*-* } } */\n+  #pragma omp allocate(a) allocator(alloc)\n+  /* { dg-error \"'alloc' is not a constant expression\" \"\" { xfail *-*-* } .-1 }*/\n+  /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { xfail *-*-* } .-2 } */\n+  /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail *-*-* } .-3 }*/\n+}\n+\n+template<typename>\n+void allocator_var_static_uninstantiated()\n+{\n+  omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note \"'omp_allocator_handle_t alloc' is not const\" \"\" { xfail *-*-* } } */\n+  static int a; /* { dg-note \"'a' declared here\" \"\" { xfail *-*-* } } */\n+  #pragma omp allocate(a) allocator(alloc)\n+  /* { dg-error \"the value of 'alloc' is not usable in a constant expression\" \"\" { xfail *-*-* } .-1 }*/\n+  /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { xfail *-*-* } .-2 } */\n+  /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail *-*-* } .-3 }*/\n+}\n+\n+/* While weird, there are inputs for AllocT that are well-formed here,\n+   therefore these cases can not be diagnosed until instantiation.  */\n+\n+template<typename AllocT>\n+void templ_allocator_param_static_uninstantiated(AllocT alloc)\n+{\n+  static int a;\n+  #pragma omp allocate(a) allocator(alloc) /* { dg-bogus \"\" } */\n+}\n+\n+template<typename AllocT>\n+void templ_allocator_var_static_uninstantiated()\n+{\n+  AllocT alloc = omp_default_mem_alloc;\n+  static int a;\n+  #pragma omp allocate(a) allocator(alloc) /* { dg-bogus \"\" } */\n+}\n+\n+\n+/************************\n+ * Invalid align clause *\n+ ************************/\n+\n+template<int Align>\n+void nttp_align()\n+{\n+  int a;\n+  #pragma omp allocate(a) align(Align) /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } } */\n+}\n+\n+template<int Align>\n+void nttp_align_uninstantiated()\n+{\n+  int a;\n+  #pragma omp allocate(a) align(Align)\n+}\n+\n+template<int* Align>\n+void nttp_wrong_type_align_uninstantiated()\n+{\n+  int a;\n+  #pragma omp allocate(a) align(Align)\n+  /* { dg-error \"could not convert 'Align' from '\\[^\\n\\r\\]+' to '\\[^\\n\\r\\]+'\" \"\" { xfail *-*-* } .-1 } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-2 } */\n+}\n+\n+template<typename AlignT, AlignT Align>\n+void nttp_dependent_type_align_0()\n+{\n+  int a;\n+  #pragma omp allocate(a) align(Align) /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } } */\n+}\n+\n+template<typename AlignT, AlignT Align>\n+void nttp_dependent_type_align_1()\n+{\n+  int a;\n+  #pragma omp allocate(a) align(Align) /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } } */\n+}\n+\n+template<typename AlignT, AlignT Align>\n+void nttp_dependent_type_align_uninstantiated()\n+{\n+  int a;\n+  #pragma omp allocate(a) align(Align)\n+}\n+\n+void instantiate_nttp_align()\n+{\n+  nttp_align<32>();\n+  nttp_align<42>(); /* { dg-message \"required from here\" } */\n+  nttp_dependent_type_align_0<int, 32>(); /* { dg-bogus \"required from here\" } */\n+  nttp_dependent_type_align_0<int, 42>(); /* { dg-message \"required from here\" } */\n+  nttp_dependent_type_align_1<int, 32>(); /* { dg-bogus \"required from here\" } */\n+  /* We just need any non integer NTTP that is valid in c++98, a fptr fits the bill.  */\n+  nttp_dependent_type_align_1<void(*)(), instantiate_nttp_align>(); /* { dg-message \"required from here\" } */\n+  /* { dg-error \"could not convert 'instantiate_nttp_align' from 'void \\\\(\\\\*\\\\)\\\\(\\\\)' to '\\[^\\n\\r\\]+'\" \"Bugged location, see comment\" { target *-*-* } .-1 } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"Bugged location, see comment\" { target *-*-* } .-2 } */\n+  /* { dg-error \"conversion from 'void \\\\(\\\\*\\\\)\\\\(\\\\)' to '\\[^\\n\\r\\]+' in a converted constant expression\" \"Bugged location, see comment\" { target *-*-* } .-3 } */\n+  /* I believe this diagnostic is bugged, it should refer to where the\n+     expression is used, not where it originated from.  This isn't a bug for\n+     this feature though so I'm making the test case work around it,\n+     when this bug is fixed this test case, and the xfail in the test case in\n+     nttp_dependent_type_align_1 can be remove.  */\n+}\n+\n+/* Cases that are never constant integer expressions (always required for the align clause.)  */\n+\n+template<typename>\n+void align_param_uninstantiated(int align)\n+{\n+  int a;\n+  #pragma omp allocate(a) align(align)\n+  /* { dg-error \"'align' is not a constant expression\" \"\" { xfail *-*-* } .-1 }*/\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-2 } */\n+}\n+\n+template<typename>\n+void align_var_uninstantiated()\n+{\n+  int align = 32; /* { dg-note \"'int align' is not const\" \"\" { xfail *-*-* } } */\n+  int a;\n+  #pragma omp allocate(a) align(align)\n+  /* { dg-error \"the value of 'align' is not usable in a constant expression\" \"\" { xfail *-*-* } .-1 } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-2 } */\n+}\n+\n+/* While weird, there are inputs for AlignT that are well-formed here,\n+   therefore these cases can not be diagnosed until instantiation.  */\n+\n+template<typename AlignT>\n+void templ_align_param_uninstantiated(AlignT align)\n+{\n+  int a;\n+  #pragma omp allocate(a) align(align) /* { dg-bogus \"\" } */\n+}\n+\n+template<typename AlignT>\n+void templ_align_var_uninstantiated()\n+{\n+  AlignT align = 32;\n+  int a;\n+  #pragma omp allocate(a) align(align) /* { dg-bogus \"\" } */\n+}\n+\n+\n+\n+/***************\n+ * Mixed cases *\n+ ***************/\n+\n+template<typename Var,\n+  typename AllocT, AllocT Alloc,\n+  typename AlignT, AlignT Align>\n+void all_dependent_uninstantiated()\n+{\n+  int b = 42;\n+  Var a = b;\n+  #pragma omp allocate(a) allocator(Alloc) align(Align)\n+}\n+\n+template<typename Var,\n+  typename AllocT, AllocT Alloc,\n+  typename AlignT, AlignT Align>\n+void all_dependent_valid()\n+{\n+  int b = 42;\n+  Var a = b;\n+  #pragma omp allocate(a) allocator(Alloc) align(Align)\n+}\n+\n+template<typename Var,\n+  typename AllocT, AllocT Alloc,\n+  typename AlignT, AlignT Align>\n+void all_dependent_0()\n+{\n+  int b = 42;\n+  Var a = b; /* { dg-note \"'a' declared here\" } */\n+  #pragma omp allocate(a) allocator(Alloc) align(Align)\n+  /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+}\n+\n+template<typename Var,\n+  typename AllocT, AllocT Alloc,\n+  typename AlignT, AlignT Align>\n+void all_dependent_1()\n+{\n+  int b = 42;\n+  Var a = b;\n+  #pragma omp allocate(a) allocator(Alloc) align(Align)\n+  /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" \"\" { target *-*-* } .-1 } */\n+}\n+\n+template<typename Var,\n+  typename AllocT, AllocT Alloc,\n+  typename AlignT, AlignT Align>\n+void all_dependent_2()\n+{\n+  int b = 42;\n+  Var a = b;\n+  #pragma omp allocate(a) allocator(Alloc) align(Align)\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-1 } */\n+}\n+\n+template<typename Var,\n+  typename AllocT, AllocT Alloc,\n+  typename AlignT, AlignT Align>\n+void all_dependent_3()\n+{\n+  int b = 42;\n+  Var a = b; /* { dg-note \"'a' declared here\" } */\n+  #pragma omp allocate(a) allocator(Alloc) align(Align)\n+  /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+  /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" \"\" { target *-*-* } .-2 } */\n+}\n+\n+template<typename Var,\n+  typename AllocT, AllocT Alloc,\n+  typename AlignT, AlignT Align>\n+void all_dependent_4()\n+{\n+  int b = 42;\n+  Var a = b; /* { dg-note \"'a' declared here\" } */\n+  #pragma omp allocate(a) allocator(Alloc) align(Align)\n+  /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-2 } */\n+}\n+\n+template<typename Var,\n+  typename AllocT, AllocT Alloc,\n+  typename AlignT, AlignT Align>\n+void all_dependent_5()\n+{\n+  int b = 42;\n+  Var a = b;\n+  #pragma omp allocate(a) allocator(Alloc) align(Align)\n+  /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" \"\" { target *-*-* } .-1 } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-2 } */\n+}\n+\n+template<typename Var,\n+  typename AllocT, AllocT Alloc,\n+  typename AlignT, AlignT Align>\n+void all_dependent_6()\n+{\n+  int b = 42;\n+  Var a = b; /* { dg-note \"'a' declared here\" } */\n+  #pragma omp allocate(a) allocator(Alloc) align(Align)\n+  /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+  /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" \"\" { target *-*-* } .-2 } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-3 } */\n+}\n+\n+void instantiate_all_dependent()\n+{\n+  all_dependent_valid<int, omp_allocator_handle_t, omp_default_mem_alloc, int, 32>();\n+  /* Don't test the type mismatch for the align clause here, it's diagnostic\n+     location is buggy, and the error message is the same.  We just really want\n+     to test that we aren't emitting bogus errors when multiple things are\n+     dependent, so it's unnecessary to test that case again.  */\n+  all_dependent_0<int, omp_allocator_handle_t, omp_default_mem_alloc, int, 32>(); /* { dg-bogus \"required from here\" } */\n+  all_dependent_0<int&, omp_allocator_handle_t, omp_default_mem_alloc, int, 32>(); /* { dg-message \"required from here\" } */\n+\n+  all_dependent_1<int, omp_allocator_handle_t, omp_default_mem_alloc, int, 32>(); /* { dg-bogus \"required from here\" } */\n+  all_dependent_1<int, int, 1, int, 32>(); /* { dg-message \"required from here\" } */\n+\n+  all_dependent_2<int, omp_allocator_handle_t, omp_default_mem_alloc, int, 32>(); /* { dg-bogus \"required from here\" } */\n+  all_dependent_2<int, omp_allocator_handle_t, omp_default_mem_alloc, int, 42>(); /* { dg-message \"required from here\" } */\n+\n+  all_dependent_3<int, omp_allocator_handle_t, omp_default_mem_alloc, int, 32>(); /* { dg-bogus \"required from here\" } */\n+  all_dependent_3<int&, int, 1, int, 32>(); /* { dg-message \"required from here\" } */\n+\n+  all_dependent_4<int, omp_allocator_handle_t, omp_default_mem_alloc, int, 32>(); /* { dg-bogus \"required from here\" } */\n+  all_dependent_4<int&, omp_allocator_handle_t, omp_default_mem_alloc, int, 42>(); /* { dg-message \"required from here\" } */\n+\n+  all_dependent_5<int, omp_allocator_handle_t, omp_default_mem_alloc, int, 32>(); /* { dg-bogus \"required from here\" } */\n+  all_dependent_5<int, int, 1, int, 42>(); /* { dg-message \"required from here\" } */\n+\n+  all_dependent_6<int, omp_allocator_handle_t, omp_default_mem_alloc, int, 32>(); /* { dg-bogus \"required from here\" } */\n+  all_dependent_6<int&, int, 1, int, 42>(); /* { dg-message \"required from here\" } */\n+}\n+\n+/* We are missing combined cases for static var used in the allocate directive,\n+   but it should be fine, the combined cases immediately above are probably\n+   overkill as it is.  */\n+\n+\n+/******************************\n+ * Invalid allocate directive *\n+ ******************************/\n+\n+/* We are only testing that we gracefully handle an empty list of vars.  */\n+\n+void no_parens()\n+{\n+  #pragma omp allocate /* { dg-error \"expected '\\\\\\(' before end of line\" } */\n+}\n+\n+template<typename>\n+void templ_no_parens()\n+{\n+  #pragma omp allocate /* { dg-error \"expected '\\\\\\(' before end of line\" } */\n+}\n+template void templ_no_parens<void>();\n+\n+template<typename>\n+void templ_no_parens_uninstantiated()\n+{\n+  #pragma omp allocate /* { dg-error \"expected '\\\\\\(' before end of line\" } */\n+}\n+\n+void no_vars()\n+{\n+  #pragma omp allocate() /* { dg-error \"expected unqualified-id before '\\\\\\)' token\" } */\n+}\n+\n+template<typename>\n+void templ_no_vars()\n+{\n+  #pragma omp allocate() /* { dg-error \"expected unqualified-id before '\\\\\\)' token\" } */\n+}\n+template void templ_no_vars<void>();\n+\n+template<typename>\n+void templ_no_vars_uninstantiated()\n+{\n+  #pragma omp allocate() /* { dg-error \"expected unqualified-id before '\\\\\\)' token\" } */\n+}\n+\n+/* We can't diagnose anything about the allocator clause if we have no\n+   variables, but we do need to make sure we don't crash.  */\n+\n+void no_vars_allocator()\n+{\n+  #pragma omp allocate() allocator(omp_default_mem_alloc) /* { dg-error \"expected unqualified-id before '\\\\\\)' token\" } */\n+}\n+\n+template<typename>\n+void templ_no_vars_allocator()\n+{\n+  #pragma omp allocate() allocator(omp_default_mem_alloc) /* { dg-error \"expected unqualified-id before '\\\\\\)' token\" } */\n+}\n+template void templ_no_vars_allocator<void>();\n+\n+template<typename>\n+void templ_no_vars_allocator_uninstantiated()\n+{\n+  #pragma omp allocate() allocator(omp_default_mem_alloc) /* { dg-error \"expected unqualified-id before '\\\\\\)' token\" } */\n+}\n+\n+/* We can still diagnose errors about the align clause without any vars.  */\n+\n+void no_vars_invalid_align()\n+{\n+  #pragma omp allocate() align(42) /* { dg-error \"expected unqualified-id before '\\\\\\)' token\" } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { target *-*-* } .-1 } */\n+}\n+\n+template<typename>\n+void templ_no_vars_invalid_align()\n+{\n+  #pragma omp allocate() align(42) /* { dg-error \"expected unqualified-id before '\\\\\\)' token\" } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { target *-*-* } .-1 } */\n+}\n+template void templ_no_vars_invalid_align<void>();\n+\n+template<typename>\n+void templ_no_vars_invalid_align_uninstantiated()\n+{\n+  #pragma omp allocate() align(42) /* { dg-error \"expected unqualified-id before '\\\\\\)' token\" } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-1 } */\n+}\n+\n+template<int Align>\n+void templ_no_vars_dep_align()\n+{\n+  #pragma omp allocate() align(Align) /* { dg-error \"expected unqualified-id before '\\\\\\)' token\" } */\n+}\n+template void templ_no_vars_dep_align<32>();\n+\n+template<int Align>\n+void templ_no_vars_dep_align_invalid()\n+{\n+  #pragma omp allocate() align(Align) /* { dg-error \"expected unqualified-id before '\\\\\\)' token\" } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-1 } */\n+}\n+template void templ_no_vars_dep_align_invalid<42>();\n+\n+template<int Align>\n+void templ_no_vars_dep_align_uninstantiated()\n+{\n+  #pragma omp allocate() align(Align) /* { dg-error \"expected unqualified-id before '\\\\\\)' token\" } */\n+}\n+\n+/*********************************\n+ * All vars in directive invalid *\n+ *********************************/\n+\n+void invalid_vars_param(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  #pragma omp allocate(p) /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" } */\n+}\n+\n+template<typename>\n+void templ_invalid_vars_param(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  #pragma omp allocate(p) /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" } */\n+}\n+template void templ_invalid_vars_param<void>(int);\n+\n+template<typename>\n+void templ_invalid_vars_param_uninstantiated(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  #pragma omp allocate(p) /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" } */\n+}\n+\n+void invalid_vars_out_of_scope()\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+  }\n+}\n+\n+template<typename>\n+void templ_invalid_vars_out_of_scope()\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+  }\n+}\n+template void templ_invalid_vars_out_of_scope<void>();\n+\n+template<typename>\n+void templ_invalid_vars_out_of_scope_uninstantiated()\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+  }\n+}\n+\n+void invalid_vars_out_of_scope_and_param(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a, p) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+  }\n+}\n+\n+template<typename>\n+void templ_invalid_vars_out_of_scope_and_param(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a, p) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+  }\n+}\n+template void templ_invalid_vars_out_of_scope_and_param<void>(int);\n+\n+template<typename>\n+void templ_invalid_vars_out_of_scope_and_param_uninstantiated(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a, p) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+  }\n+}\n+\n+/* Same as above, we can't diagnose anything about the allocator clause if we\n+   have no variables, but we do need to make sure we don't crash.  */\n+\n+void invalid_vars_param_allocator(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  #pragma omp allocate(p) allocator(omp_default_mem_alloc) /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" } */\n+}\n+\n+template<typename>\n+void templ_invalid_vars_param_allocator(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  #pragma omp allocate(p) allocator(omp_default_mem_alloc) /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" } */\n+}\n+template void templ_invalid_vars_param_allocator<void>(int);\n+\n+template<typename>\n+void templ_invalid_vars_param_allocator_uninstantiated(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  #pragma omp allocate(p) allocator(omp_default_mem_alloc) /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" } */\n+}\n+\n+void invalid_vars_out_of_scope_allocator()\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a) allocator(omp_default_mem_alloc) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+  }\n+}\n+\n+template<typename>\n+void templ_invalid_vars_out_of_scope_allocator()\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a) allocator(omp_default_mem_alloc) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+  }\n+}\n+template void templ_invalid_vars_out_of_scope_allocator<void>();\n+\n+template<typename>\n+void templ_invalid_vars_out_of_scope_allocator_uninstantiated()\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a) allocator(omp_default_mem_alloc) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+  }\n+}\n+\n+void invalid_vars_out_of_scope_and_param_allocator(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a, p) allocator(omp_default_mem_alloc) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+  }\n+}\n+\n+template<typename>\n+void templ_invalid_vars_out_of_scope_and_param_allocator(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a, p) allocator(omp_default_mem_alloc) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+  }\n+}\n+template void templ_invalid_vars_out_of_scope_and_param_allocator<void>(int);\n+\n+template<typename>\n+void templ_invalid_vars_out_of_scope_and_param_allocator_uninstantiated(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a, p) allocator(omp_default_mem_alloc) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+  }\n+}\n+\n+/* Invalid vars with non-dependent invalid align */\n+\n+void invalid_vars_param_align_invalid(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  #pragma omp allocate(p) align(42) /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { target *-*-* } .-1 } */\n+}\n+\n+template<typename>\n+void templ_invalid_vars_param_align_invalid(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  #pragma omp allocate(p) align(42) /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { target *-*-* } .-1 } */\n+}\n+template void templ_invalid_vars_param_align_invalid<void>(int);\n+\n+template<typename>\n+void templ_invalid_vars_param_align_invalid_uninstantiated(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  #pragma omp allocate(p) align(42) /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-1 } */\n+}\n+\n+void invalid_vars_out_of_scope_align_invalid()\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a) align(42) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { target *-*-* } .-1 } */\n+  }\n+}\n+\n+template<typename>\n+void templ_invalid_vars_out_of_scope_align_invalid()\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a) align(42) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { target *-*-* } .-1 } */\n+  }\n+}\n+template void templ_invalid_vars_out_of_scope_align_invalid<void>();\n+\n+template<typename>\n+void templ_invalid_vars_out_of_scope_align_invalid_uninstantiated()\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a) align(42) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-1 } */\n+  }\n+}\n+\n+void invalid_vars_out_of_scope_and_param_align_invalid(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a, p) align(42) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+    /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { target *-*-* } .-2 } */\n+  }\n+}\n+\n+template<typename>\n+void templ_invalid_vars_out_of_scope_and_param_align_invalid(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a, p) align(42) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+    /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { target *-*-* } .-2 } */\n+  }\n+}\n+template void templ_invalid_vars_out_of_scope_and_param_align_invalid<void>(int);\n+\n+template<typename>\n+void templ_invalid_vars_out_of_scope_and_param_align_invalid_uninstantiated(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a, p) align(42) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+    /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-2 } */\n+  }\n+}\n+\n+\n+/* Param (dependent align) */\n+\n+template<int Align>\n+void templ_invalid_vars_param_dependent_align_uninstantiated(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  #pragma omp allocate(p) align(Align) /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" } */\n+}\n+\n+template<int Align>\n+void templ_invalid_vars_param_dependent_align(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  #pragma omp allocate(p) align(Align) /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" } */\n+}\n+template void templ_invalid_vars_param_dependent_align<32>(int);\n+\n+template<int Align>\n+void templ_invalid_vars_param_dependent_align_invalid(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  #pragma omp allocate(p) align(Align) /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-1 } */\n+}\n+template void templ_invalid_vars_param_dependent_align_invalid<42>(int);\n+\n+\n+/* Out of scope (dependent align) */\n+\n+template<int Align>\n+void templ_invalid_vars_out_of_scope_dependent_align_uninstantiated()\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a) align(Align) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+  }\n+}\n+\n+template<int Align>\n+void templ_invalid_vars_out_of_scope_dependent_align()\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a) align(Align) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+  }\n+}\n+template void templ_invalid_vars_out_of_scope_dependent_align<32>();\n+\n+template<int Align>\n+void templ_invalid_vars_out_of_scope_dependent_align_invalid()\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a) align(Align) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-1 } */\n+  }\n+}\n+template void templ_invalid_vars_out_of_scope_dependent_align_invalid<42>();\n+\n+\n+/* Param and out of scope (dependent align) */\n+\n+template<int Align>\n+void templ_invalid_vars_out_of_scope_and_param_dependent_align_uninstantiated(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a, p) align(Align) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+  }\n+}\n+\n+template<int Align>\n+void templ_invalid_vars_out_of_scope_and_param_dependent_align(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a, p) align(Align) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+  }\n+}\n+template void templ_invalid_vars_out_of_scope_and_param_dependent_align<32>(int);\n+\n+template<int Align>\n+void templ_invalid_vars_out_of_scope_and_param_dependent_align_invalid(int p) /* { dg-note \"parameter 'p' declared here\" } */\n+{\n+  int a; /* { dg-note \"declared here\" } */\n+  {\n+    #pragma omp allocate(a, p) align(Align) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+    /* { dg-error \"function parameter 'p' may not appear as list item in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+    /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-2 } */\n+  }\n+}\n+template void templ_invalid_vars_out_of_scope_and_param_dependent_align_invalid<42>(int);\n+\n+\n+\n+/****************************************************\n+ * uses of var in multiple directives in a template *\n+ ****************************************************/\n+\n+/* We are missing a lot of cases here but testing all of them shouldn't be\n+   necessary.  Uses of variables in multiple directives are diagnosed during\n+   parsing so templates shouldn't change anything.  This is of course as long\n+   as we don't change that, and these cases should be enough to deter anyone\n+   from doing so.  */\n+\n+template<typename>\n+void multiple_uses_non_dependent_directive_uninstantiated()\n+{\n+  int a;\n+  #pragma omp allocate(a) /* { dg-note \"'a' previously appeared here\" } */\n+  #pragma omp allocate(a) /* { dg-error \"'a' already appeared as list item in an 'allocate' directive\" } */\n+}\n+\n+template<typename>\n+void multiple_uses_non_dependent_directive()\n+{\n+  int a;\n+  #pragma omp allocate(a) /* { dg-note \"'a' previously appeared here\" } */\n+  #pragma omp allocate(a) /* { dg-error \"'a' already appeared as list item in an 'allocate' directive\" } */\n+}\n+template void multiple_uses_non_dependent_directive<void>();\n+\n+\n+template<int Align>\n+void multiple_uses_dep_directive_before_align_uninstantiated()\n+{\n+  int a;\n+  #pragma omp allocate(a) align(Align) /* { dg-note \"'a' previously appeared here\" } */\n+  #pragma omp allocate(a) /* { dg-error \"'a' already appeared as list item in an 'allocate' directive\" } */\n+}\n+\n+template<int Align>\n+void multiple_uses_dep_directive_before_valid_align()\n+{\n+  int a;\n+  #pragma omp allocate(a) align(Align) /* { dg-note \"'a' previously appeared here\" } */\n+  #pragma omp allocate(a) /* { dg-error \"'a' already appeared as list item in an 'allocate' directive\" } */\n+}\n+template void multiple_uses_dep_directive_before_valid_align<32>();\n+\n+template<int Align>\n+void multiple_uses_dep_directive_before_invalid_align()\n+{\n+  int a;\n+  #pragma omp allocate(a) align(Align) /* { dg-note \"'a' previously appeared here\" } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-1 } */\n+  #pragma omp allocate(a) /* { dg-error \"'a' already appeared as list item in an 'allocate' directive\" } */\n+}\n+template void multiple_uses_dep_directive_before_invalid_align<42>();\n+\n+\n+/* Dependent directive after the independent one.  */\n+\n+template<int Align>\n+void multiple_uses_dep_directive_after_align_uninstantiated()\n+{\n+  int a;\n+  #pragma omp allocate(a) /* { dg-note \"'a' previously appeared here\" } */\n+  #pragma omp allocate(a) align(Align) /* { dg-error \"'a' already appeared as list item in an 'allocate' directive\" } */\n+}\n+\n+template<int Align>\n+void multiple_uses_dep_directive_after_valid_align()\n+{\n+  int a;\n+  #pragma omp allocate(a) /* { dg-note \"'a' previously appeared here\" } */\n+  #pragma omp allocate(a) align(Align) /* { dg-error \"'a' already appeared as list item in an 'allocate' directive\" } */\n+}\n+template void multiple_uses_dep_directive_after_valid_align<32>();\n+\n+template<int Align>\n+void multiple_uses_dep_directive_after_invalid_align()\n+{\n+  int a;\n+  #pragma omp allocate(a) /* { dg-note \"'a' previously appeared here\" } */\n+  #pragma omp allocate(a) align(Align) /* { dg-error \"'a' already appeared as list item in an 'allocate' directive\" } */\n+  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-1 } */\n+}\n+template void multiple_uses_dep_directive_after_invalid_align<42>();\n+\n+/* These are fixed by the later location wrapping patch.  */\n+/* { dg-bogus \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } 0 } */\n+/* { dg-bogus \"'allocator' clause requires a constant predefined allocator\" \"\" { xfail *-*-* } 0 } */\n+/* { dg-bogus \"expression evaluates to '1024'\" \"\" { xfail *-*-* } 0 } */\ndiff --git a/gcc/testsuite/g++.dg/gomp/allocate-15.C b/gcc/testsuite/g++.dg/gomp/allocate-15.C\nnew file mode 100644\nindex 00000000000..605e10e477f\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/gomp/allocate-15.C\n@@ -0,0 +1,50 @@\n+/* { dg-do compile { target c++11 } } */\n+\n+/* Diagnostics for rvalue reference vars used in an allocate directive.  */\n+\n+void rref_var()\n+{\n+  int&& ref = 42; /* { dg-note \"'ref' declared here\" } */\n+  #pragma omp allocate(ref) /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" } */\n+}\n+\n+void const_rref_var()\n+{\n+  int const&& ref = 42; /* { dg-note \"'ref' declared here\" } */\n+  #pragma omp allocate(ref) /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" } */\n+}\n+\n+template<typename>\n+void rref_var_templ_not_instantiated()\n+{\n+  int&& ref = 42; /* { dg-note \"'ref' declared here\" } */\n+  #pragma omp allocate(ref) /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" } */\n+}\n+\n+template<typename>\n+void const_rref_var_templ_not_instantiated()\n+{\n+  int const&& ref = 42; /* { dg-note \"'ref' declared here\" } */\n+  #pragma omp allocate(ref) /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" } */\n+}\n+\n+template<typename T>\n+void dependent_rref_var_templ_not_instantiated()\n+{\n+  T&& t = 42; /* { dg-note \"'t' declared here\" } */\n+  #pragma omp allocate(t) /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" } */\n+}\n+\n+template<typename T>\n+void dependent_var_templ()\n+{\n+  T t = 42; /* { dg-note \"'t' declared here\" } */\n+  #pragma omp allocate(t) /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" } */\n+}\n+void instantiate_var_templ()\n+{\n+  dependent_var_templ<int>(); /* { dg-bogus \"required from here\" } */\n+  dependent_var_templ<int&&>(); /* { dg-message \"required from here\" } */\n+  dependent_var_templ<int const&&>(); /* { dg-message \"required from here\" } */\n+}\n+\ndiff --git a/gcc/testsuite/g++.dg/gomp/allocate-16.C b/gcc/testsuite/g++.dg/gomp/allocate-16.C\nnew file mode 100644\nindex 00000000000..7258d8c1c3c\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/gomp/allocate-16.C\n@@ -0,0 +1,232 @@\n+/* { dg-do compile { target c++11 } } */\n+/* { dg-ice \"\" { c++17 } } */\n+#include \"allocate-allocator-handle.h\"\n+\n+/* Incorrect use of lambda captures in a directive or clause.\n+   There are a few cases in here that are impacted by the bug with implicit\n+   constexpr functions.  */\n+\n+/* These errors (specifically in capture_used_in_directive) really could be better.  */\n+\n+void capture_used_in_directive()\n+{\n+  int a = 42;\n+  auto cl = [a](){ /* { dg-note \"declared here\" } */\n+    #pragma omp allocate(a) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+  };\n+}\n+\n+template<typename>\n+void capture_used_in_directive_templ_uninstantiated()\n+{\n+  int a = 42;\n+  auto cl = [a](){ /* { dg-note \"declared here\" } */\n+    #pragma omp allocate(a) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+  };\n+}\n+\n+template<typename>\n+void capture_used_in_directive_templ()\n+{\n+  int a = 42;\n+  auto cl = [a](){ /* { dg-note \"declared here\" } */\n+    #pragma omp allocate(a) /* { dg-error \"'allocate' directive must be in the same scope as 'a'\" } */\n+  };\n+}\n+\n+void instantiate_capture_used_in_directive()\n+{\n+  capture_used_in_directive_templ<void>();\n+}\n+\n+\n+\n+void capture_used_in_allocator_clause_static_var()\n+{\n+  omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note \"'omp_allocator_handle_t alloc' is not const\" } */\n+  auto cl = [alloc](){\n+    static int a = 42; /* { dg-note \"'a' declared here\" } */\n+    int b = 42;\t       /* { dg-bogus \"'b' declared here\" } */\n+    static int c = 42; /* { dg-note \"'c' declared here\" } */\n+    int d = 42;        /* { dg-bogus \"'d' declared here\" } */\n+    #pragma omp allocate(a, b, c, d) allocator(alloc)\n+    /* { dg-error \"the value of 'alloc' is not usable in a constant expression\" \"\" { target *-*-* } .-1 } */\n+    /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { target *-*-* } .-2 } */\n+    /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target *-*-* } .-3 } */\n+  };\n+}\n+\n+template<typename>\n+void capture_used_in_allocator_clause_static_var_templ_uninstantiated()\n+{\n+  omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note \"'omp_allocator_handle_t alloc' is not const\" \"\" { xfail *-*-* } } */\n+  auto cl = [alloc](){\n+    static int a = 42; /* { dg-note \"'a' declared here\" \"\" { xfail *-*-* } } */\n+    int b = 42;\t       /* { dg-bogus \"'b' declared here\" } */\n+    static int c = 42; /* { dg-note \"'c' declared here\" \"\" { xfail *-*-* } } */\n+    int d = 42;        /* { dg-bogus \"'d' declared here\" } */\n+    #pragma omp allocate(a, b, c, d) allocator(alloc)\n+    /* { dg-error \"the value of 'alloc' is not usable in a constant expression\" \"\" { xfail *-*-* } .-1 } */\n+    /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { xfail *-*-* } .-2 } */\n+    /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail *-*-* } .-3 } */\n+  };\n+}\n+/* This case can't be diagnosed, there exists a T where alloc is a converted\n+   constant expression of type omp_allocator_handle_t.  This is demonstrated\n+   below in dependent_capture_used_in_allocator_clause_static_var_templ_valid.  */\n+template<typename T>\n+void dependent_capture_used_in_allocator_clause_static_var_templ_uninstantiated()\n+{\n+  T alloc = omp_default_mem_alloc; /* { dg-bogus \"\" } */\n+  auto cl = [alloc](){\n+    static int a = 42; /* { dg-bogus \"'a' declared here\" } */\n+    static int c = 42; /* { dg-bogus \"'c' declared here\" } */\n+    #pragma omp allocate(a, c) allocator(alloc)\n+    /* { dg-bogus \"the value of 'alloc' is not usable in a constant expression\" \"\" { target *-*-* } .-1 } */\n+    /* { dg-bogus \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target *-*-* } .-2 } */\n+  };\n+}\n+\n+template<typename>\n+void capture_used_in_allocator_clause_static_var_templ()\n+{\n+  omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note \"'omp_allocator_handle_t alloc' is not const\" \"\" { xfail c++17 } } */\n+  auto cl = [alloc](){\n+    static int a = 42; /* { dg-note \"'a' declared here\" \"\" { xfail c++17 } } */\n+    int b = 42;\t       /* { dg-bogus \"'b' declared here\" } */\n+    static int c = 42; /* { dg-note \"'c' declared here\" \"\" { xfail c++17 } } */\n+    int d = 42;        /* { dg-bogus \"'d' declared here\" } */\n+    #pragma omp allocate(a, b, c, d) allocator(alloc)\n+    /* { dg-error \"the value of 'alloc' is not usable in a constant expression\" \"\" { xfail c++17 } .-1 }*/\n+    /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { xfail c++17 } .-2 } */\n+    /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail c++17 } .-3 } */\n+  };\n+}\n+\n+template<typename T>\n+void dependent_capture_used_in_allocator_clause_static_var_templ()\n+{\n+  T alloc = omp_default_mem_alloc; /* { dg-note \"'omp_allocator_handle_t alloc' is not const\" \"\" { xfail c++17 } } */\n+  auto cl = [alloc](){\n+    static int a = 42; /* { dg-note \"'a' declared here\" \"\" { xfail c++17 } } */\n+    int b = 42;\t       /* { dg-bogus \"'b' declared here\" } */\n+    static int c = 42; /* { dg-note \"'c' declared here\" \"\" { xfail c++17 } } */\n+    int d = 42;        /* { dg-bogus \"'d' declared here\" } */\n+    #pragma omp allocate(a, b, c, d) allocator(alloc)\n+    /* { dg-error \"the value of 'alloc' is not usable in a constant expression\" \"\" { xfail c++17 } .-1 } */\n+    /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { xfail c++17 } .-2 } */\n+    /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail c++17 } .-3 } */\n+  };\n+}\n+\n+template<typename T>\n+void dependent_capture_used_in_allocator_clause_static_var_templ_valid()\n+{\n+  T alloc = omp_default_mem_alloc; /* { dg-bogus \"\" } */\n+  auto cl = [alloc](){\n+    static int a = 42; /* { dg-bogus \"\" } */\n+    static int c = 42; /* { dg-bogus \"\" } */\n+    #pragma omp allocate(a, c) allocator(alloc)\n+    /* { dg-bogus \"the value of 'alloc' is not usable in a constant expression\" \"\" { target *-*-* } .-1 } */\n+    /* { dg-bogus \"'allocator' clause requires a constant predefined allocator\" \"\" { target *-*-* } .-2 } */\n+  };\n+}\n+\n+void instantiate_capture_used_in_allocator_clause_static_var()\n+{\n+  capture_used_in_allocator_clause_static_var_templ<void>();\n+  dependent_capture_used_in_allocator_clause_static_var_templ<omp_allocator_handle_t>();\n+\n+  struct S {\n+    constexpr S (omp_allocator_handle_t) {}\n+    constexpr operator omp_allocator_handle_t () const { return omp_default_mem_alloc; }\n+  };\n+  dependent_capture_used_in_allocator_clause_static_var_templ_valid<S> ();\n+  dependent_capture_used_in_allocator_clause_static_var_templ_valid<const omp_allocator_handle_t> ();\n+}\n+\n+\n+\n+void capture_used_in_align_clause()\n+{\n+  int align = 32; /* { dg-note \"'int align' is not const\" } */\n+  auto cl = [align](){\n+    int a;\n+    #pragma omp allocate(a) align(align)\n+    /* { dg-error \"the value of 'align' is not usable in a constant expression\" \"\" { target *-*-* } .-1 } */\n+    /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { target *-*-* } .-2 } */\n+  };\n+}\n+\n+template<typename>\n+void capture_used_in_align_clause_templ_uninstantiated()\n+{\n+  int align = 32; /* { dg-note \"'int align' is not const\" \"\" { xfail *-*-* } } */\n+  auto cl = [align](){\n+  /* { dg-bogus \"the value of 'align' is not usable in a constant expression\" \"\" { target *-*-* } .-1 } */\n+    int a;\n+    #pragma omp allocate(a) align(align)\n+    /* { dg-error \"the value of 'align' is not usable in a constant expression\" \"\" { xfail *-*-* } .-1 } */\n+    /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-2 } */\n+  };\n+}\n+\n+/* This case can't be diagnosed, there exists a T where align is a converted\n+   constant expression of long unsigned int.  This is demonstrated\n+   below in dependent_capture_used_in_align_clause_templ_valid.  */\n+template<typename T>\n+void dependent_capture_used_in_align_clause_templ_uninstantiated()\n+{\n+  T align = 32; /* { dg-bogus \"\" } */\n+  auto cl = [align](){\n+    int a;\n+    #pragma omp allocate(a) align(align) /* { dg-bogus \"\" } */\n+  };\n+}\n+\n+template<typename>\n+void capture_used_in_align_clause_templ()\n+{\n+  int align = 32; /* { dg-note \"'int align' is not const\" \"\" { xfail c++17 } } */\n+  auto cl = [align](){\n+    int a;\n+    #pragma omp allocate(a) align(align)\n+    /* { dg-error \"the value of 'align' is not usable in a constant expression\" \"\" { target *-*-* xfail c++17 } .-1 } */\n+    /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { target *-*-* xfail c++17 } .-2 } */\n+  };\n+}\n+\n+template<typename T>\n+void dependent_capture_used_in_align_clause_templ()\n+{\n+  T align = 32; /* { dg-note \"'int align' is not const\" \"\" { xfail c++17 } } */\n+  auto cl = [align](){\n+    int a;\n+    #pragma omp allocate(a) align(align)\n+    /* { dg-error \"the value of 'align' is not usable in a constant expression\" \"\" { target *-*-* xfail c++17 } .-1 } */\n+    /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { target *-*-* xfail c++17 } .-2 } */\n+  };\n+}\n+\n+template<typename T>\n+void dependent_capture_used_in_align_clause_templ_valid()\n+{\n+  T align = 32; /* { dg-bogus \"\" } */\n+  auto cl = [align](){\n+    int a;\n+    #pragma omp allocate(a) align(align) /* { dg-bogus \"\" } */\n+  };\n+}\n+\n+void instantiate_capture_used_in_align()\n+{\n+  capture_used_in_align_clause_templ<void>();\n+  dependent_capture_used_in_align_clause_templ<int>();\n+\n+  struct S {\n+    constexpr S (int) {}\n+    constexpr operator unsigned int () const { return 32; }\n+  };\n+  dependent_capture_used_in_align_clause_templ_valid<S> ();\n+  dependent_capture_used_in_align_clause_templ_valid<const int> ();\n+}\ndiff --git a/gcc/testsuite/g++.dg/gomp/allocate-17.C b/gcc/testsuite/g++.dg/gomp/allocate-17.C\nnew file mode 100644\nindex 00000000000..e265ecdd1e7\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/gomp/allocate-17.C\n@@ -0,0 +1,560 @@\n+/* { dg-do compile { target c++17 } } */\n+\n+/* Nested lambdas.  */\n+\n+#include \"allocate-allocator-handle.h\"\n+\n+template<int Align>\n+auto lambda_0_valid()\n+{\n+  return [](auto p0){\n+    return [](auto p1){\n+      return [](auto p2){\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b;\n+\t  #pragma omp allocate(a) align(Align) allocator(p2)\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<int Align>\n+auto lambda_0_bad_align()\n+{\n+  return [](auto p0){\n+    return [](auto p1){\n+      return [](auto p2){\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b;\n+\t  #pragma omp allocate(a) align(Align) allocator(p2)\n+\t  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-1 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<int Align>\n+auto lambda_0_ref_in_directive()\n+{\n+  return [](auto p0){\n+    return [](auto p1){\n+      return [](auto p2){\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b; /* { dg-message \"'a' declared here\" } */\n+\t  #pragma omp allocate(a) align(Align) allocator(p2)\n+\t  /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+\n+template<int Align>\n+auto lambda_0_invalid_allocator()\n+{\n+  return [](auto p0){\n+    return [](auto p1){\n+      return [](auto p2){\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b;\n+\t  #pragma omp allocate(a) align(Align) allocator(p2)\n+\t  /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" \"\" { target *-*-* } .-1 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<int Align>\n+auto lambda_0_all()\n+{\n+  return [](auto p0){\n+    return [](auto p1){\n+      return [](auto p2){\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b; /* { dg-message \"'a' declared here\" } */\n+\t  #pragma omp allocate(a) align(Align) allocator(p2)\n+\t  /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+\t  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-2 } */\n+\t  /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" \"\" { target *-*-* } .-3 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<int Align>\n+auto lambda_0_wrong_align_partially_instantiated()\n+{\n+  return [](auto p0){\n+    return [](auto p1){\n+      return [](auto p2){\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b;\n+\t  #pragma omp allocate(a) align(Align) allocator(p2)\n+\t  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-1 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<int Align>\n+auto lambda_0_invalid_allocator_partially_instantiated()\n+{\n+  return [](auto p0){\n+    return [](auto p1){\n+      return [](auto p2){\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b;\n+\t  #pragma omp allocate(a) align(Align) allocator(p2)\n+\t  /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" \"\" { xfail *-*-* } .-1 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+void instantiate_lambdas_0()\n+{\n+  {\n+    auto c0 = lambda_0_valid<32>();\n+    auto c1 = c0(0);\n+    auto c2 = c1(0);\n+    auto c3 = c2(omp_default_mem_alloc);\n+    c3(0);\n+  }\n+  {\n+    auto c0 = lambda_0_bad_align<30>(); /* { dg-message \"required from here\" \"\" { xfail *-*-* } } */\n+    auto c1 = c0(0); /* { dg-bogus \"required from here\" } */\n+    auto c2 = c1(0); /* { dg-bogus \"required from here\" } */\n+    auto c3 = c2(omp_default_mem_alloc); /* { dg-bogus \"required from here\" } */\n+    c3(0); /* { dg-bogus \"required from here\"  \"\" { xfail *-*-* } } */\n+  }\n+  {\n+    auto c0 = lambda_0_ref_in_directive<32>();\n+    auto c1 = c0(0);\n+    auto c2 = c1(0);\n+    auto c3 = c2(omp_default_mem_alloc);\n+    int a = 0;\n+    c3.operator()<int&>(a); /* { dg-message \"required from here\" } */\n+  }\n+  {\n+    auto c0 = lambda_0_invalid_allocator<32>();\n+    auto c1 = c0(0);\n+    auto c2 = c1(0);\n+    auto c3 = c2(0); /* { dg-message \"required from here\" \"\" { xfail *-*-* } } */\n+    c3(0); /* { dg-bogus \"required from here\" \"\" { xfail *-*-* } } */\n+  }\n+  {\n+    auto c0 = lambda_0_all<30>(); /* { dg-message \"required from here\" \"\" { xfail *-*-* } } */\n+    auto c1 = c0(0); /* { dg-bogus \"required from here\" } */\n+    auto c2 = c1(0); /* { dg-bogus \"required from here\" } */\n+    auto c3 = c2(0); /* { dg-message \"required from here\" \"\" { xfail *-*-* } } */\n+    int a = 0;\n+    c3.operator()<int&>(a); /* { dg-message \"required from here\" } */\n+  }\n+  {\n+    auto c = lambda_0_wrong_align_partially_instantiated<30>(); /* { dg-message \"required from here\" \"\" { xfail *-*-* } } */\n+  }\n+  {\n+    auto c0 = lambda_0_invalid_allocator_partially_instantiated<32>();\n+    auto c1 = c0(0);\n+    auto c2 = c1(0);\n+    auto c3 = c2(0); /* { dg-message \"required from here\" \"\" { xfail *-*-* } } */\n+  }\n+}\n+\n+\n+\n+template<int Align>\n+auto lambda_1_valid()\n+{\n+  return [](auto p0){\n+    int a = 42;\n+    #pragma omp allocate(a) align(Align)\n+    return [](auto p1){\n+      int a = 42;\n+      #pragma omp allocate(a) align(Align)\n+      return [](auto p2){\n+\tint a = 42;\n+\t#pragma omp allocate(a) align(Align)\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b;\n+\t  #pragma omp allocate(a) align(Align) allocator(p2)\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<int Align>\n+auto lambda_1_bad_align()\n+{\n+  return [](auto p0){\n+    int a = 42;\n+    #pragma omp allocate(a) align(Align) /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } } */\n+    return [](auto p1){\n+      int a = 42;\n+      #pragma omp allocate(a) align(Align) /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } } */\n+      return [](auto p2){\n+\tint a = 42;\n+\t#pragma omp allocate(a) align(Align) /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } } */\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b;\n+\t  #pragma omp allocate(a) align(Align) allocator(p2)\n+\t  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-1 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<int Align>\n+auto lambda_1_ref_in_directive()\n+{\n+  return [](auto p0){\n+    int a = 42;\n+    #pragma omp allocate(a) align(Align)\n+    return [](auto p1){\n+      int a = 42;\n+      #pragma omp allocate(a) align(Align)\n+      return [](auto p2){\n+\tint a = 42;\n+\t#pragma omp allocate(a) align(Align)\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b; /* { dg-message \"'a' declared here\" } */\n+\t  #pragma omp allocate(a) align(Align) allocator(p2)\n+\t  /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<int Align>\n+auto lambda_1_invalid_allocator()\n+{\n+  return [](auto p0){\n+    int a = 42;\n+    #pragma omp allocate(a) align(Align)\n+    return [](auto p1){\n+      int a = 42;\n+      #pragma omp allocate(a) align(Align)\n+      return [](auto p2){\n+\tint a = 42;\n+\t#pragma omp allocate(a) align(Align)\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b;\n+\t  #pragma omp allocate(a) align(Align) allocator(p2)\n+\t  /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" \"\" { target *-*-* } .-1 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<int Align>\n+auto lambda_1_all()\n+{\n+  return [](auto p0){\n+    int a = 42;\n+    #pragma omp allocate(a) align(Align) /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } } */\n+    return [](auto p1){\n+      int a = 42;\n+      #pragma omp allocate(a) align(Align) /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } } */\n+      return [](auto p2){\n+\tint a = 42;\n+\t#pragma omp allocate(a) align(Align) /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } } */\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b; /* { dg-message \"'a' declared here\" } */\n+\t  #pragma omp allocate(a) align(Align) allocator(p2)\n+\t  /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+\t  /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } .-2 } */\n+\t  /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" \"\" { target *-*-* } .-3 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<int Align>\n+auto lambda_1_wrong_align_partially_instantiated()\n+{\n+  return [](auto p0){\n+    int a = 42;\n+    #pragma omp allocate(a) align(Align) /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } } */\n+    return [](auto p1){\n+      int a = 42;\n+      #pragma omp allocate(a) align(Align) /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } } */\n+      return [](auto p2){\n+\tint a = 42;\n+\t#pragma omp allocate(a) align(Align) /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } } */\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b;\n+\t  #pragma omp allocate(a) align(Align) allocator(p2) /* { dg-error \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<int Align>\n+auto lambda_1_invalid_allocator_partially_instantiated()\n+{\n+  return [](auto p0){\n+    int a = 42;\n+    #pragma omp allocate(a) align(Align)\n+    return [](auto p1){\n+      int a = 42;\n+      #pragma omp allocate(a) align(Align)\n+      return [](auto p2){\n+\tint a = 42;\n+\t#pragma omp allocate(a) align(Align)\n+\treturn [p2](auto p3){\n+\t  int b = 42;\n+\t  decltype(p3) a = b;\n+\t  #pragma omp allocate(a) align(Align) allocator(p2)\n+\t  /* { dg-error \"invalid conversion from 'int' to 'omp_allocator_handle_t'\" \"\" { xfail *-*-* } .-1 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+void instantiate_lambdas_1()\n+{\n+  {\n+    auto c0 = lambda_1_valid<32>();\n+    auto c1 = c0(0);\n+    auto c2 = c1(0);\n+    auto c3 = c2(omp_default_mem_alloc);\n+    c3(0);\n+  }\n+  {\n+    auto c0 = lambda_1_bad_align<30>(); /* { dg-message \"required from here\" \"\" { xfail *-*-* } } */\n+    auto c1 = c0(0); /* { dg-bogus \"required from here\" \"\" { xfail *-*-* } } */\n+    auto c2 = c1(0); /* { dg-bogus \"required from here\" \"\" { xfail *-*-* } } */\n+    auto c3 = c2(omp_default_mem_alloc); /* { dg-bogus \"required from here\" \"\" { xfail *-*-* } } */\n+    c3(0); /* { dg-bogus \"required from here\" \"\" { xfail *-*-* } } */\n+  }\n+  {\n+    auto c0 = lambda_1_ref_in_directive<32>();\n+    auto c1 = c0(0);\n+    auto c2 = c1(0);\n+    auto c3 = c2(omp_default_mem_alloc);\n+    int a = 0;\n+    c3.operator()<int&>(a); /* { dg-message \"required from here\" } */\n+  }\n+  {\n+    auto c0 = lambda_1_invalid_allocator<32>();\n+    auto c1 = c0(0);\n+    auto c2 = c1(0);\n+    auto c3 = c2(0); /* { dg-message \"required from here\" \"\" { xfail *-*-* } } */\n+    c3(0); /* { dg-bogus \"required from here\" \"\" { xfail *-*-* } } */\n+  }\n+  {\n+    auto c0 = lambda_1_all<30>(); /* { dg-message \"required from here\" \"\" { xfail *-*-* } } */\n+    auto c1 = c0(0); /* { dg-bogus \"required from here\" \"\" { xfail *-*-* } } */\n+    auto c2 = c1(0); /* { dg-bogus \"required from here\" \"\" { xfail *-*-* } } */\n+    auto c3 = c2(0); /* { dg-message \"required from here\" } */\n+    int a = 0;\n+    c3.operator()<int&>(a); /* { dg-message \"required from here\" } */\n+  }\n+  {\n+    auto c = lambda_1_wrong_align_partially_instantiated<30>();  /* { dg-message \"required from here\" \"\" { xfail *-*-* } } */\n+  }\n+  {\n+    auto c0 = lambda_1_invalid_allocator_partially_instantiated<32>();\n+    auto c1 = c0(0);\n+    auto c2 = c1(0);\n+    auto c3 = c2(0); /* { dg-message \"required from here\" \"\" { xfail *-*-* } } */\n+  }\n+}\n+\n+\n+\n+template<typename T>\n+auto lambda_2_0_valid()\n+{\n+  return [](auto){\n+    return [](auto){\n+      return [](auto){\n+\treturn [](auto){\n+\t  int b = 42;\n+\t  T a = b;\n+\t  #pragma omp allocate(a)\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<typename T>\n+auto lambda_2_0_invalid()\n+{\n+  return [](auto){\n+    return [](auto){\n+      return [](auto){\n+\treturn [](auto){\n+\t  int b = 42;\n+\t  T a = b; /* { dg-message \"'a' declared here\" } */\n+\t  #pragma omp allocate(a)\n+\t  /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<typename T>\n+auto lambda_2_0_invalid_partially_instantiated()\n+{\n+  return [](auto){\n+    return [](auto){\n+      return [](auto){\n+\treturn [](auto){\n+\t  int b = 42;\n+\t  T a = b; /* { dg-message \"'a' declared here\" } */\n+\t  #pragma omp allocate(a)\n+\t  /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<typename>\n+auto lambda_2_1_valid()\n+{\n+  return [](auto){\n+    return [](auto){\n+      return [](auto p2){\n+\tusing type = decltype(p2);\n+\treturn [](auto){\n+\t  int b = 42;\n+\t  type a = b;\n+\t  #pragma omp allocate(a)\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<typename>\n+auto lambda_2_1_invalid()\n+{\n+  return [](auto){\n+    return [](auto){\n+      return [](auto p2){\n+\tusing type = decltype(p2);\n+\treturn [](auto){\n+\t  int b = 42;\n+\t  type a = b; /* { dg-message \"'a' declared here\" } */\n+\t  #pragma omp allocate(a)\n+\t  /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+template<typename>\n+auto lambda_2_1_invalid_partially_instantiated()\n+{\n+  return [](auto){\n+    return [](auto){\n+      return [](auto p2){\n+\tusing type = decltype(p2);\n+\treturn [](auto){\n+\t  int b = 42;\n+\t  type a = b; /* { dg-message \"'a' declared here\" } */\n+\t  #pragma omp allocate(a)\n+\t  /* { dg-error \"variables with reference type may not appear in an 'allocate' directive\" \"\" { target *-*-* } .-1 } */\n+\t  return a;\n+\t};\n+      };\n+    };\n+  };\n+}\n+\n+void instantiate_lambdas_2()\n+{\n+  {\n+    auto c0 = lambda_2_0_valid<int>();\n+    auto c1 = c0(0);\n+    auto c2 = c1(0);\n+    auto c3 = c2(0);\n+    c3(0);\n+  }\n+  {\n+    auto c0 = lambda_2_0_invalid<int&>(); /* { dg-message \"required from here\" } */\n+    auto c1 = c0(0); /* { dg-bogus \"required from here\" } */\n+    auto c2 = c1(0); /* { dg-bogus \"required from here\" } */\n+    auto c3 = c2(0); /* { dg-bogus \"required from here\" } */\n+    c3(0); /* { dg-bogus \"required from here\" } */\n+  }\n+  {\n+    auto c0 = lambda_2_0_invalid_partially_instantiated<int&>(); /* { dg-message \"required from here\" } */\n+  }\n+  {\n+    auto c0 = lambda_2_1_valid<void>();\n+    auto c1 = c0(0);\n+    auto c2 = c1(0);\n+    auto c3 = c2(0);\n+    c3(0);\n+  }\n+  {\n+    auto c0 = lambda_2_1_invalid<void>();\n+    auto c1 = c0(0);\n+    auto c2 = c1(0);\n+    int a = 0;\n+    auto c3 = c2.operator()<int&>(a); /* { dg-message \"required from here\" } */\n+    c3(0); /* { dg-bogus \"required from here\" } */\n+  }\n+  {\n+    auto c0 = lambda_2_1_invalid_partially_instantiated<void>();\n+    auto c1 = c0(0);\n+    auto c2 = c1(0);\n+    int a = 0;\n+    auto c3 = c2.operator()<int&>(a); /* { dg-message \"required from here\" } */\n+  }\n+}\n+\n+/* This is fixed by the later location wrapping patch.  */\n+/* { dg-bogus \"'align' clause argument needs to be positive constant power of two integer expression\" \"\" { xfail *-*-* } 0 } */\ndiff --git a/gcc/testsuite/g++.dg/gomp/allocate-18.C b/gcc/testsuite/g++.dg/gomp/allocate-18.C\nnew file mode 100644\nindex 00000000000..3a04bbe8bcd\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/gomp/allocate-18.C\n@@ -0,0 +1,274 @@\n+/* { dg-do compile { target c++17 } } */\n+\n+/* OpenMP allocate directive in constant expressions where execution does not\n+   pass through the allocation of the variable in the directive.\n+   Lambdas, both implicit and explicit constexpr,\n+   in a function and in a function template.\n+\n+   These cases will be valid if/when OpenMP relaxes restrictions on directives\n+   in constexpr functions.  It might make sense to only allow this behavior in\n+   c++23 though.\n+   \n+   Constexpr lambdas are only permitted in c++17, it doesn't make sense to test\n+   anything prior than that.\n+   \n+   NOTE: The error messages for the cases that are not explicitly declared\n+   constexpr are probably not what we want, we likely want something stating\n+   that the calls are not usable in a constant expression because of the use of\n+   an OpenMP directive.  */\n+\n+void do_constexpr_lambda()\n+{\n+  auto cl = [](bool b) constexpr {\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+    return a;\n+  };\n+  constexpr int v0 = cl(true); /* { dg-error \"'do_constexpr_lambda\\\\\\(\\\\\\)::<lambda\\\\\\(bool\\\\\\)>' called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+  constexpr int v1 = [](bool b) constexpr {\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+    return a;\n+  }(true);\n+}\n+\n+void do_constexpr_generic_lambda()\n+{\n+  auto cl = [](auto b) constexpr {\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+    return a;\n+  };\n+  constexpr int v0 = cl(true); /* { dg-error \"'do_constexpr_generic_lambda\\\\\\(\\\\\\)::<lambda\\\\\\(bool\\\\\\)>' called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+  constexpr int v1 = [](auto b) constexpr {\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+    return a;\n+  }(true);\n+}\n+\n+void do_lambda()\n+{\n+  auto cl = [](bool b){\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+    return a;\n+  };\n+  constexpr int v0 = cl(true); /* { dg-error \"'do_lambda\\\\\\(\\\\\\)::<lambda\\\\\\(bool\\\\\\)>' called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+  constexpr int v1 = [](bool b){\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+    return a;\n+  }(true);\n+}\n+\n+void do_generic_lambda()\n+{\n+  auto cl = [](auto b){\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+    return a;\n+  };\n+  constexpr int v0 = cl(true); /* { dg-error \"'do_generic_lambda\\\\\\(\\\\\\)::<lambda\\\\\\(bool\\\\\\)>' called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+  constexpr int v1 = [](auto b){\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+    return a;\n+  }(true);\n+}\n+\n+template<typename>\n+void do_constexpr_lambda_templ_uninstantiated()\n+{\n+  auto cl = [](bool b) constexpr {\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+    return a;\n+  };\n+  constexpr int v0 = cl(true); /* { dg-error \"called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+  constexpr int v1 = [](bool b) constexpr {\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+    return a;\n+  }(true);\n+}\n+\n+template<typename>\n+void do_constexpr_generic_lambda_templ_uninstantiated()\n+{\n+  auto cl = [](auto b) constexpr {\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+    return a;\n+  };\n+  constexpr int v0 = cl(true); /* { dg-error \"called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+  constexpr int v1 = [](auto b) constexpr {\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+    return a;\n+  }(true);\n+}\n+\n+template<typename>\n+void do_lambda_templ_uninstantiated()\n+{\n+  auto cl = [](bool b){\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+    return a;\n+  };\n+  constexpr int v0 = cl(true); /* { dg-error \"called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+  constexpr int v1 = [](bool b){\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+    return a;\n+  }(true);\n+}\n+\n+template<typename>\n+void do_generic_lambda_templ_uninstantiated()\n+{\n+  auto cl = [](auto b){\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+    return a;\n+  };\n+  constexpr int v0 = cl(true); /* { dg-error \"called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+  constexpr int v1 = [](auto b){\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+    return a;\n+  }(true);\n+}\n+\n+\n+template<typename>\n+void do_constexpr_lambda_templ()\n+{\n+  auto cl = [](bool b) constexpr {\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+    return a;\n+  };\n+  constexpr int v0 = cl(true); /* { dg-error \"'do_constexpr_lambda_templ<void>\\\\\\(\\\\\\)::<lambda\\\\\\(bool\\\\\\)>' called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+  constexpr int v1 = [](bool b) constexpr {\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+    return a;\n+  }(true);\n+}\n+template void do_constexpr_lambda_templ<void>();\n+\n+template<typename>\n+void do_constexpr_generic_lambda_templ()\n+{\n+  auto cl = [](auto b) constexpr {\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+    return a;\n+  };\n+  constexpr int v0 = cl(true); /* { dg-error \"'do_constexpr_lambda_templ<void>\\\\\\(\\\\\\)::<lambda\\\\\\(bool\\\\\\)>' called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+  constexpr int v1 = [](auto b) constexpr {\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+    return a;\n+  }(true);\n+}\n+template void do_constexpr_generic_lambda_templ<void>();\n+\n+template<typename>\n+void do_lambda_templ()\n+{\n+  auto cl = [](bool b){\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+    return a;\n+  };\n+  constexpr int v0 = cl(true); /* { dg-error \"'do_lambda_templ<void>\\\\\\(\\\\\\)::<lambda\\\\\\(bool\\\\\\)>' called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+  constexpr int v1 = [](bool b){\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+    return a;\n+  }(true);\n+}\n+template void do_lambda_templ<void>();\n+\n+template<typename>\n+void do_generic_lambda_templ()\n+{\n+  auto cl = [](auto b){\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+    return a;\n+  };\n+  constexpr int v0 = cl(true); /* { dg-error \"'do_generic_lambda_templ<void>\\\\\\(\\\\\\)::<lambda\\\\\\(bool\\\\\\)>' called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+  constexpr int v1 = [](auto b){\n+    if (b)\n+      return 42;\n+    int a = 42;\n+    #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+    return a;\n+  }(true);\n+}\n+template void do_generic_lambda_templ<void>();\n+\n+/* Missing cases where the lambda/lambda body is dependent on the outer\n+   template params.  */\ndiff --git a/gcc/testsuite/g++.dg/gomp/allocate-19.C b/gcc/testsuite/g++.dg/gomp/allocate-19.C\nnew file mode 100644\nindex 00000000000..e99106893da\n--- /dev/null\n+++ b/gcc/testsuite/g++.dg/gomp/allocate-19.C\n@@ -0,0 +1,128 @@\n+/* { dg-do compile { target c++14 } } */\n+/* { dg-additional-options \"-fimplicit-constexpr\" } */\n+\n+/* OpenMP allocate directive in constant expressions where execution does not\n+   pass through the allocation of the variable in the directive.\n+   Regular functions and function templates,\n+   constexpr and inline with -fimplicit-constexpr.\n+\n+   These cases will be valid if/when OpenMP relaxes restrictions on directives\n+   in constexpr functions.  It might make sense to only allow this behavior in\n+   c++23 though.\n+\n+   It doesn't make sense to test these cases in c++11 as constexpr functions\n+   are far more limited, and are diagnosed completely differently.\n+\n+   Even though -fimplicit-constexpr is an extension, its behavior is similar to\n+   lambdas in c++17, so I am including tests for it.\n+   See allocate-18.C for test cases involving lambdas.\n+   \n+   NOTE: The error messages for the inline cases are are probably not what we\n+   want, we likely want something stating that the calls are not usable in a\n+   constant expression because of the use of an OpenMP directive.  */\n+\n+constexpr int f_constexpr(bool b)\n+{\n+  if (b)\n+    return 42;\n+  int a = 42;\n+  #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+  return a;\n+}\n+constexpr int g_cx_0 = f_constexpr(true); /* { dg-error \"'constexpr int f_constexpr\\\\\\(bool\\\\\\)' called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+template<typename>\n+constexpr int f_constexpr_templ_uninstantiated(bool b)\n+{\n+  if (b)\n+    return 42;\n+  int a = 42;\n+  #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+  return a;\n+}\n+\n+template<typename>\n+constexpr int f_constexpr_templ(bool b)\n+{\n+  if (b)\n+    return 42;\n+  int a = 42;\n+  #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+  return a;\n+}\n+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 *-*-* } } */\n+\n+template<typename B>\n+constexpr int f_constexpr_dep_parm_templ_uninstantiated(B b)\n+{\n+  if (b)\n+    return 42;\n+  int a = 42;\n+  #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+  return a;\n+}\n+\n+template<typename B>\n+constexpr int f_constexpr_dep_parm_templ(B b)\n+{\n+  if (b)\n+    return 42;\n+  int a = 42;\n+  #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" } */\n+  return a;\n+}\n+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 *-*-* } } */\n+\n+\n+\n+inline int f_inline(bool b)\n+{\n+  if (b)\n+    return 42;\n+  int a = 42;\n+  #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+  return a;\n+}\n+constexpr int g_inline_0 = f_inline(true);  /* { dg-error \"'int f_inline\\\\\\(bool\\\\\\)' called in a constant expression\" \"\" { xfail *-*-* } } */\n+\n+template<typename>\n+inline int f_inline_templ_uninstantiated(bool b)\n+{\n+  if (b)\n+    return 42;\n+  int a = 42;\n+  #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+  return a;\n+}\n+\n+template<typename>\n+inline int f_inline_templ(bool b)\n+{\n+  if (b)\n+    return 42;\n+  int a = 42;\n+  #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+  return a;\n+}\n+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 *-*-* } } */\n+\n+template<typename B>\n+inline int f_inline_dep_parm_templ_uninstantiated(B b)\n+{\n+  if (b)\n+    return 42;\n+  int a = 42;\n+  #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+  return a;\n+}\n+\n+template<typename B>\n+inline int f_inline_dep_parm_templ(B b)\n+{\n+  if (b)\n+    return 42;\n+  int a = 42;\n+  #pragma omp allocate(a) /* { dg-error \"OpenMP directives may not appear in 'constexpr' functions\" \"\" { xfail *-*-* } } */\n+  return a;\n+}\n+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 *-*-* } } */\ndiff --git a/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C b/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C\nindex c0c59a30a3c..786c2f5550e 100644\n--- a/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C\n+++ b/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C\n@@ -15,49 +15,47 @@\n #define GOMP_OMPX_PREDEF_ALLOC_MIN\t200\n #define GOMP_OMPX_PREDEF_ALLOC_MAX\t201\n \n-int g0 = 42; /* { dg-note \"'g0' declared here\" \"\" { xfail *-*-* } } */\n+int g0 = 42; /* { dg-note \"'g0' declared here\" } */\n #pragma omp allocate(g0) allocator(omp_null_allocator)\n /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { target *-*-* } .-1 } */\n-/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail *-*-* } .-2 } */\n+/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target *-*-* } .-2 } */\n /* { dg-note \"expression evaluates to '0'\" \"\" { target *-*-* } .-3 } */\n-int g1 = 42; /* { dg-note \"'g1' declared here\" \"\" { xfail *-*-* } }*/\n+int g1 = 42; /* { dg-note \"'g1' declared here\" } */\n #pragma omp allocate(g1) allocator(static_cast<omp_allocator_handle_t>(GOMP_OMP_PREDEF_ALLOC_MAX + 1)) \n /* { 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 } */\n-/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail *-*-* } .-2 } */\n+/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target *-*-* } .-2 } */\n /* { dg-note \"expression evaluates to '9'\" \"\" { target *-*-* } .-3 } */\n-int g2 = 42; /* { dg-note \"'g2' declared here\" \"\" { xfail *-*-* } }*/\n+int g2 = 42; /* { dg-note \"'g2' declared here\" } */\n #pragma omp allocate(g2) allocator(static_cast<omp_allocator_handle_t>(GOMP_OMPX_PREDEF_ALLOC_MIN - 1))\n /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { target *-*-* } .-1 } */\n-/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail *-*-* } .-2 } */\n+/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target *-*-* } .-2 } */\n /* { dg-note \"expression evaluates to '199'\" \"\" { target *-*-* } .-3 } */\n-int g3 = 42; /* { dg-note \"'g3' declared here\" \"\" { xfail *-*-* } }*/\n+int g3 = 42; /* { dg-note \"'g3' declared here\" } */\n #pragma omp allocate(g3) allocator(static_cast<omp_allocator_handle_t>(GOMP_OMPX_PREDEF_ALLOC_MAX + 1))\n /* { 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 } */\n-/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail *-*-* } .-2 } */\n+/* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target *-*-* } .-2 } */\n /* { dg-note \"expression evaluates to '202'\" \"\" { target *-*-* } .-3 } */\n \n void test_predefined_allocs()\n {\n-  static int a0 = 42; /* { dg-note \"'a0' declared here\" \"\" { xfail *-*-* } }*/\n+  static int a0 = 42; /* { dg-note \"'a0' declared here\" }*/\n   #pragma omp allocate(a0) allocator(omp_null_allocator)\n   /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { target *-*-* } .-1 } */\n-  /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail *-*-* } .-2 } */\n+  /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target *-*-* } .-2 } */\n   /* { dg-note \"expression evaluates to '0'\" \"\" { target *-*-* } .-3 } */\n-  static int a1 = 42; /* { dg-note \"'a1' declared here\" \"\" { xfail *-*-* } }*/\n+  static int a1 = 42; /* { dg-note \"'a1' declared here\" }*/\n   #pragma omp allocate(a1) allocator(static_cast<omp_allocator_handle_t>(GOMP_OMP_PREDEF_ALLOC_MAX + 1))\n   /* { 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 } */\n-  /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail *-*-* } .-2 } */\n+  /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target *-*-* } .-2 } */\n   /* { dg-note \"expression evaluates to '9'\" \"\" { target *-*-* } .-3 } */\n-  static int a2 = 42; /* { dg-note \"'a2' declared here\" \"\" { xfail *-*-* } }*/\n+  static int a2 = 42; /* { dg-note \"'a2' declared here\" }*/\n   #pragma omp allocate(a2) allocator(static_cast<omp_allocator_handle_t>(GOMP_OMPX_PREDEF_ALLOC_MIN - 1))\n   /* { dg-error \"'allocator' clause requires a constant predefined allocator\" \"\" { target *-*-* } .-1 } */\n-  /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail *-*-* } .-2 } */\n+  /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target *-*-* } .-2 } */\n   /* { dg-note \"expression evaluates to '199'\" \"\" { target *-*-* } .-3 } */\n-  static int a3 = 42; /* { dg-note \"'a3' declared here\" \"\" { xfail *-*-* } }*/\n+  static int a3 = 42; /* { dg-note \"'a3' declared here\" }*/\n   #pragma omp allocate(a3) allocator(static_cast<omp_allocator_handle_t>(GOMP_OMPX_PREDEF_ALLOC_MAX + 1))\n   /* { 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 } */\n-  /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail *-*-* } .-2 } */\n+  /* { dg-note \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { target *-*-* } .-2 } */\n   /* { dg-note \"expression evaluates to '202'\" \"\" { target *-*-* } .-3 } */\n }\n-\n-/* { dg-bogus \"because one or more variables with static storage duration appear in the 'allocate' directive\" \"\" { xfail c++ } 0 }*/\n",
    "prefixes": [
        "05/12"
    ]
}