diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-09-02 22:59:36 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-09-02 22:59:36 +0000 |
commit | 2dd078ae50ff7be1fb25ebeedde45e9ab691a4f0 (patch) | |
tree | 0e30fbe6d5c2cbab6ad0dc64accd298ad7822f9f /lib/Sema | |
parent | 6c35415912d1e43c21fcaa2823934ae993f2718b (diff) |
Rewrite of our handling of name lookup in C++ member access expressions, e.g.,
x->Base::f
We no longer try to "enter" the context of the type that "x" points
to. Instead, we drag that object type through the parser and pass it
into the Sema routines that need to know how to perform lookup within
member access expressions.
We now implement most of the crazy name lookup rules in C++
[basic.lookup.classref] for non-templated code, including performing
lookup both in the context of the type referred to by the member
access and in the scope of the member access itself and then detecting
ambiguities when the two lookups collide (p1 and p4; p3 and p7 are
still TODO). This change also corrects our handling of name lookup
within template arguments of template-ids inside the
nested-name-specifier (p6; we used to look into the scope of the
object expression for them) and fixes PR4703.
I have disabled some tests that involve member access expressions
where the object expression has dependent type, because we don't yet
have the ability to describe dependent nested-name-specifiers starting
with an identifier.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80843 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/Sema.h | 33 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 238 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 42 | ||||
-rw-r--r-- | lib/Sema/SemaLookup.cpp | 41 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 326 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 13 |
6 files changed, 449 insertions, 244 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index e2205d6df5..6f462e593b 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1983,6 +1983,12 @@ public: TypeTy *Ty, SourceLocation RParen); + virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S, + ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + TypeTy *&ObjectType); + virtual OwningExprResult ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, @@ -2029,6 +2035,7 @@ public: bool RequireCompleteDeclContext(const CXXScopeSpec &SS); + DeclContext *computeDeclContext(QualType T); DeclContext *computeDeclContext(const CXXScopeSpec &SS, bool EnteringContext = false); bool isDependentScopeSpecifier(const CXXScopeSpec &SS); @@ -2051,6 +2058,7 @@ public: SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, + TypeTy *ObjectType, bool EnteringContext); /// ActOnCXXNestedNameSpecifier - Called during parsing of a @@ -2067,23 +2075,6 @@ public: SourceRange TypeRange, SourceLocation CCLoc); - /// ActOnCXXEnterMemberScope - Called when a C++ class member accessor ('.' - /// or '->') is parsed. After this method is called, according to - /// [C++ 3.4.5p4], qualified-ids should be looked up in the contexts of both - /// the entire postfix-expression and the scope of the class of the object - /// expression. - /// 'SS' should be an empty CXXScopeSpec to be filled with the class's scope. - virtual OwningExprResult ActOnCXXEnterMemberScope(Scope *S, CXXScopeSpec &SS, - ExprArg Base, - tok::TokenKind OpKind); - - /// ActOnCXXExitMemberScope - Called when a postfix-expression that previously - /// invoked ActOnCXXEnterMemberScope() is finished. 'SS' is the same - /// CXXScopeSpec that was passed to ActOnCXXEnterMemberScope. Used to - /// indicate that names should revert to being looked up in the defining - /// scope. - virtual void ActOnCXXExitMemberScope(Scope *S, const CXXScopeSpec &SS); - /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be @@ -2311,8 +2302,11 @@ public: //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // - virtual TemplateNameKind isTemplateName(const IdentifierInfo &II, Scope *S, + virtual TemplateNameKind isTemplateName(Scope *S, + const IdentifierInfo &II, + SourceLocation IdLoc, const CXXScopeSpec *SS, + TypeTy *ObjectType, bool EnteringContext, TemplateTy &Template); bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); @@ -2400,7 +2394,8 @@ public: virtual TemplateTy ActOnDependentTemplateName(SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, - const CXXScopeSpec &SS); + const CXXScopeSpec &SS, + TypeTy *ObjectType); bool CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate, ClassTemplateSpecializationDecl *PrevDecl, diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index d89a610cae..251ffea925 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -22,6 +22,20 @@ #include "llvm/Support/raw_ostream.h" using namespace clang; +/// \brief Compute the DeclContext that is associated with the given type. +/// +/// \param T the type for which we are attempting to find a DeclContext. +/// +/// \returns the declaration context represented by the type T, +/// or NULL if the declaration context cannot be computed (e.g., because it is +/// dependent and not the current instantiation). +DeclContext *Sema::computeDeclContext(QualType T) { + if (const TagType *Tag = T->getAs<TagType>()) + return Tag->getDecl(); + + return 0; +} + /// \brief Compute the DeclContext that is associated with the given /// scope specifier. /// @@ -244,6 +258,36 @@ Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, return NestedNameSpecifier::GlobalSpecifier(Context); } +/// \brief Determines whether the given declaration is an valid acceptable +/// result for name lookup of a nested-name-specifier. +bool isAcceptableNestedNameSpecifier(ASTContext &Context, NamedDecl *SD) { + if (!SD) + return false; + + // Namespace and namespace aliases are fine. + if (isa<NamespaceDecl>(SD) || isa<NamespaceAliasDecl>(SD)) + return true; + + if (!isa<TypeDecl>(SD)) + return false; + + // Determine whether we have a class (or, in C++0x, an enum) or + // a typedef thereof. If so, build the nested-name-specifier. + QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD)); + if (T->isDependentType()) + return true; + else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { + if (TD->getUnderlyingType()->isRecordType() || + (Context.getLangOptions().CPlusPlus0x && + TD->getUnderlyingType()->isEnumeralType())) + return true; + } else if (isa<RecordDecl>(SD) || + (Context.getLangOptions().CPlusPlus0x && isa<EnumDecl>(SD))) + return true; + + return false; +} + /// ActOnCXXNestedNameSpecifier - Called during parsing of a /// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now /// we want to resolve "bar::". 'SS' is empty or the previously parsed @@ -255,58 +299,134 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, + TypeTy *ObjectTypePtr, bool EnteringContext) { NestedNameSpecifier *Prefix = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); + + // Determine where to perform name lookup + DeclContext *LookupCtx = 0; + bool isDependent = false; + if (ObjectTypePtr) { + // This nested-name-specifier occurs in a member access expression, e.g., + // x->B::f, and we are looking into the type of the object. + assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); + QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); + LookupCtx = computeDeclContext(ObjectType); + isDependent = ObjectType->isDependentType(); + } else if (SS.isSet()) { + // This nested-name-specifier occurs after another nested-name-specifier, + // so long into the context associated with the prior nested-name-specifier. + LookupCtx = computeDeclContext(SS, EnteringContext); + isDependent = isDependentScopeSpecifier(SS); + } - NamedDecl *SD = LookupParsedName(S, &SS, &II, LookupNestedNameSpecifierName, - false, false, SourceLocation(), - EnteringContext); + LookupResult Found; + bool ObjectTypeSearchedInScope = false; + if (LookupCtx) { + // Perform "qualified" name lookup into the declaration context we + // computed, which is either the type of the base of a member access + // expression or the declaration context associated with a prior + // nested-name-specifier. + + // The declaration context must be complete. + if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS)) + return 0; - if (SD) { + Found = LookupQualifiedName(LookupCtx, &II, LookupNestedNameSpecifierName, + false); + + if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound && S) { + // C++ [basic.lookup.classref]p4: + // If the id-expression in a class member access is a qualified-id of + // the form + // + // class-name-or-namespace-name::... + // + // the class-name-or-namespace-name following the . or -> operator is + // looked up both in the context of the entire postfix-expression and in + // the scope of the class of the object expression. If the name is found + // only in the scope of the class of the object expression, the name + // shall refer to a class-name. If the name is found only in the + // context of the entire postfix-expression, the name shall refer to a + // class-name or namespace-name. [...] + // + // Qualified name lookup into a class will not find a namespace-name, + // so we do not need to diagnoste that case specifically. However, + // this qualified name lookup may find nothing. In that case, perform + // unqualified name lookup in the given scope. + + // FIXME: When we're instantiating a template, do we actually have to + // look in the scope of the template? Seems fishy... + Found = LookupName(S, &II, LookupNestedNameSpecifierName); + ObjectTypeSearchedInScope = true; + } + } else if (isDependent) { + // We were not able to compute the declaration context for a dependent + // base object type or prior nested-name-specifier, so this + // nested-name-specifier refers to an unknown specialization. Just build + // a dependent nested-name-specifier. + return NestedNameSpecifier::Create(Context, Prefix, &II); + } else { + // Perform unqualified name lookup in the current scope. + Found = LookupName(S, &II, LookupNestedNameSpecifierName); + } + + // FIXME: Deal with ambiguities cleanly. + NamedDecl *SD = Found; + if (isAcceptableNestedNameSpecifier(Context, SD)) { + if (ObjectTypePtr && !ObjectTypeSearchedInScope && S) { + // C++ [basic.lookup.classref]p4: + // [...] If the name is found in both contexts, the + // class-name-or-namespace-name shall refer to the same entity. + // + // We already found the name in the scope of the object. Now, look + // into the current scope (the scope of the postfix-expression) to + // see if we can find the same name there. + LookupResult FoundOuter + = LookupName(S, &II, LookupNestedNameSpecifierName); + + // FIXME: Handle ambiguities in FoundOuter! + NamedDecl *OuterDecl = FoundOuter; + if (isAcceptableNestedNameSpecifier(Context, OuterDecl) && + OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() && + (!isa<TypeDecl>(OuterDecl) || !isa<TypeDecl>(SD) || + !Context.hasSameType( + Context.getTypeDeclType(cast<TypeDecl>(OuterDecl)), + Context.getTypeDeclType(cast<TypeDecl>(SD))))) { + Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous) + << &II; + Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type) + << QualType::getFromOpaquePtr(ObjectTypePtr); + Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope); + + // Fall through so that we'll pick the name we found in the object type, + // since that's probably what the user wanted anyway. + } + } + if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) return NestedNameSpecifier::Create(Context, Prefix, Namespace); - if (TypeDecl *Type = dyn_cast<TypeDecl>(SD)) { - // Determine whether we have a class (or, in C++0x, an enum) or - // a typedef thereof. If so, build the nested-name-specifier. - QualType T = Context.getTypeDeclType(Type); - bool AcceptableType = false; - if (T->isDependentType()) - AcceptableType = true; - else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) { - if (TD->getUnderlyingType()->isRecordType() || - (getLangOptions().CPlusPlus0x && - TD->getUnderlyingType()->isEnumeralType())) - AcceptableType = true; - } else if (isa<RecordDecl>(Type) || - (getLangOptions().CPlusPlus0x && isa<EnumDecl>(Type))) - AcceptableType = true; - - if (AcceptableType) - return NestedNameSpecifier::Create(Context, Prefix, false, - T.getTypePtr()); - } - // FIXME: It would be nice to maintain the namespace alias name, then // see through that alias when resolving the nested-name-specifier down to // a declaration context. if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) return NestedNameSpecifier::Create(Context, Prefix, - Alias->getNamespace()); - // Fall through to produce an error: we found something that isn't - // a class or a namespace. - } else if (SS.isSet() && isDependentScopeSpecifier(SS)) - return NestedNameSpecifier::Create(Context, Prefix, &II); + Alias->getNamespace()); + + QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD)); + return NestedNameSpecifier::Create(Context, Prefix, false, + T.getTypePtr()); + } // 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, LookupOrdinaryName, - false, false, SourceLocation(), - EnteringContext); + SD = LookupName(S, &II, LookupOrdinaryName); + unsigned DiagID; if (SD) DiagID = diag::err_expected_class_or_namespace; @@ -338,58 +458,6 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, T.getTypePtr()); } -Action::OwningExprResult -Sema::ActOnCXXEnterMemberScope(Scope *S, CXXScopeSpec &SS, ExprArg Base, - tok::TokenKind OpKind) { - // Since this might be a postfix expression, get rid of ParenListExprs. - Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); - - Expr *BaseExpr = (Expr*)Base.get(); - assert(BaseExpr && "no record expansion"); - - QualType BaseType = BaseExpr->getType(); - // FIXME: handle dependent types - if (BaseType->isDependentType()) - return move(Base); - - // C++ [over.match.oper]p8: - // [...] When operator->returns, the operator-> is applied to the value - // returned, with the original second operand. - if (OpKind == tok::arrow) { - while (BaseType->isRecordType()) { - Base = BuildOverloadedArrowExpr(S, move(Base), BaseExpr->getExprLoc()); - BaseExpr = (Expr*)Base.get(); - if (BaseExpr == NULL) - return ExprError(); - BaseType = BaseExpr->getType(); - } - } - - if (BaseType->isPointerType()) - BaseType = BaseType->getPointeeType(); - - // We could end up with various non-record types here, such as extended - // vector types or Objective-C interfaces. Just return early and let - // ActOnMemberReferenceExpr do the work. - if (!BaseType->isRecordType()) - return move(Base); - - SS.setRange(BaseExpr->getSourceRange()); - SS.setScopeRep( - NestedNameSpecifier::Create(Context, 0, false, BaseType.getTypePtr()) - ); - - if (S) - ActOnCXXEnterDeclaratorScope(S,SS); - return move(Base); -} - -void Sema::ActOnCXXExitMemberScope(Scope *S, const CXXScopeSpec &SS) { - if (S && SS.isSet()) - ActOnCXXExitDeclaratorScope(S,SS); -} - - /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 0dc4b8d180..87330ab0b6 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1754,6 +1754,48 @@ Expr *Sema::MaybeCreateCXXExprWithTemporaries(Expr *SubExpr, return E; } +Sema::OwningExprResult +Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc, + tok::TokenKind OpKind, TypeTy *&ObjectType) { + // Since this might be a postfix expression, get rid of ParenListExprs. + Base = MaybeConvertParenListExprToParenExpr(S, move(Base)); + + Expr *BaseExpr = (Expr*)Base.get(); + assert(BaseExpr && "no record expansion"); + + QualType BaseType = BaseExpr->getType(); + if (BaseType->isDependentType()) { + // FIXME: member of the current instantiation + ObjectType = BaseType.getAsOpaquePtr(); + return move(Base); + } + + // C++ [over.match.oper]p8: + // [...] When operator->returns, the operator-> is applied to the value + // returned, with the original second operand. + if (OpKind == tok::arrow) { + while (BaseType->isRecordType()) { + Base = BuildOverloadedArrowExpr(S, move(Base), BaseExpr->getExprLoc()); + BaseExpr = (Expr*)Base.get(); + if (BaseExpr == NULL) + return ExprError(); + BaseType = BaseExpr->getType(); + } + } + + if (BaseType->isPointerType()) + BaseType = BaseType->getPointeeType(); + + // We could end up with various non-record types here, such as extended + // vector types or Objective-C interfaces. Just return early and let + // ActOnMemberReferenceExpr do the work. + if (!BaseType->isRecordType()) + return move(Base); + + ObjectType = BaseType.getAsOpaquePtr(); + return move(Base); +} + Sema::OwningExprResult Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 4a699de6c8..38abd1641d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1004,8 +1004,9 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name, LookupNameKind NameKind, bool RedeclarationOnly) { assert(LookupCtx && "Sema::LookupQualifiedName requires a lookup context"); - if (!Name) return LookupResult::CreateLookupResult(Context, 0); - + if (!Name) + return LookupResult::CreateLookupResult(Context, 0); + // If we're performing qualified name lookup (e.g., lookup into a // struct), find fields as part of ordinary name lookup. unsigned IDNS @@ -1013,16 +1014,25 @@ Sema::LookupQualifiedName(DeclContext *LookupCtx, DeclarationName Name, getLangOptions().CPlusPlus); if (NameKind == LookupOrdinaryName) IDNS |= Decl::IDNS_Member; - + + // Make sure that the declaration context is complete. + assert((!isa<TagDecl>(LookupCtx) || + LookupCtx->isDependentContext() || + cast<TagDecl>(LookupCtx)->isDefinition() || + Context.getTypeDeclType(cast<TagDecl>(LookupCtx))->getAs<TagType>() + ->isBeingDefined()) && + "Declaration context must already be complete!"); + // Perform qualified name lookup into the LookupCtx. DeclContext::lookup_iterator I, E; for (llvm::tie(I, E) = LookupCtx->lookup(Name); I != E; ++I) if (isAcceptableLookupResult(*I, NameKind, IDNS)) return LookupResult::CreateLookupResult(Context, I, E); - // If this isn't a C++ class or we aren't allowed to look into base - // classes, we're done. - if (RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx)) + // If this isn't a C++ class, we aren't allowed to look into base + // classes, we're done, or the lookup context is dependent, we're done. + if (RedeclarationOnly || !isa<CXXRecordDecl>(LookupCtx) || + LookupCtx->isDependentContext()) return LookupResult::CreateLookupResult(Context, 0); // Perform lookup into our base classes. @@ -1152,24 +1162,9 @@ Sema::LookupParsedName(Scope *S, const CXXScopeSpec *SS, if (DeclContext *DC = computeDeclContext(*SS, EnteringContext)) { // We have resolved the scope specifier to a particular declaration // contex, and will perform name lookup in that context. - - if (DC->isDependentContext()) { - // If this is a dependent context, then we are looking for a member of - // the current instantiation. This is a narrow search that looks into - // just the described declaration context (C++0x [temp.dep.type]). - unsigned IDNS = getIdentifierNamespacesFromLookupNameKind(NameKind, - true); - DeclContext::lookup_iterator I, E; - for (llvm::tie(I, E) = DC->lookup(Name); I != E; ++I) - if (isAcceptableLookupResult(*I, NameKind, IDNS)) - return LookupResult::CreateLookupResult(Context, I, E); - } - - // Qualified name lookup into the named declaration context. - // The declaration context must be complete. - if (RequireCompleteDeclContext(*SS)) + if (!DC->isDependentContext() && RequireCompleteDeclContext(*SS)) return LookupResult::CreateLookupResult(Context, 0); - + return LookupQualifiedName(DC, Name, NameKind, RedeclarationOnly); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f0165c91e1..119e17f814 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -21,122 +21,215 @@ using namespace clang; -/// isTemplateName - Determines whether the identifier II is a -/// template name in the current scope, and returns the template -/// declaration if II names a template. An optional CXXScope can be -/// passed to indicate the C++ scope in which the identifier will be -/// found. -TemplateNameKind Sema::isTemplateName(const IdentifierInfo &II, Scope *S, - const CXXScopeSpec *SS, - bool EnteringContext, - TemplateTy &TemplateResult) { - LookupResult Found = LookupParsedName(S, SS, &II, LookupOrdinaryName, - false, false, SourceLocation(), - EnteringContext); +/// \brief Determine whether the declaration found is acceptable as the name +/// of a template and, if so, return that template declaration. Otherwise, +/// returns NULL. +static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) { + if (!D) + return 0; - // FIXME: Cope with ambiguous name-lookup results. - assert(!Found.isAmbiguous() && - "Cannot handle template name-lookup ambiguities"); + if (isa<TemplateDecl>(D)) + return D; + + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) { + // C++ [temp.local]p1: + // Like normal (non-template) classes, class templates have an + // injected-class-name (Clause 9). The injected-class-name + // can be used with or without a template-argument-list. When + // it is used without a template-argument-list, it is + // equivalent to the injected-class-name followed by the + // template-parameters of the class template enclosed in + // <>. When it is used with a template-argument-list, it + // refers to the specified class template specialization, + // which could be the current specialization or another + // specialization. + if (Record->isInjectedClassName()) { + Record = cast<CXXRecordDecl>(Record->getCanonicalDecl()); + if (Record->getDescribedClassTemplate()) + return Record->getDescribedClassTemplate(); + + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Record)) + return Spec->getSpecializedTemplate(); + } + + return 0; + } - NamedDecl *IIDecl = Found; + OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D); + if (!Ovl) + return 0; - TemplateNameKind TNK = TNK_Non_template; - TemplateDecl *Template = 0; - - if (IIDecl) { - if ((Template = dyn_cast<TemplateDecl>(IIDecl))) { - if (isa<FunctionTemplateDecl>(IIDecl)) - TNK = TNK_Function_template; - else if (isa<ClassTemplateDecl>(IIDecl) || - isa<TemplateTemplateParmDecl>(IIDecl)) - TNK = TNK_Type_template; - else - assert(false && "Unknown template declaration kind"); - } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(IIDecl)) { - // C++ [temp.local]p1: - // Like normal (non-template) classes, class templates have an - // injected-class-name (Clause 9). The injected-class-name - // can be used with or without a template-argument-list. When - // it is used without a template-argument-list, it is - // equivalent to the injected-class-name followed by the - // template-parameters of the class template enclosed in - // <>. When it is used with a template-argument-list, it - // refers to the specified class template specialization, - // which could be the current specialization or another - // specialization. - if (Record->isInjectedClassName()) { - Record = cast<CXXRecordDecl>(Record->getCanonicalDecl()); - if ((Template = Record->getDescribedClassTemplate())) - TNK = TNK_Type_template; - else if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(Record)) { - Template = Spec->getSpecializedTemplate(); - TNK = TNK_Type_template; - } + for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), + FEnd = Ovl->function_end(); + F != FEnd; ++F) { + if (FunctionTemplateDecl *FuncTmpl = dyn_cast<FunctionTemplateDecl>(*F)) { + // We've found a function template. Determine whether there are + // any other function templates we need to bundle together in an + // OverloadedFunctionDecl + for (++F; F != FEnd; ++F) { + if (isa<FunctionTemplateDecl>(*F)) + break; } - } else if (OverloadedFunctionDecl *Ovl - = dyn_cast<OverloadedFunctionDecl>(IIDecl)) { - for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), - FEnd = Ovl->function_end(); - F != FEnd; ++F) { - if (FunctionTemplateDecl *FuncTmpl - = dyn_cast<FunctionTemplateDecl>(*F)) { - // We've found a function template. Determine whether there are - // any other function templates we need to bundle together in an - // OverloadedFunctionDecl - for (++F; F != FEnd; ++F) { - if (isa<FunctionTemplateDecl>(*F)) - break; - } - - if (F != FEnd) { - // Build an overloaded function decl containing only the - // function templates in Ovl. - OverloadedFunctionDecl *OvlTemplate - = OverloadedFunctionDecl::Create(Context, - Ovl->getDeclContext(), - Ovl->getDeclName()); - OvlTemplate->addOverload(FuncTmpl); + + if (F != FEnd) { + // Build an overloaded function decl containing only the + // function templates in Ovl. + OverloadedFunctionDecl *OvlTemplate + = OverloadedFunctionDecl::Create(Context, + Ovl->getDeclContext(), + Ovl->getDeclName()); + OvlTemplate->addOverload(FuncTmpl); + OvlTemplate->addOverload(*F); + for (++F; F != FEnd; ++F) { + if (isa<FunctionTemplateDecl>(*F)) OvlTemplate->addOverload(*F); - for (++F; F != FEnd; ++F) { - if (isa<FunctionTemplateDecl>(*F)) - OvlTemplate->addOverload(*F); - } - - // Form the resulting TemplateName - if (SS && SS->isSet() && !SS->isInvalid()) { - NestedNameSpecifier *Qualifier - = static_cast<NestedNameSpecifier *>(SS->getScopeRep()); - TemplateResult - = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, - false, - OvlTemplate)); - } else { - TemplateResult = TemplateTy::make(TemplateName(OvlTemplate)); - } - return TNK_Function_template; - } - - TNK = TNK_Function_template; - Template = FuncTmpl; - break; } + + return OvlTemplate; } + + return FuncTmpl; } + } + + return 0; +} - if (TNK != TNK_Non_template) { - if (SS && SS->isSet() && !SS->isInvalid()) { - NestedNameSpecifier *Qualifier - = static_cast<NestedNameSpecifier *>(SS->getScopeRep()); - TemplateResult - = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, - false, - Template)); - } else - TemplateResult = TemplateTy::make(TemplateName(Template)); +TemplateNameKind Sema::isTemplateName(Scope *S, + const IdentifierInfo &II, + SourceLocation IdLoc, + const CXXScopeSpec *SS, + TypeTy *ObjectTypePtr, + bool EnteringContext, + TemplateTy &TemplateResult) { + // Determine where to perform name lookup + DeclContext *LookupCtx = 0; + bool isDependent = false; + if (ObjectTypePtr) { + // This nested-name-specifier occurs in a member access expression, e.g., + // x->B::f, and we are looking into the type of the object. + assert((!SS || !SS->isSet()) && + "ObjectType and scope specifier cannot coexist"); + QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr); + LookupCtx = computeDeclContext(ObjectType); + isDependent = ObjectType->isDependentType(); + } else if (SS && SS->isSet()) { + // This nested-name-specifier occurs after another nested-name-specifier, + // so long into the context associated with the prior nested-name-specifier. + + LookupCtx = computeDeclContext(*SS, EnteringContext); + isDependent = isDependentScopeSpecifier(*SS); + } + + LookupResult Found; + bool ObjectTypeSearchedInScope = false; + if (LookupCtx) { + // Perform "qualified" name lookup into the declaration context we + // computed, which is either the type of the base of a member access + // expression or the declaration context associated with a prior + // nested-name-specifier. + + // The declaration context must be complete. + if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS)) + return TNK_Non_template; + + Found = LookupQualifiedName(LookupCtx, &II, LookupOrdinaryName); + + if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound) { + // C++ [basic.lookup.classref]p1: + // In a class member access expression (5.2.5), if the . or -> token is + // immediately followed by an identifier followed by a <, the + // identifier must be looked up to determine whether the < is the + // beginning of a template argument list (14.2) or a less-than operator. + // The identifier is first looked up in the class of the object + // expression. If the identifier is not found, it is then looked up in + // the context of the entire postfix-expression and shall name a class + // or function template. + // + // FIXME: When we're instantiating a template, do we actually have to + // look in the scope of the template? Seems fishy... + Found = LookupName(S, &II, LookupOrdinaryName); + ObjectTypeSearchedInScope = true; } + } else if (isDependent) { + // We cannot look into a dependent object type or + return TNK_Non_template; + } else { + // Perform unqualified name lookup in the current scope. + Found = LookupName(S, &II, LookupOrdinaryName); + } + + // FIXME: Cope with ambiguous name-lookup results. + assert(!Found.isAmbiguous() && + "Cannot handle template name-lookup ambiguities"); + + NamedDecl *Template = isAcceptableTemplateName(Context, Found); + if (!Template) + return TNK_Non_template; + + if (ObjectTypePtr && !ObjectTypeSearchedInScope) { + // C++ [basic.lookup.classref]p1: + // [...] If the lookup in the class of the object expression finds a + // template, the name is also looked up in the context of the entire + // postfix-expression and [...] + // + LookupResult FoundOuter = LookupName(S, &II, LookupOrdinaryName); + // FIXME: Handle ambiguities in this lookup better + NamedDecl *OuterTemplate = isAcceptableTemplateName(Context, FoundOuter); + + if (!OuterTemplate) { + // - if the name is not found, the name found in the class of the + // object expression is used, otherwise + } else if (!isa<ClassTemplateDecl>(OuterTemplate)) { + // - if the name is found in the context of the entire + // postfix-expression and does not name a class template, the name + // found in the class of the object expression is used, otherwise + } else { + // - if the name found is a class template, it must refer to the same + // entity as the one found in the class of the object expression, + // otherwise the program is ill-formed. + if (OuterTemplate->getCanonicalDecl() != Template->getCanonicalDecl()) { + Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous) + << &II; + Diag(Template->getLocation(), diag::note_ambig_member_ref_object_type) + << QualType::getFromOpaquePtr(ObjectTypePtr); + Diag(OuterTemplate->getLocation(), diag::note_ambig_member_ref_scope); + + // Recover by taking the template that we found in the object + // expression's type. + } + } } - return TNK; + + if (SS && SS->isSet() && !SS->isInvalid()) { + NestedNameSpecifier *Qualifier + = static_cast<NestedNameSpecifier *>(SS->getScopeRep()); + if (OverloadedFunctionDecl *Ovl + = dyn_cast<OverloadedFunctionDecl>(Template)) + TemplateResult + = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false, + Ovl)); + else + TemplateResult + = TemplateTy::make(Context.getQualifiedTemplateName(Qualifier, false, + cast<TemplateDecl>(Template))); + } else if (OverloadedFunctionDecl *Ovl + = dyn_cast<OverloadedFunctionDecl&g |