From e069285cdf457cc85070e522380c4e25b0d2ed25 Mon Sep 17 00:00:00 2001 From: Patrick Palka Date: Fri, 29 May 2020 09:44:09 -0400 Subject: [PATCH] c++: constexpr ctor with RANGE_EXPR index [PR95241] In the testcase below, the CONSTRUCTOR for 'field' contains a RANGE_EXPR index: {{aggr_init_expr<...>, [1...2]={.off=1}}} but get_or_insert_ctor_field isn't prepared to handle looking up a RANGE_EXPR index. This patch adds limited support to get_or_insert_ctor_field for looking up a RANGE_EXPR index. The limited scope of this patch should make it more suitable for backporting, and more extensive support would be needed only to handle self-modifying CONSTRUCTORs that contain a RANGE_EXPR index, but I haven't yet been able to come up with a testcase that actually creates such a CONSTRUCTOR. gcc/cp/ChangeLog: PR c++/95241 * constexpr.c (get_or_insert_ctor_field): Add limited support for RANGE_EXPR index lookups. gcc/testsuite/ChangeLog: PR c++/95241 * g++.dg/cpp0x/constexpr-array25.C: New test. --- gcc/cp/constexpr.c | 16 ++++++++++++++++ gcc/testsuite/g++.dg/cpp0x/constexpr-array25.C | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-array25.C diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 4b1f92f..959f025 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -3299,6 +3299,22 @@ get_or_insert_ctor_field (tree ctor, tree index, int pos_hint = -1) } else if (TREE_CODE (type) == ARRAY_TYPE || TREE_CODE (type) == VECTOR_TYPE) { + if (TREE_CODE (index) == RANGE_EXPR) + { + /* Support for RANGE_EXPR index lookups is currently limited to + accessing an existing element via POS_HINT, or appending a new + element to the end of CTOR. ??? Support for other access + patterns may also be needed. */ + vec *elts = CONSTRUCTOR_ELTS (ctor); + if (vec_safe_length (elts)) + { + tree lo = TREE_OPERAND (index, 0); + gcc_assert (array_index_cmp (elts->last().index, lo) < 0); + } + CONSTRUCTOR_APPEND_ELT (elts, index, NULL_TREE); + return &elts->last(); + } + HOST_WIDE_INT i = find_array_ctor_elt (ctor, index, /*insert*/true); gcc_assert (i >= 0); constructor_elt *cep = CONSTRUCTOR_ELT (ctor, i); diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array25.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-array25.C new file mode 100644 index 0000000..9162943 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array25.C @@ -0,0 +1,21 @@ +// PR c++/95241 +// { dg-do compile { target c++11 } } + +struct Fragment +{ + int off; + constexpr Fragment(int _off) : off(_off) { } + constexpr Fragment() : Fragment(1) { } +}; + +struct Field +{ + Fragment fragments[3]; + constexpr Field(int off) : fragments{{off}} { } +}; + +constexpr Field field{0}; + +static_assert(field.fragments[0].off == 0 + && field.fragments[1].off == 1 + && field.fragments[2].off == 1, ""); -- 2.7.4