diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/Sema.h | 33 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCXXScopeSpec.cpp | 238 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 42 | ||||
-rw-r--r-- | clang/lib/Sema/SemaLookup.cpp | 41 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 326 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 13 |
6 files changed, 449 insertions, 244 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index e2205d6df54..6f462e593b5 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/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/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index d89a610caec..251ffea925c 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/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/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 0dc4b8d1800..87330ab0b63 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/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/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 4a699de6c8d..38abd1641d5 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/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/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index f0165c91e10..119e17f814d 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/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>(Template)) { + TemplateResult = TemplateTy::make(TemplateName(Ovl)); + } else { + TemplateResult = TemplateTy::make( + TemplateName(cast<TemplateDecl>(Template))); + } + + if (isa<ClassTemplateDecl>(Template) || + isa<TemplateTemplateParmDecl>(Template)) + return TNK_Type_template; + + assert((isa<FunctionTemplateDecl>(Template) || + isa<OverloadedFunctionDecl>(Template)) && + "Unhandled template kind in Sema::isTemplateName"); + return TNK_Function_template; } /// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining @@ -1130,14 +1223,11 @@ Sema::TemplateTy Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, const IdentifierInfo &Name, SourceLocation NameLoc, - const CXXScopeSpec &SS) { - if (!SS.isSet() || SS.isInvalid()) - return TemplateTy(); - - NestedNameSpecifier *Qualifier - = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - - if (computeDeclContext(SS, false)) { + const CXXScopeSpec &SS, + TypeTy *ObjectType) { + if ((ObjectType && + computeDeclContext(QualType::getFromOpaquePtr(ObjectType))) || + (SS.isSet() && computeDeclContext(SS, false))) { // C++0x [temp.names]p5: // If a name prefixed by the keyword template is not the name of // a template, the program is ill-formed. [Note: the keyword @@ -1155,7 +1245,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, // "template" keyword is now permitted). We follow the C++0x // rules, even in C++03 mode, retroactively applying the DR. TemplateTy Template; - TemplateNameKind TNK = isTemplateName(Name, 0, &SS, false, Template); + TemplateNameKind TNK = isTemplateName(0, Name, NameLoc, &SS, ObjectType, + false, Template); if (TNK == TNK_Non_template) { Diag(NameLoc, diag::err_template_kw_refers_to_non_template) << &Name; @@ -1165,6 +1256,13 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, return Template; } + // FIXME: We need to be able to create a dependent template name with just + // an identifier, to handle the x->template f<T> case. + assert(!ObjectType && + "Cannot handle dependent template names without a nested-name-specifier"); + + NestedNameSpecifier *Qualifier + = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); return TemplateTy::make(Context.getDependentTemplateName(Qualifier, &Name)); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index e7400e74734..8fe28a46bf5 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1454,7 +1454,10 @@ public: OwningExprResult Base = move(BaseE); tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period; CXXScopeSpec SS; - Base = SemaRef.ActOnCXXEnterMemberScope(0, SS, move(Base), OpKind); + Sema::TypeTy *ObjectType = 0; + + Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), OperatorLoc, + OpKind, ObjectType); if (Base.isInvalid()) return SemaRef.ExprError(); @@ -1463,7 +1466,6 @@ public: MemberLoc, Name, /*FIXME?*/Sema::DeclPtrTy::make((Decl*)0)); - SemaRef.ActOnCXXExitMemberScope(0, SS); return move(Base); } @@ -4410,6 +4412,7 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, return static_cast<NestedNameSpecifier *>( SemaRef.ActOnCXXNestedNameSpecifier(0, SS, Range.getEnd(), Range.getEnd(), II, + /*FIXME:ObjectType=*/0, false)); } @@ -4467,7 +4470,11 @@ TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier, SS.setRange(SourceRange(getDerived().getBaseLocation())); SS.setScopeRep(Qualifier); Sema::TemplateTy Template; - TemplateNameKind TNK = SemaRef.isTemplateName(II, 0, &SS, false, Template); + TemplateNameKind TNK = SemaRef.isTemplateName(0, II, + /*FIXME:*/getDerived().getBaseLocation(), + &SS, + /*FIXME:ObjectType=*/0, false, + Template); if (TNK == TNK_Non_template) { SemaRef.Diag(getDerived().getBaseLocation(), diag::err_template_kw_refers_to_non_template) |