blob: aaee39c51db61bdcd6cbb9cfb05285dd7fda6c51 [file] [log] [blame]
Stephen Hines6bcf27b2014-05-29 04:14:42 -07001// RUN: %clang_cc1 %s -fno-rtti -triple=i386-pc-win32 -emit-llvm -o %t.ll -fdump-vtable-layouts >%t
2// RUN: FileCheck %s < %t
Stephen Hines0e2c34f2015-03-23 12:09:02 -07003// RUN: FileCheck --check-prefix=BITCODE %s < %t.ll
Stephen Hines6bcf27b2014-05-29 04:14:42 -07004
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
Stephen Hines0e2c34f2015-03-23 12:09:02 -070032 // BITCODE-DAG: @"\01??_7X@test1@@6BA@1@@"
33 // BITCODE-DAG: @"\01??_7X@test1@@6BB@1@@"
Stephen Hines6bcf27b2014-05-29 04:14:42 -070034
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
Stephen Hines0e2c34f2015-03-23 12:09:02 -070074 // BITCODE-DAG: @"\01??_7X@test2@@6BA@1@@"
75 // BITCODE-DAG: @"\01??_7X@test2@@6BB@1@@"
76 // BITCODE-DAG: @"\01??_7X@test2@@6BC@1@@"
Stephen Hines6bcf27b2014-05-29 04:14:42 -070077
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}
Stephen Hines0e2c34f2015-03-23 12:09:02 -0700141
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*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700163 // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8, i8* [[THIS1]], i32 4
Stephen Hines0e2c34f2015-03-23 12:09:02 -0700164 // 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*
Pirama Arumuga Nainar3ea9e332015-04-08 08:57:32 -0700174 // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8, i8* [[THIS1]], i32 4
Stephen Hines0e2c34f2015-03-23 12:09:02 -0700175 // BITCODE-NEXT: call x86_thiscallcc {{.*}}(i8* [[THIS2]])
176 -c;
177}
178
179}