From: Argyrios Kyrtzidis Date: Wed, 23 Jun 2010 13:48:30 +0000 (+0000) Subject: Support C++ class template specializations and partial specializations for PCH. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dd41c14bfd7686b556de2acf6952e21a4f80b7aa;p=clang Support C++ class template specializations and partial specializations for PCH. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@106625 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Frontend/PCHReader.h b/include/clang/Frontend/PCHReader.h index 0a002687b9..95a046844a 100644 --- a/include/clang/Frontend/PCHReader.h +++ b/include/clang/Frontend/PCHReader.h @@ -702,6 +702,15 @@ public: /// \brief Read a template argument. TemplateArgument ReadTemplateArgument(const RecordData &Record,unsigned &Idx); + + /// \brief Read a template parameter list. + TemplateParameterList *ReadTemplateParameterList(const RecordData &Record, + unsigned &Idx); + + /// \brief Read a template argument array. + void + ReadTemplateArgumentList(llvm::SmallVector &TemplArgs, + const RecordData &Record, unsigned &Idx); /// \brief Read a source location. SourceLocation ReadSourceLocation(const RecordData &Record, unsigned& Idx) { diff --git a/include/clang/Frontend/PCHWriter.h b/include/clang/Frontend/PCHWriter.h index 264734d34e..af6338de98 100644 --- a/include/clang/Frontend/PCHWriter.h +++ b/include/clang/Frontend/PCHWriter.h @@ -328,6 +328,14 @@ public: /// \brief Emit a template argument. void AddTemplateArgument(const TemplateArgument &Arg, RecordData &Record); + /// \brief Emit a template parameter list. + void AddTemplateParameterList(const TemplateParameterList *TemplateParams, + RecordData &Record); + + /// \brief Emit a template argument list. + void AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs, + RecordData &Record); + /// \brief Add a string to the given record. void AddString(const std::string &Str, RecordData &Record); diff --git a/lib/Frontend/PCHReader.cpp b/lib/Frontend/PCHReader.cpp index 97c4d380eb..1f40781377 100644 --- a/lib/Frontend/PCHReader.cpp +++ b/lib/Frontend/PCHReader.cpp @@ -2220,13 +2220,11 @@ QualType PCHReader::ReadTypeRecord(uint64_t Offset) { case pch::TYPE_TEMPLATE_SPECIALIZATION: { unsigned Idx = 0; TemplateName Name = ReadTemplateName(Record, Idx); - unsigned NumArgs = Record[Idx++]; llvm::SmallVector Args; - Args.reserve(NumArgs); - while (NumArgs--) - Args.push_back(ReadTemplateArgument(Record, Idx)); + ReadTemplateArgumentList(Args, Record, Idx); + QualType Canon = GetType(Record[Idx++]); return Context->getTemplateSpecializationType(Name, Args.data(),Args.size(), - QualType()); + Canon); } } // Suppress a GCC warning @@ -3020,6 +3018,34 @@ PCHReader::ReadTemplateArgument(const RecordData &Record, unsigned &Idx) { return TemplateArgument(); } +TemplateParameterList * +PCHReader::ReadTemplateParameterList(const RecordData &Record, unsigned &Idx) { + SourceLocation TemplateLoc = ReadSourceLocation(Record, Idx); + SourceLocation LAngleLoc = ReadSourceLocation(Record, Idx); + SourceLocation RAngleLoc = ReadSourceLocation(Record, Idx); + + unsigned NumParams = Record[Idx++]; + llvm::SmallVector Params; + Params.reserve(NumParams); + while (NumParams--) + Params.push_back(cast(GetDecl(Record[Idx++]))); + + TemplateParameterList* TemplateParams = + TemplateParameterList::Create(*Context, TemplateLoc, LAngleLoc, + Params.data(), Params.size(), RAngleLoc); + return TemplateParams; +} + +void +PCHReader:: +ReadTemplateArgumentList(llvm::SmallVector &TemplArgs, + const RecordData &Record, unsigned &Idx) { + unsigned NumTemplateArgs = Record[Idx++]; + TemplArgs.reserve(NumTemplateArgs); + while (NumTemplateArgs--) + TemplArgs.push_back(ReadTemplateArgument(Record, Idx)); +} + NestedNameSpecifier * PCHReader::ReadNestedNameSpecifier(const RecordData &Record, unsigned &Idx) { unsigned N = Record[Idx++]; diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index f723baefef..1877a2199d 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -236,11 +236,8 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++]; // Template arguments. - unsigned NumTemplateArgs = Record[Idx++]; llvm::SmallVector TemplArgs; - TemplArgs.reserve(NumTemplateArgs); - for (unsigned i=0; i != NumTemplateArgs; ++i) - TemplArgs.push_back(Reader.ReadTemplateArgument(Record, Idx)); + Reader.ReadTemplateArgumentList(TemplArgs, Record, Idx); // Template args as written. unsigned NumTemplateArgLocs = Record[Idx++]; @@ -255,7 +252,7 @@ void PCHDeclReader::VisitFunctionDecl(FunctionDecl *FD) { RAngleLoc = Reader.ReadSourceLocation(Record, Idx); } - FD->setFunctionTemplateSpecialization(Template, NumTemplateArgs, + FD->setFunctionTemplateSpecialization(Template, TemplArgs.size(), TemplArgs.data(), TSK, NumTemplateArgLocs, NumTemplateArgLocs ? TemplArgLocs.data() : 0, @@ -711,23 +708,8 @@ void PCHDeclReader::VisitTemplateDecl(TemplateDecl *D) { VisitNamedDecl(D); NamedDecl *TemplatedDecl = cast(Reader.GetDecl(Record[Idx++])); - - // TemplateParams. - SourceLocation TemplateLoc = Reader.ReadSourceLocation(Record, Idx); - SourceLocation LAngleLoc = Reader.ReadSourceLocation(Record, Idx); - SourceLocation RAngleLoc = Reader.ReadSourceLocation(Record, Idx); - - unsigned NumParams = Record[Idx++]; - assert(NumParams && "No template params!"); - llvm::SmallVector Params; - Params.reserve(NumParams); - while (NumParams--) - Params.push_back(cast(Reader.GetDecl(Record[Idx++]))); - - TemplateParameterList* TemplateParams = - TemplateParameterList::Create(*Reader.getContext(), TemplateLoc, LAngleLoc, - Params.data(), Params.size(), RAngleLoc); - + TemplateParameterList* TemplateParams + = Reader.ReadTemplateParameterList(Record, Idx); D->init(TemplatedDecl, TemplateParams); } @@ -782,12 +764,57 @@ void PCHDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { void PCHDeclReader::VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D) { - assert(false && "cannot read ClassTemplateSpecializationDecl"); + VisitCXXRecordDecl(D); + + if (Decl *InstD = Reader.GetDecl(Record[Idx++])) { + if (ClassTemplateDecl *CTD = dyn_cast(InstD)) { + D->setInstantiationOf(CTD); + } else { + llvm::SmallVector TemplArgs; + Reader.ReadTemplateArgumentList(TemplArgs, Record, Idx); + D->setInstantiationOf(cast(InstD), + TemplArgs.data(), TemplArgs.size()); + } + } + + // Explicit info. + if (TypeSourceInfo *TyInfo = Reader.GetTypeSourceInfo(Record, Idx)) { + D->setTypeAsWritten(TyInfo); + D->setExternLoc(Reader.ReadSourceLocation(Record, Idx)); + D->setTemplateKeywordLoc(Reader.ReadSourceLocation(Record, Idx)); + } + + llvm::SmallVector TemplArgs; + Reader.ReadTemplateArgumentList(TemplArgs, Record, Idx); + D->initTemplateArgs(TemplArgs.data(), TemplArgs.size()); + SourceLocation POI = Reader.ReadSourceLocation(Record, Idx); + if (POI.isValid()) + D->setPointOfInstantiation(POI); + D->setSpecializationKind((TemplateSpecializationKind)Record[Idx++]); } void PCHDeclReader::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { - assert(false && "cannot read ClassTemplatePartialSpecializationDecl"); + VisitClassTemplateSpecializationDecl(D); + + D->initTemplateParameters(Reader.ReadTemplateParameterList(Record, Idx)); + + TemplateArgumentListInfo ArgInfos; + unsigned NumArgs = Record[Idx++]; + while (NumArgs--) + ArgInfos.addArgument(Reader.ReadTemplateArgumentLoc(Record, Idx)); + D->initTemplateArgsAsWritten(ArgInfos); + + D->setSequenceNumber(Record[Idx++]); + + // These are read/set from/to the first declaration. + if (D->getPreviousDeclaration() == 0) { + D->setInstantiatedFromMember( + cast_or_null( + Reader.GetDecl(Record[Idx++]))); + if (Record[Idx++]) + D->isMemberSpecialization(); + } } void PCHDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { @@ -1172,10 +1199,10 @@ Decl *PCHReader::ReadDeclRecord(uint64_t Offset, unsigned Index) { DeclarationName(), 0, 0, 0); break; case pch::DECL_CLASS_TEMPLATE_SPECIALIZATION: - assert(false && "cannot read ClasstemplateSpecializationDecl"); + D = ClassTemplateSpecializationDecl::CreateEmpty(*Context); break; case pch::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION: - assert(false && "cannot read ClassTemplatePartialSpecializationDecl"); + D = ClassTemplatePartialSpecializationDecl::CreateEmpty(*Context); break; case pch::DECL_FUNCTION_TEMPLATE: D = FunctionTemplateDecl::Create(*Context, 0, SourceLocation(), diff --git a/lib/Frontend/PCHWriter.cpp b/lib/Frontend/PCHWriter.cpp index a55684a29a..77356ccd10 100644 --- a/lib/Frontend/PCHWriter.cpp +++ b/lib/Frontend/PCHWriter.cpp @@ -223,6 +223,8 @@ PCHTypeWriter::VisitTemplateSpecializationType( for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end(); ArgI != ArgE; ++ArgI) Writer.AddTemplateArgument(*ArgI, Record); + QualType Canon = T->getCanonicalTypeInternal(); + Writer.AddTypeRef(Canon.getTypePtr() != T ? Canon : QualType(), Record); Code = pch::TYPE_TEMPLATE_SPECIALIZATION; } @@ -2572,3 +2574,27 @@ void PCHWriter::AddTemplateArgument(const TemplateArgument &Arg, break; } } + +void +PCHWriter::AddTemplateParameterList(const TemplateParameterList *TemplateParams, + RecordData &Record) { + assert(TemplateParams && "No TemplateParams!"); + AddSourceLocation(TemplateParams->getTemplateLoc(), Record); + AddSourceLocation(TemplateParams->getLAngleLoc(), Record); + AddSourceLocation(TemplateParams->getRAngleLoc(), Record); + Record.push_back(TemplateParams->size()); + for (TemplateParameterList::const_iterator + P = TemplateParams->begin(), PEnd = TemplateParams->end(); + P != PEnd; ++P) + AddDeclRef(*P, Record); +} + +/// \brief Emit a template argument list. +void +PCHWriter::AddTemplateArgumentList(const TemplateArgumentList *TemplateArgs, + RecordData &Record) { + assert(TemplateArgs && "No TemplateArgs!"); + Record.push_back(TemplateArgs->flat_size()); + for (int i=0, e = TemplateArgs->flat_size(); i != e; ++i) + AddTemplateArgument(TemplateArgs->get(i), Record); +} diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 9cc7b4833d..ade7508fd4 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -244,10 +244,7 @@ void PCHDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.push_back(FTSInfo->getTemplateSpecializationKind()); // Template arguments. - assert(FTSInfo->TemplateArguments && "No template args!"); - Record.push_back(FTSInfo->TemplateArguments->flat_size()); - for (int i=0, e = FTSInfo->TemplateArguments->flat_size(); i != e; ++i) - Writer.AddTemplateArgument(FTSInfo->TemplateArguments->get(i), Record); + Writer.AddTemplateArgumentList(FTSInfo->TemplateArguments, Record); // Template args as written. if (FTSInfo->TemplateArgumentsAsWritten) { @@ -705,18 +702,7 @@ void PCHDeclWriter::VisitTemplateDecl(TemplateDecl *D) { 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); - } + Writer.AddTemplateParameterList(D->getTemplateParameters(), Record); } void PCHDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) { @@ -749,12 +735,52 @@ void PCHDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) { void PCHDeclWriter::VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D) { - assert(false && "cannot write ClassTemplateSpecializationDecl"); + VisitCXXRecordDecl(D); + + llvm::PointerUnion InstFrom + = D->getSpecializedTemplateOrPartial(); + if (InstFrom.is()) { + Writer.AddDeclRef(InstFrom.get(), Record); + } else { + Writer.AddDeclRef(InstFrom.get(), + Record); + Writer.AddTemplateArgumentList(&D->getTemplateInstantiationArgs(), Record); + } + + // Explicit info. + Writer.AddTypeSourceInfo(D->getTypeAsWritten(), Record); + if (D->getTypeAsWritten()) { + Writer.AddSourceLocation(D->getExternLoc(), Record); + Writer.AddSourceLocation(D->getTemplateKeywordLoc(), Record); + } + + Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record); + Writer.AddSourceLocation(D->getPointOfInstantiation(), Record); + Record.push_back(D->getSpecializationKind()); + + Code = pch::DECL_CLASS_TEMPLATE_SPECIALIZATION; } void PCHDeclWriter::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { - assert(false && "cannot write ClassTemplatePartialSpecializationDecl"); + VisitClassTemplateSpecializationDecl(D); + + Writer.AddTemplateParameterList(D->getTemplateParameters(), Record); + + Record.push_back(D->getNumTemplateArgsAsWritten()); + for (int i = 0, e = D->getNumTemplateArgsAsWritten(); i != e; ++i) + Writer.AddTemplateArgumentLoc(D->getTemplateArgsAsWritten()[i], Record); + + Record.push_back(D->getSequenceNumber()); + + // These are read/set from/to the first declaration. + if (D->getPreviousDeclaration() == 0) { + Writer.AddDeclRef(D->getInstantiatedFromMember(), Record); + Record.push_back(D->isMemberSpecialization()); + } + + Code = pch::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION; } void PCHDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { diff --git a/test/PCH/cxx-templates.cpp b/test/PCH/cxx-templates.cpp index 4f66da0346..b068fa25b1 100644 --- a/test/PCH/cxx-templates.cpp +++ b/test/PCH/cxx-templates.cpp @@ -1,8 +1,14 @@ -// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-templates.h -// RUN: %clang_cc1 -include-pch %t -fsyntax-only %s +// Test this without pch. +// RUN: %clang_cc1 -include %S/cxx-templates.h -fsyntax-only -verify %s -S v; +// Test with pch. +// RUN: %clang_cc1 -x c++-header -emit-pch -o %t %S/cxx-templates.h +// RUN: %clang_cc1 -include-pch %t -fsyntax-only -verify %s void test() { int x = templ_f(3); + + S::templ(); + S::partial(); + S::explicit_special(); } diff --git a/test/PCH/cxx-templates.h b/test/PCH/cxx-templates.h index bfd499ba02..c7dc7e8c7a 100644 --- a/test/PCH/cxx-templates.h +++ b/test/PCH/cxx-templates.h @@ -1,8 +1,18 @@ // Header for PCH test cxx-templates.cpp -template +template struct S { - T x; + static void templ(); +}; + +template +struct S { + static void partial(); +}; + +template <> +struct S { + static void explicit_special(); }; template