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:
Rafael Espindola 2012-06-28 01:56:38 +00:00
Родитель d558b5238d
Коммит 632fbaa22f
4 изменённых файлов: 71 добавлений и 25 удалений

Просмотреть файл

@ -634,6 +634,13 @@ public:
/// ParenExpr or CastExprs, returning their operand.
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.
///
/// Default arguments are implicitly generated in the abstract syntax tree

Просмотреть файл

@ -34,21 +34,7 @@
using namespace clang;
const CXXRecordDecl *Expr::getBestDynamicClassType() const {
const Expr *E = this;
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;
}
const Expr *E = ignoreParenBaseCasts();
QualType DerivedType = E->getType();
if (const PointerType *PTy = DerivedType->getAs<PointerType>())
@ -2231,7 +2217,27 @@ Expr *Expr::IgnoreParenLValueCasts() {
}
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 *E = this;
while (true) {

Просмотреть файл

@ -172,11 +172,21 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
}
// 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;
if (ME->isArrow())
This = EmitScalarExpr(ME->getBase());
This = EmitScalarExpr(Inner);
else
This = EmitLValue(ME->getBase()).getAddress();
This = EmitLValue(Inner).getAddress();
if (MD->isTrivial()) {
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
// because then we know what the type is.
const Expr *Base = ME->getBase();
bool UseVirtualCall = MD->isVirtual() && !ME->hasQualifier()
&& !canDevirtualizeMemberFunctionCalls(getContext(),
Base, MD);
const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType();
bool UseVirtualCall = CanUseVirtualCall && !Devirtualize;
const CXXRecordDecl *MostDerivedClassDecl = Inner->getBestDynamicClassType();
llvm::Value *Callee;
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
@ -238,7 +245,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
MD->isVirtual() &&
ME->hasQualifier())
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
else if (ME->hasQualifier())
else if (!Devirtualize)
Callee = CGM.GetAddrOfFunction(GlobalDecl(Dtor, Dtor_Complete), Ty);
else {
const CXXMethodDecl *DM =
@ -258,7 +265,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
MD->isVirtual() &&
ME->hasQualifier())
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
else if (ME->hasQualifier())
else if (!Devirtualize)
Callee = CGM.GetAddrOfFunction(MD, Ty);
else {
const CXXMethodDecl *DerivedMethod =

Просмотреть файл

@ -107,3 +107,29 @@ namespace Test6 {
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();
}
}