diff options
Diffstat (limited to 'clang/lib/AST')
-rw-r--r-- | clang/lib/AST/CXXInheritance.cpp | 2 | ||||
-rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 32 |
2 files changed, 30 insertions, 4 deletions
diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp index a3a3794b2ed..0377bd324cb 100644 --- a/clang/lib/AST/CXXInheritance.cpp +++ b/clang/lib/AST/CXXInheritance.cpp @@ -758,6 +758,8 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const { return false; }; + // FIXME: IsHidden reads from Overriding from the middle of a remove_if + // over the same sequence! Is this guaranteed to work? Overriding.erase( std::remove_if(Overriding.begin(), Overriding.end(), IsHidden), Overriding.end()); diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 48e310e858b..227fe80ccab 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -2038,17 +2038,36 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, if (auto *MD = getCorrespondingMethodDeclaredInClass(RD, MayBeBase)) return MD; + llvm::SmallVector<CXXMethodDecl*, 4> FinalOverriders; + auto AddFinalOverrider = [&](CXXMethodDecl *D) { + // If this function is overridden by a candidate final overrider, it is not + // a final overrider. + for (CXXMethodDecl *OtherD : FinalOverriders) { + if (declaresSameEntity(D, OtherD) || recursivelyOverrides(OtherD, D)) + return; + } + + // Other candidate final overriders might be overridden by this function. + FinalOverriders.erase( + std::remove_if(FinalOverriders.begin(), FinalOverriders.end(), + [&](CXXMethodDecl *OtherD) { + return recursivelyOverrides(D, OtherD); + }), + FinalOverriders.end()); + + FinalOverriders.push_back(D); + }; + for (const auto &I : RD->bases()) { const RecordType *RT = I.getType()->getAs<RecordType>(); if (!RT) continue; const auto *Base = cast<CXXRecordDecl>(RT->getDecl()); - CXXMethodDecl *T = this->getCorrespondingMethodInClass(Base); - if (T) - return T; + if (CXXMethodDecl *D = this->getCorrespondingMethodInClass(Base)) + AddFinalOverrider(D); } - return nullptr; + return FinalOverriders.size() == 1 ? FinalOverriders.front() : nullptr; } CXXMethodDecl *CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, @@ -2105,6 +2124,11 @@ CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base, CXXMethodDecl *DevirtualizedMethod = getCorrespondingMethodInClass(BestDynamicDecl); + // If there final overrider in the dynamic type is ambiguous, we can't + // devirtualize this call. + if (!DevirtualizedMethod) + return nullptr; + // If that method is pure virtual, we can't devirtualize. If this code is // reached, the result would be UB, not a direct call to the derived class // function, and we can't assume the derived class function is defined. |