1 // RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -fdump-vtable-layouts -o %t.ll > %t 2 // RUN: FileCheck --check-prefix=EMITS-VFTABLE %s < %t.ll 3 // RUN: FileCheck --check-prefix=NO-VFTABLE %s < %t.ll 4 // RUN: FileCheck --check-prefix=CHECK-A %s < %t 5 // RUN: FileCheck --check-prefix=CHECK-B %s < %t 6 // RUN: FileCheck --check-prefix=CHECK-C %s < %t 7 // RUN: FileCheck --check-prefix=CHECK-D %s < %t 8 // RUN: FileCheck --check-prefix=CHECK-E %s < %t 9 // RUN: FileCheck --check-prefix=CHECK-F %s < %t 10 // RUN: FileCheck --check-prefix=CHECK-G %s < %t 11 // RUN: FileCheck --check-prefix=CHECK-I %s < %t 12 // RUN: FileCheck --check-prefix=CHECK-J %s < %t 13 // RUN: FileCheck --check-prefix=CHECK-K %s < %t 14 // RUN: FileCheck --check-prefix=CHECK-L %s < %t 15 // RUN: FileCheck --check-prefix=CHECK-M %s < %t 16 // RUN: FileCheck --check-prefix=CHECK-N %s < %t 17 18 struct A { 19 // CHECK-A: VFTable for 'A' (3 entries) 20 // CHECK-A-NEXT: 0 | void A::f() 21 // CHECK-A-NEXT: 1 | void A::g() 22 // CHECK-A-NEXT: 2 | void A::h() 23 // CHECK-A: VFTable indices for 'A' (3 entries) 24 // CHECK-A-NEXT: 0 | void A::f() 25 // CHECK-A-NEXT: 1 | void A::g() 26 // CHECK-A-NEXT: 2 | void A::h() 27 28 virtual void f(); 29 virtual void g(); 30 virtual void h(); 31 int ia; 32 }; 33 A a; 34 // EMITS-VFTABLE-DAG: @"\01??_7A@@6B@" = linkonce_odr unnamed_addr constant [3 x i8*] 35 36 struct B : A { 37 // CHECK-B: VFTable for 'A' in 'B' (5 entries) 38 // CHECK-B-NEXT: 0 | void B::f() 39 // CHECK-B-NEXT: 1 | void A::g() 40 // CHECK-B-NEXT: 2 | void A::h() 41 // CHECK-B-NEXT: 3 | void B::i() 42 // CHECK-B-NEXT: 4 | void B::j() 43 // CHECK-B: VFTable indices for 'B' (3 entries) 44 // CHECK-B-NEXT: 0 | void B::f() 45 // CHECK-B-NEXT: 3 | void B::i() 46 // CHECK-B-NEXT: 4 | void B::j() 47 48 virtual void f(); // overrides A::f() 49 virtual void i(); 50 virtual void j(); 51 }; 52 B b; 53 // EMITS-VFTABLE-DAG: @"\01??_7B@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*] 54 55 struct C { 56 // CHECK-C: VFTable for 'C' (2 entries) 57 // CHECK-C-NEXT: 0 | C::~C() [scalar deleting] 58 // CHECK-C-NEXT: 1 | void C::f() 59 // CHECK-C: VFTable indices for 'C' (2 entries). 60 // CHECK-C-NEXT: 0 | C::~C() [scalar deleting] 61 // CHECK-C-NEXT: 1 | void C::f() 62 63 virtual ~C(); 64 virtual void f(); 65 }; 66 void C::f() {} 67 // NO-VFTABLE-NOT: @"\01??_7C@@6B@" 68 69 struct D { 70 // CHECK-D: VFTable for 'D' (2 entries) 71 // CHECK-D-NEXT: 0 | void D::f() 72 // CHECK-D-NEXT: 1 | D::~D() [scalar deleting] 73 // CHECK-D: VFTable indices for 'D' (2 entries) 74 // CHECK-D-NEXT: 0 | void D::f() 75 // CHECK-D-NEXT: 1 | D::~D() [scalar deleting] 76 77 virtual void f(); 78 virtual ~D(); 79 }; 80 D d; 81 // EMITS-VFTABLE-DAG: @"\01??_7D@@6B@" = linkonce_odr unnamed_addr constant [2 x i8*] 82 83 struct E : A { 84 // CHECK-E: VFTable for 'A' in 'E' (5 entries) 85 // CHECK-E-NEXT: 0 | void A::f() 86 // CHECK-E-NEXT: 1 | void A::g() 87 // CHECK-E-NEXT: 2 | void A::h() 88 // CHECK-E-NEXT: 3 | E::~E() [scalar deleting] 89 // CHECK-E-NEXT: 4 | void E::i() 90 // CHECK-E: VFTable indices for 'E' (2 entries). 91 // CHECK-E-NEXT: 3 | E::~E() [scalar deleting] 92 // CHECK-E-NEXT: 4 | void E::i() 93 94 // ~E would be the key method, but it isn't used, and MS ABI has no key 95 // methods. 96 virtual ~E(); 97 virtual void i(); 98 }; 99 void E::i() {} 100 // NO-VFTABLE-NOT: @"\01??_7E@@6B@" 101 102 struct F : A { 103 // CHECK-F: VFTable for 'A' in 'F' (5 entries) 104 // CHECK-F-NEXT: 0 | void A::f() 105 // CHECK-F-NEXT: 1 | void A::g() 106 // CHECK-F-NEXT: 2 | void A::h() 107 // CHECK-F-NEXT: 3 | void F::i() 108 // CHECK-F-NEXT: 4 | F::~F() [scalar deleting] 109 // CHECK-F: VFTable indices for 'F' (2 entries). 110 // CHECK-F-NEXT: 3 | void F::i() 111 // CHECK-F-NEXT: 4 | F::~F() [scalar deleting] 112 113 virtual void i(); 114 virtual ~F(); 115 }; 116 F f; 117 // EMITS-VFTABLE-DAG: @"\01??_7F@@6B@" = linkonce_odr unnamed_addr constant [5 x i8*] 118 119 struct G : E { 120 // CHECK-G: VFTable for 'A' in 'E' in 'G' (6 entries) 121 // CHECK-G-NEXT: 0 | void G::f() 122 // CHECK-G-NEXT: 1 | void A::g() 123 // CHECK-G-NEXT: 2 | void A::h() 124 // CHECK-G-NEXT: 3 | G::~G() [scalar deleting] 125 // CHECK-G-NEXT: 4 | void E::i() 126 // CHECK-G-NEXT: 5 | void G::j() 127 // CHECK-G: VFTable indices for 'G' (3 entries). 128 // CHECK-G-NEXT: 0 | void G::f() 129 // CHECK-G-NEXT: 3 | G::~G() [scalar deleting] 130 // CHECK-G-NEXT: 5 | void G::j() 131 132 virtual void f(); // overrides A::f() 133 virtual ~G(); 134 virtual void j(); 135 }; 136 void G::j() {} 137 // NO-VFTABLE-NOT: @"\01??_7G@@6B@" 138 139 // Test that the usual Itanium-style key method does not emit a vtable. 140 struct H { 141 virtual void f(); 142 }; 143 void H::f() {} 144 // NO-VFTABLE-NOT: @"\01??_7H@@6B@" 145 146 struct Empty { }; 147 148 struct I : Empty { 149 // CHECK-I: VFTable for 'I' (2 entries) 150 // CHECK-I-NEXT: 0 | void I::f() 151 // CHECK-I-NEXT: 1 | void I::g() 152 virtual void f(); 153 virtual void g(); 154 }; 155 156 I i; 157 158 struct J { 159 // CHECK-J: VFTable for 'J' (6 entries) 160 // CHECK-J-NEXT: 0 | void J::foo(long) 161 // CHECK-J-NEXT: 1 | void J::foo(int) 162 // CHECK-J-NEXT: 2 | void J::foo(short) 163 // CHECK-J-NEXT: 3 | void J::bar(long) 164 // CHECK-J-NEXT: 4 | void J::bar(int) 165 // CHECK-J-NEXT: 5 | void J::bar(short) 166 virtual void foo(short); 167 virtual void bar(short); 168 virtual void foo(int); 169 virtual void bar(int); 170 virtual void foo(long); 171 virtual void bar(long); 172 }; 173 174 J j; 175 176 struct K : J { 177 // CHECK-K: VFTable for 'J' in 'K' (9 entries) 178 // CHECK-K-NEXT: 0 | void J::foo(long) 179 // CHECK-K-NEXT: 1 | void J::foo(int) 180 // CHECK-K-NEXT: 2 | void J::foo(short) 181 // CHECK-K-NEXT: 3 | void J::bar(long) 182 // CHECK-K-NEXT: 4 | void J::bar(int) 183 // CHECK-K-NEXT: 5 | void J::bar(short) 184 // CHECK-K-NEXT: 6 | void K::bar(double) 185 // CHECK-K-NEXT: 7 | void K::bar(float) 186 // CHECK-K-NEXT: 8 | void K::foo(float) 187 virtual void bar(float); 188 virtual void foo(float); 189 virtual void bar(double); 190 }; 191 192 K k; 193 194 struct L : J { 195 // CHECK-L: VFTable for 'J' in 'L' (9 entries) 196 // CHECK-L-NEXT: 0 | void J::foo(long) 197 // CHECK-L-NEXT: 1 | void L::foo(int) 198 // CHECK-L-NEXT: 2 | void J::foo(short) 199 // CHECK-L-NEXT: 3 | void J::bar(long) 200 // CHECK-L-NEXT: 4 | void J::bar(int) 201 // CHECK-L-NEXT: 5 | void J::bar(short) 202 // CHECK-L-NEXT: 6 | void L::foo(float) 203 // CHECK-L-NEXT: 7 | void L::bar(double) 204 // CHECK-L-NEXT: 8 | void L::bar(float) 205 206 // This case is interesting. Since the J::foo(int) override is the first method in 207 // the class, foo(float) precedes the bar(double) and bar(float) in the vftable. 208 virtual void foo(int); 209 virtual void bar(float); 210 virtual void foo(float); 211 virtual void bar(double); 212 }; 213 214 L l; 215 216 struct M : J { 217 // CHECK-M: VFTable for 'J' in 'M' (11 entries) 218 // CHECK-M-NEXT: 0 | void J::foo(long) 219 // CHECK-M-NEXT: 1 | void M::foo(int) 220 // CHECK-M-NEXT: 2 | void J::foo(short) 221 // CHECK-M-NEXT: 3 | void J::bar(long) 222 // CHECK-M-NEXT: 4 | void J::bar(int) 223 // CHECK-M-NEXT: 5 | void J::bar(short) 224 // CHECK-M-NEXT: 6 | void M::foo(float) 225 // CHECK-M-NEXT: 7 | void M::spam(long) 226 // CHECK-M-NEXT: 8 | void M::spam(int) 227 // CHECK-M-NEXT: 9 | void M::bar(double) 228 // CHECK-M-NEXT: 10 | void M::bar(float) 229 230 virtual void foo(int); 231 virtual void spam(int); 232 virtual void bar(float); 233 virtual void bar(double); 234 virtual void foo(float); 235 virtual void spam(long); 236 }; 237 238 M m; 239 240 struct N { 241 // CHECK-N: VFTable for 'N' (4 entries) 242 // CHECK-N-NEXT: 0 | void N::operator+(int) 243 // CHECK-N-NEXT: 1 | void N::operator+(short) 244 // CHECK-N-NEXT: 2 | void N::operator*(int) 245 // CHECK-N-NEXT: 3 | void N::operator*(short) 246 virtual void operator+(short); 247 virtual void operator*(short); 248 virtual void operator+(int); 249 virtual void operator*(int); 250 }; 251 252 N n; 253