|  | // RUN: %clang_cc1 -triple i386-unknown-unknown -std=c++11 %s -emit-llvm -o - | FileCheck %s | 
|  |  | 
|  | namespace Test1 { | 
|  | struct A { | 
|  | virtual int f() final; | 
|  | }; | 
|  |  | 
|  | // CHECK-LABEL: define i32 @_ZN5Test11fEPNS_1AE | 
|  | int f(A *a) { | 
|  | // CHECK: call i32 @_ZN5Test11A1fEv | 
|  | return a->f(); | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace Test2 { | 
|  | struct A final { | 
|  | virtual int f(); | 
|  | }; | 
|  |  | 
|  | // CHECK-LABEL: define i32 @_ZN5Test21fEPNS_1AE | 
|  | int f(A *a) { | 
|  | // CHECK: call i32 @_ZN5Test21A1fEv | 
|  | return a->f(); | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace Test3 { | 
|  | struct A { | 
|  | virtual int f(); | 
|  | }; | 
|  |  | 
|  | struct B final : A { }; | 
|  |  | 
|  | // CHECK-LABEL: define i32 @_ZN5Test31fEPNS_1BE | 
|  | int f(B *b) { | 
|  | // CHECK: call i32 @_ZN5Test31A1fEv | 
|  | return b->f(); | 
|  | } | 
|  |  | 
|  | // CHECK-LABEL: define i32 @_ZN5Test31fERNS_1BE | 
|  | int f(B &b) { | 
|  | // CHECK: call i32 @_ZN5Test31A1fEv | 
|  | return b.f(); | 
|  | } | 
|  |  | 
|  | // CHECK-LABEL: define i32 @_ZN5Test31fEPv | 
|  | int f(void *v) { | 
|  | // CHECK: call i32 @_ZN5Test31A1fEv | 
|  | return static_cast<B*>(v)->f(); | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace Test4 { | 
|  | struct A { | 
|  | virtual void f(); | 
|  | virtual int operator-(); | 
|  | }; | 
|  |  | 
|  | struct B final : A { | 
|  | virtual void f(); | 
|  | virtual int operator-(); | 
|  | }; | 
|  |  | 
|  | // CHECK-LABEL: define void @_ZN5Test41fEPNS_1BE | 
|  | void f(B* d) { | 
|  | // CHECK: call void @_ZN5Test41B1fEv | 
|  | static_cast<A*>(d)->f(); | 
|  | // CHECK: call i32 @_ZN5Test41BngEv | 
|  | -static_cast<A&>(*d); | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace Test5 { | 
|  | struct A { | 
|  | virtual void f(); | 
|  | virtual int operator-(); | 
|  | }; | 
|  |  | 
|  | struct B : A { | 
|  | virtual void f(); | 
|  | virtual int operator-(); | 
|  | }; | 
|  |  | 
|  | struct C final : B { | 
|  | }; | 
|  |  | 
|  | // CHECK-LABEL: define void @_ZN5Test51fEPNS_1CE | 
|  | void f(C* d) { | 
|  | // FIXME: It should be possible to devirtualize this case, but that is | 
|  | // not implemented yet. | 
|  | // CHECK: getelementptr | 
|  | // CHECK-NEXT: %[[FUNC:.*]] = load | 
|  | // CHECK-NEXT: call void %[[FUNC]] | 
|  | static_cast<A*>(d)->f(); | 
|  | } | 
|  | // CHECK-LABEL: define void @_ZN5Test53fopEPNS_1CE | 
|  | void fop(C* d) { | 
|  | // FIXME: It should be possible to devirtualize this case, but that is | 
|  | // not implemented yet. | 
|  | // CHECK: getelementptr | 
|  | // CHECK-NEXT: %[[FUNC:.*]] = load | 
|  | // CHECK-NEXT: call i32 %[[FUNC]] | 
|  | -static_cast<A&>(*d); | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace Test6 { | 
|  | struct A { | 
|  | virtual ~A(); | 
|  | }; | 
|  |  | 
|  | struct B : public A { | 
|  | virtual ~B(); | 
|  | }; | 
|  |  | 
|  | struct C { | 
|  | virtual ~C(); | 
|  | }; | 
|  |  | 
|  | struct D final : public C, public B { | 
|  | }; | 
|  |  | 
|  | // CHECK-LABEL: define void @_ZN5Test61fEPNS_1DE | 
|  | void f(D* d) { | 
|  | // CHECK: call void @_ZN5Test61DD1Ev | 
|  | static_cast<A*>(d)->~A(); | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace Test7 { | 
|  | struct foo { | 
|  | virtual void g() {} | 
|  | }; | 
|  |  | 
|  | struct bar { | 
|  | virtual int f() { return 0; } | 
|  | }; | 
|  |  | 
|  | struct zed final : public foo, public bar { | 
|  | int z; | 
|  | virtual int f() {return z;} | 
|  | }; | 
|  |  | 
|  | // CHECK-LABEL: define i32 @_ZN5Test71fEPNS_3zedE | 
|  | int f(zed *z) { | 
|  | // CHECK: alloca | 
|  | // CHECK-NEXT: store | 
|  | // CHECK-NEXT: load | 
|  | // CHECK-NEXT: call i32 @_ZN5Test73zed1fEv | 
|  | // CHECK-NEXT: ret | 
|  | return static_cast<bar*>(z)->f(); | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace Test8 { | 
|  | struct A { virtual ~A() {} }; | 
|  | struct B { | 
|  | int b; | 
|  | virtual int foo() { return b; } | 
|  | }; | 
|  | struct C final : A, B {  }; | 
|  | // CHECK-LABEL: define i32 @_ZN5Test84testEPNS_1CE | 
|  | int test(C *c) { | 
|  | // CHECK: %[[THIS:.*]] = phi | 
|  | // CHECK-NEXT: call i32 @_ZN5Test81B3fooEv(%"struct.Test8::B"* %[[THIS]]) | 
|  | return static_cast<B*>(c)->foo(); | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace Test9 { | 
|  | struct A { | 
|  | int a; | 
|  | }; | 
|  | struct B { | 
|  | int b; | 
|  | }; | 
|  | struct C : public B, public A { | 
|  | }; | 
|  | struct RA { | 
|  | virtual A *f() { | 
|  | return 0; | 
|  | } | 
|  | virtual A *operator-() { | 
|  | return 0; | 
|  | } | 
|  | }; | 
|  | struct RC final : public RA { | 
|  | virtual C *f() { | 
|  | C *x = new C(); | 
|  | x->a = 1; | 
|  | x->b = 2; | 
|  | return x; | 
|  | } | 
|  | virtual C *operator-() { | 
|  | C *x = new C(); | 
|  | x->a = 1; | 
|  | x->b = 2; | 
|  | return x; | 
|  | } | 
|  | }; | 
|  | // CHECK: define {{.*}} @_ZN5Test91fEPNS_2RCE | 
|  | A *f(RC *x) { | 
|  | // FIXME: It should be possible to devirtualize this case, but that is | 
|  | // not implemented yet. | 
|  | // CHECK: load | 
|  | // CHECK: bitcast | 
|  | // CHECK: [[F_PTR_RA:%.+]] = bitcast | 
|  | // CHECK: [[VTABLE:%.+]] = load {{.+}} [[F_PTR_RA]] | 
|  | // CHECK: [[VFN:%.+]] = getelementptr inbounds {{.+}} [[VTABLE]], i{{[0-9]+}} 0 | 
|  | // CHECK-NEXT: %[[FUNC:.*]] = load {{.+}} [[VFN]] | 
|  | // CHECK-NEXT: = call {{.*}} %[[FUNC]] | 
|  | return static_cast<RA*>(x)->f(); | 
|  | } | 
|  | // CHECK: define {{.*}} @_ZN5Test93fopEPNS_2RCE | 
|  | A *fop(RC *x) { | 
|  | // FIXME: It should be possible to devirtualize this case, but that is | 
|  | // not implemented yet. | 
|  | // CHECK: load | 
|  | // CHECK: bitcast | 
|  | // CHECK: [[F_PTR_RA:%.+]] = bitcast | 
|  | // CHECK: [[VTABLE:%.+]] = load {{.+}} [[F_PTR_RA]] | 
|  | // CHECK: [[VFN:%.+]] = getelementptr inbounds {{.+}} [[VTABLE]], i{{[0-9]+}} 1 | 
|  | // CHECK-NEXT: %[[FUNC:.*]] = load {{.+}} [[VFN]] | 
|  | // CHECK-NEXT: = call {{.*}} %[[FUNC]] | 
|  | return -static_cast<RA&>(*x); | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace Test10 { | 
|  | struct A { | 
|  | virtual int f(); | 
|  | }; | 
|  |  | 
|  | struct B : A { | 
|  | int f() final; | 
|  | }; | 
|  |  | 
|  | // CHECK-LABEL: define i32 @_ZN6Test101fEPNS_1BE | 
|  | int f(B *b) { | 
|  | // CHECK: call i32 @_ZN6Test101B1fEv | 
|  | return static_cast<A *>(b)->f(); | 
|  | } | 
|  | } | 
|  |  | 
|  | namespace Test11 { | 
|  | // Check that the definitions of Derived's operators are emitted. | 
|  |  | 
|  | // CHECK-LABEL: define linkonce_odr void @_ZN6Test111SIiE4foo1Ev( | 
|  | // CHECK: call void @_ZN6Test111SIiE7DerivedclEv( | 
|  | // CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE( | 
|  | // CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedntEv( | 
|  | // CHECK: call dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi( | 
|  | // CHECK: define linkonce_odr void @_ZN6Test111SIiE7DerivedclEv( | 
|  | // CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE( | 
|  | // CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedntEv( | 
|  | // CHECK: define linkonce_odr dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi( | 
|  | class Base { | 
|  | public: | 
|  | virtual void operator()() {} | 
|  | virtual bool operator==(const Base &other) { return false; } | 
|  | virtual bool operator!() { return false; } | 
|  | virtual Base &operator[](int i) { return *this; } | 
|  | }; | 
|  |  | 
|  | template<class T> | 
|  | struct S { | 
|  | class Derived final : public Base { | 
|  | public: | 
|  | void operator()() override {} | 
|  | bool operator==(const Base &other) override { return true; } | 
|  | bool operator!() override { return true; } | 
|  | Base &operator[](int i) override { return *this; } | 
|  | }; | 
|  |  | 
|  | Derived *ptr = nullptr, *ptr2 = nullptr; | 
|  |  | 
|  | void foo1() { | 
|  | if (ptr && ptr2) { | 
|  | // These calls get devirtualized. Linkage fails if the definitions of | 
|  | // the called functions are not emitted. | 
|  | (*ptr)(); | 
|  | (void)(*ptr == *ptr2); | 
|  | (void)(!(*ptr)); | 
|  | (void)((*ptr)[1]); | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | void foo2() { | 
|  | S<int> *s = new S<int>; | 
|  | s->foo1(); | 
|  | } | 
|  | } |