On 1/23/25 12:20 PM, Simon Martin wrote:
Hi Jason,

On 21 Jan 2025, at 22:51, Jason Merrill wrote:

On 1/3/25 3:00 PM, Simon Martin wrote:
We currently accept this code with c++ <= 17 even though it's invalid
since the base is not initialized (we properly reject it with c++ >=
20)

=== cut here ===
struct NoMut1 { int a, b; };
struct NoMut3 : NoMut1 {
    constexpr NoMut3(int a, int b) {}
};
void mutable_subobjects() {
    constexpr NoMut3 nm3(1, 2);
}
=== cut here ===

This is a fallout of r0-118700-gc2b3ec18a494e3, that ignores all
fields
with DECL_ARTIFICIAL in cx_check_missing_mem_inits, including those
that
represent base classes, and need to be checked.

This patch makes sure that we only skip fields that have
DECL_ARTIFICIAL
if they don't have DECL_FIELD_IS_BASE.

Successfully tested on x86_64-pc-linux-gnu.

        PR c++/118239

gcc/cp/ChangeLog:

        * constexpr.cc (cx_check_missing_mem_inits): Don't skip fields
        with DECL_FIELD_IS_BASE.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp0x/constexpr-base8.C: New test.

---
   gcc/cp/constexpr.cc                          |  8 +++----
   gcc/testsuite/g++.dg/cpp0x/constexpr-base8.C | 24
++++++++++++++++++++
   2 files changed, 28 insertions(+), 4 deletions(-)
   create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-base8.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index c8be5a525ee..e11444438d3 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -839,9 +839,8 @@ cx_check_missing_mem_inits (tree ctype, tree
body, bool complain)
         if (i < nelts)
        {
          index = CONSTRUCTOR_ELT (body, i)->index;
-         /* Skip base and vtable inits.  */
-         if (TREE_CODE (index) != FIELD_DECL
-             || DECL_ARTIFICIAL (index))
+         /* Skip vtable inits.  */
+         if (TREE_CODE (index) != FIELD_DECL)
            continue;

The code after your change no longer skips vtable inits; this should
make the same DECL_FIELD_IS_BASE adjustment as below.
Ouch, thanks for catching this! I hate that I could break things like
this, so I tried to craft a test case that would have failed, but was
not able to so far :-(

I can see that you added this DECL_ARTIFICIAL check via
93a85785e0d08d149077f342201b9952a84669a7, and obviously the tests that
you’d added at that time worked even with my mistake. Do you have any
suggestion about what kind of construct could hit this code I broke, so
that I add a test case along with my next patch revision?

Well, I'm not sure there is such a testcase. The earlier checks skip actual initializers, while the later checks skip members without corresponding initializers. So if we see a vptr initializer and no longer skip it early, as long as its initializer's position in the CONSTRUCTOR matches the position of the vptr in TYPE_FIELDS, we'll continue through the loop normally.

The case where this could cause a problem would be if the CONSTRUCTOR order doesn't match the TYPE_FIELDS order for some reason. I think that this shouldn't ever happen currently, because a class with virtual bases can't have a constexpr constructor, and non-virtual bases are laid out in order. If C++ ever supports constexpr virtual bases, we'll need to handle them specially here.

So actually I think your change is fine. I'd just clarify the comment to say "Skip vptr adjustment represented with a COMPONENT_REF."

OK with that change.

Jason

Reply via email to