Commit ceaaf873 by Jason Merrill Committed by Jason Merrill

re PR c++/67104 (Constant expression factory function initializes std::array…

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
parent c75ce530
2015-08-17 Jason Merrill <jason@redhat.com> 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 * constexpr.c (cxx_eval_store_expression): Don't set
CONSTRUCTOR_NO_IMPLICIT_ZERO if we have an enclosing CONSTRUCTOR CONSTRUCTOR_NO_IMPLICIT_ZERO if we have an enclosing CONSTRUCTOR
without it. without it.
......
...@@ -1654,6 +1654,90 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t, ...@@ -1654,6 +1654,90 @@ cxx_eval_conditional_expression (const constexpr_ctx *ctx, tree t,
jump_target); 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. /* Subroutine of cxx_eval_constant_expression.
Attempt to reduce a reference to an array slot. */ Attempt to reduce a reference to an array slot. */
...@@ -1699,36 +1783,26 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, ...@@ -1699,36 +1783,26 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
} }
i = tree_to_shwi (index); i = tree_to_shwi (index);
bool found = true; if (i < 0)
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)))
{ {
/* The last element doesn't match its position in the array; this must be if (!ctx->quiet)
a sparse array from cxx_eval_store_expression. So iterate. */ error ("negative array subscript");
found = false; *non_constant_p = true;
vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (ary); return t;
constructor_elt *e; }
for (unsigned ix = 0; vec_safe_iterate (v, ix, &e); ++ix)
{ bool found;
if (TREE_CODE (e->index) == RANGE_EXPR) if (TREE_CODE (ary) == CONSTRUCTOR)
{ {
tree lo = TREE_OPERAND (e->index, 0); HOST_WIDE_INT ix = find_array_ctor_elt (ary, index);
tree hi = TREE_OPERAND (e->index, 1); found = (ix >= 0);
if (tree_int_cst_le (lo, index) && tree_int_cst_le (index, hi)) if (found)
found = true; i = ix;
}
else if (tree_int_cst_equal (e->index, index))
found = true;
if (found)
{
i = ix;
break;
}
}
} }
else
found = (i < len);
if (i >= len || !found) if (!found)
{ {
if (tree_int_cst_lt (index, array_type_nelts_top (TREE_TYPE (ary)))) 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, ...@@ -1757,13 +1831,6 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
*non_constant_p = true; *non_constant_p = true;
return t; return t;
} }
else if (i < 0)
{
if (!ctx->quiet)
error ("negative array subscript");
*non_constant_p = true;
return t;
}
if (TREE_CODE (ary) == CONSTRUCTOR) if (TREE_CODE (ary) == CONSTRUCTOR)
return (*CONSTRUCTOR_ELTS (ary))[i].value; return (*CONSTRUCTOR_ELTS (ary))[i].value;
...@@ -2698,21 +2765,33 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, ...@@ -2698,21 +2765,33 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
subobjects will also be zero-initialized. */ subobjects will also be zero-initialized. */
no_zero_init = CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp); no_zero_init = CONSTRUCTOR_NO_IMPLICIT_ZERO (*valp);
constructor_elt ce; enum tree_code code = TREE_CODE (type);
type = refs->pop(); type = refs->pop();
ce.index = refs->pop(); tree index = refs->pop();
ce.value = NULL_TREE;
unsigned HOST_WIDE_INT idx = 0;
constructor_elt *cep = NULL; constructor_elt *cep = NULL;
for (idx = 0; if (code == ARRAY_TYPE)
vec_safe_iterate (CONSTRUCTOR_ELTS (*valp), idx, &cep); {
idx++) HOST_WIDE_INT i
/* ??? slow */ = find_array_ctor_elt (*valp, index, /*insert*/true);
if (cp_tree_equal (ce.index, cep->index)) gcc_assert (i >= 0);
break; cep = CONSTRUCTOR_ELT (*valp, i);
if (!cep) gcc_assert (TREE_CODE (cep->index) != RANGE_EXPR);
cep = vec_safe_push (CONSTRUCTOR_ELTS (*valp), ce); }
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; valp = &cep->value;
} }
release_tree_vector (refs); release_tree_vector (refs);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment