diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-10-13 16:30:37 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-10-13 16:30:37 +0000 |
commit | cf91555cb8d77fe2a6b2f5b5a7da7ceb4c2d8153 (patch) | |
tree | f6ff343c42e5f5fe485e52bdd5cf973fde08cb43 /clang/lib | |
parent | 0bc673de0d94ec36eb50bbfe4c00b8d6d8727708 (diff) | |
download | bcm5719-llvm-cf91555cb8d77fe2a6b2f5b5a7da7ceb4c2d8153.tar.gz bcm5719-llvm-cf91555cb8d77fe2a6b2f5b5a7da7ceb4c2d8153.zip |
When explicitly specializing a member that is a template, mark the
template as a specialization. For example, this occurs with:
template<typename T>
struct X {
template<typename U> struct Inner { /* ... */ };
};
template<> template<typename T>
struct X<int>::Inner {
T member;
};
We need to treat templates that are member specializations as special
in two contexts:
- When looking for a definition of a member template, we look
through the instantiation chain until we hit the primary template
*or a member specialization*. This allows us to distinguish
between the primary "Inner" definition and the X<int>::Inner
definition, above.
- When computing all of the levels of template arguments needed to
instantiate a member template, don't add template arguments
from contexts outside of the instantiation of a member
specialization, since the user has already manually substituted
those arguments.
Fix up the existing test for p18, which was actually wrong (but we
didn't diagnose it because of our poor handling of member
specializations of templates), and add a new test for member
specializations of templates.
llvm-svn: 83974
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/Decl.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 1 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 24 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 6 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 32 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 14 |
6 files changed, 66 insertions, 15 deletions
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 638d1cfd46e..429729ea3b0 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -737,8 +737,8 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { const TemplateArgumentList * FunctionDecl::getTemplateSpecializationArgs() const { if (FunctionTemplateSpecializationInfo *Info - = TemplateOrSpecialization - .dyn_cast<FunctionTemplateSpecializationInfo*>()) { + = TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo*>()) { return Info->TemplateArguments; } return 0; diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 40e7426e973..fed2fbc0816 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -551,6 +551,7 @@ public: bool IsFunctionDefinition, bool &Redeclaration); void CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, + bool IsExplicitSpecialization, bool &Redeclaration, bool &OverloadableAttrRequired); void CheckMain(FunctionDecl *FD); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 69426ee7554..a1582a900f9 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1735,6 +1735,10 @@ Sema::HandleDeclarator(Scope *S, Declarator &D, return DeclPtrTy(); } + if (!DC->isDependentContext() && + RequireCompleteDeclContext(D.getCXXScopeSpec())) + return DeclPtrTy(); + LookupResult Res; LookupQualifiedName(Res, DC, Name, LookupOrdinaryName, true); PrevDecl = Res.getAsSingleDecl(Context); @@ -2807,11 +2811,11 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD) && CheckMemberSpecialization(NewFD, PrevDecl)) NewFD->setInvalidDecl(); - + // Perform semantic checking on the function declaration. bool OverloadableAttrRequired = false; // FIXME: HACK! - CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration, - /*FIXME:*/OverloadableAttrRequired); + CheckFunctionDeclaration(NewFD, PrevDecl, isExplicitSpecialization, + Redeclaration, /*FIXME:*/OverloadableAttrRequired); if (D.getCXXScopeSpec().isSet() && !NewFD->isInvalidDecl()) { // An out-of-line member function declaration must also be a @@ -2914,8 +2918,12 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, /// that have been instantiated via C++ template instantiation (called /// via InstantiateDecl). /// +/// \param IsExplicitSpecialiation whether this new function declaration is +/// an explicit specialization of the previous declaration. +/// /// This sets NewFD->isInvalidDecl() to true if there was an error. void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, + bool IsExplicitSpecialization, bool &Redeclaration, bool &OverloadableAttrRequired) { // If NewFD is already known erroneous, don't do any of this checking. @@ -2990,7 +2998,7 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, if (FunctionTemplateDecl *OldTemplateDecl = dyn_cast<FunctionTemplateDecl>(OldDecl)) { - NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl()); + NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl()); FunctionTemplateDecl *NewTemplateDecl = NewFD->getDescribedFunctionTemplate(); assert(NewTemplateDecl && "Template/non-template mismatch"); @@ -2999,6 +3007,14 @@ void Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, Method->setAccess(OldTemplateDecl->getAccess()); NewTemplateDecl->setAccess(OldTemplateDecl->getAccess()); } + + // If this is an explicit specialization of a member that is a function + // template, mark it as a member specialization. + if (IsExplicitSpecialization && + NewTemplateDecl->getInstantiatedFromMemberTemplate()) { + NewTemplateDecl->setMemberSpecialization(); + assert(OldTemplateDecl->isMemberSpecialization()); + } } else { if (isa<CXXMethodDecl>(NewFD)) // Set access for out-of-line definitions NewFD->setAccess(OldDecl->getAccess()); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 74120498573..3ee15a5b4d8 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -716,6 +716,12 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, assert(T->isDependentType() && "Class template type is not dependent?"); (void)T; + // If we are providing an explicit specialization of a member that is a + // class template, make a note of that. + if (PrevClassTemplate && + PrevClassTemplate->getInstantiatedFromMemberTemplate()) + PrevClassTemplate->setMemberSpecialization(); + // Set the access specifier. if (!Invalid && TUK != TUK_Friend) SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index ec00d9805c0..65260c8e1e6 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -46,15 +46,31 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D) { break; Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); + + // If this class template specialization was instantiated from a + // specialized member that is a class template, we're done. + assert(Spec->getSpecializedTemplate() && "No class template?"); + if (Spec->getSpecializedTemplate()->isMemberSpecialization()) + break; } - // Add template arguments from a function template specialization. else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) { - // FIXME: Check whether this is an explicit specialization. + if (Function->getTemplateSpecializationKind() + == TSK_ExplicitSpecialization) + break; + if (const TemplateArgumentList *TemplateArgs - = Function->getTemplateSpecializationArgs()) + = Function->getTemplateSpecializationArgs()) { + // Add the template arguments for this specialization. Result.addOuterTemplateArguments(TemplateArgs); + // If this function was instantiated from a specialized member that is + // a function template, we're done. + assert(Function->getPrimaryTemplate() && "No function template?"); + if (Function->getPrimaryTemplate()->isMemberSpecialization()) + break; + } + // If this is a friend declaration and it declares an entity at // namespace scope, take arguments from its lexical parent // instead of its semantic parent. @@ -940,9 +956,15 @@ Sema::InstantiateClassTemplateSpecialization( // -- If no matches are found, the instantiation is generated // from the primary template. ClassTemplateDecl *OrigTemplate = Template; - while (OrigTemplate->getInstantiatedFromMemberTemplate()) + while (OrigTemplate->getInstantiatedFromMemberTemplate()) { + // If we've found an explicit specialization of this class template, + // stop here and use that as the pattern. + if (OrigTemplate->isMemberSpecialization()) + break; + OrigTemplate = OrigTemplate->getInstantiatedFromMemberTemplate(); - + } + Pattern = OrigTemplate->getTemplatedDecl(); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index b03734346c4..33fa28866e5 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -581,7 +581,7 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { PrevDecl = 0; } - SemaRef.CheckFunctionDeclaration(Function, PrevDecl, Redeclaration, + SemaRef.CheckFunctionDeclaration(Function, PrevDecl, false, Redeclaration, /*FIXME:*/OverloadableAttrRequired); // If the original function was part of a friend declaration, @@ -748,7 +748,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, bool Redeclaration = false; bool OverloadableAttrRequired = false; - SemaRef.CheckFunctionDeclaration(Method, PrevDecl, Redeclaration, + SemaRef.CheckFunctionDeclaration(Method, PrevDecl, false, Redeclaration, /*FIXME:*/OverloadableAttrRequired); if (!FunctionTemplate && (!Method->isInvalidDecl() || !PrevDecl) && @@ -1057,9 +1057,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Find the function body that we'll be substituting. const FunctionDecl *PatternDecl = 0; if (FunctionTemplateDecl *Primary = Function->getPrimaryTemplate()) { - while (Primary->getInstantiatedFromMemberTemplate()) + while (Primary->getInstantiatedFromMemberTemplate()) { + // If we have hit a point where the user provided a specialization of + // this template, we're done looking. + if (Primary->isMemberSpecialization()) + break; + Primary = Primary->getInstantiatedFromMemberTemplate(); - + } + PatternDecl = Primary->getTemplatedDecl(); } else PatternDecl = Function->getInstantiatedFromMemberFunction(); |