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. */
}
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;
+ }
+
+ 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 (i >= len || !found)
+ if (!found)
{
if (tree_int_cst_lt (index, array_type_nelts_top (TREE_TYPE (ary))))
{
*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;
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);