re PR middle-end/42803 (c++ compilation hang)

PR middle-end/42803
	* varasm.c (narrowing_initializer_constant_valid_p): Add CACHE
	argument, call initializer_constant_valid_p_1 instead of
	initializer_constant_valid_p, pass CACHE to it, return NULL
	immediately if first call returns NULL.
	(initializer_constant_valid_p_1): New function.
	(initializer_constant_valid_p): Use it.

	* g++.dg/parse/limits-initializer1.C: New test.

From-SVN: r156070
This commit is contained in:
Jakub Jelinek 2010-01-20 12:27:49 +01:00 committed by Jakub Jelinek
parent e3079365b6
commit 66c57cb805
4 changed files with 163 additions and 54 deletions

View File

@ -5,6 +5,14 @@
* unwind-dw2.c (execute_stack_op): Handle DW_OP_mod using unsigned
modulo instead of signed.
PR middle-end/42803
* varasm.c (narrowing_initializer_constant_valid_p): Add CACHE
argument, call initializer_constant_valid_p_1 instead of
initializer_constant_valid_p, pass CACHE to it, return NULL
immediately if first call returns NULL.
(initializer_constant_valid_p_1): New function.
(initializer_constant_valid_p): Use it.
2010-01-18 Uros Bizjak <ubizjak@gmail.com>
PR target/42774

View File

@ -3,6 +3,9 @@
* gcc.dg/cleanup-13.c: Expect DW_OP_mod to do unsigned modulo instead
of signed, add a few new tests.
PR middle-end/42803
* g++.dg/parse/limits-initializer1.C: New test.
2010-01-18 Uros Bizjak <ubizjak@gmail.com>
PR target/42774

View File

@ -0,0 +1,37 @@
// PR middle-end/42803
// { dg-do compile }
// { dg-options "-O0" }
#define X2 (a + a)
#define X4 (X2 + X2)
#define X8 (X4 + X4)
#define X16 (X8 + X8)
#define X32 (X16 + X16)
#define X64 (X32 + X32)
#define X128 (X64 + X64)
#define X256 (X128 + X128)
#define X512 (X256 + X256)
#define X1024 (X512 + X512)
#define X2048 (X1024 + X1024)
#define X4096 (X2048 + X2048)
#define X8192 (X4096 + X4096)
#define X16384 (X8192 + X8192)
#define X32768 (X16384 + X16384)
#define X65536 (X32768 + X32768)
#define X131072 (X65536 + X65536)
#define X262144 (X131072 + X131072)
int
foo (int a)
{
int v = X262144;
return v;
}
// Emit an error to just make sure we don't waste too much time
// in the middle-end compiling this.
int
bar (void)
{
return x; // { dg-error "was not declared in this scope" }
}

View File

