re PR c++/67104 (Constant expression factory function initializes std::array with static storage duration strangely)
PR c++/67104 * constexpr.c (array_index_cmp, find_array_ctor_elt): New. (cxx_eval_array_reference, cxx_eval_store_expression): Use them. From-SVN: r226949
This commit is contained in:
parent
c75ce5301b
commit
ceaaf873e9
2 changed files with 129 additions and 46 deletions
|
@ -1,5 +1,9 @@
|
|||
2015-08-17 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/67104
|
||||
* constexpr.c (array_index_cmp, find_array_ctor_elt): New.
|
||||
(cxx_eval_array_reference, cxx_eval_store_expression): Use them.
|
||||
|
||||
* constexpr.c (cxx_eval_store_expression): Don't set
|
||||
CONSTRUCTOR_NO_IMPLICIT_ZERO if we have an enclosing CONSTRUCTOR
|
||||
without it.
|
||||
|
|
|
@ -1654,6 +1654,90 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
|
|||
jump_target);
|
||||
}
|
||||
|
||||
/* Returns less than, equal to, or greater than zero if KEY is found to be
|
||||
less than, to match, or to be greater than the constructor_elt's INDEX. */
|
||||
|
||||
static int
|
||||
array_index_cmp (tree key, tree index)
|
||||
{
|
||||
gcc_assert (TREE_CODE (key) == INTEGER_CST);
|
||||
|
||||
switch (TREE_CODE (index))
|
||||
{
|
||||
case INTEGER_CST:
|
||||
return tree_int_cst_compare (key, index);
|
||||
case RANGE_EXPR:
|
||||
{
|
||||
tree lo = TREE_OPERAND (index, 0);
|
||||
tree hi = TREE_OPERAND (index, 1);
|
||||
if (tree_int_cst_lt (key, lo))
|
||||
return -1;
|
||||
else if (tree_int_cst_lt (hi, key))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
default:
|
||||
gcc_unreachable ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the index of the constructor_elt of ARY which matches DINDEX, or -1
|
||||
if none. If INSERT is true, insert a matching element rather than fail. */
|
||||
|
||||
static HOST_WIDE_INT
|
||||
find_array_ctor_elt (tree ary, tree dindex, bool insert = false)
|
||||
{
|
||||
if (tree_int_cst_sgn (dindex) < 0)
|
||||
return -1;
|
||||
|
||||
unsigned HOST_WIDE_INT i = tree_to_uhwi (dindex);
|
||||
vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (ary);
|
||||
unsigned HOST_WIDE_INT len = vec_safe_length (elts);
|
||||
|
||||
unsigned HOST_WIDE_INT end = len;
|
||||
unsigned HOST_WIDE_INT begin = 0;
|
||||
|
||||
/* If the last element of the CONSTRUCTOR has its own index, we can assume
|
||||
that the same is true of the other elements and index directly. */
|
||||
if (end > 0)
|
||||
{
|
||||
tree cindex = (*elts)[end-1].index;
|
||||
if (TREE_CODE (cindex) == INTEGER_CST
|
||||
&& compare_tree_int (cindex, end-1) == 0)
|
||||
{
|
||||
if (i < end)
|
||||
return i;
|
||||
else
|
||||
begin = end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, find a matching index by means of a binary search. */
|
||||
while (begin != end)
|
||||
{
|
||||
unsigned HOST_WIDE_INT middle = (begin + end) / 2;
|
||||
|
||||
int cmp = array_index_cmp (dindex, (*elts)[middle].index);
|
||||
if (cmp < 0)
|
||||
end = middle;
|
||||
else if (cmp > 0)
|
||||
begin = middle + 1;
|
||||
else
|
||||
return middle;
|
||||
}
|
||||
|
||||
if (insert)
|
||||
{
|
||||
constructor_elt e = { dindex, NULL_TREE };
|
||||
vec_safe_insert (CONSTRUCTOR_ELTS (ary), end, e);
|
||||
return end;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Subroutine of cxx_eval_constant_expression.
|
||||
Attempt to reduce a reference to an array slot. */
|
||||
|
||||
|
@ -1699,36 +1783,26 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
|
|||
}
|
||||
|
||||
i = tree_to_shwi (index);
|
||||
bool found = true;
|
||||
if (TREE_CODE (ary) == CONSTRUCTOR && len
|
||||
&& (TREE_CODE (CONSTRUCTOR_ELT (ary, len-1)->index) == RANGE_EXPR
|
||||
|| compare_tree_int (CONSTRUCTOR_ELT (ary, len-1)->index, len-1)))
|
||||
if (i < 0)
|
||||
{
|
||||
/* The last element doesn't match its position in the array; this must be
|
||||
a sparse array from cxx_eval_store_expression. So iterate. */
|
||||
found = false;
|
||||
vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (ary);
|
||||
constructor_elt *e;
|
||||
for (unsigned ix = 0; vec_safe_iterate (v, ix, &e); ++ix)
|
||||
{
|
||||
if (TREE_CODE (e->index) == RANGE_EXPR)
|
||||
{
|
||||
tree lo = TREE_OPERAND (e->index, 0);
|
||||
tree hi = TREE_OPERAND (e->index, 1);
|
||||
if (tree_int_cst_le (lo, index) && tree_int_cst_le (index, hi))
|
||||
found = true;
|
||||
}
|
||||
else if (tree_int_cst_equal (e->index, index))
|
||||
found = true;
|
||||
if (found)
|
||||
{
|
||||
i = ix;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ctx->quiet)
|
||||
error ("negative array subscript");
|
||||
*non_constant_p = true;
|
||||
return t;
|
||||
}
|
||||
|
||||
if (i >= len || !found)
|
||||
bool found;
|
||||
if (TREE_CODE (ary) == CONSTRUCTOR)
|
||||
{
|
||||
HOST_WIDE_INT ix = find_array_ctor_elt (ary, index);
|
||||
found = (ix >= 0);
|
||||
if (found)
|
||||
i = ix;
|
||||
}
|
||||
else
|
||||
found = (i < len);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
if (tree_int_cst_lt (index, array_type_nelts_top (TREE_TYPE (ary))))
|
||||
{
|
||||
|
@ -1757,13 +1831,6 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
|
|||
*non_constant_p = true;
|
||||
return t;
|
||||
}
|
||||
else if (i < 0)
|
||||
{
|
||||
if (!ctx->quiet)
|
||||
error ("negative array subscript");
|
||||
*non_constant_p = true;
|
||||
return t;
|
||||
}
|
||||
|
||||
if (TREE_CODE (ary) == CONSTRUCTOR)
|
||||
return (*CONSTRUCTOR_ELTS (ary))[i].value;
|
||||
|
@ -2698,21 +2765,33 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
|
|||
subobjects will also be zero-initialized. */
|
||||
no_zero_init = CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp);
|
||||
|
||||
constructor_elt ce;
|
||||
enum tree_code code = TREE_CODE (type);
|
||||
type = refs->pop();
|
||||
ce.index = refs->pop();
|
||||
ce.value = NULL_TREE;
|
||||
tree index = refs->pop();
|
||||
|
||||
unsigned HOST_WIDE_INT idx = 0;
|
||||
constructor_elt *cep = NULL;
|
||||
for (idx = 0;
|
||||
vec_safe_iterate (CONSTRUCTOR_ELTS (*valp), idx, &cep);
|
||||
idx++)
|
||||
/* ??? slow */
|
||||
if (cp_tree_equal (ce.index, cep->index))
|
||||
break;
|
||||
if (!cep)
|
||||
cep = vec_safe_push (CONSTRUCTOR_ELTS (*valp), ce);
|
||||
if (code == ARRAY_TYPE)
|
||||
{
|
||||
HOST_WIDE_INT i
|
||||
= find_array_ctor_elt (*valp, index, /*insert*/true);
|
||||
gcc_assert (i >= 0);
|
||||
cep = CONSTRUCTOR_ELT (*valp, i);
|
||||
gcc_assert (TREE_CODE (cep->index) != RANGE_EXPR);
|
||||
}
|
||||
else
|
||||
{
|
||||
gcc_assert (TREE_CODE (index) == FIELD_DECL);
|
||||
for (unsigned HOST_WIDE_INT idx = 0;
|
||||
vec_safe_iterate (CONSTRUCTOR_ELTS (*valp), idx, &cep);
|
||||
idx++)
|
||||
if (index == cep->index)
|
||||
break;
|
||||
if (!cep)
|
||||
{
|
||||
constructor_elt ce = { index, NULL_TREE };
|
||||
cep = vec_safe_push (CONSTRUCTOR_ELTS (*valp), ce);
|
||||
}
|
||||
}
|
||||
valp = &cep->value;
|
||||
}
|
||||
release_tree_vector (refs);
|
||||
|
|
Loading…
Add table
Reference in a new issue