https://godbolt.org/z/93qM1b ==== struct A { constexpr A() { c[0] = 0; } char c[2]; }; constexpr A a; ====
Confirmed with -std=c++20. In earlier modes GCC rejects the test case as expected. $ (set -x && gcc -O2 -S -Wall -std=c++20 pr99700.C && gcc -O2 -S -Wall -std=c++17 pr99700.C) + gcc -O2 -S -Wall -std=c++20 pr99700.C + gcc -O2 -S -Wall -std=c++17 pr99700.C pr99700.C: In constructor ‘constexpr A::A()’: pr99700.C:2:29: error: member ‘A::c’ must be initialized by mem-initializer in ‘constexpr’ constructor 2 | constexpr A() { c[0] = 0; } | ^ pr99700.C:3:8: note: declared here 3 | char c[2]; | ^ pr99700.C: At global scope: pr99700.C:6:13: error: ‘constexpr A::A()’ called in a constant expression 6 | constexpr A a; | ^ pr99700.C:2:13: note: ‘constexpr A::A()’ declared here 2 | constexpr A() { c[0] = 0; } | ^ When reporting bugs please include all the information we ask for here: https://gcc.gnu.org/bugs/#need. Links to other sites are not a substitute.
Bisection points to r279019 AKA the fix for PR c++/91353 as the first revision when the code started to be accepted.
It seems reduced_constant_expression_p needs to check that a CONSTRUCTOR_NO_CLEARING array ctor initializes all elements. I'm testing: diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index c8d9dae36fb..6e530f9c88d 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. */ @@ -2912,7 +2913,25 @@ reduced_constant_expression_p (tree t) else if (cxx_dialect >= cxx20 /* An ARRAY_TYPE doesn't have any TYPE_FIELDS. */ && TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) - field = NULL_TREE; + { + tree min = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (t))); + tree max = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (t))); + if (find_array_ctor_elt (t, min) == -1 + || find_array_ctor_elt (t, max) == -1) + return false; + tree cursor = size_zero_node; + 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); + } + return true; + } else if (cxx_dialect >= cxx20 && TREE_CODE (TREE_TYPE (t)) == UNION_TYPE) {
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>: https://gcc.gnu.org/g:baf05d54dc919c968d12de9d049e36e5bac10dec commit r11-8216-gbaf05d54dc919c968d12de9d049e36e5bac10dec Author: Patrick Palka <ppalka@redhat.com> Date: Fri Apr 16 09:24:46 2021 -0400 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.
Fixed for GCC 11 so far.
The patch doesn't apply cleanly to the 10 branch, and since this is only a C++20 regression, it doesn't seem worth backporting.