re PR c++/77830 (internal compiler error: in output_constructor_regular_field, at varasm.c:4968, when using constexpr (with testcase))

PR c++/77830
	* constexpr.c (cxx_eval_array_reference): Perform out of bounds
	verification even if lval is true, just allow one past the last
	element in that case.
	(cxx_eval_store_expression): Detect stores to out of bound
	ARRAY_REF.

	* g++.dg/cpp1y/pr77830.C: New test.
	* g++.dg/cpp0x/pr65398.C: Adjust expected diagnostics.

From-SVN: r243873
This commit is contained in:
Jakub Jelinek 2016-12-21 22:58:23 +01:00 committed by Jakub Jelinek
parent 31bfc9b9dd
commit bc2a38dff8
5 changed files with 137 additions and 41 deletions

View File

@ -1,3 +1,12 @@
2016-12-21 Jakub Jelinek <jakub@redhat.com>
PR c++/77830
* constexpr.c (cxx_eval_array_reference): Perform out of bounds
verification even if lval is true, just allow one past the last
element in that case.
(cxx_eval_store_expression): Detect stores to out of bound
ARRAY_REF.
2016-12-21 Jason Merrill <jason@redhat.com> 2016-12-21 Jason Merrill <jason@redhat.com>
Implement P0522R0, matching of template template arguments. Implement P0522R0, matching of template template arguments.

View File

