From patchwork Tue May 5 15:01:54 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Waffl3x X-Patchwork-Id: 134487 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 48FE94BA9001 for ; Tue, 5 May 2026 15:11:26 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 48FE94BA9001 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=baylibre-com.20251104.gappssmtp.com header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256 header.s=20251104 header.b=priZw+4+ X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x431.google.com (mail-pf1-x431.google.com [IPv6:2607:f8b0:4864:20::431]) by sourceware.org (Postfix) with ESMTPS id 8BD154BA2E31 for ; Tue, 5 May 2026 15:10:37 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8BD154BA2E31 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=baylibre.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 8BD154BA2E31 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::431 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993837; cv=none; b=qq1/u2GEnf+kLSlFQ42sKKt94Egukm5DYb+p8SVAD2i84n3IGDCgfMtPwJN2aNKwMjR87Uia6A52QCv7OhRnzATrzeEbC+4L213uiBmZEQsGG33q19Gq/DmuqPzyTxKf6IY+E7xH6KkeDatmnwi+wHxj/wi9QZKXrzTaSE3+A3U= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993837; c=relaxed/simple; bh=+zhDDP/jsyveY0C9QaeWR6GDMYCH0rnrkVf8KnNAiPI=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=YMo1g4DDmZVU/y5BQwj7R5w7te5VGVGmQ+Xi47zbJELPKo3NKX9+aGRWWEWwvDDUtiDRbURUYrq365tHCYspopBhLPS967dGXrDh3hWiquF+dqSmokbI0p38AcN9DuAHhpfSimoGBWV9dAXlgxTvg8spzHO7uG3fbU5qA5TWKbM= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8BD154BA2E31 Received: by mail-pf1-x431.google.com with SMTP id d2e1a72fcca58-824bcb2011bso402940b3a.3 for ; Tue, 05 May 2026 08:10:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20251104.gappssmtp.com; s=20251104; t=1777993836; x=1778598636; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=r+1Ny2broxipYqYToQJslnAZ1EsJACdWaE4muYhUivU=; b=priZw+4+exe2kvNUrFNSqr/7KjNV/QIokcJb/91OLopKkV0tDoHbBTRImDESw0HJ5Y F+q/SvvVGBPB38Wxwp7YeUneEsZ41138J12cb9v84S75XpsmWEXmg1nJNgYipK3nbQ+Y ohRIR2vwam6cXHJgzKdsevay/o9XMcIiXopwDxEGytwcYne31TsqeqW+HIbF8mY/JhhR S9jqILU3e+VDNnT+m4fdbG5Y2PYBKzdxeV3WKADGNRnVkAClPwBGIjZt4lOUf/+zme+N i0DR+NdevwhHikksw3hJhguM3HhEWXqFCyeczKjdghRPkAofwa4kaC16Zxb7D7TQ3aGL MEag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777993836; x=1778598636; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=r+1Ny2broxipYqYToQJslnAZ1EsJACdWaE4muYhUivU=; b=aiUDFv8SFTTTZWzuL8JRJnJBO6ieqXIuYxo9SJ2iW3Vde5HAGDBPQJ4YiyWsDmy4FB E4LxGH7V19IVGlhnm1QERqJn7tMwoQKP8fefRjlBLyhwwEZEpyIrnvDokDqJbMw0ERk3 xQXZgxdR3GdI8l+QodAiJP/M9djKX6xrztke8QZASYB4Aj7W0EA6UnWFKcS6fLaEsTHD UTi8zo0pM1JdMtDR/UKmDpCl0dKNTqI0NRrKMMxXNqitj5rHiKk96A5KKJW4lGxtfV1a At8SaCr4QMgRKMg1KjD3fFddwVKArOhq6SnmhHfi1GfCPMzE9hAI49hvSMAfweG8zo7h aodA== X-Gm-Message-State: AOJu0YwMP+pJ364Hz1btOc1bt/QpSZ5700odDFuvEijy4ZHtvib3mhc1 ggeV4Xwf4/PBTqBBCngIJr+9NW7XcIken+lnmSCXWABRYieyFUGMZZIxAh6UCi3AOaSgE3XPLfQ AMkt2 X-Gm-Gg: AeBDiesUoC8uTY03/sPMCfw5G9y+bQhWewfkHU5q+/ys51G9R3nIquLeLj9SsYEyvgc hmUK+ef47J87AzISskIPqlLxui80inTGqR6tgFuLgaOi/6YFlpdexzjXq5ubMLy+XJlGwbNa7T5 AGFZ3JNxSlnzq/GrqumyAz71JgCWZyi4QrGx+2CZ1Zl8r451aB01Uzsw0FnS8EBcsycRFmnxWaJ LB3UuYgJuoPB3HCtTnyEXruckAcCbs3bs8EH0txnTtJ/pyCT10zvl8VIJgqBUfPeqPfLqy72zBn d7Q1RNZr4xLnCXbuMAHITypOwB7TC6k740Q+dJHyZJGrfM5/TRZr/Rk/yGicN5jKwgjlUX9qkYn JyNsFuvZUOYW2ybUAy/7L54RqqvWKsZCYhGlPb2OFmqtvY5LWNZyk0erUILFPRHBn1Vz+TZT0Y8 WY/mxzvniG2yB7ZGPifNjXqG79sEgNf53wmrDnc95FcXxRme8pUA== X-Received: by 2002:a05:6a00:a220:b0:835:3f0b:db71 with SMTP id d2e1a72fcca58-8353f0be322mr6238065b3a.6.1777993836369; Tue, 05 May 2026 08:10:36 -0700 (PDT) Received: from waffl3x-prestige.lan ([2001:56a:f98a:b800:1f67:ce08:3cbd:86b8]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83965645140sm2674956b3a.12.2026.05.05.08.10.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 08:10:35 -0700 (PDT) From: Waffl3x To: gcc-patches@gcc.gnu.org Cc: Waffl3x Subject: [PATCH 01/12] libgomp.c: Change _Alignof to alignof for C++ in test Date: Tue, 5 May 2026 09:01:54 -0600 Message-ID: <20260505151030.1749548-2-waffl3x@baylibre.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505151030.1749548-1-waffl3x@baylibre.com> References: <20260505151030.1749548-1-waffl3x@baylibre.com> MIME-Version: 1.0 X-Spam-Status: No, score=-13.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org One static_assert incorrectly used '_Alignof' instead of 'alignof', this was most likely a typo as 'alignof' was used appropriately elsewhere. This patch changes it to 'alignof' for C++. This was likely missed because this case is not enabled for C++ yet. It will be moved to libgomp.c-c++-common in a later patch. libgomp/ChangeLog: * testsuite/libgomp.c/allocate-7.c: _Alignof to alignof. Signed-off-by: Waffl3x --- libgomp/testsuite/libgomp.c/allocate-7.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libgomp/testsuite/libgomp.c/allocate-7.c b/libgomp/testsuite/libgomp.c/allocate-7.c index e11b8eb32c0..1fa92d889d0 100644 --- a/libgomp/testsuite/libgomp.c/allocate-7.c +++ b/libgomp/testsuite/libgomp.c/allocate-7.c @@ -10,7 +10,7 @@ int AAA [[omp::decl(allocate,allocator(omp_low_lat_mem_alloc),align(4096))]]; #ifndef __cplusplus _Static_assert (_Alignof(AAA) == _Alignof(int), "wrong alignment"); #elif __cplusplus >= 201103L - static_assert (alignof(AAA) == _Alignof(int), "wrong alignment"); + static_assert (alignof(AAA) == alignof(int), "wrong alignment"); #endif From patchwork Tue May 5 15:01:55 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Waffl3x X-Patchwork-Id: 134492 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id B8BCC4BA9035 for ; Tue, 5 May 2026 15:13:17 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B8BCC4BA9035 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=baylibre-com.20251104.gappssmtp.com header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256 header.s=20251104 header.b=VBY5xZOM X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x434.google.com (mail-pf1-x434.google.com [IPv6:2607:f8b0:4864:20::434]) by sourceware.org (Postfix) with ESMTPS id 3FC284BA2E39 for ; Tue, 5 May 2026 15:10:38 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3FC284BA2E39 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=baylibre.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3FC284BA2E39 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::434 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993838; cv=none; b=fR1+OnCqFR/dX4k8i6PmHNofwzkpuXrckL2Iw3Kh/Sui3HtJ5vMhkGbqbA/OW7nUn7LaYBUzDbVNh0MP59zLd5KgCHgLrCv7UWgWOXWIjCGLNjbIIXuadeDtGi0GAib93+n/8dgFiskwJaTQRBz1KU3vYBffeYC/8xhbid/VNrE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993838; c=relaxed/simple; bh=rG6qG13soUXe1TDomKUaMJn5EPPhhQtDJs+rZWsCPk8=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=RHJsTticgGkctjSJvzyelwBSQ/NL5zNdLUl6HcYI8ifNSrp8bgDwaRMuI1UyEXsUqNO0ho5dJnHo2jLFe3J0ktmvj+kgdaT9dxUa10zlP+R7FjUfaPOFM5Ldb7xNcOSPZQ3Mze3naPRxpYT7ocguyi5w8BmmpPYgttvpx7HmusQ= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3FC284BA2E39 Received: by mail-pf1-x434.google.com with SMTP id d2e1a72fcca58-835451c5debso112978b3a.2 for ; Tue, 05 May 2026 08:10:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20251104.gappssmtp.com; s=20251104; t=1777993837; x=1778598637; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=LwZpOnZ2H+00GK4nNSp5wPrrd0izJyeyEHey1wkZGs4=; b=VBY5xZOMmldNkjX4fLpNnzfJOf3jOU/hlePF4sRvATVcQYziLkLA3EqhKEb/y/BHqj ADec5t+ln0JtVlYArr4TmzFhJNxAfo6UTvkS3QdNVLPVg7LtbcGiCMHUN++LZruF1yBr p+BLOSe7GkRky04TJAHmbwWKlNtxhkqBw+9HS/y/eb8XURPqK4vUAmaU0iLXq01b4EOo Mcd3OL8KHdkpaUJoC2IAVEPhUap+cI/XAqvS4nctF5pAhM/rGNOGXfhdBtcw1RoqO9TH Ll5SD3yDNGITbOAUCWtx7K+Z0etJO+S6rt0yy9pFDiJ8jAhr9r3pibD/Y+sqRDBLM6lC 3TuA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777993837; x=1778598637; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=LwZpOnZ2H+00GK4nNSp5wPrrd0izJyeyEHey1wkZGs4=; b=ki1wlr9cz/2E2TGnvLigIK2KLufFrnmD/cSA2qoYfJs0j+l5QSmSzFfB+LLitOddip qrHa1wMSnWY+FqQk1iLfxH3Uj1TVc6C/xzZV+hCl9Ki1iEUL193fgwvB8f9mXwDl9nZh hQG8rkzn2udBBfZQb2/aJ9uYMgRvPfgeO2O85KFtw23bsXBrjpDrBvt+53Hn9Oho/rva jTIuPg3gJ83AimRiUi4FSNBpow1exi/+KOzuxlJ36v+0CMS1TNxtXsZ8Mkujc/7Ufg/o gQi8mAHLt4d4bmgC02rToG+FK1wo8XiXgIzjI7jCvdqalpUTRy8Idly2ZkGMm+Ak50lq JL2A== X-Gm-Message-State: AOJu0Yz4aHB19MTVQn6RzSlHqPgr6ane+/V6a9gSyZEN/rbTJjkgvR/o nafu6M42kOzBtRDA2kWpJ7TwqdPyX1dgIjNHrO0Ex2niX3VZtAGXmFgv5T8chzR6Tu8wlWdw/I8 e6efq X-Gm-Gg: AeBDieu9WN2CDGnCXX5Qjo6RLcE8XnyQzkYmCqfd1z6ho11jnEJXhadXggfDGT+nJCB qi/p+mnYHVUSjKMbXblWCRslETxDbWlu7WpNJMlWGF8jzB3WCXXGf2LnnnQQg19pI3cG7JhfUJt oFt1sEN5LqW92+eOd4S5Mum73McoS4zAr/hRx8o7bWV9PRjTVCP0wHD6vM92OfUF55KjRe+qwyL mZl+S/zIeaJooceQG9y+3wJ/HHZUzxaoosbaIpT1hHYFkHhEqo+hfFjxBVtFv6C3zIh4HRnfZie KzR7qH9yQQBWSnmyzO2B/TH5Qi+kGgzoQh8977p9zSPNKKYds15e5Ph8oNa2bF5Ds/SCo/aHeP5 usAcHbEkquwmvApcps9RwvDddfa3qzYBJaPDhwXXIIlwMWpG0mKtF5OzxJdM47WiGhlCIgrojtZ Vk9UV6BMIpZtqVm8uKnWalczWV0a0GTmFwglE4KujSJhnsCF8QpN5taJRXFZYy X-Received: by 2002:a05:6a00:a803:b0:837:95fc:148d with SMTP id d2e1a72fcca58-83795fc19aamr4420700b3a.0.1777993837252; Tue, 05 May 2026 08:10:37 -0700 (PDT) Received: from waffl3x-prestige.lan ([2001:56a:f98a:b800:1f67:ce08:3cbd:86b8]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83965645140sm2674956b3a.12.2026.05.05.08.10.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 08:10:36 -0700 (PDT) From: Waffl3x To: gcc-patches@gcc.gnu.org Cc: Waffl3x Subject: [PATCH 02/12] OpenMP/C: Change repetitive allocator clause diagnostic wording Date: Tue, 5 May 2026 09:01:55 -0600 Message-ID: <20260505151030.1749548-3-waffl3x@baylibre.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505151030.1749548-1-waffl3x@baylibre.com> References: <20260505151030.1749548-1-waffl3x@baylibre.com> MIME-Version: 1.0 X-Spam-Status: No, score=-13.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org This is specifically for an allocator clause in an allocate directive. The old text, 'allocator' clause allocator expression, does not flow very well. This patch removes the redundant second allocator from the diagnostic. This case reads poorly because the two words are the same, but there are other diagnostics that use the same pattern that we could consider changing as well. For example, 'allocate' clause allocator expression, despite being two different words still feels rather redundant. gcc/c/ChangeLog: * c-parser.cc (c_parser_omp_allocate): Change diagnostic. gcc/testsuite/ChangeLog: * c-c++-common/gomp/allocate-5.c: Match new diagnostic. Signed-off-by: Waffl3x --- gcc/c/c-parser.cc | 2 +- gcc/testsuite/c-c++-common/gomp/allocate-5.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 0b8b2387109..c7b04fb5cf9 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -23488,7 +23488,7 @@ c_parser_omp_allocate (c_parser *parser) != get_identifier ("omp_allocator_handle_t")) { error_at (expr_loc, - "% clause allocator expression has type " + "% clause expression has type " "%qT rather than %", TREE_TYPE (allocator)); allocator = NULL_TREE; diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-5.c b/gcc/testsuite/c-c++-common/gomp/allocate-5.c index 2ca4786264f..09c8e4342f0 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-5.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-5.c @@ -40,7 +40,7 @@ bar () #pragma omp allocate(a) foo(my_allocator) /* { dg-error "expected 'allocator'" } */ /* { dg-error "expected end of line before '\\(' token" "" { target *-*-* } .-1 } */ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */ -#pragma omp allocate(a2) allocator(b) /* { dg-error "'allocator' clause allocator expression has type 'int' rather than 'omp_allocator_handle_t'" "todo: cp/semantics.c" { xfail c++ } } */ +#pragma omp allocate(a2) allocator(b) /* { dg-error "'allocator' clause expression has type 'int' rather than 'omp_allocator_handle_t'" "todo: cp/semantics.c" { xfail c++ } } */ /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ } From patchwork Tue May 5 15:01:56 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Waffl3x X-Patchwork-Id: 134490 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id A1A074B9DB48 for ; Tue, 5 May 2026 15:11:46 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A1A074B9DB48 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=baylibre-com.20251104.gappssmtp.com header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256 header.s=20251104 header.b=dCeazgTw X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x436.google.com (mail-pf1-x436.google.com [IPv6:2607:f8b0:4864:20::436]) by sourceware.org (Postfix) with ESMTPS id 9BFA74BA23F6 for ; Tue, 5 May 2026 15:10:39 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9BFA74BA23F6 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=baylibre.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 9BFA74BA23F6 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::436 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993839; cv=none; b=UKBWpOKzl/K87PzvysC1LXDt/WzQp9SX+cnzmBuSvh/LU/Aq2KKcw0RPNrG1gBfV2gbbTWfT90GgVR2IybRCKKpPJF9F6EEXHhgt65RHrsWzfc5o9Rgjvo/VehUiqwtcGXEj1MF/IcrzURBaMh8V2qNP6sXeZF2Y4v0mDt+nu6c= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993839; c=relaxed/simple; bh=5uDVyM+V78QBMhAG06zjqq7my4+lkK5B+DeOQXP9fn4=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=dM6LYHkB07YQFpeM7BdvGNof7UmgFY2y0EDuWBp+qkpRPWnEfMigD6iA+3tgEb1mlW9VcmWM4vNnoziWODDqgE0vYYF00nnjn+5ajQt2kPLivZo2vBubs37SBdcxmD3UnD25ODiickwDWuGPGq3DzEK30lX0oEqwTJi/Z0e1tjQ= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9BFA74BA23F6 Received: by mail-pf1-x436.google.com with SMTP id d2e1a72fcca58-826c4c6d95dso266076b3a.0 for ; Tue, 05 May 2026 08:10:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20251104.gappssmtp.com; s=20251104; t=1777993838; x=1778598638; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=3JMEH/PgOWQQPvaebZ8C/RP7WfisHsGqHaiguptCQo4=; b=dCeazgTwKEPR/COTFXh4wmmw8qBqQ3QRZUZJ30GJJj8hI1l+S7Gl5A17QdnHud4M+o QCRG8J5ioyAAa3cRPLUCiugal9fER+Y8OqCJ91qlKOUhdwE7wk6v0kOIj67srHOw0OTG w35e5r2gLGbTAAi2FcmWCNpBMoe4E8+J+g7M0ujnJ3B/RcapsIR/zk6n2I376sua0qo7 7MBWXVhn1MKRbopAABtV7YE3Q9dsVBurX1sDP4rX0kBczsf3djAYACg3jdjvd5FifaHi IUH37tRXnVnZyedYxVUIZteKgHPv7jYTdNN1qcirHsofP0zvviiOYLnxNSqIrfNAe5+n vUWA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777993838; x=1778598638; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=3JMEH/PgOWQQPvaebZ8C/RP7WfisHsGqHaiguptCQo4=; b=Jw5aExfbOBU6ac55nl9WslHfdWULLUs7J9tf1jN0pknMpgO9GpOsjvQR7/M4YADnKp mOAFzsS97RxmtHTsANJ3Vz89idDe0ZwVAIACAmFIiWe/sAM1uBON8NRhWUgdHGMuFI0X 2jZZM27JjP+gWnvGYfEOmoGQZOt+Z9tjA71y9kGkwUzFgdyXwtXjHHhExqOD5fg5p/F/ XVvMPBmhvPcOsjmxnUXTbYqpCjDjlzfNuHBAOKySg4lutwdCag7K6ovqAB2CA1D50y75 OwMLiC1hTI/1nxl5Tt2D7eY8yfUOxaklDm0Xlt+zJbyq8zSx5EuZP3J/6W7Sxc7cYTdb Cqtg== X-Gm-Message-State: AOJu0YxozN9Ls+g5TBWDnl8eyJXdicKMw9QdxMNVQcd+G11KogVnyQsb 3CEWsQnlE8Y4Zwb8XZJEyt91MAy40vyfbmtTk9qnkN1k3hNI03neIvTwMPNMX63IrUsh79GYUSF d0wKD X-Gm-Gg: AeBDieuxhsmDytJ5m+6hmzZmxm0IYomj6UYaZsHjA+S18Th7Id3or1V+Z2Th+V6wh5p NtTjuEOV7u2le8B2NXJVGrEdoQGb4ti6z+b36tu9A+LF2bkysme4N10XIPsM1lyRrpmgZXYzT6X MIVUrW4Xr5vGWjdH8NEegOUjj+N6aXqOmAQtOQpox21WfPpshGb7IwtUETekGwpfnJ1EU7u6EmD KW0v1k4UlaNz0D5/IDdMWsjjT6Or/Z/1+7xByn3PgyzFQSa8IKHtO3+OUQg5+zlaiJd3B8mlrti lBSK/AnnVxszyvLS3OOZSrVILgsnIcVLsc5AulrgbETpcrRezsJCA69Qg5aJpYH3pDYN8Pva513 AS+n1d98QWJToy+T0Tjx+A4WCUY1UwO2Z3Hu7j/rfLwho6OBQVP7dU4ZtE0HT5doimkQyxefZXp QdybbVOaV/HPYanDhBcWI//NZ7D2NFRHOZT0J25vofcd36mWRtQA== X-Received: by 2002:a05:6a21:a510:b0:3a3:2819:5d41 with SMTP id adf61e73a8af0-3a7f1c8590amr8179948637.5.1777993838433; Tue, 05 May 2026 08:10:38 -0700 (PDT) Received: from waffl3x-prestige.lan ([2001:56a:f98a:b800:1f67:ce08:3cbd:86b8]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83965645140sm2674956b3a.12.2026.05.05.08.10.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 08:10:37 -0700 (PDT) From: Waffl3x To: gcc-patches@gcc.gnu.org Cc: Waffl3x Subject: [PATCH 03/12] OpenMP/C++: Remove case PRAGMA_OMP_ALLOCATE from cp_parser_omp_construct Date: Tue, 5 May 2026 09:01:56 -0600 Message-ID: <20260505151030.1749548-4-waffl3x@baylibre.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505151030.1749548-1-waffl3x@baylibre.com> References: <20260505151030.1749548-1-waffl3x@baylibre.com> MIME-Version: 1.0 X-Spam-Status: No, score=-13.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org The OpenMP allocate directive is not a construct, and thus is not supposed to be handled by cp_parser_omp_construct, as far as I can tell it never was. With this change PRAGMA_OMP_ALLOCATE will correctly trap if handled here, as such this patch should have no functional impact, merely clarifying intent and preventing future incorrect usage. This also adds a few clarifying comments, based on my interpretation of the code. The significance of the return value of cp_parser_pragma is still not totally clear to me so no general comments are included for it. gcc/cp/ChangeLog: * parser.cc (cp_parser_omp_construct) : Remove. (cp_parser_pragma): Add comments. Signed-off-by: Waffl3x --- gcc/cp/parser.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index dc67cfd9f7c..ed24621452a 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -56537,9 +56537,6 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p) case PRAGMA_OACC_WAIT: stmt = cp_parser_oacc_wait (parser, pragma_tok); break; - case PRAGMA_OMP_ALLOCATE: - cp_parser_omp_allocate (parser, pragma_tok); - return; case PRAGMA_OMP_ATOMIC: cp_parser_omp_atomic (parser, pragma_tok, false); return; @@ -57249,7 +57246,9 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p) cp_parser_omp_construct (parser, pragma_tok, if_p); return true; case PRAGMA_OMP_ALLOCATE: + /* The allocate directive is not a construct. */ cp_parser_omp_allocate (parser, pragma_tok); + /* EOL is handled in cp_parser_omp_allocate, don't break. */ return false; case PRAGMA_OACC_ATOMIC: case PRAGMA_OACC_CACHE: From patchwork Tue May 5 15:01:57 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Waffl3x X-Patchwork-Id: 134498 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 8197A4BA23E4 for ; Tue, 5 May 2026 15:16:56 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8197A4BA23E4 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=baylibre-com.20251104.gappssmtp.com header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256 header.s=20251104 header.b=qCxZ55fG X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x432.google.com (mail-pf1-x432.google.com [IPv6:2607:f8b0:4864:20::432]) by sourceware.org (Postfix) with ESMTPS id 1DD054BA2E31 for ; Tue, 5 May 2026 15:10:42 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1DD054BA2E31 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=baylibre.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 1DD054BA2E31 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::432 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993842; cv=none; b=CWiQPJCpaRYrJbaWj1yACVHsdFMR/va5hfNxUm65uKpWFMZVXLD4MOS2L5hUibkSulmuDFfd23spzpmiU1McdyuK2yLP2+W3FrsgansdrF+jiBHi1tDUyDkkq9T4umgD4NSZ2MtFPNqzggime2RFp5sZ3iNmtHaJfv+nw0HBw3A= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993842; c=relaxed/simple; bh=M4/OipUbCLjljJfiWH4M8jgtZFBYFogsk2ILu3j+thI=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Bcug/l3D8wr15WTvuE+hfaYYB9BqO4GEcpZG1ldM3byJ6UovwkLuKhvj33htzr6bKgeu0LjfwMs/7eb+ZpdZ2aY0WlUm6cqXxQhAhWsNQTprmTbRO/drxpqruxMJya1bRgZlIHgPnpUTvbFapZVLEHxR62OfOSDOHnEH27W7g2k= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1DD054BA2E31 Received: by mail-pf1-x432.google.com with SMTP id d2e1a72fcca58-8368a5d79d3so156665b3a.0 for ; Tue, 05 May 2026 08:10:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20251104.gappssmtp.com; s=20251104; t=1777993841; x=1778598641; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=g3QPF7VO/B48TVRw61bNkeBheXLFivzu04n8gS7biV4=; b=qCxZ55fGjt5pRIP7cY5G1pL7TOeLlE+ObadpvLSOccmFHqO8yF5l6s8dkuzdy72ZXu jjfrxhrNb6nEq82Hcec0kySXajrE65aPC+zCzDA9wZ710aYqouT+rpcIBh6KXSB6O/mN luShqt8hfkJ+m69I1At3LRcA6uh2M0gAroJczghDI3qywaSeTPAD5QSYpu7wzMRdzZTq zSfYOduysgttQdV3ixbh4p+VA+x05SnfhhXxEjUFOoaQwkIhmRGUKgGxCSKFa2nTc817 o3zg6PmOp5wKe5Od7+dTX0mwr2FH1qmesDCgV/PsepHudK3ABnlvcdMDJiBYy3dJQWrU e7MA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777993841; x=1778598641; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=g3QPF7VO/B48TVRw61bNkeBheXLFivzu04n8gS7biV4=; b=HoUSoquoOi9QRpiLkQrPbNRLyurMGytFELDMGdga0Tm8arz70xJ60p1w/peVxe8Zwz uLMqOJeYpPrq6WaXkTmdOfui2CPeP61TThoO5oI0PMGS5vvs2XorTRUatLPD5+e0GSOQ cAAz4H+BzuMG0HsLvkpnUxd0smrxNijHP6g3dDXwtq/ovNRynwYonS8knSkiX9XlTZX8 Q5Ee3zXDvnw53U/miAwmD7W+sTc1kzqjBT/Fp2O7cbThtFewqC+oa/jvp+1qDe4pcngk ueIbrDIxC75lLF3bsN+COAVfiD2fGe5X0f7HNyM07gjC99HWks1torl03kN7COQAC4Mx 4+4A== X-Gm-Message-State: AOJu0YxafyEume2yxRtWYs04H1+rcpvZskYmbUBd5u+JPs1pYcnrRZG4 vwqCTU+4FEaFTXJKTiI6Qp1iiLW1K3owGazZt911xoC7bIxBubqFL6qwHWaAIxXlG9BwvlMWcVx Sr1dZ X-Gm-Gg: AeBDievl5czXQ6JTLged5m69Amr3P7QWF7TWleiWkf71K1utnogLldGii+OkkE7CYus SQDoS65lL4GCe16fXPJOFaypjsEGBH4hXrae5blvT+UDuoamQOdSMf55UKQqgVON8pF/slDLizd OrtLF6ONBE34iMSXT03A0h113ThHIvy2Tly5EzMsOs0sxkV9Iz1RYCyBL05a4G0pW1CM7m3uzpA X7qZRamkJs63GNBZ9hoXRDaealkl0qHV1A3+rO0nKb5JRdlpGaWg+FKrshxUl8QAusZA5qo8yq+ Cf+Msclo+G5oj23MO9HjC9P1mRHQbzL4Jlsn3Jn74p/eW7O5rjrxTUEEScuSc1xjCc52/IeTbX+ CLizQoxc1BqbNRFpIDXBPIJ4fu0bU/sJbSTEVHjjmTORsnn6MFq+7cWgFi7rcDSzwixW+Dvor85 cpuDzY0ifY7SItxt0CZcdUhuWfB3gCf8wS3dXUMoYISicwq47MHA== X-Received: by 2002:a05:6a00:760d:b0:835:36f2:7332 with SMTP id d2e1a72fcca58-83536f27ff9mr5052063b3a.2.1777993839821; Tue, 05 May 2026 08:10:39 -0700 (PDT) Received: from waffl3x-prestige.lan ([2001:56a:f98a:b800:1f67:ce08:3cbd:86b8]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83965645140sm2674956b3a.12.2026.05.05.08.10.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 08:10:39 -0700 (PDT) From: Waffl3x To: gcc-patches@gcc.gnu.org Cc: Waffl3x Subject: [PATCH 04/12] OpenMP/C++: Add support for 'omp allocate' directive Date: Tue, 5 May 2026 09:01:57 -0600 Message-ID: <20260505151030.1749548-5-waffl3x@baylibre.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505151030.1749548-1-waffl3x@baylibre.com> References: <20260505151030.1749548-1-waffl3x@baylibre.com> MIME-Version: 1.0 X-Spam-Status: No, score=-12.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, POISEN_SPAM_PILL, POISEN_SPAM_PILL_1, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org This patch adds support for the 'omp allocate' directive in C++. In parity with the C front end, each variable found in an allocate directive has an 'omp allocate' attribute added to it to mark it for transformation during lowering. This patch makes minimal modifications to gimplification aside from clearing C++ specific diagnostic information. This attribute is added to VAR_DECL nodes during parsing to ensure correct diagnostics. Due to the nature of this feature, the 'omp allocate' attribute is parsed after each VAR_DECL, thus care must be taken to preserve ordering with regards to dependent attributes and non-dependent attributes. This is fairly brittle, but appears to be a better solution than marking the attribute itself dependent to avoid copying the attribute each time the VAR_DECL is substituted into. A new tree code, OMP_ALLOCATE, is added for use during substitution; it should not persist after a template is instantiated. The clauses attached to the allocate directive are stored in this node. Implementing substitution this way allows it to be done once per directive, which additionally allows us to emit less repetitive and more informative diagnostics. This implementation diverges from the C front end in a few ways due to discussions with the OpenMP committee clarifying intended behavior. Where the C front end requires the exact type in a clause, this patch allows implicit conversions. Clauses are morally function calls and its arguments should be treated as if they are binding to a parameter of the clause. This patch, given it is meant to introduce support, defers diagnostics of clause arguments in templates until instantiation. Many cases likely work simply by checking for value dependence of the clause argument instead of merely checking processing_template_decl, however, there were difficulties performing implicit conversions before instantiation. Due to these issues and for simplicity, such enhancements have been deferred to a later patch. Finalization of each VAR_DECL's 'omp allocate' attribute is always done during instantiation. While it is technically possible to do so earlier, the conditions are slightly more complex than simply checking if the clause arguments are non-dependent. In particular, the expr in an allocator clause argument that is non-constant must not have local variables as those nodes are not stable during substitution, even if they are non-dependent. This enhancement is relatively minor and thus not a priority. As an aside, the allocator clause expr is considered manifestly constant evaluated if there is a static local variable in the allocate directive's arguments. While somewhat unintuitive, as it changes the semantics for each variable, I believe that this best reflects the specification. Static member variables in class templates have not been tested, and were considered outside of the scope of this patch. gcc/cp/ChangeLog: * constexpr.cc (cxx_eval_constant_expression) : New. (potential_constant_expression_1) : New. * cp-tree.def (OMP_ALLOCATE): New tree code. * cp-tree.h (OMP_ALLOCATE_VARS): Define. (OMP_ALLOCATE_ALLOCATOR): Define. (OMP_ALLOCATE_ALIGN): Define. (finish_omp_allocate): New declaration. * parser.cc (cp_parser_omp_allocate): Rework, remove sorry, call finish_omp_allocate. * pt.cc (tsubst_stmt) : New. * semantics.cc (finish_omp_allocate): New definition. gcc/ChangeLog: * gimplify.cc (gimplify_bind_expr): Add minor C++ specific checks. libgomp/ChangeLog: * testsuite/libgomp.c/allocate-4.c: Move to... * testsuite/libgomp.c-c++-common/allocate-4.c: ...here. * testsuite/libgomp.c/allocate-5.c: Move to... * testsuite/libgomp.c-c++-common/allocate-5.c: ...here. * testsuite/libgomp.c/allocate-6.c: Move to... * testsuite/libgomp.c-c++-common/allocate-6.c: ...here. * testsuite/libgomp.c/allocate-7.c: Move to... * testsuite/libgomp.c-c++-common/allocate-7.c: ...here. * testsuite/libgomp.c++/allocate-2.C: New test. gcc/testsuite/ChangeLog: * c-c++-common/gomp/allocate-5.c: Modify for C++, remove sorry. * c-c++-common/gomp/allocate-9.c: Use header, add dg-line modify for C++, remove sorry. * c-c++-common/gomp/allocate-10.c: Enable for C++, add dg-bogus. * c-c++-common/gomp/allocate-11.c: Enable and xfail for C++, add -Wno-switch-unreachable. * c-c++-common/gomp/allocate-12.c: Enable for C++, add new xfailing cases, xfail C++ cases. * c-c++-common/gomp/allocate-14.c: Enable for C++. * c-c++-common/gomp/allocate-15.c: Enable for C++. * c-c++-common/gomp/allocate-16.c: Minor changes, enable for C++, xfail C++ cases. * c-c++-common/gomp/allocate-17.c: Remove sorry. * c-c++-common/gomp/allocate-18.c: Use header, remove sorry. * c-c++-common/gomp/allocate-19.c: Remove sorry, add C++ diags. * c-c++-common/gomp/allocate-allocator-handle.h: New header. * c-c++-common/gomp/directive-1.c: Remove sorry. * c-c++-common/gomp/uses_allocators-1.c: Remove sorry. * g++.dg/gomp/allocate-5.C: New test. * g++.dg/gomp/allocate-6.C: New test. * g++.dg/gomp/allocate-7.C: New test. * g++.dg/gomp/allocate-8.C: New test. * g++.dg/gomp/allocate-9.C: New test. * g++.dg/gomp/allocate-10.C: New test. * g++.dg/gomp/allocate-11.C: New test. * g++.dg/gomp/allocate-12.C: New test. * g++.dg/gomp/allocate-13.C: New test. * g++.dg/gomp/allocate-handles-1.C: New test. * g++.dg/gomp/allocate-handles-2.C: New test. * g++.dg/gomp/allocate-allocator-handle.h: New header. Signed-off-by: Waffl3x --- gcc/cp/constexpr.cc | 2 + gcc/cp/cp-tree.def | 11 + gcc/cp/cp-tree.h | 17 + gcc/cp/parser.cc | 138 +++--- gcc/cp/pt.cc | 26 ++ gcc/cp/semantics.cc | 326 ++++++++++++++ gcc/gimplify.cc | 10 +- gcc/testsuite/c-c++-common/gomp/allocate-10.c | 5 +- gcc/testsuite/c-c++-common/gomp/allocate-11.c | 29 +- gcc/testsuite/c-c++-common/gomp/allocate-12.c | 39 +- gcc/testsuite/c-c++-common/gomp/allocate-14.c | 3 - gcc/testsuite/c-c++-common/gomp/allocate-15.c | 3 - gcc/testsuite/c-c++-common/gomp/allocate-16.c | 21 +- gcc/testsuite/c-c++-common/gomp/allocate-17.c | 2 +- gcc/testsuite/c-c++-common/gomp/allocate-18.c | 18 +- gcc/testsuite/c-c++-common/gomp/allocate-19.c | 27 +- gcc/testsuite/c-c++-common/gomp/allocate-5.c | 31 +- gcc/testsuite/c-c++-common/gomp/allocate-9.c | 88 ++-- .../gomp/allocate-allocator-handle.h | 19 + gcc/testsuite/c-c++-common/gomp/directive-1.c | 1 - .../c-c++-common/gomp/uses_allocators-1.c | 4 +- gcc/testsuite/g++.dg/gomp/allocate-10.C | 115 +++++ gcc/testsuite/g++.dg/gomp/allocate-11.C | 18 + gcc/testsuite/g++.dg/gomp/allocate-12.C | 38 ++ gcc/testsuite/g++.dg/gomp/allocate-13.C | 28 ++ gcc/testsuite/g++.dg/gomp/allocate-5.C | 411 ++++++++++++++++++ gcc/testsuite/g++.dg/gomp/allocate-6.C | 392 +++++++++++++++++ gcc/testsuite/g++.dg/gomp/allocate-7.C | 222 ++++++++++ gcc/testsuite/g++.dg/gomp/allocate-8.C | 48 ++ gcc/testsuite/g++.dg/gomp/allocate-9.C | 78 ++++ .../g++.dg/gomp/allocate-allocator-handle.h | 18 + .../g++.dg/gomp/allocate-handles-1.C | 63 +++ .../g++.dg/gomp/allocate-handles-2.C | 45 ++ libgomp/testsuite/libgomp.c++/allocate-2.C | 329 ++++++++++++++ .../allocate-4.c | 3 - .../allocate-5.c | 3 - .../allocate-6.c | 3 - .../allocate-7.c | 3 - 38 files changed, 2435 insertions(+), 202 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/allocate-allocator-handle.h create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-10.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-11.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-12.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-13.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-5.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-6.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-7.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-8.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-9.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-allocator-handle.h create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-handles-1.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-handles-2.C create mode 100644 libgomp/testsuite/libgomp.c++/allocate-2.C rename libgomp/testsuite/{libgomp.c => libgomp.c-c++-common}/allocate-4.c (95%) rename libgomp/testsuite/{libgomp.c => libgomp.c-c++-common}/allocate-5.c (96%) rename libgomp/testsuite/{libgomp.c => libgomp.c-c++-common}/allocate-6.c (98%) rename libgomp/testsuite/{libgomp.c => libgomp.c-c++-common}/allocate-7.c (90%) diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index e9388a6ba7f..43d9037eeb5 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -10620,6 +10620,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, case OMP_ATOMIC_CAPTURE_OLD: case OMP_ATOMIC_CAPTURE_NEW: case OMP_DEPOBJ: + case OMP_ALLOCATE: case OACC_PARALLEL: case OACC_KERNELS: case OACC_SERIAL: @@ -12491,6 +12492,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, bool now, case OMP_ATOMIC_CAPTURE_OLD: case OMP_ATOMIC_CAPTURE_NEW: case OMP_DEPOBJ: + case OMP_ALLOCATE: case OACC_PARALLEL: case OACC_KERNELS: case OACC_SERIAL: diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 3826b143a96..47f29bada24 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -495,6 +495,17 @@ DEFTREECODE (TEMPLATE_INFO, "template_info", tcc_exceptional, 0) Operand 1: OMP_DEPOBJ_CLAUSES: List of clauses. */ DEFTREECODE (OMP_DEPOBJ, "omp_depobj", tcc_statement, 2) +/* OpenMP - #pragma omp allocate + Underlying node type is tree_exp, used to represent the directive as a + statement in a function. Only used for template instantiation. + Operand 0: OMP_ALLOCATE_VARS: tree_list containing each var_decl passed to + the directive as an args, purpose contains the + var_decl, value contains a expr that holds the + location where the var was passed in. + Operand 1: OMP_ALLOCATE_ALLOCATOR: Expr of the allocator clause. + Operand 2: OMP_ALLOCATE_ALIGN: Expr of the align clause. */ +DEFTREECODE (OMP_ALLOCATE, "omp_allocate", tcc_statement, 3) + /* Extensions for Concepts. */ /* Used to represent information associated with constrained declarations. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 70132b586d8..d8433a0519e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -6005,6 +6005,21 @@ target_expr_needs_replace (tree t) #define OMP_DEPOBJ_DEPOBJ(NODE) TREE_OPERAND (OMP_DEPOBJ_CHECK (NODE), 0) #define OMP_DEPOBJ_CLAUSES(NODE) TREE_OPERAND (OMP_DEPOBJ_CHECK (NODE), 1) +/* OMP_ALLOCATE accessors. + #pragma omp allocate(var1, var2) allocator(Expr) align(Expr) */ +/* Contains a tree_list containing each variable passed as an argument to the + allocate directive. The purpose holds the var_decl, the value holds an expr + containing the location the var was passed as an argument. */ +#define OMP_ALLOCATE_VARS(NODE) (TREE_OPERAND (OMP_ALLOCATE_CHECK (NODE), 0)) +/* Contains the expression passed in the allocator clause, may be NULL_TREE if + no clause was provided, or error_mark_node if errors occurred. */ +#define OMP_ALLOCATE_ALLOCATOR(NODE) \ + (TREE_OPERAND (OMP_ALLOCATE_CHECK (NODE), 1)) +/* Contains the expression passed in the align clause, may be NULL_TREE if no + clause was provided, or error_mark_node if errors occurred. */ +#define OMP_ALLOCATE_ALIGN(NODE) \ + (TREE_OPERAND (OMP_ALLOCATE_CHECK (NODE), 2)) + /* An enumeration of the kind of tags that C++ accepts. */ enum tag_types { none_type = 0, /* Not a tag type. */ @@ -8562,6 +8577,8 @@ extern tree finish_omp_for (location_t, enum tree_code, tree, tree, tree, tree, tree, tree, tree, vec *, tree); extern tree finish_omp_for_block (tree, tree); +extern void finish_omp_allocate (location_t, tree, tree, tree, + tree); extern void finish_omp_atomic (location_t, enum tree_code, enum tree_code, tree, tree, tree, tree, tree, tree, tree, diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index ed24621452a..2cec22a9386 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -47184,11 +47184,85 @@ cp_parser_omp_structured_block (cp_parser *parser, bool *if_p) static void cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) { - tree allocator = NULL_TREE; - tree alignment = NULL_TREE; - location_t loc = pragma_tok->location; - tree nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_ALLOCATE, NULL_TREE); + tree nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL_TREE); + + { + /* The head might have an error and need to be removed. */ + tree *chain = &nl; + for (tree node = nl; node != NULL_TREE; node = TREE_CHAIN (node)) + { + const tree var = TREE_PURPOSE (node); + const tree arg_loc_wrapper = TREE_VALUE (node); + const location_t arg_loc = EXPR_LOCATION (arg_loc_wrapper); + + tree attr = lookup_attribute ("omp allocate", + DECL_ATTRIBUTES (var)); + if (attr) + { + auto_diagnostic_group d; + error_at (arg_loc, + "%qD already appeared as list item in an " + "% directive", var); + const location_t old_arg_loc = [&] () + { + tree attr_value = TREE_VALUE (attr); + if (TREE_CODE (attr_value) == NOP_EXPR) + return EXPR_LOCATION (attr_value); + /* If the previous directive that has this var as an arg was + already finished by finish_omp_allocate, attr_value is a + tree_list instead. */ + gcc_assert (TREE_CODE (attr_value) == TREE_LIST); + /* In this case the location wrapper is stored differently. */ + return EXPR_LOCATION (TREE_CHAIN (attr_value)); + } (); /* IILE. */ + inform (old_arg_loc, + "%qD previously appeared here", var); + /* Remove the node. */ + *chain = TREE_CHAIN (node); + } + else + { + /* Mark the variable as having appeared in an allocate directive. + Do this even if any of the clauses are dependent, we need to + know this variable appeared in a directive before instantiation + to emit correct diagnostics. Stash the arg's location here for + better diagnostics. + + There is a lot of subtle complexity here because the directive + syntactically appears after the declarations of its arguments, + so processing this directive only starts after the arguments + have been processed. This much is obvious, the issue is adding + an attribute to each VAR_DECL after they have been processed is + fairly intrusive, we need to take care to not break invariants + that those processes set up. In particular, attributes are + ordered by dependency, dependent first, non-dependent after. + There are parts of the compiler that expect this ordering. If + we naively chain the "omp allocate" attr to the front it will + effectively shadow dependent attributes, and if we chain it to + the end we will overwrite data in non-dependent attributes. + The solution is to chain it after the last dependent attribute, + this is still fairly brittle but that is the consequence of this + feature. */ + { + tree *const attr_chain = [&] () + { + tree *p = &DECL_ATTRIBUTES (var); + while (*p != NULL_TREE && ATTR_IS_DEPENDENT (*p)) + p = &TREE_CHAIN (*p); + return p; + } (); /* IILE. */ + *attr_chain = tree_cons (get_identifier ("omp allocate"), + arg_loc_wrapper, + *attr_chain); + } + /* Keep the node. */ + chain = &TREE_CHAIN (node); + } + } + } + cp_expr allocator = NULL_TREE; + cp_expr alignment = NULL_TREE; do { if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA) @@ -47209,70 +47283,30 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) } if (!parens.require_open (parser)) break; - tree expr = cp_parser_assignment_expression (parser); + cp_expr expr = cp_parser_assignment_expression (parser); if (p[2] == 'i' && alignment) { error_at (cloc, "too many %qs clauses", "align"); break; } else if (p[2] == 'i') - { - if (expr != error_mark_node) - alignment = expr; - /* FIXME: Remove when adding check to semantics.cc; cf FIXME below. */ - if (alignment - && !type_dependent_expression_p (alignment) - && !INTEGRAL_TYPE_P (TREE_TYPE (alignment))) - { - error_at (cloc, "% clause argument needs to be " - "positive constant power of two integer " - "expression"); - alignment = NULL_TREE; - } - else if (alignment) - { - alignment = mark_rvalue_use (alignment); - if (!processing_template_decl) - { - alignment = maybe_constant_value (alignment); - if (TREE_CODE (alignment) != INTEGER_CST - || !tree_fits_uhwi_p (alignment) - || !integer_pow2p (alignment)) - { - error_at (cloc, "% clause argument needs to be " - "positive constant power of two integer " - "expression"); - alignment = NULL_TREE; - } - } - } - } + alignment = expr; else if (allocator) { error_at (cloc, "too many %qs clauses", "allocator"); break; } else - { - if (expr != error_mark_node) - allocator = expr; - } + allocator = expr; parens.require_close (parser); } while (true); cp_parser_require_pragma_eol (parser, pragma_tok); - if (allocator || alignment) - for (tree c = nl; c != NULL_TREE; c = OMP_CLAUSE_CHAIN (c)) - { - OMP_CLAUSE_ALLOCATE_ALLOCATOR (c) = allocator; - OMP_CLAUSE_ALLOCATE_ALIGN (c) = alignment; - } - - /* FIXME: When implementing properly, delete the align/allocate expr error - check above and add one in semantics.cc (to properly handle templates). - Base this on the allocator/align modifiers check for the 'allocate' clause - in semantics.cc's finish_omp_clauses. */ - sorry_at (loc, "%<#pragma omp allocate%> not yet supported"); + finish_omp_allocate (pragma_tok->location, + nl, + allocator, + alignment, + current_scope ()); } /* OpenMP 2.5: diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 05ecda2a0d8..aa41a46e007 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -20466,6 +20466,32 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) OMP_DEPOBJ_CLAUSES (t)); break; + case OMP_ALLOCATE: + { + gcc_assert (flag_openmp); + + tree alloc + = tsubst_expr (OMP_ALLOCATE_ALLOCATOR (t), args, complain, in_decl); + tree align + = tsubst_expr (OMP_ALLOCATE_ALIGN (t), args, complain, in_decl); + tree vars = copy_list (OMP_ALLOCATE_VARS (t)); + for (tree node = vars; node != NULL_TREE; node = TREE_CHAIN (node)) + { + if (TREE_PURPOSE (node) == error_mark_node) + continue; + /* The var was already substituted, just look up the new node. */ + tree var = lookup_name (DECL_NAME (TREE_PURPOSE (node)), + LOOK_where::BLOCK, LOOK_want::NORMAL); + /* There's a weird edge case where lookup_name returns NULL_TREE, + but only for incorrect code. Even so, handle NULL_TREE to avoid + segfaulting in those cases. */ + TREE_PURPOSE (node) = var ? var : error_mark_node; + /* Don't copy the attr here, let finish_omp_allocate handle it. */ + } + finish_omp_allocate (EXPR_LOCATION (t), vars, alloc, align, + current_scope ()); + break; + } case OACC_DATA: case OMP_TARGET_DATA: case OMP_TARGET: diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 92ec4836a6f..ac81bbe9317 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -12354,6 +12354,332 @@ finish_omp_for_block (tree bind, tree omp_for) return bind; } +/* Validate an OpenMP allocate directive, then add the ALLOC and ALIGN exprs to + the "omp allocate" attr of each decl found in VARS. The value of attr is + a TREE_LIST with ALLOC stored in its purpose member and ALIGN stored in its + value member. ALLOC and ALIGN are exprs passed as arguments to the + allocator and align clauses of the directive. VARS may be NULL_TREE if + there were errors during parsing. + #pragma omp allocate(VARS) allocator(ALLOC) align(ALIGN) + + If processing_template_decl, a stmt of tree_code OMP_ALLOCATE is added to + the function instead. LOC is used to initialize EXPR_LOCATION of the stmt. + + If any errors occur, the "omp allocate" attr is marked so the middle end + knows to skip it during gimplification. */ + +void +finish_omp_allocate (const location_t loc, const tree var_list, + const tree alloc_in, const tree align_in, + const tree context) +{ + /* Takes a VAR_DECL. */ + using var_predicate = bool (*)(const_tree); + const auto any_of_vars = [&var_list] (var_predicate predicate) + { + for (tree vn = var_list; vn != NULL_TREE; vn = TREE_CHAIN (vn)) + if (predicate (TREE_PURPOSE (vn))) + return true; + return false; + }; + const bool global = !DECL_DECLARES_FUNCTION_P (context); + const var_predicate tree_static_p = [&] () -> var_predicate + { + /* If this directive is not in a function, all the vars are static. */ + if (global) + return [] (const_tree) -> bool { return true; }; + else + return [] (const_tree t) -> bool { return TREE_STATIC (t); }; + } (); /* IILE. */ + const bool any_static_vars = any_of_vars (tree_static_p); + + /* (OpenMP 5.2, 174:15) Type: expression of integer type + Properties: constant, positive */ + const tree align = [&align_in] () + { + if (!align_in || align_in == error_mark_node) + return align_in; + + auto emit_align_err = [&align_in] () + { + error_at (EXPR_LOCATION (align_in), + "% clause argument needs to be positive constant " + "power of two integer expression"); + }; + if (processing_template_decl) + return align_in; + + /* Identity conversions are okay. */ + const tree converted_align + = build_converted_constant_expr (size_type_node, align_in, tf_error); + gcc_assert (converted_align != NULL_TREE); + if (converted_align == error_mark_node) + { + emit_align_err (); + return error_mark_node; + } + + const tree folded_align = cxx_constant_value (converted_align); + if (folded_align == error_mark_node) + { + emit_align_err (); + return error_mark_node; + } + gcc_assert (TREE_CONSTANT (folded_align)); + /* (OpenMP 5.2, 175:10) alignment must evaluate to a power of two. */ + if (tree_int_cst_sgn (folded_align) != 1 + || !integer_pow2p (folded_align)) + { + emit_align_err (); + return error_mark_node; + } + return folded_align; + } (); /* IILE. */ + + /* (OpenMP 5.2, 175:17) Type: expression of allocator_handle type + Properties: default */ + const tree alloc = [&] () + { + if (alloc_in == error_mark_node) + return error_mark_node; + /* (OpenMP 5.2 176:26-28) + If a list item has static storage duration, the allocator clause must + be specified and the allocator expression in the clause must be a + constant expression that evaluates to one of the predefined memory + allocator values. */ + const auto emit_diag_for_static_vars = [&] () + { + inform (UNKNOWN_LOCATION, + "because one or more variables with static storage duration " + "appear in the % directive"); + }; + if (alloc_in == NULL_TREE) + { + if (!any_static_vars) + return NULL_TREE; + else + { + auto_diagnostic_group d; + error_at (loc, "% clause must be specified"); + emit_diag_for_static_vars (); + return error_mark_node; + } + gcc_unreachable (); + } + if (processing_template_decl) + return alloc_in; + + const tree alloc_type = [&] () + { + static tree cached_alloc_type = NULL_TREE; + if (cached_alloc_type != NULL_TREE) + return cached_alloc_type; + + const tree alloc_type_decl + = lookup_qualified_name (global_namespace, + get_identifier ("omp_allocator_handle_t"), + LOOK_want::TYPE); + /* User didn't include omp.h... */ + if (alloc_type_decl == error_mark_node) + { + /* We need to wait until instantiation to complain about it if + alloc_in could possibly be well-formed. */ + if (processing_template_decl + && (type_dependent_expression_p (alloc_in) + /* No one sane would have a conversion template and + use it this way, but it would still technically be + correct so we have to account for it. */ + || (CLASS_TYPE_P (TREE_TYPE (alloc_in)) + && TYPE_HAS_CONVERSION (TREE_TYPE (alloc_in))))) + { + gcc_assert (cached_alloc_type == NULL_TREE); + return cached_alloc_type; + } + auto_diagnostic_group d; + error_at (EXPR_LOCATION (alloc_in), + "% clause requires a valid declaration " + "of %"); + inform (EXPR_LOCATION (alloc_in), + "% is defined in header " + "%<%>; this is probably fixable by adding " + "%<#include %>"); + cached_alloc_type = error_mark_node; + return cached_alloc_type; + } + const auto underlying_type_is_valid = [] (const const_tree type) + { + const const_tree canonical_type = TYPE_CANONICAL (type); + if (cxx_dialect >= cxx11) + return canonical_type == uintptr_type_node; + gcc_assert (cxx_dialect < cxx11); + /* Pre c++11 we can't just assume the underlying type. */ + return TYPE_UNSIGNED (canonical_type) == true + && wi::to_widest (TYPE_SIZE (canonical_type)) + == wi::to_widest (TYPE_SIZE (uintptr_type_node)) + && wi::to_widest (TYPE_MIN_VALUE (canonical_type)) + == wi::to_widest (TYPE_MIN_VALUE (uintptr_type_node)) + && wi::to_widest (TYPE_MAX_VALUE (canonical_type)) + == wi::to_widest (TYPE_MAX_VALUE (uintptr_type_node)); + }; + const tree alloc_type = TREE_TYPE (alloc_type_decl); + if (TREE_CODE (alloc_type) != ENUMERAL_TYPE + || !underlying_type_is_valid (TREE_TYPE (alloc_type))) + { + auto_diagnostic_group d; + error_at (EXPR_LOCATION (alloc_in), + "% clause requires a valid declaration " + "of %"); + /* This diagnostic is not very good, especially if it somehow + is the declaration in omp.h. */ + inform (DECL_SOURCE_LOCATION (alloc_type_decl), + "invalid type declared here"); + cached_alloc_type = error_mark_node; + } + else + cached_alloc_type = alloc_type; + gcc_assert (cached_alloc_type != NULL_TREE); + return cached_alloc_type; + } (); /* IILE. */ + /* Any sane user will include omp.h before we get here, unfortunately + insane doesn't mean incorrect. */ + if (alloc_type == NULL_TREE) + return alloc_in; + /* We can't do anything meaningful with alloc_in if we lack a valid + omp_allocator_handle_t type. */ + if (alloc_type == error_mark_node) + return error_mark_node; + + /* Identity conversion is okay. */ + const tree converted_alloc + = any_static_vars + ? build_converted_constant_expr (alloc_type, alloc_in, tf_error) + : perform_implicit_conversion (alloc_type, alloc_in, tf_error); + + /* The expr is not manifestly constant-evaluated in this case, only do + simple folding even if it is potentially a constant expression. */ + if (!any_static_vars) + return maybe_fold_non_dependent_expr (converted_alloc, tf_none); + + /* Per OpenMP 5.2 176:26-28 quoted above, the allocator clause is + manifestly constant-evaluated in this case. */ + const tree ret = cxx_constant_value (converted_alloc); + if (ret == error_mark_node) + { + auto_diagnostic_group d; + error_at (EXPR_LOCATION (alloc_in), + "% clause requires a constant " + "predefined allocator"); + emit_diag_for_static_vars (); + return error_mark_node; + } + gcc_assert (TREE_CONSTANT (ret)); + wi::tree_to_widest_ref alloc_value = wi::to_widest (ret); + /* MAX is inclusive. */ + const bool predefined_allocator_p + = (alloc_value >= 1 + && alloc_value <= GOMP_OMP_PREDEF_ALLOC_MAX) + || (alloc_value >= GOMP_OMPX_PREDEF_ALLOC_MIN + && alloc_value <= GOMP_OMPX_PREDEF_ALLOC_MAX); + if (!predefined_allocator_p) + { + auto_diagnostic_group d; + error_at (EXPR_LOCATION (alloc_in), + "% clause requires a constant " + "predefined allocator"); + emit_diag_for_static_vars (); + inform (EXPR_LOCATION (alloc_in), + "expression evaluates to %qwu", tree_to_uhwi (ret)); + return error_mark_node; + } + return ret; + } (); /* IILE. */ + + auto finalize_allocate_attr = [] (tree var, tree alloc, tree align) + { + /* This should only be called once for each var, either after a + diagnostic, or when we are finished with the directive. */ + gcc_assert (var != NULL_TREE && var != error_mark_node); + + /* Replace the old attr in place to maintain the invariants of + DECL_ATTRIBUTES as described in cp_parser_omp_allocate. + Unfortunately lookup_attribute does not return an "iterator" to the + attr so we have to write the lookup ourselves here. */ + tree *const attr_it = [&] () + { + tree *it = &DECL_ATTRIBUTES (var); + for (; *it != NULL_TREE; it = &TREE_CHAIN (*it)) + if (is_attribute_p ("omp allocate", get_attribute_name (*it))) + return it; + gcc_unreachable (); + } (); /* IILE. */ + /* Don't modify the old attr, for various reasons it isn't marked + dependent so substitution does not copy it. */ + const_tree old_attr = *attr_it; + /* There should only be one attr. */ + gcc_checking_assert (!lookup_attribute ("omp allocate", + TREE_CHAIN (old_attr))); + /* This location is where the var was specified in the directive. */ + const tree arg_loc = TREE_VALUE (old_attr); + gcc_assert (arg_loc != NULL_TREE && TREE_CODE (arg_loc) == NOP_EXPR); + /* Smuggle the location, we might still need it for diagnostics, such as + if we are still parsing a function. */ + const tree attr_value = tree_cons (alloc, align, arg_loc); + + /* As noted above, we create the final attr ourselves instead of having + substitution handle it. */ + *attr_it = tree_cons (TREE_PURPOSE (old_attr), + attr_value, + TREE_CHAIN (old_attr)); + }; + auto finalize_var_node_with_error = [&] (tree node) + { + /* We can't remove the attribute, the variable still needs to be marked + in case that we are still parsing a function for the first time. + We avoid handling error_mark_node in varpool_node::finalize_decl by + setting align to NULL_TREE. */ + finalize_allocate_attr (TREE_PURPOSE (node), error_mark_node, NULL_TREE); + /* Prevent further diagnostics for this var. */ + TREE_PURPOSE (node) = error_mark_node; + }; + + /* Even if there have been errors, save the current state, there might be + more to diagnose on a later instantiation. */ + if (processing_template_decl) + { + tree allocate_stmt = make_node (OMP_ALLOCATE); + /* This shouldn't matter, but better to set it anyway. */ + TREE_SIDE_EFFECTS (allocate_stmt) = 0; + SET_EXPR_LOCATION (allocate_stmt, loc); + OMP_ALLOCATE_VARS (allocate_stmt) = var_list; + OMP_ALLOCATE_ALLOCATOR (allocate_stmt) = alloc; + OMP_ALLOCATE_ALIGN (allocate_stmt) = align; + add_stmt (allocate_stmt); + return; + } + else if (alloc == error_mark_node || align == error_mark_node || !var_list + || any_of_vars (&error_operand_p)) + { + /* The directive is fully instantiated, but there were errors. */ + for (tree vn = var_list; vn != NULL_TREE; vn = TREE_CHAIN (vn)) + /* Don't mark vars a second time. */ + if (TREE_PURPOSE (vn) != error_mark_node) + finalize_var_node_with_error (vn); + return; + } + + gcc_assert (!processing_template_decl + && alloc != error_mark_node + && align != error_mark_node + && var_list != NULL_TREE + && !any_of_vars (&error_operand_p)); + + /* We can technically finalize earlier if everything (vars, alloc, align) is + substituted and the alloc expr doesn't contain any local variables, this + isn't worth the added complexity for now though. */ + for (tree vn = var_list; vn != NULL_TREE; vn = TREE_CHAIN (vn)) + finalize_allocate_attr (TREE_PURPOSE (vn), alloc, align); +} + void finish_omp_atomic (location_t loc, enum tree_code code, enum tree_code opcode, tree lhs, tree rhs, tree v, tree lhs1, tree rhs1, tree r, diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 8bfc71315f9..4fa834ed38d 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -1440,11 +1440,19 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p) && DECL_CONTEXT (t) == current_function_decl && TREE_USED (t) && (attr = lookup_attribute ("omp allocate", DECL_ATTRIBUTES (t))) - != NULL_TREE) + != NULL_TREE + /* In C++, bad attributes are marked instead of removed. */ + && TREE_PURPOSE (TREE_VALUE (attr)) != error_mark_node) { gcc_assert (!DECL_HAS_VALUE_EXPR_P (t)); tree alloc = TREE_PURPOSE (TREE_VALUE (attr)); tree align = TREE_VALUE (TREE_VALUE (attr)); + /* The C++ front end smuggles a location through the chain field, + this conflicts with Fortran handling, clear it. */ + if (TREE_CHAIN (TREE_VALUE (attr)) != NULL_TREE + && TREE_CODE (TREE_CHAIN (TREE_VALUE (attr))) == NOP_EXPR) + TREE_CHAIN (TREE_VALUE (attr)) = NULL_TREE; + /* Allocate directives that appear in a target region must specify an allocator clause unless a requires directive with the dynamic_allocators clause is present in the same compilation diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-10.c b/gcc/testsuite/c-c++-common/gomp/allocate-10.c index 7e8f579871c..ed7441b6a04 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-10.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-10.c @@ -1,5 +1,3 @@ -/* TODO: enable for C++ once implemented. */ -/* { dg-do compile { target c } } */ /* { dg-additional-options "-Wall -fdump-tree-gimple" } */ typedef enum omp_allocator_handle_t @@ -23,6 +21,7 @@ void h1() { omp_allocator_handle_t my_handle; + /* { dg-bogus "variable 'my_handle' set but not used" "" { target *-*-* } .-1 } */ int B1[3]; /* { dg-warning "'my_handle' is used uninitialized" } */ /* { dg-warning "variable 'B1' set but not used" "" { target *-*-* } .-1 } */ #pragma omp allocate(B1) allocator(my_handle) @@ -36,6 +35,7 @@ void h2() { omp_allocator_handle_t my_handle; + /* { dg-bogus "variable 'my_handle' set but not used" "" { target *-*-* } .-1 } */ int B2[3]; /* { dg-warning "unused variable 'B2'" } */ #pragma omp allocate(B2) allocator(my_handle) /* No warning as 'B2' is unused */ } @@ -44,6 +44,7 @@ void h3() { omp_allocator_handle_t my_handle; + /* { dg-bogus "variable 'my_handle' set but not used" "" { target *-*-* } .-1 } */ int B3[3] = {1,2,3}; /* { dg-warning "unused variable 'B3'" } */ #pragma omp allocate(B3) allocator(my_handle) /* No warning as 'B3' is unused */ } diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-11.c b/gcc/testsuite/c-c++-common/gomp/allocate-11.c index dceb97f8c5f..dd1bcd9bec8 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-11.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-11.c @@ -1,5 +1,9 @@ -/* TODO: enable for C++ once implemented. */ -/* { dg-do compile { target c } } */ +/* This warning is effectively bogus, it appears to only trigger after UB(?) + triggers an optimization that removes the case labels. We don't actually + want to check for this behavior. If anything we might want to ensure it + doesn't trigger when jumping over a variable found in an allocate directive, + as we are supposed to already diagnose an error for that case. */ +/* { dg-additional-options -Wno-switch-unreachable } */ void bar(); void use (int*); @@ -7,15 +11,14 @@ void use (int*); void f (int i) { - switch (i) /* { dg-note "switch starts here" } */ + switch (i) /* { dg-note "switch starts here" "" { xfail c++ } } */ { - int j; /* { dg-note "'j' declared here" } */ + int j; /* { dg-note "'j' declared here" "" { xfail c++ } } */ #pragma omp allocate(j) - case 42: /* { dg-error "switch jumps over OpenMP 'allocate' allocation" } */ + case 42: /* { dg-error "switch jumps over OpenMP 'allocate' allocation" "" { xfail c++ } } */ bar (); - /* { dg-warning "statement will never be executed \\\[-Wswitch-unreachable\\\]" "" { target *-*-* } .-1 } */ break; - case 51: /* { dg-error "switch jumps over OpenMP 'allocate' allocation" } */ + case 51: /* { dg-error "switch jumps over OpenMP 'allocate' allocation" "" { xfail c++ } } */ use (&j); break; } @@ -25,13 +28,17 @@ int h (int i2) { if (i2 == 5) - goto label; /* { dg-error "jump skips OpenMP 'allocate' allocation" } */ + goto label; /* { dg-error "jump skips OpenMP 'allocate' allocation" "" { xfail c++ } } */ + /* { dg-note "from here" "" { target c++ } .-1 } */ return 5; - int k2; /* { dg-note "'k2' declared here" } */ - int j2 = 4; /* { dg-note "'j2' declared here" } */ + int k2; /* { dg-note "'k2' declared here" "" { xfail c++ } } */ + int j2 = 4; /* { dg-note "'j2' declared here" "" { xfail c++ } } */ + /* { dg-note "crosses initialization of 'int j2'" "" { target c++ } .-1 } */ #pragma omp allocate(k2, j2) -label: /* { dg-note "label 'label' defined here" } */ +label: /* { dg-note "label 'label' defined here" "" { xfail c++ } } */ +// It might make sense to make this bogus, as semantically it's assigning to the pointed at value. +/* { dg-error "jump to label 'label'" "" { target c++ } .-2 } */ k2 = 4; return j2 + k2; } diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-12.c b/gcc/testsuite/c-c++-common/gomp/allocate-12.c index 1b77db9bd6f..6a53770697c 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-12.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-12.c @@ -1,6 +1,3 @@ -/* TODO: enable for C++ once implemented. */ -/* { dg-do compile { target c } } */ - typedef enum omp_allocator_handle_t #if __cplusplus >= 201103L : __UINTPTR_TYPE__ @@ -15,9 +12,33 @@ int f () { omp_allocator_handle_t my_allocator; - int n = 5; /* { dg-note "to be allocated variable declared here" } */ - my_allocator = omp_default_mem_alloc; /* { dg-note "modified here" } */ - #pragma omp allocate(n) allocator(my_allocator) /* { dg-error "variable 'my_allocator' used in the 'allocator' clause must not be modified between declaration of 'n' and its 'allocate' directive" } */ + int n = 5; /* { dg-note "to be allocated variable declared here" "" { xfail c++ } } */ + my_allocator = omp_default_mem_alloc; /* { dg-note "modified here" "" { xfail c++ } } */ + #pragma omp allocate(n) allocator(my_allocator) /* { dg-error "variable 'my_allocator' used in the 'allocator' clause must not be modified between declaration of 'n' and its 'allocate' directive" "" { xfail c++ } } */ + n = 7; + return n; +} + +int +f1 () +{ + omp_allocator_handle_t alloc; + { + int n = 42; /* { dg-note "to be allocated variable declared here" "" { xfail *-*-* } } */ + alloc = omp_default_mem_alloc; /* { dg-note "modified here" "" { xfail *-*-* } } */ + #pragma omp allocate(n) allocator(alloc) /* { dg-error "variable 'alloc' used in the 'allocator' clause must not be modified between declaration of 'n' and its 'allocate' directive" "" { xfail *-*-* } } */ + n = 7; + return n; + } +} + +int +f2 () +{ + omp_allocator_handle_t my_allocator; + int n = 5; /* { dg-note "to be allocated variable declared here" "" { xfail *-*-* } } */ + int hide_mutation = my_allocator = omp_default_mem_alloc; /* { dg-note "modified here" "" { xfail *-*-* } } */ + #pragma omp allocate(n) allocator(my_allocator) /* { dg-error "variable 'my_allocator' used in the 'allocator' clause must not be modified between declaration of 'n' and its 'allocate' directive" "" { xfail *-*-* } } */ n = 7; return n; } @@ -26,9 +47,9 @@ f () int g () { - int n = 5; /* { dg-note "to be allocated variable declared here" } */ - omp_allocator_handle_t my_allocator = omp_low_lat_mem_alloc; /* { dg-note "declared here" } */ - #pragma omp allocate(n) allocator(my_allocator) /* { dg-error "variable 'my_allocator' used in the 'allocator' clause must be declared before 'n'" } */ + int n = 5; /* { dg-note "to be allocated variable declared here" "" { xfail c++ } } */ + omp_allocator_handle_t my_allocator = omp_low_lat_mem_alloc; /* { dg-note "declared here" "" { xfail c++ } } */ + #pragma omp allocate(n) allocator(my_allocator) /* { dg-error "variable 'my_allocator' used in the 'allocator' clause must be declared before 'n'" "" { xfail c++ } } */ n = 7; return n; } diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-14.c b/gcc/testsuite/c-c++-common/gomp/allocate-14.c index 894921a76d5..55f3739acfa 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-14.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-14.c @@ -1,6 +1,3 @@ -/* TODO: enable for C++ once implemented. */ -/* { dg-do compile { target c } } */ - #pragma omp begin declare target void f () diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-15.c b/gcc/testsuite/c-c++-common/gomp/allocate-15.c index 52cb7686b7b..b4487143504 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-15.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-15.c @@ -1,6 +1,3 @@ -/* TODO: enable for C++ once implemented. */ -/* { dg-do compile { target c } } */ - #pragma omp requires dynamic_allocators #pragma omp begin declare target diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-16.c b/gcc/testsuite/c-c++-common/gomp/allocate-16.c index 08738030e6a..7df9a92fd9f 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-16.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-16.c @@ -1,6 +1,3 @@ -/* TODO: enable for C++ once implemented. */ -/* { dg-do compile { target c } } */ - typedef enum omp_allocator_handle_t #if __cplusplus >= 201103L : __UINTPTR_TYPE__ @@ -17,12 +14,15 @@ omp_allocator_handle_t foo(int, int *); void f () { - int v; /* { dg-note "to be allocated variable declared here" } */ - int n = 5; - int a = 1; /* { dg-note "declared here" } */ + int v; /* { dg-note "to be allocated variable declared here" "" { xfail c++ } } */ + static const int n = 5; + int a = 1; + /* { dg-note "declared here" "" { xfail c++ } .-1 } */ int b[n]; + /* { dg-note "declared here" "" { target c++ xfail c++ } .-1 } */ b[a] = 5; - #pragma omp allocate (v) allocator (foo (a, &b[a])) /* { dg-error "variable 'a' used in the 'allocator' clause must be declared before 'v'" } */ + #pragma omp allocate (v) allocator (foo (a, &b[a])) + /* { dg-error "variable 'a' used in the 'allocator' clause must be declared before 'v'" "" { xfail c++ } .-1 } */ } void @@ -32,7 +32,8 @@ g () int a = 1; int b[n]; b[a] = 5; - int v; /* { dg-note "to be allocated variable declared here" } */ - a = 2; /* { dg-note "modified here" } */ - #pragma omp allocate (v) allocator (foo (a, &b[a])) /* { dg-error "variable 'a' used in the 'allocator' clause must not be modified between declaration of 'v' and its 'allocate' directive" } */ + int v; /* { dg-note "to be allocated variable declared here" "" { xfail c++ } } */ + a = 2; /* { dg-note "modified here" "" { xfail c++ } } */ + #pragma omp allocate (v) allocator (foo (a, &b[a])) + /* { dg-error "variable 'a' used in the 'allocator' clause must not be modified between declaration of 'v' and its 'allocate' directive" "" { xfail c++ } .-1 } */ } diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-17.c b/gcc/testsuite/c-c++-common/gomp/allocate-17.c index f75af0c2d93..2a896cc334d 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-17.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-17.c @@ -20,7 +20,7 @@ one () #pragma omp target map(tofrom: result) firstprivate(n) { int var = 5; //, var2[n]; - #pragma omp allocate(var) align(128) allocator(omp_low_lat_mem_alloc) /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } } */ + #pragma omp allocate(var) align(128) allocator(omp_low_lat_mem_alloc) var = 7; } diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-18.c b/gcc/testsuite/c-c++-common/gomp/allocate-18.c index cad79812032..620bc4ecc97 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-18.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-18.c @@ -1,26 +1,10 @@ // { dg-additional-options "-Wno-deprecated-openmp" } -typedef enum omp_allocator_handle_t -#if __cplusplus >= 201103L -: __UINTPTR_TYPE__ -#endif -{ - omp_null_allocator = 0, - omp_default_mem_alloc = 1, - omp_large_cap_mem_alloc = 2, - omp_const_mem_alloc = 3, - omp_high_bw_mem_alloc = 4, - omp_low_lat_mem_alloc = 5, - omp_cgroup_mem_alloc = 6, - omp_pteam_mem_alloc = 7, - omp_thread_mem_alloc = 8, - __omp_allocator_handle_t_max__ = __UINTPTR_MAX__ -} omp_allocator_handle_t; +#include "allocate-allocator-handle.h" void test0 () { int A1[5], B1[5]; #pragma omp allocate(A1) align(128) allocator(omp_default_mem_alloc) - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ #ifndef __cplusplus _Static_assert (_Alignof(A1) == _Alignof(B1), "wrong alignment"); diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-19.c b/gcc/testsuite/c-c++-common/gomp/allocate-19.c index 5c5fc008b2f..cabd3875d1e 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-19.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-19.c @@ -1,3 +1,4 @@ +/* Does not include allocate-allocator-handle.h due to extra values being added. */ typedef enum omp_allocator_handle_t #if __cplusplus >= 201103L : __UINTPTR_TYPE__ @@ -21,7 +22,6 @@ typedef enum omp_allocator_handle_t static int A1[5] = {1,2,3,4,5}, B1[5]; #pragma omp allocate(A1) align(128) allocator(omp_default_mem_alloc) -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ #ifndef __cplusplus _Static_assert (_Alignof(A1) == _Alignof(B1), "wrong alignment"); @@ -32,7 +32,6 @@ static_assert (alignof(A1) == alignof(B1), "wrong alignment"); static int *ptr; #pragma omp allocate(ptr) align(2) allocator(omp_default_mem_alloc) -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ #ifndef __cplusplus _Static_assert (_Alignof(ptr) == _Alignof(int*), "wrong alignment"); @@ -46,7 +45,6 @@ get () { static int q = 0; #pragma omp allocate(q) align(1024) allocator(omp_default_mem_alloc) - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ #ifndef __cplusplus _Static_assert (_Alignof(q) == _Alignof(int), "wrong alignment"); @@ -58,12 +56,19 @@ get () return &A1[q]; } -static int invalid1, okay1, invalid2, invalid3; -#pragma omp allocate(invalid1) align(128) allocator(ompx_gnu_pinned_bogus_1) /* { dg-error "'allocator' clause requires a predefined allocator as 'invalid1' is static" "" { xfail c++ } } */ +static int invalid1, okay1, invalid2, invalid3; /* { dg-note "'invalid\[123\]' declared here" "" { target c++ xfail c++ } } */ +#pragma omp allocate(invalid1) align(128) allocator(ompx_gnu_pinned_bogus_1) /* { dg-error "'allocator' clause requires a predefined allocator as 'invalid1' is static" "" { target c } } */ +/* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target c++ } .-1 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-2 } */ +/* { dg-note "expression evaluates to '9'" "" { target c++ } .-3 } */ #pragma omp allocate(okay1) align(128) allocator(ompx_gnu_pinned_mem_alloc) /* Okay */ -#pragma omp allocate(invalid2) align(128) allocator(ompx_gnu_pinned_bogus_2) /* { dg-error "'allocator' clause requires a predefined allocator as 'invalid2' is static" "" { xfail c++ } } */ -#pragma omp allocate(invalid3) align(128) allocator(ompx_gnu_pinned_bogus_3) /* { dg-error "'allocator' clause requires a predefined allocator as 'invalid3' is static" "" { xfail c++ } } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-4 } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-4 } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-4 } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-4 } */ +#pragma omp allocate(invalid2) align(128) allocator(ompx_gnu_pinned_bogus_2) /* { dg-error "'allocator' clause requires a predefined allocator as 'invalid2' is static" "" { target c } } */ +/* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target c++ } .-1 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-2 } */ +/* { dg-note "expression evaluates to '199'" "" { target c++ } .-3 } */ +#pragma omp allocate(invalid3) align(128) allocator(ompx_gnu_pinned_bogus_3) /* { dg-error "'allocator' clause requires a predefined allocator as 'invalid3' is static" "" { target c } } */ +/* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target c++ } .-1 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-2 } */ +/* { dg-note "expression evaluates to '2001'" "" { target c++ } .-3 } */ + +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ } 0 } */ diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-5.c b/gcc/testsuite/c-c++-common/gomp/allocate-5.c index 09c8e4342f0..b34f9ea9227 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-5.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-5.c @@ -21,11 +21,11 @@ foo () omp_allocator_handle_t my_allocator = omp_default_mem_alloc; int a, b; static int c; -#pragma omp allocate (a) /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } } */ -#pragma omp allocate (b) allocator(my_allocator) /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } } */ +#pragma omp allocate (a) +#pragma omp allocate (b) allocator(my_allocator) #pragma omp allocate(c) align(32) /* { dg-message "'allocator' clause required for static variable 'c'" "" { target c } .-1 } */ - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */ + /* { dg-error "'allocator' clause must be specified" "" { target c++ } .-2 } */ } void @@ -34,14 +34,14 @@ bar () int a, a2, b; omp_allocator_handle_t my_allocator; #pragma omp allocate /* { dg-error "expected '\\(' before end of line" } */ - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ #pragma omp allocate allocator(my_allocator) /* { dg-error "expected '\\(' before 'allocator'" } */ - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ #pragma omp allocate(a) foo(my_allocator) /* { dg-error "expected 'allocator'" } */ /* { dg-error "expected end of line before '\\(' token" "" { target *-*-* } .-1 } */ - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-2 } */ -#pragma omp allocate(a2) allocator(b) /* { dg-error "'allocator' clause expression has type 'int' rather than 'omp_allocator_handle_t'" "todo: cp/semantics.c" { xfail c++ } } */ - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ +#pragma omp allocate(a2) allocator(b) + /* { dg-error "'allocator' clause expression has type 'int' rather than 'omp_allocator_handle_t'" "" { target c } .-1 } */ + /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target c++ } .-2 } */ + /* We have diverging behavior here between c and c++ due to a difference in + order of diagnostics, as well as diverging semantics, this should probably be unified. */ } @@ -50,32 +50,27 @@ align_test () { int i1,i2,i3,i4,i5,i6; #pragma omp allocate(i1) allocator(omp_default_mem_alloc), align(32) - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ #pragma omp allocate(i2) align ( 32 ),allocator(omp_default_mem_alloc) - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ #pragma omp allocate(i3),allocator(omp_default_mem_alloc) align(32) - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ #pragma omp allocate(i4) align ( 32 ) allocator(omp_default_mem_alloc) - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ #pragma omp allocate(i5) allocator ( omp_high_bw_mem_alloc ), align ( 32 ) allocator(omp_default_mem_alloc) /* { dg-error "too many 'allocator' clauses" "" { target *-*-* } .-1 } */ /* { dg-error "expected end of line before '\\)' token" "" { target *-*-* } .-2 } */ - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-3 } */ #pragma omp allocate(i6) align ( 32 ), align(32) allocator(omp_default_mem_alloc) /* { dg-error "too many 'align' clauses" "" { target *-*-* } .-1 } */ /* { dg-error "expected end of line before '\\)' token" "" { target *-*-* } .-2 } */ - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-3 } */ } void align_test2 () { int i, i2,i3; - #pragma omp allocate(i) align (32.0) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */ - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ + #pragma omp allocate(i) align (32.0) + /* { dg-error {could not convert '(?:\(double\))?3\.2e\+1l?' from 'double' to '(?:long )?unsigned int'} "" { target c++ } .-1 } */ + /* { dg-error {conversion from 'double' to '(?:long )?unsigned int' in a converted constant expression} "" { target c++ } .-2 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-3 } */ #pragma omp allocate(i2) align ( 31 ) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */ - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ #pragma omp allocate(i3) align ( -32 ) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */ - /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ + /* { dg-bogus "narrowing conversion of '-32' from" "" { target c++ xfail c++11 } .-1 } */ } diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-9.c b/gcc/testsuite/c-c++-common/gomp/allocate-9.c index f37a11185f7..52bae8c9a6a 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-9.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-9.c @@ -1,93 +1,78 @@ -typedef enum omp_allocator_handle_t -#if __cplusplus >= 201103L -: __UINTPTR_TYPE__ -#endif -{ - omp_null_allocator = 0, - omp_default_mem_alloc = 1, - omp_large_cap_mem_alloc = 2, - omp_const_mem_alloc = 3, - omp_high_bw_mem_alloc = 4, - omp_low_lat_mem_alloc = 5, - omp_cgroup_mem_alloc = 6, - omp_pteam_mem_alloc = 7, - omp_thread_mem_alloc = 8, - __ompx_last_mem_alloc = omp_thread_mem_alloc, - __omp_allocator_handle_t_max__ = __UINTPTR_MAX__ -} omp_allocator_handle_t; - - -static int A[5] = {1,2,3,4,5}; +#include "allocate-allocator-handle.h" + +static int A1[5] = {1,2,3,4,5}; /* { dg-line A_decl } */ static int A2[5] = {1,2,3,4,5}; static int A3[5] = {1,2,3,4,5}; -static int A4[5] = {1,2,3,4,5}; -static int A5[5] = {1,2,3,4,5}; -int B, C, C2, D; +static int A4[5] = {1,2,3,4,5}; /* { dg-line A4_decl } */ +static int A5[5] = {1,2,3,4,5}; /* { dg-line A5_decl } */ +int B, C, C2, D; /* { dg-note "declared here" "" { xfail c++ } } */ /* If the following fails because of added predefined allocators, please update + - include/gomp-constants.h's GOMP_OMP_PREDEF_ALLOC_MAX or GOMP_OMPX_PREDEF_ALLOC_MAX - c/c-parser.c's c_parser_omp_allocate - fortran/openmp.cc's is_predefined_allocator - libgomp/env.c's parse_allocator - libgomp/libgomp.texi (document the new values - multiple locations) + ensure that the memory-spaces are also up to date. */ -#pragma omp allocate(A) align(32) allocator((omp_allocator_handle_t) 9) /* { dg-error "'allocator' clause requires a predefined allocator as 'A' is static" "" { xfail c++ } } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ - +#pragma omp allocate(A1) align(32) allocator((omp_allocator_handle_t) 9) +/* { dg-error "'allocator' clause requires a predefined allocator as 'A1' is static" "" { target c } .-1 } */ +/* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target c++ } .-2 } */ +/* { dg-message "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-3 } */ +/* { dg-message "expression evaluates to '9'" "" { target c++ } .-4 } */ +/* { dg-note "'A1' declared here" "" { target c++ xfail c++ } A_decl } */ // typo in allocator name: #pragma omp allocate(A2) allocator(omp_low_latency_mem_alloc) /* { dg-error "'omp_low_latency_mem_alloc' undeclared here \\(not in a function\\); did you mean 'omp_low_lat_mem_alloc'\\?" "" { target c } .-1 } */ /* { dg-error "'omp_low_latency_mem_alloc' was not declared in this scope; did you mean 'omp_low_lat_mem_alloc'\\?" "" { target c++ } .-2 } */ /* { dg-error "'allocator' clause required for static variable 'A2'" "" { target c } .-3 } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-4 } */ /* align be const multiple of 2 */ #pragma omp allocate(A3) align(31) allocator(omp_default_mem_alloc) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ -/* allocator missing (required as A is static) */ -#pragma omp allocate(A4) align(32) /* { dg-error "'allocator' clause required for static variable 'A4'" "" { xfail c++ } } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ +/* allocator missing (required as A4 is static) */ +#pragma omp allocate(A4) align(32) +/* { dg-error "'allocator' clause required for static variable 'A4'" "" { target c } .-1 } */ +/* { dg-error "'allocator' clause must be specified" "" { target c++ } .-2 } */ +/* { dg-message "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-3 } */ +/* { dg-note "'A4' declared here" "" { target c++ xfail c++ } A4_decl } */ /* "expression in the clause must be a constant expression that evaluates to one of the predefined memory allocator values -> omp_low_lat_mem_alloc" */ #pragma omp allocate(B) allocator((omp_allocator_handle_t) (omp_high_bw_mem_alloc+1)) align(32) /* OK: omp_low_lat_mem_alloc */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ #pragma omp allocate(C) allocator((omp_allocator_handle_t) 2) /* OK: omp_large_cap_mem_alloc */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ -#pragma omp allocate(A5) align(32) allocator(omp_null_allocator) /* { dg-error "'allocator' clause requires a predefined allocator as 'A5' is static" "" { xfail c++ } } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ +#pragma omp allocate(A5) align(32) allocator(omp_null_allocator) +/* { dg-error "'allocator' clause requires a predefined allocator as 'A5' is static" "" { target c } .-1 } */ +/* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target c++ } .-2 } */ +/* { dg-message "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-3 } */ +/* { dg-message "expression evaluates to '0'" "" { target c++ } .-4 } */ +/* { dg-note "'A5' declared here" "" { target c++ xfail c++ } A5_decl } */ #pragma omp allocate(C2) align(32) allocator(omp_large_cap_mem_alloc) -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ // allocate directive in same TU int f() { #pragma omp allocate(D) align(32) allocator(omp_large_cap_mem_alloc) /* { dg-error "'allocate' directive must be in the same scope as 'D'" "" { xfail c++ } } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ -/* { dg-note "declared here" "" { target c } 25 } */ - return A[0]; + return A1[0]; } int g() { - int a2=1, b2=2; + int a2=1, b2=2; /* { dg-line g_a2_b2_decl } */ #pragma omp allocate(a2) -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ - #pragma omp allocate(a2) /* { dg-error "'a2' already appeared as list item in an 'allocate' directive" "" { xfail c++ } } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ + #pragma omp allocate(a2) /* { dg-error "'a2' already appeared as list item in an 'allocate' directive" } */ +/* { dg-note "'a2' previously appeared here" "" { target c++ } .-2 } */ { int c2=3; #pragma omp allocate(c2, b2) /* { dg-error "'allocate' directive must be in the same scope as 'b2'" "" { xfail c++ } } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ -/* { dg-note "declared here" "" { target c } .-9 } */ +/* { dg-note "declared here" "" { target *-*-* xfail c++ } g_a2_b2_decl } */ return c2+a2+b2; } } @@ -95,15 +80,20 @@ int g() int h(int q) { #pragma omp allocate(q) /* { dg-error "function parameter 'q' may not appear as list item in an 'allocate' directive" "" { xfail c++ } } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ +/* { dg-note "parameter 'q' declared here" "" { target c++ xfail c++ } .-3 } */ return q; } int k () { - static int var3 = 8; - #pragma omp allocate(var3) allocator((omp_allocator_handle_t)-1L) /* { dg-error "'allocator' clause requires a predefined allocator as 'var3' is static" "" { target c } } */ -/* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } .-1 } */ + static int var3 = 8; /* { dg-note "'var3' declared here" "" { target c++ xfail c++ } } */ + #pragma omp allocate(var3) allocator((omp_allocator_handle_t)-1L) + /* { dg-error "'allocator' clause requires a predefined allocator as 'var3' is static" "" { target c } .-1 } */ + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target c++ } .-2 } */ + /* { dg-message "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-3 } */ + /* { dg-message "expression evaluates to '\\d+'" "" { target c++ } .-4 } */ return var3; } + +/* { dg-bogus "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail c++ } 0 } */ diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-allocator-handle.h b/gcc/testsuite/c-c++-common/gomp/allocate-allocator-handle.h new file mode 100644 index 00000000000..1f94c303342 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/allocate-allocator-handle.h @@ -0,0 +1,19 @@ +typedef __UINTPTR_TYPE__ omp_uintptr_t; + +typedef enum omp_allocator_handle_t +#if __cplusplus >= 201103L +: omp_uintptr_t +#endif +{ + omp_null_allocator = 0, + omp_default_mem_alloc = 1, + omp_large_cap_mem_alloc = 2, + omp_const_mem_alloc = 3, + omp_high_bw_mem_alloc = 4, + omp_low_lat_mem_alloc = 5, + omp_cgroup_mem_alloc = 6, + omp_pteam_mem_alloc = 7, + omp_thread_mem_alloc = 8, + __ompx_last_mem_alloc = omp_thread_mem_alloc, + __omp_allocator_handle_t_max__ = __UINTPTR_MAX__ +} omp_allocator_handle_t; diff --git a/gcc/testsuite/c-c++-common/gomp/directive-1.c b/gcc/testsuite/c-c++-common/gomp/directive-1.c index 34194865d10..19d9290daf8 100644 --- a/gcc/testsuite/c-c++-common/gomp/directive-1.c +++ b/gcc/testsuite/c-c++-common/gomp/directive-1.c @@ -20,7 +20,6 @@ foo (void) int i, k = 0, l = 0; #pragma omp allocate, (i) /* { dg-error "expected '\\\(' before ',' token" } */ /* { dg-error "expected end of line before ',' token" "" { target c++ } .-1 } */ - /* { dg-message "not yet supported" "" { target c++ } .-2 } */ #pragma omp critical, (bar) /* { dg-error "expected an OpenMP clause before '\\\(' token" } */ ; #pragma omp flush, (k, l) /* { dg-error "expected '\\\(' or end of line before ',' token" "" { target c } } */ diff --git a/gcc/testsuite/c-c++-common/gomp/uses_allocators-1.c b/gcc/testsuite/c-c++-common/gomp/uses_allocators-1.c index df82cbbcba9..53c497dc655 100644 --- a/gcc/testsuite/c-c++-common/gomp/uses_allocators-1.c +++ b/gcc/testsuite/c-c++-common/gomp/uses_allocators-1.c @@ -22,7 +22,7 @@ f (omp_allocator_handle_t my_alloc) #pragma omp target { int a; /* { dg-error "'my_alloc' in 'allocator' clause inside a target region must be specified in an 'uses_allocators' clause on the 'target' directive" "not yet implemented" { xfail *-*-* } } */ - #pragma omp allocate(a) allocator(my_alloc) /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } } */ + #pragma omp allocate(a) allocator(my_alloc) a = 5; void *prt = omp_alloc(32, my_alloc); #pragma omp parallel allocate(allocator(my_alloc) : a) firstprivate(a) /* { dg-error "allocator 'my_alloc' in 'allocate' clause inside a target region must be specified in an 'uses_allocators' clause on the 'target' directive" "not yet implemented" { xfail *-*-* } } */ @@ -37,7 +37,7 @@ g (omp_allocator_handle_t my_alloc) #pragma omp target uses_allocators(my_alloc) { int a; - #pragma omp allocate(a) allocator(my_alloc) /* { dg-message "sorry, unimplemented: '#pragma omp allocate' not yet supported" "" { target c++ } } */ + #pragma omp allocate(a) allocator(my_alloc) a = 5; void *prt = omp_alloc(32, my_alloc); #pragma omp parallel allocate(allocator(my_alloc) : a) firstprivate(a) diff --git a/gcc/testsuite/g++.dg/gomp/allocate-10.C b/gcc/testsuite/g++.dg/gomp/allocate-10.C new file mode 100644 index 00000000000..e0f3bcc1780 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-10.C @@ -0,0 +1,115 @@ +/* { dg-do compile { target c++17 } } */ +#include "allocate-allocator-handle.h" + +/* Invalid allocator clause. */ + +template +void auto_nttp_allocator() +{ + int a; + #pragma omp allocate(a) allocator(Alloc) /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" } */ +} + +template +void auto_nttp_allocator_uninstantiated() +{ + int a; + #pragma omp allocate(a) allocator(Alloc) +} + +#define DEFINITELY_NOT_PREDEFINED static_cast(1024) + +void instantiate_auto_nttp_allocator() +{ + auto_nttp_allocator(); /* { dg-bogus "required from here" } */ + auto_nttp_allocator(); /* { dg-bogus "required from here" } */ + auto_nttp_allocator<1>(); /* { dg-message "required from here" } */ +} + +#undef DEFINITELY_NOT_PREDEFINED + +template +void auto_nttp_allocator_static_0() +{ + static int a; + #pragma omp allocate(a) allocator(Alloc) + /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target *-*-* } .-1 } */ + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } .-2 } */ +} + +template +void auto_nttp_allocator_static_1() +{ + static int a; + #pragma omp allocate(a) allocator(Alloc) /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" } */ +} + +template +void auto_nttp_allocator_static_2() +{ + static int a; + #pragma omp allocate(a) allocator(Alloc) + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } .-1 } */ +} + +template +void auto_nttp_allocator_static_uninstantiated() +{ + static int a; + #pragma omp allocate(a) allocator(Alloc) +} + +#define DEFINITELY_NOT_PREDEFINED static_cast(1024) + +void instantiate_auto_nttp_allocator_static() +{ + auto_nttp_allocator_static_0(); /* { dg-bogus "required from here" } */ + auto_nttp_allocator_static_0<1>(); /* { dg-message "required from here" } */ + auto_nttp_allocator_static_0(); /* { dg-message "required from here" } */ + + auto_nttp_allocator_static_1(); /* { dg-bogus "required from here" } */ + auto_nttp_allocator_static_1<1>(); /* { dg-message "required from here" } */ + + auto_nttp_allocator_static_2(); /* { dg-bogus "required from here" } */ + auto_nttp_allocator_static_2(); /* { dg-message "required from here" } */ +} + +#undef DEFINITELY_NOT_PREDEFINED + +/* { dg-bogus "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } 0 } */ + +/* Invalid align clause */ + +template +void auto_nttp_align_uninstantiated() +{ + int a; + #pragma omp allocate(a) align(Align) +} + +template +void auto_nttp_align_0() +{ + int a; + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ +} + +template +void auto_nttp_align_1() +{ + int a; + #pragma omp allocate(a) align(Align) + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + /* { dg-error {could not convert 'nullptr' from 'std::nullptr_t' to '(?:long )?unsigned int'} "" { target *-*-* } .-2 } */ +} + +void instantiate_auto_nttp_align() +{ + auto_nttp_align_0<32>(); /* { dg-bogus "required from here" } */ + auto_nttp_align_0<42>(); /* { dg-message "required from here" } */ + + auto_nttp_align_1<32>(); /* { dg-bogus "required from here" } */ + auto_nttp_align_1(); /* { dg-message "required from here" } */ +} + +/* { dg-bogus "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } 0 } */ diff --git a/gcc/testsuite/g++.dg/gomp/allocate-11.C b/gcc/testsuite/g++.dg/gomp/allocate-11.C new file mode 100644 index 00000000000..d9bc1de3ef8 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-11.C @@ -0,0 +1,18 @@ +/* Just a silly ICE I came across by accident, easy fix, might be a problem + with lookup_name but I'm not certain. + + For some reason, the floating 'a;' breaks lookup_name in tsubst_stmt during + substitution of the allocate directive, despite it being found no problem + during parsing of the allocate directive's var list. + I don't have time to investigate it further so I'm just going to fix it + by checking for NULL_TREE on the return of lookup_name. */ + +template +void f() +{ + a; /* { dg-error "'a' was not declared in this scope" } */ + int a = 42; + #pragma omp allocate(a) +} +template void f(); + diff --git a/gcc/testsuite/g++.dg/gomp/allocate-12.C b/gcc/testsuite/g++.dg/gomp/allocate-12.C new file mode 100644 index 00000000000..53fa5712f50 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-12.C @@ -0,0 +1,38 @@ +/* { dg-do compile { target c++14 } } */ +/* { dg-additional-options "-fdump-tree-gimple" } */ + +/* Ensure allocate directive does not break attributes on a decl (and vice-versa). */ + +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\(64," 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\(32," 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\(16," 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\(8," 2 "gimple" } } */ + +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_free" 8 "gimple" } } */ + +template +int test0 () +{ + int a [[deprecated]]; + #pragma omp allocate(a) align(Align) + return a; /* { dg-warning "'a' is deprecated" } */ +} + +template int test0<64u>(); +template int test0<32u>(); +template int test0<16u>(); +template int test0<8u>(); + + +template +int test1 () +{ + int a [[deprecated]]; + #pragma omp allocate(a) align(Align) + return a; /* { dg-warning "'a' is deprecated" } */ +} + +template int test1<8u>(); +template int test1<16u>(); +template int test1<32u>(); +template int test1<64u>(); diff --git a/gcc/testsuite/g++.dg/gomp/allocate-13.C b/gcc/testsuite/g++.dg/gomp/allocate-13.C new file mode 100644 index 00000000000..ffc51b1d2c8 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-13.C @@ -0,0 +1,28 @@ +/* { dg-do compile { target c++11 } } */ +/* { dg-additional-options "-fdump-tree-gimple" } */ + +/* Misc valid constexpr expressions in a clause. + TODO: Really needs more cases. */ + +/* Not constexpr, invalid value, not called. */ +template +int get_align(T) { return 42; } + +template +int dependent_call_adl() +{ + int a = 42; + #pragma omp allocate(a) align(get_align(T{})) + return a; +} + +namespace foo +{ + struct S {}; + + constexpr int get_align(S) { return 32; } +} + +template int dependent_call_adl(); +/* { dg-final { scan-tree-dump "__builtin_GOMP_alloc \\(32," "gimple" } } */ +/* { dg-final { scan-tree-dump "__builtin_GOMP_free" "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/gomp/allocate-5.C b/gcc/testsuite/g++.dg/gomp/allocate-5.C new file mode 100644 index 00000000000..724dd980138 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-5.C @@ -0,0 +1,411 @@ +/* { dg-additional-options "-fdump-tree-gimple" } */ +/* { dg-skip-if "" { ilp32 } } */ + +#include "allocate-allocator-handle.h" + +/* All cases are valid and should work. */ + +/* Note: the OpenMP allocate directive is not supposed to change the alignof + of expr a, it was decided to have too many edge cases. The static asserts + in these cases correctly test that it remains untouched. + + Note: cases that take omp_default_mem_alloc and have no align clause elide + the GOMP_alloc/GOMP_free transformations. */ + +/* 86 total cases. */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc" 86 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_free" 86 "gimple" } } */ + +/* FIXME: This almost certainly needs tweaks for systems where alignof(int) + is not 4. */ + +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(32," 31 "gimple" } } */ + +/* 9 * 3 = 27 cases scanned here. */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(8," 3 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(16," 3 "gimple" } } */ +/* Align==32 scanned above. */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(64," 3 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(128," 3 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(256," 3 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(512," 3 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(1024," 3 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(2048," 3 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(4096," 3 "gimple" } } */ + +/* The align argument is at least alignof(int) (4) in all cases, thus we can subtract + the cases where align >= 8 from the total cases to determine how many cases + there are where align == 4. + 86 - (27 + 31) = 28. + Please update this math if changes are made to this test so everything + is (somewhat) coherent. */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(4," 28 "gimple" } } */ + + +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(\\d+, \\d+, 0B\\\)" 29 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(\\d+, \\d+, 1\\\)" 22 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(\\d+, \\d+, 2\\\)" 31 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(\\d+, \\d+, 3\\\)" 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(\\d+, \\d+, 4\\\)" 2 "gimple" } } */ + +struct S0 { + int _v; + S0(int v) : _v(v) {} + operator int() const { return 42; } +}; + +struct S1 { + int _v[2]; + S1(int v) : _v() { + int *end = _v + sizeof(_v) / sizeof(*_v); + for (int *it = _v; it != end; ++it) + *it = v; + } + operator int() const { return 42; } +}; + +/********************** + * dependent variable * + **********************/ + +template +T dep_local() +{ + T a = 42; + #pragma omp allocate(a) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(T)); + #endif + return a; +} + +template +T dep_local_align() +{ + T a = 42; + #pragma omp allocate(a) align(32) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(T)); + #endif + return a; +} + +template +T dep_local_alloc_0() +{ + T a = 42; + #pragma omp allocate(a) allocator(omp_default_mem_alloc) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(T)); + #endif + return a; +} + +template +T dep_local_alloc_1() +{ + T a = 42; + #pragma omp allocate(a) allocator(omp_large_cap_mem_alloc) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(T)); + #endif + return a; +} + +template +T dep_local_align_alloc_0() +{ + T a = 42; + #pragma omp allocate(a) align(32) allocator(omp_default_mem_alloc) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(T)); + #endif + return a; +} + +template +T dep_local_align_alloc_1() +{ + T a = 42; + #pragma omp allocate(a) align(32) allocator(omp_large_cap_mem_alloc) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(T)); + #endif + return a; +} + +/* 5 cases per expansion, dep_local_alloc_0 uses omp_default_mem_alloc + without an align clause. + 2 allocator==0B, + 1 allocator==1 (because 1 case elided), + 2 allocator==2 cases per expansion. + + 3 align==32 cases per expansion. */ +#define INSTANTIATE_ALL_WITH_T(type) \ + do { \ + type v0 = dep_local(); \ + type v1 = dep_local_align(); \ + type v2 = dep_local_alloc_0(); \ + type v3 = dep_local_alloc_1(); \ + type v4 = dep_local_align_alloc_0(); \ + type v5 = dep_local_align_alloc_1(); \ + static_cast(v0); \ + static_cast(v1); \ + static_cast(v2); \ + static_cast(v3); \ + static_cast(v4); \ + static_cast(v5); \ + } while (false) + +/* 4 * 5 cases, 20. + 4 * 2 allocator==0B cases, 8. + 4 * 1 allocator==1 cases, 4. + 4 * 2 allocator==2 cases, 8. + 4 * 3 align==32 cases, 12. */ +void instantiate_dep_tests() +{ + INSTANTIATE_ALL_WITH_T(int); + INSTANTIATE_ALL_WITH_T(float); + INSTANTIATE_ALL_WITH_T(S0); + INSTANTIATE_ALL_WITH_T(S1); +} + +#undef INSTANTIATE_ALL_WITH_T + +/********************** + * template parameter * + **********************/ + +template +int template_parm(T) +{ + int a = 42; + #pragma omp allocate(a) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(int)); + #endif + return a; +} + +template +int template_parm_align(T) +{ + int a = 42; + #pragma omp allocate(a) align(32) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(int)); + #endif + return a; +} + +template +int template_parm_alloc_0(T) +{ + int a = 42; + #pragma omp allocate(a) allocator(omp_default_mem_alloc) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(int)); + #endif + return a; +} + +template +int template_parm_alloc_1(T) +{ + int a = 42; + #pragma omp allocate(a) allocator(omp_large_cap_mem_alloc) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(int)); + #endif + return a; +} + +template +int template_parm_align_alloc_0(T) +{ + int a = 42; + #pragma omp allocate(a) align(32) allocator(omp_default_mem_alloc) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(int)); + #endif + return a; +} + +template +int template_parm_align_alloc_1(T) +{ + int a = 42; + #pragma omp allocate(a) align(32) allocator(omp_large_cap_mem_alloc) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(int)); + #endif + return a; +} + +/* 5 cases per expansion, template_parm_alloc_0 uses omp_default_mem_alloc + without an align clause. + 2 allocator==0B, + 1 allocator==1 (because 1 case elided), + 2 allocator==2 cases per expansion. + + 3 align==32 cases per expansion. */ +#define INSTANTIATE_ALL_WITH_T(type) \ + do { \ + type a = 42; \ + int v0 = template_parm(a); \ + int v1 = template_parm_align(a); \ + int v2 = template_parm_alloc_0(a); \ + int v3 = template_parm_alloc_1(a); \ + int v4 = template_parm_align_alloc_0(a); \ + int v5 = template_parm_align_alloc_1(a); \ + static_cast(v0); \ + static_cast(v1); \ + static_cast(v2); \ + static_cast(v3); \ + static_cast(v4); \ + static_cast(v5); \ + } while (false) + +/* 4 * 5 cases, 20. + 4 * 2 allocator==0B cases, 8. + 4 * 1 allocator==1 cases, 4. + 4 * 2 allocator==2 cases, 8. + 4 * 3 align==32 cases, 12. */ +void instantiate_template_parm_tests() +{ + INSTANTIATE_ALL_WITH_T(int); + INSTANTIATE_ALL_WITH_T(float); + INSTANTIATE_ALL_WITH_T(S0); + INSTANTIATE_ALL_WITH_T(S1); +} + +#undef INSTANTIATE_ALL_WITH_T + +/************************************* + * non-type template parameter align * + *************************************/ + +template +int nttp_align() +{ + int a = 42; + #pragma omp allocate(a) align(Align) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(int)); + #endif + return a; +} + +template +int nttp_align_alloc_0() +{ + int a = 42; + #pragma omp allocate(a) align(Align) allocator(omp_default_mem_alloc) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(int)); + #endif + return a; +} + +template +int nttp_align_alloc_1() +{ + int a = 42; + #pragma omp allocate(a) align(Align) allocator(omp_large_cap_mem_alloc) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(int)); + #endif + return a; +} + +/* 3 cases per expansion. + 1 allocator==0B, 1 allocator==1, 1 allocator==2 cases per expansion. + 3 align==value cases per expansion. */ +#define INSTANTIATE_ALL_WITH_V(value) \ + do { \ + int v0 = nttp_align(); \ + int v1 = nttp_align_alloc_0(); \ + int v2 = nttp_align_alloc_1(); \ + static_cast(v0); \ + static_cast(v1); \ + static_cast(v2); \ + } while (false) + +/* 13 * 3 cases, 39. + 13 * allocator==0B cases. + 13 * allocator==1 cases. + 13 * allocator==2 cases. */ +void instantiate_nttp_align_tests() +{ + /* Minimum align for int is 4, 3 * 3 alloc=4, 9 alloc=4. */ + INSTANTIATE_ALL_WITH_V(1); + INSTANTIATE_ALL_WITH_V(2); + INSTANTIATE_ALL_WITH_V(4); + /* 3 alloc=N for the rest. */ + INSTANTIATE_ALL_WITH_V(8); + INSTANTIATE_ALL_WITH_V(16); + INSTANTIATE_ALL_WITH_V(32); + INSTANTIATE_ALL_WITH_V(64); + INSTANTIATE_ALL_WITH_V(128); + INSTANTIATE_ALL_WITH_V(256); + INSTANTIATE_ALL_WITH_V(512); + INSTANTIATE_ALL_WITH_V(1024); + INSTANTIATE_ALL_WITH_V(2048); + INSTANTIATE_ALL_WITH_V(4096); +} + +#undef INSTANTIATE_ALL_WITH_V + + +template +int nttp_alloc() +{ + int a = 42; + #pragma omp allocate(a) allocator(Alloc) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(int)); + #endif + return a; +} + +template +int nttp_alloc_align() +{ + int a = 42; + #pragma omp allocate(a) align(32) allocator(Alloc) + #if __cplusplus >= 201103L + static_assert(alignof(a) == alignof(int)); + #endif + return a; +} + +/* 2 cases per expansion. + 2 allocator=value per expansion. + 1 alloc=32 per expansion. */ +#define INSTANTIATE_ALL_WITH_V(value) \ + do { \ + int v0 = nttp_alloc(); \ + int v1 = nttp_alloc_align(); \ + static_cast(v0); \ + static_cast(v1); \ + } while (false) + +/* 4 * 2 cases, 8, + -1 omp_default_mem_alloc without align, 7 cases. + 1 * allocator==1 (1 elided), + 2 * allocator==2, + 2 * allocator==3, + 2 * allocator==4 cases. + 4 * 1 alloc=32 cases, 4. */ +void instantiate_nttp_alloc_tests() +{ + INSTANTIATE_ALL_WITH_V(omp_default_mem_alloc); + INSTANTIATE_ALL_WITH_V(omp_large_cap_mem_alloc); + INSTANTIATE_ALL_WITH_V(omp_const_mem_alloc); + INSTANTIATE_ALL_WITH_V(omp_high_bw_mem_alloc); +} + +#undef INSTANTIATE_ALL_WITH_V + +/* We are probably missing quite a few cases here. + Missing cases with a param in allocator clause. */ diff --git a/gcc/testsuite/g++.dg/gomp/allocate-6.C b/gcc/testsuite/g++.dg/gomp/allocate-6.C new file mode 100644 index 00000000000..eb0c78a24db --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-6.C @@ -0,0 +1,392 @@ +/* { dg-do compile { target c++11 } } */ +/* { dg-skip-if "" { ilp32 } } */ +/* { dg-additional-options "-fdump-tree-gimple" } */ + +#include "allocate-allocator-handle.h" + +/* Valid uses of lambda captures in an allocator clause. */ + +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc" 200 "gimple" } } */ + +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_free" 200 "gimple" } } */ + +template +struct is_same { static constexpr bool value = false; }; + +template +struct is_same { static constexpr bool value = true; }; + +struct S0 { + int _v; + S0(int v) : _v(v) {} + operator int() const { return 42; } +}; + +struct S1 { + int _v[2]; + S1(int v) : _v() { + int *end = _v + sizeof(_v) / sizeof(*_v); + for (int *it = _v; it != end; ++it) + *it = v; + } + operator int() const { return 42; } +}; + +/* Suppresses int/float cases from being optimized out, I'm not sure if this is + going to be sufficient for all cases though. */ +int (*prevent_optimization)() = nullptr; + +#define BLANK_ARGUMENT + +/* Capturing with an initiaizer was added in C++14 */ +#if __cplusplus >= 201402L + +#define CAPTURE_LITERAL_INIT_LAMBDA(type) \ +do { \ + auto capture_literal_init = [alloc = omp_default_mem_alloc](){ \ + type a = prevent_optimization(); \ + _Pragma("omp allocate(a) allocator(alloc)") \ + return a; \ + }; \ + auto result = capture_literal_init(); \ + static_assert(is_same::value); \ +} while (false) + +void test_capture_literal_init_nondep_lambdas() +{ + /* 4 cases */ + CAPTURE_LITERAL_INIT_LAMBDA(int); + CAPTURE_LITERAL_INIT_LAMBDA(float); + CAPTURE_LITERAL_INIT_LAMBDA(S0); + CAPTURE_LITERAL_INIT_LAMBDA(S1); +} + +/* 1 case per instantiation */ +template +void test_capture_literal_init_dependent_lambdas() +{ + CAPTURE_LITERAL_INIT_LAMBDA(T); +} +/* 4 cases */ +template void test_capture_literal_init_dependent_lambdas(); +template void test_capture_literal_init_dependent_lambdas(); +template void test_capture_literal_init_dependent_lambdas(); +template void test_capture_literal_init_dependent_lambdas(); + +#undef CAPTURE_LITERAL_INIT_LAMBDA + + + +#define EXPLICIT_CAPTURE_WITH_INIT_LAMBDA(type, opt_tok, capture) \ +do { \ + auto explicit_capture_with_init = [opt_tok alloc = capture](){ \ + type a = prevent_optimization(); \ + _Pragma("omp allocate(a) allocator(alloc)") \ + return a; \ + }; \ + auto result = explicit_capture_with_init(); \ + static_assert(is_same::value); \ +} while (false) + +/* 4 cases per expansion */ +#define TEST_LAMBDAS_WITH_TYPE(type, opt_tok) \ +do { \ + EXPLICIT_CAPTURE_WITH_INIT_LAMBDA(type, opt_tok, alloc); \ + EXPLICIT_CAPTURE_WITH_INIT_LAMBDA(type, opt_tok, alloc_ref); \ + EXPLICIT_CAPTURE_WITH_INIT_LAMBDA(type, opt_tok, alloc_param); \ + EXPLICIT_CAPTURE_WITH_INIT_LAMBDA(type, opt_tok, alloc_ref_param); \ +} while (false) + +/* 4*4 = 16 cases */ +void test_capture_by_value_with_init_nondep_lambdas(omp_allocator_handle_t alloc_param, + omp_allocator_handle_t& alloc_ref_param) +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; + omp_allocator_handle_t& alloc_ref = alloc; + TEST_LAMBDAS_WITH_TYPE(int, BLANK_ARGUMENT); + TEST_LAMBDAS_WITH_TYPE(float, BLANK_ARGUMENT); + TEST_LAMBDAS_WITH_TYPE(S0, BLANK_ARGUMENT); + TEST_LAMBDAS_WITH_TYPE(S1, BLANK_ARGUMENT); +} + +/* 4*4 = 16 cases */ +void test_capture_by_ref_with_init_nondep_lambdas(omp_allocator_handle_t alloc_param, + omp_allocator_handle_t& alloc_ref_param) +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; + omp_allocator_handle_t& alloc_ref = alloc; + TEST_LAMBDAS_WITH_TYPE(int, &); + TEST_LAMBDAS_WITH_TYPE(float, &); + TEST_LAMBDAS_WITH_TYPE(S0, &); + TEST_LAMBDAS_WITH_TYPE(S1, &); +} + +/* 4 cases per instantiation */ +template +void test_capture_by_value_with_init_dependent_lambdas(omp_allocator_handle_t alloc_param, + omp_allocator_handle_t& alloc_ref_param) +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; + omp_allocator_handle_t& alloc_ref = alloc; + TEST_LAMBDAS_WITH_TYPE(T, BLANK_ARGUMENT); +} +/* 4*4 = 16 cases */ +template void test_capture_by_value_with_init_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_capture_by_value_with_init_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_capture_by_value_with_init_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_capture_by_value_with_init_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); + +/* 4 cases per instantiation */ +template +void test_capture_by_ref_with_init_dependent_lambdas(omp_allocator_handle_t alloc_param, + omp_allocator_handle_t& alloc_ref_param) +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; + omp_allocator_handle_t& alloc_ref = alloc; + TEST_LAMBDAS_WITH_TYPE(T, &); +} +/* 4*4 = 16 cases */ +template void test_capture_by_ref_with_init_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_capture_by_ref_with_init_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_capture_by_ref_with_init_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_capture_by_ref_with_init_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); + +#undef EXPLICIT_CAPTURE_WITH_INIT_LAMBDA +#undef TEST_LAMBDAS_WITH_TYPE + +#else +/* There are 4 + 4 + 16 + 16 + 16 + 16 cases in the above, we replicate that + many so our count in dg-final isn't wrong in C++11 mode. + The counter isn't required but it doesn't hurt and might make it easier + to inspect the asm if we need to, that's the goal anyway. */ + +#define DUMMY_ALLOC(counter) \ +do { \ + auto dummy_ ##counter = [alloc](){ \ + int a = prevent_optimization(); \ + _Pragma("omp allocate(a) allocator(alloc)") \ + return a; \ + }; \ + auto result = dummy_ ##counter(); \ +} while (false) + +#define DUMMY_X4(counter) \ +do { \ + DUMMY_ALLOC(counter ##A); \ + DUMMY_ALLOC(counter ##B); \ + DUMMY_ALLOC(counter ##C); \ + DUMMY_ALLOC(counter ##D); \ +} while (false) + +void dummy_cases(omp_allocator_handle_t alloc) +{ + /* 4x1 for test_capture_literal_init_nondep_lambdas */ + DUMMY_X4(0); + /* 4x1 for test_capture_literal_init_dependent_lambdas */ + DUMMY_X4(1); + /* 4x4 for test_capture_by_value_with_init_nondep_lambdas */ + DUMMY_X4(2); + DUMMY_X4(3); + DUMMY_X4(4); + DUMMY_X4(5); + /* 4x4 for test_capture_by_value_with_init_dependent_lambdas */ + DUMMY_X4(6); + DUMMY_X4(7); + DUMMY_X4(8); + DUMMY_X4(9); + /* 4x4 for test_capture_by_ref_with_init_dependent_lambdas */ + DUMMY_X4(9); + DUMMY_X4(10); + DUMMY_X4(11); + DUMMY_X4(12); + /* 4x4 for test_capture_by_ref_with_init_nondep_lambdas */ + DUMMY_X4(13); + DUMMY_X4(14); + DUMMY_X4(15); + DUMMY_X4(16); +} + +#undef DUMMY_ALLOC +#undef DUMMY_X4 + +#endif + + +#define EXPLICIT_CAPTURE_LAMBDAS(type, opt_tok) \ +do { \ + auto explicit_capture0 = [opt_tok alloc](){ \ + type a = prevent_optimization(); \ + _Pragma("omp allocate(a) allocator(alloc)") \ + return a; \ + }; \ + auto result0 = explicit_capture0(); \ + static_assert(is_same::value); \ + \ + auto explicit_capture1 = [opt_tok alloc_ref](){ \ + type a = prevent_optimization(); \ + _Pragma("omp allocate(a) allocator(alloc_ref)") \ + return a; \ + }; \ + auto result1 = explicit_capture1(); \ + static_assert(is_same::value); \ + \ + auto explicit_capture2 = [opt_tok alloc_param](){ \ + type a = prevent_optimization(); \ + _Pragma("omp allocate(a) allocator(alloc_param)") \ + return a; \ + }; \ + auto result2 = explicit_capture2(); \ + static_assert(is_same::value); \ + \ + auto explicit_capture3 = [opt_tok alloc_ref_param](){ \ + type a = prevent_optimization(); \ + _Pragma("omp allocate(a) allocator(alloc_ref_param)") \ + return a; \ + }; \ + auto result3 = explicit_capture3(); \ + static_assert(is_same::value); \ +} while (false) + +void test_explicit_capture_by_value_nondep_lambdas(omp_allocator_handle_t alloc_param, + omp_allocator_handle_t& alloc_ref_param) +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; + omp_allocator_handle_t& alloc_ref = alloc; + EXPLICIT_CAPTURE_LAMBDAS(int, BLANK_ARGUMENT); + EXPLICIT_CAPTURE_LAMBDAS(float, BLANK_ARGUMENT); + EXPLICIT_CAPTURE_LAMBDAS(S0, BLANK_ARGUMENT); + EXPLICIT_CAPTURE_LAMBDAS(S1, BLANK_ARGUMENT); +} + +void test_explicit_capture_by_ref_nondep_lambdas(omp_allocator_handle_t alloc_param, + omp_allocator_handle_t& alloc_ref_param) +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; + omp_allocator_handle_t& alloc_ref = alloc; + EXPLICIT_CAPTURE_LAMBDAS(int, &); + EXPLICIT_CAPTURE_LAMBDAS(float, &); + EXPLICIT_CAPTURE_LAMBDAS(S0, &); + EXPLICIT_CAPTURE_LAMBDAS(S1, &); +} + +template +void test_explicit_capture_by_value_dependent_lambdas(omp_allocator_handle_t alloc_param, + omp_allocator_handle_t& alloc_ref_param) +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; + omp_allocator_handle_t& alloc_ref = alloc; + EXPLICIT_CAPTURE_LAMBDAS(T, BLANK_ARGUMENT); +} +template void test_explicit_capture_by_value_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_explicit_capture_by_value_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_explicit_capture_by_value_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_explicit_capture_by_value_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); + + +template +void test_explicit_capture_by_ref_dependent_lambdas(omp_allocator_handle_t alloc_param, + omp_allocator_handle_t& alloc_ref_param) +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; + omp_allocator_handle_t& alloc_ref = alloc; + EXPLICIT_CAPTURE_LAMBDAS(T, &); +} +template void test_explicit_capture_by_ref_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_explicit_capture_by_ref_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_explicit_capture_by_ref_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_explicit_capture_by_ref_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); + +#undef EXPLICIT_CAPTURE_LAMBDA +#undef TEST_LAMBDAS_WITH_TYPE + + +#define DEFAULT_CAPTURE_LAMBDAS(type, capture) \ +do { \ + auto default_capture0 = [capture](){ \ + type a = prevent_optimization(); \ + _Pragma("omp allocate(a) allocator(alloc)") \ + return a; \ + }; \ + auto result0 = default_capture0(); \ + static_assert(is_same::value); \ + \ + auto default_capture1 = [capture](){ \ + type a = prevent_optimization(); \ + _Pragma("omp allocate(a) allocator(alloc_ref)") \ + return a; \ + }; \ + auto result1 = default_capture1(); \ + static_assert(is_same::value); \ + \ + auto default_capture2 = [capture](){ \ + type a = prevent_optimization(); \ + _Pragma("omp allocate(a) allocator(alloc_param)") \ + return a; \ + }; \ + auto result2 = default_capture2(); \ + static_assert(is_same::value); \ + \ + auto default_capture3 = [capture](){ \ + type a = prevent_optimization(); \ + _Pragma("omp allocate(a) allocator(alloc_ref_param)") \ + return a; \ + }; \ + auto result3 = default_capture3(); \ + static_assert(is_same::value); \ +} while (false) + + + +void test_default_capture_by_value_nondep_lambdas(omp_allocator_handle_t alloc_param, + omp_allocator_handle_t& alloc_ref_param) +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; + omp_allocator_handle_t& alloc_ref = alloc; + DEFAULT_CAPTURE_LAMBDAS(int, =); + DEFAULT_CAPTURE_LAMBDAS(float, =); + DEFAULT_CAPTURE_LAMBDAS(S0, =); + DEFAULT_CAPTURE_LAMBDAS(S1, =); +} + +void test_default_capture_by_ref_nondep_lambdas(omp_allocator_handle_t alloc_param, + omp_allocator_handle_t& alloc_ref_param) +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; + omp_allocator_handle_t& alloc_ref = alloc; + DEFAULT_CAPTURE_LAMBDAS(int, &); + DEFAULT_CAPTURE_LAMBDAS(float, &); + DEFAULT_CAPTURE_LAMBDAS(S0, &); + DEFAULT_CAPTURE_LAMBDAS(S1, &); +} + +template +void test_default_capture_by_value_dependent_lambdas(omp_allocator_handle_t alloc_param, + omp_allocator_handle_t& alloc_ref_param) +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; + omp_allocator_handle_t& alloc_ref = alloc; + DEFAULT_CAPTURE_LAMBDAS(T, =); +} +template void test_default_capture_by_value_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_default_capture_by_value_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_default_capture_by_value_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_default_capture_by_value_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); + +template +void test_default_capture_by_ref_dependent_lambdas(omp_allocator_handle_t alloc_param, + omp_allocator_handle_t& alloc_ref_param) +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; + omp_allocator_handle_t& alloc_ref = alloc; + DEFAULT_CAPTURE_LAMBDAS(T, &); +} +template void test_default_capture_by_ref_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_default_capture_by_ref_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_default_capture_by_ref_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); +template void test_default_capture_by_ref_dependent_lambdas(omp_allocator_handle_t, omp_allocator_handle_t&); + +#undef DEFAULT_CAPTURE_LAMBDA +#undef TEST_LAMBDAS_WITH_TYPE + +/* Potential missing cases: captures that are type dependent, mutable lambdas. */ + diff --git a/gcc/testsuite/g++.dg/gomp/allocate-7.C b/gcc/testsuite/g++.dg/gomp/allocate-7.C new file mode 100644 index 00000000000..01fc5b84014 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-7.C @@ -0,0 +1,222 @@ +/* { dg-do compile { target c++20 } } */ +/* { dg-skip-if "" { ilp32 } } */ +/* { dg-additional-options "-fdump-tree-gimple" } */ + +#include "allocate-allocator-handle.h" + + +/* Valid C++20 cases. + + Note: cases that take omp_default_mem_alloc and have no align clause elide + the GOMP_alloc/GOMP_free transformations. */ + +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc" 40 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_free" 40 "gimple" } } */ + +/* FIXME: This almost certainly needs tweaks for systems where alignof(int) + is not 4. */ + +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(32," 24 "gimple" } } */ + +/* The align argument is at least alignof(int) (4) in all cases, thus we can subtract + the cases where align >= 8 from the total cases to determine how many cases + there are where align == 4. + 40 - 24 = 16. + Please update this math if changes are made to this test so everything + is (somewhat) coherent. */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(4," 16 "gimple" } } */ + +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(\\d+, \\d+, 0B\\\)" 16 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(\\d+, \\d+, 1\\\)" 8 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\\(\\d+, \\d+, 2\\\)" 16 "gimple" } } */ + +struct S0 { + int _v; + S0(int v) : _v(v) {} + operator int() const { return 42; } +}; + +struct S1 { + int _v[2]; + S1(int v) : _v{v, v} {} + operator int() const { return 42; } +}; + +/***************************** + * template parameter (auto) * + *****************************/ + +int auto_parm(auto) +{ + int a = 42; + #pragma omp allocate(a) + static_assert(alignof(a) == alignof(int)); + return a; +} + +int auto_parm_align(auto) +{ + int a = 42; + #pragma omp allocate(a) align(32) + static_assert(alignof(a) == alignof(int)); + return a; +} + +int auto_parm_alloc_0(auto) +{ + int a = 42; + #pragma omp allocate(a) allocator(omp_default_mem_alloc) + static_assert(alignof(a) == alignof(int)); + return a; +} + +int auto_parm_alloc_1(auto) +{ + int a = 42; + #pragma omp allocate(a) allocator(omp_large_cap_mem_alloc) + static_assert(alignof(a) == alignof(int)); + return a; +} + +int auto_parm_align_alloc_0(auto) +{ + int a = 42; + #pragma omp allocate(a) align(32) allocator(omp_default_mem_alloc) + static_assert(alignof(a) == alignof(int)); + return a; +} + +int auto_parm_align_alloc_1(auto) +{ + int a = 42; + #pragma omp allocate(a) align(32) allocator(omp_large_cap_mem_alloc) + static_assert(alignof(a) == alignof(int)); + return a; +} + +/* 5 cases per expansion, auto_parm_alloc_0 uses omp_default_mem_alloc + without an align clause. + 2 allocator==0B, + 1 allocator==1 (because 1 case elided), + 2 allocator==2 cases per expansion. + + 3 align==32 cases per expansion. */ +#define INSTANTIATE_ALL_WITH_T(type) \ + do { \ + type a = 42; \ + int v0 = auto_parm(a); \ + int v1 = auto_parm_align(a); \ + int v2 = auto_parm_alloc_0(a); \ + int v3 = auto_parm_alloc_1(a); \ + int v4 = auto_parm_align_alloc_0(a); \ + int v5 = auto_parm_align_alloc_1(a); \ + static_cast(v0); \ + static_cast(v1); \ + static_cast(v2); \ + static_cast(v3); \ + static_cast(v4); \ + static_cast(v5); \ + } while (false) + +/* 4 * 5 cases, 20. + 4 * 2 allocator==0B cases, 8. + 4 * 1 allocator==1 cases, 4. + 4 * 2 allocator==2 cases, 8. + 4 * 3 align==32 cases, 12. */ +void instantiate_auto_parm_tests() +{ + INSTANTIATE_ALL_WITH_T(int); + INSTANTIATE_ALL_WITH_T(float); + INSTANTIATE_ALL_WITH_T(S0); + INSTANTIATE_ALL_WITH_T(S1); +} + +#undef INSTANTIATE_ALL_WITH_T + + +auto dep_local_auto_parm(auto p) +{ + auto a = p; + #pragma omp allocate(a) + static_assert(alignof(a) == alignof(decltype(p))); + return a; +} + +auto dep_local_auto_parm_align(auto p) +{ + auto a = p; + #pragma omp allocate(a) align(32) + static_assert(alignof(a) == alignof(decltype(p))); + return a; +} + +auto dep_local_auto_parm_alloc_0(auto p) +{ + auto a = p; + #pragma omp allocate(a) allocator(omp_default_mem_alloc) + static_assert(alignof(a) == alignof(decltype(p))); + return a; +} + +auto dep_local_auto_parm_alloc_1(auto p) +{ + auto a = p; + #pragma omp allocate(a) allocator(omp_large_cap_mem_alloc) + static_assert(alignof(a) == alignof(decltype(p))); + return a; +} + +auto dep_local_auto_parm_align_alloc_0(auto p) +{ + auto a = p; + #pragma omp allocate(a) align(32) allocator(omp_default_mem_alloc) + static_assert(alignof(a) == alignof(decltype(p))); + return a; +} + +auto dep_local_auto_parm_align_alloc_1(auto p) +{ + auto a = p; + #pragma omp allocate(a) align(32) allocator(omp_large_cap_mem_alloc) + static_assert(alignof(a) == alignof(decltype(p))); + return a; +} + +/* 5 cases per expansion, dep_local_auto_parm_alloc_0 uses omp_default_mem_alloc + without an align clause. + 2 allocator==0B, + 1 allocator==1 (because 1 case elided), + 2 allocator==2 cases per expansion. + + 3 align==32 cases per expansion. */ +#define INSTANTIATE_ALL_WITH_T(type) \ + do { \ + type a = 42; \ + type v0 = dep_local_auto_parm(a); \ + type v1 = dep_local_auto_parm_align(a); \ + type v2 = dep_local_auto_parm_alloc_0(a); \ + type v3 = dep_local_auto_parm_alloc_1(a); \ + type v4 = dep_local_auto_parm_align_alloc_0(a); \ + type v5 = dep_local_auto_parm_align_alloc_1(a); \ + static_cast(v0); \ + static_cast(v1); \ + static_cast(v2); \ + static_cast(v3); \ + static_cast(v4); \ + static_cast(v5); \ + } while (false) + +/* 4 * 5 cases, 20. + 4 * 2 allocator==0B cases, 8. + 4 * 1 allocator==1 cases, 4. + 4 * 2 allocator==2 cases, 8. + 4 * 3 align==32 cases, 12. */ +void instantiate_dep_local_auto_parm_tests() +{ + INSTANTIATE_ALL_WITH_T(int); + INSTANTIATE_ALL_WITH_T(float); + INSTANTIATE_ALL_WITH_T(S0); + INSTANTIATE_ALL_WITH_T(S1); +} + +#undef INSTANTIATE_ALL_WITH_T diff --git a/gcc/testsuite/g++.dg/gomp/allocate-8.C b/gcc/testsuite/g++.dg/gomp/allocate-8.C new file mode 100644 index 00000000000..2cfdc632cf0 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-8.C @@ -0,0 +1,48 @@ +/* { dg-additional-options "-fdump-tree-gimple" } */ +#include "allocate-allocator-handle.h" + +/* Check simple cases that do not have an align clause and the allocator clause + folds to omp_default_mem_alloc. These cases are supposed to elide + the usual transformations (calling __builtin_GOMP_alloc/__builtin_GOMP_free) + that are usually applied to vars in an allocate directive. + + It is not entirely clear if this is correct behavior, and due to differences + in how C++ works we can't support this for all cases, such as for exprs with + calls to constexpr functions. + At the very least we should make sure the obvious cases still work as + expected. */ + +/* { dg-final { scan-tree-dump-not "__builtin_GOMP_alloc" "gimple" } } */ +/* { dg-final { scan-tree-dump-not "__builtin_GOMP_free" "gimple" } } */ + +int hardcoded_alloc(int p) +{ + int a = p; + #pragma omp allocate(a) allocator(omp_default_mem_alloc) + return a; +} + +int converted_expr_alloc(int p) +{ + int a = p; + #pragma omp allocate(a) allocator(omp_allocator_handle_t(1)) + return a; +} + +int simple_expr_alloc(int p) +{ + int a = p; + #pragma omp allocate(a) allocator(omp_allocator_handle_t(0+1)) + return a; +} + +template +int nttp_alloc(int p) +{ + int a = p; + #pragma omp allocate(a) allocator(Alloc) + return a; +} +template int nttp_alloc(int); + + diff --git a/gcc/testsuite/g++.dg/gomp/allocate-9.C b/gcc/testsuite/g++.dg/gomp/allocate-9.C new file mode 100644 index 00000000000..066b8c617a7 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-9.C @@ -0,0 +1,78 @@ +/* { dg-do compile { target c++23 } } */ +/* { dg-additional-options "-fdump-tree-gimple" } */ + +#include "allocate-allocator-handle.h" + +/* Test allocator clause is conditionally manifestly constant evaluated. + + This test needs some work to actually detect if it is doing the right thing + in the static cases, but we barely implement allocation for those cases so + there isn't really much to detect. + + For the non-static cases, it would be ideal if we checked whether it + optimizes properly, currently that is not being done. */ + + +/* Note, in practice this isn't actually useful as user handles are (AFAIK) + assigned by the runtime, this is just for testing. */ +constexpr omp_allocator_handle_t get_alloc_fn_foldable () +{ + if consteval { + return omp_large_cap_mem_alloc; + } + else { + return omp_allocator_handle_t{128}; + } +} + +omp_allocator_handle_t my_global_user_handle = omp_allocator_handle_t{256}; + +constexpr omp_allocator_handle_t get_alloc_fn_non_foldable () +{ + if consteval { + return omp_large_cap_mem_alloc; + } + else { + return my_global_user_handle; + } +} + + +/* This could optimize to 128 but is not required to. */ +int non_manifest_cx_foldable (int p) +{ + int non_static_a = p; + #pragma omp allocate(non_static_a) allocator(get_alloc_fn_foldable ()) + return non_static_a; +} +/* { dg-final { scan-tree-dump-times "= get_alloc_fn_foldable" 1 "gimple" } } */ + +/* At best this can optimize to 'my_global_user_handle'. */ +int non_manifest_cx_non_foldable (int p) +{ + int non_static_b = p; + #pragma omp allocate(non_static_b) allocator(get_alloc_fn_non_foldable ()) + return non_static_b; +} +/* { dg-final { scan-tree-dump-times "= get_alloc_fn_non_foldable" 1 "gimple" } } */ + +/* In both of these cases, the allocator clause's expr is + manifestly constant evaluated. */ + +/* This MUST fold to omp_large_cap_mem_alloc. */ +int manifest_cx_foldable (int p) +{ + static int static_a = p; + #pragma omp allocate(static_a) allocator(get_alloc_fn_foldable ()) + return static_a; +} + +/* This MUST fold to omp_large_cap_mem_alloc, calling get_alloc_fn_non_foldable + is intentional, the function is only non-foldable if the allocator clause + is not manifestly constant evaluated. */ +int manifest_cx_non_foldable (int p) +{ + static int static_b = p; + #pragma omp allocate(static_b) allocator(get_alloc_fn_non_foldable ()) + return static_b; +} diff --git a/gcc/testsuite/g++.dg/gomp/allocate-allocator-handle.h b/gcc/testsuite/g++.dg/gomp/allocate-allocator-handle.h new file mode 100644 index 00000000000..c629df158c1 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-allocator-handle.h @@ -0,0 +1,18 @@ +typedef __UINTPTR_TYPE__ omp_uintptr_t; + +typedef enum omp_allocator_handle_t +#if __cplusplus >= 201103L +: omp_uintptr_t +#endif +{ + omp_null_allocator = 0, + omp_default_mem_alloc = 1, + omp_large_cap_mem_alloc = 2, + omp_const_mem_alloc = 3, + omp_high_bw_mem_alloc = 4, + omp_low_lat_mem_alloc = 5, + omp_cgroup_mem_alloc = 6, + omp_pteam_mem_alloc = 7, + omp_thread_mem_alloc = 8, + __omp_allocator_handle_t_max__ = __UINTPTR_MAX__ +} omp_allocator_handle_t; diff --git a/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C b/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C new file mode 100644 index 00000000000..c0c59a30a3c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C @@ -0,0 +1,63 @@ +#include "allocate-allocator-handle.h" + +/* If the following fails because of added predefined allocators, please update + - include/gomp-constants.h's GOMP_OMP_PREDEF_ALLOC_MAX or GOMP_OMPX_PREDEF_ALLOC_MAX + - libgomp/env.c's parse_allocator + - libgomp/libgomp.texi (document the new values - multiple locations) + - gcc/testsuite/c-c++-common/gomp/allocate-9.c (fix the hardcoded values) + - gcc/testsuite/g++.dg/gomp/allocate-handles-2.C (update GOMP_OMP_PREDEF_ALLOC_MAX and/or GOMP_OMPX_PREDEF_ALLOC_MAX) + + ensure that the memory-spaces are also up to date. */ + +/* I had wanted to simply include /include/gomp-constants.h to ensure + synchronization, while also having hardcoded values as a canary, but + including files from that directory does not seem to be supported. */ +#define GOMP_OMP_PREDEF_ALLOC_MAX 8 +#define GOMP_OMPX_PREDEF_ALLOC_MIN 200 +#define GOMP_OMPX_PREDEF_ALLOC_MAX 201 + +int g0 = 42; /* { dg-note "'g0' declared here" "" { xfail *-*-* } } */ +#pragma omp allocate(g0) allocator(omp_null_allocator) +/* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-1 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ +/* { dg-note "expression evaluates to '0'" "" { target *-*-* } .-3 } */ +int g1 = 42; /* { dg-note "'g1' declared here" "" { xfail *-*-* } }*/ +#pragma omp allocate(g1) allocator(static_cast(GOMP_OMP_PREDEF_ALLOC_MAX + 1)) +/* { dg-error "'allocator' clause requires a constant predefined allocator" "If this test fails because of added predefined allocators please ensure everything is updated accordingly, see this test case for more information" { target *-*-* } .-1 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ +/* { dg-note "expression evaluates to '9'" "" { target *-*-* } .-3 } */ +int g2 = 42; /* { dg-note "'g2' declared here" "" { xfail *-*-* } }*/ +#pragma omp allocate(g2) allocator(static_cast(GOMP_OMPX_PREDEF_ALLOC_MIN - 1)) +/* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-1 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ +/* { dg-note "expression evaluates to '199'" "" { target *-*-* } .-3 } */ +int g3 = 42; /* { dg-note "'g3' declared here" "" { xfail *-*-* } }*/ +#pragma omp allocate(g3) allocator(static_cast(GOMP_OMPX_PREDEF_ALLOC_MAX + 1)) +/* { dg-error "'allocator' clause requires a constant predefined allocator" "If this test fails because of added predefined allocators please ensure everything is updated accordingly, see this test case for more information" { target *-*-* } .-1 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ +/* { dg-note "expression evaluates to '202'" "" { target *-*-* } .-3 } */ + +void test_predefined_allocs() +{ + static int a0 = 42; /* { dg-note "'a0' declared here" "" { xfail *-*-* } }*/ + #pragma omp allocate(a0) allocator(omp_null_allocator) + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-1 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ + /* { dg-note "expression evaluates to '0'" "" { target *-*-* } .-3 } */ + static int a1 = 42; /* { dg-note "'a1' declared here" "" { xfail *-*-* } }*/ + #pragma omp allocate(a1) allocator(static_cast(GOMP_OMP_PREDEF_ALLOC_MAX + 1)) + /* { dg-error "'allocator' clause requires a constant predefined allocator" "If this test fails because of added predefined allocators please ensure everything is updated accordingly, see this test case for more information" { target *-*-* } .-1 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ + /* { dg-note "expression evaluates to '9'" "" { target *-*-* } .-3 } */ + static int a2 = 42; /* { dg-note "'a2' declared here" "" { xfail *-*-* } }*/ + #pragma omp allocate(a2) allocator(static_cast(GOMP_OMPX_PREDEF_ALLOC_MIN - 1)) + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-1 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ + /* { dg-note "expression evaluates to '199'" "" { target *-*-* } .-3 } */ + static int a3 = 42; /* { dg-note "'a3' declared here" "" { xfail *-*-* } }*/ + #pragma omp allocate(a3) allocator(static_cast(GOMP_OMPX_PREDEF_ALLOC_MAX + 1)) + /* { dg-error "'allocator' clause requires a constant predefined allocator" "If this test fails because of added predefined allocators please ensure everything is updated accordingly, see this test case for more information" { target *-*-* } .-1 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ + /* { dg-note "expression evaluates to '202'" "" { target *-*-* } .-3 } */ +} + +/* { dg-bogus "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail c++ } 0 }*/ diff --git a/gcc/testsuite/g++.dg/gomp/allocate-handles-2.C b/gcc/testsuite/g++.dg/gomp/allocate-handles-2.C new file mode 100644 index 00000000000..89949ee0fef --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-handles-2.C @@ -0,0 +1,45 @@ +/* { dg-do compile { target c++11 } } */ +#include "allocate-allocator-handle.h" + +/* I had wanted to simply include /include/gomp-constants.h to ensure + synchronization, but including files from that directory does not seem + to be supported. */ +#define GOMP_OMP_PREDEF_ALLOC_MAX 8 +#define GOMP_OMPX_PREDEF_ALLOC_MIN 200 +#define GOMP_OMPX_PREDEF_ALLOC_MAX 201 + +/* Test that all predefined allocators are correctly treated as predefined. */ + +template +void test_predefined_alloc() +{ + static int a = 42; + #pragma omp allocate(a) allocator(Alloc) +} + +/* Because this is written to work as far back as c++11 it is a little bit + crusty. It is metaprogrammed to automatically test the full ranges + specified above. */ + +template +struct sequence {}; + +template<__UINTPTR_TYPE__ Offset, __UINTPTR_TYPE__... Is> +using modified = sequence(Is + Offset)...>; + +template<__UINTPTR_TYPE__ Start, __UINTPTR_TYPE__ End> +using make_offset_sequence = modified; + +template +void unpack(sequence) +{ + int helper[] = {(test_predefined_alloc(), 0)...}; +} + +void do_tests() +{ + /* make_sequence creates a sequence [Start, End) while the *_MAX values are + inclusive, add 1 to the End arg to create an exclusive range. */ + unpack(make_offset_sequence<1, GOMP_OMP_PREDEF_ALLOC_MAX + 1>{}); + unpack(make_offset_sequence{}); +} diff --git a/libgomp/testsuite/libgomp.c++/allocate-2.C b/libgomp/testsuite/libgomp.c++/allocate-2.C new file mode 100644 index 00000000000..f79cada1777 --- /dev/null +++ b/libgomp/testsuite/libgomp.c++/allocate-2.C @@ -0,0 +1,329 @@ +/* { dg-do run } */ +/* { dg-additional-options "-fdump-tree-omplower" } */ + +/* For the 4 vars in omp_parallel, 4 in omp_target and 1 of 2 in each of no_alloc{,2}_func. */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_alloc \\(" 10 "omplower" } } */ +/* { dg-final { scan-tree-dump-times "__builtin_GOMP_free \\(" 10 "omplower" } } */ + +#include + + +void +check_int (int *x, int y) +{ + if (*x != y) + __builtin_abort (); +} + +void +check_ptr (int **x, int *y) +{ + if (*x != y) + __builtin_abort (); +} + + +template +t +no_alloc_func () +{ + /* There is no __builtin_GOMP_alloc / __builtin_GOMP_free as + allocator == omp_default_mem_alloc (known at compile time. */ + t no_alloc, alloc_has_align = 3; + #pragma omp allocate(no_alloc) allocator(omp_default_mem_alloc) + /* But this one is allocated because of align. */ + #pragma omp allocate(alloc_has_align) allocator(omp_default_mem_alloc) align(sizeof(t)) + no_alloc = 7; + return no_alloc + alloc_has_align; +} + +template +t +no_alloc2_func() +{ + /* There is no __builtin_GOMP_alloc / __builtin_GOMP_free as + no_alloc2 is TREE_UNUSED. But there is for is_alloc2. */ + t no_alloc2, is_alloc2; + #pragma omp allocate(no_alloc2, is_alloc2) + is_alloc2 = 7; + return is_alloc2; +} + + +template +void +omp_parallel () +{ + int n = 6; + t iii = 5, jjj[5], kkk[n]; + t *ptr = (t *) 0x1234; + #pragma omp allocate(iii, jjj, kkk, ptr) + + for (int i = 0; i < 5; i++) + jjj[i] = 3*i; + for (int i = 0; i < 6; i++) + kkk[i] = 7*i; + + #pragma omp parallel default(none) firstprivate(iii, jjj, kkk, ptr) if(0) + { + if (iii != 5) + __builtin_abort(); + iii = 7; + check_int (&iii, 7); + for (int i = 0; i < 5; i++) + if (jjj[i] != 3*i) + __builtin_abort (); + for (int i = 0; i < 6; i++) + if (kkk[i] != 7*i) + __builtin_abort (); + for (int i = 0; i < 5; i++) + jjj[i] = 4*i; + for (int i = 0; i < 6; i++) + kkk[i] = 8*i; + for (int i = 0; i < 5; i++) + check_int (&jjj[i], 4*i); + for (int i = 0; i < 6; i++) + check_int (&kkk[i], 8*i); + if (ptr != (int *) 0x1234) + __builtin_abort (); + ptr = (int *) 0xabcd; + if (ptr != (int *) 0xabcd) + __builtin_abort (); + check_ptr (&ptr, (int *) 0xabcd); + } + if (iii != 5) + __builtin_abort (); + check_int (&iii, 5); + for (int i = 0; i < 5; i++) + { + if (jjj[i] != 3*i) + __builtin_abort (); + check_int (&jjj[i], 3*i); + } + for (int i = 0; i < 6; i++) + { + if (kkk[i] != 7*i) + __builtin_abort (); + check_int (&kkk[i], 7*i); + } + if (ptr != (int *) 0x1234) + __builtin_abort (); + check_ptr (&ptr, (int *) 0x1234); + + #pragma omp parallel default(firstprivate) if(0) + { + if (iii != 5) + __builtin_abort(); + iii = 7; + check_int (&iii, 7); + for (int i = 0; i < 5; i++) + if (jjj[i] != 3*i) + __builtin_abort (); + for (int i = 0; i < 6; i++) + if (kkk[i] != 7*i) + __builtin_abort (); + for (int i = 0; i < 5; i++) + jjj[i] = 4*i; + for (int i = 0; i < 6; i++) + kkk[i] = 8*i; + for (int i = 0; i < 5; i++) + check_int (&jjj[i], 4*i); + for (int i = 0; i < 6; i++) + check_int (&kkk[i], 8*i); + if (ptr != (int *) 0x1234) + __builtin_abort (); + ptr = (int *) 0xabcd; + if (ptr != (int *) 0xabcd) + __builtin_abort (); + check_ptr (&ptr, (int *) 0xabcd); + } + if (iii != 5) + __builtin_abort (); + check_int (&iii, 5); + for (int i = 0; i < 5; i++) + { + if (jjj[i] != 3*i) + __builtin_abort (); + check_int (&jjj[i], 3*i); + } + for (int i = 0; i < 6; i++) + { + if (kkk[i] != 7*i) + __builtin_abort (); + check_int (&kkk[i], 7*i); + } + if (ptr != (int *) 0x1234) + __builtin_abort (); + check_ptr (&ptr, (int *) 0x1234); +} + + +template +void +omp_target () +{ + int n = 6; + t iii = 5, jjj[5], kkk[n]; + t *ptr = (int *) 0x1234; + #pragma omp allocate(iii, jjj, kkk, ptr) + + for (int i = 0; i < 5; i++) + jjj[i] = 3*i; + for (int i = 0; i < 6; i++) + kkk[i] = 7*i; + + #pragma omp target defaultmap(none) firstprivate(iii, jjj, kkk, ptr) + { + if (iii != 5) + __builtin_abort(); + iii = 7; + check_int (&iii, 7); + for (int i = 0; i < 5; i++) + if (jjj[i] != 3*i) + __builtin_abort (); + for (int i = 0; i < 6; i++) + if (kkk[i] != 7*i) + __builtin_abort (); + for (int i = 0; i < 5; i++) + jjj[i] = 4*i; + for (int i = 0; i < 6; i++) + kkk[i] = 8*i; + for (int i = 0; i < 5; i++) + check_int (&jjj[i], 4*i); + for (int i = 0; i < 6; i++) + check_int (&kkk[i], 8*i); + if (ptr != (int *) 0x1234) + __builtin_abort (); + ptr = (int *) 0xabcd; + if (ptr != (int *) 0xabcd) + __builtin_abort (); + check_ptr (&ptr, (int *) 0xabcd); + } + if (iii != 5) + __builtin_abort (); + check_int (&iii, 5); + for (int i = 0; i < 5; i++) + { + if (jjj[i] != 3*i) + __builtin_abort (); + check_int (&jjj[i], 3*i); + } + for (int i = 0; i < 6; i++) + { + if (kkk[i] != 7*i) + __builtin_abort (); + check_int (&kkk[i], 7*i); + } + if (ptr != (int *) 0x1234) + __builtin_abort (); + check_ptr (&ptr, (int *) 0x1234); + + #pragma omp target defaultmap(firstprivate) + { + if (iii != 5) + __builtin_abort(); + iii = 7; + check_int (&iii, 7); + for (int i = 0; i < 5; i++) + if (jjj[i] != 3*i) + __builtin_abort (); + for (int i = 0; i < 6; i++) + if (kkk[i] != 7*i) + __builtin_abort (); + for (int i = 0; i < 5; i++) + jjj[i] = 4*i; + for (int i = 0; i < 6; i++) + kkk[i] = 8*i; + for (int i = 0; i < 5; i++) + check_int (&jjj[i], 4*i); + for (int i = 0; i < 6; i++) + check_int (&kkk[i], 8*i); + if (ptr != (int *) 0x1234) + __builtin_abort (); + ptr = (int *) 0xabcd; + if (ptr != (int *) 0xabcd) + __builtin_abort (); + check_ptr (&ptr, (int *) 0xabcd); + } + if (iii != 5) + __builtin_abort (); + check_int (&iii, 5); + for (int i = 0; i < 5; i++) + { + if (jjj[i] != 3*i) + __builtin_abort (); + check_int (&jjj[i], 3*i); + } + for (int i = 0; i < 6; i++) + { + if (kkk[i] != 7*i) + __builtin_abort (); + check_int (&kkk[i], 7*i); + } + if (ptr != (int *) 0x1234) + __builtin_abort (); + check_ptr (&ptr, (int *) 0x1234); + + #pragma omp target defaultmap(tofrom) + { + if (iii != 5) + __builtin_abort(); + iii = 7; + check_int (&iii, 7); + for (int i = 0; i < 5; i++) + if (jjj[i] != 3*i) + __builtin_abort (); + for (int i = 0; i < 6; i++) + if (kkk[i] != 7*i) + __builtin_abort (); + for (int i = 0; i < 5; i++) + jjj[i] = 4*i; + for (int i = 0; i < 6; i++) + kkk[i] = 8*i; + for (int i = 0; i < 5; i++) + check_int (&jjj[i], 4*i); + for (int i = 0; i < 6; i++) + check_int (&kkk[i], 8*i); + if (ptr != (int *) 0x1234) + __builtin_abort (); + ptr = (int *) 0xabcd; + if (ptr != (int *) 0xabcd) + __builtin_abort (); + check_ptr (&ptr, (int *) 0xabcd); + } + + if (iii != 7) + __builtin_abort (); + check_int (&iii, 7); + for (int i = 0; i < 5; i++) + { + if (jjj[i] != 4*i) + __builtin_abort (); + check_int (&jjj[i], 4*i); + } + for (int i = 0; i < 6; i++) + { + if (kkk[i] != 8*i) + __builtin_abort (); + check_int (&kkk[i], 8*i); + } + if (ptr != (int *) 0xabcd) + __builtin_abort (); + check_ptr (&ptr, (int *) 0xabcd); +} + +int +foo() +{ + return no_alloc_func() + no_alloc2_func(); +} + +int +main () +{ + omp_parallel (); + omp_target (); + if (foo() != 10 + 7) + __builtin_abort (); + return 0; +} diff --git a/libgomp/testsuite/libgomp.c/allocate-4.c b/libgomp/testsuite/libgomp.c-c++-common/allocate-4.c similarity index 95% rename from libgomp/testsuite/libgomp.c/allocate-4.c rename to libgomp/testsuite/libgomp.c-c++-common/allocate-4.c index e81cc4093aa..706c8510b84 100644 --- a/libgomp/testsuite/libgomp.c/allocate-4.c +++ b/libgomp/testsuite/libgomp.c-c++-common/allocate-4.c @@ -1,6 +1,3 @@ -/* TODO: move to ../libgomp.c-c++-common once C++ is implemented. */ -/* NOTE: { target c } is unsupported with with the C compiler. */ - /* { dg-do run } */ /* { dg-additional-options "-fdump-tree-gimple" } */ diff --git a/libgomp/testsuite/libgomp.c/allocate-5.c b/libgomp/testsuite/libgomp.c-c++-common/allocate-5.c similarity index 96% rename from libgomp/testsuite/libgomp.c/allocate-5.c rename to libgomp/testsuite/libgomp.c-c++-common/allocate-5.c index beaf16440e1..3bbe78db840 100644 --- a/libgomp/testsuite/libgomp.c/allocate-5.c +++ b/libgomp/testsuite/libgomp.c-c++-common/allocate-5.c @@ -1,6 +1,3 @@ -/* TODO: move to ../libgomp.c-c++-common once C++ is implemented. */ -/* NOTE: { target c } is unsupported with with the C compiler. */ - /* { dg-do run } */ /* { dg-additional-options "-fdump-tree-gimple" } */ diff --git a/libgomp/testsuite/libgomp.c/allocate-6.c b/libgomp/testsuite/libgomp.c-c++-common/allocate-6.c similarity index 98% rename from libgomp/testsuite/libgomp.c/allocate-6.c rename to libgomp/testsuite/libgomp.c-c++-common/allocate-6.c index 6d7278ce571..669581b327d 100644 --- a/libgomp/testsuite/libgomp.c/allocate-6.c +++ b/libgomp/testsuite/libgomp.c-c++-common/allocate-6.c @@ -1,6 +1,3 @@ -/* TODO: move to ../libgomp.c-c++-common once C++ is implemented. */ -/* NOTE: { target c } is unsupported with with the C compiler. */ - /* { dg-do run } */ /* { dg-additional-options "-fdump-tree-omplower" } */ diff --git a/libgomp/testsuite/libgomp.c/allocate-7.c b/libgomp/testsuite/libgomp.c-c++-common/allocate-7.c similarity index 90% rename from libgomp/testsuite/libgomp.c/allocate-7.c rename to libgomp/testsuite/libgomp.c-c++-common/allocate-7.c index 1fa92d889d0..9968eb19005 100644 --- a/libgomp/testsuite/libgomp.c/allocate-7.c +++ b/libgomp/testsuite/libgomp.c-c++-common/allocate-7.c @@ -1,6 +1,3 @@ -/* TODO: move to ../libgomp.c-c++-common once C++ is implemented. */ -/* NOTE: { target c } is unsupported with with the C compiler. */ - /* { dg-do run } */ #include From patchwork Tue May 5 15:01:58 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Waffl3x X-Patchwork-Id: 134497 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id AA3BA4BA79BA for ; Tue, 5 May 2026 15:15:31 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org AA3BA4BA79BA Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=baylibre-com.20251104.gappssmtp.com header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256 header.s=20251104 header.b=q6XQnOzD X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x435.google.com (mail-pf1-x435.google.com [IPv6:2607:f8b0:4864:20::435]) by sourceware.org (Postfix) with ESMTPS id 605A94BA900F for ; Tue, 5 May 2026 15:10:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 605A94BA900F Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=baylibre.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 605A94BA900F Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::435 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993843; cv=none; b=V/ELmwiH7kLQ08may0R+6nNy2+If9YLeJXHJ7EM7G3TtLXJi/qkqYpn94gJcc9SpVVJrImDA1YiZIDoisgyRLH7/fYDHPGdtX1BiNrZryeO+1mmpy3nO7yZfhYyNN8uBITgdz/HSiJVmmIoCmMK4ssV3CJXyzT69zSTtA9F8G0Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993843; c=relaxed/simple; bh=sF4fV1bDevpXE0R5B1P3u9c74/6q8mKpOtGtykmvCtM=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Arye+rJ74xqqwXl0XTehlBUs1jsyXXKQepuef6btiDWqH/iSLDRqFdnm55oKaojJIiZyE1vmVTTHYic7OLE5CYR5UE9G+KT79d8/EEo9pyM11/UQmljxMF1grfR8vRV4hz526scRC8+YjUF3devtzGHwG14KxcSQw6rKh3ODq60= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 605A94BA900F Received: by mail-pf1-x435.google.com with SMTP id d2e1a72fcca58-835451c5debso112985b3a.2 for ; Tue, 05 May 2026 08:10:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20251104.gappssmtp.com; s=20251104; t=1777993842; x=1778598642; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=gqRopMsDKtwE2JgA2ANfgdHhULzFdSfyUcM770uho5I=; b=q6XQnOzDTyACSEKmsS4oG1JUlPDuuAmi+4vP5Jh95OiwNf3tc5JhIkFqZuzR/eHOAi Kqr2CCPgGd5UVFhX4YkJSP46Jlp8hD5cht0atKsxDeMHM/MLZHg24KSlZFtihxRE1VTL O3Jun5fJ1Xz1tDxlOeljx1txXBeSFOKCwQFSGEKS5yFQYCxQCozXo1E4aZmVGO20dWX0 Ms00WfhycXkW+HsUh3zW7jfjuWmeJ7h3Rnn45PcxSO40TB5L0AaoSWnEDKQ82Kbl5p+g At08gFlzJ4MSuYvmsZtrJmckxIHEP61iGq2bn8t3PLNJh9FIAWH0jyei1JoVor1eoGiD EUXA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777993842; x=1778598642; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=gqRopMsDKtwE2JgA2ANfgdHhULzFdSfyUcM770uho5I=; b=rMs1W+1ElcxhzSPtMYpPbwqQ+9djj4/lWX2U6Gt4orxzIebYb3SGw0I0PSdqLcJrMB S40APle9Qezb7MYSJHjNAp1+1ZMsgDgsSvu3W5VZBLfzPnybnlGSCBxjgMo+bvYxWMqB YNNhpztPgnGIjEezAcmFIpaX8p5xy3FLzum7YE+6LCI3RCJjMa3W4LaPsUmmr/M5sDz3 9XDgr4PP/xV9GcWweWg71rkMkHLLS2zf/0S3IaPDWid7soLTkyKJvQYC3aa4XRh8WUfY BjS4pTx7osJZk6C3vJ8T8ccRqZ5A1Xi7nY6QUhpfWuaue74/JHWZgwDgFFBhC9jtNPTc DxZw== X-Gm-Message-State: AOJu0YwrNjgUk9NYTrTUvN6fl54s4pUVPQEc1nTePdNyvPY7TegdUw84 XVxxP10VcKUDhF37Z352L1yEvFPsIFbvkz5Jc9Cj+Cokx5wZ449jViYH9EyLo1uf67C+d+AL9J3 KsIG3 X-Gm-Gg: AeBDieuEW60AyFxn56BZY2Ns7VWpCs2v3HUTQpDomQHYcBW0u5SBZC256xc0OOOZDcB Smgc4mBGQ/WuQjxWY+/CJGnHDv9gQ/qO/XQX2VA2SyM8LMJHdfNmLqWvveUdxBJ5tdtTu9HvfDr VeV1dxeDPMmY3koV30G34+oXF8thljqPG+PBZWZL8Bz2wWaRptv/YGZQn2m/Sg9XzTR/ujqH7JD AFuD669ICBH+Jt0uszooDPDxxA4GaOzAia7l3184opuO44iI6xXpTAKbNw5sxnnC1ynwTQ0elCm aP4/Je1RfZS7uiD+gMLB5Nfp3wyFVK4DtwJ6Cb8y0du+fJuau+sA0PDnaocz4A+QdFSSYzAgcjj t8yjgJJmohverpQQw9iS825xN7+Zhewxu9iYe2tm6UqxYy4+PKaTmhn09xqfg8TGJfVoMxxmWTT I72zBRrPl2ahtusg0hEvrV8lJrUhcmx238G81+9ZucH8aM+xSXZQ== X-Received: by 2002:a05:6a00:e18:b0:82f:6a82:4231 with SMTP id d2e1a72fcca58-8352d14842cmr7303425b3a.1.1777993841214; Tue, 05 May 2026 08:10:41 -0700 (PDT) Received: from waffl3x-prestige.lan ([2001:56a:f98a:b800:1f67:ce08:3cbd:86b8]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83965645140sm2674956b3a.12.2026.05.05.08.10.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 08:10:40 -0700 (PDT) From: Waffl3x To: gcc-patches@gcc.gnu.org Cc: Waffl3x Subject: [PATCH 05/12] OpenMP/C++: Enhance diagnostics of 'omp allocate' 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: <20260505151030.1749548-1-waffl3x@baylibre.com> MIME-Version: 1.0 X-Spam-Status: No, score=-13.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org Add diagnostics for multiple uses of a var in a single directive, uses of parameters, vars in a different scope, and vars that are references. Enhances diagnostics, as well as reporting a proper location in most cases. gcc/cp/ChangeLog: * parser.cc (cp_parser_omp_allocate): Add diagnostics, wrap a location into allocator and alignment clause exprs. * semantics.cc: Include gcc-rich-location.h. (finish_omp_allocate): Improve and add diagnostics. gcc/testsuite/ChangeLog: * c-c++-common/gomp/allocate-9.c: Remove xfails. * c-c++-common/gomp/allocate-19.c: Remove xfails. * c-c++-common/gomp/allocate-20.c: New test. * g++.dg/gomp/allocate-14.C: New test. * g++.dg/gomp/allocate-15.C: New test. * g++.dg/gomp/allocate-16.C: New test. * g++.dg/gomp/allocate-17.C: New test. * g++.dg/gomp/allocate-18.C: New test. * g++.dg/gomp/allocate-19.C: New test. * g++.dg/gomp/allocate-handles-1.C: Remove xfails. Signed-off-by: Waffl3x --- gcc/cp/parser.cc | 76 +- gcc/cp/semantics.cc | 76 +- gcc/testsuite/c-c++-common/gomp/allocate-19.c | 10 +- gcc/testsuite/c-c++-common/gomp/allocate-20.c | 343 ++++++ gcc/testsuite/c-c++-common/gomp/allocate-9.c | 30 +- gcc/testsuite/g++.dg/gomp/allocate-14.C | 1042 +++++++++++++++++ gcc/testsuite/g++.dg/gomp/allocate-15.C | 50 + gcc/testsuite/g++.dg/gomp/allocate-16.C | 232 ++++ gcc/testsuite/g++.dg/gomp/allocate-17.C | 560 +++++++++ gcc/testsuite/g++.dg/gomp/allocate-18.C | 274 +++++ gcc/testsuite/g++.dg/gomp/allocate-19.C | 128 ++ .../g++.dg/gomp/allocate-handles-1.C | 34 +- 12 files changed, 2810 insertions(+), 45 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/allocate-20.c create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-14.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-15.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-16.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-17.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-18.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-19.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 2cec22a9386..924e52da6ea 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -47186,7 +47186,31 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) { tree nl = cp_parser_omp_var_list (parser, OMP_CLAUSE_ERROR, NULL_TREE); + /* Make diagnostics emit in forward order. */ + nl = nreverse (nl); + + const tree directive_ctx = current_scope (); { + auto var_is_in_scope = [&] (tree var_decl) + { + /* (OpenMP 6.0 311:11-12) An allocate directive must appear in the same + scope as the declarations of each of its list items and must follow + all such declarations. + + Note that it states declarations, not definitions, thus we can rely + on VAR_DECL's CP_DECL_CONTEXT. This will correctly reject an + allocate directive applied to a definition in a different scope. */ + if (!DECL_DECLARES_FUNCTION_P (directive_ctx)) + return CP_DECL_CONTEXT (var_decl) == directive_ctx; + /* This is O(n^2), caching names during traversal might be better. */ + for (tree block_var = current_binding_level->names; + block_var != NULL_TREE; + block_var = DECL_CHAIN (block_var)) + if (block_var == var_decl) + return true; + return false; + }; + hash_map seen_args; /* The head might have an error and need to be removed. */ tree *chain = &nl; for (tree node = nl; node != NULL_TREE; node = TREE_CHAIN (node)) @@ -47195,6 +47219,52 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) const tree arg_loc_wrapper = TREE_VALUE (node); const location_t arg_loc = EXPR_LOCATION (arg_loc_wrapper); + gcc_assert (var && var != error_mark_node); + /* Diagnose duplicate vars passed to the allocate directive. */ + if (location_t const *const orig_loc = seen_args.get (var)) + { + auto_diagnostic_group d; + /* If we could just get the location of the comma a fixit + hint would be viable here. */ + error_at (arg_loc, + "%qD already appeared as list item in this directive", + var); + inform (*orig_loc, "appeared first here"); + /* Remove the node. */ + *chain = TREE_CHAIN (node); + continue; + } + seen_args.put (var, arg_loc); + + /* Diagnose parameters passed to the allocate directive. */ + if (TREE_CODE (var) == PARM_DECL) + { + auto_diagnostic_group d; + error_at (arg_loc, + "function parameter %qD may not appear as list item in " + "an % directive", var); + inform (DECL_SOURCE_LOCATION (var), + "parameter %qD declared here", var); + /* Remove the node. */ + *chain = TREE_CHAIN (node); + continue; + } + + /* Do this before checking if the var was used in another allocate + directive, as the latter diagnostic implies that removing the var + from the previous directive would fix the problem. */ + if (!var_is_in_scope (var)) + { + auto_diagnostic_group d; + error_at (arg_loc, + "% directive must be in the same scope as " + "%qD", var); + inform (DECL_SOURCE_LOCATION (var), "declared here"); + /* Remove the node. */ + *chain = TREE_CHAIN (node); + continue; + } + tree attr = lookup_attribute ("omp allocate", DECL_ATTRIBUTES (var)); if (attr) @@ -47284,6 +47354,7 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) if (!parens.require_open (parser)) break; cp_expr expr = cp_parser_assignment_expression (parser); + expr.maybe_add_location_wrapper (); if (p[2] == 'i' && alignment) { error_at (cloc, "too many %qs clauses", "align"); @@ -47302,11 +47373,14 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) } while (true); cp_parser_require_pragma_eol (parser, pragma_tok); + /* We can still diagnose some things about allocator/alignment even if nl + is NULL_TREE. */ + finish_omp_allocate (pragma_tok->location, nl, allocator, alignment, - current_scope ()); + directive_ctx); } /* OpenMP 2.5: diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index ac81bbe9317..00c09e119c8 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see #include "gimplify.h" #include "contracts.h" #include "c-family/c-pragma.h" +#include "gcc-rich-location.h" /* There routines provide a modular interface to perform many parsing operations. They may therefore be used during actual parsing, or @@ -12393,6 +12394,62 @@ finish_omp_allocate (const location_t loc, const tree var_list, } (); /* IILE. */ const bool any_static_vars = any_of_vars (tree_static_p); + /* Create an auto_diagnostic_group before calling this. */ + const auto emit_diag_for_var_group + = [] (const var_predicate pred, + void (*diag_fn)(rich_location *, const char *, ...), + const char *msg, + const const_tree var_list) + { + auto next_match = [&pred] (const_tree first) + { + const_tree vn = first; + for (; vn != NULL_TREE; vn = TREE_CHAIN (vn)) + if (TREE_PURPOSE (vn) != error_mark_node + && pred (TREE_PURPOSE (vn))) + return vn; + return vn; + }; + gcc_assert (var_list != NULL_TREE); + const const_tree first_node = next_match (var_list); + gcc_assert (first_node != NULL_TREE); + + gcc_rich_location rich_loc (EXPR_LOCATION (TREE_VALUE (first_node))); + /* Don't add another range for the first node. */ + for (const_tree vn = next_match (TREE_CHAIN (first_node)); + vn != NULL_TREE; + vn = next_match (TREE_CHAIN (vn))) + rich_loc.add_range (EXPR_LOCATION (TREE_VALUE (vn))); + diag_fn (&rich_loc, msg); + + const_tree vn = first_node; + for (; vn != NULL_TREE; vn = next_match (TREE_CHAIN (vn))) + inform (DECL_SOURCE_LOCATION (TREE_PURPOSE (vn)), + "%qD declared here", TREE_PURPOSE (vn)); + }; + + /* Defer error marking vars until after other diagnostics are done, we might + still need access to them when diagnosing the allocator clause. */ + hash_set deferred_erroneous_var_nodes; + + const auto ref_var_p + = [] (const_tree t) -> bool { return TYPE_REF_P (TREE_TYPE (t)); }; + if (any_of_vars (ref_var_p)) + { + auto_diagnostic_group d; + emit_diag_for_var_group (ref_var_p, + &error_at, + G_("variables with reference type may not " + "appear in an % directive"), + var_list); + for (tree vn = var_list; vn != NULL_TREE; vn = TREE_CHAIN (vn)) + { + if (!ref_var_p (TREE_PURPOSE (vn))) + continue; + deferred_erroneous_var_nodes.add (vn); + } + } + /* (OpenMP 5.2, 174:15) Type: expression of integer type Properties: constant, positive */ const tree align = [&align_in] () @@ -12449,9 +12506,12 @@ finish_omp_allocate (const location_t loc, const tree var_list, allocator values. */ const auto emit_diag_for_static_vars = [&] () { - inform (UNKNOWN_LOCATION, - "because one or more variables with static storage duration " - "appear in the % directive"); + emit_diag_for_var_group (tree_static_p, + &inform, + G_("because one or more variables with " + "static storage duration appear " + "in the % directive"), + var_list); }; if (alloc_in == NULL_TREE) { @@ -12496,10 +12556,12 @@ finish_omp_allocate (const location_t loc, const tree var_list, return cached_alloc_type; } auto_diagnostic_group d; - error_at (EXPR_LOCATION (alloc_in), + gcc_rich_location loc (EXPR_LOCATION (alloc_in)); + maybe_add_include_fixit (&loc, "", false); + error_at (&loc, "% clause requires a valid declaration " "of %"); - inform (EXPR_LOCATION (alloc_in), + inform (&loc, "% is defined in header " "%<%>; this is probably fixable by adding " "%<#include %>"); @@ -12642,6 +12704,10 @@ finish_omp_allocate (const location_t loc, const tree var_list, TREE_PURPOSE (node) = error_mark_node; }; + for (tree vn = var_list; vn != NULL_TREE; vn = TREE_CHAIN (vn)) + if (deferred_erroneous_var_nodes.contains (vn)) + finalize_var_node_with_error (vn); + /* Even if there have been errors, save the current state, there might be more to diagnose on a later instantiation. */ if (processing_template_decl) diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-19.c b/gcc/testsuite/c-c++-common/gomp/allocate-19.c index cabd3875d1e..61d1f7ba4b7 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-19.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-19.c @@ -56,19 +56,17 @@ get () return &A1[q]; } -static int invalid1, okay1, invalid2, invalid3; /* { dg-note "'invalid\[123\]' declared here" "" { target c++ xfail c++ } } */ +static int invalid1, okay1, invalid2, invalid3; /* { dg-note "'invalid\[123\]' declared here" "" { target c++ } } */ #pragma omp allocate(invalid1) align(128) allocator(ompx_gnu_pinned_bogus_1) /* { dg-error "'allocator' clause requires a predefined allocator as 'invalid1' is static" "" { target c } } */ /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target c++ } .-1 } */ -/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-2 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ } .-2 } */ /* { dg-note "expression evaluates to '9'" "" { target c++ } .-3 } */ #pragma omp allocate(okay1) align(128) allocator(ompx_gnu_pinned_mem_alloc) /* Okay */ #pragma omp allocate(invalid2) align(128) allocator(ompx_gnu_pinned_bogus_2) /* { dg-error "'allocator' clause requires a predefined allocator as 'invalid2' is static" "" { target c } } */ /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target c++ } .-1 } */ -/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-2 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ } .-2 } */ /* { dg-note "expression evaluates to '199'" "" { target c++ } .-3 } */ #pragma omp allocate(invalid3) align(128) allocator(ompx_gnu_pinned_bogus_3) /* { dg-error "'allocator' clause requires a predefined allocator as 'invalid3' is static" "" { target c } } */ /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target c++ } .-1 } */ -/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-2 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ } .-2 } */ /* { dg-note "expression evaluates to '2001'" "" { target c++ } .-3 } */ - -/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ } 0 } */ diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-20.c b/gcc/testsuite/c-c++-common/gomp/allocate-20.c new file mode 100644 index 00000000000..604e4847a92 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/allocate-20.c @@ -0,0 +1,343 @@ +#include "allocate-allocator-handle.h" + +#pragma omp allocate() allocator(omp_default_mem_alloc) +/* { dg-error "expected identifier before '\\\)' token" "" { target c } .-1 } */ +/* { dg-error "expected unqualified-id before '\\\)' token" "" { target c++ } .-2 } */ + +/* The following tests are broken up into multiple lines to verify they refer + to the correct use of the variable, this seems to be the easiest way. + C does not currently refer to the correct line. */ +int g; +/* { dg-error "'g' already appeared as list item in an 'allocate' directive" "" { target c } .+1 } */ +#pragma omp allocate(\ +g,\ +g,\ +g,\ +g,\ +g) allocator(omp_default_mem_alloc) +/* { dg-note "appeared first here" "" { target c++ } .-5 } */ +/* { dg-error "'g' already appeared as list item in this directive" "" { target c++ } .-5 } */ +/* { dg-error "'g' already appeared as list item in this directive" "" { target c++ } .-5 } */ +/* { dg-error "'g' already appeared as list item in this directive" "" { target c++ } .-5 } */ +/* { dg-error "'g' already appeared as list item in this directive" "" { target c++ } .-5 } */ + +int g0_0; +int g0_1; +/* { dg-error "'g0_0' already appeared as list item in an 'allocate' directive" "" { target c } .+1 } */ +#pragma omp allocate(\ +g0_0,\ +g0_1,\ +g0_0,\ +g0_0) allocator(omp_default_mem_alloc) +/* { dg-note "appeared first here" "" { target c++ } .-4 } */ +/* { dg-error "'g0_0' already appeared as list item in this directive" "" { target c++ } .-3 } */ +/* { dg-error "'g0_0' already appeared as list item in this directive" "" { target c++ } .-3 } */ + +int g1_0; +int g1_1; +/* { dg-error "'g1_0' already appeared as list item in an 'allocate' directive" "" { target c } .+2 } */ +/* { dg-error "'g1_1' already appeared as list item in an 'allocate' directive" "" { target c } .+1 } */ +#pragma omp allocate(\ +g1_1,\ +g1_0,\ +g1_1,\ +g1_0,\ +g1_0,\ +g1_1) allocator(omp_default_mem_alloc) +/* { dg-note "appeared first here" "" { target c++ } .-6 } */ +/* { dg-note "appeared first here" "" { target c++ } .-6 } */ +/* { dg-error "'g1_1' already appeared as list item in this directive" "" { target c++ } .-6 } */ +/* { dg-error "'g1_0' already appeared as list item in this directive" "" { target c++ } .-6 } */ +/* { dg-error "'g1_0' already appeared as list item in this directive" "" { target c++ } .-6 } */ +/* { dg-error "'g1_1' already appeared as list item in this directive" "" { target c++ } .-6 } */ + +void f() +{ + int v; + /* { dg-error "'v' already appeared as list item in an 'allocate' directive" "" { target c} .+1 } */ + #pragma omp allocate(\ + v,\ + v,\ + v,\ + v,\ + v) + /* { dg-note "appeared first here" "" { target c++ } .-5 } */ + /* { dg-error "'v' already appeared as list item in this directive" "" { target c++ } .-5 } */ + /* { dg-error "'v' already appeared as list item in this directive" "" { target c++ } .-5 } */ + /* { dg-error "'v' already appeared as list item in this directive" "" { target c++ } .-5 } */ + /* { dg-error "'v' already appeared as list item in this directive" "" { target c++ } .-5 } */ + + int v0_0; + int v0_1; + /* { dg-error "'v0_0' already appeared as list item in an 'allocate' directive" "" { target c } .+1 } */ + #pragma omp allocate(\ + v0_0,\ + v0_1,\ + v0_0,\ + v0_0) + /* { dg-note "appeared first here" "" { target c++ } .-4 } */ + /* { dg-error "'v0_0' already appeared as list item in this directive" "" { target c++ } .-3 } */ + /* { dg-error "'v0_0' already appeared as list item in this directive" "" { target c++ } .-3 } */ + + int v1_0; + int v1_1; + /* { dg-error "'v1_0' already appeared as list item in an 'allocate' directive" "" { target c } .+2 } */ + /* { dg-error "'v1_1' already appeared as list item in an 'allocate' directive" "" { target c } .+1 } */ + #pragma omp allocate(\ + v1_1,\ + v1_0,\ + v1_1,\ + v1_0,\ + v1_0,\ + v1_1) + /* { dg-note "appeared first here" "" { target c++ } .-6 } */ + /* { dg-note "appeared first here" "" { target c++ } .-6 } */ + /* { dg-error "'v1_1' already appeared as list item in this directive" "" { target c++ } .-6 } */ + /* { dg-error "'v1_0' already appeared as list item in this directive" "" { target c++ } .-6 } */ + /* { dg-error "'v1_0' already appeared as list item in this directive" "" { target c++ } .-6 } */ + /* { dg-error "'v1_1' already appeared as list item in this directive" "" { target c++ } .-6 } */ +} + +void f_with_parm(int p) /* { dg-note "parameter 'p' declared here" "" { target c++ } } */ +{ + #pragma omp allocate(p) + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c } .+1 } */ + #pragma omp allocate(\ + p,\ + p,\ + p) + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c++ } .-3 } */ + /* { dg-note "appeared first here" "" { target c++ } .-4 } */ + /* { dg-error "'p' already appeared as list item in this directive" "" { target c++ } .-4 } */ + /* { dg-error "'p' already appeared as list item in this directive" "" { target c++ } .-4 } */ + + int v; + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c } .+2 } */ + /* { dg-error "'v' already appeared as list item in an 'allocate' directive" "" { target c } .+1 } */ + #pragma omp allocate(\ + v,\ + p,\ + v,\ + v,\ + p,\ + v,\ + v) + /* { dg-note "appeared first here" "" { target c++ } .-7 } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c++ } .-7 } */ + /* { dg-note "appeared first here" "" { target c++ } .-8 } */ + /* { dg-error "'v' already appeared as list item in this directive" "" { target c++ } .-8 } */ + /* { dg-error "'v' already appeared as list item in this directive" "" { target c++ } .-8 } */ + /* { dg-error "'p' already appeared as list item in this directive" "" { target c++ } .-8 } */ + /* { dg-error "'v' already appeared as list item in this directive" "" { target c++ } .-8 } */ + /* { dg-error "'v' already appeared as list item in this directive" "" { target c++ } .-8 } */ + + int v0_0; + int v0_1; + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c } .+2 } */ + /* { dg-error "'v0_0' already appeared as list item in an 'allocate' directive" "" { target c } .+1 } */ + #pragma omp allocate(\ + p,\ + v0_0,\ + v0_1,\ + v0_0,\ + v0_0) + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c++ } .-5 } */ + /* { dg-note "appeared first here" "" { target c++ } .-5 } */ + /* { dg-error "'v0_0' already appeared as list item in this directive" "" { target c++ } .-4 } */ + /* { dg-error "'v0_0' already appeared as list item in this directive" "" { target c++ } .-4 } */ + + int v1_0; + int v1_1; + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c } .+3 } */ + /* { dg-error "'v1_0' already appeared as list item in an 'allocate' directive" "" { target c } .+2 } */ + /* { dg-error "'v1_1' already appeared as list item in an 'allocate' directive" "" { target c } .+1 } */ + #pragma omp allocate(\ + v1_1,\ + p,\ + v1_0,\ + v1_1,\ + v1_0,\ + p,\ + v1_0,\ + v1_1,\ + p) + /* { dg-note "appeared first here" "" { target c++ } .-9 } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c++ } .-9 } */ + /* { dg-note "appeared first here" "" { target c++ } .-10 } */ + /* { dg-note "appeared first here" "" { target c++ } .-10 } */ + /* { dg-error "'v1_1' already appeared as list item in this directive" "" { target c++ } .-10 } */ + /* { dg-error "'v1_0' already appeared as list item in this directive" "" { target c++ } .-10 } */ + /* { dg-error "'p' already appeared as list item in this directive" "" { target c++ } .-10 } */ + /* { dg-error "'v1_0' already appeared as list item in this directive" "" { target c++ } .-10 } */ + /* { dg-error "'v1_1' already appeared as list item in this directive" "" { target c++ } .-10 } */ + /* { dg-error "'p' already appeared as list item in this directive" "" { target c++ } .-10 } */ +} + +/* Valid var used in allocator clause diagnostics. + (No diagnostic should be emitted related to 'alloc') */ + +void f_with_parm_and_allocator0(int p) /* { dg-note "parameter 'p' declared here" "" { target c++ } } */ +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; + #pragma omp allocate(p) allocator(alloc) + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c } .+1 } */ + #pragma omp allocate(\ + p,\ + p,\ + p) allocator(alloc) + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c++ } .-3 } */ + /* { dg-note "appeared first here" "" { target c++ } .-4 } */ + /* { dg-error "'p' already appeared as list item in this directive" "" { target c++ } .-4 } */ + /* { dg-error "'p' already appeared as list item in this directive" "" { target c++ } .-4 } */ + + int v; + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c } .+2 } */ + /* { dg-error "'v' already appeared as list item in an 'allocate' directive" "" { target c } .+1 } */ + #pragma omp allocate(\ + v,\ + p,\ + v,\ + v,\ + p,\ + v,\ + v) allocator(alloc) + /* { dg-note "appeared first here" "" { target c++ } .-7 } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c++ } .-7 } */ + /* { dg-note "appeared first here" "" { target c++ } .-8 } */ + /* { dg-error "'v' already appeared as list item in this directive" "" { target c++ } .-8 } */ + /* { dg-error "'v' already appeared as list item in this directive" "" { target c++ } .-8 } */ + /* { dg-error "'p' already appeared as list item in this directive" "" { target c++ } .-8 } */ + /* { dg-error "'v' already appeared as list item in this directive" "" { target c++ } .-8 } */ + /* { dg-error "'v' already appeared as list item in this directive" "" { target c++ } .-8 } */ + + int v0_0; + int v0_1; + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c } .+2 } */ + /* { dg-error "'v0_0' already appeared as list item in an 'allocate' directive" "" { target c } .+1 } */ + #pragma omp allocate(\ + p,\ + v0_0,\ + v0_1,\ + v0_0,\ + v0_0) allocator(alloc) + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c++ } .-5 } */ + /* { dg-note "appeared first here" "" { target c++ } .-5 } */ + /* { dg-error "'v0_0' already appeared as list item in this directive" "" { target c++ } .-4 } */ + /* { dg-error "'v0_0' already appeared as list item in this directive" "" { target c++ } .-4 } */ + + int v1_0; + int v1_1; + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c } .+3 } */ + /* { dg-error "'v1_0' already appeared as list item in an 'allocate' directive" "" { target c } .+2 } */ + /* { dg-error "'v1_1' already appeared as list item in an 'allocate' directive" "" { target c } .+1 } */ + #pragma omp allocate(\ + v1_1,\ + p,\ + v1_0,\ + v1_1,\ + v1_0,\ + p,\ + v1_0,\ + v1_1,\ + p) allocator(alloc) + /* { dg-note "appeared first here" "" { target c++ } .-9 } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c++ } .-9 } */ + /* { dg-note "appeared first here" "" { target c++ } .-10 } */ + /* { dg-note "appeared first here" "" { target c++ } .-10 } */ + /* { dg-error "'v1_1' already appeared as list item in this directive" "" { target c++ } .-10 } */ + /* { dg-error "'v1_0' already appeared as list item in this directive" "" { target c++ } .-10 } */ + /* { dg-error "'p' already appeared as list item in this directive" "" { target c++ } .-10 } */ + /* { dg-error "'v1_0' already appeared as list item in this directive" "" { target c++ } .-10 } */ + /* { dg-error "'v1_1' already appeared as list item in this directive" "" { target c++ } .-10 } */ + /* { dg-error "'p' already appeared as list item in this directive" "" { target c++ } .-10 } */ +} + +/* Var used in allocator clause diagnostics. Tests that invalid vars passed + into the allocate directive are not considered and bogus/repeat diagnostics + are not emitted. */ + +void f_with_parm_and_allocator1(int p) /* { dg-note "parameter 'p' declared here" "" { target c++ } } */ +{ + int v0; /* { dg-note "to be allocated variable declared here" "" { xfail c++ } } */ + omp_allocator_handle_t alloc0 = omp_default_mem_alloc; /* { dg-note "declared here" "" { xfail c++ } } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c } .+2 } */ + /* { dg-error "variable 'alloc0' used in the 'allocator' clause must be declared before 'v0'" "" { target c } .+1 } */ + #pragma omp allocate(\ + p,\ + v0)\ + allocator(alloc0) + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c++ } .-3 } */ + /* { dg-error "variable 'alloc0' used in the 'allocator' clause must be declared before 'v0'" "" { target c++ xfail c++ } .-2 } */ + + int v1; /* { dg-note "declared here" } */ + { + omp_allocator_handle_t alloc1 = omp_default_mem_alloc; + int v2; + /* { dg-error "'allocate' directive must be in the same scope as 'v1'" "" { target c } .+1 } */ + #pragma omp allocate(\ + v1,\ + v2\ + ) allocator(alloc1) + /* { dg-error "'allocate' directive must be in the same scope as 'v1'" "" { target c++ } .-3 } */ + } + { + int v3; /* { dg-note "to be allocated variable declared here" "" { xfail c++ } } */ + omp_allocator_handle_t alloc2 = omp_default_mem_alloc; /* { dg-note "declared here" "" { xfail c++ } } */ + /* { dg-error "variable 'alloc2' used in the 'allocator' clause must be declared before 'v3'" "" { target c } .+2 } */ + /* { dg-error "'allocate' directive must be in the same scope as 'v1'" "" { target c } .+1 } */ + #pragma omp allocate(\ + v1,\ + v3\ + ) allocator(alloc2) + /* { dg-error "'allocate' directive must be in the same scope as 'v1'" "" { target c++ } .-3 } */ + /* { dg-error "variable 'alloc2' used in the 'allocator' clause must be declared before 'v3'" "" { target c++ xfail c++ } .-2 } */ + } +} + +/* First argument valid. + These cases could still be fleshed out a bit more, there was original a typo + that caused diagnostics to always refer to the first argument of the + directive in the C++ front end, these tests are for that case. */ + +void first_valid0() +{ + int a; /* { dg-note "declared here" } */ + { + int v; + /* { dg-error "'allocate' directive must be in the same scope as 'a'" "" { target c } .+1 } */ + #pragma omp allocate(\ + v,\ + a) /* { dg-error "'allocate' directive must be in the same scope as 'a'" "" { target c++ } } */ + } +} + +void first_valid1(int p) /* { dg-note "parameter 'p' declared here" "" { target c++ } } */ +{ + int v; + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c } .+1 } */ + #pragma omp allocate(\ + v,\ + p) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c++ } } */ +} + +void first_valid2(int p) /* { dg-note "parameter 'p' declared here" "" { target c++ } } */ +{ + int a; /* { dg-note "declared here" } */ + { + int v; + /* { dg-error "'allocate' directive must be in the same scope as 'a'" "" { target c } .+2 } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c } .+1 } */ + #pragma omp allocate(\ + v,\ + a,\ + p) + /* { dg-error "'allocate' directive must be in the same scope as 'a'" "" { target c++ } .-2 } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c++ } .-2 } */ + } +} + +/* Missing cases that contain undeclared variables. */ diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-9.c b/gcc/testsuite/c-c++-common/gomp/allocate-9.c index 52bae8c9a6a..872f7956cdd 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-9.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-9.c @@ -5,7 +5,7 @@ static int A2[5] = {1,2,3,4,5}; static int A3[5] = {1,2,3,4,5}; static int A4[5] = {1,2,3,4,5}; /* { dg-line A4_decl } */ static int A5[5] = {1,2,3,4,5}; /* { dg-line A5_decl } */ -int B, C, C2, D; /* { dg-note "declared here" "" { xfail c++ } } */ +int B, C, C2, D; /* { dg-note "declared here" } */ /* If the following fails because of added predefined allocators, please update - include/gomp-constants.h's GOMP_OMP_PREDEF_ALLOC_MAX or GOMP_OMPX_PREDEF_ALLOC_MAX @@ -18,9 +18,9 @@ int B, C, C2, D; /* { dg-note "declared here" "" { xfail c++ } } */ #pragma omp allocate(A1) align(32) allocator((omp_allocator_handle_t) 9) /* { dg-error "'allocator' clause requires a predefined allocator as 'A1' is static" "" { target c } .-1 } */ /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target c++ } .-2 } */ -/* { dg-message "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-3 } */ +/* { dg-message "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ } .-3 } */ /* { dg-message "expression evaluates to '9'" "" { target c++ } .-4 } */ -/* { dg-note "'A1' declared here" "" { target c++ xfail c++ } A_decl } */ +/* { dg-note "'A1' declared here" "" { target c++ } A_decl } */ // typo in allocator name: #pragma omp allocate(A2) allocator(omp_low_latency_mem_alloc) /* { dg-error "'omp_low_latency_mem_alloc' undeclared here \\(not in a function\\); did you mean 'omp_low_lat_mem_alloc'\\?" "" { target c } .-1 } */ @@ -35,8 +35,8 @@ int B, C, C2, D; /* { dg-note "declared here" "" { xfail c++ } } */ #pragma omp allocate(A4) align(32) /* { dg-error "'allocator' clause required for static variable 'A4'" "" { target c } .-1 } */ /* { dg-error "'allocator' clause must be specified" "" { target c++ } .-2 } */ -/* { dg-message "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-3 } */ -/* { dg-note "'A4' declared here" "" { target c++ xfail c++ } A4_decl } */ +/* { dg-message "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ } .-3 } */ +/* { dg-note "'A4' declared here" "" { target c++ } A4_decl } */ /* "expression in the clause must be a constant expression that evaluates to one of the predefined memory allocator values -> omp_low_lat_mem_alloc" */ @@ -49,9 +49,9 @@ int B, C, C2, D; /* { dg-note "declared here" "" { xfail c++ } } */ #pragma omp allocate(A5) align(32) allocator(omp_null_allocator) /* { dg-error "'allocator' clause requires a predefined allocator as 'A5' is static" "" { target c } .-1 } */ /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target c++ } .-2 } */ -/* { dg-message "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-3 } */ +/* { dg-message "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ } .-3 } */ /* { dg-message "expression evaluates to '0'" "" { target c++ } .-4 } */ -/* { dg-note "'A5' declared here" "" { target c++ xfail c++ } A5_decl } */ +/* { dg-note "'A5' declared here" "" { target c++ } A5_decl } */ #pragma omp allocate(C2) align(32) allocator(omp_large_cap_mem_alloc) @@ -59,7 +59,7 @@ int B, C, C2, D; /* { dg-note "declared here" "" { xfail c++ } } */ // allocate directive in same TU int f() { - #pragma omp allocate(D) align(32) allocator(omp_large_cap_mem_alloc) /* { dg-error "'allocate' directive must be in the same scope as 'D'" "" { xfail c++ } } */ + #pragma omp allocate(D) align(32) allocator(omp_large_cap_mem_alloc) /* { dg-error "'allocate' directive must be in the same scope as 'D'" } */ return A1[0]; } @@ -71,29 +71,29 @@ int g() /* { dg-note "'a2' previously appeared here" "" { target c++ } .-2 } */ { int c2=3; - #pragma omp allocate(c2, b2) /* { dg-error "'allocate' directive must be in the same scope as 'b2'" "" { xfail c++ } } */ -/* { dg-note "declared here" "" { target *-*-* xfail c++ } g_a2_b2_decl } */ + #pragma omp allocate(c2, b2) /* { dg-error "'allocate' directive must be in the same scope as 'b2'" } */ +/* { dg-note "declared here" "" { target *-*-* } g_a2_b2_decl } */ return c2+a2+b2; } } int h(int q) { - #pragma omp allocate(q) /* { dg-error "function parameter 'q' may not appear as list item in an 'allocate' directive" "" { xfail c++ } } */ -/* { dg-note "parameter 'q' declared here" "" { target c++ xfail c++ } .-3 } */ + #pragma omp allocate(q) /* { dg-error "function parameter 'q' may not appear as list item in an 'allocate' directive" } */ +/* { dg-note "parameter 'q' declared here" "" { target c++ } .-3 } */ return q; } int k () { - static int var3 = 8; /* { dg-note "'var3' declared here" "" { target c++ xfail c++ } } */ + static int var3 = 8; /* { dg-note "'var3' declared here" "" { target c++ } } */ #pragma omp allocate(var3) allocator((omp_allocator_handle_t)-1L) /* { dg-error "'allocator' clause requires a predefined allocator as 'var3' is static" "" { target c } .-1 } */ /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target c++ } .-2 } */ - /* { dg-message "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ xfail c++ } .-3 } */ + /* { dg-message "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target c++ } .-3 } */ /* { dg-message "expression evaluates to '\\d+'" "" { target c++ } .-4 } */ return var3; } -/* { dg-bogus "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail c++ } 0 } */ +/* { dg-bogus "because one or more variables with static storage duration appear in the 'allocate' directive" 0 } */ diff --git a/gcc/testsuite/g++.dg/gomp/allocate-14.C b/gcc/testsuite/g++.dg/gomp/allocate-14.C new file mode 100644 index 00000000000..d40288d957d --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-14.C @@ -0,0 +1,1042 @@ +#include "allocate-allocator-handle.h" + +/* Diagnostics for invalid cases, including a number of negative cases that + should not be diagnosed. */ + +/**************************************************** + * Reference variable used in an allocate directive * + ****************************************************/ + +void ref_var() +{ + int a = 42; + int& ref = a; /* { dg-note "'ref' declared here" } */ + #pragma omp allocate(ref) /* { dg-error "variables with reference type may not appear in an 'allocate' directive" } */ +} + +template +void ref_var_templ_not_instantiated() +{ + int a = 42; + int& ref = a; /* { dg-note "'ref' declared here" } */ + #pragma omp allocate(ref) /* { dg-error "variables with reference type may not appear in an 'allocate' directive" } */ +} + +template +void dependent_ref_var_templ_not_instantiated() +{ + T a = 42; + T& t = a; /* { dg-note "'t' declared here" } */ + #pragma omp allocate(t) /* { dg-error "variables with reference type may not appear in an 'allocate' directive" } */ +} + +template +void dependent_var_templ_not_instantiated() +{ + T t = 42; + #pragma omp allocate(t) +} + +template +void dependent_var_templ_0() +{ + T t = 42; + #pragma omp allocate(t) +} + +template +void dependent_var_templ_1() +{ + T t = 42; /* { dg-note "'t' declared here" } */ + #pragma omp allocate(t) /* { dg-error "variables with reference type may not appear in an 'allocate' directive" } */ +} + +template +void dependent_var_templ_2() +{ + int a; + T t = a; /* { dg-note "'t' declared here" } */ + #pragma omp allocate(t) /* { dg-error "variables with reference type may not appear in an 'allocate' directive" } */ +} + +void instantiate_var_templ() +{ + dependent_var_templ_0(); /* { dg-bogus "required from here" } */ + dependent_var_templ_1(); /* { dg-bogus "required from here" } */ + dependent_var_templ_1(); /* { dg-message "required from here" } */ + dependent_var_templ_2(); /* { dg-bogus "required from here" } */ + dependent_var_templ_2(); /* { dg-message "required from here" } */ + dependent_var_templ_2(); /* { dg-message "required from here" } */ +} + + +/**************************** + * Invalid allocator clause * + ****************************/ + +template +void nttp_allocator() +{ + int a; + #pragma omp allocate(a) allocator(Alloc) +} + +template +void nttp_allocator_uninstantiated() +{ + int a; + #pragma omp allocate(a) allocator(Alloc) +} + +template +void nttp_wrong_type_allocator_uninstantiated() +{ + int a; + #pragma omp allocate(a) allocator(Alloc) /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { xfail *-*-* } } */ +} + +template +void nttp_dependent_type_allocator() +{ + int a; + #pragma omp allocate(a) allocator(Alloc) /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" } */ +} + +template +void nttp_dependent_type_allocator_uninstantiated() +{ + int a; + #pragma omp allocate(a) allocator(Alloc) +} + +void instantiate_nttp_allocator() +{ + nttp_allocator(); /* { dg-bogus "required from here" } */ + nttp_dependent_type_allocator(); /* { dg-bogus "required from here" } */ + nttp_dependent_type_allocator(); /* { dg-message "required from here" } */ +} + +template +void nttp_allocator_static() +{ + static int a; /* { dg-note "'a' declared here" } */ + #pragma omp allocate(a) allocator(Alloc) + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } .-1 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ + /* { dg-note "expression evaluates to '1024'" "" { xfail *-*-* } .-3 }*/ +} + +template +void nttp_allocator_uninstantiated_static() +{ + static int a; + #pragma omp allocate(a) allocator(Alloc) +} + +template +void nttp_wrong_type_allocator_uninstantiated_static() +{ + static int a; + #pragma omp allocate(a) allocator(Alloc) /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { xfail *-*-* } } */ +} + +template +void nttp_dependent_type_allocator_static_0() +{ + static int a; /* { dg-note "'a' declared here" } */ + #pragma omp allocate(a) allocator(Alloc) + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } .-1 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ + /* { dg-note "expression evaluates to '1024'" "" { xfail *-*-* } .-3 }*/ +} + +template +void nttp_dependent_type_allocator_static_1() +{ + static int a; + #pragma omp allocate(a) allocator(Alloc) /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" } */ +} + +template +void nttp_dependent_type_allocator_uninstantiated_static() +{ + static int a; + #pragma omp allocate(a) allocator(Alloc) +} + +#define DEFINITELY_NOT_PREDEFINED static_cast(1024) + +void instantiate_nttp_allocator_static() +{ + nttp_allocator_static(); /* { dg-bogus "required from here" } */ + nttp_allocator_static(); /* { dg-message "required from here" } */ + nttp_dependent_type_allocator_static_0(); /* { dg-bogus "required from here" } */ + nttp_dependent_type_allocator_static_0(); /* { dg-message "required from here" } */ + nttp_dependent_type_allocator_static_1(); /* { dg-message "required from here" } */ +} + +#undef DEFINITELY_NOT_PREDEFINED + + +template +void templ_allocator_param_0(AllocT alloc) +{ + int a; + #pragma omp allocate(a) allocator(alloc) +} + +template +void templ_allocator_param_1(AllocT alloc) +{ + int a; + #pragma omp allocate(a) allocator(alloc) /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" } */ +} + +template +void templ_allocator_param_uninstantiated(AllocT alloc) +{ + int a; + #pragma omp allocate(a) allocator(alloc) +} + +void instantiate_templ_allocator_param() +{ + templ_allocator_param_0(omp_default_mem_alloc); /* { dg-bogus "required from here" } */ + templ_allocator_param_1(omp_default_mem_alloc); /* { dg-bogus "required from here" } */ + templ_allocator_param_1(0); /* { dg-message "required from here" } */ +} + + +template +void missing_allocator_clause_uninstantiated() +{ + static int a; /* { dg-note "'a' declared here" } */ + #pragma omp allocate(a) + /* { dg-error "'allocator' clause must be specified" "" { target *-*-* } .-1 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 }*/ +} + +/* Cases that are never constant omp_allocator_handle_t expressions (and are required to be) */ + +template +void allocator_param_static_uninstantiated(omp_allocator_handle_t alloc) +{ + static int a; /* { dg-note "'a' declared here" "" { xfail *-*-* } } */ + #pragma omp allocate(a) allocator(alloc) + /* { dg-error "'alloc' is not a constant expression" "" { xfail *-*-* } .-1 }*/ + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } .-2 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-3 }*/ +} + +template +void allocator_var_static_uninstantiated() +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note "'omp_allocator_handle_t alloc' is not const" "" { xfail *-*-* } } */ + static int a; /* { dg-note "'a' declared here" "" { xfail *-*-* } } */ + #pragma omp allocate(a) allocator(alloc) + /* { dg-error "the value of 'alloc' is not usable in a constant expression" "" { xfail *-*-* } .-1 }*/ + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } .-2 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-3 }*/ +} + +/* While weird, there are inputs for AllocT that are well-formed here, + therefore these cases can not be diagnosed until instantiation. */ + +template +void templ_allocator_param_static_uninstantiated(AllocT alloc) +{ + static int a; + #pragma omp allocate(a) allocator(alloc) /* { dg-bogus "" } */ +} + +template +void templ_allocator_var_static_uninstantiated() +{ + AllocT alloc = omp_default_mem_alloc; + static int a; + #pragma omp allocate(a) allocator(alloc) /* { dg-bogus "" } */ +} + + +/************************ + * Invalid align clause * + ************************/ + +template +void nttp_align() +{ + int a; + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ +} + +template +void nttp_align_uninstantiated() +{ + int a; + #pragma omp allocate(a) align(Align) +} + +template +void nttp_wrong_type_align_uninstantiated() +{ + int a; + #pragma omp allocate(a) align(Align) + /* { dg-error "could not convert 'Align' from '\[^\n\r\]+' to '\[^\n\r\]+'" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-2 } */ +} + +template +void nttp_dependent_type_align_0() +{ + int a; + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ +} + +template +void nttp_dependent_type_align_1() +{ + int a; + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ +} + +template +void nttp_dependent_type_align_uninstantiated() +{ + int a; + #pragma omp allocate(a) align(Align) +} + +void instantiate_nttp_align() +{ + nttp_align<32>(); + nttp_align<42>(); /* { dg-message "required from here" } */ + nttp_dependent_type_align_0(); /* { dg-bogus "required from here" } */ + nttp_dependent_type_align_0(); /* { dg-message "required from here" } */ + nttp_dependent_type_align_1(); /* { dg-bogus "required from here" } */ + /* We just need any non integer NTTP that is valid in c++98, a fptr fits the bill. */ + nttp_dependent_type_align_1(); /* { dg-message "required from here" } */ + /* { dg-error "could not convert 'instantiate_nttp_align' from 'void \\(\\*\\)\\(\\)' to '\[^\n\r\]+'" "Bugged location, see comment" { target *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "Bugged location, see comment" { target *-*-* } .-2 } */ + /* { dg-error "conversion from 'void \\(\\*\\)\\(\\)' to '\[^\n\r\]+' in a converted constant expression" "Bugged location, see comment" { target *-*-* } .-3 } */ + /* I believe this diagnostic is bugged, it should refer to where the + expression is used, not where it originated from. This isn't a bug for + this feature though so I'm making the test case work around it, + when this bug is fixed this test case, and the xfail in the test case in + nttp_dependent_type_align_1 can be remove. */ +} + +/* Cases that are never constant integer expressions (always required for the align clause.) */ + +template +void align_param_uninstantiated(int align) +{ + int a; + #pragma omp allocate(a) align(align) + /* { dg-error "'align' is not a constant expression" "" { xfail *-*-* } .-1 }*/ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-2 } */ +} + +template +void align_var_uninstantiated() +{ + int align = 32; /* { dg-note "'int align' is not const" "" { xfail *-*-* } } */ + int a; + #pragma omp allocate(a) align(align) + /* { dg-error "the value of 'align' is not usable in a constant expression" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-2 } */ +} + +/* While weird, there are inputs for AlignT that are well-formed here, + therefore these cases can not be diagnosed until instantiation. */ + +template +void templ_align_param_uninstantiated(AlignT align) +{ + int a; + #pragma omp allocate(a) align(align) /* { dg-bogus "" } */ +} + +template +void templ_align_var_uninstantiated() +{ + AlignT align = 32; + int a; + #pragma omp allocate(a) align(align) /* { dg-bogus "" } */ +} + + + +/*************** + * Mixed cases * + ***************/ + +template +void all_dependent_uninstantiated() +{ + int b = 42; + Var a = b; + #pragma omp allocate(a) allocator(Alloc) align(Align) +} + +template +void all_dependent_valid() +{ + int b = 42; + Var a = b; + #pragma omp allocate(a) allocator(Alloc) align(Align) +} + +template +void all_dependent_0() +{ + int b = 42; + Var a = b; /* { dg-note "'a' declared here" } */ + #pragma omp allocate(a) allocator(Alloc) align(Align) + /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ +} + +template +void all_dependent_1() +{ + int b = 42; + Var a = b; + #pragma omp allocate(a) allocator(Alloc) align(Align) + /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target *-*-* } .-1 } */ +} + +template +void all_dependent_2() +{ + int b = 42; + Var a = b; + #pragma omp allocate(a) allocator(Alloc) align(Align) + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ +} + +template +void all_dependent_3() +{ + int b = 42; + Var a = b; /* { dg-note "'a' declared here" } */ + #pragma omp allocate(a) allocator(Alloc) align(Align) + /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ + /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target *-*-* } .-2 } */ +} + +template +void all_dependent_4() +{ + int b = 42; + Var a = b; /* { dg-note "'a' declared here" } */ + #pragma omp allocate(a) allocator(Alloc) align(Align) + /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-2 } */ +} + +template +void all_dependent_5() +{ + int b = 42; + Var a = b; + #pragma omp allocate(a) allocator(Alloc) align(Align) + /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-2 } */ +} + +template +void all_dependent_6() +{ + int b = 42; + Var a = b; /* { dg-note "'a' declared here" } */ + #pragma omp allocate(a) allocator(Alloc) align(Align) + /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ + /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target *-*-* } .-2 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-3 } */ +} + +void instantiate_all_dependent() +{ + all_dependent_valid(); + /* Don't test the type mismatch for the align clause here, it's diagnostic + location is buggy, and the error message is the same. We just really want + to test that we aren't emitting bogus errors when multiple things are + dependent, so it's unnecessary to test that case again. */ + all_dependent_0(); /* { dg-bogus "required from here" } */ + all_dependent_0(); /* { dg-message "required from here" } */ + + all_dependent_1(); /* { dg-bogus "required from here" } */ + all_dependent_1(); /* { dg-message "required from here" } */ + + all_dependent_2(); /* { dg-bogus "required from here" } */ + all_dependent_2(); /* { dg-message "required from here" } */ + + all_dependent_3(); /* { dg-bogus "required from here" } */ + all_dependent_3(); /* { dg-message "required from here" } */ + + all_dependent_4(); /* { dg-bogus "required from here" } */ + all_dependent_4(); /* { dg-message "required from here" } */ + + all_dependent_5(); /* { dg-bogus "required from here" } */ + all_dependent_5(); /* { dg-message "required from here" } */ + + all_dependent_6(); /* { dg-bogus "required from here" } */ + all_dependent_6(); /* { dg-message "required from here" } */ +} + +/* We are missing combined cases for static var used in the allocate directive, + but it should be fine, the combined cases immediately above are probably + overkill as it is. */ + + +/****************************** + * Invalid allocate directive * + ******************************/ + +/* We are only testing that we gracefully handle an empty list of vars. */ + +void no_parens() +{ + #pragma omp allocate /* { dg-error "expected '\\\(' before end of line" } */ +} + +template +void templ_no_parens() +{ + #pragma omp allocate /* { dg-error "expected '\\\(' before end of line" } */ +} +template void templ_no_parens(); + +template +void templ_no_parens_uninstantiated() +{ + #pragma omp allocate /* { dg-error "expected '\\\(' before end of line" } */ +} + +void no_vars() +{ + #pragma omp allocate() /* { dg-error "expected unqualified-id before '\\\)' token" } */ +} + +template +void templ_no_vars() +{ + #pragma omp allocate() /* { dg-error "expected unqualified-id before '\\\)' token" } */ +} +template void templ_no_vars(); + +template +void templ_no_vars_uninstantiated() +{ + #pragma omp allocate() /* { dg-error "expected unqualified-id before '\\\)' token" } */ +} + +/* We can't diagnose anything about the allocator clause if we have no + variables, but we do need to make sure we don't crash. */ + +void no_vars_allocator() +{ + #pragma omp allocate() allocator(omp_default_mem_alloc) /* { dg-error "expected unqualified-id before '\\\)' token" } */ +} + +template +void templ_no_vars_allocator() +{ + #pragma omp allocate() allocator(omp_default_mem_alloc) /* { dg-error "expected unqualified-id before '\\\)' token" } */ +} +template void templ_no_vars_allocator(); + +template +void templ_no_vars_allocator_uninstantiated() +{ + #pragma omp allocate() allocator(omp_default_mem_alloc) /* { dg-error "expected unqualified-id before '\\\)' token" } */ +} + +/* We can still diagnose errors about the align clause without any vars. */ + +void no_vars_invalid_align() +{ + #pragma omp allocate() align(42) /* { dg-error "expected unqualified-id before '\\\)' token" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ +} + +template +void templ_no_vars_invalid_align() +{ + #pragma omp allocate() align(42) /* { dg-error "expected unqualified-id before '\\\)' token" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ +} +template void templ_no_vars_invalid_align(); + +template +void templ_no_vars_invalid_align_uninstantiated() +{ + #pragma omp allocate() align(42) /* { dg-error "expected unqualified-id before '\\\)' token" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ +} + +template +void templ_no_vars_dep_align() +{ + #pragma omp allocate() align(Align) /* { dg-error "expected unqualified-id before '\\\)' token" } */ +} +template void templ_no_vars_dep_align<32>(); + +template +void templ_no_vars_dep_align_invalid() +{ + #pragma omp allocate() align(Align) /* { dg-error "expected unqualified-id before '\\\)' token" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ +} +template void templ_no_vars_dep_align_invalid<42>(); + +template +void templ_no_vars_dep_align_uninstantiated() +{ + #pragma omp allocate() align(Align) /* { dg-error "expected unqualified-id before '\\\)' token" } */ +} + +/********************************* + * All vars in directive invalid * + *********************************/ + +void invalid_vars_param(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + #pragma omp allocate(p) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" } */ +} + +template +void templ_invalid_vars_param(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + #pragma omp allocate(p) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" } */ +} +template void templ_invalid_vars_param(int); + +template +void templ_invalid_vars_param_uninstantiated(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + #pragma omp allocate(p) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" } */ +} + +void invalid_vars_out_of_scope() +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + } +} + +template +void templ_invalid_vars_out_of_scope() +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + } +} +template void templ_invalid_vars_out_of_scope(); + +template +void templ_invalid_vars_out_of_scope_uninstantiated() +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + } +} + +void invalid_vars_out_of_scope_and_param(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a, p) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + } +} + +template +void templ_invalid_vars_out_of_scope_and_param(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a, p) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + } +} +template void templ_invalid_vars_out_of_scope_and_param(int); + +template +void templ_invalid_vars_out_of_scope_and_param_uninstantiated(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a, p) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + } +} + +/* Same as above, we can't diagnose anything about the allocator clause if we + have no variables, but we do need to make sure we don't crash. */ + +void invalid_vars_param_allocator(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + #pragma omp allocate(p) allocator(omp_default_mem_alloc) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" } */ +} + +template +void templ_invalid_vars_param_allocator(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + #pragma omp allocate(p) allocator(omp_default_mem_alloc) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" } */ +} +template void templ_invalid_vars_param_allocator(int); + +template +void templ_invalid_vars_param_allocator_uninstantiated(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + #pragma omp allocate(p) allocator(omp_default_mem_alloc) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" } */ +} + +void invalid_vars_out_of_scope_allocator() +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a) allocator(omp_default_mem_alloc) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + } +} + +template +void templ_invalid_vars_out_of_scope_allocator() +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a) allocator(omp_default_mem_alloc) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + } +} +template void templ_invalid_vars_out_of_scope_allocator(); + +template +void templ_invalid_vars_out_of_scope_allocator_uninstantiated() +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a) allocator(omp_default_mem_alloc) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + } +} + +void invalid_vars_out_of_scope_and_param_allocator(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a, p) allocator(omp_default_mem_alloc) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + } +} + +template +void templ_invalid_vars_out_of_scope_and_param_allocator(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a, p) allocator(omp_default_mem_alloc) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + } +} +template void templ_invalid_vars_out_of_scope_and_param_allocator(int); + +template +void templ_invalid_vars_out_of_scope_and_param_allocator_uninstantiated(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a, p) allocator(omp_default_mem_alloc) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + } +} + +/* Invalid vars with non-dependent invalid align */ + +void invalid_vars_param_align_invalid(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + #pragma omp allocate(p) align(42) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ +} + +template +void templ_invalid_vars_param_align_invalid(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + #pragma omp allocate(p) align(42) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ +} +template void templ_invalid_vars_param_align_invalid(int); + +template +void templ_invalid_vars_param_align_invalid_uninstantiated(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + #pragma omp allocate(p) align(42) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ +} + +void invalid_vars_out_of_scope_align_invalid() +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a) align(42) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ + } +} + +template +void templ_invalid_vars_out_of_scope_align_invalid() +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a) align(42) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ + } +} +template void templ_invalid_vars_out_of_scope_align_invalid(); + +template +void templ_invalid_vars_out_of_scope_align_invalid_uninstantiated() +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a) align(42) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + } +} + +void invalid_vars_out_of_scope_and_param_align_invalid(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a, p) align(42) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-2 } */ + } +} + +template +void templ_invalid_vars_out_of_scope_and_param_align_invalid(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a, p) align(42) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-2 } */ + } +} +template void templ_invalid_vars_out_of_scope_and_param_align_invalid(int); + +template +void templ_invalid_vars_out_of_scope_and_param_align_invalid_uninstantiated(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a, p) align(42) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-2 } */ + } +} + + +/* Param (dependent align) */ + +template +void templ_invalid_vars_param_dependent_align_uninstantiated(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + #pragma omp allocate(p) align(Align) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" } */ +} + +template +void templ_invalid_vars_param_dependent_align(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + #pragma omp allocate(p) align(Align) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" } */ +} +template void templ_invalid_vars_param_dependent_align<32>(int); + +template +void templ_invalid_vars_param_dependent_align_invalid(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + #pragma omp allocate(p) align(Align) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ +} +template void templ_invalid_vars_param_dependent_align_invalid<42>(int); + + +/* Out of scope (dependent align) */ + +template +void templ_invalid_vars_out_of_scope_dependent_align_uninstantiated() +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a) align(Align) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + } +} + +template +void templ_invalid_vars_out_of_scope_dependent_align() +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a) align(Align) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + } +} +template void templ_invalid_vars_out_of_scope_dependent_align<32>(); + +template +void templ_invalid_vars_out_of_scope_dependent_align_invalid() +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a) align(Align) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + } +} +template void templ_invalid_vars_out_of_scope_dependent_align_invalid<42>(); + + +/* Param and out of scope (dependent align) */ + +template +void templ_invalid_vars_out_of_scope_and_param_dependent_align_uninstantiated(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a, p) align(Align) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + } +} + +template +void templ_invalid_vars_out_of_scope_and_param_dependent_align(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a, p) align(Align) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + } +} +template void templ_invalid_vars_out_of_scope_and_param_dependent_align<32>(int); + +template +void templ_invalid_vars_out_of_scope_and_param_dependent_align_invalid(int p) /* { dg-note "parameter 'p' declared here" } */ +{ + int a; /* { dg-note "declared here" } */ + { + #pragma omp allocate(a, p) align(Align) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-2 } */ + } +} +template void templ_invalid_vars_out_of_scope_and_param_dependent_align_invalid<42>(int); + + + +/**************************************************** + * uses of var in multiple directives in a template * + ****************************************************/ + +/* We are missing a lot of cases here but testing all of them shouldn't be + necessary. Uses of variables in multiple directives are diagnosed during + parsing so templates shouldn't change anything. This is of course as long + as we don't change that, and these cases should be enough to deter anyone + from doing so. */ + +template +void multiple_uses_non_dependent_directive_uninstantiated() +{ + int a; + #pragma omp allocate(a) /* { dg-note "'a' previously appeared here" } */ + #pragma omp allocate(a) /* { dg-error "'a' already appeared as list item in an 'allocate' directive" } */ +} + +template +void multiple_uses_non_dependent_directive() +{ + int a; + #pragma omp allocate(a) /* { dg-note "'a' previously appeared here" } */ + #pragma omp allocate(a) /* { dg-error "'a' already appeared as list item in an 'allocate' directive" } */ +} +template void multiple_uses_non_dependent_directive(); + + +template +void multiple_uses_dep_directive_before_align_uninstantiated() +{ + int a; + #pragma omp allocate(a) align(Align) /* { dg-note "'a' previously appeared here" } */ + #pragma omp allocate(a) /* { dg-error "'a' already appeared as list item in an 'allocate' directive" } */ +} + +template +void multiple_uses_dep_directive_before_valid_align() +{ + int a; + #pragma omp allocate(a) align(Align) /* { dg-note "'a' previously appeared here" } */ + #pragma omp allocate(a) /* { dg-error "'a' already appeared as list item in an 'allocate' directive" } */ +} +template void multiple_uses_dep_directive_before_valid_align<32>(); + +template +void multiple_uses_dep_directive_before_invalid_align() +{ + int a; + #pragma omp allocate(a) align(Align) /* { dg-note "'a' previously appeared here" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + #pragma omp allocate(a) /* { dg-error "'a' already appeared as list item in an 'allocate' directive" } */ +} +template void multiple_uses_dep_directive_before_invalid_align<42>(); + + +/* Dependent directive after the independent one. */ + +template +void multiple_uses_dep_directive_after_align_uninstantiated() +{ + int a; + #pragma omp allocate(a) /* { dg-note "'a' previously appeared here" } */ + #pragma omp allocate(a) align(Align) /* { dg-error "'a' already appeared as list item in an 'allocate' directive" } */ +} + +template +void multiple_uses_dep_directive_after_valid_align() +{ + int a; + #pragma omp allocate(a) /* { dg-note "'a' previously appeared here" } */ + #pragma omp allocate(a) align(Align) /* { dg-error "'a' already appeared as list item in an 'allocate' directive" } */ +} +template void multiple_uses_dep_directive_after_valid_align<32>(); + +template +void multiple_uses_dep_directive_after_invalid_align() +{ + int a; + #pragma omp allocate(a) /* { dg-note "'a' previously appeared here" } */ + #pragma omp allocate(a) align(Align) /* { dg-error "'a' already appeared as list item in an 'allocate' directive" } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ +} +template void multiple_uses_dep_directive_after_invalid_align<42>(); + +/* These are fixed by the later location wrapping patch. */ +/* { dg-bogus "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } 0 } */ +/* { dg-bogus "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } 0 } */ +/* { dg-bogus "expression evaluates to '1024'" "" { xfail *-*-* } 0 } */ diff --git a/gcc/testsuite/g++.dg/gomp/allocate-15.C b/gcc/testsuite/g++.dg/gomp/allocate-15.C new file mode 100644 index 00000000000..605e10e477f --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-15.C @@ -0,0 +1,50 @@ +/* { dg-do compile { target c++11 } } */ + +/* Diagnostics for rvalue reference vars used in an allocate directive. */ + +void rref_var() +{ + int&& ref = 42; /* { dg-note "'ref' declared here" } */ + #pragma omp allocate(ref) /* { dg-error "variables with reference type may not appear in an 'allocate' directive" } */ +} + +void const_rref_var() +{ + int const&& ref = 42; /* { dg-note "'ref' declared here" } */ + #pragma omp allocate(ref) /* { dg-error "variables with reference type may not appear in an 'allocate' directive" } */ +} + +template +void rref_var_templ_not_instantiated() +{ + int&& ref = 42; /* { dg-note "'ref' declared here" } */ + #pragma omp allocate(ref) /* { dg-error "variables with reference type may not appear in an 'allocate' directive" } */ +} + +template +void const_rref_var_templ_not_instantiated() +{ + int const&& ref = 42; /* { dg-note "'ref' declared here" } */ + #pragma omp allocate(ref) /* { dg-error "variables with reference type may not appear in an 'allocate' directive" } */ +} + +template +void dependent_rref_var_templ_not_instantiated() +{ + T&& t = 42; /* { dg-note "'t' declared here" } */ + #pragma omp allocate(t) /* { dg-error "variables with reference type may not appear in an 'allocate' directive" } */ +} + +template +void dependent_var_templ() +{ + T t = 42; /* { dg-note "'t' declared here" } */ + #pragma omp allocate(t) /* { dg-error "variables with reference type may not appear in an 'allocate' directive" } */ +} +void instantiate_var_templ() +{ + dependent_var_templ(); /* { dg-bogus "required from here" } */ + dependent_var_templ(); /* { dg-message "required from here" } */ + dependent_var_templ(); /* { dg-message "required from here" } */ +} + diff --git a/gcc/testsuite/g++.dg/gomp/allocate-16.C b/gcc/testsuite/g++.dg/gomp/allocate-16.C new file mode 100644 index 00000000000..7258d8c1c3c --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-16.C @@ -0,0 +1,232 @@ +/* { dg-do compile { target c++11 } } */ +/* { dg-ice "" { c++17 } } */ +#include "allocate-allocator-handle.h" + +/* Incorrect use of lambda captures in a directive or clause. + There are a few cases in here that are impacted by the bug with implicit + constexpr functions. */ + +/* These errors (specifically in capture_used_in_directive) really could be better. */ + +void capture_used_in_directive() +{ + int a = 42; + auto cl = [a](){ /* { dg-note "declared here" } */ + #pragma omp allocate(a) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + }; +} + +template +void capture_used_in_directive_templ_uninstantiated() +{ + int a = 42; + auto cl = [a](){ /* { dg-note "declared here" } */ + #pragma omp allocate(a) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + }; +} + +template +void capture_used_in_directive_templ() +{ + int a = 42; + auto cl = [a](){ /* { dg-note "declared here" } */ + #pragma omp allocate(a) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ + }; +} + +void instantiate_capture_used_in_directive() +{ + capture_used_in_directive_templ(); +} + + + +void capture_used_in_allocator_clause_static_var() +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note "'omp_allocator_handle_t alloc' is not const" } */ + auto cl = [alloc](){ + static int a = 42; /* { dg-note "'a' declared here" } */ + int b = 42; /* { dg-bogus "'b' declared here" } */ + static int c = 42; /* { dg-note "'c' declared here" } */ + int d = 42; /* { dg-bogus "'d' declared here" } */ + #pragma omp allocate(a, b, c, d) allocator(alloc) + /* { dg-error "the value of 'alloc' is not usable in a constant expression" "" { target *-*-* } .-1 } */ + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-2 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-3 } */ + }; +} + +template +void capture_used_in_allocator_clause_static_var_templ_uninstantiated() +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note "'omp_allocator_handle_t alloc' is not const" "" { xfail *-*-* } } */ + auto cl = [alloc](){ + static int a = 42; /* { dg-note "'a' declared here" "" { xfail *-*-* } } */ + int b = 42; /* { dg-bogus "'b' declared here" } */ + static int c = 42; /* { dg-note "'c' declared here" "" { xfail *-*-* } } */ + int d = 42; /* { dg-bogus "'d' declared here" } */ + #pragma omp allocate(a, b, c, d) allocator(alloc) + /* { dg-error "the value of 'alloc' is not usable in a constant expression" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } .-2 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-3 } */ + }; +} +/* This case can't be diagnosed, there exists a T where alloc is a converted + constant expression of type omp_allocator_handle_t. This is demonstrated + below in dependent_capture_used_in_allocator_clause_static_var_templ_valid. */ +template +void dependent_capture_used_in_allocator_clause_static_var_templ_uninstantiated() +{ + T alloc = omp_default_mem_alloc; /* { dg-bogus "" } */ + auto cl = [alloc](){ + static int a = 42; /* { dg-bogus "'a' declared here" } */ + static int c = 42; /* { dg-bogus "'c' declared here" } */ + #pragma omp allocate(a, c) allocator(alloc) + /* { dg-bogus "the value of 'alloc' is not usable in a constant expression" "" { target *-*-* } .-1 } */ + /* { dg-bogus "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ + }; +} + +template +void capture_used_in_allocator_clause_static_var_templ() +{ + omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note "'omp_allocator_handle_t alloc' is not const" "" { xfail c++17 } } */ + auto cl = [alloc](){ + static int a = 42; /* { dg-note "'a' declared here" "" { xfail c++17 } } */ + int b = 42; /* { dg-bogus "'b' declared here" } */ + static int c = 42; /* { dg-note "'c' declared here" "" { xfail c++17 } } */ + int d = 42; /* { dg-bogus "'d' declared here" } */ + #pragma omp allocate(a, b, c, d) allocator(alloc) + /* { dg-error "the value of 'alloc' is not usable in a constant expression" "" { xfail c++17 } .-1 }*/ + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail c++17 } .-2 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail c++17 } .-3 } */ + }; +} + +template +void dependent_capture_used_in_allocator_clause_static_var_templ() +{ + T alloc = omp_default_mem_alloc; /* { dg-note "'omp_allocator_handle_t alloc' is not const" "" { xfail c++17 } } */ + auto cl = [alloc](){ + static int a = 42; /* { dg-note "'a' declared here" "" { xfail c++17 } } */ + int b = 42; /* { dg-bogus "'b' declared here" } */ + static int c = 42; /* { dg-note "'c' declared here" "" { xfail c++17 } } */ + int d = 42; /* { dg-bogus "'d' declared here" } */ + #pragma omp allocate(a, b, c, d) allocator(alloc) + /* { dg-error "the value of 'alloc' is not usable in a constant expression" "" { xfail c++17 } .-1 } */ + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail c++17 } .-2 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail c++17 } .-3 } */ + }; +} + +template +void dependent_capture_used_in_allocator_clause_static_var_templ_valid() +{ + T alloc = omp_default_mem_alloc; /* { dg-bogus "" } */ + auto cl = [alloc](){ + static int a = 42; /* { dg-bogus "" } */ + static int c = 42; /* { dg-bogus "" } */ + #pragma omp allocate(a, c) allocator(alloc) + /* { dg-bogus "the value of 'alloc' is not usable in a constant expression" "" { target *-*-* } .-1 } */ + /* { dg-bogus "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-2 } */ + }; +} + +void instantiate_capture_used_in_allocator_clause_static_var() +{ + capture_used_in_allocator_clause_static_var_templ(); + dependent_capture_used_in_allocator_clause_static_var_templ(); + + struct S { + constexpr S (omp_allocator_handle_t) {} + constexpr operator omp_allocator_handle_t () const { return omp_default_mem_alloc; } + }; + dependent_capture_used_in_allocator_clause_static_var_templ_valid (); + dependent_capture_used_in_allocator_clause_static_var_templ_valid (); +} + + + +void capture_used_in_align_clause() +{ + int align = 32; /* { dg-note "'int align' is not const" } */ + auto cl = [align](){ + int a; + #pragma omp allocate(a) align(align) + /* { dg-error "the value of 'align' is not usable in a constant expression" "" { target *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-2 } */ + }; +} + +template +void capture_used_in_align_clause_templ_uninstantiated() +{ + int align = 32; /* { dg-note "'int align' is not const" "" { xfail *-*-* } } */ + auto cl = [align](){ + /* { dg-bogus "the value of 'align' is not usable in a constant expression" "" { target *-*-* } .-1 } */ + int a; + #pragma omp allocate(a) align(align) + /* { dg-error "the value of 'align' is not usable in a constant expression" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-2 } */ + }; +} + +/* This case can't be diagnosed, there exists a T where align is a converted + constant expression of long unsigned int. This is demonstrated + below in dependent_capture_used_in_align_clause_templ_valid. */ +template +void dependent_capture_used_in_align_clause_templ_uninstantiated() +{ + T align = 32; /* { dg-bogus "" } */ + auto cl = [align](){ + int a; + #pragma omp allocate(a) align(align) /* { dg-bogus "" } */ + }; +} + +template +void capture_used_in_align_clause_templ() +{ + int align = 32; /* { dg-note "'int align' is not const" "" { xfail c++17 } } */ + auto cl = [align](){ + int a; + #pragma omp allocate(a) align(align) + /* { dg-error "the value of 'align' is not usable in a constant expression" "" { target *-*-* xfail c++17 } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* xfail c++17 } .-2 } */ + }; +} + +template +void dependent_capture_used_in_align_clause_templ() +{ + T align = 32; /* { dg-note "'int align' is not const" "" { xfail c++17 } } */ + auto cl = [align](){ + int a; + #pragma omp allocate(a) align(align) + /* { dg-error "the value of 'align' is not usable in a constant expression" "" { target *-*-* xfail c++17 } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* xfail c++17 } .-2 } */ + }; +} + +template +void dependent_capture_used_in_align_clause_templ_valid() +{ + T align = 32; /* { dg-bogus "" } */ + auto cl = [align](){ + int a; + #pragma omp allocate(a) align(align) /* { dg-bogus "" } */ + }; +} + +void instantiate_capture_used_in_align() +{ + capture_used_in_align_clause_templ(); + dependent_capture_used_in_align_clause_templ(); + + struct S { + constexpr S (int) {} + constexpr operator unsigned int () const { return 32; } + }; + dependent_capture_used_in_align_clause_templ_valid (); + dependent_capture_used_in_align_clause_templ_valid (); +} diff --git a/gcc/testsuite/g++.dg/gomp/allocate-17.C b/gcc/testsuite/g++.dg/gomp/allocate-17.C new file mode 100644 index 00000000000..e265ecdd1e7 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-17.C @@ -0,0 +1,560 @@ +/* { dg-do compile { target c++17 } } */ + +/* Nested lambdas. */ + +#include "allocate-allocator-handle.h" + +template +auto lambda_0_valid() +{ + return [](auto p0){ + return [](auto p1){ + return [](auto p2){ + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; + #pragma omp allocate(a) align(Align) allocator(p2) + return a; + }; + }; + }; + }; +} + +template +auto lambda_0_bad_align() +{ + return [](auto p0){ + return [](auto p1){ + return [](auto p2){ + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; + #pragma omp allocate(a) align(Align) allocator(p2) + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + return a; + }; + }; + }; + }; +} + +template +auto lambda_0_ref_in_directive() +{ + return [](auto p0){ + return [](auto p1){ + return [](auto p2){ + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; /* { dg-message "'a' declared here" } */ + #pragma omp allocate(a) align(Align) allocator(p2) + /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ + return a; + }; + }; + }; + }; +} + + +template +auto lambda_0_invalid_allocator() +{ + return [](auto p0){ + return [](auto p1){ + return [](auto p2){ + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; + #pragma omp allocate(a) align(Align) allocator(p2) + /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target *-*-* } .-1 } */ + return a; + }; + }; + }; + }; +} + +template +auto lambda_0_all() +{ + return [](auto p0){ + return [](auto p1){ + return [](auto p2){ + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; /* { dg-message "'a' declared here" } */ + #pragma omp allocate(a) align(Align) allocator(p2) + /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-2 } */ + /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target *-*-* } .-3 } */ + return a; + }; + }; + }; + }; +} + +template +auto lambda_0_wrong_align_partially_instantiated() +{ + return [](auto p0){ + return [](auto p1){ + return [](auto p2){ + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; + #pragma omp allocate(a) align(Align) allocator(p2) + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + return a; + }; + }; + }; + }; +} + +template +auto lambda_0_invalid_allocator_partially_instantiated() +{ + return [](auto p0){ + return [](auto p1){ + return [](auto p2){ + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; + #pragma omp allocate(a) align(Align) allocator(p2) + /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { xfail *-*-* } .-1 } */ + return a; + }; + }; + }; + }; +} + +void instantiate_lambdas_0() +{ + { + auto c0 = lambda_0_valid<32>(); + auto c1 = c0(0); + auto c2 = c1(0); + auto c3 = c2(omp_default_mem_alloc); + c3(0); + } + { + auto c0 = lambda_0_bad_align<30>(); /* { dg-message "required from here" "" { xfail *-*-* } } */ + auto c1 = c0(0); /* { dg-bogus "required from here" } */ + auto c2 = c1(0); /* { dg-bogus "required from here" } */ + auto c3 = c2(omp_default_mem_alloc); /* { dg-bogus "required from here" } */ + c3(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */ + } + { + auto c0 = lambda_0_ref_in_directive<32>(); + auto c1 = c0(0); + auto c2 = c1(0); + auto c3 = c2(omp_default_mem_alloc); + int a = 0; + c3.operator()(a); /* { dg-message "required from here" } */ + } + { + auto c0 = lambda_0_invalid_allocator<32>(); + auto c1 = c0(0); + auto c2 = c1(0); + auto c3 = c2(0); /* { dg-message "required from here" "" { xfail *-*-* } } */ + c3(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */ + } + { + auto c0 = lambda_0_all<30>(); /* { dg-message "required from here" "" { xfail *-*-* } } */ + auto c1 = c0(0); /* { dg-bogus "required from here" } */ + auto c2 = c1(0); /* { dg-bogus "required from here" } */ + auto c3 = c2(0); /* { dg-message "required from here" "" { xfail *-*-* } } */ + int a = 0; + c3.operator()(a); /* { dg-message "required from here" } */ + } + { + auto c = lambda_0_wrong_align_partially_instantiated<30>(); /* { dg-message "required from here" "" { xfail *-*-* } } */ + } + { + auto c0 = lambda_0_invalid_allocator_partially_instantiated<32>(); + auto c1 = c0(0); + auto c2 = c1(0); + auto c3 = c2(0); /* { dg-message "required from here" "" { xfail *-*-* } } */ + } +} + + + +template +auto lambda_1_valid() +{ + return [](auto p0){ + int a = 42; + #pragma omp allocate(a) align(Align) + return [](auto p1){ + int a = 42; + #pragma omp allocate(a) align(Align) + return [](auto p2){ + int a = 42; + #pragma omp allocate(a) align(Align) + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; + #pragma omp allocate(a) align(Align) allocator(p2) + return a; + }; + }; + }; + }; +} + +template +auto lambda_1_bad_align() +{ + return [](auto p0){ + int a = 42; + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + return [](auto p1){ + int a = 42; + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + return [](auto p2){ + int a = 42; + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; + #pragma omp allocate(a) align(Align) allocator(p2) + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + return a; + }; + }; + }; + }; +} + +template +auto lambda_1_ref_in_directive() +{ + return [](auto p0){ + int a = 42; + #pragma omp allocate(a) align(Align) + return [](auto p1){ + int a = 42; + #pragma omp allocate(a) align(Align) + return [](auto p2){ + int a = 42; + #pragma omp allocate(a) align(Align) + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; /* { dg-message "'a' declared here" } */ + #pragma omp allocate(a) align(Align) allocator(p2) + /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ + return a; + }; + }; + }; + }; +} + +template +auto lambda_1_invalid_allocator() +{ + return [](auto p0){ + int a = 42; + #pragma omp allocate(a) align(Align) + return [](auto p1){ + int a = 42; + #pragma omp allocate(a) align(Align) + return [](auto p2){ + int a = 42; + #pragma omp allocate(a) align(Align) + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; + #pragma omp allocate(a) align(Align) allocator(p2) + /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target *-*-* } .-1 } */ + return a; + }; + }; + }; + }; +} + +template +auto lambda_1_all() +{ + return [](auto p0){ + int a = 42; + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + return [](auto p1){ + int a = 42; + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + return [](auto p2){ + int a = 42; + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; /* { dg-message "'a' declared here" } */ + #pragma omp allocate(a) align(Align) allocator(p2) + /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-2 } */ + /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target *-*-* } .-3 } */ + return a; + }; + }; + }; + }; +} + +template +auto lambda_1_wrong_align_partially_instantiated() +{ + return [](auto p0){ + int a = 42; + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + return [](auto p1){ + int a = 42; + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + return [](auto p2){ + int a = 42; + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; + #pragma omp allocate(a) align(Align) allocator(p2) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + return a; + }; + }; + }; + }; +} + +template +auto lambda_1_invalid_allocator_partially_instantiated() +{ + return [](auto p0){ + int a = 42; + #pragma omp allocate(a) align(Align) + return [](auto p1){ + int a = 42; + #pragma omp allocate(a) align(Align) + return [](auto p2){ + int a = 42; + #pragma omp allocate(a) align(Align) + return [p2](auto p3){ + int b = 42; + decltype(p3) a = b; + #pragma omp allocate(a) align(Align) allocator(p2) + /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { xfail *-*-* } .-1 } */ + return a; + }; + }; + }; + }; +} + +void instantiate_lambdas_1() +{ + { + auto c0 = lambda_1_valid<32>(); + auto c1 = c0(0); + auto c2 = c1(0); + auto c3 = c2(omp_default_mem_alloc); + c3(0); + } + { + auto c0 = lambda_1_bad_align<30>(); /* { dg-message "required from here" "" { xfail *-*-* } } */ + auto c1 = c0(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */ + auto c2 = c1(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */ + auto c3 = c2(omp_default_mem_alloc); /* { dg-bogus "required from here" "" { xfail *-*-* } } */ + c3(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */ + } + { + auto c0 = lambda_1_ref_in_directive<32>(); + auto c1 = c0(0); + auto c2 = c1(0); + auto c3 = c2(omp_default_mem_alloc); + int a = 0; + c3.operator()(a); /* { dg-message "required from here" } */ + } + { + auto c0 = lambda_1_invalid_allocator<32>(); + auto c1 = c0(0); + auto c2 = c1(0); + auto c3 = c2(0); /* { dg-message "required from here" "" { xfail *-*-* } } */ + c3(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */ + } + { + auto c0 = lambda_1_all<30>(); /* { dg-message "required from here" "" { xfail *-*-* } } */ + auto c1 = c0(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */ + auto c2 = c1(0); /* { dg-bogus "required from here" "" { xfail *-*-* } } */ + auto c3 = c2(0); /* { dg-message "required from here" } */ + int a = 0; + c3.operator()(a); /* { dg-message "required from here" } */ + } + { + auto c = lambda_1_wrong_align_partially_instantiated<30>(); /* { dg-message "required from here" "" { xfail *-*-* } } */ + } + { + auto c0 = lambda_1_invalid_allocator_partially_instantiated<32>(); + auto c1 = c0(0); + auto c2 = c1(0); + auto c3 = c2(0); /* { dg-message "required from here" "" { xfail *-*-* } } */ + } +} + + + +template +auto lambda_2_0_valid() +{ + return [](auto){ + return [](auto){ + return [](auto){ + return [](auto){ + int b = 42; + T a = b; + #pragma omp allocate(a) + return a; + }; + }; + }; + }; +} + +template +auto lambda_2_0_invalid() +{ + return [](auto){ + return [](auto){ + return [](auto){ + return [](auto){ + int b = 42; + T a = b; /* { dg-message "'a' declared here" } */ + #pragma omp allocate(a) + /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ + return a; + }; + }; + }; + }; +} + +template +auto lambda_2_0_invalid_partially_instantiated() +{ + return [](auto){ + return [](auto){ + return [](auto){ + return [](auto){ + int b = 42; + T a = b; /* { dg-message "'a' declared here" } */ + #pragma omp allocate(a) + /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ + return a; + }; + }; + }; + }; +} + +template +auto lambda_2_1_valid() +{ + return [](auto){ + return [](auto){ + return [](auto p2){ + using type = decltype(p2); + return [](auto){ + int b = 42; + type a = b; + #pragma omp allocate(a) + return a; + }; + }; + }; + }; +} + +template +auto lambda_2_1_invalid() +{ + return [](auto){ + return [](auto){ + return [](auto p2){ + using type = decltype(p2); + return [](auto){ + int b = 42; + type a = b; /* { dg-message "'a' declared here" } */ + #pragma omp allocate(a) + /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ + return a; + }; + }; + }; + }; +} + +template +auto lambda_2_1_invalid_partially_instantiated() +{ + return [](auto){ + return [](auto){ + return [](auto p2){ + using type = decltype(p2); + return [](auto){ + int b = 42; + type a = b; /* { dg-message "'a' declared here" } */ + #pragma omp allocate(a) + /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ + return a; + }; + }; + }; + }; +} + +void instantiate_lambdas_2() +{ + { + auto c0 = lambda_2_0_valid(); + auto c1 = c0(0); + auto c2 = c1(0); + auto c3 = c2(0); + c3(0); + } + { + auto c0 = lambda_2_0_invalid(); /* { dg-message "required from here" } */ + auto c1 = c0(0); /* { dg-bogus "required from here" } */ + auto c2 = c1(0); /* { dg-bogus "required from here" } */ + auto c3 = c2(0); /* { dg-bogus "required from here" } */ + c3(0); /* { dg-bogus "required from here" } */ + } + { + auto c0 = lambda_2_0_invalid_partially_instantiated(); /* { dg-message "required from here" } */ + } + { + auto c0 = lambda_2_1_valid(); + auto c1 = c0(0); + auto c2 = c1(0); + auto c3 = c2(0); + c3(0); + } + { + auto c0 = lambda_2_1_invalid(); + auto c1 = c0(0); + auto c2 = c1(0); + int a = 0; + auto c3 = c2.operator()(a); /* { dg-message "required from here" } */ + c3(0); /* { dg-bogus "required from here" } */ + } + { + auto c0 = lambda_2_1_invalid_partially_instantiated(); + auto c1 = c0(0); + auto c2 = c1(0); + int a = 0; + auto c3 = c2.operator()(a); /* { dg-message "required from here" } */ + } +} + +/* This is fixed by the later location wrapping patch. */ +/* { dg-bogus "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } 0 } */ diff --git a/gcc/testsuite/g++.dg/gomp/allocate-18.C b/gcc/testsuite/g++.dg/gomp/allocate-18.C new file mode 100644 index 00000000000..3a04bbe8bcd --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-18.C @@ -0,0 +1,274 @@ +/* { dg-do compile { target c++17 } } */ + +/* OpenMP allocate directive in constant expressions where execution does not + pass through the allocation of the variable in the directive. + Lambdas, both implicit and explicit constexpr, + in a function and in a function template. + + These cases will be valid if/when OpenMP relaxes restrictions on directives + in constexpr functions. It might make sense to only allow this behavior in + c++23 though. + + Constexpr lambdas are only permitted in c++17, it doesn't make sense to test + anything prior than that. + + NOTE: The error messages for the cases that are not explicitly declared + constexpr are probably not what we want, we likely want something stating + that the calls are not usable in a constant expression because of the use of + an OpenMP directive. */ + +void do_constexpr_lambda() +{ + auto cl = [](bool b) constexpr { + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; + }; + constexpr int v0 = cl(true); /* { dg-error "'do_constexpr_lambda\\\(\\\)::' called in a constant expression" "" { xfail *-*-* } } */ + + constexpr int v1 = [](bool b) constexpr { + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; + }(true); +} + +void do_constexpr_generic_lambda() +{ + auto cl = [](auto b) constexpr { + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; + }; + constexpr int v0 = cl(true); /* { dg-error "'do_constexpr_generic_lambda\\\(\\\)::' called in a constant expression" "" { xfail *-*-* } } */ + + constexpr int v1 = [](auto b) constexpr { + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; + }(true); +} + +void do_lambda() +{ + auto cl = [](bool b){ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; + }; + constexpr int v0 = cl(true); /* { dg-error "'do_lambda\\\(\\\)::' called in a constant expression" "" { xfail *-*-* } } */ + + constexpr int v1 = [](bool b){ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; + }(true); +} + +void do_generic_lambda() +{ + auto cl = [](auto b){ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; + }; + constexpr int v0 = cl(true); /* { dg-error "'do_generic_lambda\\\(\\\)::' called in a constant expression" "" { xfail *-*-* } } */ + + constexpr int v1 = [](auto b){ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; + }(true); +} + +template +void do_constexpr_lambda_templ_uninstantiated() +{ + auto cl = [](bool b) constexpr { + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; + }; + constexpr int v0 = cl(true); /* { dg-error "called in a constant expression" "" { xfail *-*-* } } */ + + constexpr int v1 = [](bool b) constexpr { + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; + }(true); +} + +template +void do_constexpr_generic_lambda_templ_uninstantiated() +{ + auto cl = [](auto b) constexpr { + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; + }; + constexpr int v0 = cl(true); /* { dg-error "called in a constant expression" "" { xfail *-*-* } } */ + + constexpr int v1 = [](auto b) constexpr { + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; + }(true); +} + +template +void do_lambda_templ_uninstantiated() +{ + auto cl = [](bool b){ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; + }; + constexpr int v0 = cl(true); /* { dg-error "called in a constant expression" "" { xfail *-*-* } } */ + + constexpr int v1 = [](bool b){ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; + }(true); +} + +template +void do_generic_lambda_templ_uninstantiated() +{ + auto cl = [](auto b){ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; + }; + constexpr int v0 = cl(true); /* { dg-error "called in a constant expression" "" { xfail *-*-* } } */ + + constexpr int v1 = [](auto b){ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; + }(true); +} + + +template +void do_constexpr_lambda_templ() +{ + auto cl = [](bool b) constexpr { + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; + }; + constexpr int v0 = cl(true); /* { dg-error "'do_constexpr_lambda_templ\\\(\\\)::' called in a constant expression" "" { xfail *-*-* } } */ + + constexpr int v1 = [](bool b) constexpr { + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; + }(true); +} +template void do_constexpr_lambda_templ(); + +template +void do_constexpr_generic_lambda_templ() +{ + auto cl = [](auto b) constexpr { + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; + }; + constexpr int v0 = cl(true); /* { dg-error "'do_constexpr_lambda_templ\\\(\\\)::' called in a constant expression" "" { xfail *-*-* } } */ + + constexpr int v1 = [](auto b) constexpr { + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; + }(true); +} +template void do_constexpr_generic_lambda_templ(); + +template +void do_lambda_templ() +{ + auto cl = [](bool b){ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; + }; + constexpr int v0 = cl(true); /* { dg-error "'do_lambda_templ\\\(\\\)::' called in a constant expression" "" { xfail *-*-* } } */ + + constexpr int v1 = [](bool b){ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; + }(true); +} +template void do_lambda_templ(); + +template +void do_generic_lambda_templ() +{ + auto cl = [](auto b){ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; + }; + constexpr int v0 = cl(true); /* { dg-error "'do_generic_lambda_templ\\\(\\\)::' called in a constant expression" "" { xfail *-*-* } } */ + + constexpr int v1 = [](auto b){ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; + }(true); +} +template void do_generic_lambda_templ(); + +/* Missing cases where the lambda/lambda body is dependent on the outer + template params. */ diff --git a/gcc/testsuite/g++.dg/gomp/allocate-19.C b/gcc/testsuite/g++.dg/gomp/allocate-19.C new file mode 100644 index 00000000000..e99106893da --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-19.C @@ -0,0 +1,128 @@ +/* { dg-do compile { target c++14 } } */ +/* { dg-additional-options "-fimplicit-constexpr" } */ + +/* OpenMP allocate directive in constant expressions where execution does not + pass through the allocation of the variable in the directive. + Regular functions and function templates, + constexpr and inline with -fimplicit-constexpr. + + These cases will be valid if/when OpenMP relaxes restrictions on directives + in constexpr functions. It might make sense to only allow this behavior in + c++23 though. + + It doesn't make sense to test these cases in c++11 as constexpr functions + are far more limited, and are diagnosed completely differently. + + Even though -fimplicit-constexpr is an extension, its behavior is similar to + lambdas in c++17, so I am including tests for it. + See allocate-18.C for test cases involving lambdas. + + NOTE: The error messages for the inline cases are are probably not what we + want, we likely want something stating that the calls are not usable in a + constant expression because of the use of an OpenMP directive. */ + +constexpr int f_constexpr(bool b) +{ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; +} +constexpr int g_cx_0 = f_constexpr(true); /* { dg-error "'constexpr int f_constexpr\\\(bool\\\)' called in a constant expression" "" { xfail *-*-* } } */ + +template +constexpr int f_constexpr_templ_uninstantiated(bool b) +{ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; +} + +template +constexpr int f_constexpr_templ(bool b) +{ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; +} +constexpr int g_cx_1 = f_constexpr_templ(true); /* { dg-error "'constexpr int f_constexpr_templ\\\(bool\\\) \\\[with = void\\\]' called in a constant expression" "" { xfail *-*-* } } */ + +template +constexpr int f_constexpr_dep_parm_templ_uninstantiated(B b) +{ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; +} + +template +constexpr int f_constexpr_dep_parm_templ(B b) +{ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + return a; +} +constexpr int g_cx_2 = f_constexpr_dep_parm_templ(true); /* { dg-error "'constexpr int f_constexpr_dep_parm_templ\\\(bool\\\) \\\[with = bool\\\]' called in a constant expression" "" { xfail *-*-* } } */ + + + +inline int f_inline(bool b) +{ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; +} +constexpr int g_inline_0 = f_inline(true); /* { dg-error "'int f_inline\\\(bool\\\)' called in a constant expression" "" { xfail *-*-* } } */ + +template +inline int f_inline_templ_uninstantiated(bool b) +{ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; +} + +template +inline int f_inline_templ(bool b) +{ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; +} +constexpr int g_inline_1 = f_inline_templ(true); /* { dg-error "'int f_inline_templ\\\(bool\\\) \\\[with = void\\\]' called in a constant expression" "" { xfail *-*-* } } */ + +template +inline int f_inline_dep_parm_templ_uninstantiated(B b) +{ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; +} + +template +inline int f_inline_dep_parm_templ(B b) +{ + if (b) + return 42; + int a = 42; + #pragma omp allocate(a) /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + return a; +} +constexpr int g_inline_2 = f_inline_dep_parm_templ(true); /* { dg-error "'int f_inline_deb_parm_templ\\\(bool\\\) \\\[with = bool\\\]' called in a constant expression" "" { xfail *-*-* } } */ diff --git a/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C b/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C index c0c59a30a3c..786c2f5550e 100644 --- a/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C +++ b/gcc/testsuite/g++.dg/gomp/allocate-handles-1.C @@ -15,49 +15,47 @@ #define GOMP_OMPX_PREDEF_ALLOC_MIN 200 #define GOMP_OMPX_PREDEF_ALLOC_MAX 201 -int g0 = 42; /* { dg-note "'g0' declared here" "" { xfail *-*-* } } */ +int g0 = 42; /* { dg-note "'g0' declared here" } */ #pragma omp allocate(g0) allocator(omp_null_allocator) /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-1 } */ -/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ /* { dg-note "expression evaluates to '0'" "" { target *-*-* } .-3 } */ -int g1 = 42; /* { dg-note "'g1' declared here" "" { xfail *-*-* } }*/ +int g1 = 42; /* { dg-note "'g1' declared here" } */ #pragma omp allocate(g1) allocator(static_cast(GOMP_OMP_PREDEF_ALLOC_MAX + 1)) /* { dg-error "'allocator' clause requires a constant predefined allocator" "If this test fails because of added predefined allocators please ensure everything is updated accordingly, see this test case for more information" { target *-*-* } .-1 } */ -/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ /* { dg-note "expression evaluates to '9'" "" { target *-*-* } .-3 } */ -int g2 = 42; /* { dg-note "'g2' declared here" "" { xfail *-*-* } }*/ +int g2 = 42; /* { dg-note "'g2' declared here" } */ #pragma omp allocate(g2) allocator(static_cast(GOMP_OMPX_PREDEF_ALLOC_MIN - 1)) /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-1 } */ -/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ /* { dg-note "expression evaluates to '199'" "" { target *-*-* } .-3 } */ -int g3 = 42; /* { dg-note "'g3' declared here" "" { xfail *-*-* } }*/ +int g3 = 42; /* { dg-note "'g3' declared here" } */ #pragma omp allocate(g3) allocator(static_cast(GOMP_OMPX_PREDEF_ALLOC_MAX + 1)) /* { dg-error "'allocator' clause requires a constant predefined allocator" "If this test fails because of added predefined allocators please ensure everything is updated accordingly, see this test case for more information" { target *-*-* } .-1 } */ -/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ +/* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ /* { dg-note "expression evaluates to '202'" "" { target *-*-* } .-3 } */ void test_predefined_allocs() { - static int a0 = 42; /* { dg-note "'a0' declared here" "" { xfail *-*-* } }*/ + static int a0 = 42; /* { dg-note "'a0' declared here" }*/ #pragma omp allocate(a0) allocator(omp_null_allocator) /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-1 } */ - /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ /* { dg-note "expression evaluates to '0'" "" { target *-*-* } .-3 } */ - static int a1 = 42; /* { dg-note "'a1' declared here" "" { xfail *-*-* } }*/ + static int a1 = 42; /* { dg-note "'a1' declared here" }*/ #pragma omp allocate(a1) allocator(static_cast(GOMP_OMP_PREDEF_ALLOC_MAX + 1)) /* { dg-error "'allocator' clause requires a constant predefined allocator" "If this test fails because of added predefined allocators please ensure everything is updated accordingly, see this test case for more information" { target *-*-* } .-1 } */ - /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ /* { dg-note "expression evaluates to '9'" "" { target *-*-* } .-3 } */ - static int a2 = 42; /* { dg-note "'a2' declared here" "" { xfail *-*-* } }*/ + static int a2 = 42; /* { dg-note "'a2' declared here" }*/ #pragma omp allocate(a2) allocator(static_cast(GOMP_OMPX_PREDEF_ALLOC_MIN - 1)) /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-1 } */ - /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ /* { dg-note "expression evaluates to '199'" "" { target *-*-* } .-3 } */ - static int a3 = 42; /* { dg-note "'a3' declared here" "" { xfail *-*-* } }*/ + static int a3 = 42; /* { dg-note "'a3' declared here" }*/ #pragma omp allocate(a3) allocator(static_cast(GOMP_OMPX_PREDEF_ALLOC_MAX + 1)) /* { dg-error "'allocator' clause requires a constant predefined allocator" "If this test fails because of added predefined allocators please ensure everything is updated accordingly, see this test case for more information" { target *-*-* } .-1 } */ - /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-2 } */ + /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ /* { dg-note "expression evaluates to '202'" "" { target *-*-* } .-3 } */ } - -/* { dg-bogus "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail c++ } 0 }*/ From patchwork Tue May 5 15:01:59 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Waffl3x X-Patchwork-Id: 134488 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id B88694BA5436 for ; Tue, 5 May 2026 15:11:33 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B88694BA5436 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=baylibre-com.20251104.gappssmtp.com header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256 header.s=20251104 header.b=T67MG8fA X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x435.google.com (mail-pf1-x435.google.com [IPv6:2607:f8b0:4864:20::435]) by sourceware.org (Postfix) with ESMTPS id 5A2BF4BA900E for ; Tue, 5 May 2026 15:10:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5A2BF4BA900E Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=baylibre.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 5A2BF4BA900E Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::435 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993843; cv=none; b=fM0g7SaC6S7zCOXijWb1TeHRiZ9IY7TI8W17+A7JaF0+xvbEGvWZu/w/yLLSLsnASLsdGCHsFDwUdaejhJ8FOVDDR27PflhuKhtEVlS14AlcXOApKqpYxucPZN2kgdllO5tzcMr4nJWShcKK6GBOWfrI43fVsZZb/pdmK5RdxQE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993843; c=relaxed/simple; bh=XkqyPNKbct7Xq80C2qckPXdAECkGgnNUCONOIGMupd0=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=u0m+Xa26K+rtYTQIpCIYlzguwkZcHQGflAZVkH8U9LZjNb8DGVVvJxm/ssR7o8eY4bxOeBRT5LOdXkhvyOueLWt8/ABdv20TZVMAwbO4Ewi14qqGSLsvl6b7Bbeq49AjerUt7h8BqFLG8B6Av63hJQ1c8n4CYknv7I0YyjSNTp8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 5A2BF4BA900E Received: by mail-pf1-x435.google.com with SMTP id d2e1a72fcca58-824acdfb73dso414105b3a.2 for ; Tue, 05 May 2026 08:10:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20251104.gappssmtp.com; s=20251104; t=1777993842; x=1778598642; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=NY4AKGfBg7OhsvgHP+Fp1lLnyHflwRLlR24CsB1z0rg=; b=T67MG8fAI1Ybn09WlXAX100WjoYZfa76c+xrcT7Et/tl+wrWv/QdNffKZQIe5PWj17 pxjjKF77BxDam7cFs9Zzo4KplxPLfsUGUYC+MgoPrYqlSAm77WPTUPFsWh6Mm2sMgGWU ZaHqGlWEU0ekzdI7uVuNgWNlpt6xPSG0mznYBDMo0N6RIBI5mzqY9m0Ejd6sdABjaIDy 77zt9CHeohWQlFlR7Ekw6VdKUwdDwGqUhmpKKYtxatDRtGBjw5ZCMa1WWGsEoKvIde39 7mQs2VjYXYv+8N7/ZAAa1curK3VuuilNNjPE4ZwshXl/ObTuXPxemL2KJ9CHB49RurSs Yr2A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777993842; x=1778598642; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=NY4AKGfBg7OhsvgHP+Fp1lLnyHflwRLlR24CsB1z0rg=; b=LNUqIkvZEhQH7EzTmIRI0rJRNPcbjm4l1aNJqw9bG7lFx1KH/4ROBAYghxqKua+fr9 VlTem874CPuwg+SsNN3NurZtB/N3EXN+/DJbd6O0Mv7lljQACv+XvVGUosuiDkwcoD+M qeUHWQb3/fgMU5Bj5ar5H240OYsJl/xTINCtYAuAMZVJTBdCrUJA2ey80PUKmaoCqWwQ 5Aj7SY/zujGY2TaHWsvwpKtSAhGbkKg3g4tAeTpEEbssP0SuC+tgb4aBdqQ3N+R319NW XverkPVrD8jF9vTeJMPueVmd9DNQBXbYtXTUT/5r4tsV2U1T4D8kxTTqRWy18LFa/5/y ylgA== X-Gm-Message-State: AOJu0YyrqI2hcJX21rqj3P02BBwcZKX5lQXZOjsq33/iw0X6Nlg0yL88 bkYnIAQvZhk+N2mqNMHgZid48qs+jrdrt+vYxwsrwyHaKq6hd2Ztc3tDAmOJ2R/07bN4PLS/83c EelAX X-Gm-Gg: AeBDieuesTdK3bfxN9i+Bykiq8dzJjObINa2A0D21kaiRCGNxNp5SlOscWcQi5npVs4 +kTTUWGU8v1jZUTC8jt3umrfkkCJCPSAAG+j8V/+nBj4w0Q3TDixlUHvoAbezZvxBA/ldeynbnc MY1BtF6lHW9oWiSmt4yHzpsPkMwkzL7ZzGJfGX3hlZxLcKtm/R+09s4c/GcdL1V3wH60/uzCh52 GGBipyqtgiSP6OdHI5YL127/X9rs63Ce+CLvwKBUVHzCafTHQEsy0YnuQawD+vP49jWdSaiduT2 5VuUhGxY4+vORZV6MATTJB7u3MeDtti5VNvWCah6Z6DQ7juYQH+AyDPw9Qv0mqo5X3O/rdLDrDS mpAvtgTBhNHYl3EMlsP/dDuShh6iwhL4TUGHCVLLRIFS55A5F5yb41pWKen0768+8e1W3blDJ0w UF921eZcGI7ncsDgi6NIr1Z0EdiIKyXR9grgHTPlAtAhFRZ8PjFw== X-Received: by 2002:a05:6a00:3e0b:b0:837:73ab:1013 with SMTP id d2e1a72fcca58-83773ab284bmr4457997b3a.6.1777993842173; Tue, 05 May 2026 08:10:42 -0700 (PDT) Received: from waffl3x-prestige.lan ([2001:56a:f98a:b800:1f67:ce08:3cbd:86b8]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83965645140sm2674956b3a.12.2026.05.05.08.10.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 08:10:41 -0700 (PDT) From: Waffl3x To: gcc-patches@gcc.gnu.org Cc: Waffl3x Subject: [PATCH 06/12] OpenMP/C++: Force location wrapper on 'omp allocate' directive clauses Date: Tue, 5 May 2026 09:01:59 -0600 Message-ID: <20260505151030.1749548-7-waffl3x@baylibre.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505151030.1749548-1-waffl3x@baylibre.com> References: <20260505151030.1749548-1-waffl3x@baylibre.com> MIME-Version: 1.0 X-Spam-Status: No, score=-12.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org Some nodes, such as template parameters, don't get wrapped by maybe_wrap_with_location. We rely on location wrappers for diagnostics of clause exprs in finish_omp_allocate, the easiest solution is to force a wrapper by replicating the the mechanisms of maybe_wrap_with_location in cp_parser_omp_allocate. Unfortuntely, tsubst_expr uses maybe_wrap_with_location to rewrap location wrappers, stripping wrappers that we previously forced. This patch solves that by handling wrappers explicitly in tsubst_expr's OMP_ALLOCATE case. This is kind of a kludge, if this is deemed to be a good solution we should possibly split it out into its own function (force_wrap_with_location?) and change tsubst_expr to use that for rewrapping. This would be trivial to do, but belongs in a different patch. gcc/cp/ChangeLog: * parser.cc (cp_parser_omp_allocate): Force a location wrapper. * pt.cc (tsubst_stmt): Rewrap location wrappers after tsubst_expr. gcc/testsuite/ChangeLog: * g++.dg/gomp/allocate-10.C: Remove xfails. * g++.dg/gomp/allocate-14.C: Likewise. * g++.dg/gomp/allocate-17.C: Likewise. Signed-off-by: Waffl3x --- gcc/cp/parser.cc | 26 +++++++++++++++-- gcc/cp/pt.cc | 24 ++++++++++++---- gcc/testsuite/g++.dg/gomp/allocate-10.C | 12 +++----- gcc/testsuite/g++.dg/gomp/allocate-14.C | 37 +++++++++++-------------- gcc/testsuite/g++.dg/gomp/allocate-17.C | 23 +++++++-------- 5 files changed, 73 insertions(+), 49 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 924e52da6ea..412a71c439c 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -47373,13 +47373,35 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) } while (true); cp_parser_require_pragma_eol (parser, pragma_tok); + /* Some codes, such as template parameters, don't get wrapped by + maybe_wrap_with_location despite not being able to carry a location. + We need a location to issue good diagnostics in finish_omp_allocate. */ + auto maybe_force_wrap_with_location = [] (cp_expr expr_with_loc) -> tree + { + tree expr = expr_with_loc.get_value (); + if (!expr || error_operand_p (expr)) + return expr; + /* In most situations, expr will already have been wrapped. */ + if (CAN_HAVE_LOCATION_P (expr)) + return expr; + + location_t expr_loc = expr_with_loc.get_location (); + /* Copied from tree.cc:maybe_wrap_with_location. */ + const tree_code code + = (((CONSTANT_CLASS_P (expr) && TREE_CODE (expr) != STRING_CST) + || (TREE_CODE (expr) == CONST_DECL && !TREE_STATIC (expr))) + ? NON_LVALUE_EXPR : VIEW_CONVERT_EXPR); + tree wrapper = build1_loc (expr_loc, code, TREE_TYPE (expr), expr); + EXPR_LOCATION_WRAPPER_P (wrapper) = 1; + return wrapper; + }; /* We can still diagnose some things about allocator/alignment even if nl is NULL_TREE. */ finish_omp_allocate (pragma_tok->location, nl, - allocator, - alignment, + maybe_force_wrap_with_location (allocator), + maybe_force_wrap_with_location (alignment), directive_ctx); } diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index aa41a46e007..d27f3c1118f 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -20469,11 +20469,25 @@ tsubst_stmt (tree t, tree args, tsubst_flags_t complain, tree in_decl) case OMP_ALLOCATE: { gcc_assert (flag_openmp); - - tree alloc - = tsubst_expr (OMP_ALLOCATE_ALLOCATOR (t), args, complain, in_decl); - tree align - = tsubst_expr (OMP_ALLOCATE_ALIGN (t), args, complain, in_decl); + /* We force a location wrapper in some cases that don't get wrapped by + maybe_wrap_with_location, tsubst_expr doesn't rewrap them in those + cases so we have to do it. */ + auto subst_and_rewrap = [&] (const tree expr) + { + if (!expr || expr == error_mark_node) + return expr; + tree ret = tsubst_expr (tree_strip_any_location_wrapper (expr), + args, complain, in_decl); + if (location_wrapper_p (expr) && !CAN_HAVE_LOCATION_P (ret)) + { + ret = build1_loc (EXPR_LOCATION (expr), TREE_CODE (expr), + TREE_TYPE (ret), ret); + EXPR_LOCATION_WRAPPER_P (ret) = 1; + } + return ret; + }; + tree alloc = subst_and_rewrap (OMP_ALLOCATE_ALLOCATOR (t)); + tree align = subst_and_rewrap (OMP_ALLOCATE_ALIGN (t)); tree vars = copy_list (OMP_ALLOCATE_VARS (t)); for (tree node = vars; node != NULL_TREE; node = TREE_CHAIN (node)) { diff --git a/gcc/testsuite/g++.dg/gomp/allocate-10.C b/gcc/testsuite/g++.dg/gomp/allocate-10.C index e0f3bcc1780..27f739df6a5 100644 --- a/gcc/testsuite/g++.dg/gomp/allocate-10.C +++ b/gcc/testsuite/g++.dg/gomp/allocate-10.C @@ -34,7 +34,7 @@ void auto_nttp_allocator_static_0() static int a; #pragma omp allocate(a) allocator(Alloc) /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target *-*-* } .-1 } */ - /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } .-2 } */ + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-2 } */ } template @@ -49,7 +49,7 @@ void auto_nttp_allocator_static_2() { static int a; #pragma omp allocate(a) allocator(Alloc) - /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-1 } */ } template @@ -76,8 +76,6 @@ void instantiate_auto_nttp_allocator_static() #undef DEFINITELY_NOT_PREDEFINED -/* { dg-bogus "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } 0 } */ - /* Invalid align clause */ template @@ -91,7 +89,7 @@ template void auto_nttp_align_0() { int a; - #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } } */ } template @@ -99,7 +97,7 @@ void auto_nttp_align_1() { int a; #pragma omp allocate(a) align(Align) - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ /* { dg-error {could not convert 'nullptr' from 'std::nullptr_t' to '(?:long )?unsigned int'} "" { target *-*-* } .-2 } */ } @@ -111,5 +109,3 @@ void instantiate_auto_nttp_align() auto_nttp_align_1<32>(); /* { dg-bogus "required from here" } */ auto_nttp_align_1(); /* { dg-message "required from here" } */ } - -/* { dg-bogus "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } 0 } */ diff --git a/gcc/testsuite/g++.dg/gomp/allocate-14.C b/gcc/testsuite/g++.dg/gomp/allocate-14.C index d40288d957d..a622adc34d9 100644 --- a/gcc/testsuite/g++.dg/gomp/allocate-14.C +++ b/gcc/testsuite/g++.dg/gomp/allocate-14.C @@ -121,9 +121,9 @@ void nttp_allocator_static() { static int a; /* { dg-note "'a' declared here" } */ #pragma omp allocate(a) allocator(Alloc) - /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-1 } */ /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ - /* { dg-note "expression evaluates to '1024'" "" { xfail *-*-* } .-3 }*/ + /* { dg-note "expression evaluates to '1024'" "" { target *-*-* } .-3 }*/ } template @@ -145,9 +145,9 @@ void nttp_dependent_type_allocator_static_0() { static int a; /* { dg-note "'a' declared here" } */ #pragma omp allocate(a) allocator(Alloc) - /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-1 } */ /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ - /* { dg-note "expression evaluates to '1024'" "" { xfail *-*-* } .-3 }*/ + /* { dg-note "expression evaluates to '1024'" "" { target *-*-* } .-3 }*/ } template @@ -266,7 +266,7 @@ template void nttp_align() { int a; - #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */ } template @@ -289,7 +289,7 @@ template void nttp_dependent_type_align_0() { int a; - #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */ } template @@ -420,7 +420,7 @@ void all_dependent_2() int b = 42; Var a = b; #pragma omp allocate(a) allocator(Alloc) align(Align) - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ } template void templ_no_vars_dep_align_invalid() { #pragma omp allocate() align(Align) /* { dg-error "expected unqualified-id before '\\\)' token" } */ - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ } template void templ_no_vars_dep_align_invalid<42>(); @@ -876,7 +876,7 @@ template void templ_invalid_vars_param_dependent_align_invalid(int p) /* { dg-note "parameter 'p' declared here" } */ { #pragma omp allocate(p) align(Align) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" } */ - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ } template void templ_invalid_vars_param_dependent_align_invalid<42>(int); @@ -908,7 +908,7 @@ void templ_invalid_vars_out_of_scope_dependent_align_invalid() int a; /* { dg-note "declared here" } */ { #pragma omp allocate(a) align(Align) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ } } template void templ_invalid_vars_out_of_scope_dependent_align_invalid<42>(); @@ -944,7 +944,7 @@ void templ_invalid_vars_out_of_scope_and_param_dependent_align_invalid(int p) /* { #pragma omp allocate(a, p) align(Align) /* { dg-error "'allocate' directive must be in the same scope as 'a'" } */ /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target *-*-* } .-1 } */ - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-2 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-2 } */ } } template void templ_invalid_vars_out_of_scope_and_param_dependent_align_invalid<42>(int); @@ -1001,7 +1001,7 @@ void multiple_uses_dep_directive_before_invalid_align() { int a; #pragma omp allocate(a) align(Align) /* { dg-note "'a' previously appeared here" } */ - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ #pragma omp allocate(a) /* { dg-error "'a' already appeared as list item in an 'allocate' directive" } */ } template void multiple_uses_dep_directive_before_invalid_align<42>(); @@ -1032,11 +1032,6 @@ void multiple_uses_dep_directive_after_invalid_align() int a; #pragma omp allocate(a) /* { dg-note "'a' previously appeared here" } */ #pragma omp allocate(a) align(Align) /* { dg-error "'a' already appeared as list item in an 'allocate' directive" } */ - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ } template void multiple_uses_dep_directive_after_invalid_align<42>(); - -/* These are fixed by the later location wrapping patch. */ -/* { dg-bogus "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } 0 } */ -/* { dg-bogus "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } 0 } */ -/* { dg-bogus "expression evaluates to '1024'" "" { xfail *-*-* } 0 } */ diff --git a/gcc/testsuite/g++.dg/gomp/allocate-17.C b/gcc/testsuite/g++.dg/gomp/allocate-17.C index e265ecdd1e7..93777d611ea 100644 --- a/gcc/testsuite/g++.dg/gomp/allocate-17.C +++ b/gcc/testsuite/g++.dg/gomp/allocate-17.C @@ -31,7 +31,7 @@ auto lambda_0_bad_align() int b = 42; decltype(p3) a = b; #pragma omp allocate(a) align(Align) allocator(p2) - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ return a; }; }; @@ -87,7 +87,7 @@ auto lambda_0_all() decltype(p3) a = b; /* { dg-message "'a' declared here" } */ #pragma omp allocate(a) align(Align) allocator(p2) /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-2 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-2 } */ /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target *-*-* } .-3 } */ return a; }; @@ -212,18 +212,18 @@ auto lambda_1_bad_align() { return [](auto p0){ int a = 42; - #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */ return [](auto p1){ int a = 42; - #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */ return [](auto p2){ int a = 42; - #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */ return [p2](auto p3){ int b = 42; decltype(p3) a = b; #pragma omp allocate(a) align(Align) allocator(p2) - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-1 } */ return a; }; }; @@ -284,19 +284,19 @@ auto lambda_1_all() { return [](auto p0){ int a = 42; - #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */ return [](auto p1){ int a = 42; - #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */ return [](auto p2){ int a = 42; - #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } } */ + #pragma omp allocate(a) align(Align) /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" } */ return [p2](auto p3){ int b = 42; decltype(p3) a = b; /* { dg-message "'a' declared here" } */ #pragma omp allocate(a) align(Align) allocator(p2) /* { dg-error "variables with reference type may not appear in an 'allocate' directive" "" { target *-*-* } .-1 } */ - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } .-2 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-2 } */ /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target *-*-* } .-3 } */ return a; }; @@ -555,6 +555,3 @@ void instantiate_lambdas_2() auto c3 = c2.operator()(a); /* { dg-message "required from here" } */ } } - -/* This is fixed by the later location wrapping patch. */ -/* { dg-bogus "'align' clause argument needs to be positive constant power of two integer expression" "" { xfail *-*-* } 0 } */ From patchwork Tue May 5 15:02:00 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Waffl3x X-Patchwork-Id: 134489 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id F2D594BA9023 for ; Tue, 5 May 2026 15:11:43 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org F2D594BA9023 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=baylibre-com.20251104.gappssmtp.com header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256 header.s=20251104 header.b=WlYQsdBA X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x42e.google.com (mail-pf1-x42e.google.com [IPv6:2607:f8b0:4864:20::42e]) by sourceware.org (Postfix) with ESMTPS id 1C78A4BA900B for ; Tue, 5 May 2026 15:10:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1C78A4BA900B Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=baylibre.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 1C78A4BA900B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::42e ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993844; cv=none; b=uKJ6aVz+nKcjV1Qm4ZzdIxG7N4bg13gT/U+YQWU6ehxKiCRVeuD0+GrwoFhoGjseo6/Wqq6lh6Dx10IUy+zuGUiFtq6WVGMOLO5xB6Wix7en4Up4SW00w9eVrbFqbFevbAUPuug0fpRC9+RcOn5m0PeomLNIasXawFfCOdCLONU= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993844; c=relaxed/simple; bh=G2vQlhkBOWaDEz2caMDohH+GhO+gQ1HuBT0tT4Y4bQs=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=wplP4DS4WC4roZPqCFfiXh1ov+KJgE15NuK5xTZk4uL922A2+RyHmvcqen7Bce4mjyWStmSU5ZKUjkX0MOmhuJIA51NQOYkVHYciJJBcj3z6iO9Z/tU11JxpN58phIPTSJH4t5Ae4Ryar3C0Rg+2pwq0kVKd4UGR48p3jIhB4tk= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1C78A4BA900B Received: by mail-pf1-x42e.google.com with SMTP id d2e1a72fcca58-83538fcdda8so169598b3a.3 for ; Tue, 05 May 2026 08:10:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20251104.gappssmtp.com; s=20251104; t=1777993843; x=1778598643; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=mkLCCZpAyNYsCOGTjnMZPSLXY0v56RXrnUCh8+ZoCNQ=; b=WlYQsdBAEjVQTS9X6hTCIpVjDXRpXlwdqRdZzwzSyA7K0KUqVbFa6WvUen6PUmfYTt qOG8yNZI5iAtuZHbhkmwzgNDybHSHC9qdLIWzJ/uniKQ11vln5aJTRfNleSCN+dB331A m44+aaZN+A3vK6eoFgAzZWzQ9gWHq6W/fPB25TrXfRXAwU2VF8ij3XgGrpKTyFMUd0io e4SKbjsWzIGlcSEFD/ETJUEyhuQpkH/fjEXd6PTVOs+YrhqAik1R4/Eg9A/M2Kjtg9xa kSGOVJcqFAEZJrRK3F5uwdA4u4xMBVXMHP7zIcBYxHuBkditi18Ro9h5DTEX2WEPEpDs ikzQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777993843; x=1778598643; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=mkLCCZpAyNYsCOGTjnMZPSLXY0v56RXrnUCh8+ZoCNQ=; b=KPwZF4Ockf6jprv3UHQqjZ8LzkOCafwf/rwwdPu3eyqizp7AE2ydfJfbhhiuMfE8ec uq7JZuBX4Wy1Gd5WTYBXnVPnviTkZeVqOxTdyl2gkbpJ76vrm7ZAXr+8+wlcLrHhE0xv aV3rdH3ptstzIlSb+NSgLctXH8oGzP8t5adPtTVbAhUgSor5yqvlD4YKrmH2QvyrDqMi TKeX+W4qlKvMDr+3pz8ujJXSQwutS7SKSHCQoRFPnH/MGvkc6FkLeGGoC6wJlduPtYXS ViyELItanVByl1p5/YQVYGswHyL+9OuEa7AzHKji1A0/O9WYQ2LpL0TadoPF4trqCAVI a2OQ== X-Gm-Message-State: AOJu0YwdPOGeYfhPgiIx/L+Z5w51Y2aanGbEbeDtJQnatxO10kNf26lP JG1eyAurta0Qp1O25rg6EOIrVi8maJSa8FG/SwIFa2xDWlJUwkoGfSBiHDow4ECVnM8hRobNRUc sqDha X-Gm-Gg: AeBDiesNLDFyZPm/g5wc4/Oyoo3HdcYuPJbCkEm0FTySgoF1acj0TQj4hWCO83u+BcZ JMo/rNltvJz+UtCeSwHzjQzT0jAKt2B749srQb61fFEBRbC+TkIFhrIqGjGy9gu0Ve+RxfKasIv c3/vo3MvkZBYLriuerntTB34qng4wtxODZjH9DyqZvoOIwwE9XPNe7zW5TzxmS66IQTbmyLPT1I 1XRcWwqSOKeBw9nB1GQqy1efP0ARDmg5XVkBTKIQKScvfTzmMjspBU78GwKSGZ6HqLVtJR2Dlys eBrk6X22OWtIdTGCI3bVw9HEVcisUEO9uvE3Y5jV/3+d8RikwSCOgVu0xKZFdfavRFtW7M5IFJT 9kn91/2V3Vh5ZNcLMKe9+qDBk9G0QyaBte99zVh9BudEHU3vfW9fuoouYXPfnWbtBW2L2xGuUlx LsAm6EgKfn3X2paWc6nlU0ELmiSws+nD6JrScrR1n7Klx3UnMOOw== X-Received: by 2002:aa7:88c8:0:b0:837:42a6:58a8 with SMTP id d2e1a72fcca58-83742b5accdmr4734237b3a.2.1777993843081; Tue, 05 May 2026 08:10:43 -0700 (PDT) Received: from waffl3x-prestige.lan ([2001:56a:f98a:b800:1f67:ce08:3cbd:86b8]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83965645140sm2674956b3a.12.2026.05.05.08.10.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 08:10:42 -0700 (PDT) From: Waffl3x To: gcc-patches@gcc.gnu.org Cc: Waffl3x Subject: [PATCH 07/12] OpenMP/C++: Don't do NRVO on vars used in an 'omp allocate' directive Date: Tue, 5 May 2026 09:02:00 -0600 Message-ID: <20260505151030.1749548-8-waffl3x@baylibre.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505151030.1749548-1-waffl3x@baylibre.com> References: <20260505151030.1749548-1-waffl3x@baylibre.com> MIME-Version: 1.0 X-Spam-Status: No, score=-12.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org NRVO is incompatible with the transformations made by an allocate directive, this patch disables it for those variables. Also adjusts a few tests that were modified to work around this bug. gcc/cp/ChangeLog: * typeck.cc (can_do_nrvo_p): Return false for vars in an allocate directive. gcc/testsuite/ChangeLog: * g++.dg/gomp/allocate-5.C: Remove workarounds, enable ilp32. * g++.dg/gomp/allocate-6.C: Likewise. * g++.dg/gomp/allocate-7.C: Likewise. * g++.dg/gomp/allocate-22.C: New test. Signed-off-by: Waffl3x --- gcc/cp/typeck.cc | 5 +++- gcc/testsuite/g++.dg/gomp/allocate-22.C | 31 +++++++++++++++++++++++++ gcc/testsuite/g++.dg/gomp/allocate-5.C | 3 +-- gcc/testsuite/g++.dg/gomp/allocate-6.C | 3 +-- gcc/testsuite/g++.dg/gomp/allocate-7.C | 8 ++++--- 5 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-22.C diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index dcc35ae28a2..68a07229ece 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -11164,7 +11164,10 @@ can_do_nrvo_p (tree retval, tree functype) && same_type_p (TYPE_MAIN_VARIANT (TREE_TYPE (retval)), TYPE_MAIN_VARIANT (functype)) /* And the returned value must be non-volatile. */ - && !TYPE_VOLATILE (TREE_TYPE (retval))); + && !TYPE_VOLATILE (TREE_TYPE (retval)) + /* And the variable must not be used in an allocate directive. */ + && (!flag_openmp || !lookup_attribute ("omp allocate", + DECL_ATTRIBUTES (retval)))); } /* True if we would like to perform NRVO, i.e. can_do_nrvo_p is true and we diff --git a/gcc/testsuite/g++.dg/gomp/allocate-22.C b/gcc/testsuite/g++.dg/gomp/allocate-22.C new file mode 100644 index 00000000000..821d9b2c610 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-22.C @@ -0,0 +1,31 @@ +/* { dg-do compile { target c++14 } } */ + +/* This used to ICE due to NRVO being attempted on 's', NRVO can not be + done on a variable used in an allocate directive. */ + +/* NRVO probably kicks in when sizeof(T) is greater than 16. */ +struct S +{ + char _v[17]; +}; + +S f0() +{ + S s; + #pragma omp allocate(s) + return s; +} + +/* Also test with a VERY LARGE type just in case the above isn't big enough + to trigger NRVO in all cases. */ +struct Big +{ + char _v[4096]; +}; + +Big f1() +{ + Big b; + #pragma omp allocate(b) + return b; +} diff --git a/gcc/testsuite/g++.dg/gomp/allocate-5.C b/gcc/testsuite/g++.dg/gomp/allocate-5.C index 724dd980138..f1085521fc5 100644 --- a/gcc/testsuite/g++.dg/gomp/allocate-5.C +++ b/gcc/testsuite/g++.dg/gomp/allocate-5.C @@ -1,5 +1,4 @@ /* { dg-additional-options "-fdump-tree-gimple" } */ -/* { dg-skip-if "" { ilp32 } } */ #include "allocate-allocator-handle.h" @@ -55,7 +54,7 @@ struct S0 { }; struct S1 { - int _v[2]; + int _v[32]; S1(int v) : _v() { int *end = _v + sizeof(_v) / sizeof(*_v); for (int *it = _v; it != end; ++it) diff --git a/gcc/testsuite/g++.dg/gomp/allocate-6.C b/gcc/testsuite/g++.dg/gomp/allocate-6.C index eb0c78a24db..d33b7d53097 100644 --- a/gcc/testsuite/g++.dg/gomp/allocate-6.C +++ b/gcc/testsuite/g++.dg/gomp/allocate-6.C @@ -1,5 +1,4 @@ /* { dg-do compile { target c++11 } } */ -/* { dg-skip-if "" { ilp32 } } */ /* { dg-additional-options "-fdump-tree-gimple" } */ #include "allocate-allocator-handle.h" @@ -23,7 +22,7 @@ struct S0 { }; struct S1 { - int _v[2]; + int _v[32]; S1(int v) : _v() { int *end = _v + sizeof(_v) / sizeof(*_v); for (int *it = _v; it != end; ++it) diff --git a/gcc/testsuite/g++.dg/gomp/allocate-7.C b/gcc/testsuite/g++.dg/gomp/allocate-7.C index 01fc5b84014..16cc5843d1b 100644 --- a/gcc/testsuite/g++.dg/gomp/allocate-7.C +++ b/gcc/testsuite/g++.dg/gomp/allocate-7.C @@ -1,5 +1,4 @@ /* { dg-do compile { target c++20 } } */ -/* { dg-skip-if "" { ilp32 } } */ /* { dg-additional-options "-fdump-tree-gimple" } */ #include "allocate-allocator-handle.h" @@ -37,8 +36,11 @@ struct S0 { }; struct S1 { - int _v[2]; - S1(int v) : _v{v, v} {} + int _v[32]; + S1(int v) : _v{v, v, v, v, v, v, v, v, + v, v, v, v, v, v, v, v, + v, v, v, v, v, v, v, v, + v, v, v, v, v, v, v, v} {} operator int() const { return 42; } }; From patchwork Tue May 5 15:02:01 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Waffl3x X-Patchwork-Id: 134496 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 2852B4B9DB41 for ; Tue, 5 May 2026 15:15:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2852B4B9DB41 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=baylibre-com.20251104.gappssmtp.com header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256 header.s=20251104 header.b=pgrdbNp/ X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x429.google.com (mail-pf1-x429.google.com [IPv6:2607:f8b0:4864:20::429]) by sourceware.org (Postfix) with ESMTPS id 3D11F4BA901C for ; Tue, 5 May 2026 15:10:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3D11F4BA901C Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=baylibre.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3D11F4BA901C Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::429 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993845; cv=none; b=nwSllDtkvyyVpEOG15KR4dzSAnSfAIYHQhJTAzrykLPJDiQA4Hge9l9m5qq43x2/bVMWwSosCpWHXaHkDjU1UUyqbfbb+oJAGSqBNoAhFyvZZKVmbCIn3Zt6izGEQRdLIQzbjFvUbIIv/819kx3tUwGLo4p9Roi0FdLUVq+48is= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993845; c=relaxed/simple; bh=5MmzDzRbTa1Nc597zcSWr5hq+GLl2pjrNDwxuuud30s=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=AaN5TzdioLhU+0X1ckmWLhbQrKrn/6O0qWYeay5b5jLQ3d4pTCi768+0pSooaii0nypJ5+YsyKWuTZejRmY2xYM/d/iVPd4aNW/AbA+GUoou9REPWmylnST5anuw41dDReLJ6yyaCpcnQdBldvoIE8eBdgU2+sPY9IE3RxdXj3Y= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3D11F4BA901C Received: by mail-pf1-x429.google.com with SMTP id d2e1a72fcca58-8270edc7e2eso185039b3a.2 for ; Tue, 05 May 2026 08:10:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20251104.gappssmtp.com; s=20251104; t=1777993844; x=1778598644; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=/XG/My7MXGpBwVGqzYJsvCW3dOUAxVIVxF90SGgIS9I=; b=pgrdbNp/SKEOzopxPVI6WT4deuwLYW1Z1YizBAsv/CGdEUmWwfz1db869N2aY2xNNF vPLwoHZ0ViP0OqJoZ414axxUsrDGD5vawCLT+YFQ8qasgUv0H8Gzxo3yEVDCY/CEMyLg mRbWeHmhzbVr/3eKwItoUwJ/D8xD9mYtjt3AzlWITSMgx7+yqLZSN4JdIGz7xEG+lWMK MPFRa2DJRGJx2CEM8jrmlg+ct5U6oxNx8DZhgyi7acyoNroPpPz/9u8vD0p+xbrjcRpl LKBe+Qr8icKx8V3jfgrM3I9nS1ULzAwah4VHBO8W1jXvnoWqq4vy/v9/8FQpvcesmVBz +i9g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777993844; x=1778598644; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=/XG/My7MXGpBwVGqzYJsvCW3dOUAxVIVxF90SGgIS9I=; b=DG47WP8J2DGEtJcoMSN+R/yHYW4oIyehk+AKCoqoYaOc2FCUA3Qp1g2TGRBb0oMYQ4 ZFhF/0ij8eZ+pHz20s2Ip99OVMIO6NR/FZJlZBk5U9rAZv7zBB0g93NxfrNeW8a9R3gs xwDCCz3MMJzNsIOpyD2YBKMLXGieO6wjN37E4jg+Rbs8IAo9Ds/q81vlVpKZRys79aWK 3azJ37S5SwoG8/S1spm5fdyMAMs6IUmFZqdt6xne72vJkI2HBtJuqWClaQvxnyy1kY6T fZERorLh/hINXOdDzWnbk1Tc7860uJFJuP0ZkM23gbUsmfW67VdgkEihprRlcuPeXBEs cCdQ== X-Gm-Message-State: AOJu0Yw8HkVHoqCUTrW8tmfRlqfRuLOMY+mrlm5kINxxIl/NK86pakEC W4eUoWiBq+YRlF7yga/I6jX08I3W2K/+QqKkYL8Do4gCXW5ShFYGt2g0EBxacZQ1K0yHvZbCHf3 +iKG+ X-Gm-Gg: AeBDievc3EZUuox5tye1FDDoQODkv91UvYJGZeS5YJVDMYjOH3+L2N8nORpVENkda2O ghDW+x7CcxuZ/WeiMwFQE5b2OfkCv+6ioxG6rfcSFwiZu6DovKCsdELZdi5g0ZIfVeygInUqdMv TvXOd0nSl76pFOL789/NY7Mv2W3VqVa9BgAHzeJ2gSris1T15BxT835R2zU07n2CQ7DgoTanzfx +k5IAoeQG3VSUnQU/Ebo70XZUP5MztbxDUkwI9ED/PigvAviNbdWFurBCYOczVDcc/V4nW8qA5F LrN7wp4ozHJYAwORe7EtWp2banm6WaJNzGSA4NKhf5SZ6GWFFEuQlLikTB4Hnl0DvT5aAVSGCeY wONy5Mg1kp4kOhRrOs8HrOF7Q5HCsWGwCO7O6N83zw+9Se8zRgHX2uGzK1finmqYt06GKMvvXUP 4LVA9jkSx3kEJJ/leI0WRCI7KdUPTwh0CR18dG+n5/932t9LH2mg== X-Received: by 2002:a05:6a00:9a8:b0:81f:72ef:27f0 with SMTP id d2e1a72fcca58-8393e752930mr1589494b3a.6.1777993844048; Tue, 05 May 2026 08:10:44 -0700 (PDT) Received: from waffl3x-prestige.lan ([2001:56a:f98a:b800:1f67:ce08:3cbd:86b8]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83965645140sm2674956b3a.12.2026.05.05.08.10.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 08:10:43 -0700 (PDT) From: Waffl3x To: gcc-patches@gcc.gnu.org Cc: Waffl3x Subject: [PATCH 08/12] OpenMP/C++: Add static analysis of allocate directive allocator clause Date: Tue, 5 May 2026 09:02:01 -0600 Message-ID: <20260505151030.1749548-9-waffl3x@baylibre.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505151030.1749548-1-waffl3x@baylibre.com> References: <20260505151030.1749548-1-waffl3x@baylibre.com> MIME-Version: 1.0 X-Spam-Status: No, score=-13.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org Due to the nature of transformations made on vars in an 'omp allocate' directive, there are additional requirements on an allocator clause attached to the directive. At minimum, all vars used in its expr must be declared before all the vars specified in the allocate directive, this also includes vars used in the directive themselves. This is of course unless the vars in the expr are unevaluated or static constexpr. We could potentially allow static but it doesn't seem practical. Allowing constexpr vars without static could also be fine if the clause is constant evaluated but that increases complexity. One can still declare such vars before the first var in the allocate directive. This patch diagnoses such cases, and takes into account those exceptions. In the future we could provide better diagnostics for the edge cases, such as suggesting adding 'static' to a constexpr variable declaration. The C front end also tries to diagnose mutations of such vars that occur between the first declared variable in the allocate directive and the allocate directive itself, but it misses non-trivial cases. This patch does not attempt to diagnose these. It would be better to move such diagnostics and warnings into finish_omp_allocate as there are a lot of cases that are dependent. The diagnostics of declaration order and bad uses of vars can stay in cp_parser_omp_allocate. gcc/cp/ChangeLog: * parser.cc (cp_parser_omp_allocate): Add allocator clause expr diagnostics. gcc/testsuite/ChangeLog: * c-c++-common/gomp/allocate-5.c: Adjust test. * c-c++-common/gomp/allocate-12.c: Remove xfail. * c-c++-common/gomp/allocate-16.c: Likewise. * c-c++-common/gomp/allocate-20.c: Likewise. * g++.dg/gomp/allocate-23.C: New test. Signed-off-by: Waffl3x --- gcc/cp/parser.cc | 129 ++++++++++++++++++ gcc/testsuite/c-c++-common/gomp/allocate-12.c | 6 +- gcc/testsuite/c-c++-common/gomp/allocate-16.c | 9 +- gcc/testsuite/c-c++-common/gomp/allocate-20.c | 12 +- gcc/testsuite/c-c++-common/gomp/allocate-5.c | 5 +- gcc/testsuite/g++.dg/gomp/allocate-23.C | 24 ++++ 6 files changed, 170 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-23.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 412a71c439c..aa6777e5ed4 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -47190,6 +47190,10 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) nl = nreverse (nl); const tree directive_ctx = current_scope (); + /* Used for diagnostics of the allocator clause's expr in + check_omp_allocate_allocator_r. We only keep this locally, nl is still + what ultimately gets passed along to finish_omp_allocate. */ + hash_map arg_map; { auto var_is_in_scope = [&] (tree var_decl) { @@ -47325,6 +47329,7 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) arg_loc_wrapper, *attr_chain); } + arg_map.put (var, arg_loc); /* Keep the node. */ chain = &TREE_CHAIN (node); } @@ -47373,6 +47378,130 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) } while (true); cp_parser_require_pragma_eol (parser, pragma_tok); + /* Used in check_omp_allocate_allocator_r callback. */ + struct omp_alloc_expr_ctx + { + location_t alloc_expr_loc; + tree first_arg; + hash_map& arg_map; + hash_set& declared_after_first_arg; + /* Vars used erroneously in the alloc expr. */ + hash_set diagnosed; + }; + /* Callback for cp_walk_tree. Always returns NULL_TREE so we diagnose as + much as possible. */ + auto check_omp_allocate_allocator_r = [] (tree *tp, int *ws, void *data) + { + gcc_assert (tp != nullptr && ws != nullptr && data != nullptr); + /* Uses of variables in unevaluated contexts are permitted. */ + if (TREE_CODE (*tp) == DECLTYPE_TYPE) + { + *ws = 0; + return NULL_TREE; + } + /* Unwrap manually so we have a location for diagnostics. */ + tree var_in_expr = tree_strip_any_location_wrapper (*tp); + if (!VAR_P (var_in_expr)) + return NULL_TREE; + /* We can technically allow more than this, but it gets a bit more hazy. + In particular just 'static' should be okay, but it would need to be + constant initialized. It just doesn't make sense to allow it. + (It can still be used as long as it is declared before.) */ + if (DECL_DECLARED_CONSTEXPR_P (var_in_expr) + && TREE_STATIC (var_in_expr)) + return NULL_TREE; + /* Don't walk wrappers of vars, unwrap them manually (see above). */ + if (location_wrapper_p (*tp)) + *ws = 0; + + omp_alloc_expr_ctx& ctx = *static_cast(data); + /* Don't repeat diagnostics if we find the same var used twice. */ + if (ctx.diagnosed.contains (var_in_expr)) + return NULL_TREE; + + /* Don't evaluate the location until we need it. */ + auto make_alloc_expr_loc = [&] () + { + const location_t alloc_expr_loc = ctx.alloc_expr_loc; + const location_t loc = EXPR_LOCATION (*tp); + /* If *tp has a meaningful location, use it for the caret. */ + return loc == UNKNOWN_LOCATION + ? alloc_expr_loc + : make_location (loc, alloc_expr_loc, alloc_expr_loc); + }; + + if (const location_t *const arg_loc = ctx.arg_map.get (var_in_expr)) + { + auto_diagnostic_group d; + error_at (make_alloc_expr_loc (), + "variable %qD used in % directive must " + "not be used in its % clause", var_in_expr); + inform (DECL_SOURCE_LOCATION (var_in_expr), "declared here"); + inform (*arg_loc, + "used in allocate directive here"); + ctx.diagnosed.add (var_in_expr); + return NULL_TREE; + } + if (ctx.declared_after_first_arg.contains (var_in_expr)) + { + auto_diagnostic_group d; + error_at (make_alloc_expr_loc (), + "variable %qD used in the % clause " + "must be declared before %qD", + var_in_expr, ctx.first_arg); + inform (DECL_SOURCE_LOCATION (var_in_expr), "declared here"); + inform (DECL_SOURCE_LOCATION (ctx.first_arg), + "first to be allocated variable declared here"); + ctx.diagnosed.add (var_in_expr); + return NULL_TREE; + } + return NULL_TREE; + }; + + /* Diagnose invalid uses of variables in the allocator clause's expr. + If we want to warn about variables that are potentially modified, either + by their address being taken or a reference being bound, it must be done + in cp/semantics.cc:finish_omp_allocate instead as such cases can + potentially be dependent. */ + if (allocator != NULL_TREE && !arg_map.is_empty ()) + { + hash_set declared_after_first_arg; + const tree first_arg = [&] () + { + tree var = current_binding_level->names; + size_t remaining_args = arg_map.elements (); + for (; var != NULL_TREE; var = DECL_CHAIN (var)) + { + gcc_assert (remaining_args != 0); + if (!VAR_P (var)) + continue; + if (!arg_map.get (var)) + { + /* We haven't seen every arg in arg_map, this var is declared + after at least one of the args. */ + declared_after_first_arg.add (var); + continue; + } + --remaining_args; + if (remaining_args == 0) + break; + } + /* We stop the above loop before advancing the chain so VAR is the + first variable declared (not to be confused with the first arg) + that was passed into the allocate directive. */ + return var; + } (); /* IILE. */ + + gcc_assert (first_arg != NULL_TREE && arg_map.get (first_arg)); + omp_alloc_expr_ctx ctx = {allocator.get_location (), first_arg, arg_map, + declared_after_first_arg, hash_set()}; + tree a = allocator.get_value (); + cp_walk_tree (&a, check_omp_allocate_allocator_r, &ctx, nullptr); + /* Don't try to do anything else with an invalid allocator expr. */ + if (!ctx.diagnosed.is_empty ()) + allocator = cp_expr (error_mark_node, UNKNOWN_LOCATION); + } + /* Some codes, such as template parameters, don't get wrapped by maybe_wrap_with_location despite not being able to carry a location. We need a location to issue good diagnostics in finish_omp_allocate. */ diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-12.c b/gcc/testsuite/c-c++-common/gomp/allocate-12.c index 6a53770697c..6f3ddd361f2 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-12.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-12.c @@ -47,9 +47,9 @@ f2 () int g () { - int n = 5; /* { dg-note "to be allocated variable declared here" "" { xfail c++ } } */ - omp_allocator_handle_t my_allocator = omp_low_lat_mem_alloc; /* { dg-note "declared here" "" { xfail c++ } } */ - #pragma omp allocate(n) allocator(my_allocator) /* { dg-error "variable 'my_allocator' used in the 'allocator' clause must be declared before 'n'" "" { xfail c++ } } */ + int n = 5; /* { dg-note "to be allocated variable declared here" } */ + omp_allocator_handle_t my_allocator = omp_low_lat_mem_alloc; /* { dg-note "declared here" } */ + #pragma omp allocate(n) allocator(my_allocator) /* { dg-error "variable 'my_allocator' used in the 'allocator' clause must be declared before 'n'" } */ n = 7; return n; } diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-16.c b/gcc/testsuite/c-c++-common/gomp/allocate-16.c index 7df9a92fd9f..b5317b575e5 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-16.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-16.c @@ -14,15 +14,16 @@ omp_allocator_handle_t foo(int, int *); void f () { - int v; /* { dg-note "to be allocated variable declared here" "" { xfail c++ } } */ + int v; /* { dg-note "to be allocated variable declared here" } */ static const int n = 5; int a = 1; - /* { dg-note "declared here" "" { xfail c++ } .-1 } */ + /* { dg-note "declared here" "" { target *-*-* } .-1 } */ int b[n]; - /* { dg-note "declared here" "" { target c++ xfail c++ } .-1 } */ + /* { dg-note "declared here" "" { target c++ } .-1 } */ b[a] = 5; #pragma omp allocate (v) allocator (foo (a, &b[a])) - /* { dg-error "variable 'a' used in the 'allocator' clause must be declared before 'v'" "" { xfail c++ } .-1 } */ + /* { dg-error "variable 'a' used in the 'allocator' clause must be declared before 'v'" "" { target *-*-* } .-1 } */ + /* { dg-error "variable 'b' used in the 'allocator' clause must be declared before 'v'" "" { target c++ } .-2 } */ } void diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-20.c b/gcc/testsuite/c-c++-common/gomp/allocate-20.c index 604e4847a92..36f3cb3627c 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-20.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-20.c @@ -262,8 +262,8 @@ void f_with_parm_and_allocator0(int p) /* { dg-note "parameter 'p' declared here void f_with_parm_and_allocator1(int p) /* { dg-note "parameter 'p' declared here" "" { target c++ } } */ { - int v0; /* { dg-note "to be allocated variable declared here" "" { xfail c++ } } */ - omp_allocator_handle_t alloc0 = omp_default_mem_alloc; /* { dg-note "declared here" "" { xfail c++ } } */ + int v0; /* { dg-note "to be allocated variable declared here" } */ + omp_allocator_handle_t alloc0 = omp_default_mem_alloc; /* { dg-note "declared here" } */ /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c } .+2 } */ /* { dg-error "variable 'alloc0' used in the 'allocator' clause must be declared before 'v0'" "" { target c } .+1 } */ #pragma omp allocate(\ @@ -271,7 +271,7 @@ void f_with_parm_and_allocator1(int p) /* { dg-note "parameter 'p' declared here v0)\ allocator(alloc0) /* { dg-error "function parameter 'p' may not appear as list item in an 'allocate' directive" "" { target c++ } .-3 } */ - /* { dg-error "variable 'alloc0' used in the 'allocator' clause must be declared before 'v0'" "" { target c++ xfail c++ } .-2 } */ + /* { dg-error "variable 'alloc0' used in the 'allocator' clause must be declared before 'v0'" "" { target c++ } .-2 } */ int v1; /* { dg-note "declared here" } */ { @@ -285,8 +285,8 @@ void f_with_parm_and_allocator1(int p) /* { dg-note "parameter 'p' declared here /* { dg-error "'allocate' directive must be in the same scope as 'v1'" "" { target c++ } .-3 } */ } { - int v3; /* { dg-note "to be allocated variable declared here" "" { xfail c++ } } */ - omp_allocator_handle_t alloc2 = omp_default_mem_alloc; /* { dg-note "declared here" "" { xfail c++ } } */ + int v3; /* { dg-note "to be allocated variable declared here" } */ + omp_allocator_handle_t alloc2 = omp_default_mem_alloc; /* { dg-note "declared here" } */ /* { dg-error "variable 'alloc2' used in the 'allocator' clause must be declared before 'v3'" "" { target c } .+2 } */ /* { dg-error "'allocate' directive must be in the same scope as 'v1'" "" { target c } .+1 } */ #pragma omp allocate(\ @@ -294,7 +294,7 @@ void f_with_parm_and_allocator1(int p) /* { dg-note "parameter 'p' declared here v3\ ) allocator(alloc2) /* { dg-error "'allocate' directive must be in the same scope as 'v1'" "" { target c++ } .-3 } */ - /* { dg-error "variable 'alloc2' used in the 'allocator' clause must be declared before 'v3'" "" { target c++ xfail c++ } .-2 } */ + /* { dg-error "variable 'alloc2' used in the 'allocator' clause must be declared before 'v3'" "" { target c++ } .-2 } */ } } diff --git a/gcc/testsuite/c-c++-common/gomp/allocate-5.c b/gcc/testsuite/c-c++-common/gomp/allocate-5.c index b34f9ea9227..e47bfb217bf 100644 --- a/gcc/testsuite/c-c++-common/gomp/allocate-5.c +++ b/gcc/testsuite/c-c++-common/gomp/allocate-5.c @@ -39,9 +39,10 @@ bar () /* { dg-error "expected end of line before '\\(' token" "" { target *-*-* } .-1 } */ #pragma omp allocate(a2) allocator(b) /* { dg-error "'allocator' clause expression has type 'int' rather than 'omp_allocator_handle_t'" "" { target c } .-1 } */ - /* { dg-error "invalid conversion from 'int' to 'omp_allocator_handle_t'" "" { target c++ } .-2 } */ + /* { dg-error "variable 'b' used in the 'allocator' clause must be declared before 'a2'" "" { target c++ } .-2 } */ /* We have diverging behavior here between c and c++ due to a difference in - order of diagnostics, as well as diverging semantics, this should probably be unified. */ + order of diagnostics, as well as diverging semantics, this should probably be unified. + Really this is probably very bugged in C. */ } diff --git a/gcc/testsuite/g++.dg/gomp/allocate-23.C b/gcc/testsuite/g++.dg/gomp/allocate-23.C new file mode 100644 index 00000000000..8593dfcc915 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-23.C @@ -0,0 +1,24 @@ +/* { dg-do compile { target c++14 } } */ +#include "allocate-allocator-handle.h" + +/* Valid uses of vars in an allocator clause. */ + +void constexpr_var_declared_after() +{ + int a = 42; + static constexpr omp_allocator_handle_t my_handle = omp_default_mem_alloc; + #pragma omp allocate(a) allocator(my_handle) +} + +template +constexpr omp_allocator_handle_t get_alloc() +{ + return omp_default_mem_alloc; +} + +void unevaluated_use_of_var() +{ + int a = 42; + int b = 42; + #pragma omp allocate(a, b) allocator(get_alloc()) +} From patchwork Tue May 5 15:02:02 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Waffl3x X-Patchwork-Id: 134493 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id E6F7A4BA9018 for ; Tue, 5 May 2026 15:13:19 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E6F7A4BA9018 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=baylibre-com.20251104.gappssmtp.com header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256 header.s=20251104 header.b=vwhuTA46 X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x431.google.com (mail-pf1-x431.google.com [IPv6:2607:f8b0:4864:20::431]) by sourceware.org (Postfix) with ESMTPS id 030504BA901A for ; Tue, 5 May 2026 15:10:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 030504BA901A Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=baylibre.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 030504BA901A Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::431 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993846; cv=none; b=LsQUVoYbwft7h8H5M9GpRXZJMTwhYql3whhYvJjCAKLo2V2Bkd8PYVM6r98eRMWAeJSlPJbrdxPUwvIr2gKYNYqPOTl9oWqwLik1gda3ANU3Yd1MAflfI5VH3NZLs9v6l5whh7AJVP0VUbtM8XqoAA7I47cDvjHEIPLNyhZIDPg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993846; c=relaxed/simple; bh=owiihx2aBzcxi4dNoVGtPUGDF0a6V4YiYZnRdJ/ASiA=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=HXSJjzXwQB0v9NrgOCJYZgDZs/H448Bu8vzRlXtPtHd//AUf+KeFGuHgHOBpaxUrpvzI9BdRAkfantEbGm1asXX3wgzSpjsgKAu7R4e0k9XvGZ6QguT/X9vIh5CFFvBAkuNAQK9icHmilNNABwXfRhnohAvJNBUl3FqpijO7Z1s= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 030504BA901A Received: by mail-pf1-x431.google.com with SMTP id d2e1a72fcca58-826dab01bbdso200988b3a.0 for ; Tue, 05 May 2026 08:10:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20251104.gappssmtp.com; s=20251104; t=1777993845; x=1778598645; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=WF/GxCbpS3643tblFf06FOxBdfv6sIDbnPId+JYHRlk=; b=vwhuTA46qCVYYL9K7S57iDMAeP27S1lx6vtHvvcrwjblX5pNJUBVUEicSJ+A1tKR+n ljtuQBTJweR1j61xVpBM2fR0d3FMKDufs27QSlQuM1bfibflcj91ozaA/puj/iLRiPJ7 pGIJZgFBl41faqLbEqswPZj1KyMHmRcSlCcUa9DGnHv8GJzdbvofbbNUd9YyH2MzlG+o kgxQBzVZn7NZtJU2D6TZc0oYd+SlhmXmZJDq+lmDCOWgiU4wSx2wKa8a6cSCoE84dc4t MPrOw5ajBluu84XCi8EP4T0lefFioStjFDliTFDPVFeahoOQdKAJ/D+qlPgH5MzXuv/N nYnw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777993845; x=1778598645; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=WF/GxCbpS3643tblFf06FOxBdfv6sIDbnPId+JYHRlk=; b=D2jIxCn2BsSW22BzNExDzogk73cOeB7Y2eplvnOwaTmM1pGEEuHWGQTseCZk3Jjo7l 71nl22XqazvgA1StJEDw/8UXHXAZ0DL/Ijy36kOhmfDxdihJ6bMKkNUG2qacWzdkr8KN aRihvrBLZB7ERu6FAzwOHL9W7qbimVyntLybIO1TEoRV4uKfomacvoyXdCaTa9lxFW8p DyrCmf/96bv+v81R7/+CY3LE38FiJZHAD/9bGkiFteWnb8i6fe3D9LPbOC5/EQMm8J+C y+m5oR0hC23YpQAmzPve+zYhJe/sTGhLRDyXql1OtZ0BJyOVGkmez8ZF67RniD8OjOCB EQOg== X-Gm-Message-State: AOJu0YwxRluggUuTeNBOUGZmf5hAMg6r1a8ITAD+MJxBO4uz5BC/n0kt R9/D1lncCzUKSPT97u1RP2uHN3+iEG1aAKtGqQgTMZI0I9YiTI2oiAhvlV1pBVDOMX+OJ3gB4t4 QP/Y6 X-Gm-Gg: AeBDievluv/UUPX4BFlY4tU01AYO0geRV3IJhBhhNs9ljIFK2VqXmgT9H+AQHB3LOSJ 4+kfjY1FMZ+ELjCHpfCuJIkjApvNsX6TlO0JZ3PaWY0HfjwXQIQAbZ/6lfpeFoE/0xweaQWHxv+ +UXmO8wkshfm9elMTzBs59OD/k32B/U+hibOBy2nhqtmwqrSAHF4wCNg83puntbyx1YmBP9zkKX 3I91VH8sycSfaJETslf2jmL0tLJpu51S0jqnuSxa4qCYmjJIxyvtFUlWBVGIunt9pcJIjNWLOwb dV5NPVl7hpXSuZspkUG+YcTXmyU12mMgFUhVXHRnZIfjAcsMEaRbUsS/CQJ8isDVM6AtmQoDNDW UZVj9p5OKk0QOX6zPx6ycvilyEjZrGEYO7ZdiK8qVpHx0gEGqPVwwfCgeI88Dhp1AGPDWm3NnM9 ISm592qoYLAgWDHKOCbKInXhATcU6PItVRT3qEpzRNxpj+fUDeKw== X-Received: by 2002:a05:6a00:e08:b0:834:dfb5:6e7f with SMTP id d2e1a72fcca58-8393bbf2e19mr1596698b3a.2.1777993844973; Tue, 05 May 2026 08:10:44 -0700 (PDT) Received: from waffl3x-prestige.lan ([2001:56a:f98a:b800:1f67:ce08:3cbd:86b8]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83965645140sm2674956b3a.12.2026.05.05.08.10.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 08:10:44 -0700 (PDT) From: Waffl3x To: gcc-patches@gcc.gnu.org Cc: Waffl3x Subject: [PATCH 09/12] OpenMP/C++: Diagnose constexpr vars in an allocate directive Date: Tue, 5 May 2026 09:02:02 -0600 Message-ID: <20260505151030.1749548-10-waffl3x@baylibre.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505151030.1749548-1-waffl3x@baylibre.com> References: <20260505151030.1749548-1-waffl3x@baylibre.com> MIME-Version: 1.0 X-Spam-Status: No, score=-13.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org It is unclear whether this should be allowed or not. For now, diagnose it until one can come up with a compelling reason to allow it. gcc/cp/ChangeLog: * parser.cc (cp_parser_omp_allocate): Add diagnostics. gcc/testsuite/ChangeLog: * g++.dg/gomp/allocate-15.C: Add cases. Signed-off-by: Waffl3x --- gcc/cp/parser.cc | 13 ++++++++ gcc/testsuite/g++.dg/gomp/allocate-15.C | 42 +++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index aa6777e5ed4..791ac2d6ea9 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -47254,6 +47254,19 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) continue; } + if (DECL_DECLARED_CONSTEXPR_P (var)) + { + auto_diagnostic_group d; + error_at (arg_loc, + "constexpr variable %qD may not appear as list item in " + "an % directive", var); + inform (DECL_SOURCE_LOCATION (var), + "%qD declared here", var); + /* Remove the node. */ + *chain = TREE_CHAIN (node); + continue; + } + /* Do this before checking if the var was used in another allocate directive, as the latter diagnostic implies that removing the var from the previous directive would fix the problem. */ diff --git a/gcc/testsuite/g++.dg/gomp/allocate-15.C b/gcc/testsuite/g++.dg/gomp/allocate-15.C index 605e10e477f..ef4bd098fa9 100644 --- a/gcc/testsuite/g++.dg/gomp/allocate-15.C +++ b/gcc/testsuite/g++.dg/gomp/allocate-15.C @@ -48,3 +48,45 @@ void instantiate_var_templ() dependent_var_templ(); /* { dg-message "required from here" } */ } + +/* Diagnostics for constexpr vars used in an allocate directive. */ + +void cx_var() +{ + constexpr int cx = 42; /* { dg-note "'cx' declared here" } */ + #pragma omp allocate(cx) /* { dg-error "constexpr variable 'cx' may not appear as list item in an 'allocate' directive" } */ +} + +template +void cx_var_templ_not_instantiated() +{ + constexpr int cx = 42; /* { dg-note "'cx' declared here" } */ + #pragma omp allocate(cx) /* { dg-error "constexpr variable 'cx' may not appear as list item in an 'allocate' directive" } */ +} + +template +void cx_var_templ() +{ + constexpr int cx = 42; /* { dg-note "'cx' declared here" } */ + #pragma omp allocate(cx) /* { dg-error "constexpr variable 'cx' may not appear as list item in an 'allocate' directive" } */ +} + +template +void dependent_cx_var_templ_not_instantiated() +{ + constexpr T cx = 42; /* { dg-note "'cx' declared here" } */ + #pragma omp allocate(cx) /* { dg-error "constexpr variable 'cx' may not appear as list item in an 'allocate' directive" } */ +} + +template +void dependent_cx_var_templ() +{ + constexpr T cx = 42; /* { dg-note "'cx' declared here" } */ + #pragma omp allocate(cx) /* { dg-error "constexpr variable 'cx' may not appear as list item in an 'allocate' directive" } */ +} + +void instantiate_cx_templ() +{ + cx_var_templ(); + dependent_cx_var_templ(); +} From patchwork Tue May 5 15:02:03 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Waffl3x X-Patchwork-Id: 134491 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 64C634B9DB66 for ; Tue, 5 May 2026 15:12:00 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 64C634B9DB66 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=baylibre-com.20251104.gappssmtp.com header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256 header.s=20251104 header.b=fbs7yF6j X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x434.google.com (mail-pf1-x434.google.com [IPv6:2607:f8b0:4864:20::434]) by sourceware.org (Postfix) with ESMTPS id 3AA284BA9015 for ; Tue, 5 May 2026 15:10:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 3AA284BA9015 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=baylibre.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 3AA284BA9015 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::434 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993847; cv=none; b=YCm2yas2HJHMr1qX/2ctDMbP6QwgrHLitbex6vsb2bo7p3cvO6qOhB3w3IZzgU5X7vpc2nH8TG2islspY4oKA2qxs07b3IkdfCOdNYRsKC/Oiz/yB7zfrGBz+hrkarQPNEtqAhbuR6ddptMPhU3VrzkpqFMy97S5TvVMNfRTwFY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993847; c=relaxed/simple; bh=Kna5+Cor/te1sZtXxX2oI5hB/o5BleSnr6hMy7ueeus=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Q8mNI1SebV5Iiv2/+fEXyIPhR6WNjt0JDXVxXbW8nizWNMXKAE2ptHDNr/A3qtMT86WIgYtfszZudRcRUhgB2AAJo09/UO3ly/NVVIdS3VtXBRhkWWNyZ1L5pbiya52Q3iktyph0pBRZ7FSArhMTJkprKouF4FK5K/H2d+6e6c0= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3AA284BA9015 Received: by mail-pf1-x434.google.com with SMTP id d2e1a72fcca58-824bcb2011bso402946b3a.3 for ; Tue, 05 May 2026 08:10:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20251104.gappssmtp.com; s=20251104; t=1777993846; x=1778598646; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=/7iIZJ6yg9dbw712Gkpi2hxoOh6zcaAuFSfPFhAtNzA=; b=fbs7yF6jve11Zi0tGce54JM6rzQRTIbeKEOhQGOtW84XbecI9+9De26sqZhqQqFgHf i4JxcVeRGX31gU8sI0eGyFCyB9Xxe1hAF5KnKJU1bO/H+TT8VBQDiUNmcVD6NAtRDRl/ /+r6Q2KYB+vghgss0UIEgWQF7WWFSjyZj4OtqtKGGColxALB9dZJZG+BpNNUqitsS4Mx ztra8LMSGKyRFG78ZyPLtgSDmBpKLMhEZoiUyFHIkaoNy5SIPrXD/Ny0nLHAc2AJJT+7 gQHJTxrvnVngGV2XcvBpqq5DDVCAAnU0HU/K9BaVPzZsyn3GqgWXTdvcAL95tRD1dXC8 aJaA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777993846; x=1778598646; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=/7iIZJ6yg9dbw712Gkpi2hxoOh6zcaAuFSfPFhAtNzA=; b=YMSsSok1SREPUb2Gf5Cppuby70y4VLBnqUILcR6Jqk7jlE4DE257bUdv3FAG+svHmQ rQO7ZQEt8bbxqj1BiHfpCdYuaRyR+ltQUjH8AQGsDPgr3zIFjffPZJCbJTse055peQqY aJJqza/mrBF9UMOYkSMf3UW62NJbazVO40GZRHbDTzJDVljZmiRZ2uFCTadYRGrG2Avb BYsoRx0DnVvsv1FTrCf/rrVQ413agAgWqhv08zoz73Xo7QAik0eon8neG/KAjJH/Fayc Z3Wx+dHuW/+dglkk0uDeABF+DnQRFd4wYH21fZghLtpO05bZTAChGMEUGCGQhTs7lGsf cPww== X-Gm-Message-State: AOJu0YyDCCAecD5nK3WfENaAcPke8Pxafoy/FAvUsUIZQ2UO8tpK7OLd MEYfT3WQ3pNFIC/cpaIO8ygQotIseq6gEU5AOXo1G0i691hRNrvZAYKk3hHqp7O3yKllHYtMZOK YDoyG X-Gm-Gg: AeBDies+MOQesvqhWYGRgsWXR7hhpMzB3RpmEiufIYQdO9UO9GmgI5sBSrSsrrH6IaF 9wSf0V6Uped3vxj28VoGT3Kn+Og5DxHe3D+ULJHsRkBn+41FNfyb0cC2Gg6nzEmjwQscGP7u58V /E+UVWpDsJa+B7rLbozgNRK3HnG8nlQPxvgfb+3r4gltaLmiHWM4tex2oJGuSWo3AOp4WzbzKs9 utlYztBi8dNaRrLMRJiHx+n9kZ9d6Gkwy88HF8vz6JOyWrMGW+qAvs+doEfh+mAOcfFKD3ANpYn jiZrk3fTgd0pfRcB6+VXVltSC3KGiJjkfest12W68t8gSokU3PlCX62pbM+Iu191gAr7sPJ1a5w GTag6ggbPxGv059uiq/xrxiJqCHykdZedXfuz3/RMCB9WoQBawbvujh6Idw9f9c+ts0S7tZsIbK 4b+BEQJtB9iQHu843xrEq+R6oAkmfjG+uvq4x+D86EiA3JddWsvg== X-Received: by 2002:a05:6a21:a341:b0:3a3:a6d8:cfea with SMTP id adf61e73a8af0-3a7f1d53b2bmr8007614637.8.1777993846044; Tue, 05 May 2026 08:10:46 -0700 (PDT) Received: from waffl3x-prestige.lan ([2001:56a:f98a:b800:1f67:ce08:3cbd:86b8]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83965645140sm2674956b3a.12.2026.05.05.08.10.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 08:10:45 -0700 (PDT) From: Waffl3x To: gcc-patches@gcc.gnu.org Cc: Waffl3x Subject: [PATCH 10/12] OpenMP/C++: Sorry for static vars in implicit constexpr functions Date: Tue, 5 May 2026 09:02:03 -0600 Message-ID: <20260505151030.1749548-11-waffl3x@baylibre.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505151030.1749548-1-waffl3x@baylibre.com> References: <20260505151030.1749548-1-waffl3x@baylibre.com> MIME-Version: 1.0 X-Spam-Status: No, score=-13.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org This patch disables use of static variables in an 'omp allocate' directive inside implicit constexpr functions. In such functions, the front end rushes to emit RTL for static variables via 'make_rtl_for_nonlocal_decl' prior to having even seen the allocate directive, meaning there is no clear mechanism for how to solve this. There is a lot of history to why it is done this way, but it is clear that it is not the correct mechanism, which is a known issue. Unfortunately, the required redesign is rather substantial, and outside the scope of this patchset. This issue impacts C++17 lambdas and inline functions with '-fimplicit-constexpr'. It can be kludged to work in templates, but since this would be inconsistent behavior, it's best to omit the surprises and rather just sorry, which is what we do here. gcc/cp/ChangeLog: * semantics.cc (finish_omp_allocate): Add sorry. gcc/testsuite/ChangeLog: * g++.dg/gomp/allocate-16.C: Remove xfails, check for sorry, modify cases impacted by sorry. * g++.dg/gomp/allocate-20.C: New test. * g++.dg/gomp/allocate-21.C: New test. Signed-off-by: Waffl3x --- gcc/cp/semantics.cc | 22 ++++++ gcc/testsuite/g++.dg/gomp/allocate-16.C | 55 +++++++++----- gcc/testsuite/g++.dg/gomp/allocate-20.C | 96 +++++++++++++++++++++++++ gcc/testsuite/g++.dg/gomp/allocate-21.C | 88 +++++++++++++++++++++++ 4 files changed, 243 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-20.C create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-21.C diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index 00c09e119c8..c4a0a814318 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -12432,6 +12432,28 @@ finish_omp_allocate (const location_t loc, const tree var_list, still need access to them when diagnosing the allocator clause. */ hash_set deferred_erroneous_var_nodes; + /* Due to a workaround for static local variables in implicit constexpr + functions, this case does not work properly. */ + if (any_static_vars + && DECL_DECLARES_FUNCTION_P (context) + && maybe_constexpr_fn (context)) + { + auto_diagnostic_group d; + sorry_at (loc, "static variables are not supported in an % " + "directive in an implicit constexpr function"); + emit_diag_for_var_group (tree_static_p, + &inform, + G_("static variables appear in the " + "% directive here"), + var_list); + for (tree vn = var_list; vn != NULL_TREE; vn = TREE_CHAIN (vn)) + { + if (!tree_static_p (TREE_PURPOSE (vn))) + continue; + deferred_erroneous_var_nodes.add (vn); + } + } + const auto ref_var_p = [] (const_tree t) -> bool { return TYPE_REF_P (TREE_TYPE (t)); }; if (any_of_vars (ref_var_p)) diff --git a/gcc/testsuite/g++.dg/gomp/allocate-16.C b/gcc/testsuite/g++.dg/gomp/allocate-16.C index 7258d8c1c3c..12d2d763596 100644 --- a/gcc/testsuite/g++.dg/gomp/allocate-16.C +++ b/gcc/testsuite/g++.dg/gomp/allocate-16.C @@ -1,5 +1,4 @@ /* { dg-do compile { target c++11 } } */ -/* { dg-ice "" { c++17 } } */ #include "allocate-allocator-handle.h" /* Incorrect use of lambda captures in a directive or clause. @@ -53,6 +52,8 @@ void capture_used_in_allocator_clause_static_var() /* { dg-error "the value of 'alloc' is not usable in a constant expression" "" { target *-*-* } .-1 } */ /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-2 } */ /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-3 } */ + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target c++17 } .-4 } */ + /* { dg-note "static variables appear in the 'allocate' directive here" "" { target c++17 } .-5 } */ }; } @@ -61,14 +62,16 @@ void capture_used_in_allocator_clause_static_var_templ_uninstantiated() { omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note "'omp_allocator_handle_t alloc' is not const" "" { xfail *-*-* } } */ auto cl = [alloc](){ - static int a = 42; /* { dg-note "'a' declared here" "" { xfail *-*-* } } */ + static int a = 42; /* { dg-note "'a' declared here" "" { xfail c++14_down } } */ int b = 42; /* { dg-bogus "'b' declared here" } */ - static int c = 42; /* { dg-note "'c' declared here" "" { xfail *-*-* } } */ + static int c = 42; /* { dg-note "'c' declared here" "" { xfail c++14_down } } */ int d = 42; /* { dg-bogus "'d' declared here" } */ #pragma omp allocate(a, b, c, d) allocator(alloc) /* { dg-error "the value of 'alloc' is not usable in a constant expression" "" { xfail *-*-* } .-1 } */ /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail *-*-* } .-2 } */ /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail *-*-* } .-3 } */ + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target c++17 } .-4 } */ + /* { dg-note "static variables appear in the 'allocate' directive here" "" { target c++17 } .-5 } */ }; } /* This case can't be diagnosed, there exists a T where alloc is a converted @@ -79,11 +82,17 @@ void dependent_capture_used_in_allocator_clause_static_var_templ_uninstantiated( { T alloc = omp_default_mem_alloc; /* { dg-bogus "" } */ auto cl = [alloc](){ - static int a = 42; /* { dg-bogus "'a' declared here" } */ - static int c = 42; /* { dg-bogus "'c' declared here" } */ - #pragma omp allocate(a, c) allocator(alloc) + static int a = 42; /* { dg-bogus "'a' declared here" "" { target c++14_down } } */ + /* { dg-note "'a' declared here" "" { target c++17 } .-1 } */ + int b = 42; /* { dg-bogus "'b' declared here" } */ + static int c = 42; /* { dg-bogus "'c' declared here" "" { target c++14_down } } */ + /* { dg-note "'c' declared here" "" { target c++17 } .-1 } */ + int d = 42; /* { dg-bogus "'d' declared here" } */ + #pragma omp allocate(a, b, c, d) allocator(alloc) /* { dg-bogus "the value of 'alloc' is not usable in a constant expression" "" { target *-*-* } .-1 } */ /* { dg-bogus "because one or more variables with static storage duration appear in the 'allocate' directive" "" { target *-*-* } .-2 } */ + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target c++17 } .-3 } */ + /* { dg-note "static variables appear in the 'allocate' directive here" "" { target c++17 } .-4 } */ }; } @@ -92,14 +101,16 @@ void capture_used_in_allocator_clause_static_var_templ() { omp_allocator_handle_t alloc = omp_default_mem_alloc; /* { dg-note "'omp_allocator_handle_t alloc' is not const" "" { xfail c++17 } } */ auto cl = [alloc](){ - static int a = 42; /* { dg-note "'a' declared here" "" { xfail c++17 } } */ + static int a = 42; /* { dg-note "'a' declared here" } */ int b = 42; /* { dg-bogus "'b' declared here" } */ - static int c = 42; /* { dg-note "'c' declared here" "" { xfail c++17 } } */ + static int c = 42; /* { dg-note "'c' declared here" } */ int d = 42; /* { dg-bogus "'d' declared here" } */ #pragma omp allocate(a, b, c, d) allocator(alloc) /* { dg-error "the value of 'alloc' is not usable in a constant expression" "" { xfail c++17 } .-1 }*/ /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail c++17 } .-2 } */ /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail c++17 } .-3 } */ + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target c++17 } .-4 } */ + /* { dg-note "static variables appear in the 'allocate' directive here" "" { target c++17 } .-5 } */ }; } @@ -108,14 +119,16 @@ void dependent_capture_used_in_allocator_clause_static_var_templ() { T alloc = omp_default_mem_alloc; /* { dg-note "'omp_allocator_handle_t alloc' is not const" "" { xfail c++17 } } */ auto cl = [alloc](){ - static int a = 42; /* { dg-note "'a' declared here" "" { xfail c++17 } } */ + static int a = 42; /* { dg-note "'a' declared here" } */ int b = 42; /* { dg-bogus "'b' declared here" } */ - static int c = 42; /* { dg-note "'c' declared here" "" { xfail c++17 } } */ + static int c = 42; /* { dg-note "'c' declared here" } */ int d = 42; /* { dg-bogus "'d' declared here" } */ #pragma omp allocate(a, b, c, d) allocator(alloc) /* { dg-error "the value of 'alloc' is not usable in a constant expression" "" { xfail c++17 } .-1 } */ /* { dg-error "'allocator' clause requires a constant predefined allocator" "" { xfail c++17 } .-2 } */ /* { dg-note "because one or more variables with static storage duration appear in the 'allocate' directive" "" { xfail c++17 } .-3 } */ + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target c++17 } .-4 } */ + /* { dg-note "static variables appear in the 'allocate' directive here" "" { target c++17 } .-5 } */ }; } @@ -124,11 +137,17 @@ void dependent_capture_used_in_allocator_clause_static_var_templ_valid() { T alloc = omp_default_mem_alloc; /* { dg-bogus "" } */ auto cl = [alloc](){ - static int a = 42; /* { dg-bogus "" } */ - static int c = 42; /* { dg-bogus "" } */ + static int a = 42; /* { dg-bogus "'a' declared here" "" { target c++14_down } } */ + /* { dg-note "'a' declared here" "" { target c++17 } .-1 } */ + int b = 42; /* { dg-bogus "'b' declared here" } */ + static int c = 42; /* { dg-bogus "'c' declared here" "" { target c++14_down } } */ + /* { dg-note "'c' declared here" "" { target c++17 } .-1 } */ + int d = 42; /* { dg-bogus "'d' declared here" } */ #pragma omp allocate(a, c) allocator(alloc) /* { dg-bogus "the value of 'alloc' is not usable in a constant expression" "" { target *-*-* } .-1 } */ /* { dg-bogus "'allocator' clause requires a constant predefined allocator" "" { target *-*-* } .-2 } */ + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target c++17 } .-3 } */ + /* { dg-note "static variables appear in the 'allocate' directive here" "" { target c++17 } .-4 } */ }; } @@ -187,24 +206,24 @@ void dependent_capture_used_in_align_clause_templ_uninstantiated() template void capture_used_in_align_clause_templ() { - int align = 32; /* { dg-note "'int align' is not const" "" { xfail c++17 } } */ + int align = 32; /* { dg-note "'int align' is not const" } */ auto cl = [align](){ int a; #pragma omp allocate(a) align(align) - /* { dg-error "the value of 'align' is not usable in a constant expression" "" { target *-*-* xfail c++17 } .-1 } */ - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* xfail c++17 } .-2 } */ + /* { dg-error "the value of 'align' is not usable in a constant expression" "" { target *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-2 } */ }; } template void dependent_capture_used_in_align_clause_templ() { - T align = 32; /* { dg-note "'int align' is not const" "" { xfail c++17 } } */ + T align = 32; /* { dg-note "'int align' is not const" } */ auto cl = [align](){ int a; #pragma omp allocate(a) align(align) - /* { dg-error "the value of 'align' is not usable in a constant expression" "" { target *-*-* xfail c++17 } .-1 } */ - /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* xfail c++17 } .-2 } */ + /* { dg-error "the value of 'align' is not usable in a constant expression" "" { target *-*-* } .-1 } */ + /* { dg-error "'align' clause argument needs to be positive constant power of two integer expression" "" { target *-*-* } .-2 } */ }; } diff --git a/gcc/testsuite/g++.dg/gomp/allocate-20.C b/gcc/testsuite/g++.dg/gomp/allocate-20.C new file mode 100644 index 00000000000..d7eccf012fb --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-20.C @@ -0,0 +1,96 @@ +/* { dg-do compile { target c++11 } } */ +#include "allocate-allocator-handle.h" + +/* Diagnose static variables used in an OpenMP allocate directive in functions + that are implicitly constexpr. + Otherwise, check that static variables have a correct alignment applied to + them. + + This test case is valid in c++11 but the bug we are testing for does not + manifest until c++17, which makes lambdas implicit constexpr functions. + + For now, we simply do not support these cases. */ + + +/* Making a regex for demangled identifiers is actually way harder than making + a regex for mangled ones, too many escapes are needed. */ + +/* { dg-final { scan-assembler "\.align 256\\s*\.type\\s*_ZZZ6f0_256vENKUlvE_clEvE1a" { target c++14_down } } } */ +int* f0_256() +{ + auto cl = [](){ + static int a = 42; + #pragma omp allocate(a) align(256) allocator(omp_default_mem_alloc) + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target c++17 } .-1 } */ + return &a; + }; + return cl(); +} +/* { dg-final { scan-assembler "\.align 512\\s*\.type\\s*_ZZZ6f0_512vENKUlvE_clEvE1a" { target c++14_down } } } */ +int* f0_512() +{ + auto cl = [](){ + static int a = 42; + #pragma omp allocate(a) align(512) allocator(omp_default_mem_alloc) + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target c++17 } .-1 } */ + return &a; + }; + return cl(); +} +/* { dg-final { scan-assembler "\.align 1024\\s*\.type\\s*_ZZZ7f0_1024vENKUlvE_clEvE1a" { target c++14_down } } } */ +int* f0_1024() +{ + auto cl = [](){ + static int a = 42; + #pragma omp allocate(a) align(1024) allocator(omp_default_mem_alloc) + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target c++17 } .-1 } */ + return &a; + }; + return cl(); +} + +/* { dg-final { scan-assembler "\.align 256\\s*\.type\\s*_ZZZ6f1_256IvEPivENKUlvE_clEvE1a" { target c++14_down } } } */ +template +int* f1_256() +{ + auto cl = [](){ + static int a = 42; + #pragma omp allocate(a) align(256) allocator(omp_default_mem_alloc) + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target c++17 } .-1 } */ + return &a; + }; + return cl(); +} +template int* f1_256(); + +/* { dg-final { scan-assembler "\.align 512\\s*\.type\\s*_ZZZ6f1_512IvEPivENKUlvE_clEvE1a" { target c++14_down } } } */ +template +int* f1_512() +{ + auto cl = [](){ + static int a = 42; + #pragma omp allocate(a) align(512) allocator(omp_default_mem_alloc) + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target c++17 } .-1 } */ + return &a; + }; + return cl(); +} +template int* f1_512(); + +/* { dg-final { scan-assembler "\.align 1024\\s*\.type\\s*_ZZZ7f1_1024IvEPivENKUlvE_clEvE1a" { target c++14_down } } } */ +template +int* f1_1024() +{ + auto cl = [](){ + static int a = 42; + #pragma omp allocate(a) align(1024) allocator(omp_default_mem_alloc) + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target c++17 } .-1 } */ + return &a; + }; + return cl(); +} +template int* f1_1024(); + +/* Missing cases for generic lambda, and generic lambda in function template. + They shouldn't behave differently, but for completeness they should be + added, I'm just not going to spend any more time on this right now. */ diff --git a/gcc/testsuite/g++.dg/gomp/allocate-21.C b/gcc/testsuite/g++.dg/gomp/allocate-21.C new file mode 100644 index 00000000000..7a638443f32 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-21.C @@ -0,0 +1,88 @@ +/* { dg-do compile { target c++14 } } */ +/* { dg-additional-options "-fimplicit-constexpr" } */ +#include "allocate-allocator-handle.h" + +/* Diagnose static variables used in an OpenMP allocate directive in functions + that are implicitly constexpr. + Inline functions and function templates with -fimplicit-constexpr. + + For now, we simply do not support these cases. + + The dg-final cases are never checked, they are kept here for demonstrating + intent and so they can be switched back on if these cases are fixed. */ + +/* Making a regex for demangled identifiers is actually way harder than making + a regex for mangled ones, too many escapes are needed. + + We need to ODR-use the regular functions to force them to be emitted. */ + +/* { dg-final { scan-assembler "\.align 256\\s*\.type\\s*_ZZ6f0_256vE1a" { target { ! *-*-* } } } } */ +inline int* f0_256() +{ + static int a = 42; /* { dg-note "'a' declared here" } */ + #pragma omp allocate(a) align(256) allocator(omp_default_mem_alloc) + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target *-*-* } .-1 } */ + /* { dg-note "static variables appear in the 'allocate' directive here" "" { target *-*-* } .-2 } */ + return &a; +} +constexpr int*(*odr_use_f0_256)() = &f0_256; + +/* { dg-final { scan-assembler "\.align 512\\s*\.type\\s*_ZZ6f0_512vE1a" { target { ! *-*-* } } } } */ +inline int* f0_512() +{ + static int a = 42; /* { dg-note "'a' declared here" } */ + #pragma omp allocate(a) align(512) allocator(omp_default_mem_alloc) + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target *-*-* } .-1 } */ + /* { dg-note "static variables appear in the 'allocate' directive here" "" { target *-*-* } .-2 } */ + return &a; +} +constexpr int*(*odr_use_f0_512)() = &f0_512; + +/* { dg-final { scan-assembler "\.align 1024\\s*\.type\\s*_ZZ7f0_1024vE1a" { target { ! *-*-* } } } } */ +inline int* f0_1024() +{ + static int a = 42; /* { dg-note "'a' declared here" } */ + #pragma omp allocate(a) align(1024) allocator(omp_default_mem_alloc) + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target *-*-* } .-1 } */ + /* { dg-note "static variables appear in the 'allocate' directive here" "" { target *-*-* } .-2 } */ + return &a; +} +constexpr int*(*odr_use_f0_1024)() = &f0_1024; + + + +/* { dg-final { scan-assembler "\.align 256\\s*\.type\\s*_ZZ6f1_256IvEPivE1a" { target { ! *-*-* } } } } */ +template +inline int* f1_256() +{ + static int a = 42; /* { dg-note "'a' declared here" } */ + #pragma omp allocate(a) align(256) allocator(omp_default_mem_alloc) + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target *-*-* } .-1 } */ + /* { dg-note "static variables appear in the 'allocate' directive here" "" { target *-*-* } .-2 } */ + return &a; +} +template int* f1_256(); + +/* { dg-final { scan-assembler "\.align 512\\s*\.type\\s*_ZZ6f1_512IvEPivE1a" { target { ! *-*-* } } } } */ +template +inline int* f1_512() +{ + static int a = 42; /* { dg-note "'a' declared here" } */ + #pragma omp allocate(a) align(512) allocator(omp_default_mem_alloc) + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target *-*-* } .-1 } */ + /* { dg-note "static variables appear in the 'allocate' directive here" "" { target *-*-* } .-2 } */ + return &a; +} +template int* f1_512(); + +/* { dg-final { scan-assembler "\.align 1024\\s*\.type\\s*_ZZ7f1_1024IvEPivE1a" { target { ! *-*-* } } } } */ +template +inline int* f1_1024() +{ + static int a = 42; /* { dg-note "'a' declared here" } */ + #pragma omp allocate(a) align(1024) allocator(omp_default_mem_alloc) + /* { dg-message "static variables are not supported in an 'allocate' directive in an implicit constexpr function" "" { target *-*-* } .-1 } */ + /* { dg-note "static variables appear in the 'allocate' directive here" "" { target *-*-* } .-2 } */ + return &a; +} +template int* f1_1024(); From patchwork Tue May 5 15:02:04 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Waffl3x X-Patchwork-Id: 134494 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 688884BA23DC for ; Tue, 5 May 2026 15:13:36 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 688884BA23DC Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=baylibre-com.20251104.gappssmtp.com header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256 header.s=20251104 header.b=g3oFmBcN X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pj1-x1034.google.com (mail-pj1-x1034.google.com [IPv6:2607:f8b0:4864:20::1034]) by sourceware.org (Postfix) with ESMTPS id 2F2904BA9001 for ; Tue, 5 May 2026 15:10:48 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2F2904BA9001 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=baylibre.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2F2904BA9001 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::1034 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993848; cv=none; b=JxiGn44wZXYHTC++pFc7rtxH5kgp45bKJoIfQnfgHbTr7fcNtzZ3/a8Xrkw+VEUN0oWo/mMF7rvcDMsFCum9+gSgJ3a6NiLXWGbeKHcuBlFhRhz3XFnKHLvkVvEEQWelwEGMIr0WNe6XMQ9k9FCoX2kvTm8Mo52FrJRFQ502Ha8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993848; c=relaxed/simple; bh=Fu5hue4nOoQbN38kOhw55qpW7vheHt6HsPPpJz304sk=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=h13/qv1SwqBV2nx7ydouSJrhQwewCkMruiwd38KIGHWm4aERCuGhpfFGUxImNBfvGMcU8nXDeGoqeFJvgXoFoV7sgQg3k9zQz2lp6GJ7a0DHlkBII3AHIcPcKlcolcIeydqv8HrgFKkgOWU7x9ef4AS8HAAkJbbSpm5jnbSsj8E= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2F2904BA9001 Received: by mail-pj1-x1034.google.com with SMTP id 98e67ed59e1d1-3650cb6e128so552812a91.2 for ; Tue, 05 May 2026 08:10:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20251104.gappssmtp.com; s=20251104; t=1777993847; x=1778598647; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=L7m2/TU2/q2BwY/38b5RA6XgvH3l/1DDKi+ky8SR6oc=; b=g3oFmBcNQUkch4guf24TTyV8SNSuJpZD1joKGvYqlAci2WFG45ei9+9N1cOYW2ueAo z/KPYGSMToijOYQ07hje9RKx612kzvmSBKnSDu8d6Qak5+Et5NqipvuTm2StrrXsk1oZ OR6MihOvt6d/Bf0roib4ceOW02TEtjKicjIc/LIowBk7pmsGCVtYjrc282Rl6KjTNaFA XSGbbwlUnj2gSOY8Zwuipt6/68rWsyMSp2MR5msqCnU3/pGsrA4Me2vyVZ0Il/Eadykk HFqrAfVujOTd05TM4NLOsWbSTfDgCZKi0ZGNDDLCkYhN9X0Czh4Ffh6POKh1WwUtb95J 6caw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777993847; x=1778598647; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=L7m2/TU2/q2BwY/38b5RA6XgvH3l/1DDKi+ky8SR6oc=; b=JIKh+U7SVKp7gc/KqGVrsUIjy0XvDn8mv/618sPUz2Jvm76ZTQyb5U5kxMm8L5bHNx wVdei8/aqAATBfQ4UJUy5XkbMbNt8oDmdUt6hFdtBnIno/Zc5rVaJfNMuMrLVRE63JvE IpDOMmev1j+hEZg5FtHEkAYRf5DV4NIFrIUU4V2uEFL7xudgzLvC3pk+DlhoIHqyBfP8 ZfqkDJVRsB59b6+h1mRlYagDroxsSAopBZPy5UWaBUENkkLTDz9GznRUQDALOiWJlXja Jxfm8y5UBHbL6DcOjAZl6P5gmjqBRGOoVqy/ebsaME9Bh1zYlKufAGC/v80aKXEEtFoM PYbA== X-Gm-Message-State: AOJu0YyrVInyKX/ZgsMT9EfVTiz5IbTnPyeyGhUJKEF1Y7Q+e0zjIOxA BIk737Qg9VJugN2Y4Nsq/vIb18hYm99Vml6yCnSisw+bikH0O/Swjqy+1IYsDy14sQWZ7+WXXex 4gU+R X-Gm-Gg: AeBDietekhGG0fuMzWHdROfLrOBsT81Fmw7sk8co3M8/TNjb3djbXe37JseTwT3QxSQ wmbURWMcfsbzEbkC0GL0aDl2WtqiX9lnoPh0UsM1OKUQguAaaQqzNOofFB7eFlC0ZuGWbGKR8x1 s8GLbLL+6qWfz9PpIY3i/n6s/akdUurGivpqVijujpPvMDgZ/ld+FpeU6iIAyL10ZnGt0mNtm3s //FgS+oHcDhnV5aVFbGyk61Z6jEpodzRpcvNGVW/1eD0of26zqRLBv8U90fFriiasvP8B/vNBvu kn95CfI1ucfL0DigTU81vhdhn7IJo78K+wIzEvdxcE7TFNe37UOE2ZcRTXHTPXIkLYJiJ2jQz7Z OckBFNDXB0zUcye1plJ72t00YSP4wxngEInFMyguVGPNk8oIJc1VHJ3jvsJ7XzQm00vw3R5ucOg +SD6u8Bjp6OcL1Up7XlczIvnHHnMUARxnGOgybRoeYnlIkNze8xA== X-Received: by 2002:a05:6a21:6b87:b0:3a1:6a7c:dba5 with SMTP id adf61e73a8af0-3aa3e9862e3mr1874635637.6.1777993847045; Tue, 05 May 2026 08:10:47 -0700 (PDT) Received: from waffl3x-prestige.lan ([2001:56a:f98a:b800:1f67:ce08:3cbd:86b8]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83965645140sm2674956b3a.12.2026.05.05.08.10.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 08:10:46 -0700 (PDT) From: Waffl3x To: gcc-patches@gcc.gnu.org Cc: Waffl3x Subject: [PATCH 11/12] OpenMP/C++: Sorry for allocate directive in omp::decl attribute Date: Tue, 5 May 2026 09:02:04 -0600 Message-ID: <20260505151030.1749548-12-waffl3x@baylibre.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505151030.1749548-1-waffl3x@baylibre.com> References: <20260505151030.1749548-1-waffl3x@baylibre.com> MIME-Version: 1.0 X-Spam-Status: No, score=-13.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org At least one of the diagnostics in cp_parser_omp_allocate expects each decl to have been pushed into the current binding level. Due to when attributes are parsed this assumption does not hold for an allocate directive specified in an omp::decl attribute. The broken diagnostic checks that the vars listed in an allocate directive are in the same scope as the directive. Obviously we can assume that is the case when using omp::decl, but it is not obvious how to detect that we in an omp::decl in a robust way so this case is simply not supported for now. This patch also adds a check for TREE_PUBLIC in cp_maybe_parse_omp_decl. During investigation of this issue it was noticed that TREE_PUBLIC denotes an omp::decl attribute as opposed to an omp::directive attribute, thus it is also a precondition in that function. gcc/cp/ChangeLog: * parser.cc (cp_maybe_parse_omp_decl): Sorry for allocate directive. libgomp/ChangeLog: * testsuite/libgomp.c-c++-common/allocate-7.c: Disable for C++. gcc/testsuite/ChangeLog: * g++.dg/gomp/omp-constexpr.C: Add sorry for allocate directive. * g++.dg/gomp/allocate-24.C: New test. Signed-off-by: Waffl3x --- gcc/cp/parser.cc | 10 ++++++- gcc/testsuite/g++.dg/gomp/allocate-24.C | 26 +++++++++++++++++++ gcc/testsuite/g++.dg/gomp/omp-constexpr.C | 3 ++- .../libgomp.c-c++-common/allocate-7.c | 5 +++- 4 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gomp/allocate-24.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 791ac2d6ea9..fe628be065c 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -54410,7 +54410,8 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs, bool cp_maybe_parse_omp_decl (tree decl, tree d) { - gcc_assert (TREE_CODE (d) == DEFERRED_PARSE); + gcc_assert (TREE_CODE (d) == DEFERRED_PARSE + && TREE_PUBLIC (d)); cp_token *first = DEFPARSE_TOKENS (d)->first; cp_token *last = DEFPARSE_TOKENS (d)->last; const char *directive[3] = {}; @@ -54448,6 +54449,13 @@ cp_maybe_parse_omp_decl (tree decl, tree d) if (!flag_openmp && !dir->simd) return true; + if (dir->id == PRAGMA_OMP_ALLOCATE) + { + sorry_at (first->location, + "allocate directive not supported in %"); + return true; + } + cp_parser *parser = the_parser; cp_lexer *lexer = cp_lexer_alloc (); lexer->debugging_p = parser->lexer->debugging_p; diff --git a/gcc/testsuite/g++.dg/gomp/allocate-24.C b/gcc/testsuite/g++.dg/gomp/allocate-24.C new file mode 100644 index 00000000000..114231c8a54 --- /dev/null +++ b/gcc/testsuite/g++.dg/gomp/allocate-24.C @@ -0,0 +1,26 @@ +/* { dg-do compile { target c++11 } } */ + +#include "allocate-allocator-handle.h" + +/* TODO: Add scan-tree-dump checks once support for omp::decl is added. */ + +int AAA [[omp::decl(allocate,allocator(omp_low_lat_mem_alloc),align(4096))]]; +/* { dg-message "allocate directive not supported in 'omp::decl'" "" { target *-*-* } .-1 } */ + +static_assert (alignof(AAA) == alignof(int), "wrong alignment"); + +void f () +{ + /* This applies to A1 and B1. + (C++23 N4950 ยง9.1.3, sentence 5) + The attribute-specifier-seq appertains to each of the entities declared by + the declarators of the init-declarator-list. */ + [[omp::decl(allocate, align(4096))]] int A1[5], B1; + /* { dg-message "allocate directive not supported in 'omp::decl'" "" { target *-*-* } .-1 } */ + + static_assert (alignof(A1) == alignof(int[5]), "wrong alignment"); + static_assert (alignof(B1) == alignof(int), "wrong alignment"); + + static int BBB [[omp::decl(allocate,allocator(omp_low_lat_mem_alloc),align(4096))]]; + /* { dg-message "allocate directive not supported in 'omp::decl'" "" { target *-*-* } .-1 } */ +} diff --git a/gcc/testsuite/g++.dg/gomp/omp-constexpr.C b/gcc/testsuite/g++.dg/gomp/omp-constexpr.C index 0d984d8609b..85b1157201c 100644 --- a/gcc/testsuite/g++.dg/gomp/omp-constexpr.C +++ b/gcc/testsuite/g++.dg/gomp/omp-constexpr.C @@ -31,7 +31,8 @@ h () constexpr int i () { - int a [[omp::decl(allocate, align(128))]] = 42; /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" } */ + int a [[omp::decl(allocate, align(128))]] = 42; /* { dg-error "OpenMP directives may not appear in 'constexpr' functions" "" { xfail *-*-* } } */ + /* { dg-message "allocate directive not supported in 'omp::decl'" "" { target *-*-* } .-1 } */ return a; } // { dg-error "not a return-statement" "" { target c++11_down } } diff --git a/libgomp/testsuite/libgomp.c-c++-common/allocate-7.c b/libgomp/testsuite/libgomp.c-c++-common/allocate-7.c index 9968eb19005..8d5429b0eb3 100644 --- a/libgomp/testsuite/libgomp.c-c++-common/allocate-7.c +++ b/libgomp/testsuite/libgomp.c-c++-common/allocate-7.c @@ -1,9 +1,12 @@ -/* { dg-do run } */ +/* { dg-do run { target c } } */ + +/* In C++, omp allocate in an omp::decl attribute is not currently supported. */ #include int AAA [[omp::decl(allocate,allocator(omp_low_lat_mem_alloc),align(4096))]]; + #ifndef __cplusplus _Static_assert (_Alignof(AAA) == _Alignof(int), "wrong alignment"); #elif __cplusplus >= 201103L From patchwork Tue May 5 15:02:05 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Waffl3x X-Patchwork-Id: 134499 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id 227AD4BA9038 for ; Tue, 5 May 2026 15:17:15 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 227AD4BA9038 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=baylibre-com.20251104.gappssmtp.com header.i=@baylibre-com.20251104.gappssmtp.com header.a=rsa-sha256 header.s=20251104 header.b=f5M2Fzym X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-pf1-x432.google.com (mail-pf1-x432.google.com [IPv6:2607:f8b0:4864:20::432]) by sourceware.org (Postfix) with ESMTPS id 10FD84BA9034 for ; Tue, 5 May 2026 15:10:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 10FD84BA9034 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=baylibre.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=baylibre.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 10FD84BA9034 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::432 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993849; cv=none; b=Az1WOwvIUHOkQ+GHZoZ81Oo7nIwcV/gA7PuIV79HepX99JxRd1UWpQ7NyI+rmYjbtjsKB/rJ8QNZVw2zDR26bEB+GaWeUq1MeBbRFR5/n8RWN7L4pqYBO59Ij7Z3q8DYseMVeS6+fqK5wYuGXXOH+IjRUoIVVuE/19BmNQ5o75E= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1777993849; c=relaxed/simple; bh=cayDpVIMfIzVOLaAPcYBk3NwL7vxsX3nXeq6HfDg7vk=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=pRgh/zNdsNEnB5TwPYLMm91KMNdoWYz7av6RuaqtTF/7C7zIIRO2QszOms4za1trOKZEAiJGNfMwklNZyTKw9ynJ0hE6mIebYr/5a8GN2hjpIPEfOP84uyMr2Rrz0pMwTz7D84L9rO0kk6eoSkugsDXO2uiRUCNkKwgyYihl+ik= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 10FD84BA9034 Received: by mail-pf1-x432.google.com with SMTP id d2e1a72fcca58-826dab01bbdso200994b3a.0 for ; Tue, 05 May 2026 08:10:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20251104.gappssmtp.com; s=20251104; t=1777993848; x=1778598648; darn=gcc.gnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=17twbgtCGIUEk1yX1pJPUHPRSkOOgtZcPpiMPKK7G24=; b=f5M2FzymZ3kFUH5TnpwOcjJE+hJXLd4+cIsghDT77t/KlFcMcTFpvmkc0vlqhAlg/y Sx59mb7vE7MDkI8GaDL9Tu0VJZA9UvxVtoAU5ZC/Ighz6g9oOso3a/S7gOVvtV2Yudad VD/vEO46yGNuYzqa8DOBOkdAc6qL4Le/h7K0o/0RPUBpGL9BIRxZekJtuRpExwKYlz6r XAVJ10IMQuFFUKmPcKe0NaGGC6/H6BMYiyPFDCe3CNHZL6BNa4qleK/rPNIoI54Sc7nZ /FwDBaXcWCYwrIS73czz9GnO4QvYwiY1LCqaT6SLiz/yoD/PHahVWJ75KsuC73C1OXuy 0I2A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777993848; x=1778598648; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=17twbgtCGIUEk1yX1pJPUHPRSkOOgtZcPpiMPKK7G24=; b=T+snWWgymVNjkyIqKjQBBA089+flDbN5Zcul8skjQ+NSibrr0Yu7DjK0QZlxzS1AHU mK/9VDty4ijUrw1fPFj5nk47Xm1FnCDjdBI9Cb3S6yl7l2keVY3Vhj2WRkg1AZq9Yzmo 4N5ey0Zpyxe8RJv5bikKue/mFF+ApSV3ZjQn/K1M+gcvewXbWvOUfdQZkUpU9iF5ZhEA nlasxUiEPKunfJrgJ0fL4gVsXbh+lRWhcTzcxTc0IyQWYjCeY7zuqGuZouZHfcfLeHwC WM09ZGbSZkw6kgu5Djyc+5AmREvoLn2+fLPSsWuFZ0+KMa34nEy1R3lrQX2sHoFU/QZl pZIQ== X-Gm-Message-State: AOJu0YwA0N+s7MKrnFdW2MYIfq2YoiWcWMCqC3Sy7ZhXsyttNYl5Xzka eErfaCFiQFVi+aBjvRguUwlb7nLhuJ2FKCgYAOI6ZLe2qUWkd3sFdwUnKCBmoEaB7JCtw8TxW/O Zva69 X-Gm-Gg: AeBDievIirSQ6POaT+mVh/kyj7PWs59E66HeF6J+ge6xvWbL0asrP+Yj5ZfVSJEa5xg d7Y+sEh3Ib6ppbY6l0T8et81hpi1gHbrdPn4Nba33hJ7GhvnGBlX7e1HBeGe8Kld6h/YKlPYfuK 9E9B9t0ZObyjrRATixSDW57g7gAtTgNQ2pki2wjrshkwDVCErlsnuU1ShJ0GxRfwg6mDvccQ74O lod32JiUWbVANgNmO2G71e02jv4t7JgggVwB1pwjLjJtexi8lFHTcOKS72GTbkh2iWnVDCNa2dW 1anR15eLTzmus2bLaRYQEWqF4n9nZiKS6q1QThTqX0hj6bjp3G4vV6WgXTs1uTphHaD/Cqun1AQ L/jUvV4804wf+kye5go4xUCl5savNBgIb2rasV/V7CLM3W0e00TjsOWMVgxhxOFRN03H0G5AFUG dOY1XVmDVJTXGU8xoQsGichMLQtMv/Ob0OX14qrgRZkcYM4e30dw== X-Received: by 2002:a05:6a00:1f17:b0:82d:1faf:775f with SMTP id d2e1a72fcca58-8393e36240bmr1520875b3a.5.1777993847936; Tue, 05 May 2026 08:10:47 -0700 (PDT) Received: from waffl3x-prestige.lan ([2001:56a:f98a:b800:1f67:ce08:3cbd:86b8]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-83965645140sm2674956b3a.12.2026.05.05.08.10.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 05 May 2026 08:10:47 -0700 (PDT) From: Waffl3x To: gcc-patches@gcc.gnu.org Cc: Waffl3x Subject: [PATCH 12/12] OpenMP/C++: Avoid quadratic complexity in diagnostic Date: Tue, 5 May 2026 09:02:05 -0600 Message-ID: <20260505151030.1749548-13-waffl3x@baylibre.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260505151030.1749548-1-waffl3x@baylibre.com> References: <20260505151030.1749548-1-waffl3x@baylibre.com> MIME-Version: 1.0 X-Spam-Status: No, score=-13.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org The previous implementation of var_is_in_scope unfortunately did not avoid quadratic complexity. This implementation utilizes procedural caching to avoid that while also avoiding traversing the entire list of block vars in the current binding level. gcc/cp/ChangeLog: * parser.cc (cp_parser_omp_allocate): Change var_is_in_scope. Signed-off-by: Waffl3x --- gcc/cp/parser.cc | 54 +++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index fe628be065c..4f30b83666c 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -47195,25 +47195,41 @@ cp_parser_omp_allocate (cp_parser *parser, cp_token *pragma_tok) what ultimately gets passed along to finish_omp_allocate. */ hash_map arg_map; { - auto var_is_in_scope = [&] (tree var_decl) - { - /* (OpenMP 6.0 311:11-12) An allocate directive must appear in the same - scope as the declarations of each of its list items and must follow - all such declarations. - - Note that it states declarations, not definitions, thus we can rely - on VAR_DECL's CP_DECL_CONTEXT. This will correctly reject an - allocate directive applied to a definition in a different scope. */ - if (!DECL_DECLARES_FUNCTION_P (directive_ctx)) - return CP_DECL_CONTEXT (var_decl) == directive_ctx; - /* This is O(n^2), caching names during traversal might be better. */ - for (tree block_var = current_binding_level->names; - block_var != NULL_TREE; - block_var = DECL_CHAIN (block_var)) - if (block_var == var_decl) - return true; - return false; - }; + /* To avoid quadratic complexity in the block scope case we need to keep + some state. Our hash_set utility has a lazy option, but it sucks so + we'll just bite the allocation unconditionally. */ + auto var_is_in_scope + = [&, vars_in_scope = hash_set(), + block_var = current_binding_level->names] (tree var_decl) mutable + { + /* (OpenMP 6.0 311:11-12) An allocate directive must appear in the + same scope as the declarations of each of its list items and + must follow all such declarations. + + Note that it states declarations, not definitions, well-formed + uses of this directive will always be in the same scope as the + DECL_CONTEXT of VAR_DECL. */ + if (!DECL_DECLARES_FUNCTION_P (directive_ctx)) + return CP_DECL_CONTEXT (var_decl) == directive_ctx; + /* We can't rely on this for block scope though and must traverse + the decls in this scope instead. + As noted above, to avoid quadratic complexity we keep state + across multiple calls, caching as we go to avoid going through + all names in this scope up front. */ + if (vars_in_scope.contains (var_decl)) + return true; + /* We initialize block_var in the captures. */ + for (; block_var != NULL_TREE; block_var = DECL_CHAIN (block_var)) + { + /* Matches don't have to be cached, duplicate var_decl args are + diagnosed before scope is diagnosed. */ + if (block_var == var_decl) + return true; + else if (VAR_P (block_var)) + vars_in_scope.add (block_var); + } + return false; + }; hash_map seen_args; /* The head might have an error and need to be removed. */ tree *chain = &nl;