aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaDecl.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-01-14 22:20:51 +0000
committerDouglas Gregor <dgregor@apple.com>2009-01-14 22:20:51 +0000
commiteb11cd078ba8682bbb9b082f8f6ead8be5c98581 (patch)
tree01369931f9c2b3fbf53b8385ea9bee2e0ec0e16d /lib/Sema/SemaDecl.cpp
parent2253dc4705e7816a6cafcf95498da7080041a3e2 (diff)
Refactor name lookup.
This change refactors and cleans up our handling of name lookup with LookupDecl. There are several aspects to this refactoring: - The criteria for name lookup is now encapsulated into the class LookupCriteria, which replaces the hideous set of boolean values that LookupDecl currently has. - The results of name lookup are returned in a new class LookupResult, which can lazily build OverloadedFunctionDecls for overloaded function sets (and, eventually, eliminate the need to allocate member for OverloadedFunctionDecls) and contains a placeholder for handling ambiguous name lookup (for C++). - The primary entry points for name lookup are now LookupName (for unqualified name lookup) and LookupQualifiedName (for qualified name lookup). There is also a convenience function LookupParsedName that handles qualified/unqualified name lookup when given a scope specifier. Together, these routines are meant to gradually replace the kludgy LookupDecl, but this won't happen until after we have base class lookup (which forces us to cope with ambiguities). - Documented the heck out of name lookup. Experimenting a little with using Doxygen's member groups to make some sense of the Sema class. Feedback welcome! - Fixes some lingering issues with name lookup for nested-name-specifiers, which now goes through LookupName/LookupQualifiedName. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62245 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDecl.cpp')
-rw-r--r--lib/Sema/SemaDecl.cpp225
1 files changed, 34 insertions, 191 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 8ba6f31da8..5119388dbc 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -205,52 +205,6 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) {
return dyn_cast_or_null<ObjCInterfaceDecl>(IDecl);
}
-/// MaybeConstructOverloadSet - Name lookup has determined that the
-/// elements in [I, IEnd) have the name that we are looking for, and
-/// *I is a match for the namespace. This routine returns an
-/// appropriate Decl for name lookup, which may either be *I or an
-/// OverloadeFunctionDecl that represents the overloaded functions in
-/// [I, IEnd).
-///
-/// The existance of this routine is temporary; LookupDecl should
-/// probably be able to return multiple results, to deal with cases of
-/// ambiguity and overloaded functions without needing to create a
-/// Decl node.
-template<typename DeclIterator>
-static Decl *
-MaybeConstructOverloadSet(ASTContext &Context,
- DeclIterator I, DeclIterator IEnd) {
- assert(I != IEnd && "Iterator range cannot be empty");
- assert(!isa<OverloadedFunctionDecl>(*I) &&
- "Cannot have an overloaded function");
-
- if (isa<FunctionDecl>(*I)) {
- // If we found a function, there might be more functions. If
- // so, collect them into an overload set.
- DeclIterator Last = I;
- OverloadedFunctionDecl *Ovl = 0;
- for (++Last; Last != IEnd && isa<FunctionDecl>(*Last); ++Last) {
- if (!Ovl) {
- // FIXME: We leak this overload set. Eventually, we want to
- // stop building the declarations for these overload sets, so
- // there will be nothing to leak.
- Ovl = OverloadedFunctionDecl::Create(Context,
- cast<ScopedDecl>(*I)->getDeclContext(),
- (*I)->getDeclName());
- Ovl->addOverload(cast<FunctionDecl>(*I));
- }
- Ovl->addOverload(cast<FunctionDecl>(*Last));
- }
-
- // If we had more than one function, we built an overload
- // set. Return it.
- if (Ovl)
- return Ovl;
- }
-
- return *I;
-}
-
/// getNonFieldDeclScope - Retrieves the innermost scope, starting
/// from S, where a non-field would be declared. This routine copes
/// with the difference between C and C++ scoping rules in structs and
@@ -288,150 +242,37 @@ Scope *Sema::getNonFieldDeclScope(Scope *S) {
/// are considered as required in C++ [basic.lookup.udir] 3.4.6.p1
/// 'When looking up a namespace-name in a using-directive or
/// namespace-alias-definition, only namespace names are considered.'
-Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
- const DeclContext *LookupCtx,
- bool enableLazyBuiltinCreation,
- bool LookInParent,
- bool NamespaceNameOnly) {
- if (!Name) return 0;
- unsigned NS = NSI;
-
- // In C++, ordinary and member lookup will always find all
- // kinds of names.
- if (getLangOptions().CPlusPlus &&
- (NS & (Decl::IDNS_Ordinary | Decl::IDNS_Member)))
- NS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Ordinary;
-
- if (LookupCtx == 0 && !getLangOptions().CPlusPlus) {
- // Unqualified name lookup in C/Objective-C is purely lexical, so
- // search in the declarations attached to the name.
- assert(!LookupCtx && "Can't perform qualified name lookup here");
- assert(!NamespaceNameOnly && "Can't perform namespace name lookup here");
-
- // For the purposes of unqualified name lookup, structs and unions
- // don't have scopes at all. For example:
- //
- // struct X {
- // struct T { int i; } x;
- // };
- //
- // void f() {
- // struct T t; // okay: T is defined lexically within X, but
- // // semantically at global scope
- // };
- //
- // FIXME: Is there a better way to deal with this?
- DeclContext *SearchCtx = CurContext;
- while (isa<RecordDecl>(SearchCtx) || isa<EnumDecl>(SearchCtx))
- SearchCtx = SearchCtx->getParent();
- IdentifierResolver::iterator I
- = IdResolver.begin(Name, SearchCtx, LookInParent);
-
- // Scan up the scope chain looking for a decl that matches this
- // identifier that is in the appropriate namespace. This search
- // should not take long, as shadowing of names is uncommon, and
- // deep shadowing is extremely uncommon.
- for (; I != IdResolver.end(); ++I)
- if ((*I)->isInIdentifierNamespace(NS))
- return *I;
- } else if (LookupCtx) {
- // If we're performing qualified name lookup (e.g., lookup into a
- // struct), find fields as part of ordinary name lookup.
- if (NS & Decl::IDNS_Ordinary)
- NS |= Decl::IDNS_Member;
-
- // Perform qualified name lookup into the LookupCtx.
- // FIXME: Will need to look into base classes and such.
- DeclContext::lookup_const_iterator I, E;
- for (llvm::tie(I, E) = LookupCtx->lookup(Name); I != E; ++I)
- if ((*I)->isInIdentifierNamespace(NS)) {
- // Ignore non-namespace names if we're only looking for namespaces.
- if (NamespaceNameOnly && !isa<NamespaceDecl>(*I)) continue;
-
- return MaybeConstructOverloadSet(Context, I, E);
- }
- } else {
- // Name lookup for ordinary names and tag names in C++ requires
- // looking into scopes that aren't strictly lexical, and
- // therefore we walk through the context as well as walking
- // through the scopes.
- IdentifierResolver::iterator
- I = IdResolver.begin(Name, CurContext, true/*LookInParentCtx*/),
- IEnd = IdResolver.end();
- for (; S; S = S->getParent()) {
- // Check whether the IdResolver has anything in this scope.
- // FIXME: The isDeclScope check could be expensive. Can we do better?
- for (; I != IEnd && S->isDeclScope(*I); ++I) {
- if ((*I)->isInIdentifierNamespace(NS)) {
- // Ignore non-namespace names if we're only looking for namespaces.
- if (NamespaceNameOnly && !isa<NamespaceDecl>(*I))
- continue;
-
- // We found something. Look for anything else in our scope
- // with this same name and in an acceptable identifier
- // namespace, so that we can construct an overload set if we
- // need to.
- IdentifierResolver::iterator LastI = I;
- for (++LastI; LastI != IEnd; ++LastI) {
- if (!(*LastI)->isInIdentifierNamespace(NS) ||
- !S->isDeclScope(*LastI))
- break;
- }
- return MaybeConstructOverloadSet(Context, I, LastI);
- }
- }
-
- // If there is an entity associated with this scope, it's a
- // DeclContext. We might need to perform qualified lookup into
- // it.
- DeclContext *Ctx = static_cast<DeclContext *>(S->getEntity());
- while (Ctx && Ctx->isFunctionOrMethod())
- Ctx = Ctx->getParent();
- while (Ctx && (Ctx->isNamespace() || Ctx->isRecord())) {
- // Look for declarations of this name in this scope.
- DeclContext::lookup_const_iterator I, E;
- for (llvm::tie(I, E) = Ctx->lookup(Name); I != E; ++I) {
- // FIXME: Cache this result in the IdResolver
- if ((*I)->isInIdentifierNamespace(NS)) {
- if (NamespaceNameOnly && !isa<NamespaceDecl>(*I))
- continue;
- return MaybeConstructOverloadSet(Context, I, E);
- }
- }
-
- if (!LookInParent && !Ctx->isTransparentContext())
- return 0;
+///
+/// Note: The use of this routine is deprecated. Please use
+/// LookupName, LookupQualifiedName, or LookupParsedName instead.
+Sema::LookupResult
+Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
+ const DeclContext *LookupCtx,
+ bool enableLazyBuiltinCreation,
+ bool LookInParent,
+ bool NamespaceNameOnly) {
+ LookupCriteria::NameKind Kind;
+ if (NSI == Decl::IDNS_Ordinary) {
+ if (NamespaceNameOnly)
+ Kind = LookupCriteria::Namespace;
+ else
+ Kind = LookupCriteria::Ordinary;
+ } else if (NSI == Decl::IDNS_Tag)
+ Kind = LookupCriteria::Tag;
+ else if (NSI == Decl::IDNS_Member)
+ Kind = LookupCriteria::Member;
+ else
+ assert(false && "Unable to grok LookupDecl NSI argument");
- Ctx = Ctx->getParent();
- }
- }
- }
+ if (LookupCtx)
+ return LookupQualifiedName(const_cast<DeclContext *>(LookupCtx), Name,
+ LookupCriteria(Kind, !LookInParent,
+ getLangOptions().CPlusPlus));
- // If we didn't find a use of this identifier, and if the identifier
- // corresponds to a compiler builtin, create the decl object for the builtin
- // now, injecting it into translation unit scope, and return it.
- if (NS & Decl::IDNS_Ordinary) {
- IdentifierInfo *II = Name.getAsIdentifierInfo();
- if (enableLazyBuiltinCreation && II &&
- (LookupCtx == 0 || isa<TranslationUnitDecl>(LookupCtx))) {
- // If this is a builtin on this (or all) targets, create the decl.
- if (unsigned BuiltinID = II->getBuiltinID())
- return LazilyCreateBuiltin((IdentifierInfo *)II, BuiltinID, S);
- }
- if (getLangOptions().ObjC1 && II) {
- // @interface and @compatibility_alias introduce typedef-like names.
- // Unlike typedef's, they can only be introduced at file-scope (and are
- // therefore not scoped decls). They can, however, be shadowed by
- // other names in IDNS_Ordinary.
- ObjCInterfaceDeclsTy::iterator IDI = ObjCInterfaceDecls.find(II);
- if (IDI != ObjCInterfaceDecls.end())
- return IDI->second;
- ObjCAliasTy::iterator I = ObjCAliasDecls.find(II);
- if (I != ObjCAliasDecls.end())
- return I->second->getClassInterface();
- }
- }
- return 0;
+ // Unqualified lookup
+ return LookupName(S, Name,
+ LookupCriteria(Kind, !LookInParent,
+ getLangOptions().CPlusPlus));
}
void Sema::InitBuiltinVaListType() {
@@ -489,7 +330,7 @@ NamespaceDecl *Sema::GetStdNamespace() {
if (!StdNamespace) {
IdentifierInfo *StdIdent = &PP.getIdentifierTable().get("std");
DeclContext *Global = Context.getTranslationUnitDecl();
- Decl *Std = LookupDecl(StdIdent, Decl::IDNS_Tag | Decl::IDNS_Ordinary,
+ Decl *Std = LookupDecl(StdIdent, Decl::IDNS_Ordinary,
0, Global, /*enableLazyBuiltinCreation=*/false);
StdNamespace = dyn_cast_or_null<NamespaceDecl>(Std);
}
@@ -2944,7 +2785,8 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
DC = static_cast<DeclContext*>(SS.getScopeRep());
// Look-up name inside 'foo::'.
- PrevDecl = dyn_cast_or_null<TagDecl>(LookupDecl(Name, Decl::IDNS_Tag,S,DC));
+ PrevDecl = dyn_cast_or_null<TagDecl>(LookupDecl(Name, Decl::IDNS_Tag,S,DC)
+ .getAsDecl());
// A tag 'foo::bar' must already exist.
if (PrevDecl == 0) {
@@ -2956,7 +2798,8 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
// If this is a named struct, check to see if there was a previous forward
// declaration or definition.
// Use ScopedDecl instead of TagDecl, because a NamespaceDecl may come up.
- PrevDecl = dyn_cast_or_null<ScopedDecl>(LookupDecl(Name, Decl::IDNS_Tag,S));
+ PrevDecl = dyn_cast_or_null<ScopedDecl>(LookupDecl(Name, Decl::IDNS_Tag,S)
+ .getAsDecl());
if (!getLangOptions().CPlusPlus && TK != TK_Reference) {
// FIXME: This makes sure that we ignore the contexts associated