On 6/24/25 7:22 AM, Jakub Jelinek wrote:
Hi!
The following patch attempts to implement the C++26
P3533R2 - constexpr virtual inheritance
paper.
The changes include not rejecting it for C++26, tweaking the
error wording to show that it is valid in C++26, adjusting
synthesized_method_walk not to make synthetized cdtors non-constexpr
just because of virtual base classes in C++26 and various tweaks in
constexpr.cc so that it can deal with the expressions used for
virtual base member accesses or cdtor calls which need __in_chrg
and/or __vtt_parm arguments to be passed in some cases implicitly when
they aren't passed explicitly.
There are two places where I'm not sure what to do:
1) one can be seen on the constexpr-ice21.C testcase:
struct NoMut1 { int a, b; };
struct NoMut3 : virtual NoMut1 { constexpr NoMut3(int a, int b) : NoMut1{a, b}
{} };
void mutable_subobjects() {
constexpr NoMut3 nm3 = {1, 2};
struct A {
void f() {
static_assert(nm3.a == 1, ""); // ERROR here: "local variable"
}
};
}
The two other errors on the testcase are expectedly gone with C++26,
but the last one remains. The problem is that when parsing nm3.a
inside of mutable_subobjects()::A::f()
build_class_member_access_expr calls build_base_path which calls
cp_build_addr_expr and that makes nm3 odr-used. I must say I have
no idea whether nm3 ought to be odr-used or not just because of nm3.a
use and if not, how that should be changed.
build_simple_base_path is how we avoid this odr-use; seems we also need
to use it early in the case of (v_binfo && !virtual_access).
Plus whether the fact
if nm3.a is odr-use or not is somehow affected by the (so far unimplemented)
part of P2686R4 paper.
2) another one can be seen on the constexpr-dynamic10.C testcase
struct C { virtual void a(); };
struct B { virtual void b(); };
struct A : virtual B, C { virtual void c(); };
constexpr A a;
constexpr bool b1 = (dynamic_cast<C&>((B&)a), false); // ERROR here "reference
'dynamic_cast' failed"
I think the error is incorrect here, because
struct C { virtual void a(); };
struct B { virtual void b(); };
struct A : virtual B, C { virtual void c(); };
A a;
bool b1 = (dynamic_cast<C&>((B&)a), false);
int
main ()
{
C &c = dynamic_cast<C&>((B&)a);
C &c2 = dynamic_cast<C&>(a);
}
works at runtime. In the patch I've adjusted the function
comment of cxx_eval_dynamic_cast_fn because with virtual bases
I believe hint -1 might be possible, though I'm afraid I don't
Yes, we would get -1 for dynamic_cast from B to A.
know enough about dynamic_cast and cxx_eval_dynamic_cast_fn
to figure out what needs to change there. It is hint -2 that
fails, not hint -1.
Yes, this is a -2 case because C does not derive from B.
How does cxx_eval_dynamic_cast_fn fail in this case? From looking at
the function it seems like it ought to work.
Jason