member-function-pointers.cpp revision 93ab6bf534fb6c26563c00f28a8fc5581bb71dfd
1// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-unknown-unknown | FileCheck -check-prefix CODE-LP64 %s
2// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i386-unknown-unknown | FileCheck -check-prefix CODE-LP32 %s
3// RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-unknown-unknown | FileCheck -check-prefix GLOBAL-LP64 %s
4// RUN: %clang_cc1 %s -emit-llvm -o - -triple=i386-unknown-unknown | FileCheck -check-prefix GLOBAL-LP32 %s
5// RUN: %clang_cc1 %s -emit-llvm -o - -triple=armv7-unknown-unknown | FileCheck -check-prefix GLOBAL-ARM %s
6
7// PNaCl uses the same representation of method pointers as ARM.
8// RUN: %clang_cc1 %s -emit-llvm -o - -triple=le32-unknown-nacl | FileCheck -check-prefix GLOBAL-ARM %s
9
10struct A { int a; void f(); virtual void vf1(); virtual void vf2(); };
11struct B { int b; virtual void g(); };
12struct C : B, A { };
13
14void (A::*pa)();
15void (A::*volatile vpa)();
16void (B::*pb)();
17void (C::*pc)();
18
19// GLOBAL-LP64: @pa2 = global { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 }, align 8
20void (A::*pa2)() = &A::f;
21
22// GLOBAL-LP64: @pa3 = global { i64, i64 } { i64 1, i64 0 }, align 8
23// GLOBAL-LP32: @pa3 = global { i32, i32 } { i32 1, i32 0 }, align 4
24void (A::*pa3)() = &A::vf1;
25
26// GLOBAL-LP64: @pa4 = global { i64, i64 } { i64 9, i64 0 }, align 8
27// GLOBAL-LP32: @pa4 = global { i32, i32 } { i32 5, i32 0 }, align 4
28void (A::*pa4)() = &A::vf2;
29
30// GLOBAL-LP64: @pc2 = global { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 16 }, align 8
31void (C::*pc2)() = &C::f;
32
33// GLOBAL-LP64: @pc3 = global { i64, i64 } { i64 1, i64 0 }, align 8
34void (A::*pc3)() = &A::vf1;
35
36void f() {
37  // CODE-LP64: store { i64, i64 } zeroinitializer, { i64, i64 }* @pa
38  pa = 0;
39
40  // Is this okay?  What are LLVM's volatile semantics for structs?
41  // CODE-LP64: store volatile { i64, i64 } zeroinitializer, { i64, i64 }* @vpa
42  vpa = 0;
43
44  // CODE-LP64: [[TMP:%.*]] = load { i64, i64 }* @pa, align 8
45  // CODE-LP64: [[TMPADJ:%.*]] = extractvalue { i64, i64 } [[TMP]], 1
46  // CODE-LP64: [[ADJ:%.*]] = add nsw i64 [[TMPADJ]], 16
47  // CODE-LP64: [[RES:%.*]] = insertvalue { i64, i64 } [[TMP]], i64 [[ADJ]], 1
48  // CODE-LP64: store { i64, i64 } [[RES]], { i64, i64 }* @pc, align 8
49  pc = pa;
50
51  // CODE-LP64: [[TMP:%.*]] = load { i64, i64 }* @pc, align 8
52  // CODE-LP64: [[TMPADJ:%.*]] = extractvalue { i64, i64 } [[TMP]], 1
53  // CODE-LP64: [[ADJ:%.*]] = sub nsw i64 [[TMPADJ]], 16
54  // CODE-LP64: [[RES:%.*]] = insertvalue { i64, i64 } [[TMP]], i64 [[ADJ]], 1
55  // CODE-LP64: store { i64, i64 } [[RES]], { i64, i64 }* @pa, align 8
56  pa = static_cast<void (A::*)()>(pc);
57}
58
59void f2() {
60  // CODE-LP64: store { i64, i64 } { i64 ptrtoint (void (%struct.A*)* @_ZN1A1fEv to i64), i64 0 }
61  void (A::*pa2)() = &A::f;
62
63  // CODE-LP64: store { i64, i64 } { i64 1, i64 0 }
64  // CODE-LP32: store { i32, i32 } { i32 1, i32 0 }
65  void (A::*pa3)() = &A::vf1;
66
67  // CODE-LP64: store { i64, i64 } { i64 9, i64 0 }
68  // CODE-LP32: store { i32, i32 } { i32 5, i32 0 }
69  void (A::*pa4)() = &A::vf2;
70}
71
72void f3(A *a, A &ar) {
73  (a->*pa)();
74  (ar.*pa)();
75}
76
77bool f4() {
78  return pa;
79}
80
81// PR5177
82namespace PR5177 {
83  struct A {
84   bool foo(int*) const;
85  } a;
86
87  struct B1 {
88   bool (A::*pmf)(int*) const;
89   const A* pa;
90
91   B1() : pmf(&A::foo), pa(&a) {}
92   bool operator()() const { return (pa->*pmf)(new int); }
93  };
94
95  void bar(B1 b2) { while (b2()) ; }
96}
97
98// PR5138
99namespace PR5138 {
100  struct foo {
101      virtual void bar(foo *);
102  };
103
104  extern "C" {
105    void baz(foo *);
106  }
107
108  void (foo::*ptr1)(void *) = (void (foo::*)(void *))&foo::bar;
109  void (*ptr2)(void *) = (void (*)(void *))&baz;
110
111  void (foo::*ptr3)(void) = (void (foo::*)(void))&foo::bar;
112}
113
114// PR5593
115namespace PR5593 {
116  struct A { };
117
118  bool f(void (A::*f)()) {
119    return f && f;
120  }
121}
122
123namespace PR5718 {
124  struct A { };
125
126  bool f(void (A::*f)(), void (A::*g)()) {
127    return f == g;
128  }
129}
130
131namespace BoolMemberPointer {
132  struct A { };
133
134  bool f(void (A::*f)()) {
135    return !f;
136  }
137
138  bool g(void (A::*f)()) {
139    if (!!f)
140      return true;
141    return false;
142  }
143}
144
145// PR5940
146namespace PR5940 {
147  class foo {
148  public:
149    virtual void baz(void);
150  };
151
152  void foo::baz(void) {
153       void (foo::*ptr)(void) = &foo::baz;
154  }
155}
156
157namespace MemberPointerImpCast {
158  struct A {
159    int x;
160  };
161  struct B : public A {
162  };
163  void f(B* obj, void (A::*method)()) {
164    (obj->*method)();
165  }
166}
167
168// PR6258
169namespace PR6258 {
170
171  struct A {
172    void f(bool);
173  };
174
175  void (A::*pf)(bool) = &A::f;
176
177  void f() {
178    void (A::*pf)(bool) = &A::f;
179  }
180}
181
182// PR7027
183namespace PR7027 {
184  struct X { void test( ); };
185  void testX() { &X::test; }
186}
187
188namespace test7 {
189  struct A { void foo(); virtual void vfoo(); };
190  struct B { void foo(); virtual void vfoo(); };
191  struct C : A, B { void foo(); virtual void vfoo(); };
192
193  // GLOBAL-ARM: @_ZN5test74ptr0E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71A3fooEv to i32), i32 0 }
194  // GLOBAL-ARM: @_ZN5test74ptr1E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71B3fooEv to i32), i32 8 }
195  // GLOBAL-ARM: @_ZN5test74ptr2E = global {{.*}} { i32 ptrtoint ({{.*}}* @_ZN5test71C3fooEv to i32), i32 0 }
196  // GLOBAL-ARM: @_ZN5test74ptr3E = global {{.*}} { i32 0, i32 1 }
197  // GLOBAL-ARM: @_ZN5test74ptr4E = global {{.*}} { i32 0, i32 9 }
198  // GLOBAL-ARM: @_ZN5test74ptr5E = global {{.*}} { i32 0, i32 1 }
199  void (C::*ptr0)() = &A::foo;
200  void (C::*ptr1)() = &B::foo;
201  void (C::*ptr2)() = &C::foo;
202  void (C::*ptr3)() = &A::vfoo;
203  void (C::*ptr4)() = &B::vfoo;
204  void (C::*ptr5)() = &C::vfoo;
205}
206
207namespace test8 {
208  struct X { };
209  typedef int (X::*pmf)(int);
210
211  // CHECK: {{define.*_ZN5test81fEv}}
212  pmf f() {
213    // CHECK: {{ret.*zeroinitializer}}
214    return pmf();
215  }
216}
217
218namespace test9 {
219  struct A {
220    void foo();
221  };
222  struct B : A {
223    void foo();
224  };
225
226  typedef void (A::*fooptr)();
227
228  struct S {
229    fooptr p;
230  };
231
232  // CODE-LP64-LABEL:    define void @_ZN5test94testEv(
233  // CODE-LP64:      alloca i32
234  // CODE-LP64-NEXT: ret void
235  void test() {
236    int x;
237    static S array[] = { (fooptr) &B::foo };
238  }
239}
240
241// rdar://problem/10815683 - Verify that we can emit reinterprets of
242// member pointers as constant initializers.  For added trickiness,
243// we also add some non-trivial adjustments.
244namespace test10 {
245  struct A {
246    int nonEmpty;
247    void foo();
248  };
249  struct B : public A {
250    virtual void requireNonZeroAdjustment();
251  };
252  struct C {
253    int nonEmpty;
254  };
255  struct D : public C {
256    virtual void requireNonZeroAdjustment();
257  };
258
259
260// It's not that the offsets are doubled on ARM, it's that they're left-shifted by 1.
261
262// GLOBAL-LP64: @_ZN6test101aE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 0 }, align 8
263// GLOBAL-LP32: @_ZN6test101aE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 0 }, align 4
264// GLOBAL-ARM:  @_ZN6test101aE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 0 }, align 4
265  void (A::*a)() = &A::foo;
266
267// GLOBAL-LP64: @_ZN6test101bE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 8 }, align 8
268// GLOBAL-LP32: @_ZN6test101bE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 4 }, align 4
269// GLOBAL-ARM:  @_ZN6test101bE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4
270  void (B::*b)() = (void (B::*)()) &A::foo;
271
272// GLOBAL-LP64: @_ZN6test101cE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 8 }, align 8
273// GLOBAL-LP32: @_ZN6test101cE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 4 }, align 4
274// GLOBAL-ARM:  @_ZN6test101cE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4
275  void (C::*c)() = (void (C::*)()) (void (B::*)()) &A::foo;
276
277// GLOBAL-LP64: @_ZN6test101dE = global { i64, i64 } { i64 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i64), i64 16 }, align 8
278// GLOBAL-LP32: @_ZN6test101dE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 8 }, align 4
279// GLOBAL-ARM:  @_ZN6test101dE = global { i32, i32 } { i32 ptrtoint (void (%"struct.test10::A"*)* @_ZN6test101A3fooEv to i32), i32 16 }, align 4
280  void (D::*d)() = (void (C::*)()) (void (B::*)()) &A::foo;
281}
282
283namespace test11 {
284  struct A { virtual void a(); };
285  struct B : A {};
286  struct C : B { virtual void a(); };
287  void (C::*x)() = &C::a;
288
289  // GLOBAL-LP64: @_ZN6test111xE = global { i64, i64 } { i64 1, i64 0 }
290  // GLOBAL-LP32: @_ZN6test111xE = global { i32, i32 } { i32 1, i32 0 }
291  // GLOBAL-ARM:  @_ZN6test111xE = global { i32, i32 } { i32 0, i32 1 }
292}
293