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