Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

Here constexpr evaluation was getting confused by the result of
split_nonconstant_init, which leaves an INIT_EXPR from an empty CONSTRUCTOR
to be followed by member initialization.  As a result
CONSTRUCTOR_NO_CLEARING was set for the time_zone, and
cxx_eval_store_expression didn't set it again for the initial clobber in the
basic_string constructor, so when cxx_fold_indirect_ref wants to check
whether the anonymous union active member had type non_trivial_if, we see
that we don't currently have a value for the anonymous union, try to add
one, and fail.

So let's do constexpr evaluation before split_nonconstant_init.

        PR c++/120502

gcc/cp/ChangeLog:

        * cp-gimplify.cc (cp_fold_r) [TARGET_EXPR]: Do constexpr evaluation
        before genericize.
        * constexpr.cc (cxx_eval_store_expression): Add comment.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/constexpr-prvalue2.C: New test.
---
 gcc/cp/constexpr.cc                           |  3 ++-
 gcc/cp/cp-gimplify.cc                         | 21 +++++++++------
 .../g++.dg/cpp2a/constexpr-prvalue2.C         | 26 +++++++++++++++++++
 3 files changed, 41 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue2.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index b9fdc94b961..c0e37b2fd35 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -6413,7 +6413,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree 
t,
 
   if (TREE_CLOBBER_P (init)
       && CLOBBER_KIND (init) < CLOBBER_OBJECT_END)
-    /* Only handle clobbers ending the lifetime of objects.  */
+    /* Only handle clobbers ending the lifetime of objects.
+       ??? We should probably set CONSTRUCTOR_NO_CLEARING.  */
     return void_node;
 
   /* First we figure out where we're storing to.  */
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 16def885127..0fcfa16d2c5 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -1473,6 +1473,19 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
       break;
 
     case TARGET_EXPR:
+      if (!flag_no_inline)
+       if (tree &init = TARGET_EXPR_INITIAL (stmt))
+         {
+           tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt),
+                                              (data->flags & ff_mce_false
+                                               ? mce_false : mce_unknown));
+           if (folded != init && TREE_CONSTANT (folded))
+             init = folded;
+         }
+
+      /* This needs to happen between the constexpr evaluation (which wants
+        pre-generic trees) and fold (which wants the cp_genericize_init
+        transformations).  */
       if (data->flags & ff_genericize)
        cp_genericize_target_expr (stmt_p);
 
@@ -1481,14 +1494,6 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
          cp_walk_tree (&init, cp_fold_r, data, NULL);
          cp_walk_tree (&TARGET_EXPR_CLEANUP (stmt), cp_fold_r, data, NULL);
          *walk_subtrees = 0;
-         if (!flag_no_inline)
-           {
-             tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt),
-                                                (data->flags & ff_mce_false
-                                                 ? mce_false : mce_unknown));
-             if (folded != init && TREE_CONSTANT (folded))
-               init = folded;
-           }
          /* Folding might replace e.g. a COND_EXPR with a TARGET_EXPR; in
             that case, strip it in favor of this one.  */
          if (TREE_CODE (init) == TARGET_EXPR)
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue2.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue2.C
new file mode 100644
index 00000000000..c2dc7cd4945
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue2.C
@@ -0,0 +1,26 @@
+// PR c++/120502
+// { dg-do compile { target c++20 } }
+// { dg-additional-options -O }
+
+struct non_trivial_if {
+  constexpr non_trivial_if() {}
+};
+struct allocator : non_trivial_if {};
+struct padding {};
+struct __short {
+  [[no_unique_address]] padding p;
+};
+struct basic_string {
+  union {
+    __short s;
+    int l;
+  };
+  [[no_unique_address]] allocator a;
+  constexpr basic_string() {}
+  ~basic_string() {}
+};
+struct time_zone {
+  basic_string __abbrev;
+  long __offset;
+};
+time_zone convert_to_time_zone() { return {}; }

base-commit: 01044e0ee27093a3990996578b15f6ab69ed3395
-- 
2.49.0

Reply via email to