[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/SemaL

Daniel Dunbar daniel at zuster.org
Fri Jan 16 15:16:34 PST 2009


Sorry to be incredibly boring, but my tester is pointing at this for a
2.13% regression in -fsyntax-only on Cocoa.h. Necessary or avoidable?

 - Daniel

On Wed, Jan 14, 2009 at 2:20 PM, Douglas Gregor <dgregor at apple.com> wrote:
> 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 {
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>



More information about the cfe-commits mailing list