346 lines · cpp
1// RUN: %clang_cc1 -triple i386-unknown-unknown -std=c++11 %s -emit-llvm -o - | FileCheck %s2 3namespace Test1 {4 struct A {5 virtual int f() final;6 };7 8 // CHECK-LABEL: define{{.*}} i32 @_ZN5Test11fEPNS_1AE9 int f(A *a) {10 // CHECK: call noundef i32 @_ZN5Test11A1fEv11 return a->f();12 }13}14 15namespace Test2 {16 struct A final {17 virtual int f();18 };19 20 // CHECK-LABEL: define{{.*}} i32 @_ZN5Test21fEPNS_1AE21 int f(A *a) {22 // CHECK: call noundef i32 @_ZN5Test21A1fEv23 return a->f();24 }25}26 27namespace Test2a {28 struct A {29 virtual ~A() final {}30 virtual int f();31 };32 33 // CHECK-LABEL: define{{.*}} i32 @_ZN6Test2a1fEPNS_1AE34 int f(A *a) {35 // CHECK: call noundef i32 @_ZN6Test2a1A1fEv36 return a->f();37 }38}39 40 41namespace Test3 {42 struct A {43 virtual int f(); };44 45 struct B final : A { };46 47 // CHECK-LABEL: define{{.*}} i32 @_ZN5Test31fEPNS_1BE48 int f(B *b) {49 // CHECK: call noundef i32 @_ZN5Test31A1fEv50 return b->f();51 }52 53 // CHECK-LABEL: define{{.*}} i32 @_ZN5Test31fERNS_1BE54 int f(B &b) {55 // CHECK: call noundef i32 @_ZN5Test31A1fEv56 return b.f();57 }58 59 // CHECK-LABEL: define{{.*}} i32 @_ZN5Test31fEPv60 int f(void *v) {61 // CHECK: call noundef i32 @_ZN5Test31A1fEv62 return static_cast<B*>(v)->f();63 }64}65 66namespace Test4 {67 struct A {68 virtual void f();69 virtual int operator-();70 };71 72 struct B final : A {73 virtual void f();74 virtual int operator-();75 };76 77 // CHECK-LABEL: define{{.*}} void @_ZN5Test41fEPNS_1BE78 void f(B* d) {79 // CHECK: call void @_ZN5Test41B1fEv80 static_cast<A*>(d)->f();81 // CHECK: call noundef i32 @_ZN5Test41BngEv82 -static_cast<A&>(*d);83 }84}85 86namespace Test5 {87 struct A {88 virtual void f();89 virtual int operator-();90 };91 92 struct B : A {93 virtual void f();94 virtual int operator-();95 };96 97 struct C final : B {98 };99 100 // CHECK-LABEL: define{{.*}} void @_ZN5Test51fEPNS_1CE101 void f(C* d) {102 // FIXME: It should be possible to devirtualize this case, but that is103 // not implemented yet.104 // CHECK: getelementptr105 // CHECK-NEXT: %[[FUNC:.*]] = load106 // CHECK-NEXT: call void %[[FUNC]]107 static_cast<A*>(d)->f();108 }109 // CHECK-LABEL: define{{.*}} void @_ZN5Test53fopEPNS_1CE110 void fop(C* d) {111 // FIXME: It should be possible to devirtualize this case, but that is112 // not implemented yet.113 // CHECK: getelementptr114 // CHECK-NEXT: %[[FUNC:.*]] = load115 // CHECK-NEXT: call noundef i32 %[[FUNC]]116 -static_cast<A&>(*d);117 }118}119 120namespace Test6 {121 struct A {122 virtual ~A();123 };124 125 struct B : public A {126 virtual ~B();127 };128 129 struct C {130 virtual ~C();131 };132 133 struct D final : public C, public B {134 };135 136 // CHECK-LABEL: define{{.*}} void @_ZN5Test61fEPNS_1DE137 void f(D* d) {138 // CHECK: call void @_ZN5Test61DD1Ev139 static_cast<A*>(d)->~A();140 }141}142 143namespace Test7 {144 struct foo {145 virtual void g() {}146 };147 148 struct bar {149 virtual int f() { return 0; }150 };151 152 struct zed final : public foo, public bar {153 int z;154 virtual int f() {return z;}155 };156 157 // CHECK-LABEL: define{{.*}} i32 @_ZN5Test71fEPNS_3zedE158 int f(zed *z) {159 // CHECK: alloca160 // CHECK-NEXT: store161 // CHECK-NEXT: load162 // CHECK-NEXT: call noundef i32 @_ZN5Test73zed1fEv163 // CHECK-NEXT: ret164 return static_cast<bar*>(z)->f();165 }166}167 168namespace Test8 {169 struct A { virtual ~A() {} };170 struct B {171 int b;172 virtual int foo() { return b; }173 };174 struct C final : A, B { };175 // CHECK-LABEL: define{{.*}} i32 @_ZN5Test84testEPNS_1CE176 int test(C *c) {177 // CHECK: %[[THIS:.*]] = phi178 // CHECK-NEXT: call noundef i32 @_ZN5Test81B3fooEv(ptr {{[^,]*}} %[[THIS]])179 return static_cast<B*>(c)->foo();180 }181}182 183namespace Test9 {184 struct A {185 int a;186 };187 struct B {188 int b;189 };190 struct C : public B, public A {191 };192 struct RA {193 virtual A *f() {194 return 0;195 }196 virtual A *operator-() {197 return 0;198 }199 };200 struct RC final : public RA {201 virtual C *f() {202 C *x = new C();203 x->a = 1;204 x->b = 2;205 return x;206 }207 virtual C *operator-() {208 C *x = new C();209 x->a = 1;210 x->b = 2;211 return x;212 }213 };214 // CHECK: define {{.*}} @_ZN5Test91fEPNS_2RCE215 A *f(RC *x) {216 // FIXME: It should be possible to devirtualize this case, but that is217 // not implemented yet.218 // CHECK: load219 // CHECK: [[VTABLE:%.+]] = load {{.+}}220 // CHECK: [[VFN:%.+]] = getelementptr inbounds {{.+}} [[VTABLE]], i{{[0-9]+}} 0221 // CHECK-NEXT: %[[FUNC:.*]] = load {{.+}} [[VFN]]222 // CHECK-NEXT: = call {{.*}} %[[FUNC]]223 return static_cast<RA*>(x)->f();224 }225 // CHECK: define {{.*}} @_ZN5Test93fopEPNS_2RCE226 A *fop(RC *x) {227 // FIXME: It should be possible to devirtualize this case, but that is228 // not implemented yet.229 // CHECK: load230 // CHECK: [[VTABLE:%.+]] = load {{.+}}231 // CHECK: [[VFN:%.+]] = getelementptr inbounds {{.+}} [[VTABLE]], i{{[0-9]+}} 1232 // CHECK-NEXT: %[[FUNC:.*]] = load {{.+}} [[VFN]]233 // CHECK-NEXT: = call {{.*}} %[[FUNC]]234 return -static_cast<RA&>(*x);235 }236}237 238namespace Test10 {239 struct A {240 virtual int f();241 };242 243 struct B : A {244 int f() final;245 };246 247 // CHECK-LABEL: define{{.*}} i32 @_ZN6Test101fEPNS_1BE248 int f(B *b) {249 // CHECK: call noundef i32 @_ZN6Test101B1fEv250 return static_cast<A *>(b)->f();251 }252}253 254namespace TestVBase {255 struct A { virtual void f(); };256 struct B : virtual A {};257 struct C : virtual A { void f() override; };258 259 extern struct BC final : B, C {} &bc;260 extern struct BCusingA final : B, C { using A::f; } &bc_using_a;261 extern struct BCusingB final : B, C { using B::f; } &bc_using_b;262 extern struct BCusingC final : B, C { using C::f; } &bc_using_c;263 264 extern struct CB final : C, B {} &cb;265 extern struct CBusingA final : C, B { using A::f; } &cb_using_a;266 extern struct CBusingB final : C, B { using B::f; } &cb_using_b;267 extern struct CBusingC final : C, B { using C::f; } &cb_using_c;268 269 // CHECK-LABEL: @_ZN9TestVBase4testEv(270 void test() {271 // FIXME: The 'using A' case can be devirtualized to call A's virtual272 // adjustment thunk for C::f.273 // FIXME: The 'using B' case can be devirtualized, but requires us to emit274 // a derived-to-base or base-to-derived conversion as part of275 // devirtualization.276 277 // CHECK: call void @_ZN9TestVBase1C1fEv(278 bc.f();279 // CHECK: call void %280 bc_using_a.f();281 // CHECK: call void %282 bc_using_b.f();283 // CHECK: call void @_ZN9TestVBase1C1fEv(284 bc_using_c.f();285 286 // CHECK: call void @_ZN9TestVBase1C1fEv(287 cb.f();288 // CHECK: call void %289 cb_using_a.f();290 // CHECK: call void %291 cb_using_b.f();292 // CHECK: call void @_ZN9TestVBase1C1fEv(293 cb_using_c.f();294 }295}296 297namespace Test11 {298 // Check that the definitions of Derived's operators are emitted.299 300 // CHECK-LABEL: define linkonce_odr void @_ZN6Test111SIiE4foo1Ev(301 // CHECK: call void @_ZN6Test111SIiE7DerivedclEv(302 // CHECK: call noundef zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE(303 // CHECK: call noundef zeroext i1 @_ZN6Test111SIiE7DerivedntEv(304 // CHECK: call noundef nonnull align 4 dereferenceable(4) ptr @_ZN6Test111SIiE7DerivedixEi(305 // CHECK: define linkonce_odr void @_ZN6Test111SIiE7DerivedclEv(306 // CHECK: define linkonce_odr noundef zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE(307 // CHECK: define linkonce_odr noundef zeroext i1 @_ZN6Test111SIiE7DerivedntEv(308 // CHECK: define linkonce_odr noundef nonnull align 4 dereferenceable(4) ptr @_ZN6Test111SIiE7DerivedixEi(309 class Base {310 public:311 virtual void operator()() {}312 virtual bool operator==(const Base &other) { return false; }313 virtual bool operator!() { return false; }314 virtual Base &operator[](int i) { return *this; }315 };316 317 template<class T>318 struct S {319 class Derived final : public Base {320 public:321 void operator()() override {}322 bool operator==(const Base &other) override { return true; }323 bool operator!() override { return true; }324 Base &operator[](int i) override { return *this; }325 };326 327 Derived *ptr = nullptr, *ptr2 = nullptr;328 329 void foo1() {330 if (ptr && ptr2) {331 // These calls get devirtualized. Linkage fails if the definitions of332 // the called functions are not emitted.333 (*ptr)();334 (void)(*ptr == *ptr2);335 (void)(!(*ptr));336 (void)((*ptr)[1]);337 }338 }339 };340 341 void foo2() {342 S<int> *s = new S<int>;343 s->foo1();344 }345}346