From f17b58c98b57537e9abfaaa8b5f19ea7e6de01ee Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 22 Oct 2010 22:08:47 +0000 Subject: [PATCH] In the presence of using declarations, we can find the same class members in class subobjects of different types. So long as the underlying declaration sets are the same, and the declaration sets involve non-instance members, this is not an ambiguity. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@117163 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaLookup.cpp | 96 +++++++++++++------ .../class.derived/class.member.lookup/p9.cpp | 28 ++++++ 2 files changed, 94 insertions(+), 30 deletions(-) create mode 100644 test/CXX/class.derived/class.member.lookup/p9.cpp diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 29df503910..cc27e35bb0 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -301,7 +301,8 @@ void LookupResult::sanity() const { isa((*begin())->getUnderlyingDecl()))); assert(ResultKind != FoundUnresolvedValue || sanityCheckUnresolved()); assert(ResultKind != Ambiguous || Decls.size() > 1 || - (Decls.size() == 1 && Ambiguity == AmbiguousBaseSubobjects)); + (Decls.size() == 1 && (Ambiguity == AmbiguousBaseSubobjects || + Ambiguity == AmbiguousBaseSubobjectTypes))); assert((Paths != NULL) == (ResultKind == Ambiguous && (Ambiguity == AmbiguousBaseSubobjectTypes || Ambiguity == AmbiguousBaseSubobjects))); @@ -1237,6 +1238,38 @@ static bool LookupAnyMember(const CXXBaseSpecifier *Specifier, return Path.Decls.first != Path.Decls.second; } +/// \brief 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; +} + /// \brief Perform qualified name lookup into a given context. /// /// Qualified name lookup (C++ [basic.lookup.qual]) is used to find @@ -1362,10 +1395,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // and includes members from distinct sub-objects, there is an // ambiguity and the program is ill-formed. Otherwise that set is // the result of the lookup. - // FIXME: support using declarations! QualType SubobjectType; int SubobjectNumber = 0; AccessSpecifier SubobjectAccess = AS_none; + for (CXXBasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end(); Path != PathEnd; ++Path) { const CXXBasePathElement &PathElement = Path->back(); @@ -1379,45 +1412,48 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, // This is the first subobject we've looked at. Record its type. SubobjectType = Context.getCanonicalType(PathElement.Base->getType()); SubobjectNumber = PathElement.SubobjectNumber; - } else if (SubobjectType + continue; + } + + if (SubobjectType != Context.getCanonicalType(PathElement.Base->getType())) { // We found members of the given name in two subobjects of - // different types. This lookup is ambiguous. + // different types. If the declaration sets aren't the same, this + // this lookup is ambiguous. + if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second)) { + CXXBasePaths::paths_iterator FirstPath = Paths.begin(); + DeclContext::lookup_iterator FirstD = FirstPath->Decls.first; + DeclContext::lookup_iterator CurrentD = Path->Decls.first; + + while (FirstD != FirstPath->Decls.second && + CurrentD != Path->Decls.second) { + if ((*FirstD)->getUnderlyingDecl()->getCanonicalDecl() != + (*CurrentD)->getUnderlyingDecl()->getCanonicalDecl()) + break; + + ++FirstD; + ++CurrentD; + } + + if (FirstD == FirstPath->Decls.second && + CurrentD == Path->Decls.second) + continue; + } + R.setAmbiguousBaseSubobjectTypes(Paths); return true; - } else if (SubobjectNumber != PathElement.SubobjectNumber) { + } + + if (SubobjectNumber != PathElement.SubobjectNumber) { // We have a different subobject of the same type. // C++ [class.member.lookup]p5: // 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. - Decl *FirstDecl = *Path->Decls.first; - if (isa(FirstDecl) || - isa(FirstDecl) || - isa(FirstDecl)) + if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second)) continue; - - if (isa(FirstDecl)) { - // Determine whether all of the methods are static. - bool AllMethodsAreStatic = true; - for (DeclContext::lookup_iterator Func = Path->Decls.first; - Func != Path->Decls.second; ++Func) { - if (!isa(*Func)) { - assert(isa(*Func) && "Non-function must be a tag decl"); - break; - } - - if (!cast(*Func)->isStatic()) { - AllMethodsAreStatic = false; - break; - } - } - - if (AllMethodsAreStatic) - continue; - } - + // We have found a nonstatic member name in multiple, distinct // subobjects. Name lookup is ambiguous. R.setAmbiguousBaseSubobjects(Paths); diff --git a/test/CXX/class.derived/class.member.lookup/p9.cpp b/test/CXX/class.derived/class.member.lookup/p9.cpp new file mode 100644 index 0000000000..ba7bd21f86 --- /dev/null +++ b/test/CXX/class.derived/class.member.lookup/p9.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +namespace rdar8436162 { + class ClsA { + public: + static void f(); + void g(); + }; + + class ClsB : virtual private ClsA { + public: + using ClsA::f; + using ClsA::g; // expected-note{{member found by ambiguous name lookup}} + }; + + class ClsF : virtual private ClsA { + public: + using ClsA::f; + using ClsA::g; // expected-note{{member found by ambiguous name lookup}} + }; + + class ClsE : public ClsB, public ClsF { + void test() { + f(); + g(); // expected-error{{member 'g' found in multiple base classes of different types}} + } + }; +} -- 2.40.0