Commit 043666e0 by Jason Merrill Committed by Jason Merrill

Consolidate constexpr array handling.

	* constexpr.c (eval_and_check_array_index): Split out from...
	(cxx_eval_array_reference): ...here.
	(cxx_eval_store_expression): Use it here, too.
	(diag_array_subscript): Take location.  Strip location wrapper.

From-SVN: r272430
parent 02a8575c
2019-06-18 Jason Merrill <jason@redhat.com> 2019-06-18 Jason Merrill <jason@redhat.com>
* constexpr.c (eval_and_check_array_index): Split out from...
(cxx_eval_array_reference): ...here.
(cxx_eval_store_expression): Use it here, too.
(diag_array_subscript): Take location. Strip location wrapper.
2019-06-18 Jason Merrill <jason@redhat.com>
* constexpr.c (cxx_eval_constant_expression): Handle conversion from * constexpr.c (cxx_eval_constant_expression): Handle conversion from
and then to the same type. and then to the same type.
......
...@@ -2488,7 +2488,7 @@ find_array_ctor_elt (tree ary, tree dindex, bool insert) ...@@ -2488,7 +2488,7 @@ find_array_ctor_elt (tree ary, tree dindex, bool insert)
an out-of-bounds subscript INDEX into the expression ARRAY. */ an out-of-bounds subscript INDEX into the expression ARRAY. */
static void static void
diag_array_subscript (const constexpr_ctx *ctx, tree array, tree index) diag_array_subscript (location_t loc, const constexpr_ctx *ctx, tree array, tree index)
{ {
if (!ctx->quiet) if (!ctx->quiet)
{ {
...@@ -2497,22 +2497,23 @@ diag_array_subscript (const constexpr_ctx *ctx, tree array, tree index) ...@@ -2497,22 +2497,23 @@ diag_array_subscript (const constexpr_ctx *ctx, tree array, tree index)
/* Convert the unsigned array subscript to a signed integer to avoid /* Convert the unsigned array subscript to a signed integer to avoid
printing huge numbers for small negative values. */ printing huge numbers for small negative values. */
tree sidx = fold_convert (ssizetype, index); tree sidx = fold_convert (ssizetype, index);
STRIP_ANY_LOCATION_WRAPPER (array);
if (DECL_P (array)) if (DECL_P (array))
{ {
if (TYPE_DOMAIN (arraytype)) if (TYPE_DOMAIN (arraytype))
error ("array subscript value %qE is outside the bounds " error_at (loc, "array subscript value %qE is outside the bounds "
"of array %qD of type %qT", sidx, array, arraytype); "of array %qD of type %qT", sidx, array, arraytype);
else else
error ("nonzero array subscript %qE is used with array %qD of " error_at (loc, "nonzero array subscript %qE is used with array %qD of "
"type %qT with unknown bounds", sidx, array, arraytype); "type %qT with unknown bounds", sidx, array, arraytype);
inform (DECL_SOURCE_LOCATION (array), "declared here"); inform (DECL_SOURCE_LOCATION (array), "declared here");
} }
else if (TYPE_DOMAIN (arraytype)) else if (TYPE_DOMAIN (arraytype))
error ("array subscript value %qE is outside the bounds " error_at (loc, "array subscript value %qE is outside the bounds "
"of array type %qT", sidx, arraytype); "of array type %qT", sidx, arraytype);
else else
error ("nonzero array subscript %qE is used with array of type %qT " error_at (loc, "nonzero array subscript %qE is used with array of type %qT "
"with unknown bounds", sidx, arraytype); "with unknown bounds", sidx, arraytype);
} }
} }
...@@ -2563,6 +2564,44 @@ extract_string_elt (tree string, unsigned chars_per_elt, unsigned index) ...@@ -2563,6 +2564,44 @@ extract_string_elt (tree string, unsigned chars_per_elt, unsigned index)
return r; return r;
} }
/* Subroutine of cxx_eval_array_reference. T is an ARRAY_REF; evaluate the
subscript, diagnose any problems with it, and return the result. */
static tree
eval_and_check_array_index (const constexpr_ctx *ctx,
tree t, bool allow_one_past,
bool *non_constant_p, bool *overflow_p)
{
location_t loc = cp_expr_loc_or_loc (t, input_location);
tree ary = TREE_OPERAND (t, 0);
t = TREE_OPERAND (t, 1);
tree index = cxx_eval_constant_expression (ctx, t, false,
non_constant_p, overflow_p);
VERIFY_CONSTANT (index);
if (!tree_fits_shwi_p (index)
|| tree_int_cst_sgn (index) < 0)
{
diag_array_subscript (loc, ctx, ary, index);
*non_constant_p = true;
return t;
}
tree nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary), non_constant_p,
overflow_p);
VERIFY_CONSTANT (nelts);
if (allow_one_past
? !tree_int_cst_le (index, nelts)
: !tree_int_cst_lt (index, nelts))
{
diag_array_subscript (loc, ctx, ary, index);
*non_constant_p = true;
return t;
}
return index;
}
/* 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. */
...@@ -2575,71 +2614,47 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, ...@@ -2575,71 +2614,47 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
tree ary = cxx_eval_constant_expression (ctx, oldary, tree ary = cxx_eval_constant_expression (ctx, oldary,
lval, lval,
non_constant_p, overflow_p); non_constant_p, overflow_p);
tree index, oldidx;
HOST_WIDE_INT i = 0;
tree elem_type = NULL_TREE;
unsigned len = 0, elem_nchars = 1;
if (*non_constant_p) if (*non_constant_p)
return t; return t;
oldidx = TREE_OPERAND (t, 1); if (TREE_CODE (ary) == VIEW_CONVERT_EXPR
index = cxx_eval_constant_expression (ctx, oldidx, && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0)))
false, && TREE_TYPE (t) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0))))
non_constant_p, overflow_p); ary = TREE_OPERAND (ary, 0);
VERIFY_CONSTANT (index);
if (!lval)
{
elem_type = TREE_TYPE (TREE_TYPE (ary));
if (TREE_CODE (ary) == VIEW_CONVERT_EXPR
&& VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0)))
&& TREE_TYPE (t) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0))))
ary = TREE_OPERAND (ary, 0);
if (TREE_CODE (ary) == CONSTRUCTOR)
len = CONSTRUCTOR_NELTS (ary);
else if (TREE_CODE (ary) == STRING_CST)
{
elem_nchars = (TYPE_PRECISION (elem_type)
/ TYPE_PRECISION (char_type_node));
len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
}
else if (TREE_CODE (ary) == VECTOR_CST)
/* We don't create variable-length VECTOR_CSTs. */
len = VECTOR_CST_NELTS (ary).to_constant ();
else
{
/* We can't do anything with other tree codes, so use
VERIFY_CONSTANT to complain and fail. */
VERIFY_CONSTANT (ary);
gcc_unreachable ();
}
if (!tree_fits_shwi_p (index) tree oldidx = TREE_OPERAND (t, 1);
|| (i = tree_to_shwi (index)) < 0) tree index = eval_and_check_array_index (ctx, t, lval,
{ non_constant_p, overflow_p);
diag_array_subscript (ctx, ary, index); if (*non_constant_p)
*non_constant_p = true; return t;
return t;
}
}
tree nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary), non_constant_p,
overflow_p);
VERIFY_CONSTANT (nelts);
if ((lval
? !tree_int_cst_le (index, nelts)
: !tree_int_cst_lt (index, nelts))
|| tree_int_cst_sgn (index) < 0)
{
diag_array_subscript (ctx, ary, index);
*non_constant_p = true;
return t;
}
if (lval && ary == oldary && index == oldidx) if (lval && ary == oldary && index == oldidx)
return t; return t;
else if (lval) else if (lval)
return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL); return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
unsigned len = 0, elem_nchars = 1;
tree elem_type = TREE_TYPE (TREE_TYPE (ary));
if (TREE_CODE (ary) == CONSTRUCTOR)
len = CONSTRUCTOR_NELTS (ary);
else if (TREE_CODE (ary) == STRING_CST)
{
elem_nchars = (TYPE_PRECISION (elem_type)
/ TYPE_PRECISION (char_type_node));
len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
}
else if (TREE_CODE (ary) == VECTOR_CST)
/* We don't create variable-length VECTOR_CSTs. */
len = VECTOR_CST_NELTS (ary).to_constant ();
else
{
/* We can't do anything with other tree codes, so use
VERIFY_CONSTANT to complain and fail. */
VERIFY_CONSTANT (ary);
gcc_unreachable ();
}
bool found; bool found;
HOST_WIDE_INT i = 0;
if (TREE_CODE (ary) == CONSTRUCTOR) if (TREE_CODE (ary) == CONSTRUCTOR)
{ {
HOST_WIDE_INT ix = find_array_ctor_elt (ary, index); HOST_WIDE_INT ix = find_array_ctor_elt (ary, index);
...@@ -2648,7 +2663,10 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, ...@@ -2648,7 +2663,10 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
i = ix; i = ix;
} }
else else
found = (i < len); {
i = tree_to_shwi (index);
found = (i < len);
}
if (found) if (found)
{ {
...@@ -3735,41 +3753,6 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, ...@@ -3735,41 +3753,6 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
if (*non_constant_p) if (*non_constant_p)
return t; return t;
/* cxx_eval_array_reference for lval = true allows references one past
end of array, because it does not know if it is just taking address
(which is valid), or actual dereference. Here we know it is
a dereference, so diagnose it here. */
for (tree probe = target; probe; )
{
switch (TREE_CODE (probe))
{
case ARRAY_REF:
tree nelts, ary;
ary = TREE_OPERAND (probe, 0);
nelts = get_array_or_vector_nelts (ctx, TREE_TYPE (ary),
non_constant_p, overflow_p);
VERIFY_CONSTANT (nelts);
gcc_assert (TREE_CODE (nelts) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (probe, 1)) == INTEGER_CST);
if (wi::to_widest (TREE_OPERAND (probe, 1)) == wi::to_widest (nelts))
{
diag_array_subscript (ctx, ary, TREE_OPERAND (probe, 1));
*non_constant_p = true;
return t;
}
/* FALLTHRU */
case BIT_FIELD_REF:
case COMPONENT_REF:
probe = TREE_OPERAND (probe, 0);
continue;
default:
probe = NULL_TREE;
continue;
}
}
if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (target), type)) if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (target), type))
{ {
/* For initialization of an empty base, the original target will be /* For initialization of an empty base, the original target will be
...@@ -3782,7 +3765,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, ...@@ -3782,7 +3765,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
non_constant_p, overflow_p); non_constant_p, overflow_p);
} }
/* And then find the underlying variable. */ /* Find the underlying variable. */
releasing_vec refs; releasing_vec refs;
tree object = NULL_TREE; tree object = NULL_TREE;
for (tree probe = target; object == NULL_TREE; ) for (tree probe = target; object == NULL_TREE; )
...@@ -3792,9 +3775,20 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, ...@@ -3792,9 +3775,20 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
case BIT_FIELD_REF: case BIT_FIELD_REF:
case COMPONENT_REF: case COMPONENT_REF:
case ARRAY_REF: case ARRAY_REF:
vec_safe_push (refs, TREE_OPERAND (probe, 1)); {
vec_safe_push (refs, TREE_TYPE (probe)); tree ob = TREE_OPERAND (probe, 0);
probe = TREE_OPERAND (probe, 0); tree elt = TREE_OPERAND (probe, 1);
if (TREE_CODE (probe) == ARRAY_REF)
{
elt = eval_and_check_array_index (ctx, probe, false,
non_constant_p, overflow_p);
if (*non_constant_p)
return t;
}
vec_safe_push (refs, elt);
vec_safe_push (refs, TREE_TYPE (probe));
probe = ob;
}
break; break;
default: default:
......
...@@ -5,14 +5,14 @@ constexpr int ...@@ -5,14 +5,14 @@ constexpr int
foo (int x, int y) foo (int x, int y)
{ {
int a[6] = { 1, 2, 3, 4, 5, 6 }; int a[6] = { 1, 2, 3, 4, 5, 6 };
a[x] = 0; a[x] = 0; // { dg-error "is outside the bounds" }
return a[y]; return a[y]; // { dg-error "is outside the bounds" }
} }
constexpr int b = foo (0, -1); // { dg-error "is outside the bounds|in .constexpr. expansion of " } constexpr int b = foo (0, -1); // { dg-message "in .constexpr. expansion of " }
constexpr int c = foo (0, 6); // { dg-error "is outside the bounds|in .constexpr. expansion of " } constexpr int c = foo (0, 6); // { dg-message "in .constexpr. expansion of " }
constexpr int d = foo (6, 0); // { dg-error "is outside the bounds|in .constexpr. expansion of " } constexpr int d = foo (6, 0); // { dg-message "in .constexpr. expansion of " }
constexpr int e = foo (-1, 0); // { dg-error "is outside the bounds|in .constexpr. expansion of " } constexpr int e = foo (-1, 0); // { dg-message "in .constexpr. expansion of " }
static_assert (foo (5, 5) == 0, ""); static_assert (foo (5, 5) == 0, "");
static_assert (foo (4, 5) == 6, ""); static_assert (foo (4, 5) == 6, "");
static_assert (foo (5, 4) == 5, ""); static_assert (foo (5, 4) == 5, "");
...@@ -13,7 +13,7 @@ constexpr void ...@@ -13,7 +13,7 @@ constexpr void
P<N>::foo (const char *, int i) P<N>::foo (const char *, int i)
{ {
for (auto j = 0; j < 2; ++j) for (auto j = 0; j < 2; ++j)
arr[i][j] = true; arr[i][j] = true; // { dg-error "outside the bounds of array type" }
} }
template <typename... T> template <typename... T>
...@@ -30,5 +30,5 @@ bar (T... a) ...@@ -30,5 +30,5 @@ bar (T... a)
int int
main () main ()
{ {
constexpr auto a = bar ("", ""); // { dg-error "outside the bounds of array type|in .constexpr. expansion of " } constexpr auto a = bar ("", ""); // { dg-message "in .constexpr. expansion of " }
} }
...@@ -21,10 +21,10 @@ fn_not_ok (int n) ...@@ -21,10 +21,10 @@ fn_not_ok (int n)
int z = 0; int z = 0;
for (unsigned i = 0; i < sizeof (a); ++i) for (unsigned i = 0; i < sizeof (a); ++i)
z += a[i]; z += a[i]; // { dg-error "array subscript" }
return z; return z;
} }
constexpr int n1 = fn_ok (3); constexpr int n1 = fn_ok (3);
constexpr int n2 = fn_not_ok (3); // { dg-error "array subscript|in .constexpr. expansion of " } constexpr int n2 = fn_not_ok (3); // { dg-message "in .constexpr. expansion of " }
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