From: Patrick Palka <ppalka@redhat.com>
To: Patrick Palka <ppalka@redhat.com>
Cc: Jason Merrill <jason@redhat.com>, gcc-patches@gcc.gnu.org
Subject: Re: [PATCH] c++: constexpr init of union sub-aggr w/ base [PR105491]
Date: Fri, 6 May 2022 14:00:24 -0400 (EDT) [thread overview]
Message-ID: <48baf04b-9cb9-8668-cbb6-047eba1033d7@idea> (raw)
In-Reply-To: <7ab4b646-bade-97b0-8083-c392cf37ea49@idea>
On Fri, 6 May 2022, Patrick Palka wrote:
> On Fri, 6 May 2022, Jason Merrill wrote:
>
> > On 5/6/22 11:22, Patrick Palka wrote:
> > > 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, and
> > > so the function proceeds to verify that all fields of S are initialized.
> > > And before C++17 we don't expect to see base class fields (since
> > > next_initializable_field skips over the), so the base class initializer
> > > causes r_c_e_p to return false.
> >
> > That seems like the primary bug. I guess r_c_e_p shouldn't be using
> > next_initializable_field. Really that function should only be used for
> > aggregates.
>
> I see, I'll try replacing it in r_c_e_p. Would that be in addition to
> or instead of the clear_no_implicit_zero approach?
I'm testing the following, which uses a custom predicate instead of
next_initializable_field in r_c_e_p.
-- >8 --
gcc/cp/ChangeLog:
* constexpr.cc (reduced_constant_expression_p): Replace use of
next_initializable_field with custom predicate. Refactor to
remove the use of goto.
* decl.cc (next_initializable_field): Skip over vptr fields.
Document that this function is to be used only for aggregate
classes.
---
gcc/cp/constexpr.cc | 65 ++++++++++++++++++++++++++-------------------
gcc/cp/decl.cc | 15 +++++------
2 files changed, 44 insertions(+), 36 deletions(-)
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 9b1e71857fc..d1cd556591c 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3016,7 +3016,6 @@ reduced_constant_expression_p (tree t)
case CONSTRUCTOR:
/* And we need to handle PTRMEM_CST wrapped in a CONSTRUCTOR. */
- tree field;
if (CONSTRUCTOR_NO_CLEARING (t))
{
if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE)
@@ -3041,42 +3040,54 @@ reduced_constant_expression_p (tree t)
}
if (find_array_ctor_elt (t, max) == -1)
return false;
- goto ok;
}
- else if (cxx_dialect >= cxx20
- && TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
+ else if (TREE_CODE (TREE_TYPE (t)) == UNION_TYPE)
{
- if (CONSTRUCTOR_NELTS (t) == 0)
+ if (CONSTRUCTOR_NELTS (t) != 1)
/* An initialized union has a constructor element. */
return false;
- /* And it only initializes one member. */
- field = NULL_TREE;
+ if (!reduced_constant_expression_p (CONSTRUCTOR_ELT (t, 0)->value))
+ return false;
}
else
- field = next_initializable_field (TYPE_FIELDS (TREE_TYPE (t)));
+ {
+ /* Similar to the predicate used in next_initializable_field,
+ except that we additionally skip over empty types (for which
+ we don't require an initializer), and we always consider base
+ class fields (not just in C++17 mode) and vptr fields. */
+ auto ignorable_field_p = [] (tree field) {
+ if (!field)
+ return false;
+ return (TREE_CODE (field) != FIELD_DECL
+ || DECL_UNNAMED_BIT_FIELD (field)
+ || (DECL_ARTIFICIAL (field)
+ && !DECL_FIELD_IS_BASE (field)
+ && !DECL_VIRTUAL_P (field))
+ || is_really_empty_class (TREE_TYPE (field),
+ /*ignore_vptr*/false));
+ };
+ tree field = TYPE_FIELDS (TREE_TYPE (t));
+ for (auto &e: CONSTRUCTOR_ELTS (t))
+ {
+ if (!reduced_constant_expression_p (e.value))
+ return false;
+ while (e.index != field && ignorable_field_p (field))
+ field = DECL_CHAIN (field);
+ if (e.index == field)
+ field = DECL_CHAIN (field);
+ else
+ return false;
+ }
+ while (ignorable_field_p (field))
+ field = DECL_CHAIN (field);
+ if (field)
+ return false;
+ }
}
else
- field = NULL_TREE;
- for (auto &e: CONSTRUCTOR_ELTS (t))
- {
- /* If VAL is null, we're in the middle of initializing this
- element. */
+ for (auto &e: CONSTRUCTOR_ELTS (t))
if (!reduced_constant_expression_p (e.value))
return false;
- /* Empty class field may or may not have an initializer. */
- for (; field && e.index != field;
- field = next_initializable_field (DECL_CHAIN (field)))
- if (!is_really_empty_class (TREE_TYPE (field),
- /*ignore_vptr*/false))
- return false;
- if (field)
- field = next_initializable_field (DECL_CHAIN (field));
- }
- /* There could be a non-empty field at the end. */
- 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;
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index c9110db796a..c564e5e596d 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6382,10 +6382,10 @@ struct reshape_iter
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. */
+/* FIELD is an element of TYPE_FIELDS of an aggregate class, 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. */
tree
next_initializable_field (tree field)
@@ -6394,11 +6394,8 @@ next_initializable_field (tree 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. */
- && !DECL_VIRTUAL_P (field))))
+ /* In C++17, aggregates can have base classes. */
+ && !(cxx_dialect >= cxx17 && DECL_FIELD_IS_BASE (field)))))
field = DECL_CHAIN (field);
return field;
--
2.36.0.63.gf5aaf72f1b
next prev parent reply other threads:[~2022-05-06 18:00 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-05-06 15:22 Patrick Palka
2022-05-06 15:56 ` Jason Merrill
2022-05-06 16:04 ` Marek Polacek
2022-05-06 16:40 ` Patrick Palka
2022-05-06 18:00 ` Patrick Palka [this message]
2022-05-06 18:22 ` Jason Merrill
2022-05-06 19:24 ` Patrick Palka
2022-05-06 20:10 ` Patrick Palka
2022-05-06 20:27 ` Jason Merrill
2022-05-06 20:46 ` Patrick Palka
2022-05-07 21:18 ` Jason Merrill
2022-05-17 16:34 ` Patrick Palka
2022-05-18 14:22 ` Jason Merrill
2022-05-31 16:41 ` Patrick Palka
2022-05-31 19:06 ` Jason Merrill
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=48baf04b-9cb9-8668-cbb6-047eba1033d7@idea \
--to=ppalka@redhat.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jason@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).