aboutsummaryrefslogtreecommitdiff
path: root/test/SemaCXX/member-pointer-ms.cpp
blob: e7c4ae9409e04f9e451024d01cdcb060d03e1b5c (plain) (blame)
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
// RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -triple=i386-pc-win32 -verify -DVMB %s
// RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -triple=x86_64-pc-win32 -verify -DVMB %s
// RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -triple=x86_64-pc-win32 -verify -DVMV -fms-memptr-rep=virtual %s
//
// This file should also give no diagnostics when run through cl.exe from MSVS
// 2012, which supports C++11 and static_assert.  It should pass for both 64-bit
// and 32-bit x86.
//
// Test the size of various member pointer combinations:
// - complete and incomplete
// - single, multiple, and virtual inheritance (and unspecified for incomplete)
// - data and function pointers
// - templated with declared specializations with annotations
// - template that can be instantiated

// http://llvm.org/PR12070
struct Foo {
  typedef int Foo::*FooInt;
  int f;
};

#ifdef VMB
enum {
  kSingleDataAlign             = 1 * sizeof(int),
  kSingleFunctionAlign         = 1 * sizeof(void *),
  kMultipleDataAlign           = 1 * sizeof(int),
  // Everything with more than 1 field is 8 byte aligned, except virtual data
  // member pointers on x64 (ugh).
  kMultipleFunctionAlign       = 8,
#ifdef _M_X64
  kVirtualDataAlign            = 4,
#else
  kVirtualDataAlign            = 8,
#endif
  kVirtualFunctionAlign        = 8,
  kUnspecifiedDataAlign        = 8,
  kUnspecifiedFunctionAlign    = 8,

  kSingleDataSize             = 1 * sizeof(int),
  kSingleFunctionSize         = 1 * sizeof(void *),
  kMultipleDataSize           = 1 * sizeof(int),
  kMultipleFunctionSize       = 2 * sizeof(void *),
  kVirtualDataSize            = 2 * sizeof(int),
  kVirtualFunctionSize        = 2 * sizeof(int) + 1 * sizeof(void *),
  kUnspecifiedDataSize        = 3 * sizeof(int),
  kUnspecifiedFunctionSize    = 2 * sizeof(int) + 2 * sizeof(void *),
};
#elif VMV
enum {
  // Everything with more than 1 field is 8 byte aligned, except virtual data
  // member pointers on x64 (ugh).
#ifdef _M_X64
  kVirtualDataAlign = 4,
#else
  kVirtualDataAlign = 8,
#endif
  kMultipleDataAlign = kVirtualDataAlign,
  kSingleDataAlign = kVirtualDataAlign,

  kUnspecifiedFunctionAlign = 8,
  kVirtualFunctionAlign = kUnspecifiedFunctionAlign,
  kMultipleFunctionAlign = kUnspecifiedFunctionAlign,
  kSingleFunctionAlign = kUnspecifiedFunctionAlign,

  kUnspecifiedDataSize = 3 * sizeof(int),
  kVirtualDataSize = kUnspecifiedDataSize,
  kMultipleDataSize = kUnspecifiedDataSize,
  kSingleDataSize = kUnspecifiedDataSize,

  kUnspecifiedFunctionSize = 2 * sizeof(int) + 2 * sizeof(void *),
  kVirtualFunctionSize = kUnspecifiedFunctionSize,
  kMultipleFunctionSize = kUnspecifiedFunctionSize,
  kSingleFunctionSize = kUnspecifiedFunctionSize,
};
#else
#error "test doesn't yet support this mode!"
#endif

// incomplete types
#ifdef VMB
class __single_inheritance IncSingle;
class __multiple_inheritance IncMultiple;
class __virtual_inheritance IncVirtual;
#else
class IncSingle;
class IncMultiple;
class IncVirtual;
#endif
static_assert(sizeof(int IncSingle::*)        == kSingleDataSize, "");
static_assert(sizeof(int IncMultiple::*)      == kMultipleDataSize, "");
static_assert(sizeof(int IncVirtual::*)       == kVirtualDataSize, "");
static_assert(sizeof(void (IncSingle::*)())   == kSingleFunctionSize, "");
static_assert(sizeof(void (IncMultiple::*)()) == kMultipleFunctionSize, "");
static_assert(sizeof(void (IncVirtual::*)())  == kVirtualFunctionSize, "");

