public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
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
>


  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).