fold-const: Fix ICE in extract_muldiv_1 [PR99777]

extract_muldiv{,_1} is apparently only prepared to handle scalar integer
operations, the callers ensure it by only calling it if the divisor or
one of the multiplicands is INTEGER_CST and because neither multiplication
nor division nor modulo are really supported e.g. for pointer types, nullptr
type etc.  But the CASE_CONVERT handling doesn't really check if it isn't
a cast from some other type kind, so on the testcase we end up trying to
build MULT_EXPR in POINTER_TYPE which ICEs.  A few years ago Marek has
added ANY_INTEGRAL_TYPE_P checks to two spots, but the code uses
TYPE_PRECISION which means something completely different for vector types,
etc.
So IMNSHO we should just punt on conversions from non-integrals or
non-scalar integrals.

2021-03-29  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/99777
	* fold-const.c (extract_muldiv_1): For conversions, punt on casts from
	types other than scalar integral types.

	* g++.dg/torture/pr99777.C: New test.
This commit is contained in:
Jakub Jelinek 2021-03-29 12:35:32 +02:00
parent d579e2e76f
commit 25e515d219
2 changed files with 48 additions and 4 deletions

View File

@ -6713,6 +6713,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
break;
CASE_CONVERT: case NON_LVALUE_EXPR:
if (!INTEGRAL_TYPE_P (TREE_TYPE (op0)))
break;
/* If op0 is an expression ... */
if ((COMPARISON_CLASS_P (op0)
|| UNARY_CLASS_P (op0)
@ -6721,8 +6723,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
|| EXPRESSION_CLASS_P (op0))
/* ... and has wrapping overflow, and its type is smaller
than ctype, then we cannot pass through as widening. */
&& (((ANY_INTEGRAL_TYPE_P (TREE_TYPE (op0))
&& TYPE_OVERFLOW_WRAPS (TREE_TYPE (op0)))
&& ((TYPE_OVERFLOW_WRAPS (TREE_TYPE (op0))
&& (TYPE_PRECISION (ctype)
> TYPE_PRECISION (TREE_TYPE (op0))))
/* ... or this is a truncation (t is narrower than op0),
@ -6737,8 +6738,7 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
/* ... or has undefined overflow while the converted to
type has not, we cannot do the operation in the inner type
as that would introduce undefined overflow. */
|| ((ANY_INTEGRAL_TYPE_P (TREE_TYPE (op0))
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (op0)))
|| (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (op0))
&& !TYPE_OVERFLOW_UNDEFINED (type))))
break;

View File

@ -0,0 +1,44 @@
// PR tree-optimization/99777
template <typename T>
inline const T &
min (const T &a, const T &b)
{
if (b < a)
return b;
return a;
}
template <typename T>
inline const T &
max (const T &a, const T &b)
{
if (a < b)
return b;
return a;
}
extern int o, a, c;
long h;
unsigned long long e;
signed char d;
extern short p[][7][5][30];
void
test (long long b, short f[][17][25][22][20])
{
for (char i = 0; i < 7; i += 3)
for (unsigned char l = e; l < 5; l += 2)
{
if (max (0LL, min (7LL, b)))
for (bool j = 0; j < 1; j = b)
{
for (unsigned k = d; k < 20; k++)
h = f[0][i][l][b][k];
for (int m = 0; m < 5; m++)
p[c][i][l][m] = 0;
}
for (int n = 0; n < 4; n += a)
o = n;
}
}