2012-10-24 20:22:56 +08:00
|
|
|
// RUN: %clang_cc1 -triple i386-unknown-unknown -std=c++11 %s -emit-llvm -o - | FileCheck %s
|
2010-10-27 21:28:46 +08:00
|
|
|
|
|
|
|
namespace Test1 {
|
|
|
|
struct A {
|
2011-01-24 05:07:30 +08:00
|
|
|
virtual int f() final;
|
2010-10-27 21:28:46 +08:00
|
|
|
};
|
|
|
|
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define i32 @_ZN5Test11fEPNS_1AE
|
2010-10-27 21:34:43 +08:00
|
|
|
int f(A *a) {
|
2011-01-24 05:07:30 +08:00
|
|
|
// CHECK: call i32 @_ZN5Test11A1fEv
|
2010-10-27 21:34:43 +08:00
|
|
|
return a->f();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace Test2 {
|
2011-01-24 05:07:30 +08:00
|
|
|
struct A final {
|
|
|
|
virtual int f();
|
2010-10-27 21:34:43 +08:00
|
|
|
};
|
|
|
|
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define i32 @_ZN5Test21fEPNS_1AE
|
2010-10-27 21:34:43 +08:00
|
|
|
int f(A *a) {
|
2011-01-24 05:07:30 +08:00
|
|
|
// CHECK: call i32 @_ZN5Test21A1fEv
|
2010-10-27 21:28:46 +08:00
|
|
|
return a->f();
|
|
|
|
}
|
|
|
|
}
|
2011-01-29 11:52:01 +08:00
|
|
|
|
2019-09-01 02:52:44 +08:00
|
|
|
namespace Test2a {
|
2011-01-29 11:52:01 +08:00
|
|
|
struct A {
|
2019-09-01 02:52:44 +08:00
|
|
|
virtual ~A() final {}
|
2011-01-29 11:52:01 +08:00
|
|
|
virtual int f();
|
|
|
|
};
|
|
|
|
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define i32 @_ZN6Test2a1fEPNS_1AE
|
2019-09-01 02:52:44 +08:00
|
|
|
int f(A *a) {
|
|
|
|
// CHECK: call i32 @_ZN6Test2a1A1fEv
|
|
|
|
return a->f();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace Test3 {
|
|
|
|
struct A {
|
|
|
|
virtual int f(); };
|
|
|
|
|
2011-01-29 11:52:01 +08:00
|
|
|
struct B final : A { };
|
|
|
|
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define i32 @_ZN5Test31fEPNS_1BE
|
2011-01-29 11:52:01 +08:00
|
|
|
int f(B *b) {
|
|
|
|
// CHECK: call i32 @_ZN5Test31A1fEv
|
|
|
|
return b->f();
|
|
|
|
}
|
2011-01-29 13:04:11 +08:00
|
|
|
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define i32 @_ZN5Test31fERNS_1BE
|
2011-01-29 13:04:11 +08:00
|
|
|
int f(B &b) {
|
|
|
|
// CHECK: call i32 @_ZN5Test31A1fEv
|
|
|
|
return b.f();
|
|
|
|
}
|
|
|
|
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define i32 @_ZN5Test31fEPv
|
2011-01-29 13:04:11 +08:00
|
|
|
int f(void *v) {
|
|
|
|
// CHECK: call i32 @_ZN5Test31A1fEv
|
|
|
|
return static_cast<B*>(v)->f();
|
|
|
|
}
|
2011-01-29 11:52:01 +08:00
|
|
|
}
|
2012-06-27 01:45:31 +08:00
|
|
|
|
|
|
|
namespace Test4 {
|
|
|
|
struct A {
|
|
|
|
virtual void f();
|
Fix incorrect codegen for devirtualized calls to virtual overloaded operators.
Consider this program:
struct A {
virtual void operator-() { printf("base\n"); }
};
struct B final : public A {
virtual void operator-() override { printf("derived\n"); }
};
int main() {
B* b = new B;
-static_cast<A&>(*b);
}
Before this patch, clang saw the virtual call to A::operator-(), figured out
that it can be devirtualized, and then just called A::operator-() directly,
without going through the vtable. Instead, it should've looked up which
operator-() the call devirtualizes to and should've called that.
For regular virtual member calls, clang gets all this right already. So
instead of giving EmitCXXOperatorMemberCallee() all the logic that
EmitCXXMemberCallExpr() already has, cut the latter function into two pieces,
call the second piece EmitCXXMemberOrOperatorMemberCallExpr(), and use it also
to generate code for calls to virtual member operators.
This way, virtual overloaded operators automatically don't get devirtualized
if they have covariant returns (like it was done for regular calls in r218602),
etc.
This also happens to fix (or at least improve) codegen for explicit constructor
calls (`A a; a.A::A()`) in MS mode with -fsanitize-address-field-padding=1.
(This adjustment for virtual operator calls seems still wrong with the MS ABI.)
llvm-svn: 223185
2014-12-03 09:21:41 +08:00
|
|
|
virtual int operator-();
|
2012-06-27 01:45:31 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct B final : A {
|
|
|
|
virtual void f();
|
Fix incorrect codegen for devirtualized calls to virtual overloaded operators.
Consider this program:
struct A {
virtual void operator-() { printf("base\n"); }
};
struct B final : public A {
virtual void operator-() override { printf("derived\n"); }
};
int main() {
B* b = new B;
-static_cast<A&>(*b);
}
Before this patch, clang saw the virtual call to A::operator-(), figured out
that it can be devirtualized, and then just called A::operator-() directly,
without going through the vtable. Instead, it should've looked up which
operator-() the call devirtualizes to and should've called that.
For regular virtual member calls, clang gets all this right already. So
instead of giving EmitCXXOperatorMemberCallee() all the logic that
EmitCXXMemberCallExpr() already has, cut the latter function into two pieces,
call the second piece EmitCXXMemberOrOperatorMemberCallExpr(), and use it also
to generate code for calls to virtual member operators.
This way, virtual overloaded operators automatically don't get devirtualized
if they have covariant returns (like it was done for regular calls in r218602),
etc.
This also happens to fix (or at least improve) codegen for explicit constructor
calls (`A a; a.A::A()`) in MS mode with -fsanitize-address-field-padding=1.
(This adjustment for virtual operator calls seems still wrong with the MS ABI.)
llvm-svn: 223185
2014-12-03 09:21:41 +08:00
|
|
|
virtual int operator-();
|
2012-06-27 01:45:31 +08:00
|
|
|
};
|
|
|
|
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define void @_ZN5Test41fEPNS_1BE
|
2012-06-27 01:45:31 +08:00
|
|
|
void f(B* d) {
|
|
|
|
// CHECK: call void @_ZN5Test41B1fEv
|
|
|
|
static_cast<A*>(d)->f();
|
Fix incorrect codegen for devirtualized calls to virtual overloaded operators.
Consider this program:
struct A {
virtual void operator-() { printf("base\n"); }
};
struct B final : public A {
virtual void operator-() override { printf("derived\n"); }
};
int main() {
B* b = new B;
-static_cast<A&>(*b);
}
Before this patch, clang saw the virtual call to A::operator-(), figured out
that it can be devirtualized, and then just called A::operator-() directly,
without going through the vtable. Instead, it should've looked up which
operator-() the call devirtualizes to and should've called that.
For regular virtual member calls, clang gets all this right already. So
instead of giving EmitCXXOperatorMemberCallee() all the logic that
EmitCXXMemberCallExpr() already has, cut the latter function into two pieces,
call the second piece EmitCXXMemberOrOperatorMemberCallExpr(), and use it also
to generate code for calls to virtual member operators.
This way, virtual overloaded operators automatically don't get devirtualized
if they have covariant returns (like it was done for regular calls in r218602),
etc.
This also happens to fix (or at least improve) codegen for explicit constructor
calls (`A a; a.A::A()`) in MS mode with -fsanitize-address-field-padding=1.
(This adjustment for virtual operator calls seems still wrong with the MS ABI.)
llvm-svn: 223185
2014-12-03 09:21:41 +08:00
|
|
|
// CHECK: call i32 @_ZN5Test41BngEv
|
|
|
|
-static_cast<A&>(*d);
|
2012-06-27 01:45:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace Test5 {
|
|
|
|
struct A {
|
|
|
|
virtual void f();
|
Fix incorrect codegen for devirtualized calls to virtual overloaded operators.
Consider this program:
struct A {
virtual void operator-() { printf("base\n"); }
};
struct B final : public A {
virtual void operator-() override { printf("derived\n"); }
};
int main() {
B* b = new B;
-static_cast<A&>(*b);
}
Before this patch, clang saw the virtual call to A::operator-(), figured out
that it can be devirtualized, and then just called A::operator-() directly,
without going through the vtable. Instead, it should've looked up which
operator-() the call devirtualizes to and should've called that.
For regular virtual member calls, clang gets all this right already. So
instead of giving EmitCXXOperatorMemberCallee() all the logic that
EmitCXXMemberCallExpr() already has, cut the latter function into two pieces,
call the second piece EmitCXXMemberOrOperatorMemberCallExpr(), and use it also
to generate code for calls to virtual member operators.
This way, virtual overloaded operators automatically don't get devirtualized
if they have covariant returns (like it was done for regular calls in r218602),
etc.
This also happens to fix (or at least improve) codegen for explicit constructor
calls (`A a; a.A::A()`) in MS mode with -fsanitize-address-field-padding=1.
(This adjustment for virtual operator calls seems still wrong with the MS ABI.)
llvm-svn: 223185
2014-12-03 09:21:41 +08:00
|
|
|
virtual int operator-();
|
2012-06-27 01:45:31 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct B : A {
|
|
|
|
virtual void f();
|
Fix incorrect codegen for devirtualized calls to virtual overloaded operators.
Consider this program:
struct A {
virtual void operator-() { printf("base\n"); }
};
struct B final : public A {
virtual void operator-() override { printf("derived\n"); }
};
int main() {
B* b = new B;
-static_cast<A&>(*b);
}
Before this patch, clang saw the virtual call to A::operator-(), figured out
that it can be devirtualized, and then just called A::operator-() directly,
without going through the vtable. Instead, it should've looked up which
operator-() the call devirtualizes to and should've called that.
For regular virtual member calls, clang gets all this right already. So
instead of giving EmitCXXOperatorMemberCallee() all the logic that
EmitCXXMemberCallExpr() already has, cut the latter function into two pieces,
call the second piece EmitCXXMemberOrOperatorMemberCallExpr(), and use it also
to generate code for calls to virtual member operators.
This way, virtual overloaded operators automatically don't get devirtualized
if they have covariant returns (like it was done for regular calls in r218602),
etc.
This also happens to fix (or at least improve) codegen for explicit constructor
calls (`A a; a.A::A()`) in MS mode with -fsanitize-address-field-padding=1.
(This adjustment for virtual operator calls seems still wrong with the MS ABI.)
llvm-svn: 223185
2014-12-03 09:21:41 +08:00
|
|
|
virtual int operator-();
|
2012-06-27 01:45:31 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct C final : B {
|
|
|
|
};
|
|
|
|
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define void @_ZN5Test51fEPNS_1CE
|
2012-06-27 01:45:31 +08:00
|
|
|
void f(C* d) {
|
2012-06-28 22:28:57 +08:00
|
|
|
// 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]]
|
2012-06-27 01:45:31 +08:00
|
|
|
static_cast<A*>(d)->f();
|
|
|
|
}
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define void @_ZN5Test53fopEPNS_1CE
|
Fix incorrect codegen for devirtualized calls to virtual overloaded operators.
Consider this program:
struct A {
virtual void operator-() { printf("base\n"); }
};
struct B final : public A {
virtual void operator-() override { printf("derived\n"); }
};
int main() {
B* b = new B;
-static_cast<A&>(*b);
}
Before this patch, clang saw the virtual call to A::operator-(), figured out
that it can be devirtualized, and then just called A::operator-() directly,
without going through the vtable. Instead, it should've looked up which
operator-() the call devirtualizes to and should've called that.
For regular virtual member calls, clang gets all this right already. So
instead of giving EmitCXXOperatorMemberCallee() all the logic that
EmitCXXMemberCallExpr() already has, cut the latter function into two pieces,
call the second piece EmitCXXMemberOrOperatorMemberCallExpr(), and use it also
to generate code for calls to virtual member operators.
This way, virtual overloaded operators automatically don't get devirtualized
if they have covariant returns (like it was done for regular calls in r218602),
etc.
This also happens to fix (or at least improve) codegen for explicit constructor
calls (`A a; a.A::A()`) in MS mode with -fsanitize-address-field-padding=1.
(This adjustment for virtual operator calls seems still wrong with the MS ABI.)
llvm-svn: 223185
2014-12-03 09:21:41 +08:00
|
|
|
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);
|
|
|
|
}
|
2012-06-27 01:45:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace Test6 {
|
|
|
|
struct A {
|
|
|
|
virtual ~A();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct B : public A {
|
|
|
|
virtual ~B();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct C {
|
|
|
|
virtual ~C();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct D final : public C, public B {
|
|
|
|
};
|
|
|
|
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define void @_ZN5Test61fEPNS_1DE
|
2012-06-27 01:45:31 +08:00
|
|
|
void f(D* d) {
|
|
|
|
// CHECK: call void @_ZN5Test61DD1Ev
|
|
|
|
static_cast<A*>(d)->~A();
|
|
|
|
}
|
|
|
|
}
|
2012-06-28 09:56:38 +08:00
|
|
|
|
|
|
|
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;}
|
|
|
|
};
|
|
|
|
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define i32 @_ZN5Test71fEPNS_3zedE
|
2012-06-28 09:56:38 +08:00
|
|
|
int f(zed *z) {
|
|
|
|
// CHECK: alloca
|
|
|
|
// CHECK-NEXT: store
|
|
|
|
// CHECK-NEXT: load
|
2012-10-25 08:12:49 +08:00
|
|
|
// CHECK-NEXT: call i32 @_ZN5Test73zed1fEv
|
2012-06-28 09:56:38 +08:00
|
|
|
// CHECK-NEXT: ret
|
|
|
|
return static_cast<bar*>(z)->f();
|
|
|
|
}
|
|
|
|
}
|
2012-06-28 22:28:57 +08:00
|
|
|
|
|
|
|
namespace Test8 {
|
|
|
|
struct A { virtual ~A() {} };
|
|
|
|
struct B {
|
|
|
|
int b;
|
|
|
|
virtual int foo() { return b; }
|
|
|
|
};
|
|
|
|
struct C final : A, B { };
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define i32 @_ZN5Test84testEPNS_1CE
|
2012-06-28 22:28:57 +08:00
|
|
|
int test(C *c) {
|
|
|
|
// CHECK: %[[THIS:.*]] = phi
|
|
|
|
// CHECK-NEXT: call i32 @_ZN5Test81B3fooEv(%"struct.Test8::B"* %[[THIS]])
|
|
|
|
return static_cast<B*>(c)->foo();
|
|
|
|
}
|
|
|
|
}
|
2012-06-28 23:11:39 +08:00
|
|
|
|
|
|
|
namespace Test9 {
|
|
|
|
struct A {
|
|
|
|
int a;
|
|
|
|
};
|
|
|
|
struct B {
|
|
|
|
int b;
|
|
|
|
};
|
|
|
|
struct C : public B, public A {
|
|
|
|
};
|
|
|
|
struct RA {
|
|
|
|
virtual A *f() {
|
|
|
|
return 0;
|
|
|
|
}
|
Fix incorrect codegen for devirtualized calls to virtual overloaded operators.
Consider this program:
struct A {
virtual void operator-() { printf("base\n"); }
};
struct B final : public A {
virtual void operator-() override { printf("derived\n"); }
};
int main() {
B* b = new B;
-static_cast<A&>(*b);
}
Before this patch, clang saw the virtual call to A::operator-(), figured out
that it can be devirtualized, and then just called A::operator-() directly,
without going through the vtable. Instead, it should've looked up which
operator-() the call devirtualizes to and should've called that.
For regular virtual member calls, clang gets all this right already. So
instead of giving EmitCXXOperatorMemberCallee() all the logic that
EmitCXXMemberCallExpr() already has, cut the latter function into two pieces,
call the second piece EmitCXXMemberOrOperatorMemberCallExpr(), and use it also
to generate code for calls to virtual member operators.
This way, virtual overloaded operators automatically don't get devirtualized
if they have covariant returns (like it was done for regular calls in r218602),
etc.
This also happens to fix (or at least improve) codegen for explicit constructor
calls (`A a; a.A::A()`) in MS mode with -fsanitize-address-field-padding=1.
(This adjustment for virtual operator calls seems still wrong with the MS ABI.)
llvm-svn: 223185
2014-12-03 09:21:41 +08:00
|
|
|
virtual A *operator-() {
|
|
|
|
return 0;
|
|
|
|
}
|
2012-06-28 23:11:39 +08:00
|
|
|
};
|
|
|
|
struct RC final : public RA {
|
|
|
|
virtual C *f() {
|
|
|
|
C *x = new C();
|
|
|
|
x->a = 1;
|
|
|
|
x->b = 2;
|
|
|
|
return x;
|
|
|
|
}
|
Fix incorrect codegen for devirtualized calls to virtual overloaded operators.
Consider this program:
struct A {
virtual void operator-() { printf("base\n"); }
};
struct B final : public A {
virtual void operator-() override { printf("derived\n"); }
};
int main() {
B* b = new B;
-static_cast<A&>(*b);
}
Before this patch, clang saw the virtual call to A::operator-(), figured out
that it can be devirtualized, and then just called A::operator-() directly,
without going through the vtable. Instead, it should've looked up which
operator-() the call devirtualizes to and should've called that.
For regular virtual member calls, clang gets all this right already. So
instead of giving EmitCXXOperatorMemberCallee() all the logic that
EmitCXXMemberCallExpr() already has, cut the latter function into two pieces,
call the second piece EmitCXXMemberOrOperatorMemberCallExpr(), and use it also
to generate code for calls to virtual member operators.
This way, virtual overloaded operators automatically don't get devirtualized
if they have covariant returns (like it was done for regular calls in r218602),
etc.
This also happens to fix (or at least improve) codegen for explicit constructor
calls (`A a; a.A::A()`) in MS mode with -fsanitize-address-field-padding=1.
(This adjustment for virtual operator calls seems still wrong with the MS ABI.)
llvm-svn: 223185
2014-12-03 09:21:41 +08:00
|
|
|
virtual C *operator-() {
|
|
|
|
C *x = new C();
|
|
|
|
x->a = 1;
|
|
|
|
x->b = 2;
|
|
|
|
return x;
|
|
|
|
}
|
2012-06-28 23:11:39 +08:00
|
|
|
};
|
|
|
|
// CHECK: define {{.*}} @_ZN5Test91fEPNS_2RCE
|
|
|
|
A *f(RC *x) {
|
|
|
|
// FIXME: It should be possible to devirtualize this case, but that is
|
|
|
|
// not implemented yet.
|
2014-09-29 18:32:21 +08:00
|
|
|
// 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]]
|
2012-06-28 23:11:39 +08:00
|
|
|
// CHECK-NEXT: = call {{.*}} %[[FUNC]]
|
|
|
|
return static_cast<RA*>(x)->f();
|
|
|
|
}
|
Fix incorrect codegen for devirtualized calls to virtual overloaded operators.
Consider this program:
struct A {
virtual void operator-() { printf("base\n"); }
};
struct B final : public A {
virtual void operator-() override { printf("derived\n"); }
};
int main() {
B* b = new B;
-static_cast<A&>(*b);
}
Before this patch, clang saw the virtual call to A::operator-(), figured out
that it can be devirtualized, and then just called A::operator-() directly,
without going through the vtable. Instead, it should've looked up which
operator-() the call devirtualizes to and should've called that.
For regular virtual member calls, clang gets all this right already. So
instead of giving EmitCXXOperatorMemberCallee() all the logic that
EmitCXXMemberCallExpr() already has, cut the latter function into two pieces,
call the second piece EmitCXXMemberOrOperatorMemberCallExpr(), and use it also
to generate code for calls to virtual member operators.
This way, virtual overloaded operators automatically don't get devirtualized
if they have covariant returns (like it was done for regular calls in r218602),
etc.
This also happens to fix (or at least improve) codegen for explicit constructor
calls (`A a; a.A::A()`) in MS mode with -fsanitize-address-field-padding=1.
(This adjustment for virtual operator calls seems still wrong with the MS ABI.)
llvm-svn: 223185
2014-12-03 09:21:41 +08:00
|
|
|
// 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);
|
|
|
|
}
|
2012-06-28 23:11:39 +08:00
|
|
|
}
|
2016-10-21 02:44:14 +08:00
|
|
|
|
|
|
|
namespace Test10 {
|
|
|
|
struct A {
|
|
|
|
virtual int f();
|
|
|
|
};
|
|
|
|
|
|
|
|
struct B : A {
|
|
|
|
int f() final;
|
|
|
|
};
|
|
|
|
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define i32 @_ZN6Test101fEPNS_1BE
|
2016-10-21 02:44:14 +08:00
|
|
|
int f(B *b) {
|
|
|
|
// CHECK: call i32 @_ZN6Test101B1fEv
|
|
|
|
return static_cast<A *>(b)->f();
|
|
|
|
}
|
|
|
|
}
|
2017-07-13 14:08:27 +08:00
|
|
|
|
2020-02-01 09:05:27 +08:00
|
|
|
namespace TestVBase {
|
|
|
|
struct A { virtual void f(); };
|
|
|
|
struct B : virtual A {};
|
|
|
|
struct C : virtual A { void f() override; };
|
|
|
|
|
|
|
|
extern struct BC final : B, C {} &bc;
|
|
|
|
extern struct BCusingA final : B, C { using A::f; } &bc_using_a;
|
|
|
|
extern struct BCusingB final : B, C { using B::f; } &bc_using_b;
|
|
|
|
extern struct BCusingC final : B, C { using C::f; } &bc_using_c;
|
|
|
|
|
|
|
|
extern struct CB final : C, B {} &cb;
|
|
|
|
extern struct CBusingA final : C, B { using A::f; } &cb_using_a;
|
|
|
|
extern struct CBusingB final : C, B { using B::f; } &cb_using_b;
|
|
|
|
extern struct CBusingC final : C, B { using C::f; } &cb_using_c;
|
|
|
|
|
|
|
|
// CHECK-LABEL: @_ZN9TestVBase4testEv(
|
|
|
|
void test() {
|
|
|
|
// FIXME: The 'using A' case can be devirtualized to call A's virtual
|
|
|
|
// adjustment thunk for C::f.
|
|
|
|
// FIXME: The 'using B' case can be devirtualized, but requires us to emit
|
|
|
|
// a derived-to-base or base-to-derived conversion as part of
|
|
|
|
// devirtualization.
|
|
|
|
|
|
|
|
// CHECK: call void @_ZN9TestVBase1C1fEv(
|
|
|
|
bc.f();
|
|
|
|
// CHECK: call void %
|
|
|
|
bc_using_a.f();
|
|
|
|
// CHECK: call void %
|
|
|
|
bc_using_b.f();
|
|
|
|
// CHECK: call void @_ZN9TestVBase1C1fEv(
|
|
|
|
bc_using_c.f();
|
|
|
|
|
|
|
|
// CHECK: call void @_ZN9TestVBase1C1fEv(
|
|
|
|
cb.f();
|
|
|
|
// CHECK: call void %
|
|
|
|
cb_using_a.f();
|
|
|
|
// CHECK: call void %
|
|
|
|
cb_using_b.f();
|
|
|
|
// CHECK: call void @_ZN9TestVBase1C1fEv(
|
|
|
|
cb_using_c.f();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-13 14:08:27 +08:00
|
|
|
namespace Test11 {
|
|
|
|
// Check that the definitions of Derived's operators are emitted.
|
|
|
|
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK-LABEL: define linkonce_odr void @_ZN6Test111SIiE4foo1Ev(
|
2017-07-13 14:08:27 +08:00
|
|
|
// CHECK: call void @_ZN6Test111SIiE7DerivedclEv(
|
|
|
|
// CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE(
|
|
|
|
// CHECK: call zeroext i1 @_ZN6Test111SIiE7DerivedntEv(
|
2020-05-19 02:29:11 +08:00
|
|
|
// CHECK: call nonnull align 4 dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi(
|
2020-02-04 02:09:39 +08:00
|
|
|
// CHECK: define linkonce_odr void @_ZN6Test111SIiE7DerivedclEv(
|
|
|
|
// CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedeqERKNS_4BaseE(
|
|
|
|
// CHECK: define linkonce_odr zeroext i1 @_ZN6Test111SIiE7DerivedntEv(
|
2020-05-19 02:29:11 +08:00
|
|
|
// CHECK: define linkonce_odr nonnull align 4 dereferenceable(4) %"class.Test11::Base"* @_ZN6Test111SIiE7DerivedixEi(
|
2017-07-13 14:08:27 +08:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|