1// RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -triple=i386-pc-win32 -verify -DVMB %s
2// RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -triple=x86_64-pc-win32 -verify -DVMB %s
3// RUN: %clang_cc1 -std=c++11 -fms-compatibility -fsyntax-only -triple=x86_64-pc-win32 -verify -DVMV -fms-memptr-rep=virtual %s
4//
5// This file should also give no diagnostics when run through cl.exe from MSVS
6// 2012, which supports C++11 and static_assert.  It should pass for both 64-bit
7// and 32-bit x86.
8//
9// Test the size of various member pointer combinations:
10// - complete and incomplete
11// - single, multiple, and virtual inheritance (and unspecified for incomplete)
12// - data and function pointers
13// - templated with declared specializations with annotations
14// - template that can be instantiated
15
16// http://llvm.org/PR12070
17struct Foo {
18  typedef int Foo::*FooInt;
19  int f;
20};
21
22#ifdef VMB
23enum {
24  kSingleDataAlign             = 1 * sizeof(int),
25  kSingleFunctionAlign         = 1 * sizeof(void *),
26  kMultipleDataAlign           = 1 * sizeof(int),
27  // Everything with more than 1 field is 8 byte aligned, except virtual data
28  // member pointers on x64 (ugh).
29  kMultipleFunctionAlign       = 8,
30#ifdef _M_X64
31  kVirtualDataAlign            = 4,
32#else
33  kVirtualDataAlign            = 8,
34#endif
35  kVirtualFunctionAlign        = 8,
36  kUnspecifiedDataAlign        = 8,
37  kUnspecifiedFunctionAlign    = 8,
38
39  kSingleDataSize             = 1 * sizeof(int),
40  kSingleFunctionSize         = 1 * sizeof(void *),
41  kMultipleDataSize           = 1 * sizeof(int),
42  kMultipleFunctionSize       = 2 * sizeof(void *),
43  kVirtualDataSize            = 2 * sizeof(int),
44  kVirtualFunctionSize        = 2 * sizeof(int) + 1 * sizeof(void *),
45  kUnspecifiedDataSize        = 3 * sizeof(int),
46  kUnspecifiedFunctionSize    = 2 * sizeof(int) + 2 * sizeof(void *),
47};
48#elif VMV
49enum {
50  // Everything with more than 1 field is 8 byte aligned, except virtual data
51  // member pointers on x64 (ugh).
52#ifdef _M_X64
53  kVirtualDataAlign = 4,
54#else
55  kVirtualDataAlign = 8,
56#endif
57  kMultipleDataAlign = kVirtualDataAlign,
58  kSingleDataAlign = kVirtualDataAlign,
59
60  kUnspecifiedFunctionAlign = 8,
61  kVirtualFunctionAlign = kUnspecifiedFunctionAlign,
62  kMultipleFunctionAlign = kUnspecifiedFunctionAlign,
63  kSingleFunctionAlign = kUnspecifiedFunctionAlign,
64
65  kUnspecifiedDataSize = 3 * sizeof(int),
66  kVirtualDataSize = kUnspecifiedDataSize,
67  kMultipleDataSize = kUnspecifiedDataSize,
68  kSingleDataSize = kUnspecifiedDataSize,
69
70  kUnspecifiedFunctionSize = 2 * sizeof(int) + 2 * sizeof(void *),
71  kVirtualFunctionSize = kUnspecifiedFunctionSize,
72  kMultipleFunctionSize = kUnspecifiedFunctionSize,
73  kSingleFunctionSize = kUnspecifiedFunctionSize,
74};
75#else
76#error "test doesn't yet support this mode!"
77#endif
78
79// incomplete types
80#ifdef VMB
81class __single_inheritance IncSingle;
82class __multiple_inheritance IncMultiple;
83class __virtual_inheritance IncVirtual;
84#else
85class IncSingle;
86class IncMultiple;
87class IncVirtual;
88#endif
89static_assert(sizeof(int IncSingle::*)        == kSingleDataSize, "");
90static_assert(sizeof(int IncMultiple::*)      == kMultipleDataSize, "");
91static_assert(sizeof(int IncVirtual::*)       == kVirtualDataSize, "");
92static_assert(sizeof(void (IncSingle::*)())   == kSingleFunctionSize, "");
93static_assert(sizeof(void (IncMultiple::*)()) == kMultipleFunctionSize, "");
94static_assert(sizeof(void (IncVirtual::*)())  == kVirtualFunctionSize, "");
95
96static_assert(__alignof(int IncSingle::*)        == kSingleDataAlign, "");
97static_assert(__alignof(int IncMultiple::*)      == kMultipleDataAlign, "");
98static_assert(__alignof(int IncVirtual::*)       == kVirtualDataAlign, "");
99static_assert(__alignof(void (IncSingle::*)())   == kSingleFunctionAlign, "");
100static_assert(__alignof(void (IncMultiple::*)()) == kMultipleFunctionAlign, "");
101static_assert(__alignof(void (IncVirtual::*)())  == kVirtualFunctionAlign, "");
102
103// An incomplete type with an unspecified inheritance model seems to take one
104// more slot than virtual.  It's not clear what it's used for yet.
105class IncUnspecified;
106static_assert(sizeof(int IncUnspecified::*) == kUnspecifiedDataSize, "");
107static_assert(sizeof(void (IncUnspecified::*)()) == kUnspecifiedFunctionSize, "");
108
109// complete types
110struct B1 { };
111struct B2 { };
112struct Single { };
113struct Multiple : B1, B2 { };
114struct Virtual : virtual B1 { };
115static_assert(sizeof(int Single::*)        == kSingleDataSize, "");
116static_assert(sizeof(int Multiple::*)      == kMultipleDataSize, "");
117static_assert(sizeof(int Virtual::*)       == kVirtualDataSize, "");
118static_assert(sizeof(void (Single::*)())   == kSingleFunctionSize, "");
119static_assert(sizeof(void (Multiple::*)()) == kMultipleFunctionSize, "");
120static_assert(sizeof(void (Virtual::*)())  == kVirtualFunctionSize, "");
121
122// Test both declared and defined templates.
123template <typename T> class X;
124#ifdef VMB
125template <> class __single_inheritance   X<IncSingle>;
126template <> class __multiple_inheritance X<IncMultiple>;
127template <> class __virtual_inheritance  X<IncVirtual>;
128#else
129template <> class X<IncSingle>;
130template <> class X<IncMultiple>;
131template <> class X<IncVirtual>;
132#endif
133// Don't declare X<IncUnspecified>.
134static_assert(sizeof(int X<IncSingle>::*)           == kSingleDataSize, "");
135static_assert(sizeof(int X<IncMultiple>::*)         == kMultipleDataSize, "");
136static_assert(sizeof(int X<IncVirtual>::*)          == kVirtualDataSize, "");
137static_assert(sizeof(int X<IncUnspecified>::*)      == kUnspecifiedDataSize, "");
138static_assert(sizeof(void (X<IncSingle>::*)())      == kSingleFunctionSize, "");
139static_assert(sizeof(void (X<IncMultiple>::*)())    == kMultipleFunctionSize, "");
140static_assert(sizeof(void (X<IncVirtual>::*)())     == kVirtualFunctionSize, "");
141static_assert(sizeof(void (X<IncUnspecified>::*)()) == kUnspecifiedFunctionSize, "");
142
143template <typename T>
144struct Y : T { };
145static_assert(sizeof(int Y<Single>::*)        == kSingleDataSize, "");
146static_assert(sizeof(int Y<Multiple>::*)      == kMultipleDataSize, "");
147static_assert(sizeof(int Y<Virtual>::*)       == kVirtualDataSize, "");
148static_assert(sizeof(void (Y<Single>::*)())   == kSingleFunctionSize, "");
149static_assert(sizeof(void (Y<Multiple>::*)()) == kMultipleFunctionSize, "");
150static_assert(sizeof(void (Y<Virtual>::*)())  == kVirtualFunctionSize, "");
151
152struct A { int x; void bar(); };
153struct B : A { virtual void foo(); };
154static_assert(sizeof(int B::*) == kSingleDataSize, "");
155// A non-primary base class uses the multiple inheritance model for member
156// pointers.
157static_assert(sizeof(void (B::*)()) == kMultipleFunctionSize, "");
158
159struct AA { int x; virtual void foo(); };
160struct BB : AA { void bar(); };
161struct CC : BB { virtual void baz(); };
162static_assert(sizeof(void (CC::*)()) == kSingleFunctionSize, "");
163
164// We start out unspecified.
165struct ForwardDecl1;
166struct ForwardDecl2;
167
168// Re-declare to force us to iterate decls when adding attributes.
169struct ForwardDecl1;
170struct ForwardDecl2;
171
172typedef int ForwardDecl1::*MemPtr1;
173typedef int ForwardDecl2::*MemPtr2;
174MemPtr1 variable_forces_sizing;
175
176struct ForwardDecl1 : B {
177  virtual void foo();
178};
179struct ForwardDecl2 : B {
180  virtual void foo();
181};
182
183static_assert(sizeof(variable_forces_sizing) == kUnspecifiedDataSize, "");
184static_assert(sizeof(MemPtr1) == kUnspecifiedDataSize, "");
185static_assert(sizeof(MemPtr2) == kSingleDataSize, "");
186
187struct MemPtrInBody {
188  typedef int MemPtrInBody::*MemPtr;
189  int a;
190  operator MemPtr() const {
191    return a ? &MemPtrInBody::a : 0;
192  }
193};
194
195static_assert(sizeof(MemPtrInBody::MemPtr) == kSingleDataSize, "");
196
197// Passing a member pointer through a template should get the right size.
198template<typename T>
199struct SingleTemplate;
200template<typename T>
201struct SingleTemplate<void (T::*)(void)> {
202  static_assert(sizeof(int T::*) == kSingleDataSize, "");
203  static_assert(sizeof(void (T::*)()) == kSingleFunctionSize, "");
204};
205
206template<typename T>
207struct UnspecTemplate;
208template<typename T>
209struct UnspecTemplate<void (T::*)(void)> {
210  static_assert(sizeof(int T::*) == kUnspecifiedDataSize, "");
211  static_assert(sizeof(void (T::*)()) == kUnspecifiedFunctionSize, "");
212};
213
214struct NewUnspecified;
215SingleTemplate<void (IncSingle::*)()> tmpl_single;
216UnspecTemplate<void (NewUnspecified::*)()> tmpl_unspec;
217
218struct NewUnspecified { };
219
220static_assert(sizeof(void (NewUnspecified::*)()) == kUnspecifiedFunctionSize, "");
221
222template <typename T>
223struct MemPtrInTemplate {
224  // We can't require that the template arg be complete until we're
225  // instantiated.
226  int T::*data_ptr;
227  void (T::*func_ptr)();
228};
229
230#ifdef VMB
231int Virtual::*CastTest = reinterpret_cast<int Virtual::*>(&AA::x);
232  // expected-error@-1 {{cannot reinterpret_cast from member pointer type}}
233#endif
234
235namespace ErrorTest {
236template <typename T, typename U> struct __single_inheritance A;
237  // expected-warning@-1 {{inheritance model ignored on primary template}}
238template <typename T> struct __multiple_inheritance A<T, T>;
239  // expected-warning@-1 {{inheritance model ignored on partial specialization}}
240template <> struct __single_inheritance A<int, float>;
241
242struct B {}; // expected-note {{B defined here}}
243struct __multiple_inheritance B; // expected-error{{inheritance model does not match definition}}
244
245struct __multiple_inheritance C {}; // expected-error{{inheritance model does not match definition}}
246 // expected-note@-1 {{C defined here}}
247
248struct __virtual_inheritance D;
249struct D : virtual B {};
250}
251#ifdef VMB
252#pragma pointers_to_members(full_generality, multiple_inheritance)
253struct TrulySingleInheritance;
254static_assert(sizeof(int TrulySingleInheritance::*) == kMultipleDataSize, "");
255#pragma pointers_to_members(best_case)
256// This definition shouldn't conflict with the increased generality that the
257// multiple_inheritance model gave to TrulySingleInheritance.
258struct TrulySingleInheritance {};
259
260// Even if a definition proceeds the first mention of a pointer to member, we
261// still give the record the fully general representation.
262#pragma pointers_to_members(full_generality, virtual_inheritance)
263struct SingleInheritanceAsVirtualAfterPragma {};
264static_assert(sizeof(int SingleInheritanceAsVirtualAfterPragma::*) == 12, "");
265
266#pragma pointers_to_members(best_case)
267
268// The above holds even if the pragma comes after the definition.
269struct SingleInheritanceAsVirtualBeforePragma {};
270#pragma pointers_to_members(virtual_inheritance)
271static_assert(sizeof(int SingleInheritanceAsVirtualBeforePragma::*) == 12, "");
272
273#pragma pointers_to_members(single) // expected-error{{unexpected 'single'}}
274#endif
275