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;

Reply via email to