static_assert(__alignof(int IncSingle::*)        == kSingleDataAlign, "");
static_assert(__alignof(int IncMultiple::*)      == kMultipleDataAlign, "");
static_assert(__alignof(int IncVirtual::*)       == kVirtualDataAlign, "");
static_assert(__alignof(void (IncSingle::*)())   == kSingleFunctionAlign, "");
static_assert(__alignof(void (IncMultiple::*)()) == kMultipleFunctionAlign, "");
static_assert(__alignof(void (IncVirtual::*)())  == kVirtualFunctionAlign, "");

// An incomplete type with an unspecified inheritance model seems to take one
// more slot than virtual.  It's not clear what it's used for yet.
class IncUnspecified;
static_assert(sizeof(int IncUnspecified::*) == kUnspecifiedDataSize, "");
static_assert(sizeof(void (IncUnspecified::*)()) == kUnspecifiedFunctionSize, "");

// complete types
struct B1 { };
struct B2 { };
struct Single { };
struct Multiple : B1, B2 { };
struct Virtual : virtual B1 { };
static_assert(sizeof(int Single::*)        == kSingleDataSize, "");
static_assert(sizeof(int Multiple::*)      == kMultipleDataSize, "");
static_assert(sizeof(int Virtual::*)       == kVirtualDataSize, "");
static_assert(sizeof(void (Single::*)())   == kSingleFunctionSize, "");
static_assert(sizeof(void (Multiple::*)()) == kMultipleFunctionSize, "");
static_assert(sizeof(void (Virtual::*)())  == kVirtualFunctionSize, "");

// Test both declared and defined templates.
template <typename T> class X;
#ifdef VMB
template <> class __single_inheritance   X<IncSingle>;
template <> class __multiple_inheritance X<IncMultiple>;
template <> class __virtual_inheritance  X<IncVirtual>;
#else
template <> class X<IncSingle>;
template <> class X<IncMultiple>;
template <> class X<IncVirtual>;
#endif
// Don't declare X<IncUnspecified>.
static_assert(sizeof(int X<IncSingle>::*)           == kSingleDataSize, "");
static_assert(sizeof(int X<IncMultiple>::*)         == kMultipleDataSize, "");
static_assert(sizeof(int X<IncVirtual>::*)          == kVirtualDataSize, "");
static_assert(sizeof(int X<IncUnspecified>::*)      == kUnspecifiedDataSize, "");
static_assert(sizeof(void (X<IncSingle>::*)())      == kSingleFunctionSize, "");
static_assert(sizeof(void (X<IncMultiple>::*)())    == kMultipleFunctionSize, "");
static_assert(sizeof(void (X<IncVirtual>::*)())     == kVirtualFunctionSize, "");
static_assert(sizeof(void (X<IncUnspecified>::*)()) == kUnspecifiedFunctionSize, "");

template <typename T>
struct Y : T { };
static_assert(sizeof(int Y<Single>::*)        == kSingleDataSize, "");
static_assert(sizeof(int Y<Multiple>::*)      == kMultipleDataSize, "");
static_assert(sizeof(int Y<Virtual>::*)       == kVirtualDataSize, "");
static_assert(sizeof(void (Y<Single>::*)())   == kSingleFunctionSize, "");
static_assert(sizeof(void (Y<Multiple>::*)()) == kMultipleFunctionSize, "");
static_assert(sizeof(void (Y<Virtual>::*)())  == kVirtualFunctionSize, "");

struct A { int x; void bar(); };
struct B : A { virtual void foo(); };
static_assert(sizeof(int B::*) == kSingleDataSize, "");
// A non-primary base class uses the multiple inheritance model for member
// pointers.
static_assert(sizeof(void (B::*)()) == kMultipleFunctionSize, "");

struct AA { int x; virtual void foo(); };
struct BB : AA { void bar(); };
struct CC : BB { virtual void baz(); };
static_assert(sizeof(void (CC::*)()) == kSingleFunctionSize, "");

