https://gcc.gnu.org/g:38228ed4281a2a3beb0ac920085861cd300c1d6f
commit r15-11166-g38228ed4281a2a3beb0ac920085861cd300c1d6f Author: Egas Ribeiro <[email protected]> Date: Thu May 14 12:19:54 2026 -0400 c++: fix constexpr union with empty member [PR123346] r14-2820 changed cxx_eval_bare_aggregate to set no_slot based on whether new_ctx.ctor is NULL_TREE, to handle empty subobject elision. However this incorrectly omits entries for empty union members, which later need the entry to exist. This caused valid code to be rejected as non-constant after gcc 13.3, and in trunk caused an ICE when the diagnostic code tries to print a CONSTRUCTOR with a null value. PR c++/123346 gcc/cp/ChangeLog: * constexpr.cc (init_subob_ctx): Do initialize new_ctx.ctor for an empty union member. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/constexpr-union10.C: New test. Signed-off-by: Egas Ribeiro <[email protected]> Co-authored-by: Jason Merrill <[email protected]> (cherry picked from commit 92a1d876b20426ebd240ad9bd65d9bce2705611d) Diff: --- gcc/cp/constexpr.cc | 18 ++++++++++++++---- gcc/testsuite/g++.dg/cpp2a/constexpr-union10.C | 8 ++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index fb8a9a4211b2..b07e4bdec6b9 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -5428,8 +5428,17 @@ init_subob_ctx (const constexpr_ctx *ctx, constexpr_ctx &new_ctx, if (!AGGREGATE_TYPE_P (type) && !VECTOR_TYPE_P (type)) /* A non-aggregate member doesn't get its own CONSTRUCTOR. */ return; + + tree ctxtype = NULL_TREE; + if (ctx->ctor) + ctxtype = TREE_TYPE (ctx->ctor); + else if (ctx->object) + ctxtype = TREE_TYPE (ctx->object); + else + gcc_unreachable (); + if (VECTOR_TYPE_P (type) - && VECTOR_TYPE_P (TREE_TYPE (ctx->ctor)) + && VECTOR_TYPE_P (ctxtype) && index == NULL_TREE) /* A vector inside of a vector CONSTRUCTOR, e.g. when a larger vector is constructed from smaller vectors, doesn't get its own @@ -5448,9 +5457,10 @@ init_subob_ctx (const constexpr_ctx *ctx, constexpr_ctx &new_ctx, new_ctx.object = build_ctor_subob_ref (index, type, ctx->object); } - if (is_empty_class (type)) - /* Leave ctor null for an empty subobject, they aren't represented in the - result of evaluation. */ + if (is_empty_class (type) + && TREE_CODE (ctxtype) != UNION_TYPE) + /* Leave ctor null for an empty subobject of a non-union class, they aren't + represented in the result of evaluation. */ new_ctx.ctor = NULL_TREE; else { diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-union10.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-union10.C new file mode 100644 index 000000000000..36b0fe8fa1b5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-union10.C @@ -0,0 +1,8 @@ +// PR c++/123346 +// { dg-do compile { target c++20 } } +struct Unit {}; +union Union { Unit unit; }; +constexpr Union make(Union&& other) { + return Union {.unit = other.unit }; +} +constexpr Union u = make(Union { .unit = Unit{} });