@ -2183,9 +2183,9 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
lval, lval,
non_constant_p, overflow_p); non_constant_p, overflow_p);
tree index, oldidx; tree index, oldidx;
HOST_WIDE_INT i; HOST_WIDE_INT i = 0;
tree elem_type; tree elem_type = NULL_TREE;
unsigned len, elem_nchars = 1; unsigned len = 0, elem_nchars = 1;
if (*non_constant_p) if (*non_constant_p)
return t; return t;
oldidx = TREE_OPERAND (t, 1); oldidx = TREE_OPERAND (t, 1);
@ -2193,39 +2193,38 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
false, false,
non_constant_p, overflow_p); non_constant_p, overflow_p);
VERIFY_CONSTANT (index); VERIFY_CONSTANT (index);
if (lval && ary == oldary && index == oldidx) if (!lval)
return t;
else if (lval)
return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
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) elem_type = TREE_TYPE (TREE_TYPE (ary));
/ TYPE_PRECISION (char_type_node)); if (TREE_CODE (ary) == VIEW_CONVERT_EXPR
len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars; && VECTOR_TYPE_P (TREE_TYPE (TREE_OPERAND (ary, 0)))
} && TREE_TYPE (t) == TREE_TYPE (TREE_TYPE (TREE_OPERAND (ary, 0))))
else if (TREE_CODE (ary) == VECTOR_CST) ary = TREE_OPERAND (ary, 0);
len = VECTOR_CST_NELTS (ary); if (TREE_CODE (ary) == CONSTRUCTOR)
else len = CONSTRUCTOR_NELTS (ary);
{ else if (TREE_CODE (ary) == STRING_CST)
/* We can't do anything with other tree codes, so use {
VERIFY_CONSTANT to complain and fail. */ elem_nchars = (TYPE_PRECISION (elem_type)
VERIFY_CONSTANT (ary); / TYPE_PRECISION (char_type_node));
gcc_unreachable (); len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars;
} }
else if (TREE_CODE (ary) == VECTOR_CST)
len = VECTOR_CST_NELTS (ary);
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) if (!tree_fits_shwi_p (index)
|| (i = tree_to_shwi (index)) < 0) || (i = tree_to_shwi (index)) < 0)
{ {
diag_array_subscript (ctx, ary, index); diag_array_subscript (ctx, ary, index);
*non_constant_p = true; *non_constant_p = true;
return t; return t;
}
} }
tree nelts; tree nelts;
@ -2240,13 +2239,20 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t,
nelts = cxx_eval_constant_expression (ctx, nelts, false, non_constant_p, nelts = cxx_eval_constant_expression (ctx, nelts, false, non_constant_p,
overflow_p); overflow_p);
VERIFY_CONSTANT (nelts); VERIFY_CONSTANT (nelts);
if (!tree_int_cst_lt (index, nelts)) if (lval
? !tree_int_cst_le (index, nelts)
: !tree_int_cst_lt (index, nelts))
{ {
diag_array_subscript (ctx, ary, index); diag_array_subscript (ctx, ary, index);
*non_constant_p = true; *non_constant_p = true;
return t; return t;
} }
if (lval && ary == oldary && index == oldidx)
return t;
else if (lval)
return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL);
bool found; bool found;
if (TREE_CODE (ary) == CONSTRUCTOR) if (TREE_CODE (ary) == CONSTRUCTOR)
{ {
@ -3281,6 +3287,47 @@ 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);
if (TREE_CODE (TREE_TYPE (ary)) == ARRAY_TYPE)
nelts = array_type_nelts_top (TREE_TYPE (ary));
else if (VECTOR_TYPE_P (TREE_TYPE (ary)))
nelts = size_int (TYPE_VECTOR_SUBPARTS (TREE_TYPE (ary)));
else
gcc_unreachable ();
nelts = cxx_eval_constant_expression (ctx, nelts, false,
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::eq_p (TREE_OPERAND (probe, 1), 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

View File

@ -1,3 +1,9 @@
2016-12-21 Jakub Jelinek <jakub@redhat.com>
PR c++/77830
* g++.dg/cpp1y/pr77830.C: New test.
* g++.dg/cpp0x/pr65398.C: Adjust expected diagnostics.
2016-12-21 Bernd Schmidt <bschmidt@redhat.com> 2016-12-21 Bernd Schmidt <bschmidt@redhat.com>
PR target/71321 PR target/71321

View File

@ -20,9 +20,9 @@ constexpr char d5 = *(&s[4] - 4);
constexpr char d6 = *(&s[4] - 5); // { dg-error "array subscript" } constexpr char d6 = *(&s[4] - 5); // { dg-error "array subscript" }
/* Don't accept invalid stuff. */ /* Don't accept invalid stuff. */
constexpr char e1 = *(&s[5] - 1); // { dg-error "is not a constant expression" } constexpr char e1 = *(&s[5] - 1); // { dg-error "array subscript" }
constexpr char e2 = *(&s[5] - 2); // { dg-error "is not a constant expression" } constexpr char e2 = *(&s[5] - 2); // { dg-error "array subscript" }
constexpr char e3 = *(&s[5] - 3); // { dg-error "is not a constant expression" } constexpr char e3 = *(&s[5] - 3); // { dg-error "array subscript" }
SA (c1 == 'a'); SA (c1 == 'a');
SA (c2 == 'b'); SA (c2 == 'b');
@ -53,9 +53,9 @@ constexpr char j5 = *(&l[4] - 4);
constexpr char j6 = *(&l[4] - 5); // { dg-error "array subscript" } constexpr char j6 = *(&l[4] - 5); // { dg-error "array subscript" }
/* Don't accept invalid stuff. */ /* Don't accept invalid stuff. */
constexpr char k1 = *(&l[5] - 1); // { dg-error "is not a constant expression" } constexpr char k1 = *(&l[5] - 1); // { dg-error "array subscript" }
constexpr char k2 = *(&l[5] - 2); // { dg-error "is not a constant expression" } constexpr char k2 = *(&l[5] - 2); // { dg-error "array subscript" }
constexpr char k3 = *(&l[5] - 3); // { dg-error "is not a constant expression" } constexpr char k3 = *(&l[5] - 3); // { dg-error "array subscript" }
SA (i1 == 'c'); SA (i1 == 'c');
SA (i2 == 'd'); SA (i2 == 'd');

View File

@ -0,0 +1,34 @@
// PR c++/77830
// { dg-do compile { target c++14 } }
template <int N>
struct P
{
char arr[N][1];
constexpr void foo (const char *, int);
};
template <int N>
constexpr void
P<N>::foo (const char *, int i)
{
for (auto j = 0; j < 2; ++j)
arr[i][j] = true;
}
template <typename... T>
constexpr auto
bar (T... a)
{
const char *s[]{a...};
P<sizeof...(a)> p{};
for (auto i = 0; i < sizeof...(a); ++i)
p.foo (s[i], i);
return p;
}
int
main ()
{
constexpr auto a = bar ("", ""); // { dg-error "outside the bounds of array type" }
}