xref: /llvm-project/clang/test/CodeGenCXX/pointers-to-data-members.cpp (revision a86c1e7175d4acd8357326184bf4f88c8192676f)
1 // RUN: %clang_cc1 %s -emit-llvm -o %t.ll -triple=x86_64-apple-darwin10
2 // RUN: %clang_cc1 %s -emit-llvm -o %t.ll -triple=x86_64-apple-darwin10 -fexperimental-new-constant-interpreter
3 // RUN: FileCheck %s < %t.ll
4 // RUN: FileCheck -check-prefix=CHECK-GLOBAL %s < %t.ll
5 
6 struct A { int a; int b; };
7 struct B { int b; };
8 struct C : B, A { };
9 
10 // Zero init.
11 namespace ZeroInit {
12   // CHECK-GLOBAL: @_ZN8ZeroInit1aE ={{.*}} global i64 -1
13   int A::* a;
14 
15   // CHECK-GLOBAL: @_ZN8ZeroInit2aaE ={{.*}} global [2 x i64] [i64 -1, i64 -1]
16   int A::* aa[2];
17 
18   // CHECK-GLOBAL: @_ZN8ZeroInit3aaaE ={{.*}} global [2 x [2 x i64]] {{\[}}[2 x i64] [i64 -1, i64 -1], [2 x i64] [i64 -1, i64 -1]]
19   int A::* aaa[2][2];
20 
21   // CHECK-GLOBAL: @_ZN8ZeroInit1bE ={{.*}} global i64 -1,
22   int A::* b = 0;
23 
24   // CHECK-GLOBAL: @_ZN8ZeroInit2saE = internal global %struct.anon { i64 -1 }
25   struct {
26     int A::*a;
27   } sa;
test_sa()28   void test_sa() { (void) sa; } // force emission
29 
30   // CHECK-GLOBAL: @_ZN8ZeroInit3ssaE = internal
31   // CHECK-GLOBAL: [2 x i64] [i64 -1, i64 -1]
32   struct {
33     int A::*aa[2];
34   } ssa[2];
test_ssa()35   void test_ssa() { (void) ssa; }
36 
37   // CHECK-GLOBAL: @_ZN8ZeroInit2ssE = internal global %struct.anon.1 { %struct.anon.2 { i64 -1 } }
38   struct {
39     struct {
40       int A::*pa;
41     } s;
42   } ss;
test_ss()43   void test_ss() { (void) ss; }
44 
45   struct A {
46     int A::*a;
47     int b;
48   };
49 
50   struct B {
51     A a[10];
52     char c;
53     int B::*b;
54   };
55 
56   struct C : A, B { int j; };
57   // CHECK-GLOBAL: @_ZN8ZeroInit1cE ={{.*}} global {{%.*}} <{ %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::B" { [10 x %"struct.ZeroInit::A"] [%"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }, %"struct.ZeroInit::A" { i64 -1, i32 0 }], i8 0, i64 -1 }, i32 0, [4 x i8] zeroinitializer }>, align 8
58   C c;
59 }
60 
61 // PR5674
62 namespace PR5674 {
63   // CHECK-GLOBAL: @_ZN6PR56742pbE ={{.*}} global i64 4
64   int A::*pb = &A::b;
65 }
66 
67 // Casts.
68 namespace Casts {
69 
70 int A::*pa;
71 int C::*pc;
72 
f()73 void f() {
74   // CHECK:      store i64 -1, ptr @_ZN5Casts2paE
75   pa = 0;
76 
77   // CHECK-NEXT: [[TMP:%.*]] = load i64, ptr @_ZN5Casts2paE, align 8
78   // CHECK-NEXT: [[ADJ:%.*]] = add nsw i64 [[TMP]], 4
79   // CHECK-NEXT: [[ISNULL:%.*]] = icmp eq i64 [[TMP]], -1
80   // CHECK-NEXT: [[RES:%.*]] = select i1 [[ISNULL]], i64 [[TMP]], i64 [[ADJ]]
81   // CHECK-NEXT: store i64 [[RES]], ptr @_ZN5Casts2pcE
82   pc = pa;
83 
84   // CHECK-NEXT: [[TMP:%.*]] = load i64, ptr @_ZN5Casts2pcE, align 8
85   // CHECK-NEXT: [[ADJ:%.*]] = sub nsw i64 [[TMP]], 4
86   // CHECK-NEXT: [[ISNULL:%.*]] = icmp eq i64 [[TMP]], -1
87   // CHECK-NEXT: [[RES:%.*]] = select i1 [[ISNULL]], i64 [[TMP]], i64 [[ADJ]]
88   // CHECK-NEXT: store i64 [[RES]], ptr @_ZN5Casts2paE
89   pa = static_cast<int A::*>(pc);
90 }
91 
92 }
93 
94 // Comparisons
95 namespace Comparisons {
f()96   void f() {
97     int A::*a;
98 
99     // CHECK: icmp ne i64 {{.*}}, -1
100     if (a) { }
101 
102     // CHECK: icmp ne i64 {{.*}}, -1
103     if (a != 0) { }
104 
105     // CHECK: icmp ne i64 -1, {{.*}}
106     if (0 != a) { }
107 
108     // CHECK: icmp eq i64 {{.*}}, -1
109     if (a == 0) { }
110 
111     // CHECK: icmp eq i64 -1, {{.*}}
112     if (0 == a) { }
113   }
114 }
115 
116 namespace ValueInit {
117 
118 struct A {
119   int A::*a;
120 
121   char c;
122 
123   A();
124 };
125 
126 // CHECK-LABEL: define{{.*}} void @_ZN9ValueInit1AC2Ev(ptr {{[^,]*}} %this) unnamed_addr
127 // CHECK: store i64 -1, ptr
128 // CHECK: ret void
A()129 A::A() : a() {}
130 
131 }
132 
133 namespace VirtualBases {
134 
135 struct A {
136   char c;
137   int A::*i;
138 };
139 
140 // CHECK-GLOBAL: @_ZN12VirtualBases1bE ={{.*}} global %"struct.VirtualBases::B" { ptr null, %"struct.VirtualBases::A" { i8 0, i64 -1 } }, align 8
141 struct B : virtual A { };
142 B b;
143 
144 // CHECK-GLOBAL: @_ZN12VirtualBases1cE ={{.*}} global %"struct.VirtualBases::C" { ptr null, i64 -1, %"struct.VirtualBases::A" { i8 0, i64 -1 } }, align 8
145 struct C : virtual A { int A::*i; };
146 C c;
147 
148 // CHECK-GLOBAL: @_ZN12VirtualBases1dE ={{.*}} global %"struct.VirtualBases::D" { %"struct.VirtualBases::C.base" { ptr null, i64 -1 }, i64 -1, %"struct.VirtualBases::A" { i8 0, i64 -1 } }, align 8
149 struct D : C { int A::*i; };
150 D d;
151 
152 }
153 
154 namespace Test1 {
155 
156 // Don't crash when A contains a bit-field.
157 struct A {
158   int A::* a;
159   int b : 10;
160 };
161 A a;
162 
163 }
164 
165 namespace BoolPtrToMember {
166   struct X {
167     bool member;
168   };
169 
170   // CHECK-LABEL: define{{.*}} nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) ptr @_ZN15BoolPtrToMember1fERNS_1XEMS0_b
f(X & x,bool X::* member)171   bool &f(X &x, bool X::*member) {
172     // CHECK: getelementptr inbounds i8, ptr
173     // CHECK-NEXT: ret ptr
174     return x.*member;
175   }
176 }
177 
178 namespace PR8507 {
179 
180 struct S;
f(S * p,double S::* pm)181 void f(S* p, double S::*pm) {
182   if (0 < p->*pm) {
183   }
184 }
185 
186 }
187 
188 namespace test4 {
189   struct A             { int A_i; };
190   struct B : virtual A { int A::*B_p; };
191   struct C : virtual B { int    *C_p; };
192   struct D :         C { int    *D_p; };
193 
194   // CHECK-GLOBAL: @_ZN5test41dE ={{.*}} global %"struct.test4::D" { %"struct.test4::C.base" zeroinitializer, ptr null, %"struct.test4::B.base" { ptr null, i64 -1 }, %"struct.test4::A" zeroinitializer }, align 8
195   D d;
196 }
197 
198 namespace PR11487 {
199   union U
200   {
201     int U::* mptr;
202     char x[16];
203   } x;
204   // CHECK-GLOBAL: @_ZN7PR114871xE ={{.*}} global %"union.PR11487::U" { i64 -1, [8 x i8] zeroinitializer }, align 8
205 
206 }
207 
208 namespace PR13097 {
209   struct X { int x; X(const X&); };
210   struct A {
211     int qq;
212       X x;
213   };
214   A f();
g()215   X g() { return f().*&A::x; }
216   // CHECK-LABEL: define{{.*}} void @_ZN7PR130971gEv
217   // CHECK: call void @_ZN7PR130971fEv
218   // CHECK-NOT: memcpy
219   // CHECK: call void @_ZN7PR130971XC1ERKS0_
220 }
221 
222 namespace PR21089 {
223 struct A {
224   bool : 1;
225   int A::*x;
226   bool y;
227   A();
228 };
229 struct B : A {
230 };
231 B b;
232 // CHECK-GLOBAL: @_ZN7PR210891bE ={{.*}} global %"struct.PR21089::B" { %"struct.PR21089::A.base" <{ i8 0, [7 x i8] zeroinitializer, i64 -1, i8 0 }>, [7 x i8] zeroinitializer }, align 8
233 }
234 
235 namespace PR21282 {
236 union U {
237   int U::*x;
238   long y[2];
239 };
240 U u;
241 // CHECK-GLOBAL: @_ZN7PR212821uE ={{.*}} global %"union.PR21282::U" { i64 -1, [8 x i8] zeroinitializer }, align 8
242 }
243 
244 namespace FlexibleArrayMember {
245 struct S {
246   int S::*x[];
247 };
248 S s;
249 // CHECK-GLOBAL: @_ZN19FlexibleArrayMember1sE ={{.*}} global %"struct.FlexibleArrayMember::S" zeroinitializer, align 8
250 }
251 
252 namespace IndirectPDM {
253 union U {
254   union {
255     int U::*m;
256   };
257 };
258 U u;
259 // CHECK-GLOBAL: @_ZN11IndirectPDM1uE ={{.*}} global %"union.IndirectPDM::U" { %union.anon { i64 -1 } }, align 8
260 }
261 
262 namespace PR47864 {
263   struct B;
264   struct B {};
265   struct D : B { int m; };
266   auto x = (int B::*)&D::m;
267 }
268