/// to help build the set of paths.
CXXBasePath ScratchPath;
- /// Array of the declarations that have been found. This
- /// array is constructed only if needed, e.g., to iterate over the
- /// results within LookupResult.
- std::unique_ptr<NamedDecl *[]> DeclsFound;
- unsigned NumDeclsFound = 0;
-
/// FindAmbiguities - Whether Sema::IsDerivedFrom should try find
/// ambiguous paths while it is looking for a path from a derived
/// type to a base type.
/// is also recorded.
bool DetectVirtual;
- void ComputeDeclsFound();
-
bool lookupInBases(ASTContext &Context, const CXXRecordDecl *Record,
CXXRecordDecl::BaseMatchesCallback BaseMatches,
bool LookupInDependent = false);
using decl_range = llvm::iterator_range<decl_iterator>;
- decl_range found_decls();
-
/// Determine whether the path from the most-derived type to the
/// given base type is ambiguous (i.e., it refers to multiple subobjects of
/// the same base type).
using namespace clang;
-/// Computes the set of declarations referenced by these base
-/// paths.
-void CXXBasePaths::ComputeDeclsFound() {
- assert(NumDeclsFound == 0 && !DeclsFound &&
- "Already computed the set of declarations");
-
- llvm::SmallSetVector<NamedDecl *, 8> Decls;
- for (paths_iterator Path = begin(), PathEnd = end(); Path != PathEnd; ++Path)
- Decls.insert(Path->Decls.front());
-
- NumDeclsFound = Decls.size();
- DeclsFound = std::make_unique<NamedDecl *[]>(NumDeclsFound);
- std::copy(Decls.begin(), Decls.end(), DeclsFound.get());
-}
-
-CXXBasePaths::decl_range CXXBasePaths::found_decls() {
- if (NumDeclsFound == 0)
- ComputeDeclsFound();
-
- return decl_range(decl_iterator(DeclsFound.get()),
- decl_iterator(DeclsFound.get() + NumDeclsFound));
-}
-
/// isAmbiguous - Determines whether the set of paths provided is
/// ambiguous, i.e., there are two or more paths that refer to
/// different base class subobjects of the same type. BaseType must be
return false;
}
-namespace {
-struct FindOverriddenMethod {
- Sema *S;
- CXXMethodDecl *Method;
-
- /// Member lookup function that determines whether a given C++
- /// method overrides a method in a base class, to be used with
- /// CXXRecordDecl::lookupInBases().
- bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
- RecordDecl *BaseRecord =
- Specifier->getType()->castAs<RecordType>()->getDecl();
+/// AddOverriddenMethods - See if a method overrides any in the base classes,
+/// and if so, check that it's a valid override and remember it.
+bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
+ llvm::SmallPtrSet<const CXXMethodDecl*, 4> Overridden;
- DeclarationName Name = Method->getDeclName();
+ // Look for methods in base classes that this method might override.
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false,
+ /*DetectVirtual=*/false);
+ auto VisitBase = [&] (const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
+ CXXRecordDecl *BaseRecord = Specifier->getType()->getAsCXXRecordDecl();
+ DeclarationName Name = MD->getDeclName();
- // FIXME: Do we care about other names here too?
if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
// We really want to find the base class destructor here.
- QualType T = S->Context.getTypeDeclType(BaseRecord);
- CanQualType CT = S->Context.getCanonicalType(T);
-
- Name = S->Context.DeclarationNames.getCXXDestructorName(CT);
- }
-
- for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty();
- Path.Decls = Path.Decls.slice(1)) {
- NamedDecl *D = Path.Decls.front();
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
- if (MD->isVirtual() &&
- !S->IsOverload(
- Method, MD, /*UseMemberUsingDeclRules=*/false,
- /*ConsiderCudaAttrs=*/true,
- // C++2a [class.virtual]p2 does not consider requires clauses
- // when overriding.
- /*ConsiderRequiresClauses=*/false))
- return true;
+ QualType T = Context.getTypeDeclType(BaseRecord);
+ CanQualType CT = Context.getCanonicalType(T);
+ Name = Context.DeclarationNames.getCXXDestructorName(CT);
+ }
+
+ for (NamedDecl *BaseND : BaseRecord->lookup(Name)) {
+ CXXMethodDecl *BaseMD =
+ dyn_cast<CXXMethodDecl>(BaseND->getCanonicalDecl());
+ if (!BaseMD || !BaseMD->isVirtual() ||
+ IsOverload(MD, BaseMD, /*UseMemberUsingDeclRules=*/false,
+ /*ConsiderCudaAttrs=*/true,
+ // C++2a [class.virtual]p2 does not consider requires
+ // clauses when overriding.
+ /*ConsiderRequiresClauses=*/false))
+ continue;
+
+ if (Overridden.insert(BaseMD).second) {
+ MD->addOverriddenMethod(BaseMD);
+ CheckOverridingFunctionReturnType(MD, BaseMD);
+ CheckOverridingFunctionAttributes(MD, BaseMD);
+ CheckOverridingFunctionExceptionSpec(MD, BaseMD);
+ CheckIfOverriddenFunctionIsMarkedFinal(MD, BaseMD);
}
+
+ // A method can only override one function from each base class. We
+ // don't track indirectly overridden methods from bases of bases.
+ return true;
}
return false;
- }
-};
-} // end anonymous namespace
-
-/// AddOverriddenMethods - See if a method overrides any in the base classes,
-/// and if so, check that it's a valid override and remember it.
-bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) {
- // Look for methods in base classes that this method might override.
- CXXBasePaths Paths;
- FindOverriddenMethod FOM;
- FOM.Method = MD;
- FOM.S = this;
- bool AddedAny = false;
- if (DC->lookupInBases(FOM, Paths)) {
- for (auto *I : Paths.found_decls()) {
- if (CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(I)) {
- MD->addOverriddenMethod(OldMD->getCanonicalDecl());
- if (!CheckOverridingFunctionReturnType(MD, OldMD) &&
- !CheckOverridingFunctionAttributes(MD, OldMD) &&
- !CheckOverridingFunctionExceptionSpec(MD, OldMD) &&
- !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) {
- AddedAny = true;
- }
- }
- }
- }
+ };
- return AddedAny;
+ DC->lookupInBases(VisitBase, Paths);
+ return !Overridden.empty();
}
namespace {