// { dg-do run }
// { dg-options "-fno-strict-aliasing" }
// Origin: Mark Mitchell <mark@codesourcery.com>
#if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
#include <stddef.h>
struct S0
{
virtual void s0 ();
};
struct S1 : virtual public S0
{
virtual void s1 ();
};
struct S2 : virtual public S1
{
virtual void s1 ();
virtual void s0 ();
};
struct S3
{
virtual void s3 ();
};
struct S4 : public S3, virtual public S2
{
virtual void s1 ();
};
void S0::s0 ()
{
}
void S1::s1 ()
{
}
void S2::s1 ()
{
}
void S2::s0 ()
{
}
void S3::s3 ()
{
}
void S4::s1 ()
{
}
/* The vtables should look like:
S0 primary vtable
S0 offset to top
S0 RTTI
S0::s0
=================
S1 primary vtable
S0::s0 vcall offset
S0 vbase offset
S1 offset to top
S1 RTTI
S0::s0
S1::s1
=================
S2 primary vtable
S2::s1 vcall offset
S1 vbase offset
S2::s0 vcall offset
S0 vbase offset
S2 offset to top
S2 RTTI
S2::s0
S2::s1
=================
S3 primary vtable
S3 offset to top
S3 RTTI
S3::s3
=================
S4 primary vtable
vbase offset for S0
vbase offset for S1
vbase offset for S2
S4 offset to top
S4 RTTI
S3::s3
S4::s1
S2-in-S4 secondary vtable
S1 vbase offset
S4::s1 vcall offset
S0 vbase offset
S2:s0 vcall offset
S2 offset to top
S4 RTTI
S2::s0
S4::s1
*/
// These are tricks to allow us to get raw function pointers for
// member functions.
extern "C" {
/* We can use weakref here without dg-require-weak, because we know
the symbols are defined, so we don't actually issue the .weak
directives. */
static void S3_s3 () __attribute__((__weakref__ ("_ZN2S32s3Ev")));
static void S4_s1 () __attribute__((__weakref__ ("_ZN2S42s1Ev")));
}
// IA-64 uses function descriptors not function pointers in its vtables.
#if defined __ia64__
#define CMP_VPTR(A, B) (*(void **)(A) == *(void **)(B))
#ifdef _LP64
#define INC_VPTR(A) ((A) += 2)
#define INC_VDATA(A,N) ((A) += (N))
#else
#define INC_VPTR(A) ((A) += 4)
#define INC_VDATA(A,N) ((A) += 2*(N))
#endif
#else
#define CMP_VPTR(A, B) (*(A) == (ptrdiff_t)(B))
#define INC_VPTR(A) ((A) += 1)
#define INC_VDATA(A,N) ((A) += (N))
#endif
int main ()
{
S4 s4;
ptrdiff_t **vptr;
ptrdiff_t *vtbl;
// Set vtbl to point at the beginning of S4's primary vtable.
vptr = (ptrdiff_t **) &s4;
vtbl = *vptr;
INC_VDATA (vtbl, -5);
if (*vtbl != ((char*) (S0*) &s4) - (char*) &s4)
return 1;
INC_VDATA (vtbl, 1);
if (*vtbl != ((char*) (S1*) &s4) - (char*) &s4)
return 2;
INC_VDATA (vtbl, 1);
if (*vtbl != ((char*) (S2*) &s4) - (char*) &s4)
return 3;
INC_VDATA (vtbl, 1);
if (*vtbl != 0)
return 4;
INC_VDATA (vtbl, 1);
// Skip the RTTI entry.
INC_VDATA (vtbl, 1);
if (! CMP_VPTR (vtbl, &S3_s3))
return 5;
INC_VPTR (vtbl);
if (! CMP_VPTR (vtbl, &S4_s1))
return 6;
INC_VPTR (vtbl);
// The S1 vbase offset.
if (*vtbl != 0)
return 7;
INC_VDATA (vtbl, 1);
// The S4::s1 vcall offset is negative; once you convert to S2, you
// have to convert to S4 to find the final overrider.
if (*vtbl != ((char*) &s4 - (char*) (S2*) &s4))
return 8;
INC_VDATA (vtbl, 1);
if (*vtbl != 0)
return 9;
INC_VDATA (vtbl, 1);
if (*vtbl != 0)
return 10;
INC_VDATA (vtbl, 1);
// Now we're at the S2 offset to top entry.
if (*vtbl != ((char*) &s4 - (char*) (S2*) &s4))
return 11;
INC_VDATA (vtbl, 1);
// Skip the RTTI entry.
INC_VDATA (vtbl, 1);
// Skip the reint maining virtual functions -- they are thunks.
INC_VPTR (vtbl);
INC_VPTR (vtbl);
}
#else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
int main ()
{
}
#endif /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */