// { dg-additional-options "--param early-inlining-insns=3 --param ipa-cp-eval-threshold=100" }
-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 Test2a {
- struct A {
- virtual ~A() final {}
- virtual int f();
- };
-
- // CHECK-LABEL: define i32 @_ZN6Test2a1fEPNS_1AE
- int f(A *a) {
- // CHECK: call i32 @_ZN6Test2a1A1fEv
- 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();
- }
-}
+struct A {
+ int a;
+};
+struct B {
+ int b;
+};
+struct C : B, A {};
+struct RA {
+ virtual A *operator-();
+};
+struct RC : RA {
+ C *operator-() {
+ C *x = new C();
+ return x;
+ }
+};
+void fop(RC *x) { -static_cast<RA &>(*x); }