From: Jakub Jelinek Date: Wed, 21 Dec 2016 21:58:23 +0000 (+0100) Subject: re PR c++/77830 (internal compiler error: in output_constructor_regular_field, at... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=bc2a38dff859fcd1ec0aedd8c7d0fb748f2dbede;p=gcc.git 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 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index db3582af2bc..180a0fbbd71 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2016-12-21 Jakub Jelinek + + 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 Implement P0522R0, matching of template template arguments. diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index aedd0042102..ca259cba155 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -2183,9 +2183,9 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, lval, non_constant_p, overflow_p); tree index, oldidx; - HOST_WIDE_INT i; - tree elem_type; - unsigned len, elem_nchars = 1; + HOST_WIDE_INT i = 0; + tree elem_type = NULL_TREE; + unsigned len = 0, elem_nchars = 1; if (*non_constant_p) return t; oldidx = TREE_OPERAND (t, 1); @@ -2193,39 +2193,38 @@ cxx_eval_array_reference (const constexpr_ctx *ctx, tree t, false, non_constant_p, overflow_p); VERIFY_CONSTANT (index); - if (lval && ary == oldary && index == oldidx) - 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) + if (!lval) { - 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) - 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 (); - } + 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) + 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) - || (i = tree_to_shwi (index)) < 0) - { - diag_array_subscript (ctx, ary, index); - *non_constant_p = true; - return t; + if (!tree_fits_shwi_p (index) + || (i = tree_to_shwi (index)) < 0) + { + diag_array_subscript (ctx, ary, index); + *non_constant_p = true; + return t; + } } 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, overflow_p); 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); *non_constant_p = true; 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; if (TREE_CODE (ary) == CONSTRUCTOR) { @@ -3281,6 +3287,47 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t, if (*non_constant_p) 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)) { /* For initialization of an empty base, the original target will be diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index e6ee77023aa..2da0d44dfb7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2016-12-21 Jakub Jelinek + + PR c++/77830 + * g++.dg/cpp1y/pr77830.C: New test. + * g++.dg/cpp0x/pr65398.C: Adjust expected diagnostics. + 2016-12-21 Bernd Schmidt PR target/71321 diff --git a/gcc/testsuite/g++.dg/cpp0x/pr65398.C b/gcc/testsuite/g++.dg/cpp0x/pr65398.C index 6bd34a4ffca..bab875c788c 100644 --- a/gcc/testsuite/g++.dg/cpp0x/pr65398.C +++ b/gcc/testsuite/g++.dg/cpp0x/pr65398.C @@ -20,9 +20,9 @@ constexpr char d5 = *(&s[4] - 4); constexpr char d6 = *(&s[4] - 5); // { dg-error "array subscript" } /* Don't accept invalid stuff. */ -constexpr char e1 = *(&s[5] - 1); // { dg-error "is not a constant expression" } -constexpr char e2 = *(&s[5] - 2); // { dg-error "is not a constant expression" } -constexpr char e3 = *(&s[5] - 3); // { 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 "array subscript" } +constexpr char e3 = *(&s[5] - 3); // { dg-error "array subscript" } SA (c1 == 'a'); SA (c2 == 'b'); @@ -53,9 +53,9 @@ constexpr char j5 = *(&l[4] - 4); constexpr char j6 = *(&l[4] - 5); // { dg-error "array subscript" } /* Don't accept invalid stuff. */ -constexpr char k1 = *(&l[5] - 1); // { dg-error "is not a constant expression" } -constexpr char k2 = *(&l[5] - 2); // { dg-error "is not a constant expression" } -constexpr char k3 = *(&l[5] - 3); // { 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 "array subscript" } +constexpr char k3 = *(&l[5] - 3); // { dg-error "array subscript" } SA (i1 == 'c'); SA (i2 == 'd'); diff --git a/gcc/testsuite/g++.dg/cpp1y/pr77830.C b/gcc/testsuite/g++.dg/cpp1y/pr77830.C new file mode 100644 index 00000000000..9235b405225 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/pr77830.C @@ -0,0 +1,34 @@ +// PR c++/77830 +// { dg-do compile { target c++14 } } + +template +struct P +{ + char arr[N][1]; + constexpr void foo (const char *, int); +}; + +template +constexpr void +P::foo (const char *, int i) +{ + for (auto j = 0; j < 2; ++j) + arr[i][j] = true; +} + +template +constexpr auto +bar (T... a) +{ + const char *s[]{a...}; + P 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" } +}