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. /// 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();
}
}