[cfe-commits] r62245 - in /cfe/trunk: lib/Sema/CMakeLists.txt lib/Sema/IdentifierResolver.h lib/Sema/Sema.h lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp lib/Sema/SemaLookup.cpp test/Parser/cxx-using-directive.cpp test/SemaCXX/qualified-id-lookup.cpp

Douglas Gregor dgregor at apple.com
Wed Jan 14 14:20:53 PST 2009


Author: dgregor
Date: Wed Jan 14 16:20:51 2009
New Revision: 62245

URL: http://llvm.org/viewvc/llvm-project?rev=62245&view=rev
Log:
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. 


Added:
    cfe/trunk/lib/Sema/SemaLookup.cpp
Modified:
    cfe/trunk/lib/Sema/CMakeLists.txt
    cfe/trunk/lib/Sema/IdentifierResolver.h
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/test/Parser/cxx-using-directive.cpp
    cfe/trunk/test/SemaCXX/qualified-id-lookup.cpp

Modified: cfe/trunk/lib/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CMakeLists.txt?rev=62245&r1=62244&r2=62245&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/CMakeLists.txt (original)
+++ cfe/trunk/lib/Sema/CMakeLists.txt Wed Jan 14 16:20:51 2009
@@ -15,6 +15,7 @@
   SemaExprObjC.cpp
   SemaInherit.cpp
   SemaInit.cpp
+  SemaLookup.cpp
   SemaNamedCast.cpp
   SemaOverload.cpp
   SemaStmt.cpp

Modified: cfe/trunk/lib/Sema/IdentifierResolver.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/IdentifierResolver.h?rev=62245&r1=62244&r2=62245&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/IdentifierResolver.h (original)
+++ cfe/trunk/lib/Sema/IdentifierResolver.h Wed Jan 14 16:20:51 2009
@@ -181,6 +181,14 @@
       return *this;
     }
 
+    uintptr_t getAsOpaqueValue() const { return Ptr; }
+    
+    static iterator getFromOpaqueValue(uintptr_t P) {
+      iterator Result(0);
+      Result.Ptr = P;
+      return Result;
+    }
+    
   private:
     void PreIncIter();
   };

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=62245&r1=62244&r2=62245&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Jan 14 16:20:51 2009
@@ -18,6 +18,7 @@
 #include "IdentifierResolver.h"
 #include "CXXFieldCollector.h"
 #include "SemaOverload.h"
+#include "clang/AST/DeclBase.h"
 #include "clang/Parse/Action.h"
 #include "clang/Basic/Diagnostic.h"
 #include "llvm/ADT/SmallVector.h"
@@ -516,26 +517,206 @@
 
   Scope *getNonFieldDeclScope(Scope *S);
 
