aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaLookup.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-01-15 00:26:24 +0000
committerDouglas Gregor <dgregor@apple.com>2009-01-15 00:26:24 +0000
commit7176fff961e04c4dff61efb967b1d344d41335a7 (patch)
treebe2a2c2cb416b04178488b32155e7085a4aced9d /lib/Sema/SemaLookup.cpp
parent89db21fec845257482c8cdd3544bb2a9c1daf8e0 (diff)
Initial implementation of member name lookup
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62247 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaLookup.cpp')
-rw-r--r--lib/Sema/SemaLookup.cpp183
1 files changed, 178 insertions, 5 deletions
diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index a9ec3f2faf..b85824382b 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -12,6 +12,8 @@
//
//===----------------------------------------------------------------------===//
#include "Sema.h"
+#include "SemaInherit.h"
+#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
@@ -125,6 +127,46 @@ bool Sema::LookupCriteria::isLookupResult(Decl *D) const {
return false;
}
+Sema::LookupResult::LookupResult(ASTContext &Context,
+ IdentifierResolver::iterator F,
+ IdentifierResolver::iterator L)
+ : Context(&Context) {
+ if (F != L && isa<FunctionDecl>(*F)) {
+ IdentifierResolver::iterator Next = F;
+ ++Next;
+ if (Next != L && isa<FunctionDecl>(*Next)) {
+ StoredKind = OverloadedDeclFromIdResolver;
+ First = F.getAsOpaqueValue();
+ Last = L.getAsOpaqueValue();
+ return;
+ }
+ }
+
+ StoredKind = SingleDecl;
+ First = reinterpret_cast<uintptr_t>(*F);
+ Last = 0;
+}
+
+Sema::LookupResult::LookupResult(ASTContext &Context,
+ DeclContext::lookup_iterator F,
+ DeclContext::lookup_iterator L)
+ : Context(&Context) {
+ if (F != L && isa<FunctionDecl>(*F)) {
+ DeclContext::lookup_iterator Next = F;
+ ++Next;
+ if (Next != L && isa<FunctionDecl>(*Next)) {
+ StoredKind = OverloadedDeclFromDeclContext;
+ First = reinterpret_cast<uintptr_t>(F);
+ Last = reinterpret_cast<uintptr_t>(L);
+ return;
+ }
+ }
+
+ StoredKind = SingleDecl;
+ First = reinterpret_cast<uintptr_t>(*F);
+ Last = 0;
+}
+
/// @brief Determine the result of name lookup.
Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const {
switch (StoredKind) {
@@ -136,11 +178,11 @@ Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const {
return FoundOverloaded;
case AmbiguousLookup:
- return Ambiguous;
+ return Last? AmbiguousBaseSubobjectTypes : AmbiguousBaseSubobjects;
}
- // We can't get here, but GCC complains nonetheless.
- return Ambiguous;
+ // We can't ever get here.
+ return NotFound;
}
/// @brief Converts the result of name lookup into a single (possible
@@ -180,6 +222,14 @@ Decl *Sema::LookupResult::getAsDecl() const {
return 0;
}
+/// @brief Retrieves the BasePaths structure describing an ambiguous
+/// name lookup.
+BasePaths *Sema::LookupResult::getBasePaths() const {
+ assert((StoredKind == AmbiguousLookup) &&
+ "getBasePaths can only be used on an ambiguous lookup");
+ return reinterpret_cast<BasePaths *>(First);
+}
+
/// @brief Perform unqualified name lookup starting from a given
/// scope.
///
@@ -379,13 +429,99 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
Criteria.IDNS |= Decl::IDNS_Member;
// Perform qualified name lookup into the LookupCtx.
- // FIXME: Will need to look into base classes and such.
DeclContext::lookup_iterator I, E;
for (llvm::tie(I, E) = LookupCtx->lookup(Name); I != E; ++I)
if (Criteria.isLookupResult(*I))
return LookupResult(Context, I, E);
- return LookupResult(Context, 0);
+ // If this isn't a C++ class or we aren't allowed to look into base
+ // classes, we're done.
+ if (Criteria.RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx))
+ return LookupResult(Context, 0);
+
+ // Perform lookup into our base classes.
+ BasePaths Paths;
+
+ // Look for this member in our base classes
+ if (!LookupInBases(cast<CXXRecordDecl>(LookupCtx),
+ MemberLookupCriteria(Name, Criteria), Paths))
+ return LookupResult(Context, 0);
+
+ // C++ [class.member.lookup]p2:
+ // [...] If the resulting set of declarations are not all from
+ // sub-objects of the same type, or the set has a nonstatic member
+ // 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;
+ for (BasePaths::paths_iterator Path = Paths.begin(), PathEnd = Paths.end();
+ Path != PathEnd; ++Path) {
+ const BasePathElement &PathElement = Path->back();
+
+ // Determine whether we're looking at a distinct sub-object or not.
+ if (SubobjectType.isNull()) {
+ // This is the first subobject we've looked at. Record it's type.
+ SubobjectType = Context.getCanonicalType(PathElement.Base->getType());
+ SubobjectNumber = PathElement.SubobjectNumber;
+ } else if (SubobjectType
+ != Context.getCanonicalType(PathElement.Base->getType())) {
+ // We found members of the given name in two subobjects of
+ // different types. This lookup is ambiguous.
+ BasePaths *PathsOnHeap = new BasePaths;
+ PathsOnHeap->swap(Paths);
+ return LookupResult(Context, PathsOnHeap, true);
+ } else 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.
+ ScopedDecl *FirstDecl = *Path->Decls.first;
+ if (isa<VarDecl>(FirstDecl) ||
+ isa<TypeDecl>(FirstDecl) ||
+ isa<EnumConstantDecl>(FirstDecl))
+ 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.
+ BasePaths *PathsOnHeap = new BasePaths;
+ PathsOnHeap->swap(Paths);
+ return LookupResult(Context, PathsOnHeap, false);
+ }
+ }
+
+ // Lookup in a base class succeeded; return these results.
+
+ // If we found a function declaration, return an overload set.
+ if (isa<FunctionDecl>(*Paths.front().Decls.first))
+ return LookupResult(Context,
+ Paths.front().Decls.first, Paths.front().Decls.second);
+
+ // We found a non-function declaration; return a single declaration.
+ return LookupResult(Context, *Paths.front().Decls.first);
}
/// @brief Performs name lookup for a name that was parsed in the
@@ -419,4 +555,41 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec &SS,
return LookupName(S, Name, Criteria);
}
+/// @brief Produce a diagnostic describing the ambiguity that resulted
+/// from name lookup.
+///
+/// @param Result The ambiguous name lookup result.
+///
+/// @param Name The name of the entity that name lookup was
+/// searching for.
+///
+/// @param NameLoc The location of the name within the source code.
+///
+/// @param LookupRange A source range that provides more
+/// source-location information concerning the lookup itself. For
+/// example, this range might highlight a nested-name-specifier that
+/// precedes the name.
+///
+/// @returns true
+bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result, DeclarationName Name,
+ SourceLocation NameLoc,
+ SourceRange LookupRange) {
+ assert(Result.isAmbiguous() && "Lookup result must be ambiguous");
+
+ if (Result.getKind() == LookupResult::AmbiguousBaseSubobjects) {
+ BasePaths *Paths = Result.getBasePaths();
+ QualType SubobjectType = Paths->front().back().Base->getType();
+ return Diag(NameLoc, diag::err_ambiguous_member_multiple_subobjects)
+ << Name << SubobjectType << LookupRange;
+ }
+
+ assert(Result.getKind() == LookupResult::AmbiguousBaseSubobjectTypes &&
+ "Unhandled form of name lookup ambiguity");
+
+ Diag(NameLoc, diag::err_ambiguous_member_multiple_subobject_types)
+ << Name << LookupRange;
+
+ // FIXME: point out the members we found using notes.
+ return true;
+}