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

commit r16-2265-gf23b5df56e237df9f66b615ca4babc564d5f75de
Author: Jason Merrill <ja...@redhat.com>
Date:   Sat Jul 12 05:15:01 2025 -0400

    c++: constexpr uninitialized union [PR120577]
    
    This was failing for two reasons:
    
    1) We were wrongly treating the basic_string constructor as
    zero-initializing the object, which it doesn't.
    2) Given that, when we went to look for a value for the anonymous union,
    we concluded that it was value-initialized, and trying to evaluate that
    broke because we weren't setting ctx->ctor for it.
    
    This patch fixes both issues, #1 by setting CONSTRUCTOR_NO_CLEARING and #2
    by inserting a new CONSTRUCTOR for the member rather than evaluate it out of
    context, which is consistent with cxx_eval_store_expression.
    
            PR c++/120577
    
    gcc/cp/ChangeLog:
    
            * constexpr.cc (cxx_eval_call_expression): Set
            CONSTRUCTOR_NO_CLEARING on initial value for ctor.
            (cxx_eval_component_reference): Make value-initialization
            of an aggregate member explicit.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp2a/constexpr-union9.C: New test.

Diff:
---
 gcc/cp/constexpr.cc                           | 18 ++++++++++++---
 gcc/testsuite/g++.dg/cpp2a/constexpr-union9.C | 33 +++++++++++++++++++++++++++
 2 files changed, 48 insertions(+), 3 deletions(-)

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index eb19784dbbaa..ee06858f7153 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -4201,10 +4201,10 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, 
tree t,
              && TREE_CODE (new_obj) == COMPONENT_REF
              && TREE_CODE (TREE_TYPE (TREE_OPERAND (new_obj, 0))) == 
UNION_TYPE)
            {
+             tree ctor = build_constructor (TREE_TYPE (new_obj), NULL);
+             CONSTRUCTOR_NO_CLEARING (ctor) = true;
              tree activate = build2 (INIT_EXPR, TREE_TYPE (new_obj),
-                                     new_obj,
-                                     build_constructor (TREE_TYPE (new_obj),
-                                                        NULL));
+                                     new_obj, ctor);
              cxx_eval_constant_expression (ctx, activate,
                                            lval, non_constant_p, overflow_p,
                                            jump_target);
@@ -5793,6 +5793,18 @@ cxx_eval_component_reference (const constexpr_ctx *ctx, 
tree t,
     }
 
   /* If there's no explicit init for this field, it's value-initialized.  */
+
+  if (AGGREGATE_TYPE_P (TREE_TYPE (t)))
+    {
+      /* As in cxx_eval_store_expression, insert an empty CONSTRUCTOR
+        and copy the flags.  */
+      constructor_elt *e = get_or_insert_ctor_field (whole, part);
+      e->value = value = build_constructor (TREE_TYPE (part), NULL);
+      CONSTRUCTOR_ZERO_PADDING_BITS (value)
+       = CONSTRUCTOR_ZERO_PADDING_BITS (whole);
+      return value;
+    }
+
   value = build_value_init (TREE_TYPE (t), tf_warning_or_error);
   return cxx_eval_constant_expression (ctx, value,
                                       lval,
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-union9.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-union9.C
new file mode 100644
index 000000000000..7db1030ab200
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-union9.C
@@ -0,0 +1,33 @@
+// PR c++/120577
+// { dg-do compile { target c++20 } }
+
+template <class _Tp> struct optional {
+  union {
+    _Tp __val_;
+  };
+  template <class... _Args>
+  constexpr optional(_Args... __args)
+      : __val_(__args...) {}
+};
+template <class _Tp, class... _Args>
+constexpr optional<_Tp> make_optional(_Args... __args) {
+  return optional<_Tp>(__args...);
+}
+
+struct __non_trivial_if {
+  constexpr __non_trivial_if() {}
+};
+struct allocator : __non_trivial_if {};
+struct __padding {};
+struct __short {
+  [[__no_unique_address__]] __padding __padding_;
+  int __data_;
+};
+struct basic_string {
+  union {
+    __short __s;
+  };
+  [[__no_unique_address__]] allocator __alloc_;
+  constexpr basic_string(int, int) {}
+};
+auto opt = make_optional<basic_string>(4, 'X');

Reply via email to