diff options
author | Benjamin Kramer <benny.kra@googlemail.com> | 2015-07-25 15:07:25 +0000 |
---|---|---|
committer | Benjamin Kramer <benny.kra@googlemail.com> | 2015-07-25 15:07:25 +0000 |
commit | 6e4f6e1f06aaca0d1479e324c30162251692a59b (patch) | |
tree | 94e15a16642f28fdd5cfc611291f1ca205489e24 /clang/lib/Sema/SemaDeclCXX.cpp | |
parent | 944a5777bba28ff905fd0fae7d29b0eb9200b315 (diff) | |
download | bcm5719-llvm-6e4f6e1f06aaca0d1479e324c30162251692a59b.tar.gz bcm5719-llvm-6e4f6e1f06aaca0d1479e324c30162251692a59b.zip |
[AST] Turn the callbacks of lookupInBases and forallBases into a function_ref
This lets us pass functors (and lambdas) without void * tricks. On the
downside we can't pass CXXRecordDecl's Find* members (which are now type
safe) to lookupInBases directly, but a lambda trampoline is a small
price to pay. No functionality change intended.
llvm-svn: 243217
Diffstat (limited to 'clang/lib/Sema/SemaDeclCXX.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 186 |
1 files changed, 85 insertions, 101 deletions
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 50890fbff88..3bd4a23eee7 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -6268,77 +6268,75 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, return true; } -/// \brief Data used with FindHiddenVirtualMethod namespace { - struct FindHiddenVirtualMethodData { - Sema *S; - CXXMethodDecl *Method; - llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverridenAndUsingBaseMethods; - SmallVector<CXXMethodDecl *, 8> OverloadedMethods; - }; -} - -/// \brief Check whether any most overriden method from MD in Methods -static bool CheckMostOverridenMethods(const CXXMethodDecl *MD, - const llvm::SmallPtrSetImpl<const CXXMethodDecl *>& Methods) { - if (MD->size_overridden_methods() == 0) - return Methods.count(MD->getCanonicalDecl()); - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); - I != E; ++I) - if (CheckMostOverridenMethods(*I, Methods)) - return true; - return false; -} +struct FindHiddenVirtualMethod { + Sema *S; + CXXMethodDecl *Method; + llvm::SmallPtrSet<const CXXMethodDecl *, 8> OverridenAndUsingBaseMethods; + SmallVector<CXXMethodDecl *, 8> OverloadedMethods; -/// \brief Member lookup function that determines whether a given C++ -/// method overloads virtual methods in a base class without overriding any, -/// to be used with CXXRecordDecl::lookupInBases(). -static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, - void *UserData) { - RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); - - FindHiddenVirtualMethodData &Data - = *static_cast<FindHiddenVirtualMethodData*>(UserData); - - DeclarationName Name = Data.Method->getDeclName(); - assert(Name.getNameKind() == DeclarationName::Identifier); - - bool foundSameNameMethod = false; - SmallVector<CXXMethodDecl *, 8> overloadedMethods; - 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)) { - MD = MD->getCanonicalDecl(); - foundSameNameMethod = true; - // Interested only in hidden virtual methods. - if (!MD->isVirtual()) - continue; - // If the method we are checking overrides a method from its base - // don't warn about the other overloaded methods. Clang deviates from GCC - // by only diagnosing overloads of inherited virtual functions that do not - // override any other virtual functions in the base. GCC's - // -Woverloaded-virtual diagnoses any derived function hiding a virtual - // function from a base class. These cases may be better served by a - // warning (not specific to virtual functions) on call sites when the call - // would select a different function from the base class, were it visible. - // See FIXME in test/SemaCXX/warn-overload-virtual.cpp for an example. - if (!Data.S->IsOverload(Data.Method, MD, false)) +private: + /// Check whether any most overriden method from MD in Methods + static bool CheckMostOverridenMethods( + const CXXMethodDecl *MD, + const llvm::SmallPtrSetImpl<const CXXMethodDecl *> &Methods) { + if (MD->size_overridden_methods() == 0) + return Methods.count(MD->getCanonicalDecl()); + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); + I != E; ++I) + if (CheckMostOverridenMethods(*I, Methods)) return true; - // Collect the overload only if its hidden. - if (!CheckMostOverridenMethods(MD, Data.OverridenAndUsingBaseMethods)) - overloadedMethods.push_back(MD); - } + return false; } - if (foundSameNameMethod) - Data.OverloadedMethods.append(overloadedMethods.begin(), - overloadedMethods.end()); - return foundSameNameMethod; -} +public: + /// Member lookup function that determines whether a given C++ + /// method overloads virtual methods in a base class without overriding any, + /// to be used with CXXRecordDecl::lookupInBases(). + bool operator()(const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { + RecordDecl *BaseRecord = + Specifier->getType()->getAs<RecordType>()->getDecl(); + + DeclarationName Name = Method->getDeclName(); + assert(Name.getNameKind() == DeclarationName::Identifier); + + bool foundSameNameMethod = false; + SmallVector<CXXMethodDecl *, 8> overloadedMethods; + 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)) { + MD = MD->getCanonicalDecl(); + foundSameNameMethod = true; + // Interested only in hidden virtual methods. + if (!MD->isVirtual()) + continue; + // If the method we are checking overrides a method from its base + // don't warn about the other overloaded methods. Clang deviates from + // GCC by only diagnosing overloads of inherited virtual functions that + // do not override any other virtual functions in the base. GCC's + // -Woverloaded-virtual diagnoses any derived function hiding a virtual + // function from a base class. These cases may be better served by a + // warning (not specific to virtual functions) on call sites when the + // call would select a different function from the base class, were it + // visible. + // See FIXME in test/SemaCXX/warn-overload-virtual.cpp for an example. + if (!S->IsOverload(Method, MD, false)) + return true; + // Collect the overload only if its hidden. + if (!CheckMostOverridenMethods(MD, OverridenAndUsingBaseMethods)) + overloadedMethods.push_back(MD); + } + } + + if (foundSameNameMethod) + OverloadedMethods.append(overloadedMethods.begin(), + overloadedMethods.end()); + return foundSameNameMethod; + } +}; +} // end anonymous namespace /// \brief Add the most overriden methods from MD to Methods static void AddMostOverridenMethods(const CXXMethodDecl *MD, @@ -6361,9 +6359,9 @@ void Sema::FindHiddenVirtualMethods(CXXMethodDecl *MD, CXXBasePaths Paths(/*FindAmbiguities=*/true, // true to look in all bases. /*bool RecordPaths=*/false, /*bool DetectVirtual=*/false); - FindHiddenVirtualMethodData Data; - Data.Method = MD; - Data.S = this; + FindHiddenVirtualMethod FHVM; + FHVM.Method = MD; + FHVM.S = this; // Keep the base methods that were overriden or introduced in the subclass // by 'using' in a set. A base method not in this set is hidden. @@ -6374,11 +6372,11 @@ void Sema::FindHiddenVirtualMethods(CXXMethodDecl *MD, if (UsingShadowDecl *shad = dyn_cast<UsingShadowDecl>(*I)) ND = shad->getTargetDecl(); if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND)) - AddMostOverridenMethods(MD, Data.OverridenAndUsingBaseMethods); + AddMostOverridenMethods(MD, FHVM.OverridenAndUsingBaseMethods); } - if (DC->lookupInBases(&FindHiddenVirtualMethod, &Data, Paths)) - OverloadedMethods = Data.OverloadedMethods; + if (DC->lookupInBases(FHVM, Paths)) + OverloadedMethods = FHVM.OverloadedMethods; } void Sema::NoteHiddenVirtualMethods(CXXMethodDecl *MD, @@ -8468,40 +8466,26 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, // in the UsingDecl and UsingShadowDecl so that these checks didn't // need to be repeated. - struct UserData { - llvm::SmallPtrSet<const CXXRecordDecl*, 4> Bases; - - static bool collect(const CXXRecordDecl *Base, void *OpaqueData) { - UserData *Data = reinterpret_cast<UserData*>(OpaqueData); - Data->Bases.insert(Base); - return true; - } - - bool hasDependentBases(const CXXRecordDecl *Class) { - return !Class->forallBases(collect, this); - } - - /// Returns true if the base is dependent or is one of the - /// accumulated base classes. - static bool doesNotContain(const CXXRecordDecl *Base, void *OpaqueData) { - UserData *Data = reinterpret_cast<UserData*>(OpaqueData); - return !Data->Bases.count(Base); - } - - bool mightShareBases(const CXXRecordDecl *Class) { - return Bases.count(Class) || !Class->forallBases(doesNotContain, this); - } + llvm::SmallPtrSet<const CXXRecordDecl *, 4> Bases; + auto Collect = [&Bases](const CXXRecordDecl *Base) { + Bases.insert(Base); + return true; }; - UserData Data; - - // Returns false if we find a dependent base. - if (Data.hasDependentBases(cast<CXXRecordDecl>(CurContext))) + // Collect all bases. Return false if we find a dependent base. + if (!cast<CXXRecordDecl>(CurContext)->forallBases(Collect)) return false; - // Returns false if the class has a dependent base or if it or one + // Returns true if the base is dependent or is one of the accumulated base + // classes. + auto IsNotBase = [&Bases](const CXXRecordDecl *Base) { + return !Bases.count(Base); + }; + + // Return false if the class has a dependent base or if it or one // of its bases is present in the base set of the current context. - if (Data.mightShareBases(cast<CXXRecordDecl>(NamedContext))) + if (Bases.count(cast<CXXRecordDecl>(NamedContext)) || + !cast<CXXRecordDecl>(NamedContext)->forallBases(IsNotBase)) return false; Diag(SS.getRange().getBegin(), |