From ef4579cda09b73e3d4d98af48201da25adc29326 Mon Sep 17 00:00:00 2001 From: Larisse Voufo Date: Tue, 6 Aug 2013 01:03:05 +0000 Subject: [PATCH] Started implementing variable templates. Top level declarations should be fully supported, up to some limitations documented as FIXMEs or TODO. Static data member templates work very partially. Static data member templates of class templates need particular attention... git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@187762 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 35 +- include/clang/AST/ASTMutationListener.h | 8 + include/clang/AST/Decl.h | 36 +- include/clang/AST/DeclTemplate.h | 591 ++++++++++++++ include/clang/AST/RecursiveASTVisitor.h | 88 ++ include/clang/Basic/DeclNodes.td | 4 + include/clang/Basic/DiagnosticParseKinds.td | 8 +- include/clang/Basic/DiagnosticSemaKinds.td | 59 +- include/clang/Basic/TemplateKinds.h | 3 + include/clang/Sema/Sema.h | 110 ++- include/clang/Sema/Template.h | 32 +- include/clang/Serialization/ASTBitCodes.h | 6 + include/clang/Serialization/ASTWriter.h | 3 + lib/AST/ASTContext.cpp | 57 +- lib/AST/ASTImporter.cpp | 247 +++++- lib/AST/Decl.cpp | 64 +- lib/AST/DeclBase.cpp | 3 + lib/AST/DeclTemplate.cpp | 245 ++++++ lib/AST/ItaniumMangle.cpp | 10 +- lib/CodeGen/CGDecl.cpp | 3 + lib/CodeGen/CodeGenModule.cpp | 8 +- lib/Frontend/MultiplexConsumer.cpp | 8 + lib/Parse/ParseCXXInlineMethods.cpp | 6 +- lib/Parse/ParseDecl.cpp | 66 +- lib/Parse/ParseDeclCXX.cpp | 8 + lib/Parse/ParseExprCXX.cpp | 10 +- lib/Parse/ParseTemplate.cpp | 33 +- lib/Parse/Parser.cpp | 6 +- lib/Sema/SemaDecl.cpp | 245 +++++- lib/Sema/SemaDeclCXX.cpp | 6 +- lib/Sema/SemaExpr.cpp | 134 ++- lib/Sema/SemaTemplate.cpp | 645 +++++++++++++-- lib/Sema/SemaTemplateDeduction.cpp | 213 ++++- lib/Sema/SemaTemplateInstantiate.cpp | 42 +- lib/Sema/SemaTemplateInstantiateDecl.cpp | 768 ++++++++++++++---- lib/Serialization/ASTCommon.cpp | 3 + lib/Serialization/ASTReaderDecl.cpp | 141 +++- lib/Serialization/ASTWriter.cpp | 16 + lib/Serialization/ASTWriterDecl.cpp | 85 ++ .../temp.decls/temp.class/temp.static/p1.cpp | 2 +- .../cxx1y-variable-template-no-body.cpp | 37 + .../temp.spec/temp.expl.spec/examples.cpp | 3 +- test/SemaCXX/conversion-function.cpp | 2 +- .../cxx1y-variable-templates_in_class.cpp | 159 ++++ .../cxx1y-variable-templates_top_level.cpp | 415 ++++++++++ test/SemaCXX/cxx98-compat.cpp | 77 ++ test/SemaCXX/for-range-examples.cpp | 2 +- test/SemaCXX/unknown-type-name.cpp | 4 +- test/SemaTemplate/class-template-decl.cpp | 4 +- tools/libclang/CIndex.cpp | 11 +- tools/libclang/RecursiveASTVisitor.h | 89 ++ 51 files changed, 4445 insertions(+), 415 deletions(-) create mode 100644 test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp create mode 100644 test/SemaCXX/cxx1y-variable-templates_in_class.cpp create mode 100644 test/SemaCXX/cxx1y-variable-templates_top_level.cpp diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index a686f3378f..405043a1db 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -271,13 +271,25 @@ class ASTContext : public RefCountedBase { /// wasting space in the Decl class. llvm::DenseMap DeclAttrs; - /// \brief Keeps track of the static data member templates from which - /// static data members of class template specializations were instantiated. +public: + /// \brief A type synonym for the TemplateOrInstantiation mapping. + typedef llvm::PointerUnion + TemplateOrSpecializationInfo; + +private: + + /// \brief A mapping to contain the template or declaration that + /// a variable declaration describes or was instantiated from, + /// respectively. /// - /// This data structure stores the mapping from instantiations of static - /// data members to the static data member representations within the - /// class template from which they were instantiated along with the kind - /// of instantiation or specialization (a TemplateSpecializationKind - 1). + /// For non-templates, this value will be NULL. For variable + /// declarations that describe a variable template, this will be a + /// pointer to a VarTemplateDecl. For static data members + /// of class template specializations, this will be the + /// MemberSpecializationInfo referring to the member variable that was + /// instantiated or specialized. Thus, the mapping will keep track of + /// the static data member templates from which static data members of + /// class template specializations were instantiated. /// /// Given the following example: /// @@ -296,8 +308,8 @@ class ASTContext : public RefCountedBase { /// This mapping will contain an entry that maps from the VarDecl for /// X::value to the corresponding VarDecl for X::value (within the /// class template X) and will be marked TSK_ImplicitInstantiation. - llvm::DenseMap - InstantiatedFromStaticDataMember; + llvm::DenseMap + TemplateOrInstantiation; /// \brief Keeps track of the declaration from which a UsingDecl was /// created during instantiation. @@ -606,9 +618,13 @@ public: /// \brief If this variable is an instantiated static data member of a /// class template specialization, returns the templated static data member /// from which it was instantiated. + // FIXME: Remove ? MemberSpecializationInfo *getInstantiatedFromStaticDataMember( const VarDecl *Var); + TemplateOrSpecializationInfo + getTemplateOrSpecializationInfo(const VarDecl *Var); + FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD); void setClassScopeSpecializationPattern(FunctionDecl *FD, @@ -620,6 +636,9 @@ public: TemplateSpecializationKind TSK, SourceLocation PointOfInstantiation = SourceLocation()); + void setTemplateOrSpecializationInfo(VarDecl *Inst, + TemplateOrSpecializationInfo TSI); + /// \brief If the given using decl \p Inst is an instantiation of a /// (possibly unresolved) using decl from a template instantiation, /// return it. diff --git a/include/clang/AST/ASTMutationListener.h b/include/clang/AST/ASTMutationListener.h index 3681381bf6..ab0d79aecb 100644 --- a/include/clang/AST/ASTMutationListener.h +++ b/include/clang/AST/ASTMutationListener.h @@ -30,6 +30,8 @@ namespace clang { class QualType; class TagDecl; class VarDecl; + class VarTemplateDecl; + class VarTemplateSpecializationDecl; /// \brief An abstract interface that should be implemented by listeners /// that want to be notified when an AST entity gets modified after its @@ -52,6 +54,12 @@ public: 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 VarTemplateDecl *TD, + const VarTemplateSpecializationDecl *D) {} + /// \brief A template specialization (or partial one) was added to the /// template declaration. virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index b1fe7b4c20..671e47f3e1 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -44,6 +44,7 @@ class TemplateArgumentList; class TemplateParameterList; class TypeLoc; class UnresolvedSetImpl; +class VarTemplateDecl; /// \brief A container of type source information. /// @@ -710,6 +711,7 @@ private: friend class ASTDeclReader; friend class StmtIteratorBase; + friend class ASTNodeImporter; protected: enum { NumParameterIndexBits = 8 }; @@ -748,15 +750,8 @@ protected: }; VarDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, StorageClass SC) - : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), Init() { - assert(sizeof(VarDeclBitfields) <= sizeof(unsigned)); - assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned)); - AllBits = 0; - VarDeclBits.SClass = SC; - // Everything else is implicitly initialized to false. - } + SourceLocation IdLoc, IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, StorageClass SC); typedef Redeclarable redeclarable_base; virtual VarDecl *getNextRedeclaration() { return RedeclLink.getNext(); } @@ -955,7 +950,8 @@ public: /// isFileVarDecl - Returns true for file scoped variable declaration. bool isFileVarDecl() const { - if (getKind() != Decl::Var) + Kind K = getKind(); + if (K == ParmVar || K == ImplicitParam) return false; if (getDeclContext()->getRedeclContext()->isFileContext()) @@ -1150,6 +1146,26 @@ public: void setTemplateSpecializationKind(TemplateSpecializationKind TSK, SourceLocation PointOfInstantiation = SourceLocation()); + /// \brief Specify that this variable is an instantiation of the + /// static data member VD. + void setInstantiationOfStaticDataMember(VarDecl *VD, + TemplateSpecializationKind TSK); + + /// \brief Retrieves the variable template that is described by this + /// variable declaration. + /// + /// Every variable template is represented as a VarTemplateDecl and a + /// VarDecl. The former contains template properties (such as + /// the template parameter lists) while the latter contains the + /// actual description of the template's + /// contents. VarTemplateDecl::getTemplatedDecl() retrieves the + /// VarDecl that from a VarTemplateDecl, while + /// getDescribedVarTemplate() retrieves the VarTemplateDecl from + /// a VarDecl. + VarTemplateDecl *getDescribedVarTemplate() const; + + void setDescribedVarTemplate(VarTemplateDecl *Template); + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K >= firstVar && K <= lastVar; } diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 14ed8a1e62..a0764054c7 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -34,6 +34,8 @@ class TemplateTypeParmDecl; class NonTypeTemplateParmDecl; class TemplateTemplateParmDecl; class TypeAliasTemplateDecl; +class VarTemplateDecl; +class VarTemplatePartialSpecializationDecl; /// \brief Stores a template parameter of any kind. typedef llvm::PointerUnion3 constexpr T pi = T(3.1415926535897932385); +/// +/// template<> +/// constexpr float pi; // variable template specialization pi +/// \endcode +class VarTemplateSpecializationDecl : public VarDecl, + public llvm::FoldingSetNode { + + /// \brief Structure that stores information about a variable template + /// specialization that was instantiated from a variable template partial + /// specialization. + struct SpecializedPartialSpecialization { + /// \brief The variable template partial specialization from which this + /// variable template specialization was instantiated. + VarTemplatePartialSpecializationDecl *PartialSpecialization; + + /// \brief The template argument list deduced for the variable template + /// partial specialization itself. + TemplateArgumentList *TemplateArgs; + }; + + /// \brief The template that this specialization specializes. + llvm::PointerUnion + SpecializedTemplate; + + /// \brief Further info for explicit template specialization/instantiation. + struct ExplicitSpecializationInfo { + /// \brief The type-as-written. + TypeSourceInfo *TypeAsWritten; + /// \brief The location of the extern keyword. + SourceLocation ExternLoc; + /// \brief The location of the template keyword. + SourceLocation TemplateKeywordLoc; + + ExplicitSpecializationInfo() + : TypeAsWritten(0), ExternLoc(), TemplateKeywordLoc() {} + }; + + /// \brief Further info for explicit template specialization/instantiation. + /// Does not apply to implicit specializations. + ExplicitSpecializationInfo *ExplicitInfo; + + /// \brief The template arguments used to describe this specialization. + TemplateArgumentList *TemplateArgs; + TemplateArgumentListInfo TemplateArgsInfo; + + /// \brief The point where this template was instantiated (if any). + SourceLocation PointOfInstantiation; + + /// \brief The kind of specialization this declaration refers to. + /// Really a value of type TemplateSpecializationKind. + unsigned SpecializationKind : 3; + +protected: + VarTemplateSpecializationDecl(ASTContext &Context, Kind DK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + VarTemplateDecl *SpecializedTemplate, + QualType T, TypeSourceInfo *TInfo, + StorageClass S, const TemplateArgument *Args, + unsigned NumArgs); + + explicit VarTemplateSpecializationDecl(Kind DK); + +public: + static VarTemplateSpecializationDecl * + Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T, + TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args, + unsigned NumArgs); + static VarTemplateSpecializationDecl *CreateDeserialized(ASTContext &C, + unsigned ID); + + virtual void getNameForDiagnostic(raw_ostream &OS, + const PrintingPolicy &Policy, + bool Qualified) const; + + VarTemplateSpecializationDecl *getMostRecentDecl() { + VarDecl *Recent = cast(VarDecl::getMostRecentDecl()); + return cast(Recent); + } + + /// \brief Retrieve the template that this specialization specializes. + VarTemplateDecl *getSpecializedTemplate() const; + + /// \brief Retrieve the template arguments of the variable template + /// specialization. + const TemplateArgumentList &getTemplateArgs() const { return *TemplateArgs; } + + // TODO: Always set this when creating the new specialization? + void setTemplateArgsInfo(const TemplateArgumentListInfo &ArgsInfo); + + const TemplateArgumentListInfo &getTemplateArgsInfo() const { + return TemplateArgsInfo; + } + + /// \brief Determine the kind of specialization that this + /// declaration represents. + TemplateSpecializationKind getSpecializationKind() const { + return static_cast(SpecializationKind); + } + + bool isExplicitSpecialization() const { + return getSpecializationKind() == TSK_ExplicitSpecialization; + } + + /// \brief True if this declaration is an explicit specialization, + /// explicit instantiation declaration, or explicit instantiation + /// definition. + bool isExplicitInstantiationOrSpecialization() const { + switch (getTemplateSpecializationKind()) { + case TSK_ExplicitSpecialization: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + return true; + + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + return false; + } + llvm_unreachable("bad template specialization kind"); + } + + void setSpecializationKind(TemplateSpecializationKind TSK) { + SpecializationKind = TSK; + } + + /// \brief Get the point of instantiation (if any), or null if none. + SourceLocation getPointOfInstantiation() const { + return PointOfInstantiation; + } + + void setPointOfInstantiation(SourceLocation Loc) { + assert(Loc.isValid() && "point of instantiation must be valid!"); + PointOfInstantiation = Loc; + } + + /// \brief If this variable template specialization is an instantiation of + /// a template (rather than an explicit specialization), return the + /// variable template or variable template partial specialization from which + /// it was instantiated. + llvm::PointerUnion + getInstantiatedFrom() const { + if (getSpecializationKind() != TSK_ImplicitInstantiation && + getSpecializationKind() != TSK_ExplicitInstantiationDefinition && + getSpecializationKind() != TSK_ExplicitInstantiationDeclaration) + return llvm::PointerUnion(); + + if (SpecializedPartialSpecialization *PartialSpec = + SpecializedTemplate.dyn_cast()) + return PartialSpec->PartialSpecialization; + + return SpecializedTemplate.get(); + } + + /// \brief Retrieve the variable template or variable template partial + /// specialization which was specialized by this. + llvm::PointerUnion + getSpecializedTemplateOrPartial() const { + if (SpecializedPartialSpecialization *PartialSpec = + SpecializedTemplate.dyn_cast()) + return PartialSpec->PartialSpecialization; + + return SpecializedTemplate.get(); + } + + /// \brief Retrieve the set of template arguments that should be used + /// to instantiate the initializer of the variable template or variable + /// template partial specialization from which this variable template + /// specialization was instantiated. + /// + /// \returns For a variable template specialization instantiated from the + /// primary template, this function will return the same template arguments + /// as getTemplateArgs(). For a variable template specialization instantiated + /// from a variable template partial specialization, this function will the + /// return deduced template arguments for the variable template partial + /// specialization itself. + const TemplateArgumentList &getTemplateInstantiationArgs() const { + if (SpecializedPartialSpecialization *PartialSpec = + SpecializedTemplate.dyn_cast()) + return *PartialSpec->TemplateArgs; + + return getTemplateArgs(); + } + + /// \brief Note that this variable template specialization is actually an + /// instantiation of the given variable template partial specialization whose + /// template arguments have been deduced. + void setInstantiationOf(VarTemplatePartialSpecializationDecl *PartialSpec, + TemplateArgumentList *TemplateArgs) { + assert(!SpecializedTemplate.is() && + "Already set to a variable template partial specialization!"); + SpecializedPartialSpecialization *PS = + new (getASTContext()) SpecializedPartialSpecialization(); + PS->PartialSpecialization = PartialSpec; + PS->TemplateArgs = TemplateArgs; + SpecializedTemplate = PS; + } + + /// \brief Note that this variable template specialization is an instantiation + /// of the given variable template. + void setInstantiationOf(VarTemplateDecl *TemplDecl) { + assert(!SpecializedTemplate.is() && + "Previously set to a variable template partial specialization!"); + SpecializedTemplate = TemplDecl; + } + + /// \brief Sets the type of this specialization as it was written by + /// the user. + void setTypeAsWritten(TypeSourceInfo *T) { + if (!ExplicitInfo) + ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; + ExplicitInfo->TypeAsWritten = T; + } + /// \brief Gets the type of this specialization as it was written by + /// the user, if it was so written. + TypeSourceInfo *getTypeAsWritten() const { + return ExplicitInfo ? ExplicitInfo->TypeAsWritten : 0; + } + + /// \brief Gets the location of the extern keyword, if present. + SourceLocation getExternLoc() const { + return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation(); + } + /// \brief Sets the location of the extern keyword. + void setExternLoc(SourceLocation Loc) { + if (!ExplicitInfo) + ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; + ExplicitInfo->ExternLoc = Loc; + } + + /// \brief Sets the location of the template keyword. + void setTemplateKeywordLoc(SourceLocation Loc) { + if (!ExplicitInfo) + ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo; + ExplicitInfo->TemplateKeywordLoc = Loc; + } + /// \brief Gets the location of the template keyword, if present. + SourceLocation getTemplateKeywordLoc() const { + return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation(); + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + Profile(ID, TemplateArgs->data(), TemplateArgs->size(), getASTContext()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, ASTContext &Context) { + ID.AddInteger(NumTemplateArgs); + for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg) + TemplateArgs[Arg].Profile(ID, Context); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K >= firstVarTemplateSpecialization && + K <= lastVarTemplateSpecialization; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +class VarTemplatePartialSpecializationDecl + : public VarTemplateSpecializationDecl { + virtual void anchor(); + + /// \brief The list of template parameters + TemplateParameterList *TemplateParams; + + /// \brief The source info for the template arguments as written. + /// FIXME: redundant with TypeAsWritten? + TemplateArgumentLoc *ArgsAsWritten; + unsigned NumArgsAsWritten; + + /// \brief Sequence number indicating when this variable template partial + /// specialization was added to the set of partial specializations for + /// its owning variable template. + unsigned SequenceNumber; + + /// \brief The variable template partial specialization from which this + /// variable template partial specialization was instantiated. + /// + /// The boolean value will be true to indicate that this variable template + /// partial specialization was specialized at this level. + llvm::PointerIntPair + InstantiatedFromMember; + + VarTemplatePartialSpecializationDecl( + ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, TemplateParameterList *Params, + VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo, + StorageClass S, const TemplateArgument *Args, unsigned NumArgs, + TemplateArgumentLoc *ArgInfos, unsigned NumArgInfos, + unsigned SequenceNumber); + + VarTemplatePartialSpecializationDecl() + : VarTemplateSpecializationDecl(VarTemplatePartialSpecialization), + TemplateParams(0), ArgsAsWritten(0), NumArgsAsWritten(0), + SequenceNumber(SequenceNumber), InstantiatedFromMember(0, false) {} + +public: + static VarTemplatePartialSpecializationDecl * + Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, TemplateParameterList *Params, + VarTemplateDecl *SpecializedTemplate, QualType T, + TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args, + unsigned NumArgs, const TemplateArgumentListInfo &ArgInfos, + unsigned SequenceNumber); + + static VarTemplatePartialSpecializationDecl *CreateDeserialized(ASTContext &C, + unsigned ID); + + VarTemplatePartialSpecializationDecl *getMostRecentDecl() { + return cast( + VarTemplateSpecializationDecl::getMostRecentDecl()); + } + + /// Get the list of template parameters + TemplateParameterList *getTemplateParameters() const { + return TemplateParams; + } + + /// Get the template arguments as written. + TemplateArgumentLoc *getTemplateArgsAsWritten() const { + return ArgsAsWritten; + } + + /// Get the number of template arguments as written. + unsigned getNumTemplateArgsAsWritten() const { return NumArgsAsWritten; } + + /// \brief Get the sequence number for this variable template partial + /// specialization. + unsigned getSequenceNumber() const { return SequenceNumber; } + + /// \brief Retrieve the member variable template partial specialization from + /// which this particular variable template partial specialization was + /// instantiated. + /// + /// \code + /// template + /// struct Outer { + /// template U Inner; + /// template U* Inner = (U*)(0); // #1 + /// }; + /// + /// template int* Outer::Inner; + /// \endcode + /// + /// In this example, the instantiation of \c Outer::Inner will + /// end up instantiating the partial specialization + /// \c Outer::Inner, which itself was instantiated from the + /// variable template partial specialization \c Outer::Inner. Given + /// \c Outer::Inner, this function would return + /// \c Outer::Inner. + VarTemplatePartialSpecializationDecl *getInstantiatedFromMember() { + VarTemplatePartialSpecializationDecl *First = + cast(getFirstDeclaration()); + return First->InstantiatedFromMember.getPointer(); + } + + void + setInstantiatedFromMember(VarTemplatePartialSpecializationDecl *PartialSpec) { + VarTemplatePartialSpecializationDecl *First = + cast(getFirstDeclaration()); + First->InstantiatedFromMember.setPointer(PartialSpec); + } + + /// \brief Determines whether this variable template partial specialization + /// was a specialization of a member partial specialization. + /// + /// In the following example, the member template partial specialization + /// \c X::Inner is a member specialization. + /// + /// \code + /// template + /// struct X { + /// template U Inner; + /// template U* Inner = (U*)(0); + /// }; + /// + /// template<> template + /// U* X::Inner = (T*)(0) + 1; + /// \endcode + bool isMemberSpecialization() { + VarTemplatePartialSpecializationDecl *First = + cast(getFirstDeclaration()); + return First->InstantiatedFromMember.getInt(); + } + + /// \brief Note that this member template is a specialization. + void setMemberSpecialization() { + VarTemplatePartialSpecializationDecl *First = + cast(getFirstDeclaration()); + assert(First->InstantiatedFromMember.getPointer() && + "Only member templates can be member template specializations"); + return First->InstantiatedFromMember.setInt(true); + } + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { + return K == VarTemplatePartialSpecialization; + } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + +/// Declaration of a variable template. +class VarTemplateDecl : public RedeclarableTemplateDecl { + static void DeallocateCommon(void *Ptr); + +protected: + /// \brief Data that is common to all of the declarations of a given + /// variable template. + struct Common : CommonBase { + Common() : LazySpecializations() {} + + /// \brief The variable template specializations for this variable + /// template, including explicit specializations and instantiations. + llvm::FoldingSetVector Specializations; + + /// \brief The variable template partial specializations for this variable + /// template. + llvm::FoldingSetVector + PartialSpecializations; + + /// \brief If non-null, points to an array of specializations (including + /// partial specializations) known ownly by their external declaration IDs. + /// + /// The first value in the array is the number of of specializations/ + /// partial specializations that follow. + uint32_t *LazySpecializations; + }; + + /// \brief Load any lazily-loaded specializations from the external source. + void LoadLazySpecializations() const; + + /// \brief Retrieve the set of specializations of this variable template. + llvm::FoldingSetVector & + getSpecializations() const; + + /// \brief Retrieve the set of partial specializations of this class + /// template. + llvm::FoldingSetVector & + getPartialSpecializations(); + + VarTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, NamedDecl *Decl) + : RedeclarableTemplateDecl(VarTemplate, DC, L, Name, Params, Decl) {} + + VarTemplateDecl(EmptyShell Empty) + : RedeclarableTemplateDecl(VarTemplate, 0, SourceLocation(), + DeclarationName(), 0, 0) {} + + CommonBase *newCommon(ASTContext &C) const; + + Common *getCommonPtr() const { + return static_cast(RedeclarableTemplateDecl::getCommonPtr()); + } + +public: + /// \brief Get the underlying variable declarations of the template. + VarDecl *getTemplatedDecl() const { + return static_cast(TemplatedDecl); + } + + /// \brief Returns whether this template declaration defines the primary + /// variable pattern. + bool isThisDeclarationADefinition() const { + return getTemplatedDecl()->isThisDeclarationADefinition(); + } + + /// \brief Create a variable template node. + static VarTemplateDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, NamedDecl *Decl, + VarTemplateDecl *PrevDecl); + + /// \brief Create an empty variable template node. + static VarTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); + + /// \brief Return the specialization with the provided arguments if it exists, + /// otherwise return the insertion point. + VarTemplateSpecializationDecl * + findSpecialization(const TemplateArgument *Args, unsigned NumArgs, + void *&InsertPos); + + /// \brief Insert the specified specialization knowing that it is not already + /// in. InsertPos must be obtained from findSpecialization. + void AddSpecialization(VarTemplateSpecializationDecl *D, void *InsertPos); + + VarTemplateDecl *getCanonicalDecl() { + return cast(RedeclarableTemplateDecl::getCanonicalDecl()); + } + const VarTemplateDecl *getCanonicalDecl() const { + return cast(RedeclarableTemplateDecl::getCanonicalDecl()); + } + + /// \brief Retrieve the previous declaration of this variable template, or + /// NULL if no such declaration exists. + VarTemplateDecl *getPreviousDecl() { + return cast_or_null( + RedeclarableTemplateDecl::getPreviousDecl()); + } + + /// \brief Retrieve the previous declaration of this variable template, or + /// NULL if no such declaration exists. + const VarTemplateDecl *getPreviousDecl() const { + return cast_or_null( + RedeclarableTemplateDecl::getPreviousDecl()); + } + + VarTemplateDecl *getInstantiatedFromMemberTemplate() { + return cast_or_null( + RedeclarableTemplateDecl::getInstantiatedFromMemberTemplate()); + } + + /// \brief Return the partial specialization with the provided arguments if it + /// exists, otherwise return the insertion point. + VarTemplatePartialSpecializationDecl * + findPartialSpecialization(const TemplateArgument *Args, unsigned NumArgs, + void *&InsertPos); + + /// \brief Insert the specified partial specialization knowing that it is not + /// already in. InsertPos must be obtained from findPartialSpecialization. + void AddPartialSpecialization(VarTemplatePartialSpecializationDecl *D, + void *InsertPos); + + /// \brief Return the next partial specialization sequence number. + unsigned getNextPartialSpecSequenceNumber() { + return getPartialSpecializations().size(); + } + + /// \brief Retrieve the partial specializations as an ordered list. + void getPartialSpecializations( + SmallVectorImpl &PS); + + /// \brief Find a variable template partial specialization which was + /// instantiated + /// from the given member partial specialization. + /// + /// \param D a member variable template partial specialization. + /// + /// \returns the variable template partial specialization which was + /// instantiated + /// from the given member partial specialization, or NULL if no such partial + /// specialization exists. + VarTemplatePartialSpecializationDecl *findPartialSpecInstantiatedFromMember( + VarTemplatePartialSpecializationDecl *D); + + typedef SpecIterator spec_iterator; + + spec_iterator spec_begin() const { + return makeSpecIterator(getSpecializations(), false); + } + + spec_iterator spec_end() const { + return makeSpecIterator(getSpecializations(), true); + } + + typedef SpecIterator + partial_spec_iterator; + + partial_spec_iterator partial_spec_begin() { + return makeSpecIterator(getPartialSpecializations(), false); + } + + partial_spec_iterator partial_spec_end() { + return makeSpecIterator(getPartialSpecializations(), true); + } + + // Implement isa/cast/dyncast support + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == VarTemplate; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + } /* end of namespace clang */ #endif diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 1b7d5200e5..da6a3a321a 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -408,6 +408,7 @@ private: // These are helper methods used by more than one Traverse* method. bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL); bool TraverseClassInstantiations(ClassTemplateDecl *D); + bool TraverseVariableInstantiations(VarTemplateDecl *D); bool TraverseFunctionInstantiations(FunctionTemplateDecl *D) ; bool TraverseTemplateArgumentLocsHelper(const TemplateArgumentLoc *TAL, unsigned Count); @@ -1500,6 +1501,57 @@ DEF_TRAVERSE_DECL(ClassTemplateDecl, { // it was instantiated, and thus should not be traversed. }) +// A helper method for traversing the implicit instantiations of a +// variable template. +template +bool RecursiveASTVisitor::TraverseVariableInstantiations( + VarTemplateDecl *D) { + VarTemplateDecl::spec_iterator end = D->spec_end(); + for (VarTemplateDecl::spec_iterator it = D->spec_begin(); it != end; ++it) { + VarTemplateSpecializationDecl *SD = *it; + + switch (SD->getSpecializationKind()) { + // Visit the implicit instantiations with the requested pattern. + case TSK_Undeclared: + case TSK_ImplicitInstantiation: + TRY_TO(TraverseDecl(SD)); + break; + + // We don't need to do anything on an explicit instantiation + // or explicit specialization because there will be an explicit + // node for it elsewhere. + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + case TSK_ExplicitSpecialization: + break; + } + } + + return true; +} + + // FIXME: Unify traversal for variable templates, class templates and function + // templates. +DEF_TRAVERSE_DECL(VarTemplateDecl, { + VarDecl *TempDecl = D->getTemplatedDecl(); + TRY_TO(TraverseDecl(TempDecl)); + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); + + // By default, we do not traverse the instantiations of + // class templates since they do not appear in the user code. The + // following code optionally traverses them. + // + // We only traverse the class instantiations when we see the canonical + // declaration of the template, to ensure we only visit them once. + if (getDerived().shouldVisitTemplateInstantiations() && + D == D->getCanonicalDecl()) + TRY_TO(TraverseVariableInstantiations(D)); + + // Note that getInstantiatedFromMemberTemplate() is just a link + // from a template instantiation back to the template from which + // it was instantiated, and thus should not be traversed. +}) + // A helper method for traversing the instantiations of a // function while skipping its specializations. template @@ -1830,6 +1882,42 @@ DEF_TRAVERSE_DECL(VarDecl, { TRY_TO(TraverseVarHelper(D)); }) +DEF_TRAVERSE_DECL(VarTemplateSpecializationDecl, { + // For implicit instantiations, we don't want to + // recurse at all, since the instatiated class isn't written in + // the source code anywhere. + if (TypeSourceInfo *TSI = D->getTypeAsWritten()) + TRY_TO(TraverseTypeLoc(TSI->getTypeLoc())); + + if (!getDerived().shouldVisitTemplateInstantiations() && + D->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) + // Returning from here skips traversing the + // declaration context of the VarTemplateSpecializationDecl + // (embedded in the DEF_TRAVERSE_DECL() macro). + return true; +}) + +DEF_TRAVERSE_DECL(VarTemplatePartialSpecializationDecl, { + // The partial specialization. + if (TemplateParameterList *TPL = D->getTemplateParameters()) { + for (TemplateParameterList::iterator I = TPL->begin(), E = TPL->end(); + I != E; ++I) { + TRY_TO(TraverseDecl(*I)); + } + } + // The args that remain unspecialized. + TRY_TO(TraverseTemplateArgumentLocsHelper(D->getTemplateArgsAsWritten(), + D->getNumTemplateArgsAsWritten())); + + // Don't need the VarTemplatePartialSpecializationHelper, even + // though that's our parent class -- we already visit all the + // template args here. + TRY_TO(TraverseVarHelper(D)); + + // Instantiations will have been visited with the primary + // template. +}) + DEF_TRAVERSE_DECL(ImplicitParamDecl, { TRY_TO(TraverseVarHelper(D)); }) diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td index ad2afa7a57..18bca57419 100644 --- a/include/clang/Basic/DeclNodes.td +++ b/include/clang/Basic/DeclNodes.td @@ -44,6 +44,9 @@ def Named : Decl<1>; def CXXDestructor : DDecl; def CXXConversion : DDecl; def Var : DDecl; + def VarTemplateSpecialization : DDecl; + def VarTemplatePartialSpecialization + : DDecl; def ImplicitParam : DDecl; def ParmVar : DDecl; def NonTypeTemplateParm : DDecl; @@ -51,6 +54,7 @@ def Named : Decl<1>; def RedeclarableTemplate : DDecl; def FunctionTemplate : DDecl; def ClassTemplate : DDecl; + def VarTemplate : DDecl; def TypeAliasTemplate : DDecl; def TemplateTemplateParm : DDecl