https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88335
--- Comment #18 from Jakub Jelinek <jakub at gcc dot gnu.org> --- Testcase for pmf (incomplete, guess the non-pmf calls should be converted too): struct S { constexpr S () : s (0) {} virtual int foo () const { return 42; } consteval virtual int bar () const { return 43; } consteval virtual int baz () const { return 44; } int s; }; struct T : public S { constexpr T () : t (0) {} consteval int bar () const { return 45; } consteval virtual int baz () const { return 46; } int t; }; consteval int foo () { S s; T t; S *u = (S *) &t; T *v = &t; auto pmf1 = &S::bar; auto pmf2 = &S::baz; if ((s.*pmf1) () != 43) throw 1; if ((s.*pmf2) () != 44) throw 2; if ((t.*pmf1) () != 45) throw 3; if ((t.*pmf2) () != 46) throw 4; if ((u->*pmf1) () != 45) throw 5; if ((u->*pmf2) () != 46) throw 6; return 0; } constexpr S s; constexpr T t; constexpr const S * bar (bool x) { return x ? &s : (const S *) &t; } int a = foo (); int b = bar (false)->bar (); int c = bar (true)->baz (); static_assert (bar (false)->bar () == 45); static_assert (bar (true)->baz () == 44); Not sure what to do there, expand_ptrmemfunc_cst uses DECL_VINDEX which for immediate virtual functions is negative. It could transform those into positive say by adding list_length (BINFO_VIRTUALS ()) to it, but during the constexpr evaluation it isn't evaluated as some kind of OBJ_TYPE_REF, but rather dereference of the vtable. And, for vtable decls we don't want the consteval methods in there, so maybe cxx_eval_constant_call would need to figure out it is a PMF call to a consteval method and look it up in BINFO_VIRTUALS chain rather than actually in the vtable. Testcase for covariants, this one compiles, but fails the assertion. It is covariant2.C where I had to s/virtual/public/ on the D prototype, so that D's ctor could be constexpr, so maybe it is ok it works this way. // { dg-do compile { target c++2a } } struct B1; struct B2; struct D; struct B1 { virtual consteval const B1 *foo1 () const {return this;} consteval virtual const B2 *foo2 (const D *) const; }; struct B2 { consteval virtual const B2 *baz1 () const {return this;} consteval virtual const B1 *baz2 (const D *) const; }; struct D : public B1, B2 { virtual consteval const D *foo1 () const {return this;} virtual consteval const D *foo2 (const D *d) const {return d;} consteval virtual const D *baz1 () const {return this;} virtual consteval const D *baz2 (const D *d) const {return d;} }; consteval const B2 *B1::foo2 (const D *d) const {return d;} consteval const B1 *B2::baz2 (const D *d) const {return d;} consteval int test (const B1 *b1, const B2 *b2, const D *d) { if (b1->foo1 () != b1) return 1; if (b2->baz1 () != b2) return 2; if (b1->foo2 (d) != b2) return 3; if (b2->baz2 (d) != b1) return 4; return 0; } consteval int test (const D *d) { if (d->foo2 (d) != d) return 11; if (d->baz2 (d) != d) return 12; if (d->foo1 () != d) return 13; if (d->baz1 () != d) return 14; return 0; } constexpr D d; constexpr auto e = test (&d, &d, &d); constexpr auto f = test (&d); //static_assert (e == 0); static_assert (f == 0); int g = e;