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