From: Richard Smith Date: Wed, 25 Nov 2020 23:22:51 +0000 (-0800) Subject: Refactor and simplify class scope name lookup. X-Git-Tag: llvmorg-13-init~5097 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=3fb0879867d7039cb61ffb6287ac17ac949adfa9;p=platform%2Fupstream%2Fllvm.git Refactor and simplify class scope name lookup. This is partly in preparation for an upcoming change that can change the order in which DeclContext lookup results are presented. In passing, fix some obvious errors where name lookup's notion of a "static member function" missed static member function templates, and where its notion of "same set of declarations" was confused by the same declarations appearing in a different order. --- diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp index efc683c..ef8f549 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp @@ -611,12 +611,10 @@ static StyleKind findStyleKind( // If this method has the same name as any base method, this is likely // necessary even if it's not an override. e.g. CRTP. - auto FindHidden = [&](const CXXBaseSpecifier *S, clang::CXXBasePath &P) { - return CXXRecordDecl::FindOrdinaryMember(S, P, Decl->getDeclName()); - }; - CXXBasePaths UnusedPaths; - if (Decl->getParent()->lookupInBases(FindHidden, UnusedPaths)) - return SK_Invalid; + for (const CXXBaseSpecifier &Base : Decl->getParent()->bases()) + if (const auto *RD = Base.getType()->getAsCXXRecordDecl()) + if (RD->hasMemberName(Decl->getDeclName())) + return SK_Invalid; if (Decl->isConstexpr() && NamingStyles[SK_ConstexprMethod]) return SK_ConstexprMethod; diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 36f42c0..568eeb6 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1622,58 +1622,6 @@ public: CXXBasePath &Path, const CXXRecordDecl *BaseRecord); - /// Base-class lookup callback that determines whether there exists - /// a tag with the given name. - /// - /// This callback can be used with \c lookupInBases() to find tag members - /// of the given name within a C++ class hierarchy. - static bool FindTagMember(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, DeclarationName Name); - - /// Base-class lookup callback that determines whether there exists - /// a member with the given name. - /// - /// This callback can be used with \c lookupInBases() to find members - /// of the given name within a C++ class hierarchy. - static bool FindOrdinaryMember(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, DeclarationName Name); - - /// Base-class lookup callback that determines whether there exists - /// a member with the given name. - /// - /// This callback can be used with \c lookupInBases() to find members - /// of the given name within a C++ class hierarchy, including dependent - /// classes. - static bool - FindOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, DeclarationName Name); - - /// Base-class lookup callback that determines whether there exists - /// an OpenMP declare reduction member with the given name. - /// - /// This callback can be used with \c lookupInBases() to find members - /// of the given name within a C++ class hierarchy. - static bool FindOMPReductionMember(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, DeclarationName Name); - - /// Base-class lookup callback that determines whether there exists - /// an OpenMP declare mapper member with the given name. - /// - /// This callback can be used with \c lookupInBases() to find members - /// of the given name within a C++ class hierarchy. - static bool FindOMPMapperMember(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, DeclarationName Name); - - /// Base-class lookup callback that determines whether there exists - /// a member with the given name that can be used in a nested-name-specifier. - /// - /// This callback can be used with \c lookupInBases() to find members of - /// the given name within a C++ class hierarchy that can occur within - /// nested-name-specifiers. - static bool FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, - DeclarationName Name); - /// Retrieve the final overriders for each virtual member /// function in the class hierarchy where this class is the /// most-derived class in the class hierarchy. @@ -1682,12 +1630,20 @@ public: /// Get the indirect primary bases for this class. void getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const; + /// Determine whether this class has a member with the given name, possibly + /// in a non-dependent base class. + /// + /// No check for ambiguity is performed, so this should never be used when + /// implementing language semantics, but it may be appropriate for warnings, + /// static analysis, or similar. + bool hasMemberName(DeclarationName N) const; + /// Performs an imprecise lookup of a dependent name in this class. /// /// This function does not follow strict semantic rules and should be used /// only when lookup rules can be relaxed, e.g. indexing. std::vector - lookupDependentName(const DeclarationName &Name, + lookupDependentName(DeclarationName Name, llvm::function_ref Filter); /// Renders and displays an inheritance diagram diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 20c7e8c..775dd17 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7268,9 +7268,9 @@ public: /// considered valid results. /// \param AllowDependent Whether unresolved using declarations (that might /// name templates) should be considered valid results. - NamedDecl *getAsTemplateNameDecl(NamedDecl *D, - bool AllowFunctionTemplates = true, - bool AllowDependent = true); + static NamedDecl *getAsTemplateNameDecl(NamedDecl *D, + bool AllowFunctionTemplates = true, + bool AllowDependent = true); enum TemplateNameIsRequiredTag { TemplateNameIsRequired }; /// Whether and why a template name is required in this lookup. diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp index 8af9711..816b5d1 100644 --- a/clang/lib/AST/CXXInheritance.cpp +++ b/clang/lib/AST/CXXInheritance.cpp @@ -402,54 +402,45 @@ bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier, ->getCanonicalDecl() == BaseRecord; } -bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, - DeclarationName Name) { - RecordDecl *BaseRecord = - Specifier->getType()->castAs()->getDecl(); - - for (Path.Decls = BaseRecord->lookup(Name); - !Path.Decls.empty(); - Path.Decls = Path.Decls.slice(1)) { - if (Path.Decls.front()->isInIdentifierNamespace(IDNS_Tag)) - return true; - } - - return false; +static bool isOrdinaryMember(const NamedDecl *ND) { + return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag | + Decl::IDNS_Member); } -static bool findOrdinaryMember(RecordDecl *BaseRecord, CXXBasePath &Path, +static bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path, DeclarationName Name) { - const unsigned IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | - Decl::IDNS_Member; - for (Path.Decls = BaseRecord->lookup(Name); - !Path.Decls.empty(); - Path.Decls = Path.Decls.slice(1)) { - if (Path.Decls.front()->isInIdentifierNamespace(IDNS)) + Path.Decls = RD->lookup(Name); + for (NamedDecl *ND : Path.Decls) + if (isOrdinaryMember(ND)) return true; - } return false; } -bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, - DeclarationName Name) { - RecordDecl *BaseRecord = - Specifier->getType()->castAs()->getDecl(); - return findOrdinaryMember(BaseRecord, Path, Name); +bool CXXRecordDecl::hasMemberName(DeclarationName Name) const { + CXXBasePath P; + if (findOrdinaryMember(this, P, Name)) + return true; + + CXXBasePaths Paths(false, false, false); + return lookupInBases( + [Name](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { + return findOrdinaryMember(Specifier->getType()->getAsCXXRecordDecl(), + Path, Name); + }, + Paths); } -bool CXXRecordDecl::FindOrdinaryMemberInDependentClasses( - const CXXBaseSpecifier *Specifier, CXXBasePath &Path, - DeclarationName Name) { +static bool +findOrdinaryMemberInDependentClasses(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, DeclarationName Name) { const TemplateSpecializationType *TST = Specifier->getType()->getAs(); if (!TST) { auto *RT = Specifier->getType()->getAs(); if (!RT) return false; - return findOrdinaryMember(RT->getDecl(), Path, Name); + return findOrdinaryMember(cast(RT->getDecl()), Path, Name); } TemplateName TN = TST->getTemplateName(); const auto *TD = dyn_cast_or_null(TN.getAsTemplateDecl()); @@ -461,80 +452,32 @@ bool CXXRecordDecl::FindOrdinaryMemberInDependentClasses( return findOrdinaryMember(RD, Path, Name); } -bool CXXRecordDecl::FindOMPReductionMember(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, - DeclarationName Name) { - RecordDecl *BaseRecord = - Specifier->getType()->castAs()->getDecl(); - - for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty(); - Path.Decls = Path.Decls.slice(1)) { - if (Path.Decls.front()->isInIdentifierNamespace(IDNS_OMPReduction)) - return true; - } - - return false; -} - -bool CXXRecordDecl::FindOMPMapperMember(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, - DeclarationName Name) { - RecordDecl *BaseRecord = - Specifier->getType()->castAs()->getDecl(); - - for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty(); - Path.Decls = Path.Decls.slice(1)) { - if (Path.Decls.front()->isInIdentifierNamespace(IDNS_OMPMapper)) - return true; - } - - return false; -} - -bool CXXRecordDecl:: -FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, - DeclarationName Name) { - RecordDecl *BaseRecord = - Specifier->getType()->castAs()->getDecl(); - - for (Path.Decls = BaseRecord->lookup(Name); - !Path.Decls.empty(); - Path.Decls = Path.Decls.slice(1)) { - // FIXME: Refactor the "is it a nested-name-specifier?" check - if (isa(Path.Decls.front()) || - Path.Decls.front()->isInIdentifierNamespace(IDNS_Tag)) - return true; - } - - return false; -} - std::vector CXXRecordDecl::lookupDependentName( - const DeclarationName &Name, + DeclarationName Name, llvm::function_ref Filter) { std::vector Results; // Lookup in the class. - DeclContext::lookup_result DirectResult = lookup(Name); - if (!DirectResult.empty()) { - for (const NamedDecl *ND : DirectResult) { - if (Filter(ND)) - Results.push_back(ND); - } - return Results; + bool AnyOrdinaryMembers = false; + for (const NamedDecl *ND : lookup(Name)) { + if (isOrdinaryMember(ND)) + AnyOrdinaryMembers = true; + if (Filter(ND)) + Results.push_back(ND); } + if (AnyOrdinaryMembers) + return Results; + // Perform lookup into our base classes. CXXBasePaths Paths; Paths.setOrigin(this); if (!lookupInBases( [&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { - return CXXRecordDecl::FindOrdinaryMemberInDependentClasses( - Specifier, Path, Name); + return findOrdinaryMemberInDependentClasses(Specifier, Path, Name); }, Paths, /*LookupInDependent=*/true)) return Results; for (const NamedDecl *ND : Paths.front().Decls) { - if (Filter(ND)) + if (isOrdinaryMember(ND) && Filter(ND)) Results.push_back(ND); } return Results; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index eb6ce6f..9a1312a 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2085,47 +2085,6 @@ static bool LookupQualifiedNameInUsingDirectives(Sema &S, LookupResult &R, return Found; } -/// Callback that looks for any member of a class with the given name. -static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, - CXXBasePath &Path, DeclarationName Name) { - RecordDecl *BaseRecord = Specifier->getType()->castAs()->getDecl(); - - Path.Decls = BaseRecord->lookup(Name); - return !Path.Decls.empty(); -} - -/// Determine whether the given set of member declarations contains only -/// static members, nested types, and enumerators. -template -static bool HasOnlyStaticMembers(InputIterator First, InputIterator Last) { - Decl *D = (*First)->getUnderlyingDecl(); - if (isa(D) || isa(D) || isa(D)) - return true; - - if (isa(D)) { - // Determine whether all of the methods are static. - bool AllMethodsAreStatic = true; - for(; First != Last; ++First) { - D = (*First)->getUnderlyingDecl(); - - if (!isa(D)) { - assert(isa(D) && "Non-function must be a tag decl"); - break; - } - - if (!cast(D)->isStatic()) { - AllMethodsAreStatic = false; - break; - } - } - - if (AllMethodsAreStatic) - return true; - } - - return false; -} - /// Perform qualified name lookup into a given context. /// /// Qualified name lookup (C++ [basic.lookup.qual]) is used to find @@ -2203,6 +2162,13 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, if (!LookupRec || !LookupRec->getDefinition()) return false; + // We're done for lookups that can never succeed for C++ classes. + if (R.getLookupKind() == LookupOperatorName || + R.getLookupKind() == LookupNamespaceName || + R.getLookupKind() == LookupObjCProtocolName || + R.getLookupKind() == LookupLabel) + return false; + // If we're performing qualified name lookup into a dependent class, // then we are actually looking into a current instantiation. If we have any // dependent base classes, then we either have to delay lookup until @@ -2215,59 +2181,27 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, } // Perform lookup into our base classes. - CXXBasePaths Paths; - Paths.setOrigin(LookupRec); - - // Look for this member in our base classes - bool (*BaseCallback)(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, - DeclarationName Name) = nullptr; - switch (R.getLookupKind()) { - case LookupObjCImplicitSelfParam: - case LookupOrdinaryName: - case LookupMemberName: - case LookupRedeclarationWithLinkage: - case LookupLocalFriendName: - case LookupDestructorName: - BaseCallback = &CXXRecordDecl::FindOrdinaryMember; - break; - - case LookupTagName: - BaseCallback = &CXXRecordDecl::FindTagMember; - break; - - case LookupAnyName: - BaseCallback = &LookupAnyMember; - break; - - case LookupOMPReductionName: - BaseCallback = &CXXRecordDecl::FindOMPReductionMember; - break; - - case LookupOMPMapperName: - BaseCallback = &CXXRecordDecl::FindOMPMapperMember; - break; - - case LookupUsingDeclName: - // This lookup is for redeclarations only. - - case LookupOperatorName: - case LookupNamespaceName: - case LookupObjCProtocolName: - case LookupLabel: - // These lookups will never find a member in a C++ class (or base class). - return false; - - case LookupNestedNameSpecifierName: - BaseCallback = &CXXRecordDecl::FindNestedNameSpecifierMember; - break; - } DeclarationName Name = R.getLookupName(); - if (!LookupRec->lookupInBases( - [=](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { - return BaseCallback(Specifier, Path, Name); - }, - Paths)) + unsigned IDNS = R.getIdentifierNamespace(); + + // Look for this member in our base classes. + auto BaseCallback = [Name, IDNS](const CXXBaseSpecifier *Specifier, + CXXBasePath &Path) -> bool { + CXXRecordDecl *BaseRecord = Specifier->getType()->getAsCXXRecordDecl(); + // Drop leading non-matching lookup results from the declaration list so + // we don't need to consider them again below. + for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty(); + Path.Decls = Path.Decls.slice(1)) { + if (Path.Decls.front()->isInIdentifierNamespace(IDNS)) + return true; + } + return false; + }; + + CXXBasePaths Paths; + Paths.setOrigin(LookupRec); + if (!LookupRec->lookupInBases(BaseCallback, Paths)) return false; R.setNamingClass(LookupRec); @@ -2282,6 +2216,85 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, int SubobjectNumber = 0; AccessSpecifier SubobjectAccess = AS_none; + // Check whether the given lookup result contains only static members. + auto HasOnlyStaticMembers = [&](DeclContextLookupResult Result) { + for (NamedDecl *ND : Result) + if (ND->isInIdentifierNamespace(IDNS) && ND->isCXXInstanceMember()) + return false; + return true; + }; + + bool TemplateNameLookup = R.isTemplateNameLookup(); + + // Determine whether two sets of members contain the same members, as + // required by C++ [class.member.lookup]p6. + auto HasSameDeclarations = [IDNS, + TemplateNameLookup](DeclContextLookupResult A, + DeclContextLookupResult B) { + using Iterator = DeclContextLookupResult::iterator; + using Result = const Decl *; + + auto Next = [&](Iterator &It, Iterator End) -> Result { + while (It != End) { + NamedDecl *ND = *It++; + if (!ND->isInIdentifierNamespace(IDNS)) + continue; + + // C++ [temp.local]p3: + // A lookup that finds an injected-class-name (10.2) can result in + // an ambiguity in certain cases (for example, if it is found in + // more than one base class). If all of the injected-class-names + // that are found refer to specializations of the same class + // template, and if the name is used as a template-name, the + // reference refers to the class template itself and not a + // specialization thereof, and is not ambiguous. + if (TemplateNameLookup) + if (auto *TD = getAsTemplateNameDecl(ND)) + ND = TD; + + // FIXME: Per C++ [class.member.lookup]p3: + // type declarations (including injected-class-names are replaced by the + // types they designate + // So two different typedef declarations with the same name from two + // different base classes declaring the same type do not introduce an + // ambiguity. + + return cast(ND->getUnderlyingDecl()->getCanonicalDecl()); + } + return nullptr; + }; + + // We'll often find the declarations are in the same order. Handle this + // case (and the special case of only one declaration) efficiently. + Iterator AIt = A.begin(), BIt = B.begin(), AEnd = A.end(), BEnd = B.end(); + while (true) { + Result AResult = Next(AIt, AEnd); + Result BResult = Next(BIt, BEnd); + if (!AResult && !BResult) + return true; + if (!AResult || !BResult) + return false; + if (AResult != BResult) { + // Found a mismatch; carefully check both lists, accounting for the + // possibility of declarations appearing more than once. + llvm::SmallDenseMap AResults; + for (; AResult; AResult = Next(AIt, AEnd)) + AResults.insert({AResult, /*FoundInB*/false}); + unsigned Found = 0; + for (; BResult; BResult = Next(BIt, BEnd)) { + auto It = AResults.find(BResult); + if (It == AResults.end()) + return false; + if (!It->second) { + It->second = true; + ++Found; + } + } + return AResults.size() == Found; + } + } + }; + for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); Path != PathEnd; ++Path) { const CXXBasePathElement &PathElement = Path->back(); @@ -2298,51 +2311,25 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, continue; } - if (SubobjectType - != Context.getCanonicalType(PathElement.Base->getType())) { + if (SubobjectType != + Context.getCanonicalType(PathElement.Base->getType())) { // We found members of the given name in two subobjects of // different types. If the declaration sets aren't the same, this // lookup is ambiguous. - if (HasOnlyStaticMembers(Path->Decls.begin(), Path->Decls.end())) { - CXXBasePaths::paths_iterator FirstPath = Paths.begin(); - DeclContext::lookup_iterator FirstD = FirstPath->Decls.begin(); - DeclContext::lookup_iterator CurrentD = Path->Decls.begin(); - - // Get the decl that we should use for deduplicating this lookup. - auto GetRepresentativeDecl = [&](NamedDecl *D) -> Decl * { - // C++ [temp.local]p3: - // A lookup that finds an injected-class-name (10.2) can result in - // an ambiguity in certain cases (for example, if it is found in - // more than one base class). If all of the injected-class-names - // that are found refer to specializations of the same class - // template, and if the name is used as a template-name, the - // reference refers to the class template itself and not a - // specialization thereof, and is not ambiguous. - if (R.isTemplateNameLookup()) - if (auto *TD = getAsTemplateNameDecl(D)) - D = TD; - return D->getUnderlyingDecl()->getCanonicalDecl(); - }; - - while (FirstD != FirstPath->Decls.end() && - CurrentD != Path->Decls.end()) { - if (GetRepresentativeDecl(*FirstD) != - GetRepresentativeDecl(*CurrentD)) - break; - - ++FirstD; - ++CurrentD; - } - - if (FirstD == FirstPath->Decls.end() && - CurrentD == Path->Decls.end()) - continue; - } + // + // FIXME: The language rule says that this applies irrespective of + // whether the sets contain only static members. + if (HasOnlyStaticMembers(Path->Decls) && + HasSameDeclarations(Paths.begin()->Decls, Path->Decls)) + continue; R.setAmbiguousBaseSubobjectTypes(Paths); return true; } + // FIXME: This language rule no longer exists. Checking for ambiguous base + // subobjects should be done as part of formation of a class member access + // expression (when converting the object parameter to the member's type). if (SubobjectNumber != PathElement.SubobjectNumber) { // We have a different subobject of the same type. @@ -2350,7 +2337,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // A static member, a nested type or an enumerator defined in // a base class T can unambiguously be found even if an object // has more than one base class subobject of type T. - if (HasOnlyStaticMembers(Path->Decls.begin(), Path->Decls.end())) + if (HasOnlyStaticMembers(Path->Decls)) continue; // We have found a nonstatic member name in multiple, distinct @@ -2365,7 +2352,8 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, for (auto *D : Paths.front().Decls) { AccessSpecifier AS = CXXRecordDecl::MergeAccess(SubobjectAccess, D->getAccess()); - R.addDecl(D, AS); + if (NamedDecl *ND = R.getAcceptableDecl(D)) + R.addDecl(ND, AS); } R.resolveKind(); return true; diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 52ba17d..996d364 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -842,19 +842,7 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred, static bool hasMember(const ASTContext &Ctx, const CXXRecordDecl *RD, StringRef Name) { const IdentifierInfo &II = Ctx.Idents.get(Name); - DeclarationName DeclName = Ctx.DeclarationNames.getIdentifier(&II); - if (!RD->lookup(DeclName).empty()) - return true; - - CXXBasePaths Paths(false, false, false); - if (RD->lookupInBases( - [DeclName](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { - return CXXRecordDecl::FindOrdinaryMember(Specifier, Path, DeclName); - }, - Paths)) - return true; - - return false; + return RD->hasMemberName(Ctx.DeclarationNames.getIdentifier(&II)); } /// Returns true if the given C++ class is a container or iterator. diff --git a/clang/test/SemaCXX/lookup-member.cpp b/clang/test/SemaCXX/lookup-member.cpp index a2256a8..46ba74a 100644 --- a/clang/test/SemaCXX/lookup-member.cpp +++ b/clang/test/SemaCXX/lookup-member.cpp @@ -11,3 +11,29 @@ class String; // expected-error {{conflicts with target of using declaration}} union value { char *String; }; + +namespace UnambiguousStaticMemberTemplate { + // A static member template is not ambiguous if found in multiple base class + // subobjects. + struct A { template static void f(T); static void g(); }; + struct B : A { using A::f; using A::g; }; + struct C : A { using A::f; using A::g; }; + struct D : B, C {}; + void f(D d) { d.f(0); d.g(); } +} + +namespace UnambiguousReorderedMembers { + // Static members are not ambiguous if we find them in a different order in + // multiple base classes. + struct A { static void f(); }; + struct B { static void f(int); }; + struct C : A, B { using A::f; using B::f; }; // expected-note {{found}} + struct D : B, A { using B::f; using A::f; }; + struct E : C, D {}; + void f(E e) { e.f(0); } + + // But a different declaration set in different base classes does result in ambiguity. + struct X : B, A { using B::f; using A::f; static void f(int, int); }; // expected-note {{found}} + struct Y : C, X {}; + void g(Y y) { y.f(0); } // expected-error {{found in multiple base classes of different types}} +} diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index 37ad7ff..7747048 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -6541,8 +6541,10 @@ size_t TypeSystemClang::GetIndexOfChildMemberWithName( if (cxx_record_decl->lookupInBases( [decl_name](const clang::CXXBaseSpecifier *specifier, clang::CXXBasePath &path) { - return clang::CXXRecordDecl::FindOrdinaryMember( - specifier, path, decl_name); + path.Decls = + specifier->getType()->getAsCXXRecordDecl()->lookup( + decl_name); + return !path.Decls.empty(); }, paths)) { clang::CXXBasePaths::const_paths_iterator path,