// We start out unspecified.
struct ForwardDecl1;
struct ForwardDecl2;

// Re-declare to force us to iterate decls when adding attributes.
struct ForwardDecl1;
struct ForwardDecl2;

typedef int ForwardDecl1::*MemPtr1;
typedef int ForwardDecl2::*MemPtr2;
MemPtr1 variable_forces_sizing;

struct ForwardDecl1 : B {
  virtual void foo();
};
struct ForwardDecl2 : B {
  virtual void foo();
};

static_assert(sizeof(variable_forces_sizing) == kUnspecifiedDataSize, "");
static_assert(sizeof(MemPtr1) == kUnspecifiedDataSize, "");
static_assert(sizeof(MemPtr2) == kSingleDataSize, "");

struct MemPtrInBody {
  typedef int MemPtrInBody::*MemPtr;
  int a;
  operator MemPtr() const {
    return a ? &MemPtrInBody::a : 0;
  }
};

static_assert(sizeof(MemPtrInBody::MemPtr) == kSingleDataSize, "");

// Passing a member pointer through a template should get the right size.
template<typename T>
struct SingleTemplate;
template<typename T>
struct SingleTemplate<void (T::*)(void)> {
  static_assert(sizeof(int T::*) == kSingleDataSize, "");
  static_assert(sizeof(void (T::*)()) == kSingleFunctionSize, "");
};

template<typename T>
struct UnspecTemplate;
template<typename T>
struct UnspecTemplate<void (T::*)(void)> {
  static_assert(sizeof(int T::*) == kUnspecifiedDataSize, "");
  static_assert(sizeof(void (T::*)()) == kUnspecifiedFunctionSize, "");
};

struct NewUnspecified;
SingleTemplate<void (IncSingle::*)()> tmpl_single;
UnspecTemplate<void (NewUnspecified::*)()> tmpl_unspec;

struct NewUnspecified { };

static_assert(sizeof(void (NewUnspecified::*)()) == kUnspecifiedFunctionSize, "");

template <typename T>
struct MemPtrInTemplate {
  // We can't require that the template arg be complete until we're
  // instantiated.
  int T::*data_ptr;
  void (T::*func_ptr)();
};

#ifdef VMB
int Virtual::*CastTest = reinterpret_cast<int Virtual::*>(&AA::x);
  // expected-error@-1 {{cannot reinterpret_cast from member pointer type}}
#endif

namespace ErrorTest {
template <typename T, typename U> struct __single_inheritance A;
  // expected-warning@-1 {{inheritance model ignored on primary template}}
template <typename T> struct __multiple_inheritance A<T, T>;
  // expected-warning@-1 {{inheritance model ignored on partial specialization}}
template <> struct __single_inheritance A<int, float>;

struct B {}; // expected-note {{B defined here}}
struct __multiple_inheritance B; // expected-error{{inheritance model does not match definition}}

struct __multiple_inheritance C {}; // expected-error{{inheritance model does not match definition}}
 // expected-note@-1 {{C defined here}}

struct __virtual_inheritance D;
struct D : virtual B {};
}
#ifdef VMB
#pragma pointers_to_members(full_generality, multiple_inheritance)
struct TrulySingleInheritance;
static_assert(sizeof(int TrulySingleInheritance::*) == kMultipleDataSize, "");
#pragma pointers_to_members(best_case)
// This definition shouldn't conflict with the increased generality that the
// multiple_inheritance model gave to TrulySingleInheritance.
struct TrulySingleInheritance {};

// Even if a definition proceeds the first mention of a pointer to member, we
// still give the record the fully general representation.
#pragma pointers_to_members(full_generality, virtual_inheritance)
struct SingleInheritanceAsVirtualAfterPragma {};
static_assert(sizeof(int SingleInheritanceAsVirtualAfterPragma::*) == 12, "");

#pragma pointers_to_members(best_case)

// The above holds even if the pragma comes after the definition.
struct SingleInheritanceAsVirtualBeforePragma {};
#pragma pointers_to_members(virtual_inheritance)
static_assert(sizeof(int SingleInheritanceAsVirtualBeforePragma::*) == 12, "");

#pragma pointers_to_members(single) // expected-error{{unexpected 'single'}}
#endif