-  /// More parsing and symbol table subroutines.
-  Decl *LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
-                   const DeclContext *LookupCtx = 0,
-                   bool enableLazyBuiltinCreation = true,
-                   bool LookInParent = true,
-                   bool NamespaceNameOnly = false);
-
-  Decl *LookupNamespaceName(DeclarationName Name, Scope *S,
-                            const DeclContext *LookupCtx) {
-    return LookupDecl(Name, Decl::IDNS_Tag | Decl::IDNS_Ordinary, S,
-                      LookupCtx,
-                      /* enableLazyBuiltinCreation */ false,
-                      /* LookInParent */ true,
-                      /* NamespaceNameOnly */ true);
-  }
+  /// \name Name lookup
+  ///
+  /// These routines provide name lookup that is used during semantic
+  /// analysis to resolve the various kinds of names (identifiers,
+  /// overloaded operator names, constructor names, etc.) into zero or
+  /// more declarations within a particular scope. The major entry
+  /// points are LookupName, which performs unqualified name lookup,
+  /// and LookupQualifiedName, which performs qualified name lookup. 
+  ///
+  /// All name lookup is performed based on some specific criteria,
+  /// which specify what names will be visible to name lookup and how
+  /// far name lookup should work. These criteria are important both
+  /// for capturing language semantics (certain lookups will ignore
+  /// certain names, for example) and for performance, since name
+  /// lookup is often a bottleneck in the compilation of C++. Name
+  /// lookup criteria is specified via the LookupCriteria class.
+  ///
+  /// The results of name lookup can vary based on the kind of name
+  /// lookup performed, the current language, and the translation
+  /// unit. In C, for example, name lookup will either return nothing
+  /// (no entity found) or a single declaration. In C++, name lookup
+  /// can additionally refer to a set of overloaded functions or
+  /// result in an ambiguity. All of the possible results of name
+  /// lookup are captured by the LookupResult class, which provides
+  /// the ability to distinguish among them.
+  //@{
+
+  /// @brief Describes the criteria by which name lookup will
+  /// determine whether a given name will be found.
+  ///
+  /// The LookupCriteria class captures the information required to
+  /// direct name lookup to find the appropriate kind of name. It
+  /// includes information about which kinds of names to consider
+  /// (ordinary names, tag names, class/struct/union member names,
+  /// namespace names, etc.) and where to look for those
+  /// names. LookupCriteria is used throughout semantic analysis to
+  /// specify how to search for a name, e.g., with the LookupName and
+  /// LookupQualifiedName functions.
+  struct LookupCriteria {
+    /// NameKind - The kinds of names that we are looking for. 
+    enum NameKind {
+      /// Ordinary - Ordinary name lookup, which finds ordinary names
+      /// (functions, variables, typedefs, etc.) in C and most kinds
+      /// of names (functions, variables, members, types, etc.) in
+      /// C++.
+      Ordinary,
+      /// Tag - Tag name lookup, which finds the names of enums,
+      /// classes, structs, and unions.
+      Tag,
+      /// Member - Member name lookup, which finds the names of
+      /// class/struct/union members.
+      Member,
+      /// NestedNameSpecifier - Look up of a name that precedes the
+      /// '::' scope resolution operator in C++. This lookup
+      /// completely ignores operator, function, and enumerator names
+      /// (C++ [basic.lookup.qual]p1).
+      NestedNameSpecifier,
+      /// Namespace - Look up a namespace name within a C++
+      /// using directive or namespace alias definition, ignoring
+      /// non-namespace names (C++ [basic.lookup.udir]p1).
+      Namespace
+    } Kind;
+
+    /// AllowLazyBuiltinCreation - If true, permits name lookup to
+    /// lazily build declarations for built-in names, e.g.,
+    /// __builtin_expect.
+    bool AllowLazyBuiltinCreation;
+
+    /// RedeclarationOnly - If true, the lookup will only
+    /// consider entities within the scope where the lookup
+    /// began. Entities that might otherwise meet the lookup criteria
+    /// but are not within the original lookup scope will be ignored.
+    bool RedeclarationOnly;
+
+    /// IDNS - Bitwise OR of the appropriate Decl::IDNS_* flags that
+    /// describe the namespaces where we should look for names. This
+    /// field is determined by the kind of name we're searching for.
+    unsigned IDNS;
+
+    LookupCriteria(NameKind K, bool RedeclarationOnly, bool CPlusPlus);
+    
+    bool isLookupResult(Decl *D) const;
+  };
+
+  /// @brief Represents the results of name lookup.
+  ///
+  /// An instance of the LookupResult class captures the results of a
+  /// single name lookup, which can return no result (nothing found),
+  /// a single declaration, a set of overloaded functions, or an
+  /// ambiguity. Use the getKind() method to determine which of these
+  /// results occurred for a given lookup. 
+  ///
+  /// Any non-ambiguous lookup can be converted into a single
+  /// (possibly NULL) @c Decl* via a conversion function or the
+  /// getAsDecl() method. This conversion permits the common-case
+  /// usage in C and Objective-C where name lookup will always return
+  /// a single declaration.
+  class LookupResult {
+    /// The kind of entity that is actually stored within the
+    /// LookupResult object.
+    mutable enum {
+      /// First is a single declaration (a Decl*), which may be NULL.
+      SingleDecl,
+      /// [First, Last) is an iterator range represented as opaque
+      /// pointers used to reconstruct IdentifierResolver::iterators.
+      OverloadedDeclFromIdResolver,
+      /// [First, Last) is an iterator range represented as opaque
+      /// pointers used to reconstruct DeclContext::lookup_iterators.
+      OverloadedDeclFromDeclContext,
+      /// FIXME: Cope with ambiguous name lookup.
+      AmbiguousLookup
+    } StoredKind;
+
+    /// The first lookup result, whose contents depend on the kind of
+    /// lookup result. This may be a Decl* (if StoredKind ==
+    /// SingleDecl), the opaque pointer from an
+    /// IdentifierResolver::iterator (if StoredKind ==
+    /// OverloadedDeclFromIdResolver), or a
+    /// DeclContext::lookup_iterator (if StoredKind ==
+    /// OverloadedDeclFromDeclContext).
+    mutable uintptr_t First;
+
+    /// The last lookup result, whose contents depend on the kind of
+    /// lookup result. This may be unused (if StoredKind ==
+    /// SingleDecl) or it may have the same type as First (for
+    /// overloaded function declarations).
+    mutable uintptr_t Last;
+
+    /// Context - The context in which we will build any
+    /// OverloadedFunctionDecl nodes needed by the conversion to
+    /// Decl*.
+    ASTContext *Context;
+
+  public:
+    /// @brief The kind of entity found by name lookup.
+    enum LookupKind {
+      /// @brief No entity found met the criteria.
+      NotFound = 0,
+      /// @brief Name lookup found a single declaration that met the
+      /// criteria.
+      Found,
+      /// @brief Name lookup found a set of overloaded functions that
+      /// met the criteria.
+      FoundOverloaded,
+      /// @brief Name lookup resulted in an ambiguity, e.g., because
+      /// the name was found in two different base classes.
+      Ambiguous
+    };
+
+    LookupResult(ASTContext &Context, Decl *D) 
+      : StoredKind(SingleDecl), First(reinterpret_cast<uintptr_t>(D)),
+        Last(0), Context(&Context) { }
+
+    LookupResult(ASTContext &Context, 
+                 IdentifierResolver::iterator F, IdentifierResolver::iterator L)
+      : StoredKind(OverloadedDeclFromIdResolver),
+        First(F.getAsOpaqueValue()), Last(L.getAsOpaqueValue()), 
+        Context(&Context) { }
+
+    LookupResult(ASTContext &Context, 
+                 DeclContext::lookup_iterator F, DeclContext::lookup_iterator L)
+      : StoredKind(OverloadedDeclFromDeclContext),
+        First(reinterpret_cast<uintptr_t>(F)), 
+        Last(reinterpret_cast<uintptr_t>(L)),
+        Context(&Context) { }
+
+    LookupKind getKind() const;
+
+    /// @brief Determine whether name look found something.
+    operator bool() const { return getKind() != NotFound; }
+
+    /// @brief Allows conversion of a lookup result into a
+    /// declaration, with the same behavior as getAsDecl.
+    operator Decl*() const { return getAsDecl(); }
+
+    Decl* getAsDecl() const;
+  };
+
+  LookupResult LookupName(Scope *S, DeclarationName Name, 
+                          LookupCriteria Criteria);
+  LookupResult LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
+                                   LookupCriteria Criteria);
+  LookupResult LookupParsedName(Scope *S, const CXXScopeSpec &SS, 
+                                DeclarationName Name, LookupCriteria Criteria);
+  
+  LookupResult LookupDecl(DeclarationName Name, unsigned NSI, Scope *S,
+                          const DeclContext *LookupCtx = 0,
+                          bool enableLazyBuiltinCreation = true,
+                          bool LookInParent = true,
+                          bool NamespaceNameOnly = false);
+  //@}
+  
   ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id);
   ScopedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, 
                                   Scope *S);
   ScopedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II,
                                  Scope *S);
