1*0a6a1f1dSLionel Sambuc // RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t
2*0a6a1f1dSLionel Sambuc // RUN: FileCheck %s < %t
3*0a6a1f1dSLionel Sambuc // RUN: FileCheck --check-prefix=BITCODE %s < %t.ll
4*0a6a1f1dSLionel Sambuc 
5*0a6a1f1dSLionel Sambuc namespace test1 {
6*0a6a1f1dSLionel Sambuc struct A {
7*0a6a1f1dSLionel Sambuc   virtual void g();
8*0a6a1f1dSLionel Sambuc   // Add an extra virtual method so it's easier to check for the absence of thunks.
9*0a6a1f1dSLionel Sambuc   virtual void h();
10*0a6a1f1dSLionel Sambuc };
11*0a6a1f1dSLionel Sambuc 
12*0a6a1f1dSLionel Sambuc struct B {
13*0a6a1f1dSLionel Sambuc   virtual void g();  // Collides with A::g if both are bases of some class.
14*0a6a1f1dSLionel Sambuc };
15*0a6a1f1dSLionel Sambuc 
16*0a6a1f1dSLionel Sambuc // Overrides methods of two bases at the same time, thus needing thunks.
17*0a6a1f1dSLionel Sambuc struct X : A, B {
18*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: VFTable for 'test1::A' in 'test1::X' (2 entries).
19*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | void test1::X::g()
20*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   1 | void test1::A::h()
21*0a6a1f1dSLionel Sambuc 
22*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: VFTable for 'test1::B' in 'test1::X' (1 entry).
23*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | void test1::X::g()
24*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
25*0a6a1f1dSLionel Sambuc 
26*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: Thunks for 'void test1::X::g()' (1 entry).
27*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | [this adjustment: -4 non-virtual]
28*0a6a1f1dSLionel Sambuc 
29*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry).
30*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | void test1::X::g()
31*0a6a1f1dSLionel Sambuc 
32*0a6a1f1dSLionel Sambuc   // BITCODE-DAG: @"\01??_7X@test1@@6BA@1@@"
33*0a6a1f1dSLionel Sambuc   // BITCODE-DAG: @"\01??_7X@test1@@6BB@1@@"
34*0a6a1f1dSLionel Sambuc 
35*0a6a1f1dSLionel Sambuc   virtual void g();
36*0a6a1f1dSLionel Sambuc } x;
37*0a6a1f1dSLionel Sambuc 
build_vftable(X * obj)38*0a6a1f1dSLionel Sambuc void build_vftable(X *obj) { obj->g(); }
39*0a6a1f1dSLionel Sambuc }
40*0a6a1f1dSLionel Sambuc 
41*0a6a1f1dSLionel Sambuc namespace test2 {
42*0a6a1f1dSLionel Sambuc struct A {
43*0a6a1f1dSLionel Sambuc   virtual void f();
44*0a6a1f1dSLionel Sambuc };
45*0a6a1f1dSLionel Sambuc 
46*0a6a1f1dSLionel Sambuc struct B {
47*0a6a1f1dSLionel Sambuc   virtual void g();
48*0a6a1f1dSLionel Sambuc   virtual void h();
49*0a6a1f1dSLionel Sambuc };
50*0a6a1f1dSLionel Sambuc 
51*0a6a1f1dSLionel Sambuc struct C {
52*0a6a1f1dSLionel Sambuc   virtual void g();
53*0a6a1f1dSLionel Sambuc };
54*0a6a1f1dSLionel Sambuc 
55*0a6a1f1dSLionel Sambuc struct X : A, B, C {
56*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: VFTable for 'test2::A' in 'test2::X' (1 entry).
57*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | void test2::A::f()
58*0a6a1f1dSLionel Sambuc 
59*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: VFTable for 'test2::B' in 'test2::X' (2 entries).
60*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | void test2::X::g()
61*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   1 | void test2::B::h()
62*0a6a1f1dSLionel Sambuc 
63*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: VFTable for 'test2::C' in 'test2::X' (1 entry).
64*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | void test2::X::g()
65*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:       [this adjustment: -4 non-virtual]
66*0a6a1f1dSLionel Sambuc 
67*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: Thunks for 'void test2::X::g()' (1 entry).
68*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | [this adjustment: -4 non-virtual]
69*0a6a1f1dSLionel Sambuc 
70*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: VFTable indices for 'test2::X' (1 entry).
71*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   via vfptr at offset 4
72*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | void test2::X::g()
73*0a6a1f1dSLionel Sambuc 
74*0a6a1f1dSLionel Sambuc   // BITCODE-DAG: @"\01??_7X@test2@@6BA@1@@"
75*0a6a1f1dSLionel Sambuc   // BITCODE-DAG: @"\01??_7X@test2@@6BB@1@@"
76*0a6a1f1dSLionel Sambuc   // BITCODE-DAG: @"\01??_7X@test2@@6BC@1@@"
77*0a6a1f1dSLionel Sambuc 
78*0a6a1f1dSLionel Sambuc   virtual void g();
79*0a6a1f1dSLionel Sambuc } x;
80*0a6a1f1dSLionel Sambuc 
build_vftable(X * obj)81*0a6a1f1dSLionel Sambuc void build_vftable(X *obj) { obj->g(); }
82*0a6a1f1dSLionel Sambuc }
83*0a6a1f1dSLionel Sambuc 
84*0a6a1f1dSLionel Sambuc namespace test3 {
85*0a6a1f1dSLionel Sambuc struct A {
86*0a6a1f1dSLionel Sambuc   virtual void f();
87*0a6a1f1dSLionel Sambuc };
88*0a6a1f1dSLionel Sambuc 
89*0a6a1f1dSLionel Sambuc struct B {
90*0a6a1f1dSLionel Sambuc   virtual void g();
91*0a6a1f1dSLionel Sambuc   virtual void h();
92*0a6a1f1dSLionel Sambuc };
93*0a6a1f1dSLionel Sambuc 
94*0a6a1f1dSLionel Sambuc struct C: A, B {
95*0a6a1f1dSLionel Sambuc   // Overrides only the left child's method (A::f), needs no thunks.
96*0a6a1f1dSLionel Sambuc   virtual void f();
97*0a6a1f1dSLionel Sambuc };
98*0a6a1f1dSLionel Sambuc 
99*0a6a1f1dSLionel Sambuc struct D: A, B {
100*0a6a1f1dSLionel Sambuc   // Overrides only the right child's method (B::g),
101*0a6a1f1dSLionel Sambuc   // needs this adjustment but not thunks.
102*0a6a1f1dSLionel Sambuc   virtual void g();
103*0a6a1f1dSLionel Sambuc };
104*0a6a1f1dSLionel Sambuc 
105*0a6a1f1dSLionel Sambuc // Overrides methods of two bases at the same time, thus needing thunks.
106*0a6a1f1dSLionel Sambuc struct X: C, D {
107*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: VFTable for 'test3::A' in 'test3::C' in 'test3::X' (1 entry).
108*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | void test3::X::f()
109*0a6a1f1dSLionel Sambuc 
110*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: VFTable for 'test3::B' in 'test3::C' in 'test3::X' (2 entries).
111*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | void test3::X::g()
112*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   1 | void test3::B::h()
113*0a6a1f1dSLionel Sambuc 
114*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: VFTable for 'test3::A' in 'test3::D' in 'test3::X' (1 entry).
115*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | void test3::X::f()
116*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:       [this adjustment: -8 non-virtual]
117*0a6a1f1dSLionel Sambuc 
118*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: Thunks for 'void test3::X::f()' (1 entry).
119*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | [this adjustment: -8 non-virtual]
120*0a6a1f1dSLionel Sambuc 
121*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: VFTable for 'test3::B' in 'test3::D' in 'test3::X' (2 entries).
122*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | void test3::X::g()
123*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:       [this adjustment: -8 non-virtual]
124*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   1 | void test3::B::h()
125*0a6a1f1dSLionel Sambuc 
126*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: Thunks for 'void test3::X::g()' (1 entry).
127*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | [this adjustment: -8 non-virtual]
128*0a6a1f1dSLionel Sambuc 
129*0a6a1f1dSLionel Sambuc   // CHECK-LABEL: VFTable indices for 'test3::X' (2 entries).
130*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   via vfptr at offset 0
131*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | void test3::X::f()
132*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   via vfptr at offset 4
133*0a6a1f1dSLionel Sambuc   // CHECK-NEXT:   0 | void test3::X::g()
134*0a6a1f1dSLionel Sambuc 
135*0a6a1f1dSLionel Sambuc   virtual void f();
136*0a6a1f1dSLionel Sambuc   virtual void g();
137*0a6a1f1dSLionel Sambuc } x;
138*0a6a1f1dSLionel Sambuc 
build_vftable(X * obj)139*0a6a1f1dSLionel Sambuc void build_vftable(X *obj) { obj->g(); }
140*0a6a1f1dSLionel Sambuc }
141*0a6a1f1dSLionel Sambuc 
142*0a6a1f1dSLionel Sambuc namespace test4 {
143*0a6a1f1dSLionel Sambuc struct A {
144*0a6a1f1dSLionel Sambuc   virtual void foo();
145*0a6a1f1dSLionel Sambuc };
146*0a6a1f1dSLionel Sambuc struct B {
147*0a6a1f1dSLionel Sambuc   virtual int filler();
148*0a6a1f1dSLionel Sambuc   virtual int operator-();
149*0a6a1f1dSLionel Sambuc   virtual int bar();
150*0a6a1f1dSLionel Sambuc };
151*0a6a1f1dSLionel Sambuc struct C : public A, public B {
152*0a6a1f1dSLionel Sambuc   virtual int filler();
153*0a6a1f1dSLionel Sambuc   virtual int operator-();
154*0a6a1f1dSLionel Sambuc   virtual int bar();
155*0a6a1f1dSLionel Sambuc };
156*0a6a1f1dSLionel Sambuc 
157*0a6a1f1dSLionel Sambuc // BITCODE-LABEL: define {{.*}}\01?ffun@test4@@YAXAAUC@1@@Z
ffun(C & c)158*0a6a1f1dSLionel Sambuc void ffun(C &c) {
159*0a6a1f1dSLionel Sambuc   // BITCODE: load
160*0a6a1f1dSLionel Sambuc   // BITCODE: bitcast
161*0a6a1f1dSLionel Sambuc   // BITCODE: bitcast
162*0a6a1f1dSLionel Sambuc   // BITCODE: [[THIS1:%.+]] = bitcast %"struct.test4::C"* {{.*}} to i8*
163*0a6a1f1dSLionel Sambuc   // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8* [[THIS1]], i32 4
164*0a6a1f1dSLionel Sambuc   // BITCODE-NEXT: call x86_thiscallcc {{.*}}(i8* [[THIS2]])
165*0a6a1f1dSLionel Sambuc   c.bar();
166*0a6a1f1dSLionel Sambuc }
167*0a6a1f1dSLionel Sambuc 
168*0a6a1f1dSLionel Sambuc // BITCODE-LABEL: define {{.*}}\01?fop@test4@@YAXAAUC@1@@Z
fop(C & c)169*0a6a1f1dSLionel Sambuc void fop(C &c) {
170*0a6a1f1dSLionel Sambuc   // BITCODE: load
171*0a6a1f1dSLionel Sambuc   // BITCODE: bitcast
172*0a6a1f1dSLionel Sambuc   // BITCODE: bitcast
173*0a6a1f1dSLionel Sambuc   // BITCODE: [[THIS1:%.+]] = bitcast %"struct.test4::C"* {{.*}} to i8*
174*0a6a1f1dSLionel Sambuc   // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8* [[THIS1]], i32 4
175*0a6a1f1dSLionel Sambuc   // BITCODE-NEXT: call x86_thiscallcc {{.*}}(i8* [[THIS2]])
176*0a6a1f1dSLionel Sambuc   -c;
177*0a6a1f1dSLionel Sambuc }
178*0a6a1f1dSLionel Sambuc 
179*0a6a1f1dSLionel Sambuc }
180