From 5bbcdbf36f8cf79d99703ef20848c55960065e43 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Thu, 14 Apr 2011 14:07:59 +0000 Subject: [PATCH] Chained PCH: Remember when additional specializations are added to a function template from a previous PCH. Fixes the only crasher when using massive chains on Clang's Sema component. We still have some incomplete codegen there. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129516 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTMutationListener.h | 7 ++++++ include/clang/AST/DeclTemplate.h | 7 ++++++ include/clang/Serialization/ASTWriter.h | 2 ++ lib/AST/Decl.cpp | 2 +- lib/AST/DeclTemplate.cpp | 7 ++++++ lib/Frontend/MultiplexConsumer.cpp | 7 ++++++ lib/Serialization/ASTWriter.cpp | 12 +++++++++ test/PCH/cxx-chain-function-template.cpp | 32 ++++++++++++++++++++++++ 8 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 test/PCH/cxx-chain-function-template.cpp diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h index 01e6180249..33e9ad4859 100644 --- a/include/clang/AST/ASTMutationListener.h +++ b/include/clang/AST/ASTMutationListener.h @@ -20,6 +20,8 @@ namespace clang { class CXXRecordDecl; class ClassTemplateDecl; class ClassTemplateSpecializationDecl; + class FunctionDecl; + class FunctionTemplateDecl; /// \brief An abstract interface that should be implemented by listeners /// that want to be notified when an AST entity gets modified after its @@ -41,6 +43,11 @@ public: /// template declaration. virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D) {} + + /// \brief A template specialization (or partial one) was added to the + /// template declaration. + virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, + const FunctionDecl *D) {} }; } // end namespace clang diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 0fba9f6207..823bd84b38 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -804,6 +804,13 @@ protected: llvm::FoldingSet &getSpecializations() { return getCommonPtr()->Specializations; } + + /// \brief Add a specialization of this function template. + /// + /// \param InsertPos Insert position in the FoldingSet, must have been + /// retrieved by an earlier call to findSpecialization(). + void addSpecialization(FunctionTemplateSpecializationInfo* Info, + void *InsertPos); public: /// Get the underlying function declaration of the template. diff --git a/include/clang/Serialization/ASTWriter.h b/include/clang/Serialization/ASTWriter.h index 474631fce0..f33381ed05 100644 --- a/include/clang/Serialization/ASTWriter.h +++ b/include/clang/Serialization/ASTWriter.h @@ -586,6 +586,8 @@ public: virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D); virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D); + virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, + const FunctionDecl *D); }; /// \brief AST and semantic-analysis consumer that generates a diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index dfa53881f1..99a180662d 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1893,7 +1893,7 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C, // Insert this function template specialization into the set of known // function template specializations. if (InsertPos) - Template->getSpecializations().InsertNode(Info, InsertPos); + Template->addSpecialization(Info, InsertPos); else { // Try to insert the new node. If there is an existing node, leave it, the // set will contain the canonical decls while diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index ae17dd15b1..73c91dbd72 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -242,6 +242,13 @@ FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args, return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos); } +void FunctionTemplateDecl::addSpecialization( + FunctionTemplateSpecializationInfo *Info, void *InsertPos) { + getSpecializations().InsertNode(Info, InsertPos); + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, Info->Function); +} + std::pair FunctionTemplateDecl::getInjectedTemplateArgs() { TemplateParameterList *Params = getTemplateParameters(); diff --git a/lib/Frontend/MultiplexConsumer.cpp b/lib/Frontend/MultiplexConsumer.cpp index 3649c3c997..ecad91f1f0 100644 --- a/lib/Frontend/MultiplexConsumer.cpp +++ b/lib/Frontend/MultiplexConsumer.cpp @@ -95,6 +95,8 @@ public: virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D); virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D); + virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, + const FunctionDecl *D); private: std::vector Listeners; }; @@ -125,6 +127,11 @@ void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( for (size_t i = 0, e = Listeners.size(); i != e; ++i) Listeners[i]->AddedCXXTemplateSpecialization(TD, D); } +void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( + const FunctionTemplateDecl *TD, const FunctionDecl *D) { + for (size_t i = 0, e = Listeners.size(); i != e; ++i) + Listeners[i]->AddedCXXTemplateSpecialization(TD, D); +} } // end namespace clang diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index f7dfc38224..0e925a2691 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -3936,4 +3936,16 @@ void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, AddDeclRef(D, Record); } +void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, + const FunctionDecl *D) { + // The specializations set is kept in the canonical template. + TD = TD->getCanonicalDecl(); + if (!(D->getPCHLevel() == 0 && TD->getPCHLevel() > 0)) + return; // Not a source specialization added to a template from PCH. + + UpdateRecord &Record = DeclUpdates[TD]; + Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION); + AddDeclRef(D, Record); +} + ASTSerializationListener::~ASTSerializationListener() { } diff --git a/test/PCH/cxx-chain-function-template.cpp b/test/PCH/cxx-chain-function-template.cpp new file mode 100644 index 0000000000..494e190f77 --- /dev/null +++ b/test/PCH/cxx-chain-function-template.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -chain-include %s -chain-include %s -fsyntax-only %s +// Just don't crash. +#if !defined(RUN1) +#define RUN1 + +struct CXXRecordDecl { CXXRecordDecl(int); }; + +template +T cast(U u) { + return reinterpret_cast(u); +} + +void test1() { + cast(1); +} + +#elif !defined(RUN2) +#define RUN2 + +template +void test2(T) { + cast(1.0f); +} + +#else + +void test3() { + cast(1.0f); + test2(1); +} + +#endif -- 2.40.0