+
+  // More parsing and symbol table subroutines.
+
   // Decl attributes - this routine is the top level dispatcher. 
   void ProcessDeclAttributes(Decl *D, const Declarator &PD);
   void ProcessDeclAttributeList(Decl *D, const AttributeList *AttrList);

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=62245&r1=62244&r2=62245&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Wed Jan 14 16:20:51 2009
@@ -19,54 +19,6 @@
 using namespace clang;
 
 
-namespace {
-  Decl *LookupNestedName(DeclContext *LookupCtx, bool LookInParentCtx,
-                         DeclarationName Name, bool &IdIsUndeclared,
-                         ASTContext &Context) {
-    if (LookupCtx && !LookInParentCtx) {
-      IdIsUndeclared = true;
-      DeclContext::lookup_const_iterator I, E;
-      for (llvm::tie(I, E) = LookupCtx->lookup(Name); I != E; ++I) {
-       IdIsUndeclared = false;
-       if (((*I)->isInIdentifierNamespace(Decl::IDNS_Tag)) || 
-           isa<TypedefDecl>(*I))
-         return *I;
-      }
-
-      return 0;
-    }
-
-    // FIXME: Decouple this from the IdentifierResolver so that we can
-    // deal with lookups into the semantic parent contexts that aren't
-    // lexical parent contexts.
-
-    IdentifierResolver::iterator
-      I = IdentifierResolver::begin(Name, LookupCtx, LookInParentCtx),
-      E = IdentifierResolver::end();
-
-    if (I == E) {
-      IdIsUndeclared = true;
-      return 0;
-    }
-    IdIsUndeclared = false;
-
-    // C++ 3.4.3p1 :
-    // During the lookup for a name preceding the :: scope resolution operator,
-    // object, function, and enumerator names are ignored. If the name found is
-    // not a class-name or namespace-name, the program is ill-formed.
-
-    for (; I != E; ++I) {
-      if (isa<TypedefDecl>(*I)) {
-        break;
-      }
-      if (((*I)->getIdentifierNamespace() & Decl::IDNS_Tag))
-        break;    
-    }
-
-    return (I != E ? *I : 0);
-  }
-} // anonymous namespace
-
 /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
 /// global scope ('::').
 Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S,
