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
8 // Add an extra virtual method so it's easier to check for the absence of thunks.
13 virtual void g(); // Collides with A::g if both are bases of some class.
16 // Overrides methods of two bases at the same time, thus needing thunks.
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()
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]
26 // CHECK-LABEL: Thunks for 'void test1::X::g()' (1 entry).
27 // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
29 // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry).
30 // CHECK-NEXT: 0 | void test1::X::g()
32 // BITCODE-DAG: @"??_7X@test1@@6BA@1@@"
33 // BITCODE-DAG: @"??_7X@test1@@6BB@1@@"
38 void build_vftable(X
*obj
) { obj
->g(); }
56 // CHECK-LABEL: VFTable for 'test2::A' in 'test2::X' (1 entry).
57 // CHECK-NEXT: 0 | void test2::A::f()
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()
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]
67 // CHECK-LABEL: Thunks for 'void test2::X::g()' (1 entry).
68 // CHECK-NEXT: 0 | [this adjustment: -4 non-virtual]
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()
74 // BITCODE-DAG: @"??_7X@test2@@6BA@1@@"
75 // BITCODE-DAG: @"??_7X@test2@@6BB@1@@"
76 // BITCODE-DAG: @"??_7X@test2@@6BC@1@@"
81 void build_vftable(X
*obj
) { obj
->g(); }
95 // Overrides only the left child's method (A::f), needs no thunks.
100 // Overrides only the right child's method (B::g),
101 // needs this adjustment but not thunks.
105 // Overrides methods of two bases at the same time, thus needing thunks.
107 // CHECK-LABEL: VFTable for 'test3::A' in 'test3::C' in 'test3::X' (1 entry).
108 // CHECK-NEXT: 0 | void test3::X::f()
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()
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]
118 // CHECK-LABEL: Thunks for 'void test3::X::f()' (1 entry).
119 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
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()
126 // CHECK-LABEL: Thunks for 'void test3::X::g()' (1 entry).
127 // CHECK-NEXT: 0 | [this adjustment: -8 non-virtual]
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()
139 void build_vftable(X
*obj
) { obj
->g(); }
147 virtual int filler();
148 virtual int operator-();
151 struct C
: public A
, public B
{
152 virtual int filler();
153 virtual int operator-();
157 // BITCODE-LABEL: define {{.*}}"?ffun@test4@@YAXAAUC@1@@Z
159 // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8, ptr {{.*}}, i32 4
160 // BITCODE: call x86_thiscallcc {{.*}}(ptr noundef [[THIS2]])
164 // BITCODE-LABEL: define {{.*}}"?fop@test4@@YAXAAUC@1@@Z
166 // BITCODE: [[THIS2:%.+]] = getelementptr inbounds i8, ptr {{.*}}, i32 4
167 // BITCODE: call x86_thiscallcc {{.*}}(ptr noundef [[THIS2]])
178 struct A
{ virtual void f(); };
179 struct B
{ virtual void __cdecl
g(NonTrivial
); };
180 struct C final
: A
, B
{
182 void __cdecl
g(NonTrivial
) override
;
185 void C::f() { g(NonTrivial()); }
186 void C::g(NonTrivial o
) {
190 // BITCODE-LABEL: define dso_local void @"?g@C@pr30293@@UAAXUNonTrivial@2@@Z"(ptr inalloca(<{ ptr, %"struct.pr30293::NonTrivial" }>) %0)
191 // BITCODE: %[[thisaddr:[^ ]*]] = getelementptr inbounds <{ ptr, %"struct.pr30293::NonTrivial" }>, ptr {{.*}}, i32 0, i32 0
192 // BITCODE: %[[this1:[^ ]*]] = load ptr, ptr %[[thisaddr]], align 4
193 // BITCODE: %[[this3:[^ ]*]] = getelementptr inbounds i8, ptr %[[this1]], i32 -4
194 // BITCODE: store ptr %[[this3]], ptr @"?whatsthis@pr30293@@3PAUC@1@A", align 4