diff options
author | Jakub Jelinek <jakub@gcc.gnu.org> | 2019-10-04 08:56:02 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2019-10-04 08:56:02 +0200 |
commit | 0fe2ae2902e9e65a4ce6cf56b3c34c02677d33a4 (patch) | |
tree | da09480f193d690523899f897466bdd507134d52 /gcc | |
parent | 708935b2b44663505a1cccf1a4aec80b310d0052 (diff) | |
download | gcc-0fe2ae2902e9e65a4ce6cf56b3c34c02677d33a4.zip gcc-0fe2ae2902e9e65a4ce6cf56b3c34c02677d33a4.tar.gz gcc-0fe2ae2902e9e65a4ce6cf56b3c34c02677d33a4.tar.bz2 |
re PR c++/71504 ([C++11] constexpr fails with multidimensional arrays)
PR c++/71504
* constexpr.c (cxx_fold_indirect_ref_1): New function.
(cxx_fold_indirect_ref): Use it.
* g++.dg/cpp0x/constexpr-array21.C: New test.
* g++.dg/cpp1y/constexpr-array7.C: New test.
* g++.dg/cpp1z/constexpr-array1.C: New test.
2019-10-04 Jason Merrill <jason@redhat.com>
PR c++/71504
* g++.dg/cpp0x/constexpr-array20.C: New test.
From-SVN: r276563
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/cp/constexpr.c | 231 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/constexpr-array20.C | 15 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp0x/constexpr-array21.C | 27 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1y/constexpr-array7.C | 16 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/constexpr-array1.C | 46 |
7 files changed, 223 insertions, 128 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a11bdaf..e705bcc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,9 @@ 2019-10-04 Jakub Jelinek <jakub@redhat.com> + PR c++/71504 + * constexpr.c (cxx_fold_indirect_ref_1): New function. + (cxx_fold_indirect_ref): Use it. + PR c++/91974 * cp-gimplify.c (cp_gimplify_expr) <case CALL_EXPR>: For -fstrong-eval-order ensure CALL_EXPR_FN side-effects are evaluated diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 2008793..2dc57f1 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3346,6 +3346,103 @@ same_type_ignoring_tlq_and_bounds_p (tree type1, tree type2) return same_type_ignoring_top_level_qualifiers_p (type1, type2); } +/* Helper function for cxx_fold_indirect_ref_1, called recursively. */ + +static tree +cxx_fold_indirect_ref_1 (location_t loc, tree type, tree op, + unsigned HOST_WIDE_INT off, bool *empty_base) +{ + tree optype = TREE_TYPE (op); + unsigned HOST_WIDE_INT const_nunits; + if (off == 0) + { + if (similar_type_p (optype, type)) + return op; + /* Also handle conversion to an empty base class, which + is represented with a NOP_EXPR. */ + /* *(foo *)&complexfoo => __real__ complexfoo */ + else if (TREE_CODE (optype) == COMPLEX_TYPE + && similar_type_p (type, TREE_TYPE (optype))) + return build1_loc (loc, REALPART_EXPR, type, op); + } + /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ + else if (TREE_CODE (optype) == COMPLEX_TYPE + && similar_type_p (type, TREE_TYPE (optype)) + && tree_to_uhwi (TYPE_SIZE_UNIT (type)) == off) + return build1_loc (loc, IMAGPART_EXPR, type, op); + if (is_empty_class (type) + && CLASS_TYPE_P (optype) + && DERIVED_FROM_P (type, optype)) + { + *empty_base = true; + return op; + } + /* ((foo*)&vectorfoo)[x] => BIT_FIELD_REF<vectorfoo,...> */ + else if (VECTOR_TYPE_P (optype) + && similar_type_p (type, TREE_TYPE (optype)) + && TYPE_VECTOR_SUBPARTS (optype).is_constant (&const_nunits)) + { + unsigned HOST_WIDE_INT part_width = tree_to_uhwi (TYPE_SIZE_UNIT (type)); + unsigned HOST_WIDE_INT max_offset = part_width * const_nunits; + if (off < max_offset && off % part_width == 0) + { + tree index = bitsize_int (off * BITS_PER_UNIT); + return build3_loc (loc, BIT_FIELD_REF, type, op, + TYPE_SIZE (type), index); + } + } + /* ((foo *)&fooarray)[x] => fooarray[x] */ + else if (TREE_CODE (optype) == ARRAY_TYPE + && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (optype))) + && !integer_zerop (TYPE_SIZE_UNIT (TREE_TYPE (optype)))) + { + tree type_domain = TYPE_DOMAIN (optype); + tree min_val = size_zero_node; + if (type_domain && TYPE_MIN_VALUE (type_domain)) + min_val = TYPE_MIN_VALUE (type_domain); + unsigned HOST_WIDE_INT el_sz + = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (optype))); + unsigned HOST_WIDE_INT idx = off / el_sz; + unsigned HOST_WIDE_INT rem = off % el_sz; + if (tree_fits_uhwi_p (min_val)) + { + tree index = size_int (idx + tree_to_uhwi (min_val)); + op = build4_loc (loc, ARRAY_REF, TREE_TYPE (optype), op, index, + NULL_TREE, NULL_TREE); + return cxx_fold_indirect_ref_1 (loc, type, op, rem, + empty_base); + } + } + /* ((foo *)&struct_with_foo_field)[x] => COMPONENT_REF */ + else if (TREE_CODE (optype) == RECORD_TYPE) + { + for (tree field = TYPE_FIELDS (optype); + field; field = DECL_CHAIN (field)) + if (TREE_CODE (field) == FIELD_DECL + && TREE_TYPE (field) != error_mark_node + && tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (field)))) + { + tree pos = byte_position (field); + if (!tree_fits_uhwi_p (pos)) + continue; + unsigned HOST_WIDE_INT upos = tree_to_uhwi (pos); + unsigned el_sz + = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))); + if (upos <= off && off < upos + el_sz) + { + tree cop = build3 (COMPONENT_REF, TREE_TYPE (field), + op, field, NULL_TREE); + if (tree ret = cxx_fold_indirect_ref_1 (loc, type, cop, + off - upos, + empty_base)) + return ret; + } + } + } + + return NULL_TREE; +} + /* A less strict version of fold_indirect_ref_1, which requires cv-quals to match. We want to be less strict for simple *& folding; if we have a non-const temporary that we access through a const pointer, that should @@ -3353,9 +3450,7 @@ same_type_ignoring_tlq_and_bounds_p (tree type1, tree type2) because we're dealing with things like ADDR_EXPR of INTEGER_CST which don't really make sense outside of constant expression evaluation. Also we want to allow folding to COMPONENT_REF, which could cause trouble - with TBAA in fold_indirect_ref_1. - - Try to keep this function synced with fold_indirect_ref_1. */ + with TBAA in fold_indirect_ref_1. */ static tree cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) @@ -3386,139 +3481,19 @@ cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) else return op; } - /* *(foo *)&fooarray => fooarray[0] */ - else if (TREE_CODE (optype) == ARRAY_TYPE - && similar_type_p (type, TREE_TYPE (optype))) - { - tree type_domain = TYPE_DOMAIN (optype); - tree min_val = size_zero_node; - if (type_domain && TYPE_MIN_VALUE (type_domain)) - min_val = TYPE_MIN_VALUE (type_domain); - return build4_loc (loc, ARRAY_REF, type, op, min_val, - NULL_TREE, NULL_TREE); - } - /* *(foo *)&complexfoo => __real__ complexfoo */ - else if (TREE_CODE (optype) == COMPLEX_TYPE - && similar_type_p (type, TREE_TYPE (optype))) - return fold_build1_loc (loc, REALPART_EXPR, type, op); - /* *(foo *)&vectorfoo => BIT_FIELD_REF<vectorfoo,...> */ - else if (VECTOR_TYPE_P (optype) - && similar_type_p (type, TREE_TYPE (optype))) - { - tree part_width = TYPE_SIZE (type); - tree index = bitsize_int (0); - return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width, - index); - } - /* Also handle conversion to an empty base class, which - is represented with a NOP_EXPR. */ - else if (is_empty_class (type) - && CLASS_TYPE_P (optype) - && DERIVED_FROM_P (type, optype)) - { - *empty_base = true; - return op; - } - /* *(foo *)&struct_with_foo_field => COMPONENT_REF */ - else if (RECORD_OR_UNION_TYPE_P (optype)) - { - tree field = TYPE_FIELDS (optype); - for (; field; field = DECL_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL - && TREE_TYPE (field) != error_mark_node - && integer_zerop (byte_position (field)) - && similar_type_p (TREE_TYPE (field), type)) - return fold_build3 (COMPONENT_REF, type, op, field, NULL_TREE); - } + else + return cxx_fold_indirect_ref_1 (loc, type, op, 0, empty_base); } else if (TREE_CODE (sub) == POINTER_PLUS_EXPR - && poly_int_tree_p (TREE_OPERAND (sub, 1), &const_op01)) + && tree_fits_uhwi_p (TREE_OPERAND (sub, 1))) { tree op00 = TREE_OPERAND (sub, 0); tree op01 = TREE_OPERAND (sub, 1); STRIP_NOPS (op00); if (TREE_CODE (op00) == ADDR_EXPR) - { - tree op00type; - op00 = TREE_OPERAND (op00, 0); - op00type = TREE_TYPE (op00); - - /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */ - if (VECTOR_TYPE_P (op00type) - && similar_type_p (type, TREE_TYPE (op00type)) - /* POINTER_PLUS_EXPR second operand is sizetype, unsigned, - but we want to treat offsets with MSB set as negative. - For the code below negative offsets are invalid and - TYPE_SIZE of the element is something unsigned, so - check whether op01 fits into poly_int64, which implies - it is from 0 to INTTYPE_MAXIMUM (HOST_WIDE_INT), and - then just use poly_uint64 because we want to treat the - value as unsigned. */ - && tree_fits_poly_int64_p (op01)) - { - tree part_width = TYPE_SIZE (type); - poly_uint64 max_offset - = (tree_to_uhwi (part_width) / BITS_PER_UNIT - * TYPE_VECTOR_SUBPARTS (op00type)); - if (known_lt (const_op01, max_offset)) - { - tree index = bitsize_int (const_op01 * BITS_PER_UNIT); - return fold_build3_loc (loc, - BIT_FIELD_REF, type, op00, - part_width, index); - } - } - /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ - else if (TREE_CODE (op00type) == COMPLEX_TYPE - && similar_type_p (type, TREE_TYPE (op00type))) - { - if (known_eq (wi::to_poly_offset (TYPE_SIZE_UNIT (type)), - const_op01)) - return fold_build1_loc (loc, IMAGPART_EXPR, type, op00); - } - /* ((foo *)&fooarray)[1] => fooarray[1] */ - else if (TREE_CODE (op00type) == ARRAY_TYPE - && similar_type_p (type, TREE_TYPE (op00type))) - { - tree type_domain = TYPE_DOMAIN (op00type); - tree min_val = size_zero_node; - if (type_domain && TYPE_MIN_VALUE (type_domain)) - min_val = TYPE_MIN_VALUE (type_domain); - offset_int off = wi::to_offset (op01); - offset_int el_sz = wi::to_offset (TYPE_SIZE_UNIT (type)); - offset_int remainder; - off = wi::divmod_trunc (off, el_sz, SIGNED, &remainder); - if (remainder == 0 && TREE_CODE (min_val) == INTEGER_CST) - { - off = off + wi::to_offset (min_val); - op01 = wide_int_to_tree (sizetype, off); - return build4_loc (loc, ARRAY_REF, type, op00, op01, - NULL_TREE, NULL_TREE); - } - } - /* Also handle conversion to an empty base class, which - is represented with a NOP_EXPR. */ - else if (is_empty_class (type) - && CLASS_TYPE_P (op00type) - && DERIVED_FROM_P (type, op00type)) - { - *empty_base = true; - return op00; - } - /* ((foo *)&struct_with_foo_field)[1] => COMPONENT_REF */ - else if (RECORD_OR_UNION_TYPE_P (op00type)) - { - tree field = TYPE_FIELDS (op00type); - for (; field; field = DECL_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL - && TREE_TYPE (field) != error_mark_node - && tree_int_cst_equal (byte_position (field), op01) - && similar_type_p (TREE_TYPE (field), type)) - return fold_build3 (COMPONENT_REF, type, op00, - field, NULL_TREE); - } - } + return cxx_fold_indirect_ref_1 (loc, type, TREE_OPERAND (op00, 0), + tree_to_uhwi (op01), empty_base); } /* *(foo *)fooarrptr => (*fooarrptr)[0] */ else if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1dce341..60e6caa 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,17 @@ 2019-10-04 Jakub Jelinek <jakub@redhat.com> + PR c++/71504 + * g++.dg/cpp0x/constexpr-array21.C: New test. + * g++.dg/cpp1y/constexpr-array7.C: New test. + * g++.dg/cpp1z/constexpr-array1.C: New test. + +2019-10-04 Jason Merrill <jason@redhat.com> + + PR c++/71504 + * g++.dg/cpp0x/constexpr-array20.C: New test. + +2019-10-04 Jakub Jelinek <jakub@redhat.com> + PR c++/91974 * g++.dg/cpp1z/eval-order5.C: New test. diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array20.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array20.C new file mode 100644 index 0000000..217bbf4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array20.C @@ -0,0 +1,15 @@ +// PR c++/71504 +// { dg-do compile { target c++11 } } + +enum E { e }; + +constexpr bool arr[1][1] = {{true}}; + +template<E x, E y> +void check() { + static_assert(arr[x][y], ""); +} + +int main() { + check<e, e>(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array21.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array21.C new file mode 100644 index 0000000..e085098 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array21.C @@ -0,0 +1,27 @@ +// PR c++/71504 +// { dg-do compile { target c++11 } } + +typedef const char A4 [10]; + +constexpr A4 a [] = { "123", "123456", "123456789" }; + +constexpr int len (const char *s) +{ + return *s ? 1 + len (s + 1) : 0; +} + +constexpr const char *s = a[0]; +constexpr const char *t = (a + 2)[-2]; + +constexpr int n0 = len (s); +constexpr int n1 = len (t); + +constexpr int n2 = len (a[0]); +constexpr int n3 = len ((a + 2)[-2]); + +#define A(e) static_assert ((e), #e) + +A (n0 == 3); +A (n0 == n1); +A (n0 == n2); +A (n0 == n3); diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-array7.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-array7.C new file mode 100644 index 0000000..30bd8fd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1y/constexpr-array7.C @@ -0,0 +1,16 @@ +// PR c++/71504 +// { dg-do compile { target c++14 } } + +template <typename A> +constexpr auto +sum (A const &a) +{ + int tot = 0; + for (auto &row : a) + for (auto elem : row) + tot += elem; + return tot; +} + +constexpr int const a22[2][2] = {{1,2},{3,4}}; +static_assert (sum(a22) == 10, "badsum"); diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-array1.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-array1.C new file mode 100644 index 0000000..02435d5 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-array1.C @@ -0,0 +1,46 @@ +// PR c++/71504 +// { dg-do compile { target c++17 } } + +typedef __SIZE_TYPE__ size_t; +template <typename T, T v> +struct integral_constant +{ + static constexpr T value = v; + typedef T value_type; + typedef integral_constant<T, v> type; + constexpr operator value_type () const noexcept { return value; } + constexpr value_type operator() () const noexcept { return value; } +}; +template <typename T, T v> +constexpr T integral_constant<T, v>::value; +typedef integral_constant<bool, true> true_type; +typedef integral_constant<bool, false> false_type; +template <typename> +struct is_array : public false_type { }; +template <typename T, size_t s> +struct is_array<T[s]> : public true_type { }; +template <typename T> +struct is_array<T[]> : public true_type { }; +template <bool, typename, typename> +struct conditional; +template <bool C, typename T, typename F> +struct conditional { typedef T type; }; +template <typename T, typename F> +struct conditional<false, T, F> { typedef F type; }; +template <typename T> +struct array_ref; +template <typename T> +using ref_t = typename conditional<is_array<T>::value, array_ref<T>, T&>::type; +template <typename T, unsigned N> +struct array_ref<T[N]> +{ + T *a; + using const_reference = const ref_t<T>; + constexpr const_reference operator[] (unsigned I) const { return {a[I]}; } +}; +template <typename A> +array_ref (A&) -> array_ref<A>; +constexpr int a2[2] = {1,2}; +static_assert (array_ref{a2}[0] == 1); +constexpr int a22[2][2] = {{1,2},{3,4}}; +static_assert (array_ref{a22}[0][0] == 1); |