diff options
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 81 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 24 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 32 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 14 | ||||
-rw-r--r-- | test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp | 6 | ||||
-rw-r--r-- | test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp | 30 |
9 files changed, 172 insertions, 26 deletions
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index e21849c453..8d44676124 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -621,7 +621,7 @@ protected: /// \brief Data that is common to all of the declarations of a given /// function template. struct Common { - Common() : InstantiatedFromMember(0) { } + Common() : InstantiatedFromMember(0, false) { } /// \brief The function template specializations for this function /// template, including explicit specializations and instantiations. @@ -629,7 +629,10 @@ protected: /// \brief The member function template from which this was most /// directly instantiated (or null). - FunctionTemplateDecl *InstantiatedFromMember; + /// + /// The boolean value indicates whether this member function template + /// was explicitly specialized. + llvm::PointerIntPair<FunctionTemplateDecl*, 1, bool> InstantiatedFromMember; }; /// \brief A pointer to the previous declaration (if this is a redeclaration) @@ -704,14 +707,40 @@ public: /// \returns NULL if this is not an instantiation of a member function /// template. FunctionTemplateDecl *getInstantiatedFromMemberTemplate() { - return getCommonPtr()->InstantiatedFromMember; + return getCommonPtr()->InstantiatedFromMember.getPointer(); } void setInstantiatedFromMemberTemplate(FunctionTemplateDecl *FTD) { - assert(!getCommonPtr()->InstantiatedFromMember); - getCommonPtr()->InstantiatedFromMember = FTD; + assert(!getCommonPtr()->InstantiatedFromMember.getPointer()); + getCommonPtr()->InstantiatedFromMember.setPointer(FTD); } + /// \brief Determines whether this template was a specialization of a + /// member template. + /// + /// In the following example, the function template \c X<int>::f is a + /// member specialization. + /// + /// \code + /// template<typename T> + /// struct X { + /// template<typename U> void f(T, U); + /// }; + /// + /// template<> template<typename T> + /// void X<int>::f(int, T); + /// \endcode + bool isMemberSpecialization() { + return getCommonPtr()->InstantiatedFromMember.getInt(); + } + + /// \brief Note that this member template is a specialization. + void setMemberSpecialization() { + assert(getCommonPtr()->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + getCommonPtr()->InstantiatedFromMember.setInt(true); + } + /// Create a template function node. static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -1163,7 +1192,7 @@ protected: /// \brief Data that is common to all of the declarations of a given /// class template. struct Common { - Common() : InstantiatedFromMember(0) {} + Common() : InstantiatedFromMember(0, 0) {} /// \brief The class template specializations for this class /// template, including explicit specializations and instantiations. @@ -1179,9 +1208,15 @@ protected: /// \brief The templated member class from which this was most /// directly instantiated (or null). - ClassTemplateDecl *InstantiatedFromMember; + /// + /// The boolean value indicates whether this member class template + /// was explicitly specialized. + llvm::PointerIntPair<ClassTemplateDecl *, 1, bool> InstantiatedFromMember; }; + // FIXME: Combine PreviousDeclaration with CommonPtr, as in + // FunctionTemplateDecl. + /// \brief Previous declaration of this class template. ClassTemplateDecl *PreviousDeclaration; @@ -1280,14 +1315,40 @@ public: /// /// \returns null if this is not an instantiation of a member class template. ClassTemplateDecl *getInstantiatedFromMemberTemplate() const { - return CommonPtr->InstantiatedFromMember; + return CommonPtr->InstantiatedFromMember.getPointer(); } void setInstantiatedFromMemberTemplate(ClassTemplateDecl *CTD) { - assert(!CommonPtr->InstantiatedFromMember); - CommonPtr->InstantiatedFromMember = CTD; + assert(!CommonPtr->InstantiatedFromMember.getPointer()); + CommonPtr->InstantiatedFromMember.setPointer(CTD); } + /// \brief Determines whether this template was a specialization of a + /// member template. + /// + /// In the following example, the member template \c X<int>::Inner is a + /// member specialization. + /// + /// \code + /// template<typename T> + /// struct X { + /// template<typename U> struct Inner; + /// }; + /// + /// template<> template<typename T> + /// struct X<int>::Inner { /* ... */ }; + /// \endcode + bool isMemberSpecialization() { + return CommonPtr->InstantiatedFromMember.getInt(); + } + + /// \brief Note that this member template is a specialization. + void setMemberSpecialization() { + assert(CommonPtr->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + CommonPtr->InstantiatedFromMember.setInt(true); + } + // Implement isa/cast/dyncast support static bool classof(const Decl *D) { return D->getKind() == ClassTemplate; } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 638d1cfd46..429729ea3b 100644 --- a/lib/AST/Decl.cpp +++ b/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/lib/Sema/Sema.h b/lib/Sema/Sema.h index 40e7426e97..fed2fbc081 100644 --- a/lib/Sema/Sema.h +++ b/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/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 69426ee755..a1582a900f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/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/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 7412049857..3ee15a5b4d 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/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/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index ec00d9805c..65260c8e1e 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/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/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index b03734346c..33fa28866e 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/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(); diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp index 112444af95..04129f8091 100644 --- a/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp +++ b/test/CXX/temp/temp.spec/temp.expl.spec/p18.cpp @@ -7,10 +7,14 @@ template<class T1> class A { }; template<> template<class X> -class A<int>::B { }; +class A<long>::B { }; +// FIXME: If we make the explicit specialization of A<long>::B, above, into +// a specialization of A<int>::B, our diagnostic is correct but not very +// helpful. template<> template<> template<class T> void A<int>::B<double>::mf1(T t) { } +// FIXME: This diagnostic could probably be better. template<class Y> template<> void A<Y>::B<double>::mf2() { } // expected-error{{does not refer}} diff --git a/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp b/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp new file mode 100644 index 0000000000..1f38e5a2c1 --- /dev/null +++ b/test/CXX/temp/temp.spec/temp.expl.spec/p19.cpp @@ -0,0 +1,30 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T> +struct X { + template<typename U> struct Inner { }; + + template<typename U> void f(T, U) { } +}; + +template<> template<typename U> +struct X<int>::Inner { + U member; +}; + +template<> template<typename U> +void X<int>::f(int x, U y) { + x = y; // expected-error{{incompatible type}} +} + +void test(X<int> xi, X<long> xl, float *fp) { + X<int>::Inner<float*> xii; + xii.member = fp; + xi.f(17, 25); + xi.f(17, 3.14159); + xi.f(17, fp); // expected-note{{instantiation}} + X<long>::Inner<float*> xli; + + xli.member = fp; // expected-error{{no member}} + xl.f(17, fp); // okay +} |