summaryrefslogtreecommitdiff
path: root/gcc/testsuite/g++.old-deja/g++.abi/ptrmem.C
blob: 077fa50840c978f9c0dda8c0e7071eda514395b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// { dg-do run  }
// { dg-options "-fno-strict-aliasing" }
// Origin: Mark Mitchell <mark@codesourcery.com>

/* 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
   function.  However, some platforms use all bits to encode a
   function pointer.  Such platforms use the lowest bit of the delta,
   that is shifted left by one bit.  */
#if defined __MN10300__ || defined __SH5__ || defined __arm__ || defined __thumb__ || defined __mips__
#define ADJUST_PTRFN(func, virt) ((void (*)())(func))
#define ADJUST_DELTA(delta, virt) (((delta) << 1) + !!(virt))
#else
#define ADJUST_PTRFN(func, virt) ((void (*)())((ptrdiff_t)(func) + !!(virt)))
#define ADJUST_DELTA(delta, virt) (delta)
#endif

/* IA64 uses function descriptors instead of function pointers in its
   vtables, which means that we can't meaningfully compare them directly.  */
#if defined __ia64__
#define CMP_PTRFN(A, B)	(*(void **)(A) == *(void **)(B))
#define VPTE_SIZE	(16)
#else
#define CMP_PTRFN(A, B) ((A) == (B))
#define VPTE_SIZE	sizeof(void *)
#endif

#if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100

// Check that pointers-to-member functions are represented correctly.

#include <cstddef>

struct S
{
  int i;
  int j;
};

// 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.

struct T : public S 
{
  void f () {}
  virtual void g () {}
  virtual void h () {}
};

// Provide access to the raw function pointers.  This is
// mangling-dependent.

extern "C" void _ZN1T1fEv ();
extern "C" void _ZN1T1gEv ();
extern "C" void _ZN1T1hEv ();

// This structure is a C representation of a pointer-to-member.

struct ptrmemfunc 
{
  void (*ptr) ();
  ptrdiff_t adj;
};

typedef int S::*sdp;
typedef void (S::*sp)();
typedef void (T::*tp)();

int
main ()
{
  S s;
  T t;
  sp x;
  tp y;
  ptrmemfunc *xp = (ptrmemfunc *) &x;
  ptrmemfunc *yp = (ptrmemfunc *) &y;
  ptrdiff_t delta = ((char *) &t) - ((char*) (S*) (&t));

  // Pointers-to-function-members should have the same size and
  // alignment as the PTRMEMFUNC type.
  if (sizeof (sp) != sizeof (ptrmemfunc))
    return 1;
  if (__alignof__ (sp) != __alignof__ (ptrmemfunc))
    return 2;
  
  // The NULL pointer-to-member should have a NULL first PTR field.
  x = 0;
  if (xp->ptr != 0)
    return 3;
  y = x;
  if (yp->ptr != 0)
    return 4;
  
  // A non-virtual function should have a pointer to the function.
  // There should be no adjustment for the `T' version, and an
  // appropriate adjustment for the `S' version.
  y = &T::f;
  if (! CMP_PTRFN (yp->ptr, ADJUST_PTRFN (&_ZN1T1fEv, 0)))
    return 5;
  if (yp->adj != ADJUST_DELTA (0, 0))
    return 6;
  x = (sp) y;
  if (! CMP_PTRFN (xp->ptr, ADJUST_PTRFN (&_ZN1T1fEv, 0)))
    return 7;
  if (xp->adj != ADJUST_DELTA (delta, 0))
    return 8;

  // For a virtual function, we should see the vtable offset, plus
  // one.  `T::h' is in the second slot: the vtable pointer points to
  // the first virtual function.
  y = &T::h;
  if (yp->ptr != ADJUST_PTRFN (VPTE_SIZE, 1))
    return 9;
  if (yp->adj != ADJUST_DELTA (0, 1))
    return 10;
  x = (sp) y;
  if (xp->ptr != ADJUST_PTRFN (VPTE_SIZE, 1))
    return 11;
  if (xp->adj != ADJUST_DELTA (delta, 1))
    return 12;

  // Pointers-to-data-members should have the same size and alignment
  // as a ptrdiff_t.
  if (sizeof (sdp) != sizeof (ptrdiff_t))
    return 13;
  if (__alignof__ (sdp) != __alignof__ (ptrdiff_t))
    return 14;

  // The value of a pointer-to-data member should be the offset from
  // the start of the structure.
  sdp z = &S::j;
  if ((char *) &s.j - (char *) &s != *((ptrdiff_t *) &z))
    return 15;
  z = 0;
  if (*((ptrdiff_t *) &z) != -1)
    return 16;
}

#else /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */

int main () 
{
}

#endif /* !(defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100) */