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? 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
