On 10/3/25 4:52 PM, Jakub Jelinek wrote:
On Wed, Oct 01, 2025 at 07:24:36PM +0100, Jason Merrill wrote:
The problem is that in e.g. cpp2a/constexpr-new23.C we end up trying to
clobber an int[1] variable arr as int[1][1], and constexpr complains. Except
that currently it doesn't because we don't emit the clobber before
initializing a non-class, but it does if we change the int[1] to an array of
class type.
So do you mean something like the attached test?
What testcase breaks with the added whole array clobber if the VEC_INIT is
not removed?
and not emit clobbers at least for now at all if
there is trivial constructor for the elements and we'd emit the clobbers in
a loop.
Unfortunately we still need the clobber for constexpr placement new; with
that change, if I modify constexpr-new4.C to take the new array bound as a
parameter, it breaks.
I can certainly try this one.
Plus the other one (constexpr-new4.C with function argument instead of 3)?
From what I can see, with your patch all the tests work, with the one I've
posted on top of it (or its variant which always did a whole array clobber
using char[array_size] type) I see constexpr-new28.C FAIL (and a couple of
others).
I don't see that constexpr-new29.C FAILing when not emitting clobbers, but
when I test all constexpr-new*.C tests with
GXX_TESTSUITE_STDS=98,11,14,17,20,23,26 make check-g++
RUNTESTFLAGS='--target_board=unix/-flifetime-dse=0 dg.exp=constexpr-new*'
and just your patch I see
FAIL: g++.dg/cpp26/constexpr-new5.C -std=c++26 (test for excess errors)
FAIL: g++.dg/cpp26/constexpr-new6a.C -std=c++26 (test for errors, line 11)
FAIL: g++.dg/cpp26/constexpr-new6a.C -std=c++26 (test for excess errors)
FAIL: g++.dg/cpp2a/constexpr-new3.C -std=c++20 (test for errors, line 37)
FAIL: g++.dg/cpp2a/constexpr-new3.C -std=c++20 (test for excess errors)
FAIL: g++.dg/cpp2a/constexpr-new3.C -std=c++23 (test for errors, line 37)
FAIL: g++.dg/cpp2a/constexpr-new3.C -std=c++23 (test for excess errors)
FAIL: g++.dg/cpp2a/constexpr-new3.C -std=c++26 (test for errors, line 37)
FAIL: g++.dg/cpp2a/constexpr-new3.C -std=c++26 (test for excess errors)
So, I wonder if some clobbers are essential for correct constexpr
evaluations, whether we shouldn't be emitting some CLOBBERs with some
constexpr only kinds which gimplification would remove even for
-flifetime-dse=0 or -flifetime-dse=1.
Anyway, are the following two testcases ok for trunk?
OK.
2025-10-03 Jakub Jelinek <[email protected]>
* g++.dg/cpp2a/constexpr-new28.C: New test.
* g++.dg/cpp2a/constexpr-new29.C: New test.
--- gcc/testsuite/g++.dg/cpp2a/constexpr-new28.C.jj 2025-10-03
17:35:09.024315244 +0200
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-new28.C 2025-10-03
17:10:16.073066504 +0200
@@ -0,0 +1,45 @@
+// PR c++/115645
+// { dg-do compile { target c++20 } }
+
+using size_t = decltype(sizeof(0));
+
+void* operator new(size_t, void* p) { return p; }
+void* operator new[](size_t, void* p) { return p; }
+
+#define VERIFY(C) if (!(C)) throw
+
+namespace std {
+ template<typename T>
+ constexpr T* construct_at(T* p)
+ {
+ if constexpr (__is_array(T))
+ return ::new((void*)p) T[1]();
+ else
+ return ::new((void*)p) T();
+ }
+}
+
+struct S {
+ constexpr S () : s (0) {}
+ constexpr S (int x) : s (x) {}
+ constexpr bool operator== (int x) const { return s == x; }
+ int s;
+};
+
+constexpr void
+test_array()
+{
+ S arr[1] { 99 };
+ std::construct_at(&arr);
+ VERIFY( arr[0] == 0 );
+
+ union U {
+ long long x = -1;
+ S arr[4];
+ } u;
+
+ auto p = std::construct_at(&u.arr);
+ VERIFY( (*p)[0] == 0 );
+}
+
+static_assert( [] { test_array(); return true; }() );
--- gcc/testsuite/g++.dg/cpp2a/constexpr-new29.C.jj 2025-10-03
17:35:13.398254376 +0200
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-new29.C 2025-10-03
17:13:48.512109425 +0200
@@ -0,0 +1,30 @@
+// P0784R7
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-fdelete-null-pointer-checks" }
+
+struct S
+{
+ constexpr S () : s (0) { s++; }
+ constexpr S (int x) : s (x) { s += 2; }
+ constexpr ~S () { if (s != 35) asm (""); s = 5; }
+ int s;
+};
+
+constexpr bool
+foo (int n)
+{
+ S *p = new S (7);
+ if (p->s != 9) return false;
+ p->s = 35;
+ delete p;
+ p = new S[n] { 11, 13, 15 };
+ if (p[0].s != 13 || p[1].s != 15 || p[2].s != 17) return false;
+ p[0].s = 35;
+ p[2].s = 35;
+ p[1].s = 35;
+ delete[] p;
+ return true;
+}
+
+constexpr bool a = foo (3);
+static_assert (a);
Jakub