diff options
author | Patrick Palka <ppalka@redhat.com> | 2021-04-16 09:24:46 -0400 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2021-04-16 09:24:46 -0400 |
commit | baf05d54dc919c968d12de9d049e36e5bac10dec (patch) | |
tree | 27466678b6db6aec3db06272c99efde1b6a2b651 /gcc/cp/constexpr.c | |
parent | 47f42744f6e10ad41db926d739306e6f237fd3ac (diff) | |
download | gcc-baf05d54dc919c968d12de9d049e36e5bac10dec.zip gcc-baf05d54dc919c968d12de9d049e36e5bac10dec.tar.gz gcc-baf05d54dc919c968d12de9d049e36e5bac10dec.tar.bz2 |
c++: partially initialized constexpr array [PR99700]
Here, reduced_constant_expression_p is incorrectly returning true for a
partially initialized array CONSTRUCTOR (in C++20 mode) because when the
CONSTRUCTOR_NO_CLEARING flag is set, the predicate doesn't check that
the CONSTRUCTOR spans the entire array like it does for class CONSTRUCTORS.
This patch adds a dedicated loop for the array case that simultaneously
verifies the CONSTRUCTOR spans the entire array and is made up of valid
constant expressions.
gcc/cp/ChangeLog:
PR c++/99700
* constexpr.c (reduced_constant_expression_p): For array
CONSTRUCTORs, use a dedicated loop that additionally verifies
the CONSTRUCTOR spans the entire array.
gcc/testsuite/ChangeLog:
PR c++/99700
* g++.dg/cpp2a/constexpr-init21.C: New test.
Diffstat (limited to 'gcc/cp/constexpr.c')
-rw-r--r-- | gcc/cp/constexpr.c | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index c8d9dae..b74bbac 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -46,6 +46,7 @@ do { \ static HOST_WIDE_INT find_array_ctor_elt (tree ary, tree dindex, bool insert = false); +static int array_index_cmp (tree key, tree index); /* Returns true iff FUN is an instantiation of a constexpr function template or a defaulted constexpr function. */ @@ -2910,9 +2911,27 @@ reduced_constant_expression_p (tree t) /* An initialized vector would have a VECTOR_CST. */ return false; else if (cxx_dialect >= cxx20 - /* An ARRAY_TYPE doesn't have any TYPE_FIELDS. */ && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) - field = NULL_TREE; + { + /* There must be a valid constant initializer at every array + index. */ + tree min = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t))); + tree max = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (t))); + tree cursor = min; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), i, idx, val) + { + if (!reduced_constant_expression_p (val)) + return false; + if (array_index_cmp (cursor, idx) != 0) + return false; + if (TREE_CODE (idx) == RANGE_EXPR) + cursor = TREE_OPERAND (idx, 1); + cursor = int_const_binop (PLUS_EXPR, cursor, size_one_node); + } + if (find_array_ctor_elt (t, max) == -1) + return false; + goto ok; + } else if (cxx_dialect >= cxx20 && TREE_CODE (TREE_TYPE (t)) == UNION_TYPE) { @@ -2946,6 +2965,7 @@ reduced_constant_expression_p (tree t) for (; field; field = next_initializable_field (DECL_CHAIN (field))) if (!is_really_empty_class (TREE_TYPE (field), /*ignore_vptr*/false)) return false; +ok: if (CONSTRUCTOR_NO_CLEARING (t)) /* All the fields are initialized. */ CONSTRUCTOR_NO_CLEARING (t) = false; |