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


Reply via email to