c++: Don't shortcut TREE_CONSTANT vector type CONSTRUCTORs in cxx_eval_constant_expression [PR107295]

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.
This commit is contained in:
Jakub Jelinek 2022-10-21 18:04:54 +02:00
parent bf3b532b52
commit 2cc41601d9
2 changed files with 25 additions and 8 deletions

View 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);

View File

@ -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;