зеркало из https://github.com/microsoft/clang-1.git
Fix another issue with devirtualizing calls to final methods by passing them
the correct this pointer. There is some potential for sharing a bit more code with canDevirtualizeMemberFunctionCalls, but that can be done in an independent patch. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@159326 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
d558b5238d
Коммит
632fbaa22f
|
@ -634,6 +634,13 @@ public:
|
||||||
/// ParenExpr or CastExprs, returning their operand.
|
/// ParenExpr or CastExprs, returning their operand.
|
||||||
Expr *IgnoreParenNoopCasts(ASTContext &Ctx) LLVM_READONLY;
|
Expr *IgnoreParenNoopCasts(ASTContext &Ctx) LLVM_READONLY;
|
||||||
|
|
||||||
|
/// Ignore parentheses and derived-to-base casts.
|
||||||
|
Expr *ignoreParenBaseCasts() LLVM_READONLY;
|
||||||
|
|
||||||
|
const Expr *ignoreParenBaseCasts() const LLVM_READONLY {
|
||||||
|
return const_cast<Expr*>(this)->ignoreParenBaseCasts();
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Determine whether this expression is a default function argument.
|
/// \brief Determine whether this expression is a default function argument.
|
||||||
///
|
///
|
||||||
/// Default arguments are implicitly generated in the abstract syntax tree
|
/// Default arguments are implicitly generated in the abstract syntax tree
|
||||||
|
|
|
@ -34,21 +34,7 @@
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
const CXXRecordDecl *Expr::getBestDynamicClassType() const {
|
const CXXRecordDecl *Expr::getBestDynamicClassType() const {
|
||||||
const Expr *E = this;
|
const Expr *E = ignoreParenBaseCasts();
|
||||||
|
|
||||||
while (true) {
|
|
||||||
E = E->IgnoreParens();
|
|
||||||
if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
|
|
||||||
if (CE->getCastKind() == CK_DerivedToBase ||
|
|
||||||
CE->getCastKind() == CK_UncheckedDerivedToBase ||
|
|
||||||
CE->getCastKind() == CK_NoOp) {
|
|
||||||
E = CE->getSubExpr();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
QualType DerivedType = E->getType();
|
QualType DerivedType = E->getType();
|
||||||
if (const PointerType *PTy = DerivedType->getAs<PointerType>())
|
if (const PointerType *PTy = DerivedType->getAs<PointerType>())
|
||||||
|
@ -2231,7 +2217,27 @@ Expr *Expr::IgnoreParenLValueCasts() {
|
||||||
}
|
}
|
||||||
return E;
|
return E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expr *Expr::ignoreParenBaseCasts() {
|
||||||
|
Expr *E = this;
|
||||||
|
while (true) {
|
||||||
|
if (ParenExpr *P = dyn_cast<ParenExpr>(E)) {
|
||||||
|
E = P->getSubExpr();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (CastExpr *CE = dyn_cast<CastExpr>(E)) {
|
||||||
|
if (CE->getCastKind() == CK_DerivedToBase ||
|
||||||
|
CE->getCastKind() == CK_UncheckedDerivedToBase ||
|
||||||
|
CE->getCastKind() == CK_NoOp) {
|
||||||
|
E = CE->getSubExpr();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return E;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Expr *Expr::IgnoreParenImpCasts() {
|
Expr *Expr::IgnoreParenImpCasts() {
|
||||||
Expr *E = this;
|
Expr *E = this;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
|
@ -172,11 +172,21 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the object pointer.
|
// Compute the object pointer.
|
||||||
|
const Expr *Base = ME->getBase();
|
||||||
|
bool CanUseVirtualCall = MD->isVirtual() && !ME->hasQualifier();
|
||||||
|
bool Devirtualize = CanUseVirtualCall &&
|
||||||
|
canDevirtualizeMemberFunctionCalls(getContext(), Base, MD);
|
||||||
|
|
||||||
|
const Expr *Inner = Base;
|
||||||
|
if (Devirtualize)
|
||||||
|
Inner = Base->ignoreParenBaseCasts();
|
||||||
|
|
||||||
llvm::Value *This;
|
llvm::Value *This;
|
||||||
if (ME->isArrow())
|
if (ME->isArrow())
|
||||||
This = EmitScalarExpr(ME->getBase());
|
This = EmitScalarExpr(Inner);
|
||||||
else
|
else
|
||||||
This = EmitLValue(ME->getBase()).getAddress();
|
This = EmitLValue(Inner).getAddress();
|
||||||
|
|
||||||
|
|
||||||
if (MD->isTrivial()) {
|
if (MD->isTrivial()) {
|
||||||
if (isa<CXXDestructorDecl>(MD)) return RValue::get(0);
|
if (isa<CXXDestructorDecl>(MD)) return RValue::get(0);
|
||||||
|
@ -223,11 +233,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
|
||||||
//
|
//
|
||||||
// We also don't emit a virtual call if the base expression has a record type
|
// We also don't emit a virtual call if the base expression has a record type
|
||||||
// because then we know what the type is.
|
// because then we know what the type is.
|
||||||
const Expr *Base = ME->getBase();
|
bool UseVirtualCall = CanUseVirtualCall && !Devirtualize;
|
||||||
bool UseVirtualCall = MD->isVirtual() && !ME->hasQualifier()
|
const CXXRecordDecl *MostDerivedClassDecl = Inner->getBestDynamicClassType();
|
||||||
&& !canDevirtualizeMemberFunctionCalls(getContext(),
|
|
||||||
Base, MD);
|
|
||||||
const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType();
|
|
||||||
|
|
||||||
llvm::Value *Callee;
|
llvm::Value *Callee;
|
||||||
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
|
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
|
||||||
|
@ -238,7 +245,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
|
||||||
MD->isVirtual() &&
|
MD->isVirtual() &&
|
||||||
ME->hasQualifier())
|
ME->hasQualifier())
|
||||||
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
|
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
|
||||||
else if (ME->hasQualifier())
|
else if (!Devirtualize)
|
||||||
Callee = CGM.GetAddrOfFunction(GlobalDecl(Dtor, Dtor_Complete), Ty);
|
Callee = CGM.GetAddrOfFunction(GlobalDecl(Dtor, Dtor_Complete), Ty);
|
||||||
else {
|
else {
|
||||||
const CXXMethodDecl *DM =
|
const CXXMethodDecl *DM =
|
||||||
|
@ -258,7 +265,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
|
||||||
MD->isVirtual() &&
|
MD->isVirtual() &&
|
||||||
ME->hasQualifier())
|
ME->hasQualifier())
|
||||||
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
|
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
|
||||||
else if (ME->hasQualifier())
|
else if (!Devirtualize)
|
||||||
Callee = CGM.GetAddrOfFunction(MD, Ty);
|
Callee = CGM.GetAddrOfFunction(MD, Ty);
|
||||||
else {
|
else {
|
||||||
const CXXMethodDecl *DerivedMethod =
|
const CXXMethodDecl *DerivedMethod =
|
||||||
|
|
|
@ -107,3 +107,29 @@ namespace Test6 {
|
||||||
static_cast<A*>(d)->~A();
|
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: define i32 @_ZN5Test71fEPNS_3zedE
|
||||||
|
int f(zed *z) {
|
||||||
|
// CHECK: alloca
|
||||||
|
// CHECK-NEXT: store
|
||||||
|
// CHECK-NEXT: load
|
||||||
|
// CHECK-NEXT: bitcast
|
||||||
|
// CHECK-NEXT: call {{.*}} @_ZN5Test73zed1fEv
|
||||||
|
// CHECK-NEXT: ret
|
||||||
|
return static_cast<bar*>(z)->f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче