diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-12-11 16:49:14 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-12-11 16:49:14 +0000 |
commit | 91f84216f78f52f9aae422a2a034c1c7eaa098ce (patch) | |
tree | fc0c4c5b68ca37cab2115e3d2564ed36cb016b69 /clang/lib/Sema | |
parent | 32bfb5de3408728c5da5101db863098a8f854848 (diff) | |
download | bcm5719-llvm-91f84216f78f52f9aae422a2a034c1c7eaa098ce.tar.gz bcm5719-llvm-91f84216f78f52f9aae422a2a034c1c7eaa098ce.zip |
Unifies the name-lookup mechanisms used in various parts of the AST
and separates lexical name lookup from qualified name lookup. In
particular:
* Make DeclContext the central data structure for storing and
looking up declarations within existing declarations, e.g., members
of structs/unions/classes, enumerators in C++0x enums, members of
C++ namespaces, and (later) members of Objective-C
interfaces/implementations. DeclContext uses a lazily-constructed
data structure optimized for fast lookup (array for small contexts,
hash table for larger contexts).
* Implement C++ qualified name lookup in terms of lookup into
DeclContext.
* Implement C++ unqualified name lookup in terms of
qualified+unqualified name lookup (since unqualified lookup is not
purely lexical in C++!)
* Limit the use of the chains of declarations stored in
IdentifierInfo to those names declared lexically.
* Eliminate CXXFieldDecl, collapsing its behavior into
FieldDecl. (FieldDecl is now a ScopedDecl).
* Make RecordDecl into a DeclContext and eliminates its
Members/NumMembers fields (since one can just iterate through the
DeclContext to get the fields).
llvm-svn: 60878
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/CXXFieldCollector.h | 10 | ||||
-rw-r--r-- | clang/lib/Sema/IdentifierResolver.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/IdentifierResolver.h | 3 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 11 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCXXScopeSpec.cpp | 25 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 297 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 73 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 32 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 28 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 23 |
14 files changed, 343 insertions, 183 deletions
diff --git a/clang/lib/Sema/CXXFieldCollector.h b/clang/lib/Sema/CXXFieldCollector.h index 44d482692b7..69d13515fa6 100644 --- a/clang/lib/Sema/CXXFieldCollector.h +++ b/clang/lib/Sema/CXXFieldCollector.h @@ -18,15 +18,15 @@ #include "llvm/ADT/SmallVector.h" namespace clang { - class CXXFieldDecl; + class FieldDecl; /// CXXFieldCollector - Used to keep track of CXXFieldDecls during parsing of /// C++ classes. class CXXFieldCollector { - /// Fields - Contains all CXXFieldDecls collected during parsing of a C++ + /// Fields - Contains all FieldDecls collected during parsing of a C++ /// class. When a nested class is entered, its fields are appended to the /// fields of its parent class, when it is exited its fields are removed. - llvm::SmallVector<CXXFieldDecl*, 32> Fields; + llvm::SmallVector<FieldDecl*, 32> Fields; /// FieldCount - Each entry represents the number of fields collected during /// the parsing of a C++ class. When a nested class is entered, a new field @@ -52,7 +52,7 @@ public: void StartClass() { FieldCount.push_back(0); } /// Add - Called by Sema::ActOnCXXMemberDeclarator. - void Add(CXXFieldDecl *D) { + void Add(FieldDecl *D) { Fields.push_back(D); ++FieldCount.back(); } @@ -62,7 +62,7 @@ public: /// getCurFields - Pointer to array of fields added to the currently parsed /// class. - CXXFieldDecl **getCurFields() { return &*(Fields.end() - getCurNumFields()); } + FieldDecl **getCurFields() { return &*(Fields.end() - getCurNumFields()); } /// FinishClass - Called by Sema::ActOnFinishCXXClassDef. void FinishClass() { diff --git a/clang/lib/Sema/IdentifierResolver.cpp b/clang/lib/Sema/IdentifierResolver.cpp index 5fb18f6cef4..4441503528a 100644 --- a/clang/lib/Sema/IdentifierResolver.cpp +++ b/clang/lib/Sema/IdentifierResolver.cpp @@ -51,9 +51,6 @@ public: DeclContext *IdentifierResolver::LookupContext::getContext(Decl *D) { DeclContext *Ctx; - if (CXXFieldDecl *FD = dyn_cast<CXXFieldDecl>(D)) - return FD->getParent(); - if (EnumConstantDecl *EnumD = dyn_cast<EnumConstantDecl>(D)) { Ctx = EnumD->getDeclContext()->getParent(); } else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) @@ -149,7 +146,7 @@ IdentifierResolver::~IdentifierResolver() { /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns /// true if 'D' belongs to the given declaration context. bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, - Scope *S) const { + ASTContext &Context, Scope *S) const { if (Ctx->isFunctionOrMethod()) { if (S->isDeclScope(D)) return true; @@ -169,7 +166,7 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, return false; } - return LookupContext(D) == LookupContext(Ctx); + return LookupContext(D) == LookupContext(Ctx->getPrimaryContext(Context)); } /// AddDecl - Link the decl to its shadowed decl chain. diff --git a/clang/lib/Sema/IdentifierResolver.h b/clang/lib/Sema/IdentifierResolver.h index 9d785133957..bc9da6126d0 100644 --- a/clang/lib/Sema/IdentifierResolver.h +++ b/clang/lib/Sema/IdentifierResolver.h @@ -208,7 +208,8 @@ public: /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns /// true if 'D' belongs to the given declaration context. - bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = 0) const; + bool isDeclInScope(Decl *D, DeclContext *Ctx, ASTContext &Context, + Scope *S = 0) const; /// AddDecl - Link the decl to its shadowed decl chain. void AddDecl(NamedDecl *D); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 13226c0b0ea..650b8d7d7dd 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -68,7 +68,7 @@ static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) { void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { TUScope = S; - PushDeclContext(Context.getTranslationUnitDecl()); + PushDeclContext(S, Context.getTranslationUnitDecl()); if (!PP.getLangOptions().ObjC1) return; // Synthesize "typedef struct objc_selector *SEL;" diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 4a8f83084dd..97e8507e9b3 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -300,10 +300,10 @@ public: IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr); - virtual void ActOnDefs(Scope *S, SourceLocation DeclStart, + virtual void ActOnDefs(Scope *S, DeclTy *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, llvm::SmallVectorImpl<DeclTy*> &Decls); - virtual DeclTy *ActOnField(Scope *S, SourceLocation DeclStart, + virtual DeclTy *ActOnField(Scope *S, DeclTy *TagD, SourceLocation DeclStart, Declarator &D, ExprTy *BitfieldWidth); virtual DeclTy *ActOnIvar(Scope *S, SourceLocation DeclStart, @@ -326,7 +326,7 @@ public: DeclContext *getContainingDC(DeclContext *DC); /// Set the current declaration context until it gets popped. - void PushDeclContext(DeclContext *DC); + void PushDeclContext(Scope *S, DeclContext *DC); void PopDeclContext(); /// getCurFunctionDecl - If inside of a function body, this returns a pointer @@ -351,7 +351,7 @@ public: /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns /// true if 'D' belongs to the given declaration context. bool isDeclInScope(Decl *D, DeclContext *Ctx, Scope *S = 0) { - return IdResolver.isDeclInScope(D, Ctx, S); + return IdResolver.isDeclInScope(D, Ctx, Context, S); } /// Subroutines of ActOnDeclarator(). @@ -478,7 +478,8 @@ public: /// More parsing and symbol table subroutines... Decl *LookupDecl(DeclarationName Name, unsigned NSI, Scope *S, const DeclContext *LookupCtx = 0, - bool enableLazyBuiltinCreation = true); + bool enableLazyBuiltinCreation = true, + bool LookInParent = true); ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *Id); ScopedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S); diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 1f92b6f6aab..d01552c373b 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -20,7 +20,25 @@ using namespace clang; namespace {
Decl *LookupNestedName(DeclContext *LookupCtx, bool LookInParentCtx,
- DeclarationName Name, bool &IdIsUndeclared) {
+ DeclarationName Name, bool &IdIsUndeclared,
+ ASTContext &Context) {
+ if (LookupCtx && !LookInParentCtx) {
+ IdIsUndeclared = true;
+ for (DeclContext::lookup_const_result I = LookupCtx->lookup(Context, Name);
+ I.first != I.second; ++I.first) {
+ IdIsUndeclared = false;
+ if (((*I.first)->getIdentifierNamespace() & Decl::IDNS_Tag) &&
+ !isa<EnumDecl>(*I.first))
+ return *I.first;
+ }
+
+ 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();
@@ -73,10 +91,11 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, bool IdIsUndeclared;
if (DC)
- SD = LookupNestedName(DC, false/*LookInParentCtx*/, &II, IdIsUndeclared);
+ SD = LookupNestedName(DC, false/*LookInParentCtx*/, &II, IdIsUndeclared,
+ Context);
else
SD = LookupNestedName(CurContext, true/*LookInParent*/, &II,
- IdIsUndeclared);
+ IdIsUndeclared, Context);
if (SD) {
if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 41587c5aee6..b541f59a223 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -74,14 +74,16 @@ DeclContext *Sema::getContainingDC(DeclContext *DC) { return DC->getLexicalParent(); } -void Sema::PushDeclContext(DeclContext *DC) { +void Sema::PushDeclContext(Scope *S, DeclContext *DC) { assert(getContainingDC(DC) == CurContext && "The next DeclContext should be lexically contained in the current one."); CurContext = DC; + S->setEntity(DC); } void Sema::PopDeclContext() { assert(CurContext && "DeclContext imbalance!"); + CurContext = getContainingDC(CurContext); } @@ -97,53 +99,90 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S) { // in this case the class name or enumeration name is hidden. if (TagDecl *TD = dyn_cast<TagDecl>(D)) { // We are pushing the name of a tag (enum or class). - IdentifierResolver::iterator - I = IdResolver.begin(TD->getIdentifier(), - TD->getDeclContext(), false/*LookInParentCtx*/); - if (I != IdResolver.end() && isDeclInScope(*I, TD->getDeclContext(), S)) { - // There is already a declaration with the same name in the same - // scope. It must be found before we find the new declaration, - // so swap the order on the shadowed declaration chain. - - IdResolver.AddShadowedDecl(TD, *I); - return; + if (CurContext == TD->getDeclContext()) { + // We're pushing the tag into the current context, which might + // require some reshuffling in the identifier resolver. + IdentifierResolver::iterator + I = IdResolver.begin(TD->getIdentifier(), CurContext, + false/*LookInParentCtx*/); + if (I != IdResolver.end()) { + // There is already a declaration with the same name in the same + // scope. It must be found before we find the new declaration, + // so swap the order on the shadowed declaration chain. + IdResolver.AddShadowedDecl(TD, *I); + + // Add this declaration to the current context. + CurContext->addDecl(Context, TD); + + return; + } } } else if (getLangOptions().CPlusPlus && isa<FunctionDecl>(D)) { - FunctionDecl *FD = cast<FunctionDecl>(D); // We are pushing the name of a function, which might be an // overloaded name. - IdentifierResolver::iterator - I = IdResolver.begin(FD->getDeclName(), - FD->getDeclContext(), false/*LookInParentCtx*/); - if (I != IdResolver.end() && - IdResolver.isDeclInScope(*I, FD->getDeclContext(), S) && - (isa<OverloadedFunctionDecl>(*I) || isa<FunctionDecl>(*I))) { - // There is already a declaration with the same name in the same - // scope. It must be a function or an overloaded function. - OverloadedFunctionDecl* Ovl = dyn_cast<OverloadedFunctionDecl>(*I); + FunctionDecl *FD = cast<FunctionDecl>(D); + Decl *Prev = LookupDecl(FD->getDeclName(), Decl::IDNS_Ordinary, S, + FD->getDeclContext(), false, false); + if (Prev && (isa<OverloadedFunctionDecl>(Prev) || isa<FunctionDecl>(Prev))) { + // There is already a declaration with the same name in + // the same scope. It must be a function or an overloaded + // function. + OverloadedFunctionDecl* Ovl = dyn_cast<OverloadedFunctionDecl>(Prev); if (!Ovl) { // We haven't yet overloaded this function. Take the existing // FunctionDecl and put it into an OverloadedFunctionDecl. Ovl = OverloadedFunctionDecl::Create(Context, FD->getDeclContext(), FD->getDeclName()); - Ovl->addOverload(dyn_cast<FunctionDecl>(*I)); + Ovl->addOverload(dyn_cast<FunctionDecl>(Prev)); - // Remove the name binding to the existing FunctionDecl... - IdResolver.RemoveDecl(*I); - - // ... and put the OverloadedFunctionDecl in its place. + // If there is an name binding for the existing FunctionDecl, + // remove it. + for (IdentifierResolver::iterator I + = IdResolver.begin(FD->getDeclName(), FD->getDeclContext(), + false/*LookInParentCtx*/); + I != IdResolver.end(); ++I) { + if (*I == Prev) { + IdResolver.RemoveDecl(*I); + S->RemoveDecl(*I); + break; + } + } + + // Add the name binding for the OverloadedFunctionDecl. IdResolver.AddDecl(Ovl); + + // Update the context with the newly-created overloaded + // function set. + FD->getDeclContext()->insert(Context, Ovl); + + S->AddDecl(Ovl); } + // We added this function declaration to the scope earlier, but + // we don't want it there because it is part of the overloaded + // function declaration. + S->RemoveDecl(FD); + // We have an OverloadedFunctionDecl. Add the new FunctionDecl // to its list of overloads. Ovl->addOverload(FD); - return; + // Add this new function declaration to the declaration context. + CurContext->addDecl(Context, FD, false); + + return; } } + if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D)) + CurContext->addDecl(Context, SD); + else { + // Other kinds of declarations don't currently have a context + // where they need to be inserted. + } + + IdResolver.AddDecl(D); } @@ -157,25 +196,13 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { Decl *TmpD = static_cast<Decl*>(*I); assert(TmpD && "This decl didn't get pushed??"); - if (isa<CXXFieldDecl>(TmpD)) continue; + assert(isa<NamedDecl>(TmpD) && "Decl isn't NamedDecl?"); + NamedDecl *D = cast<NamedDecl>(TmpD); - assert(isa<ScopedDecl>(TmpD) && "Decl isn't ScopedDecl?"); - ScopedDecl *D = cast<ScopedDecl>(TmpD); - - IdentifierInfo *II = D->getIdentifier(); - if (!II) continue; - - // We only want to remove the decls from the identifier decl chains for - // local scopes, when inside a function/method. - // However, we *always* remove template parameters, since they are - // purely lexically scoped (and can never be found by qualified - // name lookup). - if (S->getFnParent() != 0 || isa<TemplateTypeParmDecl>(D)) - IdResolver.RemoveDecl(D); - - // Chain this decl to the containing DeclContext. - D->setNext(CurContext->getDeclChain()); - CurContext->setDeclChain(D); + if (!D->getDeclName()) continue; + + // Remove this name from our lexical scope. + IdResolver.RemoveDecl(D); } } @@ -193,21 +220,76 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *Id) { /// namespace. Decl *Sema::LookupDecl(DeclarationName Name, unsigned NSI, Scope *S, const DeclContext *LookupCtx, - bool enableLazyBuiltinCreation) { + bool enableLazyBuiltinCreation, + bool LookInParent) { if (!Name) return 0; unsigned NS = NSI; if (getLangOptions().CPlusPlus && (NS & Decl::IDNS_Ordinary)) NS |= Decl::IDNS_Tag; - IdentifierResolver::iterator - I = LookupCtx ? IdResolver.begin(Name, LookupCtx, false/*LookInParentCtx*/) - : IdResolver.begin(Name, CurContext, true/*LookInParentCtx*/); - // 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)->getIdentifierNamespace() & NS) - return *I; + if (LookupCtx) { + assert(getLangOptions().CPlusPlus && "No qualified name lookup in C"); + + // Perform qualified name lookup into the LookupCtx. + // FIXME: Will need to look into base classes and such. + for (DeclContext::lookup_const_result I = LookupCtx->lookup(Context, Name); + I.first != I.second; ++I.first) + if ((*I.first)->getIdentifierNamespace() & NS) + return *I.first; + } else if (getLangOptions().CPlusPlus && + (NS & (Decl::IDNS_Ordinary | Decl::IDNS_Tag))) { + // 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)->getIdentifierNamespace() & NS) + return *I; + + // 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->isCXXRecord())) { + // Look for declarations of this name in this scope. + for (DeclContext::lookup_const_result I = Ctx->lookup(Context, Name); + I.first != I.second; ++I.first) { + // FIXME: Cache this result in the IdResolver + if ((*I.first)->getIdentifierNamespace() & NS) + return *I.first; + } + + Ctx = Ctx->getParent(); + } + + if (!LookInParent) + return 0; + } + } else { + // Unqualified name lookup for names in our lexical scope. This + // name lookup suffices when all of the potential names are known + // to have been pushed onto the IdResolver, as happens in C + // (always) and in C++ for names in the "label" namespace. + assert(!LookupCtx && "Can't perform qualified name lookup here"); + IdentifierResolver::iterator I + = IdResolver.begin(Name, CurContext, 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)->getIdentifierNamespace() & NS) + return *I; + } // 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 @@ -826,7 +908,8 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { // The scope passed in may not be a decl scope. Zip up the scope tree until // we find one that is. - while ((S->getFlags() & Scope::DeclScope) == 0) + while ((S->getFlags() & Scope::DeclScope) == 0 || + (S->getFlags() & Scope::TemplateParamScope) != 0) S = S->getParent(); DeclContext *DC; @@ -854,6 +937,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { // No previous declaration in the qualifying scope. Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member) << Name << D.getCXXScopeSpec().getRange(); + InvalidDecl = true; } else if (!CurContext->Encloses(DC)) { // The qualifying scope doesn't enclose the original declaration. // Emit diagnostic based on current scope. @@ -865,6 +949,7 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { Diag(L, diag::err_invalid_declarator_scope) << Name << cast<NamedDecl>(DC)->getDeclName() << R; } + InvalidDecl = true; } } @@ -1127,23 +1212,42 @@ Sema::ActOnDeclarator(Scope *S, Declarator &D, DeclTy *lastDecl) { if (OldDecl == PrevDecl) { // Remove the name binding for the previous - // declaration. We'll add the binding back later, but then - // it will refer to the new declaration (which will - // contain more information). - IdResolver.RemoveDecl(cast<NamedDecl>(PrevDecl)); + // declaration. + if (S->isDeclScope(PrevDecl)) { + IdResolver.RemoveDecl(cast<NamedDecl>(PrevDecl)); + S->RemoveDecl(PrevDecl); + } + + // Introduce the new binding for this declaration. + IdResolver.AddDecl(NewFD); + if (getLangOptions().CPlusPlus && NewFD->getParent()) + NewFD->getParent()->insert(Context, NewFD); + + // Add the redeclaration to the current scope, since we'll + // be skipping PushOnScopeChains. + S->AddDecl(NewFD); } else { // We need to update the OverloadedFunctionDecl with the // latest declaration of this function, so that name // lookup will always refer to the latest declaration of // this function. *MatchedDecl = NewFD; + } - // Add the redeclaration to the current scope, since we'll - // be skipping PushOnScopeChains. - S->AddDecl(NewFD); + if (getLangOptions().CPlusPlus) { + // Add this declaration to the current context. + CurContext->addDecl(Context, NewFD, false); - return NewFD; + // Check default arguments now that we have merged decls. + CheckCXXDefaultArguments(NewFD); } + + // Set the lexical context. If the declarator has a C++ + // scope specifier, the lexical context will be different + // from the semantic context. + NewFD->setLexicalDeclContext(CurContext); + + return NewFD; } } } @@ -2071,7 +2175,7 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { parmDeclType = Context.getArrayDecayedType(parmDeclType); } else if (parmDeclType->isFunctionType()) parmDeclType = Context.getPointerType(parmDeclType); - + ParmVarDecl *New = ParmVarDecl::Create(Context, CurContext, D.getIdentifierLoc(), II, parmDeclType, StorageClass, @@ -2079,9 +2183,11 @@ Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (D.getInvalidType()) New->setInvalidDecl(); - + + // Add the parameter declaration into this scope. + S->AddDecl(New); if (II) - PushOnScopeChains(New, S); + IdResolver.AddDecl(New); ProcessDeclAttributes(New, D); return New; @@ -2133,7 +2239,7 @@ Sema::DeclTy *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclTy *D) { Diag(Definition->getLocation(), diag::note_previous_definition); } - PushDeclContext(FD); + PushDeclContext(FnBodyScope, FD); // Check the validity of our function parameters CheckParmsForFunctionDef(FD); @@ -2573,17 +2679,19 @@ Sema::DeclTy *Sema::ActOnTagStruct(Scope *S, TagDecl::TagKind Kind, TagKind TK, /// Collect the instance variables declared in an Objective-C object. Used in /// the creation of structures from objects using the @defs directive. -static void CollectIvars(ObjCInterfaceDecl *Class, ASTContext& Ctx, +static void CollectIvars(ObjCInterfaceDecl *Class, RecordDecl *Record, + ASTContext& Ctx, llvm::SmallVectorImpl<Sema::DeclTy*> &ivars) { if (Class->getSuperClass()) - CollectIvars(Class->getSuperClass(), Ctx, ivars); + CollectIvars(Class->getSuperClass(), Record, Ctx, ivars); // For each ivar, create a fresh ObjCAtDefsFieldDecl. for (ObjCInterfaceDecl::ivar_iterator I=Class->ivar_begin(), E=Class->ivar_end(); I!=E; ++I) { ObjCIvarDecl* ID = *I; - ivars.push_back(ObjCAtDefsFieldDecl::Create(Ctx, ID->getLocation(), + ivars.push_back(ObjCAtDefsFieldDecl::Create(Ctx, Record, + ID->getLocation(), ID->getIdentifier(), ID->getType(), ID->getBitWidth())); @@ -2592,7 +2700,7 @@ static void CollectIvars(ObjCInterfaceDecl *Class, ASTContext& Ctx, /// Called whenever @defs(ClassName) is encountered in the source. Inserts the /// instance variables of ClassName into Decls. -void Sema::ActOnDefs(Scope *S, SourceLocation DeclStart, +void Sema::ActOnDefs(Scope *S, DeclTy *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, llvm::SmallVectorImpl<DeclTy*> &Decls) { // Check that ClassName is a valid class @@ -2602,7 +2710,17 @@ void Sema::ActOnDefs(Scope *S, SourceLocation DeclStart, return; } // Collect the instance variables - CollectIvars(Class, Context, Decls); + CollectIvars(Class, dyn_cast<RecordDecl>((Decl*)TagD), Context, Decls); + + // Introduce all of these fields into the appropriate scope. + for (llvm::SmallVectorImpl<DeclTy*>::iterator D = Decls.begin(); + D != Decls.end(); ++D) { + FieldDecl *FD = cast<FieldDecl>((Decl*)*D); + if (getLangOptions().CPlusPlus) + PushOnScopeChains(cast<FieldDecl>(FD), S); + else if (RecordDecl *Record = dyn_cast<RecordDecl>((Decl*)TagD)) + Record->addDecl(Context, FD); + } } /// TryToFixInvalidVariablyModifiedType - Helper method to turn variable array @@ -2657,12 +2775,13 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, /// ActOnField - Each field of a struct/union/class is passed into this in order /// to create a FieldDecl object for it. -Sema::DeclTy *Sema::ActOnField(Scope *S, +Sema::DeclTy *Sema::ActOnField(Scope *S, DeclTy *TagD, SourceLocation DeclStart, Declarator &D, ExprTy *BitfieldWidth) { IdentifierInfo *II = D.getIdentifier(); Expr *BitWidth = (Expr*)BitfieldWidth; SourceLocation Loc = DeclStart; + RecordDecl *Record = (RecordDecl *)TagD; if (II) Loc = D.getIdentifierLoc(); // FIXME: Unnamed fields can be handled in various different ways, for @@ -2699,22 +2818,24 @@ Sema::DeclTy *Sema::ActOnField(Scope *S, // FIXME: Chain fielddecls together. FieldDecl *NewFD; - if (getLangOptions().CPlusPlus) { - // FIXME: Replace CXXFieldDecls with FieldDecls for simple structs. - NewFD = CXXFieldDecl::Create(Context, cast<CXXRecordDecl>(CurContext), - Loc, II, T, - D.getDeclSpec().getStorageClassSpec() == - DeclSpec::SCS_mutable, BitWidth); - if (II) - PushOnScopeChains(NewFD, S); - } - else - NewFD = FieldDecl::Create(Context, Loc, II, T, BitWidth); - + // FIXME: We don't want CurContext for C, do we? No, we'll need some + // other way to determine the current RecordDecl. + NewFD = FieldDecl::Create(Context, Record, + Loc, II, T, BitWidth, + D.getDeclSpec().getStorageClassSpec() == + DeclSpec::SCS_mutable, + /*PrevDecl=*/0); + ProcessDeclAttributes(NewFD, D); if (D.getInvalidType() || InvalidDecl) NewFD->setInvalidDecl(); + + if (II && getLangOptions().CPlusPlus) + PushOnScopeChains(NewFD, S); + else + Record->addDecl(Context, NewFD); + return NewFD; } @@ -2921,7 +3042,7 @@ void Sema::ActOnFields(Scope* S, // Okay, we successfully defined 'Record'. if (Record) { - Record->defineBody(Context, &RecFields[0], RecFields.size()); + Record->completeDefinition(Context); // If this is a C++ record, HandleTagDeclDefinition will be invoked in // Sema::ActOnFinishCXXClassDef. if (!isa<CXXRecordDecl>(Record)) @@ -3189,7 +3310,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, DeclTy *EnumDeclX, ECD->setType(NewTy); } - Enum->defineElements(EltList, BestType); + Enum->completeDefinition(Context, BestType); Consumer.HandleTagDeclDefinition(Enum); } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index bff650db5fe..5c2b49472b1 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -904,8 +904,10 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr, // FIXME: This isn't supposed to be restricted to pointers, but otherwise // we might silently generate incorrect code; see following code - for (int i = 0; i < RD->getNumMembers(); i++) { - if (!RD->getMember(i)->getType()->isPointerType()) { + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + if (!Field->getType()->isPointerType()) { S.Diag(Attr.getLoc(), diag::warn_transparent_union_nonpointer); return; } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index bedf3f7d6b6..31ecfbabd29 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -382,7 +382,7 @@ void Sema::ActOnBaseSpecifiers(DeclTy *ClassDecl, BaseTy **Bases, /// definition, when on C++. void Sema::ActOnStartCXXClassDef(Scope *S, DeclTy *D, SourceLocation LBrace) { CXXRecordDecl *Dcl = cast<CXXRecordDecl>(static_cast<Decl *>(D)); - PushDeclContext(Dcl); + PushDeclContext(S, Dcl); FieldCollector->StartClass(); if (Dcl->getIdentifier()) { @@ -486,7 +486,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, bool InvalidDecl = false; if (isInstField) - Member = static_cast<Decl*>(ActOnField(S, Loc, D, BitWidth)); + Member = static_cast<Decl*>(ActOnField(S, cast<CXXRecordDecl>(CurContext), + Loc, D, BitWidth)); else Member = static_cast<Decl*>(ActOnDeclarator(S, D, LastInGroup)); @@ -593,7 +594,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Member->setInvalidDecl(); if (isInstField) { - FieldCollector->Add(cast<CXXFieldDecl>(Member)); + FieldCollector->Add(cast<FieldDecl>(Member)); return LastInGroup; } return Member; @@ -632,7 +633,10 @@ Sema::ActOnMemInitializer(DeclTy *ConstructorD, // mem-initializer-id for the hidden base class may be specified // using a qualified name. ] // Look for a member, first. - CXXFieldDecl *Member = ClassDecl->getMember(MemberOrBase); + FieldDecl *Member = 0; + DeclContext::lookup_result Result = ClassDecl->lookup(Context, MemberOrBase); + if (Result.first != Result.second) + Member = dyn_cast<FieldDecl>(*Result.first); // FIXME: Handle members of an anonymous union. @@ -1251,43 +1255,42 @@ Sema::DeclTy *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, // in that declarative region, it is treated as an original-namespace-name. Decl *PrevDecl = - LookupDecl(II, Decl::IDNS_Tag | Decl::IDNS_Ordinary, DeclRegionScope, 0, - /*enableLazyBuiltinCreation=*/false); - - if (PrevDecl && isDeclInScope(PrevDecl, CurContext, DeclRegionScope)) { - if (NamespaceDecl *OrigNS = dyn_cast<NamespaceDecl>(PrevDecl)) { - // This is an extended namespace definition. - // Attach this namespace decl to the chain of extended namespace - // definitions. - NamespaceDecl *NextNS = OrigNS; - while (NextNS->getNextNamespace()) - NextNS = NextNS->getNextNamespace(); - - NextNS->setNextNamespace(Namespc); - Namespc->setOriginalNamespace(OrigNS); - - // We won't add this decl to the current scope. We want the namespace - // name to return the original namespace decl during a name lookup. - } else { - // This is an invalid name redefinition. - Diag(Namespc->getLocation(), diag::err_redefinition_different_kind) - << Namespc->getDeclName(); - Diag(PrevDecl->getLocation(), diag::note_previous_definition); - Namespc->setInvalidDecl(); - // Continue on to push Namespc as current DeclContext and return it. + LookupDecl(II, Decl::IDNS_Tag | Decl::IDNS_Ordinary, DeclRegionScope, 0, + /*enableLazyBuiltinCreation=*/false, + /*LookupInParent=*/false); + + if (NamespaceDecl *OrigNS = dyn_cast_or_null<NamespaceDecl>(PrevDecl)) { + // This is an extended namespace definition. + // Attach this namespace decl to the chain of extended namespace + // definitions. + OrigNS->setNextNamespace(Namespc); + Namespc->setOriginalNamespace(OrigNS->getOriginalNamespace()); + + // Remove the previous declaration from the scope. + if (DeclRegionScope->isDeclScope(OrigNS)) { + IdResolver.RemoveDecl(OrigNS); + DeclRegionScope->RemoveDecl(OrigNS); } - } else { - // This namespace name is declared for the first time. - PushOnScopeChains(Namespc, DeclRegionScope); - } - } - else { + } else if (PrevDecl) { + // This is an invalid name redefinition. + Diag(Namespc->getLocation(), diag::err_redefinition_different_kind) + << Namespc->getDeclName(); + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + Namespc->setInvalidDecl(); + // Continue on to push Namespc as current DeclContext and return it. + } + + PushOnScopeChains(Namespc, DeclRegionScope); + } else { // FIXME: Handle anonymous namespaces } // Although we could have an invalid decl (i.e. the namespace name is a // redefinition), push it as current DeclContext and try to continue parsing. - PushDeclContext(Namespc->getOriginalNamespace()); + // FIXME: We should be able to push Namespc here, so that the + // each DeclContext for the namespace has the declarations + // that showed up in that particular namespace definition. + PushDeclContext(NamespcScope, Namespc); return Namespc; } diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index fa73bcf2591..d1357247709 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -36,7 +36,7 @@ void Sema::ObjCActOnStartOfMethodDef(Scope *FnBodyScope, DeclTy *D) { AddFactoryMethodToGlobalPool(MDecl); // Allow all of Sema to see that we are entering a method definition. - PushDeclContext(MDecl); + PushDeclContext(FnBodyScope, MDecl); // Create Decl objects for each parameter, entrring them in the scope for // binding to their use. diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index b2542542417..ba5d28a6334 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -453,13 +453,13 @@ Sema::ExprResult Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, } } - if (CXXFieldDecl *FD = dyn_cast<CXXFieldDecl>(D)) { + if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) { if (MD->isStatic()) // "invalid use of member 'x' in static member function" return Diag(Loc, diag::err_invalid_member_use_in_static_method) << FD->getDeclName(); - if (cast<CXXRecordDecl>(MD->getParent()) != FD->getParent()) + if (MD->getParent() != FD->getDeclContext()) // "invalid use of nonstatic data member 'x'" return Diag(Loc, diag::err_invalid_non_static_member_use) << FD->getDeclName(); @@ -1231,20 +1231,28 @@ ActOnMemberReferenceExpr(ExprTy *Base, SourceLocation OpLoc, return Diag(OpLoc, diag::err_typecheck_incomplete_tag) << RDecl->getDeclName() << BaseExpr->getSourceRange(); // The record definition is complete, now make sure the member is valid. - FieldDecl *MemberDecl = RDecl->getMember(&Member); - if (!MemberDecl) + // FIXME: Qualified name lookup for C++ is a bit more complicated + // than this. + DeclContext::lookup_result Lookup = RDecl->lookup(Context, &Member); + if (Lookup.first == Lookup.second) { return Diag(MemberLoc, diag::err_typecheck_no_member) << &Member << BaseExpr->getSourceRange(); + } + + FieldDecl *MemberDecl = dyn_cast<FieldDecl>(*Lookup.first); + if (!MemberDecl) { + unsigned DiagID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error, + "Clang only supports references to members"); + return Diag(MemberLoc, DiagID); + } // Figure out the type of the member; see C99 6.5.2.3p3 // FIXME: Handle address space modifiers QualType MemberType = MemberDecl->getType(); unsigned combinedQualifiers = MemberType.getCVRQualifiers() | BaseType.getCVRQualifiers(); - if (CXXFieldDecl *CXXMember = dyn_cast<CXXFieldDecl>(MemberDecl)) { - if (CXXMember->isMutable()) - combinedQualifiers &= ~QualType::Const; - } + if (MemberDecl->isMutable()) + combinedQualifiers &= ~QualType::Const; MemberType = MemberType.getQualifiedType(combinedQualifiers); return new MemberExpr(BaseExpr, OpKind == tok::arrow, MemberDecl, @@ -3484,7 +3492,11 @@ Sema::ExprResult Sema::ActOnBuiltinOffsetOf(SourceLocation BuiltinLoc, // Get the decl corresponding to this. RecordDecl *RD = RC->getDecl(); - FieldDecl *MemberDecl = RD->getMember(OC.U.IdentInfo); + FieldDecl *MemberDecl = 0; + DeclContext::lookup_result Lookup = RD->lookup(Context, OC.U.IdentInfo); + if (Lookup.first != Lookup.second) + MemberDecl = dyn_cast<FieldDecl>(*Lookup.first); + if (!MemberDecl) return Diag(BuiltinLoc, diag::err_typecheck_no_member) << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd); @@ -3552,7 +3564,7 @@ void Sema::ActOnBlockStart(SourceLocation CaretLoc, Scope *BlockScope) { BSI->TheScope = BlockScope; BSI->TheDecl = BlockDecl::Create(Context, CurContext, CaretLoc); - PushDeclContext(BSI->TheDecl); + PushDeclContext(BlockScope, BSI->TheDecl); } void Sema::ActOnBlockArguments(Declarator &ParamInfo) { diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 27b0ba34d19..a32a6f68fad 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -412,9 +412,8 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, DeclarationName Name, DeclContext *Ctx, bool AllowMissing, FunctionDecl *&Operator) { - IdentifierResolver::iterator I = - IdResolver.begin(Name, Ctx, /*LookInParentCtx=*/false); - if (I == IdResolver.end()) { + DeclContext::lookup_result Lookup = Ctx->lookup(Context, Name); + if (Lookup.first == Lookup.second) { if (AllowMissing) return false; // FIXME: Bad location information. @@ -423,7 +422,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, DeclarationName Name, } OverloadCandidateSet Candidates; - NamedDecl *Decl = *I; + NamedDecl *Decl = *Lookup.first; // Even member operator new/delete are implicitly treated as static, so don't // use AddMemberCandidate. if (FunctionDecl *Fn = dyn_cast_or_null<FunctionDecl>(Decl)) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 42f9b14085e..f36d3a504fc 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -15,6 +15,8 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/Basic/Diagnostic.h" +#include <algorithm> // for std::count_if +#include <functional> // for std::mem_fun namespace clang { @@ -39,10 +41,9 @@ int InitListChecker::numArrayElements(QualType DeclType) { int InitListChecker::numStructUnionElements(QualType DeclType) { RecordDecl *structDecl = DeclType->getAsRecordType()->getDecl(); - int InitializableMembers = 0; - for (int i = 0; i < structDecl->getNumMembers(); i++) - if (structDecl->getMember(i)->getIdentifier()) - ++InitializableMembers; + int InitializableMembers + = std::count_if(structDecl->field_begin(), structDecl->field_end(), + std::mem_fun(&FieldDecl::getDeclName)); if (structDecl->isUnion()) return std::min(InitializableMembers, 1); return InitializableMembers - structDecl->hasFlexibleArrayMember(); @@ -286,21 +287,28 @@ void InitListChecker::CheckStructUnionTypes(InitListExpr *IList, // If structDecl is a forward declaration, this loop won't do anything; // That's okay, because an error should get printed out elsewhere. It // might be worthwhile to skip over the rest of the initializer, though. - int numMembers = DeclType->getAsRecordType()->getDecl()->getNumMembers() - - structDecl->hasFlexibleArrayMember(); - for (int i = 0; i < numMembers; i++) { + RecordDecl *RD = DeclType->getAsRecordType()->getDecl(); + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; ++Field) { + // If we've hit the flexible array member at the end, we're done. + if (Field->getType()->isIncompleteArrayType()) + break; + // Don't attempt to go past the end of the init list if (Index >= IList->getNumInits()) break; - FieldDecl * curField = structDecl->getMember(i); - if (!curField->getIdentifier()) { + + if (!Field->getIdentifier()) { // Don't initialize unnamed fields, e.g. "int : 20;" continue; } - CheckSubElementType(IList, curField->getType(), Index); + + CheckSubElementType(IList, Field->getType(), Index); if (DeclType->isUnionType()) break; } + // FIXME: Implement flexible array initialization GCC extension (it's a // really messy extension to implement, unfortunately...the necessary // information isn't actually even here!) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 8a68d5be5c3..307abe3ac95 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1955,10 +1955,9 @@ void Sema::AddOperatorCandidates(OverloadedOperatorKind Op, Scope *S, // (13.3.1.1.1); otherwise, the set of member candidates is // empty. if (const RecordType *T1Rec = T1->getAsRecordType()) { - IdentifierResolver::iterator I - = IdResolver.begin(OpName, cast<CXXRecordType>(T1Rec)->getDecl(), - /*LookInParentCtx=*/false); - NamedDecl *MemberOps = (I == IdResolver.end())? 0 : *I; + DeclContext::lookup_const_result Lookup + = cast<CXXRecordType>(T1Rec)->getDecl()->lookup(Context, OpName); + NamedDecl *MemberOps = (Lookup.first == Lookup.second)? 0 : *Lookup.first; if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(MemberOps)) AddMethodCandidate(Method, Args[0], Args+1, NumArgs - 1, CandidateSet, /*SuppressUserConversions=*/false); @@ -3118,11 +3117,10 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // ordinary lookup of the name operator() in the context of // (E).operator(). OverloadCandidateSet CandidateSet; - IdentifierResolver::iterator I - = IdResolver.begin(Context.DeclarationNames.getCXXOperatorName(OO_Call), - cast<CXXRecordType>(Record)->getDecl(), - /*LookInParentCtx=*/false); - NamedDecl *MemberOps = (I == IdResolver.end())? 0 : *I; + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Call); + DeclContext::lookup_const_result Lookup + = cast<CXXRecordType>(Record)->getDecl()->lookup(Context, OpName); + NamedDecl *MemberOps = (Lookup.first == Lookup.second)? 0 : *Lookup.first; if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(MemberOps)) AddMethodCandidate(Method, Object, Args, NumArgs, CandidateSet, /*SuppressUserConversions=*/false); @@ -3315,10 +3313,9 @@ Sema::BuildOverloadedArrowExpr(Expr *Base, SourceLocation OpLoc, DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow); OverloadCandidateSet CandidateSet; const RecordType *BaseRecord = Base->getType()->getAsRecordType(); - IdentifierResolver::iterator I - = IdResolver.begin(OpName, cast<CXXRecordType>(BaseRecord)->getDecl(), - /*LookInParentCtx=*/false); - NamedDecl *MemberOps = (I == IdResolver.end())? 0 : *I; + DeclContext::lookup_const_result Lookup + = cast<CXXRecordType>(BaseRecord)->getDecl()->lookup(Context, OpName); + NamedDecl *MemberOps = (Lookup.first == Lookup.second)? 0 : *Lookup.first; if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(MemberOps)) AddMethodCandidate(Method, Base, 0, 0, CandidateSet, /*SuppressUserConversions=*/false); |