aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/decl.cc
diff options
context:
space:
mode:
authorPatrick Palka <ppalka@redhat.com>2022-05-09 09:53:27 -0400
committerPatrick Palka <ppalka@redhat.com>2022-05-09 09:53:27 -0400
commit0c7bce0ac184c057bacad9c8e615ce82923835fd (patch)
tree0d9ce377d64297ac2850a6089423a6476efd7187 /gcc/cp/decl.cc
parentfcda0efccad41eba9134c1bd9d024a93d93fb82f (diff)
downloadgcc-0c7bce0ac184c057bacad9c8e615ce82923835fd.zip
gcc-0c7bce0ac184c057bacad9c8e615ce82923835fd.tar.gz
gcc-0c7bce0ac184c057bacad9c8e615ce82923835fd.tar.bz2
c++: constexpr init of union sub-aggr w/ base [PR105491]
Here ever since r10-7313-gb599bf9d6d1e18, reduced_constant_expression_p in C++11/14 is rejecting the marked sub-aggregate initializer (of type S) W w = {.D.2445={.s={.D.2387={.m=0}, .b=0}}}; ^ ultimately because said initializer has CONSTRUCTOR_NO_CLEARING set, hence the function must verify that all fields of S are initialized. And before C++17 it doesn't expect to see base class fields (since next_initializable_field skips over them), so the presence thereof causes r_c_e_p to return false. The reason r10-7313-gb599bf9d6d1e18 causes this is because in that commit we began using CONSTRUCTOR_NO_CLEARING to precisely track whether we're in middle of activating a union member. This ends up affecting clear_no_implicit_zero, which recurses into sub-aggregate initializers only if the outer initializer has CONSTRUCTOR_NO_CLEARING set. After that commit, the outer union initializer above no longer has the flag set at this point and so clear_no_implicit_zero no longer recurses into the marked inner initializer. But arguably r_c_e_p should be able to accept the marked initializer regardless of whether CONSTRUCTOR_NO_CLEARING is set. The primary bug therefore seems to be that r_c_e_p relies on next_initializable_field which skips over base class fields in C++11/14. To fix this, this patch introduces a new helper function next_subobject_field which is like next_initializable_field except that it never skips base class fields, and makes r_c_e_p use it. This patch then renames next_initializable_field to next_aggregate_field (and makes it skip over vptr fields again). PR c++/105491 gcc/cp/ChangeLog: * call.cc (field_in_pset): Adjust after next_initializable_field renaming. (build_aggr_conv): Likewise. (convert_like_internal): Likewise. (type_has_extended_temps): Likewise. * class.cc (default_init_uninitialized_part): Likewise. (finish_struct): Likewise. * constexpr.cc (cx_check_missing_mem_inits): Likewise. (reduced_constant_expression_p): Use next_subobject_field instead. * cp-gimplify.cc (get_source_location_impl_type): Adjust after next_initializable_field renaming. (fold_builtin_source_location): Likewise. * cp-tree.h (next_initializable_field): Rename to ... (next_aggregate_field): ... this. (next_subobject_field): Declare. * decl.cc (next_aggregate_field): Renamed from ... (next_initializable_field): ... this. Skip over vptr fields again. (next_subobject_field): Define. (reshape_init_class): Adjust after next_initializable_field renaming. * init.cc (build_value_init_noctor): Likewise. (emit_mem_initializers): Likewise. * lambda.cc (build_capture_proxy): Likewise. * method.cc (build_comparison_op): Likewise. * pt.cc (maybe_aggr_guide): Likewise. * tree.cc (structural_type_p): Likewise. * typeck2.cc (split_nonconstant_init_1): Likewise. (digest_init_r): Likewise. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/constexpr-union7.C: New test. * g++.dg/cpp0x/constexpr-union7a.C: New test. * g++.dg/cpp2a/constinit17.C: New test.
Diffstat (limited to 'gcc/cp/decl.cc')
-rw-r--r--gcc/cp/decl.cc36
1 files changed, 26 insertions, 10 deletions
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 0fa758f..872b02d 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6384,20 +6384,36 @@ static tree reshape_init_r (tree, reshape_iter *, tree, tsubst_flags_t);
/* FIELD is an element of TYPE_FIELDS or NULL. In the former case, the value
returned is the next FIELD_DECL (possibly FIELD itself) that can be
- initialized. If there are no more such fields, the return value
- will be NULL. */
+ initialized as if for an aggregate class. If there are no more such fields,
+ the return value will be NULL. */
tree
-next_initializable_field (tree field)
+next_aggregate_field (tree field)
{
while (field
&& (TREE_CODE (field) != FIELD_DECL
|| DECL_UNNAMED_BIT_FIELD (field)
|| (DECL_ARTIFICIAL (field)
- /* In C++17, don't skip base class fields. */
- && !(cxx_dialect >= cxx17 && DECL_FIELD_IS_BASE (field))
- /* Don't skip vptr fields. We might see them when we're
- called from reduced_constant_expression_p. */
+ /* In C++17, aggregates can have bases. */
+ && !(cxx_dialect >= cxx17 && DECL_FIELD_IS_BASE (field)))))
+ field = DECL_CHAIN (field);
+
+ return field;
+}
+
+/* FIELD is an element of TYPE_FIELDS or NULL. In the former case, the value
+ returned is the next FIELD_DECL (possibly FIELD itself) that corresponds
+ to a subobject. If there are no more such fields, the return value will be
+ NULL. */
+
+tree
+next_subobject_field (tree field)
+{
+ while (field
+ && (TREE_CODE (field) != FIELD_DECL
+ || DECL_UNNAMED_BIT_FIELD (field)
+ || (DECL_ARTIFICIAL (field)
+ && !DECL_FIELD_IS_BASE (field)
&& !DECL_VIRTUAL_P (field))))
field = DECL_CHAIN (field);
@@ -6595,7 +6611,7 @@ reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p,
if (base_binfo)
field = base_binfo;
else
- field = next_initializable_field (TYPE_FIELDS (type));
+ field = next_aggregate_field (TYPE_FIELDS (type));
if (!field)
{
@@ -6762,10 +6778,10 @@ reshape_init_class (tree type, reshape_iter *d, bool first_initializer_p,
if (BINFO_BASE_ITERATE (binfo, ++binfo_idx, base_binfo))
field = base_binfo;
else
- field = next_initializable_field (TYPE_FIELDS (type));
+ field = next_aggregate_field (TYPE_FIELDS (type));
}
else
- field = next_initializable_field (DECL_CHAIN (field));
+ field = next_aggregate_field (DECL_CHAIN (field));
}
/* A trailing aggregate element that is a pack expansion is assumed to