aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/AST/DeclCXX.cpp49
-rw-r--r--lib/AST/Expr.cpp31
-rw-r--r--lib/CodeGen/CGExprCXX.cpp55
-rw-r--r--lib/Sema/SemaExpr.cpp16
4 files changed, 118 insertions, 33 deletions
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 3d76e68ff7..a8aabb68d7 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -1269,6 +1269,55 @@ bool CXXRecordDecl::mayBeAbstract() const {
void CXXMethodDecl::anchor() { }
+static bool recursivelyOverrides(const CXXMethodDecl *DerivedMD,
+ const CXXMethodDecl *BaseMD) {
+ for (CXXMethodDecl::method_iterator I = DerivedMD->begin_overridden_methods(),
+ E = DerivedMD->end_overridden_methods(); I != E; ++I) {
+ const CXXMethodDecl *MD = *I;
+ if (MD->getCanonicalDecl() == BaseMD->getCanonicalDecl())
+ return true;
+ if (recursivelyOverrides(MD, BaseMD))
+ return true;
+ }
+ return false;
+}
+
+CXXMethodDecl *
+CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD) {
+ if (this->getParent()->getCanonicalDecl() == RD->getCanonicalDecl())
+ return this;
+
+ // Lookup doesn't work for destructors, so handle them separately.
+ if (isa<CXXDestructorDecl>(this)) {
+ CXXMethodDecl *MD = RD->getDestructor();
+ if (recursivelyOverrides(MD, this))
+ return MD;
+ return NULL;
+ }
+
+ lookup_const_result Candidates = RD->lookup(getDeclName());
+ for (NamedDecl * const * I = Candidates.first; I != Candidates.second; ++I) {
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*I);
+ if (!MD)
+ continue;
+ if (recursivelyOverrides(MD, this))
+ return MD;
+ }
+
+ for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+ E = RD->bases_end(); I != E; ++I) {
+ const RecordType *RT = I->getType()->getAs<RecordType>();
+ if (!RT)
+ continue;
+ const CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl());
+ CXXMethodDecl *T = this->getCorrespondingMethodInClass(Base);
+ if (T)
+ return T;
+ }
+
+ return NULL;
+}
+
CXXMethodDecl *
CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 3de4b5771a..22d15be6a8 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -33,6 +33,37 @@
#include <cstring>
using namespace clang;
+const CXXRecordDecl *Expr::getMostDerivedClassDeclForType() 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;
+ }
+
+ QualType DerivedType = E->getType();
+ if (DerivedType->isDependentType())
+ return NULL;
+ if (const PointerType *PTy = DerivedType->getAs<PointerType>())
+ DerivedType = PTy->getPointeeType();
+
+ const RecordType *Ty = DerivedType->castAs<RecordType>();
+ if (!Ty)
+ return NULL;
+
+ Decl *D = Ty->getDecl();
+ return cast<CXXRecordDecl>(D);
+}
+
/// isKnownToHaveBooleanValue - Return true if this is an integer expression
/// that is known to return 0 or 1. This happens for _Bool/bool expressions
/// but also int expressions which are produced by things like comparisons in
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index f1d0395714..f35287d540 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -56,30 +56,6 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
Callee, ReturnValue, Args, MD);
}
-static const CXXRecordDecl *getMostDerivedClassDecl(const Expr *Base) {
- const Expr *E = Base;
-
- 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();
- if (const PointerType *PTy = DerivedType->getAs<PointerType>())
- DerivedType = PTy->getPointeeType();
-
- return cast<CXXRecordDecl>(DerivedType->castAs<RecordType>()->getDecl());
-}
-
// FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do
// quite what we want.
static const Expr *skipNoOpCastsAndParens(const Expr *E) {
@@ -126,7 +102,8 @@ static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context,
// b->f();
// }
//
- const CXXRecordDecl *MostDerivedClassDecl = getMostDerivedClassDecl(Base);
+ const CXXRecordDecl *MostDerivedClassDecl =
+ Base->getMostDerivedClassDeclForType();
if (MostDerivedClassDecl->hasAttr<FinalAttr>())
return true;
@@ -247,10 +224,13 @@ 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.
- bool UseVirtualCall;
- UseVirtualCall = MD->isVirtual() && !ME->hasQualifier()
- && !canDevirtualizeMemberFunctionCalls(getContext(),
- ME->getBase(), MD);
+ const Expr *Base = ME->getBase();
+ bool UseVirtualCall = MD->isVirtual() && !ME->hasQualifier()
+ && !canDevirtualizeMemberFunctionCalls(getContext(),
+ Base, MD);
+ const CXXRecordDecl *MostDerivedClassDecl =
+ Base->getMostDerivedClassDeclForType();
+
llvm::Value *Callee;
if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
if (UseVirtualCall) {
@@ -260,8 +240,13 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
MD->isVirtual() &&
ME->hasQualifier())
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
- else
- Callee = CGM.GetAddrOfFunction(GlobalDecl(Dtor, Dtor_Complete), Ty);
+ else {
+ const CXXMethodDecl *DM =
+ Dtor->getCorrespondingMethodInClass(MostDerivedClassDecl);
+ assert(DM);
+ const CXXDestructorDecl *DDtor = cast<CXXDestructorDecl>(DM);
+ Callee = CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty);
+ }
}
} else if (const CXXConstructorDecl *Ctor =
dyn_cast<CXXConstructorDecl>(MD)) {
@@ -273,8 +258,12 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
MD->isVirtual() &&
ME->hasQualifier())
Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
- else
- Callee = CGM.GetAddrOfFunction(MD, Ty);
+ else {
+ const CXXMethodDecl *DerivedMethod =
+ MD->getCorrespondingMethodInClass(MostDerivedClassDecl);
+ assert(DerivedMethod);
+ Callee = CGM.GetAddrOfFunction(DerivedMethod, Ty);
+ }
}
return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0,
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 07f3c1d6c7..4dd6f0b552 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -10844,6 +10844,22 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
}
SemaRef.MarkAnyDeclReferenced(Loc, D);
+
+ // If this is a call to a method via a cast, also mark the method in the
+ // derived class used in case codegen can devirtualize the call.
+ const MemberExpr *ME = dyn_cast<MemberExpr>(E);
+ if (!ME)
+ return;
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ME->getMemberDecl());
+ if (!MD)
+ return;
+ const Expr *Base = ME->getBase();
+ const CXXRecordDecl *MostDerivedClassDecl
+ = Base->getMostDerivedClassDeclForType();
+ if (!MostDerivedClassDecl)
+ return;
+ CXXMethodDecl *DM = MD->getCorrespondingMethodInClass(MostDerivedClassDecl);
+ SemaRef.MarkAnyDeclReferenced(Loc, DM);
}
/// \brief Perform reference-marking and odr-use handling for a DeclRefExpr.