2024-07-03 Jakub Jelinek <ja...@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