@ -1,7 +1,7 @@
/* Output variables, constants and external declarations, for GNU compiler.
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997,
1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
Free Software Foundation, Inc.
1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
2010 Free Software Foundation, Inc.
This file is part of GCC.
@ -4072,6 +4072,9 @@ constructor_static_from_elts_p (const_tree ctor)
&& !VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (ctor)));
}
static tree initializer_constant_valid_p_1 (tree value, tree endtype,
tree *cache);
/* A subroutine of initializer_constant_valid_p. VALUE is a MINUS_EXPR,
PLUS_EXPR or POINTER_PLUS_EXPR. This looks for cases of VALUE
which are valid when ENDTYPE is an integer of any size; in
@ -4081,7 +4084,7 @@ constructor_static_from_elts_p (const_tree ctor)
returns NULL. */
static tree
narrowing_initializer_constant_valid_p (tree value, tree endtype)
narrowing_initializer_constant_valid_p (tree value, tree endtype, tree *cache)
{
tree op0, op1;
@ -4120,11 +4123,14 @@ narrowing_initializer_constant_valid_p (tree value, tree endtype)
op1 = inner;
}
op0 = initializer_constant_valid_p (op0, endtype);
op1 = initializer_constant_valid_p (op1, endtype);
op0 = initializer_constant_valid_p_1 (op0, endtype, cache);
if (!op0)
return NULL_TREE;
op1 = initializer_constant_valid_p_1 (op1, endtype,
cache ? cache + 2 : NULL);
/* Both initializers must be known. */
if (op0 && op1)
if (op1)
{
if (op0 == op1
&& (op0 == null_pointer_node
@ -4145,7 +4151,8 @@ narrowing_initializer_constant_valid_p (tree value, tree endtype)
return NULL_TREE;
}
/* Return nonzero if VALUE is a valid constant-valued expression
/* Helper function of initializer_constant_valid_p.
Return nonzero if VALUE is a valid constant-valued expression
for use in initializing a static variable; one that can be an
element of a "constant" initializer.
@ -4153,10 +4160,12 @@ narrowing_initializer_constant_valid_p (tree value, tree endtype)
if it is relocatable, return the variable that determines the relocation.
We assume that VALUE has been folded as much as possible;
therefore, we do not need to check for such things as
arithmetic-combinations of integers. */
arithmetic-combinations of integers.
tree
initializer_constant_valid_p (tree value, tree endtype)
Use CACHE (pointer to 2 tree values) for caching if non-NULL. */
static tree
initializer_constant_valid_p_1 (tree value, tree endtype, tree *cache)
{
tree ret;
@ -4169,18 +4178,33 @@ initializer_constant_valid_p (tree value, tree endtype)
tree elt;
bool absolute = true;
if (cache && cache[0] == value)
return cache[1];
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (value), idx, elt)
{
tree reloc;
reloc = initializer_constant_valid_p (elt, TREE_TYPE (elt));
reloc = initializer_constant_valid_p_1 (elt, TREE_TYPE (elt),
NULL);
if (!reloc)
return NULL_TREE;
{
if (cache)
{
cache[0] = value;
cache[1] = NULL_TREE;
}
return NULL_TREE;
}
if (reloc != null_pointer_node)
absolute = false;
}
/* For a non-absolute relocation, there is no single
variable that can be "the variable that determines the
relocation." */
if (cache)
{
cache[0] = value;
cache[1] = absolute ? null_pointer_node : error_mark_node;
}
return absolute ? null_pointer_node : error_mark_node;
}
@ -4221,7 +4245,8 @@ initializer_constant_valid_p (tree value, tree endtype)
}
case NON_LVALUE_EXPR:
return initializer_constant_valid_p (TREE_OPERAND (value, 0), endtype);
return initializer_constant_valid_p_1 (TREE_OPERAND (value, 0),
endtype, cache);
case VIEW_CONVERT_EXPR:
{
@ -4236,13 +4261,13 @@ initializer_constant_valid_p (tree value, tree endtype)
if (AGGREGATE_TYPE_P (src_type) && !AGGREGATE_TYPE_P (dest_type))
{
if (TYPE_MODE (endtype) == TYPE_MODE (dest_type))
return initializer_constant_valid_p (src, endtype);
return initializer_constant_valid_p_1 (src, endtype, cache);
else
return NULL_TREE;
}
/* Allow all other kinds of view-conversion. */
return initializer_constant_valid_p (src, endtype);
return initializer_constant_valid_p_1 (src, endtype, cache);
}
CASE_CONVERT:
@ -4257,18 +4282,18 @@ initializer_constant_valid_p (tree value, tree endtype)
|| (FLOAT_TYPE_P (dest_type) && FLOAT_TYPE_P (src_type))
|| (TREE_CODE (dest_type) == OFFSET_TYPE
&& TREE_CODE (src_type) == OFFSET_TYPE))
return initializer_constant_valid_p (src, endtype);
return initializer_constant_valid_p_1 (src, endtype, cache);
/* Allow length-preserving conversions between integer types. */
if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type)
&& (TYPE_PRECISION (dest_type) == TYPE_PRECISION (src_type)))
return initializer_constant_valid_p (src, endtype);
return initializer_constant_valid_p_1 (src, endtype, cache);
/* Allow conversions between other integer types only if
explicit value. */
if (INTEGRAL_TYPE_P (dest_type) && INTEGRAL_TYPE_P (src_type))
{
tree inner = initializer_constant_valid_p (src, endtype);
tree inner = initializer_constant_valid_p_1 (src, endtype, cache);
if (inner == null_pointer_node)
return null_pointer_node;
break;
@ -4277,7 +4302,7 @@ initializer_constant_valid_p (tree value, tree endtype)
/* Allow (int) &foo provided int is as wide as a pointer. */
if (INTEGRAL_TYPE_P (dest_type) && POINTER_TYPE_P (src_type)
&& (TYPE_PRECISION (dest_type) >= TYPE_PRECISION (src_type)))
return initializer_constant_valid_p (src, endtype);
return initializer_constant_valid_p_1 (src, endtype, cache);
/* Likewise conversions from int to pointers, but also allow
conversions from 0. */
@ -4291,14 +4316,14 @@ initializer_constant_valid_p (tree value, tree endtype)
if (integer_zerop (src))
return null_pointer_node;
else if (TYPE_PRECISION (dest_type) <= TYPE_PRECISION (src_type))
return initializer_constant_valid_p (src, endtype);
return initializer_constant_valid_p_1 (src, endtype, cache);
}
/* Allow conversions to struct or union types if the value
inside is okay. */
if (TREE_CODE (dest_type) == RECORD_TYPE
|| TREE_CODE (dest_type) == UNION_TYPE)
return initializer_constant_valid_p (src, endtype);
return initializer_constant_valid_p_1 (src, endtype, cache);
}
break;
@ -4308,66 +4333,102 @@ initializer_constant_valid_p (tree value, tree endtype)
with -frounding-math we hit this with addition of two constants. */
if (TREE_CODE (endtype) == REAL_TYPE)
return NULL_TREE;
if (cache && cache[0] == value)
return cache[1];
if (! INTEGRAL_TYPE_P (endtype)
|| TYPE_PRECISION (endtype) >= POINTER_SIZE)
{
tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
endtype);
tree ncache[4] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE };
tree valid0
= initializer_constant_valid_p_1 (TREE_OPERAND (value, 0),
endtype, ncache);
tree valid1
= initializer_constant_valid_p_1 (TREE_OPERAND (value, 1),
endtype, ncache + 2);
/* If either term is absolute, use the other term's relocation. */
if (valid0 == null_pointer_node)
return valid1;
if (valid1 == null_pointer_node)
return valid0;
ret = valid1;
else if (valid1 == null_pointer_node)
ret = valid0;
/* Support narrowing pointer differences. */
else
ret = narrowing_initializer_constant_valid_p (value, endtype,
ncache);
}
else
/* Support narrowing pointer differences. */
ret = narrowing_initializer_constant_valid_p (value, endtype);
if (ret != NULL_TREE)
return ret;
break;
ret = narrowing_initializer_constant_valid_p (value, endtype, NULL);
if (cache)
{
cache[0] = value;
cache[1] = ret;
}
return ret;
case MINUS_EXPR:
if (TREE_CODE (endtype) == REAL_TYPE)
return NULL_TREE;
if (cache && cache[0] == value)
return cache[1];
if (! INTEGRAL_TYPE_P (endtype)
|| TYPE_PRECISION (endtype) >= POINTER_SIZE)
{
tree valid0 = initializer_constant_valid_p (TREE_OPERAND (value, 0),
endtype);
tree valid1 = initializer_constant_valid_p (TREE_OPERAND (value, 1),
endtype);
tree ncache[4] = { NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE };
tree valid0
= initializer_constant_valid_p_1 (TREE_OPERAND (value, 0),
endtype, ncache);
tree valid1
= initializer_constant_valid_p_1 (TREE_OPERAND (value, 1),
endtype, ncache + 2);
/* Win if second argument is absolute. */
if (valid1 == null_pointer_node)
return valid0;
ret = valid0;
/* Win if both arguments have the same relocation.
Then the value is absolute. */
if (valid0 == valid1 && valid0 != 0)
return null_pointer_node;
else if (valid0 == valid1 && valid0 != 0)
ret = null_pointer_node;
/* Since GCC guarantees that string constants are unique in the
generated code, a subtraction between two copies of the same
constant string is absolute. */
if (valid0 && TREE_CODE (valid0) == STRING_CST
&& valid1 && TREE_CODE (valid1) == STRING_CST
&& operand_equal_p (valid0, valid1, 1))
return null_pointer_node;
else if (valid0 && TREE_CODE (valid0) == STRING_CST
&& valid1 && TREE_CODE (valid1) == STRING_CST
&& operand_equal_p (valid0, valid1, 1))
ret = null_pointer_node;
/* Support narrowing differences. */
else
ret = narrowing_initializer_constant_valid_p (value, endtype,
ncache);
}
/* Support narrowing differences. */
ret = narrowing_initializer_constant_valid_p (value, endtype);
if (ret != NULL_TREE)
return ret;
break;
else
/* Support narrowing differences. */
ret = narrowing_initializer_constant_valid_p (value, endtype, NULL);
if (cache)
{
cache[0] = value;
cache[1] = ret;
}
return ret;
default:
break;
}
return 0;
return NULL_TREE;
}
/* Return nonzero if VALUE is a valid constant-valued expression
for use in initializing a static variable; one that can be an
element of a "constant" initializer.
Return null_pointer_node if the value is absolute;
if it is relocatable, return the variable that determines the relocation.
We assume that VALUE has been folded as much as possible;
therefore, we do not need to check for such things as
arithmetic-combinations of integers. */
tree
initializer_constant_valid_p (tree value, tree endtype)
{
return initializer_constant_valid_p_1 (value, endtype, NULL);
}
/* Output assembler code for constant EXP to FILE, with no label.