summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2024-08-08 11:05:36 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2024-08-08 11:07:29 +0200
commitafa3a4a52cf91485477e4aaa5f05987ec7ff869d (patch)
tree28eefc7d2a4da71312abcb0e0eecc05ac8e6af96
parentlibgomp.c++/static-aggr-constructor-destructor-{1,2}.C: Fix scan-tree-dump (diff)
c++, libstdc++: Implement C++26 P2747R2 - constexpr placement new [PR115744]
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? 2024-08-08 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.
-rw-r--r--gcc/c-family/c-cppbuiltin.cc2
-rw-r--r--gcc/testsuite/g++.dg/cpp26/constexpr-new1.C66
-rw-r--r--gcc/testsuite/g++.dg/cpp26/constexpr-new2.C73
-rw-r--r--gcc/testsuite/g++.dg/cpp26/constexpr-new3.C47
-rw-r--r--gcc/testsuite/g++.dg/cpp26/feat-cxx26.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/construct_at.h15
-rw-r--r--libstdc++-v3/include/bits/version.def9
-rw-r--r--libstdc++-v3/include/bits/version.h10
-rw-r--r--libstdc++-v3/libsupc++/new15
9 files changed, 235 insertions, 6 deletions
diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc
index a80372c89914..97c3ecb7d161 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)
1091 if (cxx_dialect > cxx23) 1091 if (cxx_dialect > cxx23)
1092 { 1092 {
1093 /* Set feature test macros for C++26. */ 1093 /* Set feature test macros for C++26. */
1094 cpp_define (pfile, "__cpp_constexpr=202306L"); 1094 cpp_define (pfile, "__cpp_constexpr=202406L");
1095 cpp_define (pfile, "__cpp_static_assert=202306L"); 1095 cpp_define (pfile, "__cpp_static_assert=202306L");
1096 cpp_define (pfile, "__cpp_placeholder_variables=202306L"); 1096 cpp_define (pfile, "__cpp_placeholder_variables=202306L");
1097 cpp_define (pfile, "__cpp_structured_bindings=202403L"); 1097 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 000000000000..131b718efa5b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/constexpr-new1.C
@@ -0,0 +1,66 @@
1// C++26 P2747R2 - constexpr placement new
2// { dg-do compile { target c++26 } }
3
4#include "../cpp2a/construct_at.h"
5
6struct S {
7 constexpr S () : a (42), b (43) {}
8 constexpr S (int c, int d) : a (c), b (d) {}
9 int a, b;
10};
11struct T {
12 int a, b;
13};
14
15constexpr bool
16foo ()
17{
18 std::allocator<int> a;
19 auto b = a.allocate (3);
20 ::new (b) int ();
21 ::new (b + 1) int (1);
22 ::new (b + 2) int {2};
23 if (b[0] != 0 || b[1] != 1 || b[2] != 2)
24 return false;
25 a.deallocate (b, 3);
26 std::allocator<S> c;
27 auto d = c.allocate (4);
28 ::new (d) S;
29 ::new (d + 1) S ();
30 ::new (d + 2) S (7, 8);
31 ::new (d + 3) S { 9, 10 };
32 if (d[0].a != 42 || d[0].b != 43
33 || d[1].a != 42 || d[1].b != 43
34 || d[2].a != 7 || d[2].b != 8
35 || d[3].a != 9 || d[3].b != 10)
36 return false;
37 d[0].~S ();
38 d[1].~S ();
39 d[2].~S ();
40 d[3].~S ();
41 c.deallocate (d, 4);
42 std::allocator<T> e;
43 auto f = e.allocate (3);
44 ::new (f) T ();
45 ::new (f + 1) T (7, 8);
46 ::new (f + 2) T { .a = 9, .b = 10 };
47 if (f[0].a != 0 || f[0].b != 0
48 || f[1].a != 7 || f[1].b != 8
49 || f[2].a != 9 || f[2].b != 10)
50 return false;
51 f[0].~T ();
52 f[1].~T ();
53 f[2].~T ();
54 e.deallocate (f, 3);
55 auto g = a.allocate (3);
56 new (g) int[] {1, 2, 3};
57 if (g[0] != 1 || g[1] != 2 || g[2] != 3)
58 return false;
59 new (g) int[] {4, 5};
60 if (g[0] != 4 || g[1] != 5)
61 return false;
62 a.deallocate (g, 3);
63 return true;
64}
65
66static_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 000000000000..e33318542537
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/constexpr-new2.C
@@ -0,0 +1,73 @@
1// C++26 P2747R2 - constexpr placement new
2// { dg-do compile { target c++26 } }
3
4#include <memory>
5#include <new>
6
7#ifndef __cpp_lib_constexpr_new
8# error "__cpp_lib_constexpr_new"
9#elif __cpp_lib_constexpr_new < 202406L
10# error "__cpp_lib_constexpr_new < 202406"
11#endif
12
13struct S {
14 constexpr S () : a (42), b (43) {}
15 constexpr S (int c, int d) : a (c), b (d) {}
16 int a, b;
17};
18struct T {
19 int a, b;
20};
21
22constexpr bool
23foo ()
24{
25 std::allocator<int> a;
26 auto b = a.allocate (3);
27 ::new (b) int ();
28 ::new (b + 1) int (1);
29 ::new (b + 2) int {2};
30 if (b[0] != 0 || b[1] != 1 || b[2] != 2)
31 return false;
32 a.deallocate (b, 3);
33 std::allocator<S> c;
34 auto d = c.allocate (4);
35 ::new (d) S;
36 ::new (d + 1) S ();
37 ::new (d + 2) S (7, 8);
38 ::new (d + 3) S { 9, 10 };
39 if (d[0].a != 42 || d[0].b != 43
40 || d[1].a != 42 || d[1].b != 43
41 || d[2].a != 7 || d[2].b != 8
42 || d[3].a != 9 || d[3].b != 10)
43 return false;
44 d[0].~S ();
45 d[1].~S ();
46 d[2].~S ();
47 d[3].~S ();
48 c.deallocate (d, 4);
49 std::allocator<T> e;
50 auto f = e.allocate (3);
51 ::new (f) T ();
52 ::new (f + 1) T (7, 8);
53 ::new (f + 2) T { .a = 9, .b = 10 };
54 if (f[0].a != 0 || f[0].b != 0
55 || f[1].a != 7 || f[1].b != 8
56 || f[2].a != 9 || f[2].b != 10)
57 return false;
58 f[0].~T ();
59 f[1].~T ();
60 f[2].~T ();
61 e.deallocate (f, 3);
62 auto g = a.allocate (3);
63 new (g) int[] {1, 2, 3};
64 if (g[0] != 1 || g[1] != 2 || g[2] != 3)
65 return false;
66 new (g) int[] {4, 5};
67 if (g[0] != 4 || g[1] != 5)
68 return false;
69 a.deallocate (g, 3);
70 return true;
71}
72
73static_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 000000000000..6a06a6e6f32e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/constexpr-new3.C
@@ -0,0 +1,47 @@
1// C++26 P2747R2 - constexpr placement new
2// { dg-do compile { target c++26 } }
3
4#include "../cpp2a/construct_at.h"
5
6struct S {
7 constexpr S () : a (42), b (43) {}
8 constexpr S (int c, int d) : a (c), b (d) {}
9 int a, b;
10};
11struct T {
12 int a, b;
13};
14
15constexpr bool
16foo ()
17{
18 std::allocator<int> a;
19 auto b = a.allocate (3);
20 new (b + 1) int[] {2, 3}; // { dg-error "" "" { xfail *-*-* } }
21 a.deallocate (b, 3);
22 return true;
23}
24
25constexpr bool
26bar ()
27{
28 std::allocator<int> a;
29 auto b = a.allocate (3);
30 new (b) int[] {1, 2, 3, 4}; // { dg-error "array subscript value '3' is outside the bounds of array 'heap ' of type 'int \\\[3\\\]'" }
31 a.deallocate (b, 3);
32 return true;
33}
34
35constexpr bool
36baz ()
37{
38 std::allocator<int> a;
39 auto b = a.allocate (2);
40 new (b) long (42); // { dg-error "accessing value of 'heap ' through a 'long int' glvalue in a constant expression" }
41 a.deallocate (b, 2);
42 return true;
43}
44
45constexpr bool a = foo ();
46constexpr bool b = bar ();
47constexpr bool c = baz ();
diff --git a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
index 8a5fd64d3960..82be39c996f2 100644
--- a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
+++ b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
@@ -134,8 +134,8 @@
134 134
135#ifndef __cpp_constexpr 135#ifndef __cpp_constexpr
136# error "__cpp_constexpr" 136# error "__cpp_constexpr"
137#elif __cpp_constexpr != 202306L 137#elif __cpp_constexpr != 202406L
138# error "__cpp_constexpr != 202306L" 138# error "__cpp_constexpr != 202406L"
139#endif 139#endif
140 140
141#ifndef __cpp_decltype_auto 141#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 27e92cbb28c5..ed6165610424 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
58 { l->~T (); } 58 { l->~T (); }
59} 59}
60 60
61inline void *operator new (std::size_t, void *p) noexcept 61#if __cpp_constexpr >= 202406L
62constexpr
63#else
64inline
65#endif
66void *operator new (std::size_t, void *p) noexcept
67{ return p; }
68
69#if __cpp_constexpr >= 202406L
70constexpr
71#else
72inline
73#endif
74void *operator new[] (std::size_t, void *p) noexcept
62{ return p; } 75{ return p; }
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index ee0a9e45c441..6791c6f6f936 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -1838,6 +1838,15 @@ ftms = {
1838 }; 1838 };
1839}; 1839};
1840 1840
1841ftms = {
1842 name = constexpr_new;
1843 values = {
1844 v = 202406;
1845 cxxmin = 26;
1846 extra_cond = "__cpp_constexpr >= 202406L";
1847 };
1848};
1849
1841// Standard test specifications. 1850// Standard test specifications.
1842stds[97] = ">= 199711L"; 1851stds[97] = ">= 199711L";
1843stds[03] = ">= 199711L"; 1852stds[03] = ">= 199711L";
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index cee497d7443f..0b78cb94ecc9 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2033,4 +2033,14 @@
2033#endif /* !defined(__cpp_lib_ranges_concat) && defined(__glibcxx_want_ranges_concat) */ 2033#endif /* !defined(__cpp_lib_ranges_concat) && defined(__glibcxx_want_ranges_concat) */
2034#undef __glibcxx_want_ranges_concat 2034#undef __glibcxx_want_ranges_concat
2035 2035
2036#if !defined(__cpp_lib_constexpr_new)
2037# if (__cplusplus > 202302L) && (__cpp_constexpr >= 202406L)
2038# define __glibcxx_constexpr_new 202406L
2039# if defined(__glibcxx_want_all) || defined(__glibcxx_want_constexpr_new)
2040# define __cpp_lib_constexpr_new 202406L
2041# endif
2042# endif
2043#endif /* !defined(__cpp_lib_constexpr_new) && defined(__glibcxx_want_constexpr_new) */
2044#undef __glibcxx_want_constexpr_new
2045
2036#undef __glibcxx_want_all 2046#undef __glibcxx_want_all
diff --git a/libstdc++-v3/libsupc++/new b/libstdc++-v3/libsupc++/new
index 8b07150fb949..2e2038e1a82c 100644
--- a/libstdc++-v3/libsupc++/new
+++ b/libstdc++-v3/libsupc++/new
@@ -43,6 +43,7 @@
43#define __glibcxx_want_launder 43#define __glibcxx_want_launder
44#define __glibcxx_want_hardware_interference_size 44#define __glibcxx_want_hardware_interference_size
45#define __glibcxx_want_destroying_delete 45#define __glibcxx_want_destroying_delete
46#define __glibcxx_want_constexpr_new
46#include <bits/version.h> 47#include <bits/version.h>
47 48
48#pragma GCC visibility push(default) 49#pragma GCC visibility push(default)
@@ -175,12 +176,22 @@ void operator delete[](void*, std::size_t, std::align_val_t)
175#endif // __cpp_sized_deallocation 176#endif // __cpp_sized_deallocation
176#endif // __cpp_aligned_new 177#endif // __cpp_aligned_new
177 178
179#if __cpp_lib_constexpr_new >= 202406L
180# define _GLIBCXX_PLACEMENT_CONSTEXPR constexpr
181#else
182# define _GLIBCXX_PLACEMENT_CONSTEXPR inline
183#endif
184
178// Default placement versions of operator new. 185// Default placement versions of operator new.
179_GLIBCXX_NODISCARD inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT 186_GLIBCXX_NODISCARD _GLIBCXX_PLACEMENT_CONSTEXPR
187void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
180{ return __p; } 188{ return __p; }
181_GLIBCXX_NODISCARD inline void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT 189_GLIBCXX_NODISCARD _GLIBCXX_PLACEMENT_CONSTEXPR
190void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT
182{ return __p; } 191{ return __p; }
183 192
193#undef _GLIBCXX_PLACEMENT_CONSTEXPR
194
184// Default placement versions of operator delete. 195// Default placement versions of operator delete.
185inline void operator delete (void*, void*) _GLIBCXX_USE_NOEXCEPT { } 196inline void operator delete (void*, void*) _GLIBCXX_USE_NOEXCEPT { }
186inline void operator delete[](void*, void*) _GLIBCXX_USE_NOEXCEPT { } 197inline void operator delete[](void*, void*) _GLIBCXX_USE_NOEXCEPT { }