From: Argyrios Kyrtzidis Date: Sat, 19 Jun 2010 19:28:53 +0000 (+0000) Subject: Initial support for writing templates to PCH. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=90b715e0df34eae2b50b9b43ec60828ed31dcf94;p=clang Initial support for writing templates to PCH. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106391 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/TemplateName.h b/include/clang/AST/TemplateName.h index 2e3b6df054..ddfac71273 100644 --- a/include/clang/AST/TemplateName.h +++ b/include/clang/AST/TemplateName.h @@ -101,6 +101,14 @@ class TemplateName { } public: + // \brief Kind of name that is actually stored. + enum NameKind { + Template, + OverloadedTemplate, + QualifiedTemplate, + DependentTemplate + }; + TemplateName() : Storage() { } explicit TemplateName(TemplateDecl *Template) : Storage(Template) { } explicit TemplateName(OverloadedTemplateStorage *Storage) @@ -110,6 +118,9 @@ public: /// \brief Determine whether this template name is NULL. bool isNull() const { return Storage.isNull(); } + + // \brief Get the kind of name that is actually stored. + NameKind getKind() const; /// \brief Retrieve the the underlying template declaration that /// this template name refers to, if known. diff --git a/include/clang/Frontend/PCHBitCodes.h b/include/clang/Frontend/PCHBitCodes.h index 32643de261..4e1320188a 100644 --- a/include/clang/Frontend/PCHBitCodes.h +++ b/include/clang/Frontend/PCHBitCodes.h @@ -417,7 +417,11 @@ namespace clang { /// \brief An InjectedClassNameType record. TYPE_INJECTED_CLASS_NAME = 27, /// \brief An ObjCObjectType record. - TYPE_OBJC_OBJECT = 28 + TYPE_OBJC_OBJECT = 28, + /// \brief An TemplateTypeParmType record. + TYPE_TEMPLATE_TYPE_PARM = 29, + /// \brief An TemplateSpecializationType record. + TYPE_TEMPLATE_SPECIALIZATION = 30 }; /// \brief The type IDs for special types constructed by semantic @@ -569,7 +573,6 @@ namespace clang { // allocates the order in which DECL_FRIEND, DECL_FRIEND_TEMPLATE, - DECL_TEMPLATE, DECL_CLASS_TEMPLATE, DECL_CLASS_TEMPLATE_SPECIALIZATION, DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION, diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index 85f53b9e03..7e589f3321 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -315,6 +315,12 @@ public: /// \brief Emit a nested name specifier. void AddNestedNameSpecifier(NestedNameSpecifier *NNS, RecordData &Record); + + /// \brief Emit a template name. + void AddTemplateName(TemplateName Name, RecordData &Record); + + /// \brief Emit a template argument. + void AddTemplateArgument(const TemplateArgument &Arg, RecordData &Record); /// \brief Add a string to the given record. void AddString(const std::string &Str, RecordData &Record); diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp index 14722f7039..ef7b315314 100644 --- a/lib/AST/TemplateName.cpp +++ b/lib/AST/TemplateName.cpp @@ -21,6 +21,17 @@ using namespace clang; using namespace llvm; +TemplateName::NameKind TemplateName::getKind() const { + if (Storage.is()) + return Template; + if (Storage.is()) + return OverloadedTemplate; + if (Storage.is()) + return QualifiedTemplate; + assert(Storage.is() && "There's a case unhandled!"); + return DependentTemplate; +} + TemplateDecl *TemplateName::getAsTemplateDecl() const { if (TemplateDecl *Template = Storage.dyn_cast()) return Template; diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index e555d9078f..99c28d4f03 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -2207,6 +2207,14 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { QualType TST = GetType(Record[1]); // probably derivable return Context->getInjectedClassNameType(D, TST); } + + case pch::TYPE_TEMPLATE_TYPE_PARM: + assert(false && "can't read template type parm types yet"); + break; + + case pch::TYPE_TEMPLATE_SPECIALIZATION: + assert(false && "can't read template specialization types yet"); + break; } // Suppress a GCC warning return QualType(); diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 78ae5f01b7..cbc0da673c 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -987,10 +987,6 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { case pch::DECL_FRIEND_TEMPLATE: assert(false && "cannot read FriendTemplateDecl"); break; - case pch::DECL_TEMPLATE: - // FIXME: Should TemplateDecl be ABSTRACT_DECL??? - assert(false && "TemplateDecl should be abstract!"); - break; case pch::DECL_CLASS_TEMPLATE: assert(false && "cannot read ClassTemplateDecl"); break; diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index b03a7bdac3..a0bd9ec2a7 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -61,9 +61,7 @@ namespace { #define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T); #define ABSTRACT_TYPE(Class, Base) -#define DEPENDENT_TYPE(Class, Base) #include "clang/AST/TypeNodes.def" - void VisitInjectedClassNameType(const InjectedClassNameType *T); }; } @@ -169,13 +167,10 @@ void PCHTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { Code = pch::TYPE_FUNCTION_PROTO; } -#if 0 -// For when we want it.... void PCHTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { Writer.AddDeclRef(T->getDecl(), Record); Code = pch::TYPE_UNRESOLVED_USING; } -#endif void PCHTypeWriter::VisitTypedefType(const TypedefType *T) { Writer.AddDeclRef(T->getDecl(), Record); @@ -224,8 +219,47 @@ PCHTypeWriter::VisitSubstTemplateTypeParmType( void PCHTypeWriter::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { + Writer.AddTemplateName(T->getTemplateName(), Record); + Record.push_back(T->getNumArgs()); + for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end(); + ArgI != ArgE; ++ArgI) + Writer.AddTemplateArgument(*ArgI, Record); + Code = pch::TYPE_TEMPLATE_SPECIALIZATION; +} + +void +PCHTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) { + // FIXME: Serialize this type (C++ only) + assert(false && "Cannot serialize dependent sized array types"); +} + +void +PCHTypeWriter::VisitDependentSizedExtVectorType( + const DependentSizedExtVectorType *T) { + // FIXME: Serialize this type (C++ only) + assert(false && "Cannot serialize dependent sized extended vector types"); +} + +void +PCHTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) { + Record.push_back(T->getDepth()); + Record.push_back(T->getIndex()); + Record.push_back(T->isParameterPack()); + Writer.AddIdentifierRef(T->getName(), Record); + Code = pch::TYPE_TEMPLATE_TYPE_PARM; +} + +void +PCHTypeWriter::VisitDependentNameType(const DependentNameType *T) { // FIXME: Serialize this type (C++ only) - assert(false && "Cannot serialize template specialization types"); + assert(false && "Cannot serialize dependent name types"); +} + +void +PCHTypeWriter::VisitDependentTemplateSpecializationType( + const DependentTemplateSpecializationType *T) { + // FIXME: Serialize this type (C++ only) + assert(false && "Cannot serialize dependent template specialization types"); } void PCHTypeWriter::VisitElaboratedType(const ElaboratedType *T) { @@ -1357,16 +1391,7 @@ void PCHWriter::WriteType(QualType T) { #define TYPE(Class, Base) \ case Type::Class: W.Visit##Class##Type(cast(T)); break; #define ABSTRACT_TYPE(Class, Base) -#define DEPENDENT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.def" - - // For all of the dependent type nodes (which only occur in C++ - // templates), produce an error. -#define TYPE(Class, Base) -#define DEPENDENT_TYPE(Class, Base) case Type::Class: #include "clang/AST/TypeNodes.def" - assert(false && "Cannot serialize dependent type nodes"); - break; } } @@ -2469,3 +2494,72 @@ void PCHWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS, } } } + +void PCHWriter::AddTemplateName(TemplateName Name, RecordData &Record) { + TemplateName::NameKind Kind = Name.getKind(); + Record.push_back(Kind); + switch (Kind) { + case TemplateName::Template: + AddDeclRef(Name.getAsTemplateDecl(), Record); + break; + + case TemplateName::OverloadedTemplate: { + OverloadedTemplateStorage *OvT = Name.getAsOverloadedTemplate(); + Record.push_back(OvT->size()); + for (OverloadedTemplateStorage::iterator I = OvT->begin(), E = OvT->end(); + I != E; ++I) + AddDeclRef(*I, Record); + break; + } + + case TemplateName::QualifiedTemplate: { + QualifiedTemplateName *QualT = Name.getAsQualifiedTemplateName(); + AddNestedNameSpecifier(QualT->getQualifier(), Record); + Record.push_back(QualT->hasTemplateKeyword()); + AddDeclRef(QualT->getTemplateDecl(), Record); + break; + } + + case TemplateName::DependentTemplate: { + DependentTemplateName *DepT = Name.getAsDependentTemplateName(); + AddNestedNameSpecifier(DepT->getQualifier(), Record); + Record.push_back(DepT->isIdentifier()); + if (DepT->isIdentifier()) + AddIdentifierRef(DepT->getIdentifier(), Record); + else + Record.push_back(DepT->getOperator()); + break; + } + } +} + +void PCHWriter::AddTemplateArgument(const TemplateArgument &Arg, + RecordData &Record) { + Record.push_back(Arg.getKind()); + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + case TemplateArgument::Type: + AddTypeRef(Arg.getAsType(), Record); + break; + case TemplateArgument::Declaration: + AddDeclRef(Arg.getAsDecl(), Record); + break; + case TemplateArgument::Integral: + AddAPSInt(*Arg.getAsIntegral(), Record); + AddTypeRef(Arg.getIntegralType(), Record); + break; + case TemplateArgument::Template: + AddTemplateName(Arg.getAsTemplate(), Record); + break; + case TemplateArgument::Expression: + AddStmt(Arg.getAsExpr()); + break; + case TemplateArgument::Pack: + Record.push_back(Arg.pack_size()); + for (TemplateArgument::pack_iterator I=Arg.pack_begin(), E=Arg.pack_end(); + I != E; ++I) + AddTemplateArgument(*I, Record); + break; + } +} diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 36ce5c047f..0671710882 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -574,6 +574,23 @@ void PCHDeclWriter::WriteCXXBaseSpecifier(const CXXBaseSpecifier *Base) { void PCHDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { // assert(false && "cannot write CXXRecordDecl"); VisitRecordDecl(D); + + enum { + CXXRecNotTemplate = 0, CXXRecTemplate, CXXRecMemberSpecialization + }; + if (ClassTemplateDecl *TemplD = D->getDescribedClassTemplate()) { + Record.push_back(CXXRecTemplate); + Writer.AddDeclRef(TemplD, Record); + } else if (MemberSpecializationInfo *MSInfo + = D->getMemberSpecializationInfo()) { + Record.push_back(CXXRecMemberSpecialization); + Writer.AddDeclRef(MSInfo->getInstantiatedFrom(), Record); + Record.push_back(MSInfo->getTemplateSpecializationKind()); + Writer.AddSourceLocation(MSInfo->getPointOfInstantiation(), Record); + } else { + Record.push_back(CXXRecNotTemplate); + } + if (D->isDefinition()) { unsigned NumBases = D->getNumBases(); Record.push_back(NumBases); @@ -619,11 +636,49 @@ void PCHDeclWriter::VisitFriendTemplateDecl(FriendTemplateDecl *D) { } void PCHDeclWriter::VisitTemplateDecl(TemplateDecl *D) { - assert(false && "cannot write TemplateDecl"); + VisitNamedDecl(D); + + Writer.AddDeclRef(D->getTemplatedDecl(), Record); + { + // TemplateParams. + TemplateParameterList *TPL = D->getTemplateParameters(); + assert(TPL && "No TemplateParameters!"); + Writer.AddSourceLocation(TPL->getTemplateLoc(), Record); + Writer.AddSourceLocation(TPL->getLAngleLoc(), Record); + Writer.AddSourceLocation(TPL->getRAngleLoc(), Record); + Record.push_back(TPL->size()); + for (TemplateParameterList::iterator P = TPL->begin(), PEnd = TPL->end(); + P != PEnd; ++P) + Writer.AddDeclRef(*P, Record); + } } void PCHDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) { - assert(false && "cannot write ClassTemplateDecl"); + VisitTemplateDecl(D); + + Writer.AddDeclRef(D->getPreviousDeclaration(), Record); + if (D->getPreviousDeclaration() == 0) { + // This ClassTemplateDecl owns the CommonPtr; write it. + + typedef llvm::FoldingSet CTSDSetTy; + CTSDSetTy &CTSDSet = D->getSpecializations(); + Record.push_back(CTSDSet.size()); + for (CTSDSetTy::iterator I=CTSDSet.begin(), E = CTSDSet.end(); I!=E; ++I) + Writer.AddDeclRef(&*I, Record); + + typedef llvm::FoldingSet CTPSDSetTy; + CTPSDSetTy &CTPSDSet = D->getPartialSpecializations(); + Record.push_back(CTPSDSet.size()); + for (CTPSDSetTy::iterator I=CTPSDSet.begin(), E = CTPSDSet.end(); I!=E; ++I) + Writer.AddDeclRef(&*I, Record); + + // InjectedClassNameType is computed, no need to write it. + + Writer.AddDeclRef(D->getInstantiatedFromMemberTemplate(), Record); + if (D->getInstantiatedFromMemberTemplate()) + Record.push_back(D->isMemberSpecialization()); + } + Code = pch::DECL_CLASS_TEMPLATE; } void PCHDeclWriter::VisitClassTemplateSpecializationDecl( @@ -641,7 +696,14 @@ void PCHDeclWriter::visitFunctionTemplateDecl(FunctionTemplateDecl *D) { } void PCHDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { - assert(false && "cannot write TemplateTypeParmDecl"); + VisitTypeDecl(D); + + Record.push_back(D->wasDeclaredWithTypename()); + Record.push_back(D->isParameterPack()); + Record.push_back(D->defaultArgumentWasInherited()); + Writer.AddTypeSourceInfo(D->getDefaultArgumentInfo(), Record); + + Code = pch::DECL_TEMPLATE_TYPE_PARM; } void PCHDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp new file mode 100644 index 0000000000..00756736c2 --- /dev/null +++ b/test/PCH/cxx-templates.cpp @@ -0,0 +1,3 @@ +// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-templates.h + +// Placeholder for stuff using the header. diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h new file mode 100644 index 0000000000..74885f0590 --- /dev/null +++ b/test/PCH/cxx-templates.h @@ -0,0 +1,6 @@ +// Header for PCH test cxx-templates.cpp + +template +struct S { + T x; +};