https://gcc.gnu.org/g:660fa7fd354b71f864f67e5e1966a6e62f8a2c3b

commit r14-12605-g660fa7fd354b71f864f67e5e1966a6e62f8a2c3b
Author: Egas Ribeiro <[email protected]>
Date:   Thu May 14 12:20:23 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 6ec87be560b6..55086b930e73 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -5285,8 +5285,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
@@ -5305,9 +5314,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{} });

Reply via email to