On Fri, May 15, 2026 at 06:05:29PM -0400, Patrick Palka wrote:
> On Fri, 15 May 2026, Marek Polacek wrote:
>
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/branches?
> >
> > -- >8 --
> > When looking into 125315 I came up with another test that crashes
> > due to an empty object. It still crashes even after Jason's patch.
> >
> > Here we have a subobject nested in an empty object:
> >
> > {.w = {.v = TARGET_EXPR <f(s)>}}
> >
> > w's type is W, an empty union due to [[no_unique_address]], so
> > init_subob_ctx clears the ctor, but then we recurse to
> >
> > {.v = TARGET_EXPR <f(s)>}
> >
> > with a null ctx->ctor so the call to get_or_insert_ctor_field in
> > cxx_eval_bare_aggregate crashes. This fixes the crash similarly
> > to c++/125315.
> >
> > no_unique_address18.C worked fine even before this patch because
> > there we don't have an empty object. But let's test it also.
> >
> > PR c++/125336
> >
> > gcc/cp/ChangeLog:
> >
> > * constexpr.cc (cxx_eval_bare_aggregate): Don't call
> > get_or_insert_ctor_field when there is no CONSTRUCTOR. Assert
> > is_empty_class.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * g++.dg/cpp2a/no_unique_address17.C: New test.
> > * g++.dg/cpp2a/no_unique_address18.C: New test.
> > ---
> > gcc/cp/constexpr.cc | 8 ++++++--
> > gcc/testsuite/g++.dg/cpp2a/no_unique_address17.C | 12 ++++++++++++
> > gcc/testsuite/g++.dg/cpp2a/no_unique_address18.C | 12 ++++++++++++
> > 3 files changed, 30 insertions(+), 2 deletions(-)
> > create mode 100644 gcc/testsuite/g++.dg/cpp2a/no_unique_address17.C
> > create mode 100644 gcc/testsuite/g++.dg/cpp2a/no_unique_address18.C
> >
> > diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> > index 1fc8a56503c..84896170d05 100644
> > --- a/gcc/cp/constexpr.cc
> > +++ b/gcc/cp/constexpr.cc
> > @@ -6841,7 +6841,11 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx,
> > tree t,
> > /* Like in cxx_eval_store_expression, omit entries for empty fields.
> > */
> > bool no_slot = new_ctx.ctor == NULL_TREE;
> > int pos_hint = -1;
> > - if (new_ctx.ctor != ctx->ctor && !no_slot)
> > + if (!ctx->ctor)
> > + /* The enclosing object could be an empty subobject so we have no
> > + CONSTRUCTOR (c++/125336). */
> > + gcc_checking_assert (is_empty_class (type));
> > + else if (new_ctx.ctor != ctx->ctor && !no_slot)
> > {
> > /* If we built a new CONSTRUCTOR, attach it now so that other
> > initializers can refer to it. */
> > @@ -6892,7 +6896,7 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx,
> > tree t,
> > gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (index))));
> > changed = true;
> > }
> > - else
> > + else if (ctx->ctor)
> > {
> > if (TREE_CODE (type) == UNION_TYPE
> > && (*p)->last().index != index)
> > diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address17.C
> > b/gcc/testsuite/g++.dg/cpp2a/no_unique_address17.C
> > new file mode 100644
> > index 00000000000..11099698a9b
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address17.C
> > @@ -0,0 +1,12 @@
> > +// PR c++/125336
> > +// { dg-do compile { target c++20 } }
> > +// { dg-prune-output "used but never defined" }
>
> The "used but never defined" warning implies the testcase is UB right?
> Would be nice to have a valid testcase that triggers this bug.
It would be very nice but I don't know how to construct such
a test. If the class didn't have to be empty, I would know
how. To exhibit the problem we need to call cxx_eval_bare_aggregate
which is not going to happen when the CONSTRUCTOR is constant. If
a constexpr function calls a non-constexpr function, we trigger the
bug but it's again invalid code. This is valid but it doesn't show
the ICE because we don't have a nested { }:
struct A { constexpr A(int) { } };
struct S { [[no_unique_address]] A a; };
constexpr S f(int n) { return S{A{n}}; }
union W {
[[no_unique_address]] S v;
};
struct R { W w; };
auto x = R{{ f(1) }};
Marek