[PATCH] c++, libstdc++, v2: Implement C++26 P3074R7, P3726R0 and CWG3189 - trivial unions [PR119059]

Jakub Jelinek jakub@redhat.com
Thu May 21 09:13:32 GMT 2026


On Thu, May 21, 2026 at 11:01:57AM +0200, Tomasz Kaminski wrote:
> > That what I assumed with current inplace_vector, that zeroes all elements
> > of array at compile time. But with the start_lifetime, constexpr
> > FixedVector<char, 4> res{'a', 'b', 'c'};
> > It also contains the same out of lifetime element, as return {'a', 'b',
> > 'c'} would.
> >
> > I think the expecation from
> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124121
> > is that `return FixedVector<char, 4>{'a', 'b', 'c'}` would constant-fold
> > creation of
> > fixed vector, and be equivalent to `constexpr FixedVector<char, 4>
> > res{'a', 'b', 'c'}; return res;`.
> >
> That expectation may be misplaced. I have no intuition about when
> constant-folding occurs for
> compilers.

In the constexpr case, the FE turns it into a CONSTRUCTOR with all the
elements, so it is then handled as if it is a return (S) { { 'a', 'b', 'c' }, 3 };
or similar.

Anyway, after some initial optimizations, we are talking about the
differences between (first 4 are the ones from the C testcase I've posted,
the last one slightly different from the FixedVector case):
  MEM <unsigned char[3]> [(char * {ref-all})&r] = "abc";
  r.b = 3;
  D.2981 = r;
  r ={v} {CLOBBER(eos)};
  return D.2981;
vs.
  MEM <unsigned short> [(unsigned char *)&D.2984] = 25185;
  D.2984.a[2] = 99;
  D.2984.b = 3;
  return D.2984;
vs.
  MEM <unsigned int> [(struct S *)&D.2987] = 1684234849;
  D.2987.b = 4;
  return D.2987;
vs.
  MEM <unsigned int> [(unsigned char *)&D.2990] = 1684234849;
  D.2990.b = 4;
  return D.2990;
vs. (FixedVector):
  static const char C.0[3] = {97, 98, 99};
  struct FixedVector & _4(D);

  MEM <unsigned char[3]> [(char * {ref-all})_4(D)] = MEM <unsigned char[3]> [(char * {ref-all})&C.0];
  *_4(D).size = 3;
  return _4(D);
vs.
  MEM <unsigned long> [(void *)res_2(D)] = 6513249;
  MEM <unsigned long> [(void *)res_2(D) + 8B] = 3;
  return res_2(D);

Note, the second case is a result of store merging
  D.2984.a[0] = 97;
  D.2984.a[1] = 98;
  D.2984.a[2] = 99;
  D.2984.b = 3;
  return D.2984;
In the baz/qux case (third/fourth), before store merging it is
  D.2990.a[0] = 97;
  D.2990.a[1] = 98;
  D.2990.a[2] = 99;
  D.2990.a[3] = 100;
  D.2990.b = 4;
  return D.2990;
in one case and store merging turns it into exactly what the
other case was already before.

	Jakub



More information about the Libstdc++ mailing list