[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-08-21 Thread cvs-commit at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #21 from GCC Commits  ---
The trunk branch has been updated by Jason Merrill :

https://gcc.gnu.org/g:70f33ad677e6350a724b56d4cb766480ed8367fc

commit r16--g70f33ad677e6350a724b56d4cb766480ed8367fc
Author: Jason Merrill 
Date:   Thu Aug 21 13:52:25 2025 -0400

c++: constexpr clobber of const [PR121068]

Since r16-3022, 20_util/variant/102912.cc was failing in C++20 and above
due
to wrong errors about destruction modifying a const object; destruction is
OK.

PR c++/121068

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_store_expression): Allow clobber of a
const
object.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/constexpr-dtor18.C: New test.

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-08-21 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

Jason Merrill  changed:

   What|Removed |Added

 Status|NEW |ASSIGNED

--- Comment #20 from Jason Merrill  ---
(In reply to Jonathan Wakely from comment #19)
> FAIL: 20_util/variant/102912.cc  -std=gnu++20 (test for excess errors)

Ah, thanks, I was only running that test in 17 mode (the default).  I'll fix
that as well.

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-08-21 Thread redi at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #19 from Jonathan Wakely  ---
I'm seeing a new libstdc++ testsuite failure since r16-3022-gbc42128330c0ea

FAIL: 20_util/variant/102912.cc  -std=gnu++20 (test for excess errors)
FAIL: 20_util/variant/102912.cc  -std=gnu++23 (test for excess errors)
FAIL: 20_util/variant/102912.cc  -std=gnu++26 (test for excess errors)

The error is:

in 'constexpr' expansion of 'std::destroy_at(__pointer)'
/home/jwakely/gcc/15/include/c++/15.1.1/bits/stl_construct.h:164:22:   
  164 |   std::destroy_at(__pointer);
  |   ~~~^~~
/home/jwakely/gcc/15/include/c++/15.1.1/bits/stl_construct.h:88:9: error:
modifying a const object '* __location' is not allowed in a constant expression
   88 | __location->~_Tp();
  | ^~
/home/jwakely/gcc/15/include/c++/15.1.1/variant:246:13: note: originally
declared 'const' here
  246 |   _Type _M_storage;
  | ^~

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-08-05 Thread cvs-commit at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #18 from GCC Commits  ---
The trunk branch has been updated by Jason Merrill :

https://gcc.gnu.org/g:bc42128330c0ea70a015b74b655cb8c48b6a8c06

commit r16-3022-gbc42128330c0ea70a015b74b655cb8c48b6a8c06
Author: Jason Merrill 
Date:   Tue Aug 5 15:16:50 2025 -0700

c++: clobber object on placement new [PR121068]

My r16-2432 patch addressed the original testcase involving an array of
scalars, but not this additional testcase involving an array of classes.

This patch addresses the issue more thoroughly, by having placement new
first clobber the new object, and improving cxx_eval_store_expression to
implement initial clobbers as well.

My earlier attempt to do this clobbered the array as a whole, which broke
construct_at after the resolution of LWG3436 due to trying to create a
multidimensional array over the top of a single-dimensional array.  To
side-step that issue, this patch instead clobbers the individual elements
of
an array, taking advantage of the earlier change to let that activate the
array member of a union.

PR c++/121068

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_store_expression): Handle clobbers.
(potential_constant_expression_1): Handle clobbers more.
* decl.cc (build_clobber_this): Use INIT_EXPR for initial clobber.
* init.cc (build_new_1): Clobber on placement new.
(build_vec_init): Don't clean up after clobber.

gcc/testsuite/ChangeLog:

* g++.dg/cpp26/constexpr-new5.C: New test.

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-25 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #17 from Jason Merrill  ---
OK, the issue is that we currently don't represent trivial initialization at
all, so the initial placement new has no effect.

Then the trivial destructors are represented by clobbers, but constant
evaluation doesn't currently do anything with them (before my WIP patch).

