| // RUN: %clang_cc1 -std=c++98 %s -triple armv7-none-eabi -emit-llvm -o - | FileCheck %s | |
| // RUN: %clang_cc1 -std=c++11 %s -triple armv7-none-eabi -emit-llvm -o - | FileCheck %s | |
| // RUN: %clang_cc1 -std=c++1z %s -triple armv7-none-eabi -emit-llvm -o - | FileCheck %s | |
| struct A { | |
| virtual void f(); | |
| virtual void f_const() const; | |
| virtual void g(); | |
| A h(); | |
| }; | |
| A g(); | |
| void f(A a, A *ap, A& ar) { | |
| // This should not be a virtual function call. | |
| // CHECK: call void @_ZN1A1fEv(ptr {{[^,]*}} %a) | |
| a.f(); | |
| // CHECK: call void % | |
| ap->f(); | |
| // CHECK: call void % | |
| ar.f(); | |
| // CHECK: call void @_ZN1A1fEv | |
| A().f(); | |
| // CHECK: call void @_ZN1A1fEv | |
| g().f(); | |
| // CHECK: call void @_ZN1A1fEv | |
| a.h().f(); | |
| // CHECK: call void @_ZNK1A7f_constEv | |
| a.f_const(); | |
| // CHECK: call void @_ZN1A1fEv | |
| (a).f(); | |
| } | |
| struct D : A { virtual void g(); }; | |
| struct XD { D d; }; | |
| D gd(); | |
| void fd(D d, XD xd, D *p) { | |
| // CHECK: call void @_ZN1A1fEv(ptr | |
| d.f(); | |
| // CHECK: call void @_ZN1D1gEv(ptr | |
| d.g(); | |
| // CHECK: call void @_ZN1A1fEv | |
| D().f(); | |
| // CHECK: call void @_ZN1D1gEv | |
| D().g(); | |
| // CHECK: call void @_ZN1A1fEv | |
| gd().f(); | |
| // CHECK: call void @_ZNK1A7f_constEv | |
| d.f_const(); | |
| // CHECK: call void @_ZN1A1fEv | |
| (d).f(); | |
| // CHECK: call void @_ZN1A1fEv | |
| (true, d).f(); | |
| // CHECK: call void @_ZN1D1gEv | |
| (true, d).g(); | |
| // CHECK: call void @_ZN1A1fEv | |
| xd.d.f(); | |
| // CHECK: call void @_ZN1A1fEv | |
| XD().d.f(); | |
| // CHECK: call void @_ZN1A1fEv | |
| D XD::*mp; | |
| (xd.*mp).f(); | |
| // CHECK: call void @_ZN1D1gEv | |
| (xd.*mp).g(); | |
| // Can't devirtualize this; we have no guarantee that p points to a D here, | |
| // due to the "single object is considered to be an array of one element" | |
| // rule. | |
| // CHECK: call void % | |
| p[0].f(); | |
| // FIXME: We can devirtualize this, by C++1z [expr.add]/6 (if the array | |
| // element type and the pointee type are not similar, behavior is undefined). | |
| // CHECK: call void % | |
| p[1].f(); | |
| } | |
| struct B { | |
| virtual void f(); | |
| ~B(); | |
| B h(); | |
| }; | |
| void f() { | |
| // CHECK: call void @_ZN1B1fEv | |
| B().f(); | |
| // CHECK: call void @_ZN1B1fEv | |
| B().h().f(); | |
| } | |
| namespace test2 { | |
| struct foo { | |
| virtual void f(); | |
| virtual ~foo(); | |
| }; | |
| struct bar : public foo { | |
| virtual void f(); | |
| virtual ~bar(); | |
| }; | |
| void f(bar *b) { | |
| // CHECK: call void @_ZN5test23foo1fEv | |
| // CHECK: call noundef ptr @_ZN5test23fooD1Ev | |
| b->foo::f(); | |
| b->foo::~foo(); | |
| } | |
| } | |
| namespace test3 { | |
| // Test that we don't crash in this case. | |
| struct B { | |
| }; | |
| struct D : public B { | |
| }; | |
| void f(D d) { | |
| // CHECK-LABEL: define{{.*}} void @_ZN5test31fENS_1DE | |
| d.B::~B(); | |
| } | |
| } | |
| namespace test4 { | |
| struct Animal { | |
| virtual void eat(); | |
| }; | |
| struct Fish : Animal { | |
| virtual void eat(); | |
| }; | |
| struct Wrapper { | |
| Fish fish; | |
| }; | |
| extern Wrapper *p; | |
| void test() { | |
| // CHECK: call void @_ZN5test44Fish3eatEv | |
| p->fish.eat(); | |
| } | |
| } | |
| // Do not devirtualize to pure virtual function calls. | |
| namespace test5 { | |
| struct X { | |
| virtual void f() = 0; | |
| }; | |
| struct Y {}; | |
| // CHECK-LABEL: define {{.*}} @_ZN5test51f | |
| void f(Y &y, X Y::*p) { | |
| // CHECK-NOT: call {{.*}} @_ZN5test51X1fEv | |
| // CHECK: call void % | |
| (y.*p).f(); | |
| }; | |
| struct Z final { | |
| virtual void f() = 0; | |
| }; | |
| // CHECK-LABEL: define {{.*}} @_ZN5test51g | |
| void g(Z &z) { | |
| // CHECK-NOT: call {{.*}} @_ZN5test51Z1fEv | |
| // CHECK: call void % | |
| z.f(); | |
| } | |
| struct Q { | |
| virtual void f() final = 0; | |
| }; | |
| // CHECK-LABEL: define {{.*}} @_ZN5test51h | |
| void h(Q &q) { | |
| // CHECK-NOT: call {{.*}} @_ZN5test51Q1fEv | |
| // CHECK: call void % | |
| q.f(); | |
| } | |
| } |