From: Jonathan Wakely <jwakely@redhat.com>
To: Jakub Jelinek <jakub@redhat.com>
Cc: Jason Merrill <jason@redhat.com>,
gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org
Subject: Re: [PATCH] c++, libstdc++: Implement C++26 P2747R2 - constexpr placement new [PR115744]
Date: Wed, 3 Jul 2024 15:50:29 +0100 [thread overview]
Message-ID: <CACb0b4mY+LqBH4wD3szL8Lg2=CmV=WXq6FDLaS0NYM=HfJqowQ@mail.gmail.com> (raw)
In-Reply-To: <ZoViDDKrpczHeWxm@tucnak>
On Wed, 3 Jul 2024 at 15:37, Jakub Jelinek <jakub@redhat.com> wrote:
>
> 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 <new>, 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<int>{}.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 <D.2640, (void *) TARGET_EXPR <D.2641, VIEW_CONVERT_EXPR<int *>(b) + 4>>, TARGET_EXPR <D.2642, operator new [] (8, NON_LVALUE_EXPR <D.2640>)>, 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?
I have a mild preference for #undef _GLIBCXX_PLACEMENT_CONSTEXPR after
we're finished using it, but the libstdc++ parts are OK either way.
>
> 2024-07-03 Jakub Jelinek <jakub@redhat.com>
>
> 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.
>
> --- 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<int> 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<S> 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<T> 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 <memory>
> +#include <new>
> +
> +#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<int> 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<S> 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<T> 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<int> 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<int> 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<int> 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 <bits/version.h>
>
> #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
>
> Jakub
>
next prev parent reply other threads:[~2024-07-03 14:50 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-07-03 14:37 Jakub Jelinek
2024-07-03 14:50 ` Jonathan Wakely [this message]
2024-07-03 15:41 ` Jason Merrill
2024-07-03 15:51 ` Jakub Jelinek
2024-07-03 16:35 ` Jonathan Wakely
2024-08-07 12:36 ` C++ Patch ping Jakub Jelinek
2024-08-07 22:23 ` [PATCH] c++, libstdc++: Implement C++26 P2747R2 - constexpr placement new [PR115744] Jason Merrill
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CACb0b4mY+LqBH4wD3szL8Lg2=CmV=WXq6FDLaS0NYM=HfJqowQ@mail.gmail.com' \
--to=jwakely@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jakub@redhat.com \
--cc=jason@redhat.com \
--cc=libstdc++@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).