Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/2233047/?format=api
{ "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" ] }