diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc index a80372c89914454da944809c3cf539cd69881aba..97c3ecb7d1616c0a3f566d62eb03615e1b9098ea 100644 --- a/gcc/c-family/c-cppbuiltin.cc +++ b/gcc/c-family/c-cppbuiltin.cc @@ -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"); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-new1.C b/gcc/testsuite/g++.dg/cpp26/constexpr-new1.C new file mode 100644 index 0000000000000000000000000000000000000000..131b718efa5b2e3cf1b8479559f18fd055542135 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-new1.C @@ -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 ()); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-new2.C b/gcc/testsuite/g++.dg/cpp26/constexpr-new2.C new file mode 100644 index 0000000000000000000000000000000000000000..e333185425376696302372f0a1b30e630a07dd3b --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-new2.C @@ -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 ()); diff --git a/gcc/testsuite/g++.dg/cpp26/constexpr-new3.C b/gcc/testsuite/g++.dg/cpp26/constexpr-new3.C new file mode 100644 index 0000000000000000000000000000000000000000..6a06a6e6f32e5dc8cf4ee3d7ae4b43140067035f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/constexpr-new3.C @@ -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 (); diff --git a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C index 8a5fd64d39604b03af738ad9d5f3b826c04cdf51..82be39c996f247576e7f0ac3357bf1b374870dd2 100644 --- a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C +++ b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C @@ -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 diff --git a/gcc/testsuite/g++.dg/cpp2a/construct_at.h b/gcc/testsuite/g++.dg/cpp2a/construct_at.h index 27e92cbb28c5bb84a7f21b453a3014e1e1acb090..ed6165610424fc5e289dec20aa59273ede952253 100644 --- a/gcc/testsuite/g++.dg/cpp2a/construct_at.h +++ b/gcc/testsuite/g++.dg/cpp2a/construct_at.h @@ -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; } diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def index ee0a9e45c441d272ed925bdaa3fc3da35db071ab..6791c6f6f93678ae473648361b6a161db883705d 100644 --- a/libstdc++-v3/include/bits/version.def +++ b/libstdc++-v3/include/bits/version.def @@ -1838,6 +1838,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"; diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h index cee497d7443fa2eafde5975696e996d81c0d0533..0b78cb94ecc97dda9ffced2b8fdb1b498e71ea9a 100644 --- a/libstdc++-v3/include/bits/version.h +++ b/libstdc++-v3/include/bits/version.h @@ -2033,4 +2033,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 diff --git a/libstdc++-v3/libsupc++/new b/libstdc++-v3/libsupc++/new index 8b07150fb94941bd29a334cfa178c922255ea394..2e2038e1a82ccbcd2e73becedeb1665b6fb660e8 100644 --- a/libstdc++-v3/libsupc++/new +++ b/libstdc++-v3/libsupc++/new @@ -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,12 +176,22 @@ void operator delete[](void*, std::size_t, std::align_val_t) #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; } +#undef _GLIBCXX_PLACEMENT_CONSTEXPR + // Default placement versions of operator delete. inline void operator delete (void*, void*) _GLIBCXX_USE_NOEXCEPT { } inline void operator delete[](void*, void*) _GLIBCXX_USE_NOEXCEPT { }