From patchwork Wed Jul 3 14:37:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1956293 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=ZaxfrBto; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WDj6n3jlRz1xqm for ; Thu, 4 Jul 2024 00:37:37 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 74701386187F for ; Wed, 3 Jul 2024 14:37:35 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 80DD73860C37 for ; Wed, 3 Jul 2024 14:37:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 80DD73860C37 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 80DD73860C37 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720017435; cv=none; b=KoOhjSvFRebtRCr6SNlUiiXjuKSMSmtQj8pSVAQkv4hNRLMLk+uYwuXKvOvavb2G8Ry/8bLZevvmu7DIWPa7GpquWhe/KEZokms7AFFiFJN7kGfBPgKGyKUf+io28TaSi4aHnMGpP7Lk1SxCgV8tQpiDE8QdzYoT8HpzNoM1/w8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720017435; c=relaxed/simple; bh=+X2uvBVDq6TkAAtM70V2kQFy2HB2LTGSbyrthdWD21w=; h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version; b=x4xnapIn0EHYSoM/Ssf7mSRZdUjcKqUc/AWPjj15Z6AT+LUWeW+grfED9BlovdythUb5bMVNZU4uC/wVYbmJZvQLTdjNzMbb1AIZWxou91CV4817d3eTt4VnMxLH0EfMxZdccscifC+5aJX1vOIfn2yET+dtgJUQKJXKUwLXLJc= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1720017431; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type; bh=vDJdaNrhsKG8ykz4Xw+QJ6B2tns+798K0WMt2NXTdfA=; b=ZaxfrBtoxSOFnXgBz9MZJNK1oJKrgG/cuhEhtBMZJ6OOqjX3qLGolc6PwZgfb4VfFNjteO 9YVjcKLQAtZaZNpN6iPmdhmN/Sr2AdDiaHm+1yadeysygzA64YFYoejRczRcxUTO8CN0Vf l1WTXn7/1Q2vtTbYHwYOt+hruYnvgD4= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-688-RhZsUNA3OOyYb_xCioPvwA-1; Wed, 03 Jul 2024 10:37:08 -0400 X-MC-Unique: RhZsUNA3OOyYb_xCioPvwA-1 Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 0928D1955BC9; Wed, 3 Jul 2024 14:37:07 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.45.224.5]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 85789195607C; Wed, 3 Jul 2024 14:37:04 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.17.1/8.17.1) with ESMTPS id 463Eb17s3666103 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Wed, 3 Jul 2024 16:37:01 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.17.1/8.17.1/Submit) id 463Eb0353666102; Wed, 3 Jul 2024 16:37:00 +0200 Date: Wed, 3 Jul 2024 16:37:00 +0200 From: Jakub Jelinek To: Jason Merrill , Jonathan Wakely Cc: gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org Subject: [PATCH] c++, libstdc++: Implement C++26 P2747R2 - constexpr placement new [PR115744] Message-ID: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Disposition: inline X-Spam-Status: No, score=-3.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.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: , Reply-To: Jakub Jelinek Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Hi! With the PR115754 fix in, constexpr placement new mostly just works, so this patch just adds constexpr keyword to the placement new operators in , adds FTMs and testsuite coverage. There is one accepts-invalid though, the new (p + 1) int[]{2, 3}; // error (in this paper) case from the paper. Can we handle that incrementally? The problem with that is I think calling operator new now that it is constexpr should be fine even in that case in constant expressions, so int *p = std::allocator{}.allocate(3); int *q = operator new[] (sizeof (int) * 2, p + 1); should be ok, so it can't be easily the placement new operator call itself on whose constexpr evaluation we try something special, it should be on the new expression, but constexpr.cc actually sees only <<< Unknown tree: expr_stmt (void) (TARGET_EXPR (b) + 4>>, TARGET_EXPR )>, int * D.2643; <<< Unknown tree: expr_stmt (void) (D.2643 = (int *) D.2642) >>>; and that is just fine by the preexisting constexpr evaluation rules. Should build_new_1 emit some extra cast for the array cases with placement new in maybe_constexpr_fn (current_function_decl) that the existing P2738 code would catch? Anyway, bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2024-07-03 Jakub Jelinek PR c++/115744 gcc/c-family/ * c-cppbuiltin.cc (c_cpp_builtins): Change __cpp_constexpr from 202306L to 202406L for C++26. gcc/testsuite/ * g++.dg/cpp2a/construct_at.h (operator new, operator new[]): Use constexpr instead of inline if __cpp_constexpr >= 202406L. * g++.dg/cpp26/constexpr-new1.C: New test. * g++.dg/cpp26/constexpr-new2.C: New test. * g++.dg/cpp26/constexpr-new3.C: New test. * g++.dg/cpp26/feat-cxx26.C (__cpp_constexpr): Adjust expected value. libstdc++-v3/ * libsupc++/new (__glibcxx_want_constexpr_new): Define before including bits/version.h. (_GLIBCXX_PLACEMENT_CONSTEXPR): Define. (operator new, operator new[]): Use it for placement new instead of inline. * include/bits/version.def (constexpr_new): New FTM. * include/bits/version.h: Regenerate. Jakub --- gcc/c-family/c-cppbuiltin.cc.jj 2024-07-02 22:06:21.343875948 +0200 +++ gcc/c-family/c-cppbuiltin.cc 2024-07-03 10:18:00.311324004 +0200 @@ -1091,7 +1091,7 @@ c_cpp_builtins (cpp_reader *pfile) if (cxx_dialect > cxx23) { /* Set feature test macros for C++26. */ - cpp_define (pfile, "__cpp_constexpr=202306L"); + cpp_define (pfile, "__cpp_constexpr=202406L"); cpp_define (pfile, "__cpp_static_assert=202306L"); cpp_define (pfile, "__cpp_placeholder_variables=202306L"); cpp_define (pfile, "__cpp_structured_bindings=202403L"); --- gcc/testsuite/g++.dg/cpp2a/construct_at.h.jj 2024-07-02 22:06:22.138865784 +0200 +++ gcc/testsuite/g++.dg/cpp2a/construct_at.h 2024-07-03 10:18:00.312323991 +0200 @@ -58,5 +58,18 @@ namespace std { l->~T (); } } -inline void *operator new (std::size_t, void *p) noexcept +#if __cpp_constexpr >= 202406L +constexpr +#else +inline +#endif +void *operator new (std::size_t, void *p) noexcept +{ return p; } + +#if __cpp_constexpr >= 202406L +constexpr +#else +inline +#endif +void *operator new[] (std::size_t, void *p) noexcept { return p; } --- gcc/testsuite/g++.dg/cpp26/constexpr-new1.C.jj 2024-07-03 10:18:00.312323991 +0200 +++ gcc/testsuite/g++.dg/cpp26/constexpr-new1.C 2024-07-03 10:18:00.312323991 +0200 @@ -0,0 +1,66 @@ +// C++26 P2747R2 - constexpr placement new +// { dg-do compile { target c++26 } } + +#include "../cpp2a/construct_at.h" + +struct S { + constexpr S () : a (42), b (43) {} + constexpr S (int c, int d) : a (c), b (d) {} + int a, b; +}; +struct T { + int a, b; +}; + +constexpr bool +foo () +{ + std::allocator a; + auto b = a.allocate (3); + ::new (b) int (); + ::new (b + 1) int (1); + ::new (b + 2) int {2}; + if (b[0] != 0 || b[1] != 1 || b[2] != 2) + return false; + a.deallocate (b, 3); + std::allocator c; + auto d = c.allocate (4); + ::new (d) S; + ::new (d + 1) S (); + ::new (d + 2) S (7, 8); + ::new (d + 3) S { 9, 10 }; + if (d[0].a != 42 || d[0].b != 43 + || d[1].a != 42 || d[1].b != 43 + || d[2].a != 7 || d[2].b != 8 + || d[3].a != 9 || d[3].b != 10) + return false; + d[0].~S (); + d[1].~S (); + d[2].~S (); + d[3].~S (); + c.deallocate (d, 4); + std::allocator e; + auto f = e.allocate (3); + ::new (f) T (); + ::new (f + 1) T (7, 8); + ::new (f + 2) T { .a = 9, .b = 10 }; + if (f[0].a != 0 || f[0].b != 0 + || f[1].a != 7 || f[1].b != 8 + || f[2].a != 9 || f[2].b != 10) + return false; + f[0].~T (); + f[1].~T (); + f[2].~T (); + e.deallocate (f, 3); + auto g = a.allocate (3); + new (g) int[] {1, 2, 3}; + if (g[0] != 1 || g[1] != 2 || g[2] != 3) + return false; + new (g) int[] {4, 5}; + if (g[0] != 4 || g[1] != 5) + return false; + a.deallocate (g, 3); + return true; +} + +static_assert (foo ()); --- gcc/testsuite/g++.dg/cpp26/constexpr-new2.C.jj 2024-07-03 10:57:14.936113640 +0200 +++ gcc/testsuite/g++.dg/cpp26/constexpr-new2.C 2024-07-03 10:58:34.268063259 +0200 @@ -0,0 +1,73 @@ +// C++26 P2747R2 - constexpr placement new +// { dg-do compile { target c++26 } } + +#include +#include + +#ifndef __cpp_lib_constexpr_new +# error "__cpp_lib_constexpr_new" +#elif __cpp_lib_constexpr_new < 202406L +# error "__cpp_lib_constexpr_new < 202406" +#endif + +struct S { + constexpr S () : a (42), b (43) {} + constexpr S (int c, int d) : a (c), b (d) {} + int a, b; +}; +struct T { + int a, b; +}; + +constexpr bool +foo () +{ + std::allocator a; + auto b = a.allocate (3); + ::new (b) int (); + ::new (b + 1) int (1); + ::new (b + 2) int {2}; + if (b[0] != 0 || b[1] != 1 || b[2] != 2) + return false; + a.deallocate (b, 3); + std::allocator c; + auto d = c.allocate (4); + ::new (d) S; + ::new (d + 1) S (); + ::new (d + 2) S (7, 8); + ::new (d + 3) S { 9, 10 }; + if (d[0].a != 42 || d[0].b != 43 + || d[1].a != 42 || d[1].b != 43 + || d[2].a != 7 || d[2].b != 8 + || d[3].a != 9 || d[3].b != 10) + return false; + d[0].~S (); + d[1].~S (); + d[2].~S (); + d[3].~S (); + c.deallocate (d, 4); + std::allocator e; + auto f = e.allocate (3); + ::new (f) T (); + ::new (f + 1) T (7, 8); + ::new (f + 2) T { .a = 9, .b = 10 }; + if (f[0].a != 0 || f[0].b != 0 + || f[1].a != 7 || f[1].b != 8 + || f[2].a != 9 || f[2].b != 10) + return false; + f[0].~T (); + f[1].~T (); + f[2].~T (); + e.deallocate (f, 3); + auto g = a.allocate (3); + new (g) int[] {1, 2, 3}; + if (g[0] != 1 || g[1] != 2 || g[2] != 3) + return false; + new (g) int[] {4, 5}; + if (g[0] != 4 || g[1] != 5) + return false; + a.deallocate (g, 3); + return true; +} + +static_assert (foo ()); --- gcc/testsuite/g++.dg/cpp26/constexpr-new3.C.jj 2024-07-03 11:03:44.848951067 +0200 +++ gcc/testsuite/g++.dg/cpp26/constexpr-new3.C 2024-07-03 11:20:19.850776541 +0200 @@ -0,0 +1,47 @@ +// C++26 P2747R2 - constexpr placement new +// { dg-do compile { target c++26 } } + +#include "../cpp2a/construct_at.h" + +struct S { + constexpr S () : a (42), b (43) {} + constexpr S (int c, int d) : a (c), b (d) {} + int a, b; +}; +struct T { + int a, b; +}; + +constexpr bool +foo () +{ + std::allocator a; + auto b = a.allocate (3); + new (b + 1) int[] {2, 3}; // { dg-error "" "" { xfail *-*-* } } + a.deallocate (b, 3); + return true; +} + +constexpr bool +bar () +{ + std::allocator a; + auto b = a.allocate (3); + new (b) int[] {1, 2, 3, 4}; // { dg-error "array subscript value '3' is outside the bounds of array 'heap ' of type 'int \\\[3\\\]'" } + a.deallocate (b, 3); + return true; +} + +constexpr bool +baz () +{ + std::allocator a; + auto b = a.allocate (2); + new (b) long (42); // { dg-error "accessing value of 'heap ' through a 'long int' glvalue in a constant expression" } + a.deallocate (b, 2); + return true; +} + +constexpr bool a = foo (); +constexpr bool b = bar (); +constexpr bool c = baz (); --- gcc/testsuite/g++.dg/cpp26/feat-cxx26.C.jj 2024-07-02 22:06:22.081866513 +0200 +++ gcc/testsuite/g++.dg/cpp26/feat-cxx26.C 2024-07-03 10:18:00.312323991 +0200 @@ -134,8 +134,8 @@ #ifndef __cpp_constexpr # error "__cpp_constexpr" -#elif __cpp_constexpr != 202306L -# error "__cpp_constexpr != 202306L" +#elif __cpp_constexpr != 202406L +# error "__cpp_constexpr != 202406L" #endif #ifndef __cpp_decltype_auto --- libstdc++-v3/libsupc++/new.jj 2024-01-03 12:07:51.070049086 +0100 +++ libstdc++-v3/libsupc++/new 2024-07-03 10:36:17.728769550 +0200 @@ -43,6 +43,7 @@ #define __glibcxx_want_launder #define __glibcxx_want_hardware_interference_size #define __glibcxx_want_destroying_delete +#define __glibcxx_want_constexpr_new #include #pragma GCC visibility push(default) @@ -175,10 +176,18 @@ void operator delete[](void*, std::size_ #endif // __cpp_sized_deallocation #endif // __cpp_aligned_new +#if __cpp_lib_constexpr_new >= 202406L +# define _GLIBCXX_PLACEMENT_CONSTEXPR constexpr +#else +# define _GLIBCXX_PLACEMENT_CONSTEXPR inline +#endif + // Default placement versions of operator new. -_GLIBCXX_NODISCARD inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT +_GLIBCXX_NODISCARD _GLIBCXX_PLACEMENT_CONSTEXPR +void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT { return __p; } -_GLIBCXX_NODISCARD inline void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT +_GLIBCXX_NODISCARD _GLIBCXX_PLACEMENT_CONSTEXPR +void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT { return __p; } // Default placement versions of operator delete. --- libstdc++-v3/include/bits/version.def.jj 2024-07-01 11:28:23.642225952 +0200 +++ libstdc++-v3/include/bits/version.def 2024-07-03 10:33:56.996636092 +0200 @@ -1814,6 +1814,15 @@ ftms = { }; }; +ftms = { + name = constexpr_new; + values = { + v = 202406; + cxxmin = 26; + extra_cond = "__cpp_constexpr >= 202406L"; + }; +}; + // Standard test specifications. stds[97] = ">= 199711L"; stds[03] = ">= 199711L"; --- libstdc++-v3/include/bits/version.h.jj 2024-07-01 11:28:23.643225939 +0200 +++ libstdc++-v3/include/bits/version.h 2024-07-03 10:34:28.487052774 +0200 @@ -2023,4 +2023,14 @@ #endif /* !defined(__cpp_lib_ranges_concat) && defined(__glibcxx_want_ranges_concat) */ #undef __glibcxx_want_ranges_concat +#if !defined(__cpp_lib_constexpr_new) +# if (__cplusplus > 202302L) && (__cpp_constexpr >= 202406L) +# define __glibcxx_constexpr_new 202406L +# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_new) +# define __cpp_lib_constexpr_new 202406L +# endif +# endif +#endif /* !defined(__cpp_lib_constexpr_new) && defined(__glibcxx_want_constexpr_new) */ +#undef __glibcxx_want_constexpr_new + #undef __glibcxx_want_all