Author: rsmith Date: Wed May 1 17:49:14 2019 New Revision: 359747 URL: http://llvm.org/viewvc/llvm-project?rev=359747&view=rev Log: Replace ad-hoc tracking of pattern for an instantiated class-scope explicit function specialization with the MemberSpecializationInfo used everywhere else.
Not NFC: the ad-hoc pattern tracking was not being serialized / deserialized properly. That's fixed here. Modified: cfe/trunk/include/clang/AST/ASTContext.h cfe/trunk/include/clang/AST/ASTNodeTraverser.h cfe/trunk/include/clang/AST/Decl.h cfe/trunk/include/clang/AST/DeclTemplate.h cfe/trunk/include/clang/AST/RecursiveASTVisitor.h cfe/trunk/include/clang/Sema/Template.h cfe/trunk/lib/AST/ASTContext.cpp cfe/trunk/lib/AST/Decl.cpp cfe/trunk/lib/AST/DeclTemplate.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp cfe/trunk/lib/Serialization/ASTReaderDecl.cpp cfe/trunk/lib/Serialization/ASTWriterDecl.cpp cfe/trunk/test/PCH/cxx-templates.cpp cfe/trunk/test/PCH/cxx-templates.h Modified: cfe/trunk/include/clang/AST/ASTContext.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ASTContext.h (original) +++ cfe/trunk/include/clang/AST/ASTContext.h Wed May 1 17:49:14 2019 @@ -265,11 +265,6 @@ private: /// Mapping from __block VarDecls to BlockVarCopyInit. llvm::DenseMap<const VarDecl *, BlockVarCopyInit> BlockVarCopyInits; - /// Mapping from class scope functions specialization to their - /// template patterns. - llvm::DenseMap<const FunctionDecl*, FunctionDecl*> - ClassScopeSpecializationPattern; - /// Mapping from materialized temporaries with static storage duration /// that appear in constant initializers to their evaluated values. These are /// allocated in a std::map because their address must be stable. @@ -891,11 +886,6 @@ public: TemplateOrSpecializationInfo getTemplateOrSpecializationInfo(const VarDecl *Var); - FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD); - - void setClassScopeSpecializationPattern(FunctionDecl *FD, - FunctionDecl *Pattern); - /// Note that the static data member \p Inst is an instantiation of /// the static data member template \p Tmpl of a class template. void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, Modified: cfe/trunk/include/clang/AST/ASTNodeTraverser.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTNodeTraverser.h?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ASTNodeTraverser.h (original) +++ cfe/trunk/include/clang/AST/ASTNodeTraverser.h Wed May 1 17:49:14 2019 @@ -221,8 +221,12 @@ public: Visit(TP); } - void dumpTemplateArgumentListInfo(const TemplateArgumentListInfo &TALI) { - for (const auto &TA : TALI.arguments()) + void + dumpASTTemplateArgumentListInfo(const ASTTemplateArgumentListInfo *TALI) { + if (!TALI) + return; + + for (const auto &TA : TALI->arguments()) dumpTemplateArgumentLoc(TA); } @@ -465,8 +469,7 @@ public: void VisitClassScopeFunctionSpecializationDecl( const ClassScopeFunctionSpecializationDecl *D) { Visit(D->getSpecialization()); - if (D->hasExplicitTemplateArgs()) - dumpTemplateArgumentListInfo(D->templateArgs()); + dumpASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten()); } void VisitVarTemplateDecl(const VarTemplateDecl *D) { dumpTemplateDecl(D); } Modified: cfe/trunk/include/clang/AST/Decl.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Decl.h (original) +++ cfe/trunk/include/clang/AST/Decl.h Wed May 1 17:49:14 2019 @@ -1742,10 +1742,19 @@ class FunctionDecl : public DeclaratorDe public: /// The kind of templated function a FunctionDecl can be. enum TemplatedKind { + // Not templated. TK_NonTemplate, + // The pattern in a function template declaration. TK_FunctionTemplate, + // A non-template function that is an instantiation or explicit + // specialization of a member of a templated class. TK_MemberSpecialization, + // An instantiation or explicit specialization of a function template. + // Note: this might have been instantiated from a templated class if it + // is a class-scope explicit specialization. TK_FunctionTemplateSpecialization, + // A function template specialization that hasn't yet been resolved to a + // particular specialized function template. TK_DependentFunctionTemplateSpecialization }; @@ -2440,10 +2449,6 @@ public: return getPrimaryTemplate() != nullptr; } - /// Retrieve the class scope template pattern that this function - /// template specialization is instantiated from. - FunctionDecl *getClassScopeSpecializationPattern() const; - /// If this function is actually a function template specialization, /// retrieve information about this function template specialization. /// Otherwise, returns NULL. @@ -2530,6 +2535,11 @@ public: /// represents. TemplateSpecializationKind getTemplateSpecializationKind() const; + /// Determine the kind of template specialization this function represents + /// for the purpose of template instantiation. + TemplateSpecializationKind + getTemplateSpecializationKindForInstantiation() const; + /// Determine what kind of template instantiation this function /// represents. void setTemplateSpecializationKind(TemplateSpecializationKind TSK, Modified: cfe/trunk/include/clang/AST/DeclTemplate.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclTemplate.h (original) +++ cfe/trunk/include/clang/AST/DeclTemplate.h Wed May 1 17:49:14 2019 @@ -504,29 +504,13 @@ public: /// Provides information about a function template specialization, /// which is a FunctionDecl that has been explicitly specialization or /// instantiated from a function template. -class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode { - FunctionTemplateSpecializationInfo(FunctionDecl *FD, - FunctionTemplateDecl *Template, - TemplateSpecializationKind TSK, - const TemplateArgumentList *TemplateArgs, - const ASTTemplateArgumentListInfo *TemplateArgsAsWritten, - SourceLocation POI) - : Function(FD), Template(Template, TSK - 1), - TemplateArguments(TemplateArgs), - TemplateArgumentsAsWritten(TemplateArgsAsWritten), - PointOfInstantiation(POI) {} - -public: - static FunctionTemplateSpecializationInfo * - Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template, - TemplateSpecializationKind TSK, - const TemplateArgumentList *TemplateArgs, - const TemplateArgumentListInfo *TemplateArgsAsWritten, - SourceLocation POI); - - /// The function template specialization that this structure - /// describes. - FunctionDecl *Function; +class FunctionTemplateSpecializationInfo final + : public llvm::FoldingSetNode, + private llvm::TrailingObjects<FunctionTemplateSpecializationInfo, + MemberSpecializationInfo *> { + /// The function template specialization that this structure describes and a + /// flag indicating if the function is a member specialization. + llvm::PointerIntPair<FunctionDecl *, 1, bool> Function; /// The function template from which this function template /// specialization was generated. @@ -534,17 +518,50 @@ public: /// The two bits contain the top 4 values of TemplateSpecializationKind. llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template; +public: /// The template arguments used to produce the function template /// specialization from the function template. const TemplateArgumentList *TemplateArguments; /// The template arguments as written in the sources, if provided. + /// FIXME: Normally null; tail-allocate this. const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten; /// The point at which this function template specialization was /// first instantiated. SourceLocation PointOfInstantiation; +private: + FunctionTemplateSpecializationInfo( + FunctionDecl *FD, FunctionTemplateDecl *Template, + TemplateSpecializationKind TSK, const TemplateArgumentList *TemplateArgs, + const ASTTemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation POI, MemberSpecializationInfo *MSInfo) + : Function(FD, MSInfo ? 1 : 0), Template(Template, TSK - 1), + TemplateArguments(TemplateArgs), + TemplateArgumentsAsWritten(TemplateArgsAsWritten), + PointOfInstantiation(POI) { + if (MSInfo) + getTrailingObjects<MemberSpecializationInfo *>()[0] = MSInfo; + } + + size_t numTrailingObjects(OverloadToken<MemberSpecializationInfo*>) const { + return Function.getInt(); + } + +public: + friend TrailingObjects; + + static FunctionTemplateSpecializationInfo * + Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template, + TemplateSpecializationKind TSK, + const TemplateArgumentList *TemplateArgs, + const TemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation POI, MemberSpecializationInfo *MSInfo); + + /// Retrieve the declaration of the function template specialization. + FunctionDecl *getFunction() const { return Function.getPointer(); } + /// Retrieve the template from which this function was specialized. FunctionTemplateDecl *getTemplate() const { return Template.getPointer(); } @@ -587,9 +604,44 @@ public: PointOfInstantiation = POI; } + /// Get the specialization info if this function template specialization is + /// also a member specialization: + /// + /// \code + /// template<typename> struct A { + /// template<typename> void f(); + /// template<> void f<int>(); // ClassScopeFunctionSpecializationDecl + /// }; + /// \endcode + /// + /// Here, A<int>::f<int> is a function template specialization that is + /// an explicit specialization of A<int>::f, but it's also a member + /// specialization (an implicit instantiation in this case) of A::f<int>. + /// Further: + /// + /// \code + /// template<> template<> void A<int>::f<int>() {} + /// \endcode + /// + /// ... declares a function template specialization that is an explicit + /// specialization of A<int>::f, and is also an explicit member + /// specialization of A::f<int>. + /// + /// Note that the TemplateSpecializationKind of the MemberSpecializationInfo + /// need not be the same as that returned by getTemplateSpecializationKind(), + /// and represents the relationship between the function and the class-scope + /// explicit specialization in the original templated class -- whereas our + /// TemplateSpecializationKind represents the relationship between the + /// function and the function template, and should always be + /// TSK_ExplicitSpecialization whenever we have MemberSpecializationInfo. + MemberSpecializationInfo *getMemberSpecializationInfo() const { + return numTrailingObjects(OverloadToken<MemberSpecializationInfo *>()) + ? getTrailingObjects<MemberSpecializationInfo *>()[0] + : nullptr; + } + void Profile(llvm::FoldingSetNodeID &ID) { - Profile(ID, TemplateArguments->asArray(), - Function->getASTContext()); + Profile(ID, TemplateArguments->asArray(), getFunction()->getASTContext()); } static void @@ -955,7 +1007,7 @@ SpecEntryTraits<FunctionTemplateSpeciali using DeclType = FunctionDecl; static DeclType *getDecl(FunctionTemplateSpecializationInfo *I) { - return I->Function; + return I->getFunction(); } static ArrayRef<TemplateArgument> @@ -2408,8 +2460,6 @@ public: /// Declaration of a function specialization at template class scope. /// -/// This is a non-standard extension needed to support MSVC. -/// /// For example: /// \code /// template <class T> @@ -2422,17 +2472,18 @@ public: /// "template<> foo(int a)" will be saved in Specialization as a normal /// CXXMethodDecl. Then during an instantiation of class A, it will be /// transformed into an actual function specialization. +/// +/// FIXME: This is redundant; we could store the same information directly on +/// the CXXMethodDecl as a DependentFunctionTemplateSpecializationInfo. class ClassScopeFunctionSpecializationDecl : public Decl { CXXMethodDecl *Specialization; - bool HasExplicitTemplateArgs; - TemplateArgumentListInfo TemplateArgs; + const ASTTemplateArgumentListInfo *TemplateArgs; - ClassScopeFunctionSpecializationDecl(DeclContext *DC, SourceLocation Loc, - CXXMethodDecl *FD, bool Args, - TemplateArgumentListInfo TemplArgs) + ClassScopeFunctionSpecializationDecl( + DeclContext *DC, SourceLocation Loc, CXXMethodDecl *FD, + const ASTTemplateArgumentListInfo *TemplArgs) : Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc), - Specialization(FD), HasExplicitTemplateArgs(Args), - TemplateArgs(std::move(TemplArgs)) {} + Specialization(FD), TemplateArgs(TemplArgs) {} ClassScopeFunctionSpecializationDecl(EmptyShell Empty) : Decl(Decl::ClassScopeFunctionSpecialization, Empty) {} @@ -2444,17 +2495,20 @@ public: friend class ASTDeclWriter; CXXMethodDecl *getSpecialization() const { return Specialization; } - bool hasExplicitTemplateArgs() const { return HasExplicitTemplateArgs; } - const TemplateArgumentListInfo& templateArgs() const { return TemplateArgs; } + bool hasExplicitTemplateArgs() const { return TemplateArgs; } + const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { + return TemplateArgs; + } - static ClassScopeFunctionSpecializationDecl *Create(ASTContext &C, - DeclContext *DC, - SourceLocation Loc, - CXXMethodDecl *FD, - bool HasExplicitTemplateArgs, - TemplateArgumentListInfo TemplateArgs) { + static ClassScopeFunctionSpecializationDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation Loc, CXXMethodDecl *FD, + bool HasExplicitTemplateArgs, + const TemplateArgumentListInfo &TemplateArgs) { return new (C, DC) ClassScopeFunctionSpecializationDecl( - DC, Loc, FD, HasExplicitTemplateArgs, std::move(TemplateArgs)); + DC, Loc, FD, + HasExplicitTemplateArgs + ? ASTTemplateArgumentListInfo::Create(C, TemplateArgs) + : nullptr); } static ClassScopeFunctionSpecializationDecl * Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original) +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Wed May 1 17:49:14 2019 @@ -1458,9 +1458,9 @@ DEF_TRAVERSE_DECL(ClassScopeFunctionSpec TRY_TO(TraverseDecl(D->getSpecialization())); if (D->hasExplicitTemplateArgs()) { - const TemplateArgumentListInfo &args = D->templateArgs(); - TRY_TO(TraverseTemplateArgumentLocsHelper(args.getArgumentArray(), - args.size())); + TRY_TO(TraverseTemplateArgumentLocsHelper( + D->getTemplateArgsAsWritten()->getTemplateArgs(), + D->getTemplateArgsAsWritten()->NumTemplateArgs)); } }) Modified: cfe/trunk/include/clang/Sema/Template.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Template.h?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Template.h (original) +++ cfe/trunk/include/clang/Sema/Template.h Wed May 1 17:49:14 2019 @@ -475,7 +475,8 @@ class VarDecl; // A few supplemental visitor functions. Decl *VisitCXXMethodDecl(CXXMethodDecl *D, TemplateParameterList *TemplateParams, - bool IsClassScopeSpecialization = false); + Optional<const ASTTemplateArgumentListInfo *> + ClassScopeSpecializationArgs = llvm::None); Decl *VisitFunctionDecl(FunctionDecl *D, TemplateParameterList *TemplateParams); Decl *VisitDecl(Decl *D); Modified: cfe/trunk/lib/AST/ASTContext.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTContext.cpp (original) +++ cfe/trunk/lib/AST/ASTContext.cpp Wed May 1 17:49:14 2019 @@ -1381,24 +1381,6 @@ ASTContext::setTemplateOrSpecializationI TemplateOrInstantiation[Inst] = TSI; } -FunctionDecl *ASTContext::getClassScopeSpecializationPattern( - const FunctionDecl *FD){ - assert(FD && "Specialization is 0"); - llvm::DenseMap<const FunctionDecl*, FunctionDecl *>::const_iterator Pos - = ClassScopeSpecializationPattern.find(FD); - if (Pos == ClassScopeSpecializationPattern.end()) - return nullptr; - - return Pos->second; -} - -void ASTContext::setClassScopeSpecializationPattern(FunctionDecl *FD, - FunctionDecl *Pattern) { - assert(FD && "Specialization is 0"); - assert(Pattern && "Class scope specialization pattern is 0"); - ClassScopeSpecializationPattern[FD] = Pattern; -} - NamedDecl * ASTContext::getInstantiatedFromUsingDecl(NamedDecl *UUD) { auto Pos = InstantiatedFromUsingDecl.find(UUD); @@ -10033,8 +10015,7 @@ size_t ASTContext::getSideTableAllocated llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) + llvm::capacity_in_bytes(OverriddenMethods) + llvm::capacity_in_bytes(Types) + - llvm::capacity_in_bytes(VariableArrayTypes) + - llvm::capacity_in_bytes(ClassScopeSpecializationPattern); + llvm::capacity_in_bytes(VariableArrayTypes); } /// getIntTypeForBitwidth - Modified: cfe/trunk/lib/AST/Decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/lib/AST/Decl.cpp (original) +++ cfe/trunk/lib/AST/Decl.cpp Wed May 1 17:49:14 2019 @@ -3375,7 +3375,13 @@ FunctionDecl *FunctionDecl::getInstantia } MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const { - return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>(); + if (auto *MSI = + TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()) + return MSI; + if (auto *FTSI = TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo *>()) + return FTSI->getMemberSpecializationInfo(); + return nullptr; } void @@ -3394,6 +3400,8 @@ FunctionTemplateDecl *FunctionDecl::getD } void FunctionDecl::setDescribedFunctionTemplate(FunctionTemplateDecl *Template) { + assert(TemplateOrSpecialization.isNull() && + "Member function is already a specialization"); TemplateOrSpecialization = Template; } @@ -3402,19 +3410,15 @@ bool FunctionDecl::isImplicitlyInstantia if (isInvalidDecl()) return false; - switch (getTemplateSpecializationKind()) { + switch (getTemplateSpecializationKindForInstantiation()) { case TSK_Undeclared: case TSK_ExplicitInstantiationDefinition: + case TSK_ExplicitSpecialization: return false; case TSK_ImplicitInstantiation: return true; - // It is possible to instantiate TSK_ExplicitSpecialization kind - // if the FunctionDecl has a class scope specialization pattern. - case TSK_ExplicitSpecialization: - return getClassScopeSpecializationPattern() != nullptr; - case TSK_ExplicitInstantiationDeclaration: // Handled below. break; @@ -3437,26 +3441,12 @@ bool FunctionDecl::isImplicitlyInstantia } bool FunctionDecl::isTemplateInstantiation() const { - switch (getTemplateSpecializationKind()) { - case TSK_Undeclared: - case TSK_ExplicitSpecialization: - return false; - case TSK_ImplicitInstantiation: - case TSK_ExplicitInstantiationDeclaration: - case TSK_ExplicitInstantiationDefinition: - return true; - } - llvm_unreachable("All TSK values handled."); + // FIXME: Remove this, it's not clear what it means. (Which template + // specialization kind?) + return clang::isTemplateInstantiation(getTemplateSpecializationKind()); } FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { - // Handle class scope explicit specialization special case. - if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { - if (auto *Spec = getClassScopeSpecializationPattern()) - return getDefinitionOrSelf(Spec); - return nullptr; - } - // If this is a generic lambda call operator specialization, its // instantiation pattern is always its primary template's pattern // even if its primary template was instantiated from another @@ -3472,6 +3462,15 @@ FunctionDecl *FunctionDecl::getTemplateI return getDefinitionOrSelf(getPrimaryTemplate()->getTemplatedDecl()); } + if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) { + if (!clang::isTemplateInstantiation(Info->getTemplateSpecializationKind())) + return nullptr; + return getDefinitionOrSelf(cast<FunctionDecl>(Info->getInstantiatedFrom())); + } + + if (!clang::isTemplateInstantiation(getTemplateSpecializationKind())) + return nullptr; + if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) { while (Primary->getInstantiatedFromMemberTemplate()) { // If we have hit a point where the user provided a specialization of @@ -3484,9 +3483,6 @@ FunctionDecl *FunctionDecl::getTemplateI return getDefinitionOrSelf(Primary->getTemplatedDecl()); } - if (auto *MFD = getInstantiatedFromMemberFunction()) - return getDefinitionOrSelf(MFD); - return nullptr; } @@ -3494,15 +3490,11 @@ FunctionTemplateDecl *FunctionDecl::getP if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization .dyn_cast<FunctionTemplateSpecializationInfo*>()) { - return Info->Template.getPointer(); + return Info->getTemplate(); } return nullptr; } -FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const { - return getASTContext().getClassScopeSpecializationPattern(this); -} - FunctionTemplateSpecializationInfo * FunctionDecl::getTemplateSpecializationInfo() const { return TemplateOrSpecialization @@ -3537,15 +3529,19 @@ FunctionDecl::setFunctionTemplateSpecial TemplateSpecializationKind TSK, const TemplateArgumentListInfo *TemplateArgsAsWritten, SourceLocation PointOfInstantiation) { + assert((TemplateOrSpecialization.isNull() || + TemplateOrSpecialization.is<MemberSpecializationInfo *>()) && + "Member function is already a specialization"); assert(TSK != TSK_Undeclared && "Must specify the type of function template specialization"); - FunctionTemplateSpecializationInfo *Info - = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); - if (!Info) - Info = FunctionTemplateSpecializationInfo::Create(C, this, Template, TSK, - TemplateArgs, - TemplateArgsAsWritten, - PointOfInstantiation); + assert((TemplateOrSpecialization.isNull() || + TSK == TSK_ExplicitSpecialization) && + "Member specialization must be an explicit specialization"); + FunctionTemplateSpecializationInfo *Info = + FunctionTemplateSpecializationInfo::Create( + C, this, Template, TSK, TemplateArgs, TemplateArgsAsWritten, + PointOfInstantiation, + TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()); TemplateOrSpecialization = Info; Template->addSpecialization(Info, InsertPos); } @@ -3596,14 +3592,47 @@ DependentFunctionTemplateSpecializationI TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { // For a function template specialization, query the specialization // information object. - FunctionTemplateSpecializationInfo *FTSInfo - = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); - if (FTSInfo) + if (FunctionTemplateSpecializationInfo *FTSInfo = + TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo *>()) return FTSInfo->getTemplateSpecializationKind(); - MemberSpecializationInfo *MSInfo - = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>(); - if (MSInfo) + if (MemberSpecializationInfo *MSInfo = + TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()) + return MSInfo->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +TemplateSpecializationKind +FunctionDecl::getTemplateSpecializationKindForInstantiation() const { + // This is the same as getTemplateSpecializationKind(), except that for a + // function that is both a function template specialization and a member + // specialization, we prefer the member specialization information. Eg: + // + // template<typename T> struct A { + // template<typename U> void f() {} + // template<> void f<int>() {} + // }; + // + // For A<int>::f<int>(): + // * getTemplateSpecializationKind() will return TSK_ExplicitSpecialization + // * getTemplateSpecializationKindForInstantiation() will return + // TSK_ImplicitInstantiation + // + // This reflects the facts that A<int>::f<int> is an explicit specialization + // of A<int>::f, and that A<int>::f<int> should be implicitly instantiated + // from A::f<int> if a definition is needed. + if (FunctionTemplateSpecializationInfo *FTSInfo = + TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo *>()) { + if (auto *MSInfo = FTSInfo->getMemberSpecializationInfo()) + return MSInfo->getTemplateSpecializationKind(); + return FTSInfo->getTemplateSpecializationKind(); + } + + if (MemberSpecializationInfo *MSInfo = + TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()) return MSInfo->getTemplateSpecializationKind(); return TSK_Undeclared; Modified: cfe/trunk/lib/AST/DeclTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclTemplate.cpp (original) +++ cfe/trunk/lib/AST/DeclTemplate.cpp Wed May 1 17:49:14 2019 @@ -687,22 +687,20 @@ TemplateArgumentList::CreateCopy(ASTCont return new (Mem) TemplateArgumentList(Args); } -FunctionTemplateSpecializationInfo * -FunctionTemplateSpecializationInfo::Create(ASTContext &C, FunctionDecl *FD, - FunctionTemplateDecl *Template, - TemplateSpecializationKind TSK, - const TemplateArgumentList *TemplateArgs, - const TemplateArgumentListInfo *TemplateArgsAsWritten, - SourceLocation POI) { +FunctionTemplateSpecializationInfo *FunctionTemplateSpecializationInfo::Create( + ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template, + TemplateSpecializationKind TSK, const TemplateArgumentList *TemplateArgs, + const TemplateArgumentListInfo *TemplateArgsAsWritten, SourceLocation POI, + MemberSpecializationInfo *MSInfo) { const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr; if (TemplateArgsAsWritten) ArgsAsWritten = ASTTemplateArgumentListInfo::Create(C, *TemplateArgsAsWritten); - return new (C) FunctionTemplateSpecializationInfo(FD, Template, TSK, - TemplateArgs, - ArgsAsWritten, - POI); + void *Mem = + C.Allocate(totalSizeToAlloc<MemberSpecializationInfo *>(MSInfo ? 1 : 0)); + return new (Mem) FunctionTemplateSpecializationInfo( + FD, Template, TSK, TemplateArgs, ArgsAsWritten, POI, MSInfo); } //===----------------------------------------------------------------------===// @@ -935,7 +933,7 @@ ClassScopeFunctionSpecializationDecl * ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) ClassScopeFunctionSpecializationDecl( - nullptr, SourceLocation(), nullptr, false, TemplateArgumentListInfo()); + nullptr, SourceLocation(), nullptr, nullptr); } //===----------------------------------------------------------------------===// Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed May 1 17:49:14 2019 @@ -14859,7 +14859,8 @@ void Sema::MarkFunctionReferenced(Source // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { - TemplateSpecializationKind TSK = Func->getTemplateSpecializationKind(); + TemplateSpecializationKind TSK = + Func->getTemplateSpecializationKindForInstantiation(); SourceLocation PointOfInstantiation = Func->getPointOfInstantiation(); bool FirstInstantiation = PointOfInstantiation.isInvalid(); if (FirstInstantiation) { Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed May 1 17:49:14 2019 @@ -133,9 +133,8 @@ Sema::getTemplateInstantiationArgs(Named // Add template arguments from a function template specialization. else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) { if (!RelativeToPrimary && - (Function->getTemplateSpecializationKind() == - TSK_ExplicitSpecialization && - !Function->getClassScopeSpecializationPattern())) + Function->getTemplateSpecializationKindForInstantiation() == + TSK_ExplicitSpecialization) break; if (const TemplateArgumentList *TemplateArgs Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed May 1 17:49:14 2019 @@ -1951,10 +1951,10 @@ Decl *TemplateDeclInstantiator::VisitFun return Function; } -Decl * -TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, - TemplateParameterList *TemplateParams, - bool IsClassScopeSpecialization) { +Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( + CXXMethodDecl *D, TemplateParameterList *TemplateParams, + Optional<const ASTTemplateArgumentListInfo *> + ClassScopeSpecializationArgs) { FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); if (FunctionTemplate && !TemplateParams) { // We are creating a function template specialization from a function @@ -2158,7 +2158,8 @@ TemplateDeclInstantiator::VisitCXXMethod IsExplicitSpecialization = true; } else if (const ASTTemplateArgumentListInfo *Info = - D->getTemplateSpecializationArgsAsWritten()) { + ClassScopeSpecializationArgs.getValueOr( + D->getTemplateSpecializationArgsAsWritten())) { SemaRef.LookupQualifiedName(Previous, DC); TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), @@ -2173,6 +2174,14 @@ TemplateDeclInstantiator::VisitCXXMethod Method->setInvalidDecl(); IsExplicitSpecialization = true; + } else if (ClassScopeSpecializationArgs) { + // Class-scope explicit specialization written without explicit template + // arguments. + SemaRef.LookupQualifiedName(Previous, DC); + if (SemaRef.CheckFunctionTemplateSpecialization(Method, nullptr, Previous)) + Method->setInvalidDecl(); + + IsExplicitSpecialization = true; } else if (!FunctionTemplate || TemplateParams || isFriend) { SemaRef.LookupQualifiedName(Previous, Record); @@ -2184,9 +2193,8 @@ TemplateDeclInstantiator::VisitCXXMethod Previous.clear(); } - if (!IsClassScopeSpecialization) - SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, - IsExplicitSpecialization); + SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, + IsExplicitSpecialization); if (D->isPure()) SemaRef.CheckPureMethod(Method, SourceRange()); @@ -2209,6 +2217,12 @@ TemplateDeclInstantiator::VisitCXXMethod if (D->isDeletedAsWritten()) SemaRef.SetDeclDeleted(Method, Method->getLocation()); + // If this is an explicit specialization, mark the implicitly-instantiated + // template specialization as being an explicit specialization too. + // FIXME: Is this necessary? + if (IsExplicitSpecialization && !isFriend) + SemaRef.CompleteMemberSpecialization(Method, Previous); + // If there's a function template, let our caller handle it. if (FunctionTemplate) { // do nothing @@ -2229,7 +2243,7 @@ TemplateDeclInstantiator::VisitCXXMethod // Otherwise, add the declaration. We don't need to do this for // class-scope specializations because we'll have matched them with // the appropriate template. - } else if (!IsClassScopeSpecialization) { + } else { Owner->addDecl(Method); } @@ -2839,38 +2853,8 @@ Decl *TemplateDeclInstantiator::VisitUsi Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *Decl) { CXXMethodDecl *OldFD = Decl->getSpecialization(); - CXXMethodDecl *NewFD = - cast_or_null<CXXMethodDecl>(VisitCXXMethodDecl(OldFD, nullptr, true)); - if (!NewFD) - return nullptr; - - TemplateArgumentListInfo ExplicitTemplateArgs; - TemplateArgumentListInfo *ExplicitTemplateArgsPtr = nullptr; - if (Decl->hasExplicitTemplateArgs()) { - if (SemaRef.Subst(Decl->templateArgs().getArgumentArray(), - Decl->templateArgs().size(), ExplicitTemplateArgs, - TemplateArgs)) - return nullptr; - ExplicitTemplateArgsPtr = &ExplicitTemplateArgs; - } - - LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName, - Sema::ForExternalRedeclaration); - SemaRef.LookupQualifiedName(Previous, SemaRef.CurContext); - if (SemaRef.CheckFunctionTemplateSpecialization( - NewFD, ExplicitTemplateArgsPtr, Previous)) { - NewFD->setInvalidDecl(); - return NewFD; - } - - // Associate the specialization with the pattern. - FunctionDecl *Specialization = cast<FunctionDecl>(Previous.getFoundDecl()); - assert(Specialization && "Class scope Specialization is null"); - SemaRef.Context.setClassScopeSpecializationPattern(Specialization, OldFD); - - // FIXME: If this is a definition, check for redefinition errors! - - return NewFD; + return cast_or_null<CXXMethodDecl>( + VisitCXXMethodDecl(OldFD, nullptr, Decl->getTemplateArgsAsWritten())); } Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( @@ -4068,9 +4052,9 @@ void Sema::InstantiateFunctionDefinition // Never instantiate an explicit specialization except if it is a class scope // explicit specialization. - TemplateSpecializationKind TSK = Function->getTemplateSpecializationKind(); - if (TSK == TSK_ExplicitSpecialization && - !Function->getClassScopeSpecializationPattern()) + TemplateSpecializationKind TSK = + Function->getTemplateSpecializationKindForInstantiation(); + if (TSK == TSK_ExplicitSpecialization) return; // Find the function body that we'll be substituting. Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed May 1 17:49:14 2019 @@ -928,12 +928,22 @@ void ASTDeclReader::VisitFunctionDecl(Fu TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc); for (unsigned i = 0, e = TemplArgLocs.size(); i != e; ++i) TemplArgsInfo.addArgument(TemplArgLocs[i]); - FunctionTemplateSpecializationInfo *FTInfo - = FunctionTemplateSpecializationInfo::Create(C, FD, Template, TSK, - TemplArgList, - HasTemplateArgumentsAsWritten ? &TemplArgsInfo - : nullptr, - POI); + + MemberSpecializationInfo *MSInfo = nullptr; + if (Record.readInt()) { + auto *FD = ReadDeclAs<FunctionDecl>(); + auto TSK = (TemplateSpecializationKind)Record.readInt(); + SourceLocation POI = ReadSourceLocation(); + + MSInfo = new (C) MemberSpecializationInfo(FD, TSK); + MSInfo->setPointOfInstantiation(POI); + } + + FunctionTemplateSpecializationInfo *FTInfo = + FunctionTemplateSpecializationInfo::Create( + C, FD, Template, TSK, TemplArgList, + HasTemplateArgumentsAsWritten ? &TemplArgsInfo : nullptr, POI, + MSInfo); FD->TemplateOrSpecialization = FTInfo; if (FD->isCanonicalDecl()) { // if canonical add to template's set. @@ -956,7 +966,7 @@ void ASTDeclReader::VisitFunctionDecl(Fu else { assert(Reader.getContext().getLangOpts().Modules && "already deserialized this template specialization"); - mergeRedeclarable(FD, ExistingInfo->Function, Redecl); + mergeRedeclarable(FD, ExistingInfo->getFunction(), Redecl); } } break; @@ -2244,6 +2254,8 @@ void ASTDeclReader::VisitClassScopeFunct ClassScopeFunctionSpecializationDecl *D) { VisitDecl(D); D->Specialization = ReadDeclAs<CXXMethodDecl>(); + if (Record.readInt()) + D->TemplateArgs = Record.readASTTemplateArgumentListInfo(); } void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Wed May 1 17:49:14 2019 @@ -596,6 +596,16 @@ void ASTDeclWriter::VisitFunctionDecl(Fu Record.AddSourceLocation(FTSInfo->getPointOfInstantiation()); + if (MemberSpecializationInfo *MemberInfo = + FTSInfo->getMemberSpecializationInfo()) { + Record.push_back(1); + Record.AddDeclRef(MemberInfo->getInstantiatedFrom()); + Record.push_back(MemberInfo->getTemplateSpecializationKind()); + Record.AddSourceLocation(MemberInfo->getPointOfInstantiation()); + } else { + Record.push_back(0); + } + if (D->isCanonicalDecl()) { // Write the template that contains the specializations set. We will // add a FunctionTemplateSpecializationInfo to it when reading. @@ -1555,6 +1565,9 @@ void ASTDeclWriter::VisitClassScopeFunct ClassScopeFunctionSpecializationDecl *D) { VisitDecl(D); Record.AddDeclRef(D->getSpecialization()); + Record.push_back(D->hasExplicitTemplateArgs()); + if (D->hasExplicitTemplateArgs()) + Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten()); Code = serialization::DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION; } Modified: cfe/trunk/test/PCH/cxx-templates.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-templates.cpp?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/test/PCH/cxx-templates.cpp (original) +++ cfe/trunk/test/PCH/cxx-templates.cpp Wed May 1 17:49:14 2019 @@ -1,20 +1,20 @@ // Test this without pch. -// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include %S/cxx-templates.h -verify %s -ast-dump -o - +// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include %S/cxx-templates.h -verify %s // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include %S/cxx-templates.h %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s // Test with pch. // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h -// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t -verify %s -ast-dump -o - +// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t -verify %s // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS | FileCheck %s // Test with modules. // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -x c++-header -emit-pch -o %t %S/cxx-templates.h -// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t -verify %s -ast-dump -o - +// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t -verify %s // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fexceptions -fmodules -include-pch %t %s -emit-llvm -o - -error-on-deserialized-decl doNotDeserialize -DNO_ERRORS -fmodules-ignore-macro=NO_ERRORS | FileCheck %s // Test with pch and delayed template parsing. // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -x c++-header -emit-pch -o %t %S/cxx-templates.h -// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t -verify %s -ast-dump -o - +// RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t -verify %s // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fcxx-exceptions -fdelayed-template-parsing -fexceptions -include-pch %t %s -emit-llvm -o - -DNO_ERRORS | FileCheck %s // CHECK: define weak_odr {{.*}}void @_ZN2S4IiE1mEv @@ -132,3 +132,25 @@ int test() { return z1 + z2 + z3; } } // end namespace PR34728 + +namespace ClassScopeExplicitSpecializations { + // FIXME: It's unclear these warnings (and the behavior they're describing) + // are desirable. These explicit instantiations could meaningfully + // instantiate the explicit specializations defined in the primary template. + template int A<3>::f<0>() const; // expected-warning {{has no effect}} + template int A<3>::f<1>() const; + template int A<4>::f<0>() const; // expected-warning {{has no effect}} + template int A<4>::f<1>() const; + // expected-note@cxx-templates.h:403 2{{here}} + + static_assert(A<0>().f<1>() == 3, ""); + static_assert(A<0>().f<0>() == 4, ""); + static_assert(A<1>().f<1>() == 1, ""); + static_assert(A<1>().f<0>() == 2, ""); + static_assert(A<2>().f<1>() == 1, ""); + static_assert(A<2>().f<0>() == 2, ""); + static_assert(A<3>().f<1>() == 1, ""); + static_assert(A<3>().f<0>() == 2, ""); + static_assert(A<4>().f<1>() == 1, ""); + static_assert(A<4>().f<0>() == 2, ""); +} Modified: cfe/trunk/test/PCH/cxx-templates.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-templates.h?rev=359747&r1=359746&r2=359747&view=diff ============================================================================== --- cfe/trunk/test/PCH/cxx-templates.h (original) +++ cfe/trunk/test/PCH/cxx-templates.h Wed May 1 17:49:14 2019 @@ -396,3 +396,19 @@ C<D> func3(D const &d) { } } // end namespace PR34728 + +namespace ClassScopeExplicitSpecializations { + template<int> struct A { + template<int> constexpr int f() const { return 1; } + template<> constexpr int f<0>() const { return 2; } + }; + template<> template<int> constexpr int A<0>::f() const { return 3; } + template<> template<> constexpr int A<0>::f<0>() const { return 4; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winstantiation-after-specialization" + template int A<2>::f<0>() const; +#pragma clang diagnostic pop + template int A<2>::f<1>() const; + extern template int A<3>::f<0>() const; + extern template int A<3>::f<1>() const; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits