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