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=MANGLING %s < %t.ll 4 5 namespace test1 { 6 struct A { 7 virtual void f(); 8 }; 9 10 struct B { 11 virtual void g(); 12 // Add an extra virtual method so it's easier to check for the absence of thunks. 13 virtual void h(); 14 }; 15 16 struct X : A, B { 17 // CHECK-LABEL: VFTable for 'test1::A' in 'test1::X' (1 entry) 18 // CHECK-NEXT: 0 | void test1::X::f() 19 20 // CHECK-LABEL: VFTable for 'test1::B' in 'test1::X' (2 entries) 21 // CHECK-NEXT: 0 | void test1::B::g() 22 // CHECK-NEXT: 1 | void test1::B::h() 23 24 // CHECK-LABEL: VFTable indices for 'test1::X' (1 entry) 25 // CHECK-NEXT: 0 | void test1::X::f() 26 27 // MANGLING-DAG: @"\01??_7X@test1@@6BA@1@@" 28 // MANGLING-DAG: @"\01??_7X@test1@@6BB@1@@" 29 30 // Overrides only the left child's method (A::f), needs no thunks. 31 virtual void f(); 32 } x; 33 34 void build_vftable(X *obj) { obj->f(); } 35 } 36 37 namespace test2 { 38 struct A { 39 virtual void f(); 40 }; 41 42 struct B { 43 virtual void g(); 44 virtual void h(); 45 }; 46 47 struct X : A, B { 48 // CHECK-LABEL: VFTable for 'test2::A' in 'test2::X' (1 entry) 49 // CHECK-NEXT: 0 | void test2::A::f() 50 51 // CHECK-LABEL: VFTable for 'test2::B' in 'test2::X' (2 entries) 52 // CHECK-NEXT: 0 | void test2::X::g() 53 // CHECK-NEXT: 1 | void test2::B::h() 54 55 // CHECK-LABEL: VFTable indices for 'test2::X' (1 entry). 56 // CHECK-NEXT: via vfptr at offset 4 57 // CHECK-NEXT: 0 | void test2::X::g() 58 59 // Overrides only the right child's method (B::g), needs this adjustment but 60 // not thunks. 61 virtual void g(); 62 }; 63 64 void build_vftable(X *obj) { obj->g(); } 65 } 66 67 namespace test3 { 68 struct A { 69 virtual void f(); 70 }; 71 72 struct B { 73 virtual void g(); 74 virtual void h(); 75 }; 76 77 struct X : A, B { 78 // CHECK-LABEL: VFTable for 'test3::A' in 'test3::X' (2 entries) 79 // CHECK-NEXT: 0 | void test3::A::f() 80 // CHECK-NEXT: 1 | void test3::X::i() 81 82 // CHECK-LABEL: VFTable for 'test3::B' in 'test3::X' (2 entries) 83 // CHECK-NEXT: 0 | void test3::B::g() 84 // CHECK-NEXT: 1 | void test3::B::h() 85 86 // CHECK-LABEL: VFTable indices for 'test3::X' (1 entry). 87 // CHECK-NEXT: 1 | void test3::X::i() 88 89 // Only adds a new method. 90 virtual void i(); 91 }; 92 93 void build_vftable(X *obj) { obj->i(); } 94 } 95 96 namespace test4 { 97 struct A { 98 virtual void f(); 99 }; 100 101 struct Empty { }; // Doesn't have a vftable! 102 103 // Only the right base has a vftable, so it's laid out before the left one! 104 struct X : Empty, A { 105 // CHECK-LABEL: VFTable for 'test4::A' in 'test4::X' (1 entry) 106 // CHECK-NEXT: 0 | void test4::X::f() 107 108 // CHECK-LABEL: VFTable indices for 'test4::X' (1 entry). 109 // CHECK-NEXT: 0 | void test4::X::f() 110 111 // MANGLING-DAG: @"\01??_7X@test4@@6B@" 112 113 virtual void f(); 114 } x; 115 116 void build_vftable(X *obj) { obj->f(); } 117 } 118 119 namespace test5 { 120 struct A { 121 virtual void f(); 122 }; 123 124 struct B { 125 virtual void g(); 126 virtual void h(); 127 }; 128 129 struct C : A, B { 130 virtual void f(); 131 }; 132 133 struct X : C { 134 // CHECK-LABEL: VFTable for 'test5::A' in 'test5::C' in 'test5::X' (1 entry). 135 // CHECK-NEXT: 0 | void test5::X::f() 136 137 // CHECK-LABEL: VFTable for 'test5::B' in 'test5::C' in 'test5::X' (2 entries). 138 // CHECK-NEXT: 0 | void test5::B::g() 139 // CHECK-NEXT: 1 | void test5::B::h() 140 141 // CHECK-LABEL: VFTable indices for 'test5::X' (1 entry). 142 // CHECK-NEXT: 0 | void test5::X::f() 143 144 // MANGLING-DAG: @"\01??_7X@test5@@6BA@1@@" 145 // MANGLING-DAG: @"\01??_7X@test5@@6BB@1@@" 146 147 // Overrides both C::f and A::f. 148 virtual void f(); 149 } x; 150 151 void build_vftable(X *obj) { obj->f(); } 152 } 153 154 namespace test6 { 155 struct A { 156 virtual void f(); 157 }; 158 159 struct B { 160 virtual void g(); 161 virtual void h(); 162 }; 163 164 struct C : A, B { 165 virtual void g(); 166 }; 167 168 struct X : C { 169 // CHECK-LABEL: VFTable for 'test6::A' in 'test6::C' in 'test6::X' (1 entry). 170 // CHECK-NEXT: 0 | void test6::A::f() 171 172 // CHECK-LABEL: VFTable for 'test6::B' in 'test6::C' in 'test6::X' (2 entries). 173 // CHECK-NEXT: 0 | void test6::X::g() 174 // CHECK-NEXT: 1 | void test6::B::h() 175 176 // CHECK-LABEL: VFTable indices for 'test6::X' (1 entry). 177 // CHECK-NEXT: via vfptr at offset 4 178 // CHECK-NEXT: 0 | void test6::X::g() 179 180 // Overrides both C::g and B::g. 181 virtual void g(); 182 }; 183 184 void build_vftable(X *obj) { obj->g(); } 185 } 186 187 namespace test7 { 188 struct A { 189 virtual void f(); 190 }; 191 192 struct B { 193 virtual void g(); 194 virtual void h(); 195 }; 196 197 struct C : A, B { 198 // Only adds a new method. 199 virtual void i(); 200 }; 201 202 struct X : C { 203 // CHECK-LABEL: VFTable for 'test7::A' in 'test7::C' in 'test7::X' (2 entries). 204 // CHECK-NEXT: 0 | void test7::A::f() 205 // CHECK-NEXT: 1 | void test7::C::i() 206 207 // CHECK-LABEL: VFTable for 'test7::B' in 'test7::C' in 'test7::X' (2 entries). 208 // CHECK-NEXT: 0 | void test7::X::g() 209 // CHECK-NEXT: 1 | void test7::B::h() 210 211 // CHECK-LABEL: VFTable indices for 'test7::X' (1 entry). 212 // CHECK-NEXT: via vfptr at offset 4 213 // CHECK-NEXT: 0 | void test7::X::g() 214 215 // Overrides grandparent's B::g. 216 virtual void g(); 217 }; 218 219 void build_vftable(X *obj) { obj->g(); } 220 } 221 222 namespace test8 { 223 struct A { 224 virtual void f(); 225 }; 226 227 struct B : A { 228 virtual void g(); 229 }; 230 231 // There are two 'A' subobjects in this class. 232 struct X : A, B { 233 // CHECK-LABEL: VFTable for 'test8::A' in 'test8::X' (2 entries). 234 // CHECK-NEXT: 0 | void test8::A::f() 235 // CHECK-NEXT: 1 | void test8::X::h() 236 237 // CHECK-LABEL: VFTable for 'test8::A' in 'test8::B' in 'test8::X' (2 entries). 238 // CHECK-NEXT: 0 | void test8::A::f() 239 // CHECK-NEXT: 1 | void test8::B::g() 240 241 // CHECK-LABEL: VFTable indices for 'test8::X' (1 entry). 242 // CHECK-NEXT: 1 | void test8::X::h() 243 244 // MANGLING-DAG: @"\01??_7X@test8@@6BA@1@@" 245 // MANGLING-DAG: @"\01??_7X@test8@@6BB@1@@" 246 247 virtual void h(); 248 } x; 249 250 void build_vftable(X *obj) { obj->h(); } 251 } 252 253 namespace test9 { 254 struct A { 255 virtual void f(); 256 }; 257 258 struct B { 259 virtual void g(); 260 virtual void h(); 261 }; 262 263 struct C : A, B { 264 // Overrides only the left child's method (A::f). 265 virtual void f(); 266 }; 267 268 struct D : A, B { 269 // Overrides only the right child's method (B::g). 270 virtual void g(); 271 }; 272 273 // 2-level structure with repeating subobject types, but no thunks needed. 274 struct X : C, D { 275 // CHECK-LABEL: VFTable for 'test9::A' in 'test9::C' in 'test9::X' (2 entries) 276 // CHECK-NEXT: 0 | void test9::C::f() 277 // CHECK-NEXT: 1 | void test9::X::z() 278 279 // CHECK-LABEL: VFTable for 'test9::B' in 'test9::C' in 'test9::X' (2 entries) 280 // CHECK-NEXT: 0 | void test9::B::g() 281 // CHECK-NEXT: 1 | void test9::B::h() 282 283 // CHECK-LABEL: VFTable for 'test9::A' in 'test9::D' in 'test9::X' (1 entry) 284 // CHECK-NEXT: 0 | void test9::A::f() 285 286 // CHECK-LABEL: VFTable for 'test9::B' in 'test9::D' in 'test9::X' (2 entries) 287 // CHECK-NEXT: 0 | void test9::D::g() 288 // CHECK-NEXT: 1 | void test9::B::h() 289 290 // CHECK-LABEL: VFTable indices for 'test9::X' (1 entry). 291 // CHECK-NEXT: 1 | void test9::X::z() 292 293 // MANGLING-DAG: @"\01??_7X@test9@@6BA@1@C@1@@" 294 // MANGLING-DAG: @"\01??_7X@test9@@6BA@1@D@1@@" 295 // MANGLING-DAG: @"\01??_7X@test9@@6BB@1@C@1@@" 296 // MANGLING-DAG: @"\01??_7X@test9@@6BB@1@D@1@@" 297 298 virtual void z(); 299 } x; 300 301 void build_vftable(test9::X *obj) { obj->z(); } 302 } 303