@@ -85,16 +37,10 @@
                                                     SourceLocation IdLoc,
                                                     SourceLocation CCLoc,
                                                     IdentifierInfo &II) {
-  DeclContext *DC = static_cast<DeclContext*>(SS.getScopeRep());
-  Decl *SD;
-  bool IdIsUndeclared;
-
-  if (DC)
-    SD = LookupNestedName(DC, false/*LookInParentCtx*/, &II, IdIsUndeclared,
-                         Context);
-  else
-    SD = LookupNestedName(CurContext, true/*LookInParent*/, &II, 
-                          IdIsUndeclared, Context);
+  Decl *SD = LookupParsedName(S, SS, &II,
+                              LookupCriteria(LookupCriteria::NestedNameSpecifier, 
+                                             /*RedeclarationOnly=*/false, 
+                                             /*CPlusPlus=*/true));
 
   if (SD) {
     if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
@@ -104,19 +50,29 @@
       return cast<DeclContext>(SD);
     }
 
+    // FIXME: C++0x scoped enums
+
     // Fall through to produce an error: we found something that isn't
     // a class or a namespace.
   }
 
+  // If we didn't find anything during our lookup, try again with
+  // ordinary name lookup, which can help us produce better error
+  // messages.
+  if (!SD)
+    SD = LookupParsedName(S, SS, &II,
+                          LookupCriteria(LookupCriteria::Ordinary,
+                                         /*RedeclarationOnly=*/false, 
+                                         /*CPlusPlus=*/true));
   unsigned DiagID;
-  if (!IdIsUndeclared)
+  if (SD)
     DiagID = diag::err_expected_class_or_namespace;
-  else if (DC)
+  else if (SS.isSet())
     DiagID = diag::err_typecheck_no_member;
   else
     DiagID = diag::err_undeclared_var_use;
 
-  if (DC)
+  if (SS.isSet())
     Diag(IdLoc, DiagID) << &II << SS.getRange();
   else
     Diag(IdLoc, DiagID) << &II;

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=62245&r1=62244&r2=62245&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jan 14 16:20:51 2009
@@ -205,52 +205,6 @@
   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 @@
 /// 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;
