diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/DeclCXX.cpp | 49 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 31 | ||||
-rw-r--r-- | lib/CodeGen/CGExprCXX.cpp | 55 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 16 |
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. |