aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaLookup.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-10-22 22:08:47 +0000
committerDouglas Gregor <dgregor@apple.com>2010-10-22 22:08:47 +0000
commitf17b58c98b57537e9abfaaa8b5f19ea7e6de01ee (patch)
treed1a16675d8b8941a63157390ff83c623faa74d6c /lib/Sema/SemaLookup.cpp
parentf50595df931bde89e3acd3ec18e4c7e41aa80852 (diff)
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
Diffstat (limited to 'lib/Sema/SemaLookup.cpp')
-rw-r--r--lib/Sema/SemaLookup.cpp96
1 files changed, 66 insertions, 30 deletions
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<FunctionTemplateDecl>((*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<typename InputIterator>
+static bool HasOnlyStaticMembers(InputIterator First, InputIterator Last) {
+ Decl *D = (*First)->getUnderlyingDecl();
+ if (isa<VarDecl>(D) || isa<TypeDecl>(D) || isa<EnumConstantDecl>(D))
+ return true;
+
+ if (isa<CXXMethodDecl>(D)) {
+ // Determine whether all of the methods are static.
+ bool AllMethodsAreStatic = true;
+ for(; First != Last; ++First) {
+ D = (*First)->getUnderlyingDecl();
+
+ if (!isa<CXXMethodDecl>(D)) {
+ assert(isa<TagDecl>(D) && "Non-function must be a tag decl");
+ break;
+ }
+
+ if (!cast<CXXMethodDecl>(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<VarDecl>(FirstDecl) ||
- isa<TypeDecl>(FirstDecl) ||
- isa<EnumConstantDecl>(FirstDecl))
+ if (HasOnlyStaticMembers(Path->Decls.first, Path->Decls.second))
continue;
-
- if (isa<CXXMethodDecl>(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<CXXMethodDecl>(*Func)) {
- assert(isa<TagDecl>(*Func) && "Non-function must be a tag decl");
- break;
- }
-
- if (!cast<CXXMethodDecl>(*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);