https://github.com/sdkrystian updated https://github.com/llvm/llvm-project/pull/66636
>From 4ea4e89cb47ed7e4d3f1cf2a9d99d2f7e9ad33bb Mon Sep 17 00:00:00 2001 From: Krystian Stasiowski <sdkryst...@gmail.com> Date: Fri, 25 Aug 2023 14:07:32 -0400 Subject: [PATCH] [clang] remove ClassScopeFunctionSpecializationDecl --- .../clang-tidy/modernize/UseEmplaceCheck.cpp | 8 +- .../clangd/SemanticHighlighting.cpp | 9 -- clang/docs/ReleaseNotes.rst | 5 + clang/include/clang/AST/ASTNodeTraverser.h | 11 +- clang/include/clang/AST/Decl.h | 10 +- clang/include/clang/AST/DeclTemplate.h | 150 +++--------------- clang/include/clang/AST/RecursiveASTVisitor.h | 17 +- clang/include/clang/Basic/DeclNodes.td | 1 - .../clang/Basic/DiagnosticSemaKinds.td | 8 +- clang/include/clang/Sema/Sema.h | 6 +- clang/include/clang/Sema/Template.h | 2 - .../include/clang/Serialization/ASTBitCodes.h | 4 - .../clang/Serialization/ASTRecordReader.h | 2 + clang/lib/AST/ASTImporter.cpp | 26 ++- clang/lib/AST/Decl.cpp | 71 ++++++--- clang/lib/AST/DeclBase.cpp | 2 - clang/lib/AST/DeclTemplate.cpp | 13 -- clang/lib/AST/ODRHash.cpp | 4 + clang/lib/CodeGen/CGDecl.cpp | 1 - clang/lib/Index/IndexSymbol.cpp | 1 - clang/lib/Sema/SemaDecl.cpp | 112 ++++++------- clang/lib/Sema/SemaTemplate.cpp | 14 +- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 123 +++++++------- clang/lib/Serialization/ASTCommon.cpp | 1 - clang/lib/Serialization/ASTReader.cpp | 19 ++- clang/lib/Serialization/ASTReaderDecl.cpp | 59 ++----- clang/lib/Serialization/ASTWriter.cpp | 1 - clang/lib/Serialization/ASTWriterDecl.cpp | 42 ++--- .../Checkers/SmartPtrModeling.cpp | 2 +- clang/test/AST/ast-dump-decl.cpp | 9 +- clang/test/CXX/drs/dr7xx.cpp | 5 + .../test/SemaTemplate/instantiate-method.cpp | 23 ++- clang/tools/libclang/CIndex.cpp | 1 - 33 files changed, 308 insertions(+), 454 deletions(-) diff --git a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp index 554abcd900e329c..b85dde5644d313f 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseEmplaceCheck.cpp @@ -67,11 +67,9 @@ AST_MATCHER_P(CallExpr, hasLastArgument, // function had parameters defined (this is useful to check if there is only one // variadic argument). AST_MATCHER(CXXMemberCallExpr, hasSameNumArgsAsDeclNumParams) { - if (Node.getMethodDecl()->isFunctionTemplateSpecialization()) - return Node.getNumArgs() == Node.getMethodDecl() - ->getPrimaryTemplate() - ->getTemplatedDecl() - ->getNumParams(); + if (const FunctionTemplateDecl *Primary = + Node.getMethodDecl()->getPrimaryTemplate()) + return Node.getNumArgs() == Primary->getTemplatedDecl()->getNumParams(); return Node.getNumArgs() == Node.getMethodDecl()->getNumParams(); } diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp index 45c01634e2e38d1..7649e37e1f96663 100644 --- a/clang-tools-extra/clangd/SemanticHighlighting.cpp +++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -715,13 +715,6 @@ class CollectExtraHighlightings return true; } - bool VisitClassScopeFunctionSpecializationDecl( - ClassScopeFunctionSpecializationDecl *D) { - if (auto *Args = D->getTemplateArgsAsWritten()) - H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc()); - return true; - } - bool VisitDeclRefExpr(DeclRefExpr *E) { H.addAngleBracketTokens(E->getLAngleLoc(), E->getRAngleLoc()); return true; @@ -752,8 +745,6 @@ class CollectExtraHighlightings } if (auto *Args = D->getTemplateSpecializationArgsAsWritten()) H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc()); - if (auto *I = D->getDependentSpecializationInfo()) - H.addAngleBracketTokens(I->getLAngleLoc(), I->getRAngleLoc()); return true; } diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d2a435041a1542f..ea737fdb5fdad15 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -71,6 +71,11 @@ C++ Specific Potentially Breaking Changes (`#49884 <https://github.com/llvm/llvm-project/issues/49884>`_), and (`#61273 <https://github.com/llvm/llvm-project/issues/61273>`_) +- The `ClassScopeFunctionSpecializationDecl` AST node has been removed. Dependent class scope +explicit function template specializations now use `DependentFunctionTemplateSpecializationInfo` +to store candidate primary templates and explicit template arguments. This should not impact users +of Clang as a compiler, but it may break assumptions in Clang-based tools iterating over the AST. + ABI Changes in This Version --------------------------- - Following the SystemV ABI for x86-64, ``__int128`` arguments will no longer diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 1151a756ff377b6..cc8dab97f8b010f 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -426,8 +426,12 @@ class ASTNodeTraverser } void VisitFunctionDecl(const FunctionDecl *D) { - if (const auto *FTSI = D->getTemplateSpecializationInfo()) + if (FunctionTemplateSpecializationInfo *FTSI = + D->getTemplateSpecializationInfo()) dumpTemplateArgumentList(*FTSI->TemplateArguments); + else if (DependentFunctionTemplateSpecializationInfo *DFTSI = + D->getDependentSpecializationInfo()) + dumpASTTemplateArgumentListInfo(DFTSI->TemplateArgumentsAsWritten); if (D->param_begin()) for (const auto *Parameter : D->parameters()) @@ -578,11 +582,6 @@ class ASTNodeTraverser dumpTemplateParameters(D->getTemplateParameters()); } - void VisitClassScopeFunctionSpecializationDecl( - const ClassScopeFunctionSpecializationDecl *D) { - Visit(D->getSpecialization()); - dumpASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten()); - } void VisitVarTemplateDecl(const VarTemplateDecl *D) { dumpTemplateDecl(D); } void VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) { diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 2830861add39e7c..7f076cc77ea82cb 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2845,9 +2845,7 @@ class FunctionDecl : public DeclaratorDecl, /// Determine whether this function is a function template /// specialization. - bool isFunctionTemplateSpecialization() const { - return getPrimaryTemplate() != nullptr; - } + bool isFunctionTemplateSpecialization() const; /// If this function is actually a function template specialization, /// retrieve information about this function template specialization. @@ -2930,9 +2928,9 @@ class FunctionDecl : public DeclaratorDecl, /// Specifies that this function declaration is actually a /// dependent function template specialization. - void setDependentTemplateSpecialization(ASTContext &Context, - const UnresolvedSetImpl &Templates, - const TemplateArgumentListInfo &TemplateArgs); + void setDependentTemplateSpecialization( + ASTContext &Context, const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo *TemplateArgs); DependentFunctionTemplateSpecializationInfo * getDependentSpecializationInfo() const; diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 6264f15d6ffb961..54d28227a4ae91b 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -583,7 +583,7 @@ class FunctionTemplateSpecializationInfo final /// \code /// template<typename> struct A { /// template<typename> void f(); - /// template<> void f<int>(); // ClassScopeFunctionSpecializationDecl + /// template<> void f<int>(); /// }; /// \endcode /// @@ -682,82 +682,48 @@ class MemberSpecializationInfo { /// Provides information about a dependent function-template /// specialization declaration. /// -/// Since explicit function template specialization and instantiation -/// declarations can only appear in namespace scope, and you can only -/// specialize a member of a fully-specialized class, the only way to -/// get one of these is in a friend declaration like the following: +/// This is used for function templates explicit specializations declared +/// within class templates: +/// +/// \code +/// template<typename> struct A { +/// template<typename> void f(); +/// template<> void f<int>(); // DependentFunctionTemplateSpecializationInfo +/// }; +/// \endcode +/// +/// As well as dependent friend declarations naming function template +/// specializations declared within class templates: /// /// \code /// template \<class T> void foo(T); /// template \<class T> class A { -/// friend void foo<>(T); +/// friend void foo<>(T); // DependentFunctionTemplateSpecializationInfo /// }; /// \endcode class DependentFunctionTemplateSpecializationInfo final : private llvm::TrailingObjects<DependentFunctionTemplateSpecializationInfo, - TemplateArgumentLoc, FunctionTemplateDecl *> { - /// The number of potential template candidates. - unsigned NumTemplates; - - /// The number of template arguments. - unsigned NumArgs; - - /// The locations of the left and right angle brackets. - SourceRange AngleLocs; + friend TrailingObjects; - size_t numTrailingObjects(OverloadToken<TemplateArgumentLoc>) const { - return NumArgs; - } - size_t numTrailingObjects(OverloadToken<FunctionTemplateDecl *>) const { - return NumTemplates; - } + /// The number of candidates for the primary template. + unsigned NumCandidates; DependentFunctionTemplateSpecializationInfo( - const UnresolvedSetImpl &Templates, - const TemplateArgumentListInfo &TemplateArgs); + const UnresolvedSetImpl &Candidates, + const ASTTemplateArgumentListInfo *TemplateArgsWritten); public: - friend TrailingObjects; + /// The template arguments as written in the sources, if provided. + const ASTTemplateArgumentListInfo *TemplateArgumentsAsWritten; static DependentFunctionTemplateSpecializationInfo * - Create(ASTContext &Context, const UnresolvedSetImpl &Templates, - const TemplateArgumentListInfo &TemplateArgs); - - /// Returns the number of function templates that this might - /// be a specialization of. - unsigned getNumTemplates() const { return NumTemplates; } + Create(ASTContext &Context, const UnresolvedSetImpl &Candidates, + const TemplateArgumentListInfo *TemplateArgs); - /// Returns the i'th template candidate. - FunctionTemplateDecl *getTemplate(unsigned I) const { - assert(I < getNumTemplates() && "template index out of range"); - return getTrailingObjects<FunctionTemplateDecl *>()[I]; - } - - /// Returns the explicit template arguments that were given. - const TemplateArgumentLoc *getTemplateArgs() const { - return getTrailingObjects<TemplateArgumentLoc>(); - } - - /// Returns the number of explicit template arguments that were given. - unsigned getNumTemplateArgs() const { return NumArgs; } - - llvm::ArrayRef<TemplateArgumentLoc> arguments() const { - return llvm::ArrayRef(getTemplateArgs(), getNumTemplateArgs()); - } - - /// Returns the nth template argument. - const TemplateArgumentLoc &getTemplateArg(unsigned I) const { - assert(I < getNumTemplateArgs() && "template arg index out of range"); - return getTemplateArgs()[I]; - } - - SourceLocation getLAngleLoc() const { - return AngleLocs.getBegin(); - } - - SourceLocation getRAngleLoc() const { - return AngleLocs.getEnd(); + /// Returns the candidates for the primary function template. + ArrayRef<FunctionTemplateDecl *> getCandidates() const { + return {getTrailingObjects<FunctionTemplateDecl *>(), NumCandidates}; } }; @@ -2613,70 +2579,6 @@ class TypeAliasTemplateDecl : public RedeclarableTemplateDecl { static bool classofKind(Kind K) { return K == TypeAliasTemplate; } }; -/// Declaration of a function specialization at template class scope. -/// -/// For example: -/// \code -/// template <class T> -/// class A { -/// template <class U> void foo(U a) { } -/// template<> void foo(int a) { } -/// } -/// \endcode -/// -/// "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; - const ASTTemplateArgumentListInfo *TemplateArgs; - - ClassScopeFunctionSpecializationDecl( - DeclContext *DC, SourceLocation Loc, CXXMethodDecl *FD, - const ASTTemplateArgumentListInfo *TemplArgs) - : Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc), - Specialization(FD), TemplateArgs(TemplArgs) {} - - ClassScopeFunctionSpecializationDecl(EmptyShell Empty) - : Decl(Decl::ClassScopeFunctionSpecialization, Empty) {} - - virtual void anchor(); - -public: - friend class ASTDeclReader; - friend class ASTDeclWriter; - - CXXMethodDecl *getSpecialization() const { return Specialization; } - bool hasExplicitTemplateArgs() const { return TemplateArgs; } - const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { - return 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 - ? ASTTemplateArgumentListInfo::Create(C, TemplateArgs) - : nullptr); - } - - static ClassScopeFunctionSpecializationDecl * - CreateDeserialized(ASTContext &Context, unsigned ID); - - // Implement isa/cast/dyncast/etc. - static bool classof(const Decl *D) { return classofKind(D->getKind()); } - - static bool classofKind(Kind K) { - return K == Decl::ClassScopeFunctionSpecialization; - } -}; - /// Represents a variable template specialization, which refers to /// a variable template with a given set of template arguments. /// diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 298489e7d4fc413..3dd23eb38eeabfc 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1563,16 +1563,6 @@ DEF_TRAVERSE_DECL(FriendTemplateDecl, { } }) -DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, { - TRY_TO(TraverseDecl(D->getSpecialization())); - - if (D->hasExplicitTemplateArgs()) { - TRY_TO(TraverseTemplateArgumentLocsHelper( - D->getTemplateArgsAsWritten()->getTemplateArgs(), - D->getTemplateArgsAsWritten()->NumTemplateArgs)); - } -}) - DEF_TRAVERSE_DECL(LinkageSpecDecl, {}) DEF_TRAVERSE_DECL(ExportDecl, {}) @@ -2154,6 +2144,13 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) { TALI->NumTemplateArgs)); } } + } else if (const DependentFunctionTemplateSpecializationInfo *DFSI = + D->getDependentSpecializationInfo()) { + if (const ASTTemplateArgumentListInfo *TALI = + DFSI->TemplateArgumentsAsWritten) { + TRY_TO(TraverseTemplateArgumentLocsHelper(TALI->getTemplateArgs(), + TALI->NumTemplateArgs)); + } } // Visit the function type itself, which can be either diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index 5e726c1bdf8fa5c..8b1f415dd5fe2cb 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -102,7 +102,6 @@ def FriendTemplate : DeclNode<Decl>; def StaticAssert : DeclNode<Decl>; def Block : DeclNode<Decl, "blocks">, DeclContext; def Captured : DeclNode<Decl>, DeclContext; -def ClassScopeFunctionSpecialization : DeclNode<Decl>; def Import : DeclNode<Decl>; def OMPThreadPrivate : DeclNode<Decl>; def OMPAllocate : DeclNode<Decl>; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index e3cd49bcc9ecc6a..21048b06398bfa3 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5240,11 +5240,11 @@ def err_explicit_specialization_inconsistent_storage_class : Error< "'%select{none|extern|static|__private_extern__|auto|register}0'">; def err_dependent_function_template_spec_no_match : Error< "no candidate function template was found for dependent" - " friend function template specialization">; + " %select{member|friend}0 function template specialization">; def note_dependent_function_template_spec_discard_reason : Note< - "candidate ignored: %select{not a function template" - "|not a member of the enclosing namespace;" - " did you mean to explicitly qualify the specialization?}0">; + "candidate ignored: %select{not a function template|" + "not a member of the enclosing %select{class template|" + "namespace; did you mean to explicitly qualify the specialization?}1}0">; // C++ class template specializations and out-of-line definitions def err_template_spec_needs_header : Error< diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f77e109bac323eb..1c88855a73970d3 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8451,9 +8451,9 @@ class Sema final { SourceLocation PrevPtOfInstantiation, bool &SuppressNew); - bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, - const TemplateArgumentListInfo &ExplicitTemplateArgs, - LookupResult &Previous); + bool CheckDependentFunctionTemplateSpecialization( + FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs, + LookupResult &Previous); bool CheckFunctionTemplateSpecialization( FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 1de2cc6917b424a..28d603bf115950a 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -630,8 +630,6 @@ enum class TemplateSubstitutionKind : char { // A few supplemental visitor functions. Decl *VisitCXXMethodDecl(CXXMethodDecl *D, TemplateParameterList *TemplateParams, - std::optional<const ASTTemplateArgumentListInfo *> - ClassScopeSpecializationArgs = std::nullopt, RewriteKind RK = RewriteKind::None); Decl *VisitFunctionDecl(FunctionDecl *D, TemplateParameterList *TemplateParams, diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 85f49e21b2e2ec1..5c32fbc079c9a65 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1475,10 +1475,6 @@ enum DeclCode { /// template template parameter pack. DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK, - /// A ClassScopeFunctionSpecializationDecl record a class scope - /// function specialization. (Microsoft extension). - DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION, - /// An ImportDecl recording a module import. DECL_IMPORT, diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index ca85163e0f21c6d..d643e54e3d923a7 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -155,6 +155,8 @@ class ASTRecordReader /// Reads a TemplateArgumentLoc, advancing Idx. TemplateArgumentLoc readTemplateArgumentLoc(); + void readTemplateArgumentListInfo(TemplateArgumentListInfo &Result); + const ASTTemplateArgumentListInfo* readASTTemplateArgumentListInfo(); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 29b9d492904f5c8..ecf13598a8d0372 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -3342,27 +3342,25 @@ Error ASTNodeImporter::ImportTemplateInformation( case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { auto *FromInfo = FromFD->getDependentSpecializationInfo(); - UnresolvedSet<8> TemplDecls; - unsigned NumTemplates = FromInfo->getNumTemplates(); - for (unsigned I = 0; I < NumTemplates; I++) { - if (Expected<FunctionTemplateDecl *> ToFTDOrErr = - import(FromInfo->getTemplate(I))) - TemplDecls.addDecl(*ToFTDOrErr); + UnresolvedSet<8> Candidates; + for (FunctionTemplateDecl *FTD : FromInfo->getCandidates()) { + if (Expected<FunctionTemplateDecl *> ToFTDOrErr = import(FTD)) + Candidates.addDecl(*ToFTDOrErr); else return ToFTDOrErr.takeError(); } // Import TemplateArgumentListInfo. TemplateArgumentListInfo ToTAInfo; - if (Error Err = ImportTemplateArgumentListInfo( - FromInfo->getLAngleLoc(), FromInfo->getRAngleLoc(), - llvm::ArrayRef(FromInfo->getTemplateArgs(), - FromInfo->getNumTemplateArgs()), - ToTAInfo)) - return Err; + const auto *FromTAArgsAsWritten = FromInfo->TemplateArgumentsAsWritten; + if (FromTAArgsAsWritten) + if (Error Err = + ImportTemplateArgumentListInfo(*FromTAArgsAsWritten, ToTAInfo)) + return Err; - ToFD->setDependentTemplateSpecialization(Importer.getToContext(), - TemplDecls, ToTAInfo); + ToFD->setDependentTemplateSpecialization( + Importer.getToContext(), Candidates, + FromTAArgsAsWritten ? &ToTAInfo : nullptr); return Error::success(); } } diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index b88df1edf845ac0..f4a73f137fcf87a 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3975,6 +3975,12 @@ void FunctionDecl::setDescribedFunctionTemplate( TemplateOrSpecialization = Template; } +bool FunctionDecl::isFunctionTemplateSpecialization() const { + return TemplateOrSpecialization.is<FunctionTemplateSpecializationInfo *>() || + TemplateOrSpecialization + .is<DependentFunctionTemplateSpecializationInfo *>(); +} + void FunctionDecl::setInstantiatedFromDecl(FunctionDecl *FD) { assert(TemplateOrSpecialization.isNull() && "Function is already a specialization"); @@ -4109,6 +4115,11 @@ FunctionDecl::getTemplateSpecializationArgsAsWritten() const { .dyn_cast<FunctionTemplateSpecializationInfo*>()) { return Info->TemplateArgumentsAsWritten; } + if (DependentFunctionTemplateSpecializationInfo *Info = + TemplateOrSpecialization + .dyn_cast<DependentFunctionTemplateSpecializationInfo *>()) { + return Info->TemplateArgumentsAsWritten; + } return nullptr; } @@ -4137,10 +4148,9 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C, Template->addSpecialization(Info, InsertPos); } -void -FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context, - const UnresolvedSetImpl &Templates, - const TemplateArgumentListInfo &TemplateArgs) { +void FunctionDecl::setDependentTemplateSpecialization( + ASTContext &Context, const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo *TemplateArgs) { assert(TemplateOrSpecialization.isNull()); DependentFunctionTemplateSpecializationInfo *Info = DependentFunctionTemplateSpecializationInfo::Create(Context, Templates, @@ -4156,28 +4166,26 @@ FunctionDecl::getDependentSpecializationInfo() const { DependentFunctionTemplateSpecializationInfo * DependentFunctionTemplateSpecializationInfo::Create( - ASTContext &Context, const UnresolvedSetImpl &Ts, - const TemplateArgumentListInfo &TArgs) { - void *Buffer = Context.Allocate( - totalSizeToAlloc<TemplateArgumentLoc, FunctionTemplateDecl *>( - TArgs.size(), Ts.size())); - return new (Buffer) DependentFunctionTemplateSpecializationInfo(Ts, TArgs); + ASTContext &Context, const UnresolvedSetImpl &Candidates, + const TemplateArgumentListInfo *TArgs) { + const auto *TArgsWritten = + TArgs ? ASTTemplateArgumentListInfo::Create(Context, *TArgs) : nullptr; + return new (Context.Allocate( + totalSizeToAlloc<FunctionTemplateDecl *>(Candidates.size()))) + DependentFunctionTemplateSpecializationInfo(Candidates, TArgsWritten); } DependentFunctionTemplateSpecializationInfo:: -DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts, - const TemplateArgumentListInfo &TArgs) - : AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) { - NumTemplates = Ts.size(); - NumArgs = TArgs.size(); - - FunctionTemplateDecl **TsArray = getTrailingObjects<FunctionTemplateDecl *>(); - for (unsigned I = 0, E = Ts.size(); I != E; ++I) - TsArray[I] = cast<FunctionTemplateDecl>(Ts[I]->getUnderlyingDecl()); - - TemplateArgumentLoc *ArgsArray = getTrailingObjects<TemplateArgumentLoc>(); - for (unsigned I = 0, E = TArgs.size(); I != E; ++I) - new (&ArgsArray[I]) TemplateArgumentLoc(TArgs[I]); + DependentFunctionTemplateSpecializationInfo( + const UnresolvedSetImpl &Candidates, + const ASTTemplateArgumentListInfo *TemplateArgsWritten) + : TemplateArgumentsAsWritten(TemplateArgsWritten), + NumCandidates(Candidates.size()) { + std::transform(Candidates.begin(), Candidates.end(), + getTrailingObjects<FunctionTemplateDecl *>(), + [](NamedDecl *ND) { + return cast<FunctionTemplateDecl>(ND->getUnderlyingDecl()); + }); } TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { @@ -4192,6 +4200,13 @@ TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()) return MSInfo->getTemplateSpecializationKind(); + // A dependent function template specialization is an explicit specialization, + // except when it's a friend declaration. + if (TemplateOrSpecialization + .is<DependentFunctionTemplateSpecializationInfo *>() && + getFriendObjectKind() == FOK_None) + return TSK_ExplicitSpecialization; + return TSK_Undeclared; } @@ -4206,6 +4221,11 @@ FunctionDecl::getTemplateSpecializationKindForInstantiation() const { // template<> void f<int>() {} // }; // + // Within the templated CXXRecordDecl, A<T>::f<int> is a dependent function + // template specialization; both getTemplateSpecializationKind() and + // getTemplateSpecializationKindForInstantiation() will return + // TSK_ExplicitSpecialization. + // // For A<int>::f<int>(): // * getTemplateSpecializationKind() will return TSK_ExplicitSpecialization // * getTemplateSpecializationKindForInstantiation() will return @@ -4226,6 +4246,11 @@ FunctionDecl::getTemplateSpecializationKindForInstantiation() const { TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo *>()) return MSInfo->getTemplateSpecializationKind(); + if (TemplateOrSpecialization + .is<DependentFunctionTemplateSpecializationInfo *>() && + getFriendObjectKind() == FOK_None) + return TSK_ExplicitSpecialization; + return TSK_Undeclared; } diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 46372f97289c30f..e2934dcc586632c 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -936,7 +936,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case BuiltinTemplate: case ClassTemplateSpecialization: case ClassTemplatePartialSpecialization: - case ClassScopeFunctionSpecialization: case VarTemplateSpecialization: case VarTemplatePartialSpecialization: case ObjCImplementation: @@ -1078,7 +1077,6 @@ bool Decl::AccessDeclContextCheck() const { // FIXME: a ClassTemplateSpecialization or CXXRecordDecl can have // AS_none as access specifier. isa<CXXRecordDecl>(this) || - isa<ClassScopeFunctionSpecializationDecl>(this) || isa<LifetimeExtendedTemporaryDecl>(this)) return true; diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 5e2742b4949f260..be385ca1152546e 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -1195,19 +1195,6 @@ TypeAliasTemplateDecl::newCommon(ASTContext &C) const { return CommonPtr; } -//===----------------------------------------------------------------------===// -// ClassScopeFunctionSpecializationDecl Implementation -//===----------------------------------------------------------------------===// - -void ClassScopeFunctionSpecializationDecl::anchor() {} - -ClassScopeFunctionSpecializationDecl * -ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C, - unsigned ID) { - return new (C, ID) ClassScopeFunctionSpecializationDecl( - nullptr, SourceLocation(), nullptr, nullptr); -} - //===----------------------------------------------------------------------===// // VarTemplateDecl Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 5eab315793b4113..7f9b5eb52e367eb 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -658,6 +658,10 @@ void ODRHash::AddFunctionDecl(const FunctionDecl *Function, if (F->isFunctionTemplateSpecialization()) { if (!isa<CXXMethodDecl>(DC)) return; if (DC->getLexicalParent()->isFileContext()) return; + // Skip class scope explicit function template specializations, + // as they have not yet been instantiated. + if (F->getDependentSpecializationInfo()) + return; // Inline method specializations are the only supported // specialization for now. } diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 99b94588f56f0a5..4d4c94d008c9dfc 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -96,7 +96,6 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::FriendTemplate: case Decl::Block: case Decl::Captured: - case Decl::ClassScopeFunctionSpecialization: case Decl::UsingShadow: case Decl::ConstructorUsingShadow: case Decl::ObjCTypeParam: diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp index d7316538f606141..cfdffeed834e687 100644 --- a/clang/lib/Index/IndexSymbol.cpp +++ b/clang/lib/Index/IndexSymbol.cpp @@ -346,7 +346,6 @@ SymbolInfo index::getSymbolInfo(const Decl *D) { } break; case Decl::ClassTemplatePartialSpecialization: - case Decl::ClassScopeFunctionSpecialization: case Decl::ClassTemplateSpecialization: case Decl::CXXRecord: case Decl::Enum: diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 324a3674732aa04..c6cb04b64f545e0 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -9775,7 +9775,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, bool isMemberSpecialization = false; bool isFunctionTemplateSpecialization = false; - bool isDependentClassScopeExplicitSpecialization = false; bool HasExplicitTemplateArgs = false; TemplateArgumentListInfo TemplateArgs; @@ -10415,12 +10414,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc); HasExplicitTemplateArgs = false; - } else { - assert((isFunctionTemplateSpecialization || - D.getDeclSpec().isFriendSpecified()) && - "should have a 'template<>' for this decl"); + } else if (isFriend) { // "friend void foo<>(int);" is an implicit specialization decl. isFunctionTemplateSpecialization = true; + } else { + assert(isFunctionTemplateSpecialization && + "should have a 'template<>' for this decl"); } } else if (isFriend && isFunctionTemplateSpecialization) { // This combination is only possible in a recovery case; the user @@ -10443,32 +10442,54 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (getLangOpts().CUDA && !isFunctionTemplateSpecialization) maybeAddCUDAHostDeviceAttrs(NewFD, Previous); - // If it's a friend (and only if it's a friend), it's possible - // that either the specialized function type or the specialized - // template is dependent, and therefore matching will fail. In - // this case, don't check the specialization yet. - if (isFunctionTemplateSpecialization && isFriend && - (NewFD->getType()->isDependentType() || DC->isDependentContext() || - TemplateSpecializationType::anyInstantiationDependentTemplateArguments( - TemplateArgs.arguments()))) { - assert(HasExplicitTemplateArgs && - "friend function specialization without template args"); - if (CheckDependentFunctionTemplateSpecialization(NewFD, TemplateArgs, - Previous)) - NewFD->setInvalidDecl(); - } else if (isFunctionTemplateSpecialization) { - if (CurContext->isDependentContext() && CurContext->isRecord() - && !isFriend) { - isDependentClassScopeExplicitSpecialization = true; - } else if (!NewFD->isInvalidDecl() && - CheckFunctionTemplateSpecialization( - NewFD, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr), - Previous)) - NewFD->setInvalidDecl(); + // Handle explict specializations of function templates + // and friend function declarations with an explicit + // template argument list. + if (isFunctionTemplateSpecialization) { + bool isDependentSpecialization = false; + if (isFriend) { + // For friend function specializations, this is a dependent + // specialization if its semantic context is dependent, its + // type is dependent, or if its template-id is dependent. + isDependentSpecialization = + DC->isDependentContext() || NewFD->getType()->isDependentType() || + (HasExplicitTemplateArgs && + TemplateSpecializationType:: + anyInstantiationDependentTemplateArguments( + TemplateArgs.arguments())); + assert(!isDependentSpecialization || + (HasExplicitTemplateArgs == isDependentSpecialization) && + "dependent friend function specialization without template " + "args"); + } else { + // For class-scope explicit specializations of function templates, + // if the lexical context is dependent, then the specialization + // is dependent. + isDependentSpecialization = + CurContext->isRecord() && CurContext->isDependentContext(); + } + + TemplateArgumentListInfo *ExplicitTemplateArgs = + HasExplicitTemplateArgs ? &TemplateArgs : nullptr; + if (isDependentSpecialization) { + // If it's a dependent specialization, it may not be possible + // to determine the primary template (for explicit specializations) + // or befriended declaration (for friends) until the enclosing + // template is instantiated. In such cases, we store the declarations + // found by name lookup and defer resolution until instantiation. + if (CheckDependentFunctionTemplateSpecialization( + NewFD, ExplicitTemplateArgs, Previous)) + NewFD->setInvalidDecl(); + } else if (!NewFD->isInvalidDecl()) { + if (CheckFunctionTemplateSpecialization(NewFD, ExplicitTemplateArgs, + Previous)) + NewFD->setInvalidDecl(); + } // C++ [dcl.stc]p1: // A storage-class-specifier shall not be specified in an explicit // specialization (14.7.3) + // FIXME: We should be checking this for dependent specializations. FunctionTemplateSpecializationInfo *Info = NewFD->getTemplateSpecializationInfo(); if (Info && SC != SC_None) { @@ -10491,21 +10512,19 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // Perform semantic checking on the function declaration. - if (!isDependentClassScopeExplicitSpecialization) { - if (!NewFD->isInvalidDecl() && NewFD->isMain()) - CheckMain(NewFD, D.getDeclSpec()); + if (!NewFD->isInvalidDecl() && NewFD->isMain()) + CheckMain(NewFD, D.getDeclSpec()); - if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint()) - CheckMSVCRTEntryPoint(NewFD); + if (!NewFD->isInvalidDecl() && NewFD->isMSVCRTEntryPoint()) + CheckMSVCRTEntryPoint(NewFD); - if (!NewFD->isInvalidDecl()) - D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, - isMemberSpecialization, - D.isFunctionDefinition())); - else if (!Previous.empty()) - // Recover gracefully from an invalid redeclaration. - D.setRedeclaration(true); - } + if (!NewFD->isInvalidDecl()) + D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, + isMemberSpecialization, + D.isFunctionDefinition())); + else if (!Previous.empty()) + // Recover gracefully from an invalid redeclaration. + D.setRedeclaration(true); assert((NewFD->isInvalidDecl() || NewFD->isMultiVersion() || !D.isRedeclaration() || @@ -10817,19 +10836,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - // Here we have an function template explicit specialization at class scope. - // The actual specialization will be postponed to template instatiation - // time via the ClassScopeFunctionSpecializationDecl node. - if (isDependentClassScopeExplicitSpecialization) { - ClassScopeFunctionSpecializationDecl *NewSpec = - ClassScopeFunctionSpecializationDecl::Create( - Context, CurContext, NewFD->getLocation(), - cast<CXXMethodDecl>(NewFD), - HasExplicitTemplateArgs, TemplateArgs); - CurContext->addDecl(NewSpec); - AddToScope = false; - } - // Diagnose availability attributes. Availability cannot be used on functions // that are run during load/unload. if (const auto *attr = NewFD->getAttr<AvailabilityAttr>()) { diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 080f005e04402cb..ff370dd1e080b2b 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -9334,10 +9334,9 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, /// /// There really isn't any useful analysis we can do here, so we /// just store the information. -bool -Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, - const TemplateArgumentListInfo &ExplicitTemplateArgs, - LookupResult &Previous) { +bool Sema::CheckDependentFunctionTemplateSpecialization( + FunctionDecl *FD, const TemplateArgumentListInfo *ExplicitTemplateArgs, + LookupResult &Previous) { // Remove anything from Previous that isn't a function template in // the correct context. DeclContext *FDLookupContext = FD->getDeclContext()->getRedeclContext(); @@ -9361,13 +9360,14 @@ Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, } F.done(); + bool IsFriend = FD->getFriendObjectKind() != Decl::FOK_None; if (Previous.empty()) { - Diag(FD->getLocation(), - diag::err_dependent_function_template_spec_no_match); + Diag(FD->getLocation(), diag::err_dependent_function_template_spec_no_match) + << IsFriend; for (auto &P : DiscardedCandidates) Diag(P.second->getLocation(), diag::note_dependent_function_template_spec_discard_reason) - << P.first; + << P.first << IsFriend; return true; } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 071366ac0ee9834..ec0f7d1fe0ddd8e 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2247,42 +2247,46 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( D->isLocalExternDecl() ? Sema::ForExternalRedeclaration : SemaRef.forRedeclarationInCurContext()); - if (DependentFunctionTemplateSpecializationInfo *Info - = D->getDependentSpecializationInfo()) { - assert(isFriend && "non-friend has dependent specialization info?"); + if (DependentFunctionTemplateSpecializationInfo *DFTSI = + D->getDependentSpecializationInfo()) { + assert(isFriend && "dependent specialization info on " + "non-member non-friend function?"); // Instantiate the explicit template arguments. - TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), - Info->getRAngleLoc()); - if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs, - ExplicitArgs)) - return nullptr; - - // Map the candidate templates to their instantiations. - for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) { - Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(), - Info->getTemplate(I), - TemplateArgs); - if (!Temp) return nullptr; + TemplateArgumentListInfo ExplicitArgs; + if (const auto *ArgsWritten = DFTSI->TemplateArgumentsAsWritten) { + ExplicitArgs.setLAngleLoc(ArgsWritten->getLAngleLoc()); + ExplicitArgs.setRAngleLoc(ArgsWritten->getRAngleLoc()); + if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs, + ExplicitArgs)) + return nullptr; + } - Previous.addDecl(cast<FunctionTemplateDecl>(Temp)); + // Map the candidates for the primary template to their instantiations. + for (FunctionTemplateDecl *FTD : DFTSI->getCandidates()) { + if (NamedDecl *ND = + SemaRef.FindInstantiatedDecl(D->getLocation(), FTD, TemplateArgs)) + Previous.addDecl(ND); + else + return nullptr; } - if (SemaRef.CheckFunctionTemplateSpecialization(Function, - &ExplicitArgs, - Previous)) + if (SemaRef.CheckFunctionTemplateSpecialization( + Function, + DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr, + Previous)) Function->setInvalidDecl(); IsExplicitSpecialization = true; - } else if (const ASTTemplateArgumentListInfo *Info = + } else if (const ASTTemplateArgumentListInfo *ArgsWritten = D->getTemplateSpecializationArgsAsWritten()) { // The name of this function was written as a template-id. SemaRef.LookupQualifiedName(Previous, DC); // Instantiate the explicit template arguments. - TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), - Info->getRAngleLoc()); - if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs, + TemplateArgumentListInfo ExplicitArgs(ArgsWritten->getLAngleLoc(), + ArgsWritten->getRAngleLoc()); + if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs, ExplicitArgs)) return nullptr; @@ -2404,8 +2408,6 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( CXXMethodDecl *D, TemplateParameterList *TemplateParams, - std::optional<const ASTTemplateArgumentListInfo *> - ClassScopeSpecializationArgs, RewriteKind FunctionRewriteKind) { FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); if (FunctionTemplate && !TemplateParams) { @@ -2635,41 +2637,41 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( // If the name of this function was written as a template-id, instantiate // the explicit template arguments. - if (DependentFunctionTemplateSpecializationInfo *Info - = D->getDependentSpecializationInfo()) { - assert(isFriend && "non-friend has dependent specialization info?"); - + if (DependentFunctionTemplateSpecializationInfo *DFTSI = + D->getDependentSpecializationInfo()) { // Instantiate the explicit template arguments. - TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), - Info->getRAngleLoc()); - if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs, - ExplicitArgs)) - return nullptr; - - // Map the candidate templates to their instantiations. - for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) { - Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(), - Info->getTemplate(I), - TemplateArgs); - if (!Temp) return nullptr; + TemplateArgumentListInfo ExplicitArgs; + if (const auto *ArgsWritten = DFTSI->TemplateArgumentsAsWritten) { + ExplicitArgs.setLAngleLoc(ArgsWritten->getLAngleLoc()); + ExplicitArgs.setRAngleLoc(ArgsWritten->getRAngleLoc()); + if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs, + ExplicitArgs)) + return nullptr; + } - Previous.addDecl(cast<FunctionTemplateDecl>(Temp)); + // Map the candidates for the primary template to their instantiations. + for (FunctionTemplateDecl *FTD : DFTSI->getCandidates()) { + if (NamedDecl *ND = + SemaRef.FindInstantiatedDecl(D->getLocation(), FTD, TemplateArgs)) + Previous.addDecl(ND); + else + return nullptr; } - if (SemaRef.CheckFunctionTemplateSpecialization(Method, - &ExplicitArgs, - Previous)) + if (SemaRef.CheckFunctionTemplateSpecialization( + Method, DFTSI->TemplateArgumentsAsWritten ? &ExplicitArgs : nullptr, + Previous)) Method->setInvalidDecl(); IsExplicitSpecialization = true; - } else if (const ASTTemplateArgumentListInfo *Info = - ClassScopeSpecializationArgs.value_or( - D->getTemplateSpecializationArgsAsWritten())) { + } else if (const ASTTemplateArgumentListInfo *ArgsWritten = + D->getTemplateSpecializationArgsAsWritten()) { SemaRef.LookupQualifiedName(Previous, DC); - TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(), - Info->getRAngleLoc()); - if (SemaRef.SubstTemplateArguments(Info->arguments(), TemplateArgs, + TemplateArgumentListInfo ExplicitArgs(ArgsWritten->getLAngleLoc(), + ArgsWritten->getRAngleLoc()); + + if (SemaRef.SubstTemplateArguments(ArgsWritten->arguments(), TemplateArgs, ExplicitArgs)) return nullptr; @@ -2678,14 +2680,6 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( Previous)) 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); @@ -3510,13 +3504,6 @@ Decl *TemplateDeclInstantiator::VisitUsingPackDecl(UsingPackDecl *D) { return NewD; } -Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( - ClassScopeFunctionSpecializationDecl *Decl) { - CXXMethodDecl *OldFD = Decl->getSpecialization(); - return cast_or_null<CXXMethodDecl>( - VisitCXXMethodDecl(OldFD, nullptr, Decl->getTemplateArgsAsWritten())); -} - Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( OMPThreadPrivateDecl *D) { SmallVector<Expr *, 5> Vars; @@ -4094,14 +4081,14 @@ FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD, Decl *R; if (auto *MD = dyn_cast<CXXMethodDecl>(Spaceship)) { R = Instantiator.VisitCXXMethodDecl( - MD, nullptr, std::nullopt, + MD, /*TemplateParams=*/nullptr, TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual); } else { assert(Spaceship->getFriendObjectKind() && "defaulted spaceship is neither a member nor a friend"); R = Instantiator.VisitFunctionDecl( - Spaceship, nullptr, + Spaceship, /*TemplateParams=*/nullptr, TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual); if (!R) return nullptr; diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index 72e582107480976..6110e287b7fb50f 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -424,7 +424,6 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::StaticAssert: case Decl::Block: case Decl::Captured: - case Decl::ClassScopeFunctionSpecialization: case Decl::Import: case Decl::OMPThreadPrivate: case Decl::OMPAllocate: diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index b4d5325601e59c1..c2e080e3f593f81 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7362,15 +7362,20 @@ TemplateArgumentLoc ASTRecordReader::readTemplateArgumentLoc() { return TemplateArgumentLoc(Arg, readTemplateArgumentLocInfo(Arg.getKind())); } -const ASTTemplateArgumentListInfo * -ASTRecordReader::readASTTemplateArgumentListInfo() { - SourceLocation LAngleLoc = readSourceLocation(); - SourceLocation RAngleLoc = readSourceLocation(); +void ASTRecordReader::readTemplateArgumentListInfo( + TemplateArgumentListInfo &Result) { + Result.setLAngleLoc(readSourceLocation()); + Result.setRAngleLoc(readSourceLocation()); unsigned NumArgsAsWritten = readInt(); - TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc); for (unsigned i = 0; i != NumArgsAsWritten; ++i) - TemplArgsInfo.addArgument(readTemplateArgumentLoc()); - return ASTTemplateArgumentListInfo::Create(getContext(), TemplArgsInfo); + Result.addArgument(readTemplateArgumentLoc()); +} + +const ASTTemplateArgumentListInfo * +ASTRecordReader::readASTTemplateArgumentListInfo() { + TemplateArgumentListInfo Result; + readTemplateArgumentListInfo(Result); + return ASTTemplateArgumentListInfo::Create(getContext(), Result); } Decl *ASTReader::GetExternalDecl(uint32_t ID) { diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 6a2f607d916c472..485e18efbd02a87 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -359,8 +359,6 @@ namespace clang { void VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); - void VisitClassScopeFunctionSpecializationDecl( - ClassScopeFunctionSpecializationDecl *D); RedeclarableResult VisitVarTemplateSpecializationDeclImpl(VarTemplateSpecializationDecl *D); @@ -950,27 +948,16 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true); // Template args as written. - SmallVector<TemplateArgumentLoc, 8> TemplArgLocs; - SourceLocation LAngleLoc, RAngleLoc; - bool HasTemplateArgumentsAsWritten = Record.readInt(); - if (HasTemplateArgumentsAsWritten) { - unsigned NumTemplateArgLocs = Record.readInt(); - TemplArgLocs.reserve(NumTemplateArgLocs); - for (unsigned i = 0; i != NumTemplateArgLocs; ++i) - TemplArgLocs.push_back(Record.readTemplateArgumentLoc()); - - LAngleLoc = readSourceLocation(); - RAngleLoc = readSourceLocation(); - } + TemplateArgumentListInfo TemplArgsWritten; + bool HasTemplateArgumentsAsWritten = Record.readBool(); + if (HasTemplateArgumentsAsWritten) + Record.readTemplateArgumentListInfo(TemplArgsWritten); SourceLocation POI = readSourceLocation(); ASTContext &C = Reader.getContext(); TemplateArgumentList *TemplArgList = TemplateArgumentList::CreateCopy(C, TemplArgs); - TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc); - for (unsigned i = 0, e = TemplArgLocs.size(); i != e; ++i) - TemplArgsInfo.addArgument(TemplArgLocs[i]); MemberSpecializationInfo *MSInfo = nullptr; if (Record.readInt()) { @@ -985,7 +972,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FunctionTemplateSpecializationInfo *FTInfo = FunctionTemplateSpecializationInfo::Create( C, FD, Template, TSK, TemplArgList, - HasTemplateArgumentsAsWritten ? &TemplArgsInfo : nullptr, POI, + HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr, POI, MSInfo); FD->TemplateOrSpecialization = FTInfo; @@ -1016,21 +1003,20 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { } case FunctionDecl::TK_DependentFunctionTemplateSpecialization: { // Templates. - UnresolvedSet<8> TemplDecls; - unsigned NumTemplates = Record.readInt(); - while (NumTemplates--) - TemplDecls.addDecl(readDeclAs<NamedDecl>()); + UnresolvedSet<8> Candidates; + unsigned NumCandidates = Record.readInt(); + while (NumCandidates--) + Candidates.addDecl(readDeclAs<NamedDecl>()); // Templates args. - TemplateArgumentListInfo TemplArgs; - unsigned NumArgs = Record.readInt(); - while (NumArgs--) - TemplArgs.addArgument(Record.readTemplateArgumentLoc()); - TemplArgs.setLAngleLoc(readSourceLocation()); - TemplArgs.setRAngleLoc(readSourceLocation()); - - FD->setDependentTemplateSpecialization(Reader.getContext(), - TemplDecls, TemplArgs); + TemplateArgumentListInfo TemplArgsWritten; + bool HasTemplateArgumentsAsWritten = Record.readBool(); + if (HasTemplateArgumentsAsWritten) + Record.readTemplateArgumentListInfo(TemplArgsWritten); + + FD->setDependentTemplateSpecialization( + Reader.getContext(), Candidates, + HasTemplateArgumentsAsWritten ? &TemplArgsWritten : nullptr); // These are not merged; we don't need to merge redeclarations of dependent // template friends. break; @@ -2525,14 +2511,6 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl( } } -void ASTDeclReader::VisitClassScopeFunctionSpecializationDecl( - ClassScopeFunctionSpecializationDecl *D) { - VisitDecl(D); - D->Specialization = readDeclAs<CXXMethodDecl>(); - if (Record.readInt()) - D->TemplateArgs = Record.readASTTemplateArgumentListInfo(); -} - void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D); @@ -3881,9 +3859,6 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION: D = VarTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID); break; - case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION: - D = ClassScopeFunctionSpecializationDecl::CreateDeserialized(Context, ID); - break; case DECL_FUNCTION_TEMPLATE: D = FunctionTemplateDecl::CreateDeserialized(Context, ID); break; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 7b4ab6fe0a1f971..27700c711d52fdd 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -1029,7 +1029,6 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(DECL_INDIRECTFIELD); RECORD(DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK); RECORD(DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK); - RECORD(DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION); RECORD(DECL_IMPORT); RECORD(DECL_OMP_THREADPRIVATE); RECORD(DECL_EMPTY); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 91c8ed9f75db1f5..8a2ea7c7624ceb8 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -81,8 +81,6 @@ namespace clang { void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D); void VisitVarTemplatePartialSpecializationDecl( VarTemplatePartialSpecializationDecl *D); - void VisitClassScopeFunctionSpecializationDecl( - ClassScopeFunctionSpecializationDecl *D); void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitValueDecl(ValueDecl *D); void VisitEnumConstantDecl(EnumConstantDecl *D); @@ -617,15 +615,9 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { // Template args as written. Record.push_back(FTSInfo->TemplateArgumentsAsWritten != nullptr); - if (FTSInfo->TemplateArgumentsAsWritten) { - Record.push_back(FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs); - for (int i=0, e = FTSInfo->TemplateArgumentsAsWritten->NumTemplateArgs; - i!=e; ++i) - Record.AddTemplateArgumentLoc( - (*FTSInfo->TemplateArgumentsAsWritten)[i]); - Record.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->LAngleLoc); - Record.AddSourceLocation(FTSInfo->TemplateArgumentsAsWritten->RAngleLoc); - } + if (FTSInfo->TemplateArgumentsAsWritten) + Record.AddASTTemplateArgumentListInfo( + FTSInfo->TemplateArgumentsAsWritten); Record.AddSourceLocation(FTSInfo->getPointOfInstantiation()); @@ -650,17 +642,16 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { DependentFunctionTemplateSpecializationInfo * DFTSInfo = D->getDependentSpecializationInfo(); - // Templates. - Record.push_back(DFTSInfo->getNumTemplates()); - for (int i=0, e = DFTSInfo->getNumTemplates(); i != e; ++i) - Record.AddDeclRef(DFTSInfo->getTemplate(i)); + // Candidates. + Record.push_back(DFTSInfo->getCandidates().size()); + for (FunctionTemplateDecl *FTD : DFTSInfo->getCandidates()) + Record.AddDeclRef(FTD); // Templates args. - Record.push_back(DFTSInfo->getNumTemplateArgs()); - for (int i=0, e = DFTSInfo->getNumTemplateArgs(); i != e; ++i) - Record.AddTemplateArgumentLoc(DFTSInfo->getTemplateArg(i)); - Record.AddSourceLocation(DFTSInfo->getLAngleLoc()); - Record.AddSourceLocation(DFTSInfo->getRAngleLoc()); + Record.push_back(DFTSInfo->TemplateArgumentsAsWritten != nullptr); + if (DFTSInfo->TemplateArgumentsAsWritten) + Record.AddASTTemplateArgumentListInfo( + DFTSInfo->TemplateArgumentsAsWritten); break; } } @@ -1739,17 +1730,6 @@ void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl( Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION; } -void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl( - 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; -} - - void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { VisitRedeclarableTemplateDecl(D); diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp index a20d24db158f50b..66e9a501c348eb5 100644 --- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp @@ -202,7 +202,7 @@ static QualType getInnerPointerType(CheckerContext C, const CXXRecordDecl *RD) { static QualType getPointerTypeFromTemplateArg(const CallEvent &Call, CheckerContext &C) { const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); - if (!FD || !FD->isFunctionTemplateSpecialization()) + if (!FD || !FD->getPrimaryTemplate()) return {}; const auto &TemplateArgs = FD->getTemplateSpecializationArgs()->asArray(); if (TemplateArgs.size() == 0) diff --git a/clang/test/AST/ast-dump-decl.cpp b/clang/test/AST/ast-dump-decl.cpp index 6848a2b01da2c91..017e640aeaea6d7 100644 --- a/clang/test/AST/ast-dump-decl.cpp +++ b/clang/test/AST/ast-dump-decl.cpp @@ -645,11 +645,16 @@ class TestClassScopeFunctionSpecialization { template<class U> void foo(U a) { } template<> void foo<int>(int a) { } }; -// CHECK: ClassScopeFunctionSpecializationDecl -// CHECK-NEXT: CXXMethod{{.*}} foo 'void (int)' +// CHECK: FunctionTemplateDecl{{.*}} foo +// CHECK-NEXT: TemplateTypeParmDecl{{.*}} referenced class depth 1 index 0 U +// CHECK-NEXT: CXXMethodDecl{{.*}} foo 'void (U)' implicit-inline // CHECK-NEXT: ParmVarDecl // CHECK-NEXT: CompoundStmt +// CHECK-NEXT: CXXMethodDecl{{.*}} foo 'void (int)' explicit_specialization implicit-inline // CHECK-NEXT: TemplateArgument{{.*}} 'int' +// CHECK-NEXT: BuiltinType{{.*}} 'int' +// CHECK-NEXT: ParmVarDecl +// CHECK-NEXT: CompoundStmt namespace TestTemplateTypeParmDecl { template<typename ... T, class U = int> void foo(); diff --git a/clang/test/CXX/drs/dr7xx.cpp b/clang/test/CXX/drs/dr7xx.cpp index f6a2e5923bedb5d..11901b80d646225 100644 --- a/clang/test/CXX/drs/dr7xx.cpp +++ b/clang/test/CXX/drs/dr7xx.cpp @@ -111,6 +111,11 @@ namespace dr727 { // dr727: partial template<typename T> struct C<T*> {}; template<typename T> static const int N<T*>; + + template<typename> + struct E { + template<> void f<void>() {} // expected-error {{no candidate function template}} + }; }; void d(D<int> di) { diff --git a/clang/test/SemaTemplate/instantiate-method.cpp b/clang/test/SemaTemplate/instantiate-method.cpp index 9cd668dacf5c9c5..60889a4cffe46ae 100644 --- a/clang/test/SemaTemplate/instantiate-method.cpp +++ b/clang/test/SemaTemplate/instantiate-method.cpp @@ -45,7 +45,7 @@ class HasDestructor { virtual ~HasDestructor() = 0; }; -int i = sizeof(HasDestructor<int>); // FIXME: forces instantiation, but +int i = sizeof(HasDestructor<int>); // FIXME: forces instantiation, but // the code below should probably instantiate by itself. int abstract_destructor[__is_abstract(HasDestructor<int>)? 1 : -1]; @@ -94,7 +94,7 @@ struct X0 : X0Base { template<typename U> struct X1 : X0<U> { - int &f2() { + int &f2() { return X0Base::f(); } }; @@ -129,19 +129,19 @@ namespace test1 { } namespace PR6947 { - template< class T > + template< class T > struct X { - int f0( ) + int f0( ) { typedef void ( X::*impl_fun_ptr )( ); impl_fun_ptr pImpl = &X::template f0_impl1<int>; } - private: + private: int f1() { } - template< class Processor> - void f0_impl1( ) + template< class Processor> + void f0_impl1( ) { } }; @@ -154,7 +154,7 @@ namespace PR6947 { } namespace PR7022 { - template <typename > + template <typename > struct X1 { typedef int state_t( ); @@ -185,13 +185,12 @@ namespace SameSignatureAfterInstantiation { namespace PR22040 { template <typename T> struct Foobar { - template <> void bazqux(typename T::type) {} // expected-error 2{{cannot be used prior to '::' because it has no members}} + template <> void bazqux(typename T::type) {} // expected-error {{no candidate function template was found for dependent member function template specialization}} }; void test() { - // FIXME: we should suppress the "no member" errors - Foobar<void>::bazqux(); // expected-error{{no member named 'bazqux' in }} expected-note{{in instantiation of template class }} - Foobar<int>::bazqux(); // expected-error{{no member named 'bazqux' in }} expected-note{{in instantiation of template class }} + Foobar<void>::bazqux(); + Foobar<int>::bazqux(); Foobar<int>::bazqux(3); // expected-error{{no member named 'bazqux' in }} } } diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 7915050a78eaffc..46226f4325b0a7a 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -6848,7 +6848,6 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::Captured: case Decl::OMPCapturedExpr: case Decl::Label: // FIXME: Is this right?? - case Decl::ClassScopeFunctionSpecialization: case Decl::CXXDeductionGuide: case Decl::Import: case Decl::OMPThreadPrivate: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits