On 7/4/22 11:50, Jakub Jelinek wrote:
On Mon, Jun 27, 2022 at 06:31:18PM +0200, Jakub Jelinek via Gcc-patches wrote:

Hmm, why do we need to handle complex in the !preeval case?  I'd think we
want to preevaluate all complex values or components thereof.

Because the late evaluation of the initializer could have touched
the destination, so we need to reevaluate it.
Same reason why we call get_or_insert_ctor_field again in the second
loop as we call it in the first loop.

But preeval should always be true, so we'd never reach the new handling in the if (!preeval) block. Certainly the new testcase doesn't exercise this code.

If it would help, I could move that repeated part into:

This seems like it needs to come before the ctors loop, so that these flags
can be propagated out to enclosing constructors.

I could indeed move this in between
   bool c = TREE_CONSTANT (init);
   bool s = TREE_SIDE_EFFECTS (init);
and
   if (!c || s || activated_union_member_p)
and update c and s from *cexpr flags.

Here is it in patch form, so far lightly tested, ok for trunk if it passes
full bootstrap/regtest?

2022-07-04  Jakub Jelinek  <ja...@redhat.com>

        PR c++/88174
        * constexpr.cc (canonicalize_complex_to_complex_expr): New function.
        (cxx_eval_store_expression): Handle REALPART_EXPR and IMAGPART_EXPR.
        Change ctors from releasing_vec to auto_vec<tree *>, adjust all uses.

        * g++.dg/cpp1y/constexpr-complex1.C: New test.

--- gcc/cp/constexpr.cc.jj      2022-07-04 12:26:18.147053851 +0200
+++ gcc/cp/constexpr.cc 2022-07-04 17:35:53.100556949 +0200
@@ -5640,6 +5640,26 @@ modifying_const_object_p (tree_code code
    return false;
  }
+/* Helper of cxx_eval_store_expression, turn a COMPLEX_CST or
+   empty no clearing CONSTRUCTOR into a COMPLEX_EXPR.  */
+
+static tree
+canonicalize_complex_to_complex_expr (tree t)
+{
+  if (TREE_CODE (t) == COMPLEX_CST)
+    t = build2 (COMPLEX_EXPR, TREE_TYPE (t),
+               TREE_REALPART (t), TREE_IMAGPART (t));
+  else if (TREE_CODE (t) == CONSTRUCTOR
+          && CONSTRUCTOR_NELTS (t) == 0
+          && CONSTRUCTOR_NO_CLEARING (t))
+    {
+      tree r = build_constructor (TREE_TYPE (TREE_TYPE (t)), NULL);
+      CONSTRUCTOR_NO_CLEARING (r) = 1;
+      t = build2 (COMPLEX_EXPR, TREE_TYPE (t), r, r);
+    }
+  return t;
+}
+
  /* Evaluate an INIT_EXPR or MODIFY_EXPR.  */
static tree
@@ -5726,6 +5746,20 @@ cxx_eval_store_expression (const constex
          }
          break;
+ case REALPART_EXPR:
+         gcc_assert (probe == target);
+         vec_safe_push (refs, probe);
+         vec_safe_push (refs, TREE_TYPE (probe));
+         probe = TREE_OPERAND (probe, 0);
+         break;
+
+       case IMAGPART_EXPR:
+         gcc_assert (probe == target);
+         vec_safe_push (refs, probe);
+         vec_safe_push (refs, TREE_TYPE (probe));
+         probe = TREE_OPERAND (probe, 0);
+         break;
+
        default:
          if (evaluated)
            object = probe;
@@ -5764,7 +5798,8 @@ cxx_eval_store_expression (const constex
    type = TREE_TYPE (object);
    bool no_zero_init = true;
- releasing_vec ctors, indexes;
+  auto_vec<tree *> ctors;
+  releasing_vec indexes;
    auto_vec<int> index_pos_hints;
    bool activated_union_member_p = false;
    bool empty_base = false;
@@ -5804,14 +5839,26 @@ cxx_eval_store_expression (const constex
          *valp = ary_ctor;
        }
- /* If the value of object is already zero-initialized, any new ctors for
-        subobjects will also be zero-initialized.  */
-      no_zero_init = CONSTRUCTOR_NO_CLEARING (*valp);
-
        enum tree_code code = TREE_CODE (type);
        tree reftype = refs->pop();
        tree index = refs->pop();
+ if (code == COMPLEX_TYPE)
+       {
+         *valp = canonicalize_complex_to_complex_expr (*valp);
+         gcc_assert (TREE_CODE (*valp) == COMPLEX_EXPR);
+         ctors.safe_push (valp);
+         vec_safe_push (indexes, index);
+         valp = &TREE_OPERAND (*valp, TREE_CODE (index) == IMAGPART_EXPR);
+         gcc_checking_assert (refs->is_empty ());
+         type = reftype;
+         break;
+       }
+
+      /* If the value of object is already zero-initialized, any new ctors for
+        subobjects will also be zero-initialized.  */
+      no_zero_init = CONSTRUCTOR_NO_CLEARING (*valp);
+
        if (code == RECORD_TYPE && is_empty_field (index))
        /* Don't build a sub-CONSTRUCTOR for an empty base or field, as they
           have no data and might have an offset lower than previously declared
@@ -5854,7 +5901,7 @@ cxx_eval_store_expression (const constex
          no_zero_init = true;
        }
- vec_safe_push (ctors, *valp);
+      ctors.safe_push (valp);
        vec_safe_push (indexes, index);
constructor_elt *cep
@@ -5916,11 +5963,11 @@ cxx_eval_store_expression (const constex
             semantics are not applied on an object under construction.
             They come into effect when the constructor for the most
             derived object ends."  */
-         for (tree elt : *ctors)
+         for (tree *elt : ctors)
            if (same_type_ignoring_top_level_qualifiers_p
-               (TREE_TYPE (const_object_being_modified), TREE_TYPE (elt)))
+               (TREE_TYPE (const_object_being_modified), TREE_TYPE (*elt)))
              {
-               fail = TREE_READONLY (elt);
+               fail = TREE_READONLY (*elt);
                break;
              }
        }
