summaryrefslogtreecommitdiffstats
path: root/test/SemaCXX/member-pointer-ms.cpp
blob: 7dca12190584685797d0dd3f91b39715b85b918b (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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// RUN: %clang_cc1 -std=c++11 -cxx-abi microsoft -fms-compatibility -fsyntax-only -triple=i386-pc-win32 -verify %s
// RUN: %clang_cc1 -std=c++11 -cxx-abi microsoft -fms-compatibility -fsyntax-only -triple=x86_64-pc-win32 -verify %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.
//
// expected-no-diagnostics

// 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;
};

enum {
  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 *),
  // Unspecified is weird, it's 1 more slot than virtual.
  kUnspecifiedDataSize        = kVirtualDataSize + 1 * sizeof(int),
  kUnspecifiedFunctionSize    = kVirtualFunctionSize + 1 * sizeof(void *),
};

// incomplete types
class __single_inheritance IncSingle;
class __multiple_inheritance IncMultiple;
class __virtual_inheritance IncVirtual;
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, "");

// 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;
template <> class __single_inheritance   X<IncSingle>;
template <> class __multiple_inheritance X<IncMultiple>;
template <> class __virtual_inheritance  X<IncVirtual>;
// 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, "");
// FIXME: Clang fails this assert because it locks in the inheritance model at
// the point of the typedef instead of the first usage, while MSVC does not.
//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)();
};
OpenPOWER on IntegriCloud