-
-        Ctx = Ctx->getParent();
-      }
-    }
-  }
+///
+/// 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");
 
-  // 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;
+  if (LookupCtx)
+    return LookupQualifiedName(const_cast<DeclContext *>(LookupCtx), Name, 
+                               LookupCriteria(Kind, !LookInParent,
+                                              getLangOptions().CPlusPlus));
+
+  // Unqualified lookup
+  return LookupName(S, Name, 
+                    LookupCriteria(Kind, !LookInParent,
+                                   getLangOptions().CPlusPlus));
 }
 
 void Sema::InitBuiltinVaListType() {
@@ -489,7 +330,7 @@
   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 @@
 
     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 @@
     // 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

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=62245&r1=62244&r2=62245&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Jan 14 16:20:51 2009
@@ -1393,7 +1393,7 @@
     // in that declarative region, it is treated as an original-namespace-name.
 
     Decl *PrevDecl =
-      LookupDecl(II, Decl::IDNS_Tag | Decl::IDNS_Ordinary, DeclRegionScope, 0,
+      LookupDecl(II, Decl::IDNS_Ordinary, DeclRegionScope, 0,
                 /*enableLazyBuiltinCreation=*/false, 
                 /*LookupInParent=*/false);
     
@@ -1454,10 +1454,18 @@
   assert(IdentLoc.isValid() && "Invalid NamespceName location.");
 
   // FIXME: This still requires lot more checks, and AST support.
+
   // Lookup namespace name.
-  DeclContext *DC = static_cast<DeclContext*>(SS.getScopeRep());
+  LookupCriteria Criteria(LookupCriteria::Namespace, /*RedeclarationOnly=*/false, 
+                          /*CPlusPlus=*/true);
+  Decl *NS = 0;
+  if (SS.isSet())
+    NS = LookupQualifiedName(static_cast<DeclContext*>(SS.getScopeRep()), 
+                             NamespcName, Criteria);
+  else
+    NS = LookupName(S, NamespcName, Criteria);
 
-  if (Decl *NS = LookupNamespaceName(NamespcName, S, DC)) {
+  if (NS) {
     assert(isa<NamespaceDecl>(NS) && "expected namespace decl");
   } else {
     Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=62245&r1=62244&r2=62245&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Jan 14 16:20:51 2009
@@ -3843,7 +3843,7 @@
     FieldDecl *MemberDecl 
       = dyn_cast_or_null<FieldDecl>(LookupDecl(OC.U.IdentInfo, 
                                                Decl::IDNS_Ordinary,
-                                               S, RD, false, false));
+                                               S, RD, false, false).getAsDecl());
     if (!MemberDecl)
       return Diag(BuiltinLoc, diag::err_typecheck_no_member)
        << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd);

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=62245&r1=62244&r2=62245&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Jan 14 16:20:51 2009
@@ -61,8 +61,7 @@
     return Diag(OpLoc, diag::err_need_header_before_typeid);
   
   IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info");
-  Decl *TypeInfoDecl = LookupDecl(TypeInfoII,
-                                  Decl::IDNS_Tag | Decl::IDNS_Ordinary,
+  Decl *TypeInfoDecl = LookupDecl(TypeInfoII, Decl::IDNS_Tag,
                                   0, StdNs, /*createBuiltins=*/false);
   RecordDecl *TypeInfoRecordDecl = dyn_cast_or_null<RecordDecl>(TypeInfoDecl);
   if (!TypeInfoRecordDecl)

Added: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=62245&view=auto

==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (added)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Wed Jan 14 16:20:51 2009
@@ -0,0 +1,422 @@
+//===--------------------- SemaLookup.cpp - Name Lookup  ------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements name lookup for C, C++, Objective-C, and
+//  Objective-C++.
+//
+//===----------------------------------------------------------------------===//
+#include "Sema.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Parse/DeclSpec.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace clang;
+
+/// 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;
+}
+
+/// @brief Constructs name lookup criteria.
+///
+/// @param K The kind of name that we're searching for.
+///
+/// @param RedeclarationOnly If true, then name lookup will only look
+/// into the current scope for names, not in parent scopes. This
+/// option should be set when we're looking to introduce a new
+/// declaration into scope.
+///
+/// @param CPlusPlus Whether we are performing C++ name lookup or not.
+Sema::LookupCriteria::LookupCriteria(NameKind K, bool RedeclarationOnly,
+                                     bool CPlusPlus)  
+  : Kind(K), AllowLazyBuiltinCreation(K == Ordinary), 
+    RedeclarationOnly(RedeclarationOnly) { 
+  switch (Kind) {
+  case Ordinary:
+    IDNS = Decl::IDNS_Ordinary;
+    if (CPlusPlus)
+      IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member;
+    break;
+
+  case Tag:
+    IDNS = Decl::IDNS_Tag;
+    break;
+
+  case Member:
+    IDNS = Decl::IDNS_Member;
+    if (CPlusPlus)
+      IDNS |= Decl::IDNS_Tag | Decl::IDNS_Ordinary;    
+    break;
+
+  case NestedNameSpecifier:
+  case Namespace:
+    IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member;
+    break;
+  }
+}
+
+/// isLookupResult - Determines whether D is a suitable lookup result
+/// according to the lookup criteria.
+bool Sema::LookupCriteria::isLookupResult(Decl *D) const {
+  switch (Kind) {
+  case Ordinary:
+  case Tag:
+  case Member:
+    return D->isInIdentifierNamespace(IDNS);
+
+  case NestedNameSpecifier:
+    return isa<TypedefDecl>(D) || D->isInIdentifierNamespace(Decl::IDNS_Tag);
+
+  case Namespace:
+    return isa<NamespaceDecl>(D);
+  }
+
+  assert(false && "isLookupResult always returns before this point");
+  return false;
+}
+
+/// @brief Determine the result of name lookup.
+Sema::LookupResult::LookupKind Sema::LookupResult::getKind() const {
+  switch (StoredKind) {
+  case SingleDecl:
+    return (reinterpret_cast<Decl *>(First) != 0)? Found : NotFound;
+
+  case OverloadedDeclFromIdResolver:
+  case OverloadedDeclFromDeclContext:
+    return FoundOverloaded;
+
+  case AmbiguousLookup:
+    return Ambiguous;
+  }
+
+  // We can't get here, but GCC complains nonetheless.
+  return Ambiguous;
+}
+
+/// @brief Converts the result of name lookup into a single (possible
+/// NULL) pointer to a declaration.
+///
+/// The resulting declaration will either be the declaration we found
+/// (if only a single declaration was found), an
+/// OverloadedFunctionDecl (if an overloaded function was found), or
+/// NULL (if no declaration was found). This conversion must not be
+/// used anywhere where name lookup could result in an ambiguity. 
+///
+/// The OverloadedFunctionDecl conversion is meant as a stop-gap
+/// solution, since it causes the OverloadedFunctionDecl to be
+/// leaked. FIXME: Eventually, there will be a better way to iterate
+/// over the set of overloaded functions returned by name lookup.
+Decl *Sema::LookupResult::getAsDecl() const {
+  switch (StoredKind) {
+  case SingleDecl:
+    return reinterpret_cast<Decl *>(First);
+
+  case OverloadedDeclFromIdResolver:
+    return MaybeConstructOverloadSet(*Context,
+                         IdentifierResolver::iterator::getFromOpaqueValue(First),
+                         IdentifierResolver::iterator::getFromOpaqueValue(Last));
+
+  case OverloadedDeclFromDeclContext:
+    return MaybeConstructOverloadSet(*Context, 
+                           reinterpret_cast<DeclContext::lookup_iterator>(First),
+                           reinterpret_cast<DeclContext::lookup_iterator>(Last));
+
+  case AmbiguousLookup:
+    assert(false && 
+           "Name lookup returned an ambiguity that could not be handled");
+    break;
+  }
+
+  return 0;
+}
+
+/// @brief Perform unqualified name lookup starting from a given
+/// scope.
+///
+/// Unqualified name lookup (C++ [basic.lookup.unqual], C99 6.2.1) is
+/// used to find names within the current scope. For example, 'x' in
+/// @code
+/// int x;
+/// int f() {
+///   return x; // unqualified name look finds 'x' in the global scope
+/// }
+/// @endcode
+///
+/// Different lookup criteria can find different names. For example, a
+/// particular scope can have both a struct and a function of the same
+/// name, and each can be found by certain lookup criteria. For more
+/// information about lookup criteria, see the documentation for the
+/// class LookupCriteria.
+///
+/// @param S        The scope from which unqualified name lookup will
+/// begin. If the lookup criteria permits, name lookup may also search
+/// in the parent scopes.
+///
+/// @param Name     The name of the entity that we are searching for.
+///
+/// @param Criteria The criteria that this routine will use to
+/// determine which names are visible and which names will be
+/// found. Note that name lookup will find a name that is visible by
+/// the given criteria, but the entity itself may not be semantically
+/// correct or even the kind of entity expected based on the
+/// lookup. For example, searching for a nested-name-specifier name
+/// might result in an EnumDecl, which is visible but is not permitted
+/// as a nested-name-specifier in C++03.
+///
+/// @returns The result of name lookup, which includes zero or more
+/// declarations and possibly additional information used to diagnose
+/// ambiguities.
+Sema::LookupResult 
+Sema::LookupName(Scope *S, DeclarationName Name, LookupCriteria Criteria) {
+  if (!Name) return LookupResult(Context, 0);
+
+  if (!getLangOptions().CPlusPlus) {
+    // Unqualified name lookup in C/Objective-C is purely lexical, so
+    // search in the declarations attached to the name.
+
+    // 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, !Criteria.RedeclarationOnly);
+    
+    // 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 (Criteria.isLookupResult(*I))
+        return LookupResult(Context, *I);
+  } else {
+    // Unqualified name lookup 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.
+
+    // FIXME: does "true" for LookInParentCtx actually make sense?
+    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.
+      for (; I != IEnd && S->isDeclScope(*I); ++I) {
+        if (Criteria.isLookupResult(*I)) {
+          // 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 (!S->isDeclScope(*LastI))
+              break;
+          }
+          return LookupResult(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.
+      // FIXME: We're performing redundant lookups here, where the
+      // scope stack mirrors the semantic nested of classes and
+      // namespaces. We can save some work by checking the lexical
+      // scope against the semantic scope and avoiding any lookups
+      // when they are the same.
+      // FIXME: In some cases, we know that every name that could be
+      // found by this qualified name lookup will also be on the
+      // identifier chain. For example, inside a class without any
+      // base classes, we never need to perform qualified lookup
+      // because all of the members are on top of the identifier
+      // chain. However, we cannot perform this optimization when the
+      // lexical and semantic scopes don't line up, e.g., in an
+      // out-of-line member definition.
+      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.
+        if (LookupResult Result = LookupQualifiedName(Ctx, Name, Criteria))
+          return Result;
+        
+        if (Criteria.RedeclarationOnly && !Ctx->isTransparentContext())
+          return LookupResult(Context, 0);
+
+        Ctx = Ctx->getParent();
+      }
+    }
+  }
+
+  // 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 (Criteria.Kind == LookupCriteria::Ordinary) {
+    IdentifierInfo *II = Name.getAsIdentifierInfo();
+    if (Criteria.AllowLazyBuiltinCreation && II) {
+      // If this is a builtin on this (or all) targets, create the decl.
+      if (unsigned BuiltinID = II->getBuiltinID())
+        return LookupResult(Context,
+                            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 LookupResult(Context, IDI->second);
+      ObjCAliasTy::iterator I = ObjCAliasDecls.find(II);
+      if (I != ObjCAliasDecls.end())
+        return LookupResult(Context, I->second->getClassInterface());
+    }
+  }
+  return LookupResult(Context, 0);
+}
+
+/// @brief Perform qualified name lookup into a given context.
+///
+/// Qualified name lookup (C++ [basic.lookup.qual]) is used to find
+/// names when the context of those names is explicit specified, e.g.,
+/// "std::vector" or "x->member".
+///
+/// Different lookup criteria can find different names. For example, a
+/// particular scope can have both a struct and a function of the same
+/// name, and each can be found by certain lookup criteria. For more
+/// information about lookup criteria, see the documentation for the
+/// class LookupCriteria.
+///
+/// @param LookupCtx The context in which qualified name lookup will
+/// search. If the lookup criteria permits, name lookup may also search
+/// in the parent contexts or (for C++ classes) base classes.
+///
+/// @param Name     The name of the entity that we are searching for.
+///
+/// @param Criteria The criteria that this routine will use to
+/// determine which names are visible and which names will be
+/// found. Note that name lookup will find a name that is visible by
+/// the given criteria, but the entity itself may not be semantically
+/// correct or even the kind of entity expected based on the
+/// lookup. For example, searching for a nested-name-specifier name
+/// might result in an EnumDecl, which is visible but is not permitted
+/// as a nested-name-specifier in C++03.
+///
+/// @returns The result of name lookup, which includes zero or more
+/// declarations and possibly additional information used to diagnose
+/// ambiguities.
+Sema::LookupResult
+Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name,
+                          LookupCriteria Criteria) {
+  assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context");
+  
+  if (!Name) return LookupResult(Context, 0);
+
+  // If we're performing qualified name lookup (e.g., lookup into a
+  // struct), find fields as part of ordinary name lookup.
+  if (Criteria.Kind == LookupCriteria::Ordinary)
+    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);
+}
+
+/// @brief Performs name lookup for a name that was parsed in the
+/// source code, and may contain a C++ scope specifier.
+///
+/// This routine is a convenience routine meant to be called from
+/// contexts that receive a name and an optional C++ scope specifier
+/// (e.g., "N::M::x"). It will then perform either qualified or
+/// unqualified name lookup (with LookupQualifiedName or LookupName,
+/// respectively) on the given name and return those results.
+///
+/// @param S        The scope from which unqualified name lookup will
+/// begin.
+/// 
+/// @param SS       An optional C++ scope-specified, e.g., "::N::M".
+///
+/// @param Name     The name of the entity that name lookup will
+/// search for.
+///
+/// @param Criteria The criteria that will determine which entities
+/// are visible to name lookup.
+///
+/// @returns The result of qualified or unqualified name lookup.
+Sema::LookupResult
+Sema::LookupParsedName(Scope *S, const CXXScopeSpec &SS, 
+                       DeclarationName Name, LookupCriteria Criteria) {
+  if (SS.isSet())
+    return LookupQualifiedName(static_cast<DeclContext *>(SS.getScopeRep()),
+                               Name, Criteria);
+
+  return LookupName(S, Name, Criteria);
+}
+
+

Modified: cfe/trunk/test/Parser/cxx-using-directive.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-using-directive.cpp?rev=62245&r1=62244&r2=62245&view=diff

==============================================================================
--- cfe/trunk/test/Parser/cxx-using-directive.cpp (original)
+++ cfe/trunk/test/Parser/cxx-using-directive.cpp Wed Jan 14 16:20:51 2009
@@ -31,3 +31,10 @@
 using namespace ::A // expected-error{{expected namespace name}}
                     B ; // expected-error{{expected ';' after namespace name}}
 
+void test_nslookup() {
+  int B;
+  class C;
+  using namespace B;
+  using namespace C;
+}
+

Modified: cfe/trunk/test/SemaCXX/qualified-id-lookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/qualified-id-lookup.cpp?rev=62245&r1=62244&r2=62245&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/qualified-id-lookup.cpp (original)
+++ cfe/trunk/test/SemaCXX/qualified-id-lookup.cpp Wed Jan 14 16:20:51 2009
@@ -49,7 +49,7 @@
 namespace N {
   float& f1(int x) {
     N::f1::type& i1 = x;
-    // FIXME: currently fails    f1::type& i2 = x;
+    f1::type& i2 = x;
   }
 
   struct f2 {





More information about the cfe-commits mailing list