// { dg-do run }
|
// { dg-do run }
|
// { dg-options "-fno-strict-aliasing" }
|
// { dg-options "-fno-strict-aliasing" }
|
// Origin: Mark Mitchell
|
// Origin: Mark Mitchell
|
|
|
/* Generally, the lowest bit of the ptr is used to indicate whether a
|
/* Generally, the lowest bit of the ptr is used to indicate whether a
|
ptr-to-mem-func points to a virtual or a non-virtual member
|
ptr-to-mem-func points to a virtual or a non-virtual member
|
function. However, some platforms use all bits to encode a
|
function. However, some platforms use all bits to encode a
|
function pointer. Such platforms use the lowest bit of the delta,
|
function pointer. Such platforms use the lowest bit of the delta,
|
that is shifted left by one bit. */
|
that is shifted left by one bit. */
|
#if defined __MN10300__ || defined __SH5__ || defined __arm__ || defined __thumb__ || defined __mips__
|
#if defined __MN10300__ || defined __SH5__ || defined __arm__ || defined __thumb__ || defined __mips__
|
#define ADJUST_PTRFN(func, virt) ((void (*)())(func))
|
#define ADJUST_PTRFN(func, virt) ((void (*)())(func))
|
#define ADJUST_DELTA(delta, virt) (((delta) << 1) + !!(virt))
|
#define ADJUST_DELTA(delta, virt) (((delta) << 1) + !!(virt))
|
#else
|
#else
|
#define ADJUST_PTRFN(func, virt) ((void (*)())((ptrdiff_t)(func) + !!(virt)))
|
#define ADJUST_PTRFN(func, virt) ((void (*)())((ptrdiff_t)(func) + !!(virt)))
|
#define ADJUST_DELTA(delta, virt) (delta)
|
#define ADJUST_DELTA(delta, virt) (delta)
|
#endif
|
#endif
|
|
|
/* IA64 uses function descriptors instead of function pointers in its
|
/* IA64 uses function descriptors instead of function pointers in its
|
vtables, which means that we can't meaningfully compare them directly. */
|
vtables, which means that we can't meaningfully compare them directly. */
|
#if defined __ia64__
|
#if defined __ia64__
|
#define CMP_PTRFN(A, B) (*(void **)(A) == *(void **)(B))
|
#define CMP_PTRFN(A, B) (*(void **)(A) == *(void **)(B))
|
#define VPTE_SIZE (16)
|
#define VPTE_SIZE (16)
|
#else
|
#else
|
#define CMP_PTRFN(A, B) ((A) == (B))
|
#define CMP_PTRFN(A, B) ((A) == (B))
|
#define VPTE_SIZE sizeof(void *)
|
#define VPTE_SIZE sizeof(void *)
|
#endif
|
#endif
|
|
|
#if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
|
#if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
|
|
|
// Check that pointers-to-member functions are represented correctly.
|
// Check that pointers-to-member functions are represented correctly.
|
|
|
#include
|
#include
|
|
|
struct S
|
struct S
|
{
|
{
|
int i;
|
int i;
|
int j;
|
int j;
|
};
|
};
|
|
|
// Because S does not have a VPTR, it will not be a primary base of T,
|
// Because S does not have a VPTR, it will not be a primary base of T,
|
// and will therefore end up at a nonzero offset.
|
// and will therefore end up at a nonzero offset.
|
|
|
struct T : public S
|
struct T : public S
|
{
|
{
|
void f () {}
|
void f () {}
|
virtual void g () {}
|
virtual void g () {}
|
virtual void h () {}
|
virtual void h () {}
|
};
|
};
|
|
|
// Provide access to the raw function pointers. This is
|
// Provide access to the raw function pointers. This is
|
// mangling-dependent.
|
// mangling-dependent.
|
|
|
extern "C" void _ZN1T1fEv ();
|
extern "C" void _ZN1T1fEv ();
|
extern "C" void _ZN1T1gEv ();
|
extern "C" void _ZN1T1gEv ();
|
extern "C" void _ZN1T1hEv ();
|
extern "C" void _ZN1T1hEv ();
|
|
|
// This structure is a C representation of a pointer-to-member.
|
// This structure is a C representation of a pointer-to-member.
|
|
|
struct ptrmemfunc
|
struct ptrmemfunc
|
{
|
{
|
void (*ptr) ();
|
void (*ptr) ();
|
ptrdiff_t adj;
|
ptrdiff_t adj;
|
};
|
};
|
|
|
typedef int S::*sdp;
|
typedef int S::*sdp;
|
typedef void (S::*sp)();
|
typedef void (S::*sp)();
|
typedef void (T::*tp)();
|
typedef void (T::*tp)();
|
|
|
int
|
int
|
main ()
|
main ()
|
{
|
{
|
S s;
|
S s;
|
T t;
|
T t;
|
sp x;
|
sp x;
|
tp y;
|
tp y;
|
ptrmemfunc *xp = (ptrmemfunc *) &x;
|
ptrmemfunc *xp = (ptrmemfunc *) &x;
|
ptrmemfunc *yp = (ptrmemfunc *) &y;
|
ptrmemfunc *yp = (ptrmemfunc *) &y;
|
ptrdiff_t delta = ((char *) &t) - ((char*) (S*) (&t));
|
ptrdiff_t delta = ((char *) &t) - ((char*) (S*) (&t));
|
|
|
// Pointers-to-function-members should have the same size and
|
// Pointers-to-function-members should have the same size and
|
// alignment as the PTRMEMFUNC type.
|
// alignment as the PTRMEMFUNC type.
|
if (sizeof (sp) != sizeof (ptrmemfunc))
|
if (sizeof (sp) != sizeof (ptrmemfunc))
|
return 1;
|
return 1;
|
if (__alignof__ (sp) != __alignof__ (ptrmemfunc))
|
if (__alignof__ (sp) != __alignof__ (ptrmemfunc))
|
return 2;
|
return 2;
|
|
|
// The NULL pointer-to-member should have a NULL first PTR field.
|
// The NULL pointer-to-member should have a NULL first PTR field.
|
x = 0;
|
x = 0;
|
if (xp->ptr != 0)
|
if (xp->ptr != 0)
|
return 3;
|
return 3;
|
y = x;
|
y = x;
|
if (yp->ptr != 0)
|
if (yp->ptr != 0)
|
return 4;
|
return 4;
|
|
|
// A non-virtual function should have a pointer to the function.
|
// A non-virtual function should have a pointer to the function.
|
// There should be no adjustment for the `T' version, and an
|
// There should be no adjustment for the `T' version, and an
|
// appropriate adjustment for the `S' version.
|
// appropriate adjustment for the `S' version.
|
y = &T::f;
|
y = &T::f;
|
if (! CMP_PTRFN (yp->ptr, ADJUST_PTRFN (&_ZN1T1fEv, 0)))
|
if (! CMP_PTRFN (yp->ptr, ADJUST_PTRFN (&_ZN1T1fEv, 0)))
|
return 5;
|
return 5;
|
if (yp->adj != ADJUST_DELTA (0, 0))
|
if (yp->adj != ADJUST_DELTA (0, 0))
|
return 6;
|
return 6;
|
x = (sp) y;
|
x = (sp) y;
|
if (! CMP_PTRFN (xp->ptr, ADJUST_PTRFN (&_ZN1T1fEv, 0)))
|
if (! CMP_PTRFN (xp->ptr, ADJUST_PTRFN (&_ZN1T1fEv, 0)))
|
return 7;
|
return 7;
|
if (xp->adj != ADJUST_DELTA (delta, 0))
|
if (xp->adj != ADJUST_DELTA (delta, 0))
|
return 8;
|
return 8;
|
|
|
// For a virtual function, we should see the vtable offset, plus
|
// For a virtual function, we should see the vtable offset, plus
|
// one. `T::h' is in the second slot: the vtable pointer points to
|
// one. `T::h' is in the second slot: the vtable pointer points to
|
// the first virtual function.
|
// the first virtual function.
|
y = &T::h;
|
y = &T::h;
|
if (yp->ptr != ADJUST_PTRFN (VPTE_SIZE, 1))
|
if (yp->ptr != ADJUST_PTRFN (VPTE_SIZE, 1))
|
return 9;
|
return 9;
|
if (yp->adj != ADJUST_DELTA (0, 1))
|
if (yp->adj != ADJUST_DELTA (0, 1))
|
return 10;
|
return 10;
|
x = (sp) y;
|
x = (sp) y;
|
if (xp->ptr != ADJUST_PTRFN (VPTE_SIZE, 1))
|
if (xp->ptr != ADJUST_PTRFN (VPTE_SIZE, 1))
|
return 11;
|
return 11;
|
if (xp->adj != ADJUST_DELTA (delta, 1))
|
if (xp->adj != ADJUST_DELTA (delta, 1))
|
return 12;
|
return 12;
|
|
|
// Pointers-to-data-members should have the same size and alignment
|
// Pointers-to-data-members should have the same size and alignment
|
// as a ptrdiff_t.
|
// as a ptrdiff_t.
|
if (sizeof (sdp) != sizeof (ptrdiff_t))
|
if (sizeof (sdp) != sizeof (ptrdiff_t))
|
return 13;
|
return 13;
|
if (__alignof__ (sdp) != __alignof__ (ptrdiff_t))
|
if (__alignof__ (sdp) != __alignof__ (ptrdiff_t))
|
return 14;
|
return 14;
|
|
|
// The value of a pointer-to-data member should be the offset from
|
// The value of a pointer-to-data member should be the offset from
|
// the start of the structure.
|
// the start of the structure.
|
sdp z = &S::j;
|
sdp z = &S::j;
|
if ((char *) &s.j - (char *) &s != *((ptrdiff_t *) &z))
|
if ((char *) &s.j - (char *) &s != *((ptrdiff_t *) &z))
|
return 15;
|
return 15;
|
z = 0;
|
z = 0;
|
if (*((ptrdiff_t *) &z) != -1)
|
if (*((ptrdiff_t *) &z) != -1)
|
return 16;
|
return 16;
|
}
|
}
|
|
|
#else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
|
#else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
|
|
|
int main ()
|
int main ()
|
{
|
{
|
}
|
}
|
|
|
#endif /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
|
#endif /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */
|
|
|