f4a2713ac8
Change-Id: Ia40e9ffdf29b5dab2f122f673ff6802a58bc690f
187 lines
3.4 KiB
C++
187 lines
3.4 KiB
C++
// 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();
|
|
};
|
|
|
|
struct B final : A {
|
|
virtual void f();
|
|
};
|
|
|
|
// CHECK-LABEL: define void @_ZN5Test41fEPNS_1BE
|
|
void f(B* d) {
|
|
// CHECK: call void @_ZN5Test41B1fEv
|
|
static_cast<A*>(d)->f();
|
|
}
|
|
}
|
|
|
|
namespace Test5 {
|
|
struct A {
|
|
virtual void f();
|
|
};
|
|
|
|
struct B : A {
|
|
virtual void f();
|
|
};
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
};
|
|
struct RC final : public RA {
|
|
virtual C *f() {
|
|
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: getelementptr
|
|
// CHECK-NEXT: %[[FUNC:.*]] = load
|
|
// CHECK-NEXT: bitcast
|
|
// CHECK-NEXT: = call {{.*}} %[[FUNC]]
|
|
return static_cast<RA*>(x)->f();
|
|
}
|
|
}
|