c++: Don't shortcut TREE_CONSTANT vector type CONSTRUCTORs in cxx_eval_constant_expre...
authorJakub Jelinek <jakub@redhat.com>
Fri, 21 Oct 2022 16:04:54 +0000 (18:04 +0200)
committerJakub Jelinek <jakub@redhat.com>
Fri, 21 Oct 2022 16:04:54 +0000 (18:04 +0200)
The excess precision support broke building skia (dependency of firefox)
on ia32 (it has something like the a constexpr variable), but as the other
cases show, it is actually a preexisting problem if one uses casts from
constants with wider floating point types.
The problem is that cxx_eval_constant_expression tries to short-cut
processing of TREE_CONSTANT CONSTRUCTORs if they satisfy
reduced_constant_expression_p - instead of calling cxx_eval_bare_aggregate
on them it just verifies flags and if they are TREE_CONSTANT even after
that, just fold.
Now, on the testcase we have a TREE_CONSTANT CONSTRUCTOR containing
TREE_CONSTANT NOP_EXPR of REAL_CST.  And, fold, which isn't recursive,
doesn't optimize that into VECTOR_CST, while later on we are only able
to optimize VECTOR_CST arithmetics, not arithmetics with vector
CONSTRUCTORs.
The following patch fixes that by rejecting CONSTRUCTORs with vector type
in reduced_constant_expression_p regardless of whether they have
CONSTRUCTOR_NO_CLEARING set or not, folding result in cxx_eval_bare_aggregate
even if nothing has changed but it wasn't non-constant and removing folding
from the TREE_CONSTANT reduced_constant_expression_p short-cut.

2022-10-21  Jakub Jelinek  <jakub@redhat.com>

PR c++/107295
* constexpr.cc (reduced_constant_expression_p) <case CONSTRUCTOR>:
Return false for VECTOR_TYPE CONSTRUCTORs even without
CONSTRUCTOR_NO_CLEARING set on them.
(cxx_eval_bare_aggregate): If constant but !changed, fold before
returning VECTOR_TYPE_P CONSTRUCTOR.
(cxx_eval_constant_expression) <case CONSTRUCTOR>: Don't fold
TREE_CONSTANT CONSTRUCTOR, just return it.

* g++.dg/ext/vector42.C: New test.

gcc/cp/constexpr.cc
gcc/testsuite/g++.dg/ext/vector42.C [new file with mode: 0644]

index 0366396..c3ee970 100644 (file)
@@ -3104,12 +3104,12 @@ reduced_constant_expression_p (tree t)
     case CONSTRUCTOR:
       /* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR.  */
       tree field;
+      if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
+       /* An initialized vector would have a VECTOR_CST.  */
+       return false;
       if (CONSTRUCTOR_NO_CLEARING (t))
        {
-         if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
-           /* An initialized vector would have a VECTOR_CST.  */
-           return false;
-         else if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
+         if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE)
            {
              /* There must be a valid constant initializer at every array
                 index.  */
@@ -4956,8 +4956,14 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree t,
          TREE_SIDE_EFFECTS (ctx->ctor) = side_effects_p;
        }
     }
-  if (*non_constant_p || !changed)
+  if (*non_constant_p)
     return t;
+  if (!changed)
+    {
+      if (VECTOR_TYPE_P (type))
+       t = fold (t);
+      return t;
+    }
   t = ctx->ctor;
   if (!t)
     t = build_constructor (type, NULL);
@@ -7387,11 +7393,10 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
     case CONSTRUCTOR:
       if (TREE_CONSTANT (t) && reduced_constant_expression_p (t))
        {
-         /* Don't re-process a constant CONSTRUCTOR, but do fold it to
-            VECTOR_CST if applicable.  */
+         /* Don't re-process a constant CONSTRUCTOR.  */
          verify_constructor_flags (t);
          if (TREE_CONSTANT (t))
-           return fold (t);
+           return t;
        }
       r = cxx_eval_bare_aggregate (ctx, t, lval,
                                   non_constant_p, overflow_p);
diff --git a/gcc/testsuite/g++.dg/ext/vector42.C b/gcc/testsuite/g++.dg/ext/vector42.C
new file mode 100644 (file)
index 0000000..e781097
--- /dev/null
@@ -0,0 +1,12 @@
+// PR c++/107295
+// { dg-do compile { target c++11 } }
+
+template <typename T> struct A {
+  typedef T __attribute__((vector_size (sizeof (int)))) V;
+};
+template <int, typename T> using B = typename A<T>::V;
+template <typename T> using V = B<4, T>;
+using F = V<float>;
+constexpr F a = F () + 0.0f;
+constexpr F b = F () + (float) 0.0;
+constexpr F c = F () + (float) 0.0L;