Then the individual construction starts with a clobber that the evaluator
ignores.

Then the constructor starts to initialize the individual member, but that's not
directly initializing the union member, so it gets rejected.

As in the WIP patch I think the solution is to represent trivial initialization
by clobbering the object instead of doing nothing.

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-25 Thread tkaminsk at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #16 from Tomasz Kamiński  ---
Ah sorry, I was sure I posted the function before:
```
#include 

struct S
{
  constexpr S() = default;
  constexpr S(int x) : s(x) {}
  constexpr S(S&& x) : s(x.s) {}
  constexpr S& operator=(S&& x) { s = x.s; return *this; }  
  unsigned char s;  
};

constexpr
int foo()
{
  union { S a[20]; };
  new (&a) S[20](); // OK
  for (int i = 0; i < 20; ++i)
a[i].~S();

  auto* sf = ::new(&a[2]) S(11);
  return 1;
}

static_assert(foo());

constexpr
int foo2()
{
  union { S a[20]; };
  new (&a) S[20]; // ILL-FORMED
  for (int i = 0; i < 20; ++i)
a[i].~S();

  auto* sf = ::new(&a[2]) S(11);
  return 1;
}

static_assert(foo2());
```
https://godbolt.org/z/cKbEsdzEh

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-25 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #15 from Jason Merrill  ---
(In reply to Tomasz Kamiński from comment #14)
Please provide complete testcases, this snippet isn't enough to reproduce.

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-23 Thread tkaminsk at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #14 from Tomasz Kamiński  ---
Not sure if this is expected, so noting this here.

On trunk (with r16-2432-gfdbc5ff61b471076cc9c758fb6c30d62f7ef1c56), if I value
initialize the array (like in inplace_vector), then the code works:
  union { S a[20]; };
  new (&a) S[20](); // OK
  for (int i = 0; i < 20; ++i)
a[i].~S();

  auto* sf = ::new(&a[2]) S(11);
See also: https://gcc.gnu.org/pipermail/libstdc++/2025-July/062752.html

But after changing the placement new to perform default initialization `new
(&a) S`, the above code no longer works. This is not a blocker on any library
feature.

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-22 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

Jason Merrill  changed:

   What|Removed |Added

  Attachment #61891|0   |1
is obsolete||

--- Comment #13 from Jason Merrill  ---
Created attachment 61942
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61942&action=edit
revised clobber patch

Here's the current state of the patch to clobber arrays to start their
lifetime.

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-22 Thread cvs-commit at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #12 from GCC Commits  ---
The trunk branch has been updated by Jason Merrill :

https://gcc.gnu.org/g:fdbc5ff61b471076cc9c758fb6c30d62f7ef1c56

commit r16-2432-gfdbc5ff61b471076cc9c758fb6c30d62f7ef1c56
Author: Jason Merrill 
Date:   Wed Jul 16 11:52:45 2025 -0400

c++: constexpr union placement new [PR121068]

The note and example in [class.union] p6 think that placement new can be
used to change the active member of a union, but we didn't support that for
array members in constant-evaluation even after implementing P1330 and
P2747.

First I tried to address this by introducing a CLOBBER_BEGIN_OBJECT for the
entire array, but that broke the resolution of LWG3436, which invokes 'new
T[1]' for an array T, and trying to clobber a multidimensional array when
the actual object is single-dimensional breaks.  So I've raised that issue
with the committee.  Until that is resolved, this patch takes a simpler
approach: allow initialization of an element of an array to make the array
the active member of a union.

PR c++/121068

gcc/cp/ChangeLog:

* constexpr.cc (cxx_eval_store_expression): Allow ARRAY_REFs
when activating an array member of a union.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/constexpr-union6.C: Expect x5 to work.
* g++.dg/cpp26/constexpr-new4.C: New test.

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-22 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #11 from Jason Merrill  ---
(In reply to Tomasz Kamiński from comment #9)
> I remember that LWG3436 was discussed in core in Varna
> (https://wiki.edg.com/bin/view/Wg21varna/CoreWorkingGroup#LWG3436) and the
> current wording is result from there. 

Ah, right.

> I was always suspicious about creating Tp[1] there, as in case when we are
> creating a member (or any other object that is not transparently
> replaceable), we will simply reuse storage and destroy the original object.
> I do not think there is UB caused by lack of multidimensional array at that
> location, but the new call is for sure not constant for the same reason.

I guess the Tp[1] idea was justified by
https://eel.is/c++draft/basic#compound-3 "an object of type T that is not an
array element is considered to belong to an array with one element of type T"
but that's qualified by "For purposes of pointer arithmetic and comparison", I
don't see that it applies to the whole object model.

My argument that this is UB is based on https://eel.is/c++draft/basic.lval#11 ,
thinking that int[3] is not accessible through int[3][1].  But that section
also makes the point that access is based on scalars, so perhaps it doesn't
apply.

Actually, it's unclear to me what actually prevents us from creating a struct
of one int overlaying an int

> I agree that your proposed change seem to be much better direction, but as
> far as I can see it does not match direction of
> https://cplusplus.github.io/LWG/issue3436. Am I looking at wrong place?

Ah, no, I was; https://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html
seems to be out of date.

I sent mail to the core reflector.

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-22 Thread tkaminsk at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #10 from Tomasz Kamiński  ---
If the object pointed by __location is not transparently replaceable, for
example if I would create an object inside std::byte array that is an member,
then does std::launder(__location) produce pointer to new object? __location
does not automatically point there per (https://eel.is/c++draft/basic.life#10),
by we meet precondition for launder (https://eel.is/c++draft/ptr.launder#2).

This cannot happen for compile-time evaluation, as calling construct_at such
way would require equivalent of reinterpret_cast, so we could do, but I am not
sure if that is necessary.
+#if __cpp_lib_launder
+  if consteval 
+{
+  return std::launder(__location);
+}
+  else
+{
+  return std::launder(static_cast<_Tp*>(__loc));
+}
+#else
+  return static_cast<_Tp*>(__loc);
+#endif

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-22 Thread tkaminsk at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #9 from Tomasz Kamiński  ---
I remember that LWG3436 was discussed in core in Varna
(https://wiki.edg.com/bin/view/Wg21varna/CoreWorkingGroup#LWG3436) and the
current wording is result from there. 

I was always suspicious about creating Tp[1] there, as in case when we are
creating a member (or any other object that is not transparently replaceable),
we will simply reuse storage and destroy the original object. I do not think
there is UB caused by lack of multidimensional array at that location, but the
new call is for sure not constant for the same reason.

I agree that your proposed change seem to be much better direction, but as far
as I can see it does not match direction of
https://cplusplus.github.io/LWG/issue3436. Am I looking at wrong place?

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-21 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

Jason Merrill  changed:

   What|Removed |Added

 Ever confirmed|0   |1
 Status|UNCONFIRMED |NEW
   Last reconfirmed||2025-07-21
   Assignee|unassigned at gcc dot gnu.org  |jason at gcc dot gnu.org

--- Comment #8 from Jason Merrill  ---
(In reply to Tomasz Kamiński from comment #6)
> I believed that `_member` being active after new should directly fall from
> the definition of active member in
> https://eel.is/c++draft/class.union#general-2:
> > In a union, a non-static data member is active if its name refers to an 
> > object whose lifetime has begun and has not ended ([basic.life]).
> 
> So if new operations, starts lifetime of member of the union (regardless of
> how) it becomes active member of the union, until it's lifetime is ended. I
> do not think that syntax how does it happen matters.

Sure, that matches this comment in cxx_eval_store_expression:
  /* An INIT_EXPR of the last member in an access chain is always OK,   

so I tried changing the clobber to happen regardless of the syntax of the
placement argument.  This mostly worked well, including fixing an xfail in one
of the constexpr new tests.  But it also ran into trouble on the current
libstdc++ construct_at, which when told to construct a _Tp where _Tp is an
array type, instead tries to construct a _Tp[1], which seems undefined to me;
there is no such multidimensional array at that location.

This is related to LWG issue 3436.  The proposed resolution there seems
reasonable, so I'm trying this library change:

index 217a0416d42..1ba9740e90d 100644
--- a/libstdc++-v3/include/bits/stl_construct.h
+++ b/libstdc++-v3/include/bits/stl_construct.h
@@ -104,7 +104,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
  static_assert(sizeof...(_Args) == 0, "std::construct_at for array "
   "types must not use any arguments to initialize the "
   "array");
- return ::new(__loc) _Tp[1]();
+ __loc = ::new(__loc) _Tp();
+#if __cpp_lib_launder
+ return std::launder(__location);
+#else
+ return static_cast<_Tp*>(__loc);
+#endif

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-17 Thread tkaminsk at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #7 from Tomasz Kamiński  ---
Or in other words, I believe my example is equivalent to implementation of
optional,
where we have:
union {
  T val;
};

And then call:
  new(static_cast(addressof(val))) T(...);
It is just version were T is array.

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-17 Thread tkaminsk at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #6 from Tomasz Kamiński  ---
I believed that `_member` being active after new should directly fall from the
definition of active member in https://eel.is/c++draft/class.union#general-2:
> In a union, a non-static data member is active if its name refers to an 
> object whose lifetime has begun and has not ended ([basic.life]).

So if new operations, starts lifetime of member of the union (regardless of
how) it becomes active member of the union, until it's lifetime is ended. I do
not think that syntax how does it happen matters.

The unclear case, would be if creating element of array member, should start
the union, i.e. something like:
new (&union_.member[2]) T;

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-17 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #5 from Jason Merrill  ---
The intent of the patch was to support 
  new (&union_.member) T
syntax like
  union_.member = T()
for setting the active member, as in
https://eel.is/c++draft/class.union#general-example-3
but adding the library fluff obscures that syntax, and so is less clear that it
ought to work.

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-17 Thread tkaminsk at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #4 from Tomasz Kamiński  ---
Hi, the original example works, but when I start to add library fluff, I get
the same error. I mean cases like:
// passing address to actual member
new(&arr) T[3];
new(std::addressof(arr)) T[3]; // Disable overload op&

// Disabling ADL
new(static_cast(arr)) T[3];
new(static_cast(&arr)) T[3];
new(static_cast(std::addressof(arr))) T[3];

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-16 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #3 from Jason Merrill  ---
Created attachment 61891
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61891&action=edit
fix

Let me know how this works for you.

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-16 Thread tkaminsk at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

--- Comment #2 from Tomasz Kamiński  ---
That is indeed very surprising, as it would mean that if I have:
```
struct S {
  union {
int x;
  };
};

constexpr S test()
{
  S s;
  new(&s.x) int;
  is_active_member(s.x); // this is false
}
```
One we have ability to ask for active member, we can observe if new marked it
active.

However, marking the member as active is also breaking, as following will no
longer compiler:
```
constexpr S create()
{
   S s;
   new(&s.x) int;
   return s;
}

constexpr S g = create(); // OK now, x is not active,
  // ILL-FORMED if new will start lifetime of s.x
```
But I think this should be ILL-FORMED.

[Bug c++/121068] Placement new of array element is rejected at compile-time

2025-07-16 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121068

Jason Merrill  changed:

   What|Removed |Added

 CC||jason at gcc dot gnu.org

--- Comment #1 from Jason Merrill  ---
Ah, the actual bug is that we don't represent the first array new because it's
trivial default initialization, and we don't represent the trivial
pseudo-destructor calls, so we don't see any access to arr until we get to
actually trying to give it a value.

The error is correct under the current standard, but I want to make it
well-formed by making the first array new make arr the active member.