@@ -5961,6 +6008,16 @@ cxx_eval_store_expression (const constex
        valp = ctx->global->values.get (object);
        for (unsigned i = 0; i < vec_safe_length (indexes); i++)
        {
+         ctors[i] = valp;
+         if (TREE_CODE (indexes[i]) == REALPART_EXPR
+             || TREE_CODE (indexes[i]) == IMAGPART_EXPR)
+           {
+             *valp = canonicalize_complex_to_complex_expr (*valp);
+             gcc_assert (TREE_CODE (*valp) == COMPLEX_EXPR);
+             valp = &TREE_OPERAND (*valp,
+                                   TREE_CODE (indexes[i]) == IMAGPART_EXPR);
+             break;
+           }
          constructor_elt *cep
            = get_or_insert_ctor_field (*valp, indexes[i], index_pos_hints[i]);
          valp = &cep->value;
@@ -6023,17 +6080,45 @@ cxx_eval_store_expression (const constex
       CONSTRUCTORs, if any.  */
    bool c = TREE_CONSTANT (init);
    bool s = TREE_SIDE_EFFECTS (init);
+  if (!indexes->is_empty ())
+    {
+      tree last = indexes->last ();
+      if (TREE_CODE (last) == REALPART_EXPR
+         || TREE_CODE (last) == IMAGPART_EXPR)
+       {
+         /* And canonicalize COMPLEX_EXPR into COMPLEX_CST if
+            possible.  */
+         tree *cexpr = ctors.last ();
+         if (tree c = const_binop (COMPLEX_EXPR, TREE_TYPE (*cexpr),
+                                   TREE_OPERAND (*cexpr, 0),
+                                   TREE_OPERAND (*cexpr, 1)))
+           *cexpr = c;
+         else
+           {
+             TREE_CONSTANT (*cexpr)
+               = (TREE_CONSTANT (TREE_OPERAND (*cexpr, 0))
+                  & TREE_CONSTANT (TREE_OPERAND (*cexpr, 1)));
+             TREE_SIDE_EFFECTS (*cexpr)
+               = (TREE_SIDE_EFFECTS (TREE_OPERAND (*cexpr, 0))
+                  | TREE_SIDE_EFFECTS (TREE_OPERAND (*cexpr, 1)));
+           }
+         c = TREE_CONSTANT (*cexpr);
+         s = TREE_SIDE_EFFECTS (*cexpr);
+       }
+    }
    if (!c || s || activated_union_member_p)
-    for (tree elt : *ctors)
+    for (tree *elt : ctors)
        {
+       if (TREE_CODE (*elt) != CONSTRUCTOR)
+         continue;
        if (!c)
-         TREE_CONSTANT (elt) = false;
+         TREE_CONSTANT (*elt) = false;
        if (s)
-         TREE_SIDE_EFFECTS (elt) = true;
+         TREE_SIDE_EFFECTS (*elt) = true;
        /* Clear CONSTRUCTOR_NO_CLEARING since we've activated a member of
           this union.  */
-       if (TREE_CODE (TREE_TYPE (elt)) == UNION_TYPE)
-         CONSTRUCTOR_NO_CLEARING (elt) = false;
+       if (TREE_CODE (TREE_TYPE (*elt)) == UNION_TYPE)
+         CONSTRUCTOR_NO_CLEARING (*elt) = false;
        }
if (lval)
--- gcc/testsuite/g++.dg/cpp1y/constexpr-complex1.C.jj  2022-07-04 
17:30:47.884580998 +0200
+++ gcc/testsuite/g++.dg/cpp1y/constexpr-complex1.C     2022-07-04 
17:30:47.884580998 +0200
@@ -0,0 +1,24 @@
+// PR c++/88174
+// { dg-do compile { target c++14 } }
+
+constexpr bool
+foo (double x, double y, double z, double w)
+{
+  __complex__ double a = 0;
+  __real__ a = x;
+  __imag__ a = y;
+#if __cpp_constexpr >= 201907L
+  __complex__ double b;
+  __real__ b = z;
+#else
+  __complex__ double b = z;
+#endif
+  __imag__ b = w;
+  a += b;
+  a -= b;
+  a *= b;
+  a /= b;
+  return __real__ a == x && __imag__ a == y;
+}
+
+static_assert (foo (1.0, 2.0, 3.0, 4.0), "");


        Jakub


Reply via email to