diff options
51 files changed, 4445 insertions, 415 deletions
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index a686f3378fa..405043a1db0 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -271,13 +271,25 @@ class ASTContext : public RefCountedBase<ASTContext> { /// wasting space in the Decl class. llvm::DenseMap<const Decl*, AttrVec*> 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<VarTemplateDecl *, MemberSpecializationInfo *> + 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<ASTContext> { /// This mapping will contain an entry that maps from the VarDecl for /// X<int>::value to the corresponding VarDecl for X<T>::value (within the /// class template X) and will be marked TSK_ImplicitInstantiation. - llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *> - InstantiatedFromStaticDataMember; + llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo> + 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/clang/include/clang/AST/ASTMutationListener.h b/clang/include/clang/AST/ASTMutationListener.h index 3681381bf69..ab0d79aecba 100644 --- a/clang/include/clang/AST/ASTMutationListener.h +++ b/clang/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 @@ -54,6 +56,12 @@ public: /// \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, const FunctionDecl *D) {} diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index b1fe7b4c207..671e47f3e17 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/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<VarDecl> 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/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 14ed8a1e621..a0764054c7f 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/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<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*, @@ -2250,6 +2252,595 @@ public: inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD) : Function(FTD) { } +/// \brief Represents a variable template specialization, which refers to +/// a variable template with a given set of template arguments. +/// +/// Variable template specializations represent both explicit +/// specializations of variable templates, as in the example below, and +/// implicit instantiations of variable templates. +/// +/// \code +/// template<typename T> constexpr T pi = T(3.1415926535897932385); +/// +/// template<> +/// constexpr float pi<float>; // variable template specialization pi<float> +/// \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<VarTemplateDecl *, SpecializedPartialSpecialization *> + 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>(VarDecl::getMostRecentDecl()); + return cast<VarTemplateSpecializationDecl>(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<TemplateSpecializationKind>(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<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> + getInstantiatedFrom() const { + if (getSpecializationKind() != TSK_ImplicitInstantiation && + getSpecializationKind() != TSK_ExplicitInstantiationDefinition && + getSpecializationKind() != TSK_ExplicitInstantiationDeclaration) + return llvm::PointerUnion<VarTemplateDecl *, + VarTemplatePartialSpecializationDecl *>(); + + if (SpecializedPartialSpecialization *PartialSpec = + SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>()) + return PartialSpec->PartialSpecialization; + + return SpecializedTemplate.get<VarTemplateDecl *>(); + } + + /// \brief Retrieve the variable template or variable template partial + /// specialization which was specialized by this. + llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> + getSpecializedTemplateOrPartial() const { + if (SpecializedPartialSpecialization *PartialSpec = + SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>()) + return PartialSpec->PartialSpecialization; + + return SpecializedTemplate.get<VarTemplateDecl *>(); + } + + /// \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<SpecializedPartialSpecialization *>()) + 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<SpecializedPartialSpecialization *>() && + "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<SpecializedPartialSpecialization *>() && + "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<VarTemplatePartialSpecializationDecl *, 1, bool> + 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<VarTemplatePartialSpecializationDecl>( + 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<typename T> + /// struct Outer { + /// template<typename U> U Inner; + /// template<typename U> U* Inner<U*> = (U*)(0); // #1 + /// }; + /// + /// template int* Outer<float>::Inner<int*>; + /// \endcode + /// + /// In this example, the instantiation of \c Outer<float>::Inner<int*> will + /// end up instantiating the partial specialization + /// \c Outer<float>::Inner<U*>, which itself was instantiated from the + /// variable template partial specialization \c Outer<T>::Inner<U*>. Given + /// \c Outer<float>::Inner<U*>, this function would return + /// \c Outer<T>::Inner<U*>. + VarTemplatePartialSpecializationDecl *getInstantiatedFromMember() { + VarTemplatePartialSpecializationDecl *First = + cast<VarTemplatePartialSpecializationDecl>(getFirstDeclaration()); + return First->InstantiatedFromMember.getPointer(); + } + + void + setInstantiatedFromMember(VarTemplatePartialSpecializationDecl *PartialSpec) { + VarTemplatePartialSpecializationDecl *First = + cast<VarTemplatePartialSpecializationDecl>(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<int>::Inner<T*> is a member specialization. + /// + /// \code + /// template<typename T> + /// struct X { + /// template<typename U> U Inner; + /// template<typename U> U* Inner<U*> = (U*)(0); + /// }; + /// + /// template<> template<typename T> + /// U* X<int>::Inner<T*> = (T*)(0) + 1; + /// \endcode + bool isMemberSpecialization() { + VarTemplatePartialSpecializationDecl *First = + cast<VarTemplatePartialSpecializationDecl>(getFirstDeclaration()); + return First->InstantiatedFromMember.getInt(); + } + + /// \brief Note that this member template is a specialization. + void setMemberSpecialization() { + VarTemplatePartialSpecializationDecl *First = + cast<VarTemplatePartialSpecializationDecl>(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<VarTemplateSpecializationDecl> Specializations; + + /// \brief The variable template partial specializations for this variable + /// template. + llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> + 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<VarTemplateSpecializationDecl> & + getSpecializations() const; + + /// \brief Retrieve the set of partial specializations of this class + /// template. + llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> & + 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<Common *>(RedeclarableTemplateDecl::getCommonPtr()); + } + +public: + /// \brief Get the underlying variable declarations of the template. + VarDecl *getTemplatedDecl() const { + return static_cast<VarDecl *>(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<VarTemplateDecl>(RedeclarableTemplateDecl::getCanonicalDecl()); + } + const VarTemplateDecl *getCanonicalDecl() const { + return cast<VarTemplateDecl>(RedeclarableTemplateDecl::getCanonicalDecl()); + } + + /// \brief Retrieve the previous declaration of this variable template, or + /// NULL if no such declaration exists. + VarTemplateDecl *getPreviousDecl() { + return cast_or_null<VarTemplateDecl>( + 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<VarTemplateDecl>( + RedeclarableTemplateDecl::getPreviousDecl()); + } + + VarTemplateDecl *getInstantiatedFromMemberTemplate() { + return cast_or_null<VarTemplateDecl>( + 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<VarTemplatePartialSpecializationDecl *> &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<VarTemplateSpecializationDecl> spec_iterator; + + spec_iterator spec_begin() const { + return makeSpecIterator(getSpecializations(), false); + } + + spec_iterator spec_end() const { + return makeSpecIterator(getSpecializations(), true); + } + + typedef SpecIterator<VarTemplatePartialSpecializationDecl> + 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/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 1b7d5200e56..da6a3a321a9 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/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 <typename Derived> +bool RecursiveASTVisitor<Derived>::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<typename Derived> @@ -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/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index ad2afa7a57c..18bca574196 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -44,6 +44,9 @@ def Named : Decl<1>; def CXXDestructor : DDecl<CXXMethod>; def CXXConversion : DDecl<CXXMethod>; def Var : DDecl<Declarator>; + def VarTemplateSpecialization : DDecl<Var>; + def VarTemplatePartialSpecialization + : DDecl<VarTemplateSpecialization>; def ImplicitParam : DDecl<Var>; def ParmVar : DDecl<Var>; def NonTypeTemplateParm : DDecl<Declarator>; @@ -51,6 +54,7 @@ def Named : Decl<1>; def RedeclarableTemplate : DDecl<Template, 1>; def FunctionTemplate : DDecl<RedeclarableTemplate>; def ClassTemplate : DDecl<RedeclarableTemplate>; + def VarTemplate : DDecl<RedeclarableTemplate>; def TypeAliasTemplate : DDecl<RedeclarableTemplate>; def TemplateTemplateParm : DDecl<Template>; def Using : DDecl<Named>; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 3cda5b364c2..e9712a20d50 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -597,8 +597,8 @@ def err_explicit_instantiation_with_definition : Error< "definition is meant to be an explicit specialization, add '<>' after the " "'template' keyword">; def err_template_defn_explicit_instantiation : Error< - "%select{function|class}0 cannot be defined in an explicit instantiation; if this " - "declaration is meant to be a %select{function|class}0 definition, remove the 'template' keyword">; + "%select{function|class|variable}0 cannot be defined in an explicit instantiation; if this " + "declaration is meant to be a %select{function|class|variable}0 definition, remove the 'template' keyword">; def err_friend_explicit_instantiation : Error< "friend cannot be declared in an explicit instantiation; if this " "declaration is meant to be a friend declaration, remove the 'template' keyword">; @@ -606,6 +606,10 @@ def err_explicit_instantiation_enum : Error< "enumerations cannot be explicitly instantiated">; def err_expected_template_parameter : Error<"expected template parameter">; +def err_forward_var_nested_name_specifier : Error< + "forward declaration of variable template%select{| partial specialization}0 cannot " + "have a nested name specifier">; + def err_missing_dependent_template_keyword : Error< "use 'template' keyword to treat '%0' as a dependent template name">; def warn_missing_dependent_template_keyword : ExtWarn< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index bdfc8b54cfc..cd909d443c7 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -1461,6 +1461,8 @@ def err_auto_not_allowed : Error< "|in exception declaration|in template parameter|in block literal" "|in template argument|in typedef|in type alias|in function return type" "|in conversion function type|here}0">; +def err_auto_not_allowed_var_inst : Error< + "'auto' variable template instantiation is not allowed">; def err_auto_var_requires_init : Error< "declaration of variable %0 with type %1 requires an initializer">; def err_auto_new_requires_ctor_arg : Error< @@ -2779,6 +2781,8 @@ def err_template_linkage : Error<"templates must have C++ linkage">; def err_template_typedef : Error<"a typedef cannot be a template">; def err_template_unnamed_class : Error< "cannot declare a class template with no name">; +def err_var_template_unnamed_class : Error< + "cannot declare a variable template with no name">; def err_template_param_list_different_arity : Error< "%select{too few|too many}0 template parameters in template " "%select{|template parameter }1redeclaration">; @@ -2823,7 +2827,11 @@ def err_template_parameter_default_friend_template : Error< def err_template_template_parm_no_parms : Error< "template template parameter must have its own template parameters">; -def err_template_variable : Error<"variable %0 declared as a template">; +def ext_variable_template : ExtWarn<"variable templates are a C++1y extension">, + InGroup<CXX1y>; +def warn_cxx11_compat_variable_template : Warning< + "variable templates are incompatible with C++ standards before C++1y">, + InGroup<CXXPre1yCompat>, DefaultIgnore; def err_template_variable_noparams : Error< "extraneous 'template<>' in declaration of variable %0">; def err_template_member : Error<"member %0 declared as a template">; @@ -2832,7 +2840,7 @@ def err_template_member_noparams : Error< def err_template_tag_noparams : Error< "extraneous 'template<>' in declaration of %0 %1">; def err_template_decl_ref : Error< - "cannot refer to class template %0 without a template argument list">; + "cannot refer to %select{class|variable}0 template %1 without a template argument list">; // C++ Template Argument Lists def err_template_missing_args : Error< @@ -2964,7 +2972,7 @@ def err_pointer_to_member_oper_value_classify: Error< // C++ template specialization def err_template_spec_unknown_kind : Error< "can only provide an explicit specialization for a class template, function " - "template, or a member function, static data member, " + "template, variable template, or a member function, static data member, " "%select{or member class|member class, or member enumeration}0 of a " "class template">; def note_specialized_entity : Note< @@ -2976,29 +2984,35 @@ def err_template_spec_decl_class_scope : Error< def err_template_spec_decl_friend : Error< "cannot declare an explicit specialization in a friend">; def err_template_spec_decl_out_of_scope_global : Error< - "%select{class template|class template partial|function template|member " - "function|static data member|member class|member enumeration}0 " + "%select{class template|class template partial|variable template|" + "variable template partial|function template|member function|" + "static data member|member class|member enumeration}0 " "specialization of %1 must originally be declared in the global scope">; def err_template_spec_decl_out_of_scope : Error< - "%select{class template|class template partial|function template|member " + "%select{class template|class template partial|variable template|" + "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " "specialization of %1 must originally be declared in namespace %2">; def ext_template_spec_decl_out_of_scope : ExtWarn< "first declaration of %select{class template|class template partial|" + "variable template|variable template partial|" "function template|member function|static data member|member class|" "member enumeration}0 specialization of %1 outside namespace %2 is a " "C++11 extension">, InGroup<CXX11>; def warn_cxx98_compat_template_spec_decl_out_of_scope : Warning< - "%select{class template|class template partial|function template|member " + "%select{class template|class template partial|variable template|" + "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " "specialization of %1 outside namespace %2 is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore; def err_template_spec_redecl_out_of_scope : Error< - "%select{class template|class template partial|function template|member " + "%select{class template|class template partial|variable template|" + "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " "specialization of %1 not in a namespace enclosing %2">; def err_template_spec_redecl_global_scope : Error< - "%select{class template|class template partial|function template|member " + "%select{class template|class template partial|variable template|" + "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " "specialization of %1 must occur at global scope">; def err_spec_member_not_instantiated : Error< @@ -3081,6 +3095,16 @@ def note_prev_partial_spec_here : Note< "previous declaration of class template partial specialization %0 is here">; def err_partial_spec_fully_specialized : Error< "partial specialization of %0 does not use any of its template parameters">; + +// C++ Variable Template Partial Specialization +def err_var_default_arg_in_partial_spec : Error< + "default template argument in a variable template partial specialization">; +def err_var_partial_spec_redeclared : Error< + "variable template partial specialization %0 cannot be redefined">; +def note_var_prev_partial_spec_here : Note< + "previous declaration of variable template partial specialization is here">; +def err_var_spec_no_template : Error< + "no variable template matches%select{| partial}0 specialization">; // C++ Function template specializations def err_function_template_spec_no_match : Error< @@ -3194,8 +3218,8 @@ def err_explicit_instantiation_of_typedef : Error< def err_explicit_instantiation_storage_class : Error< "explicit instantiation cannot have a storage class">; def err_explicit_instantiation_not_known : Error< - "explicit instantiation of %0 does not refer to a function template, member " - "function, member class, or static data member">; + "explicit instantiation of %0 does not refer to a function template, " + "variable template, member function, member class, or static data member">; def note_explicit_instantiation_here : Note< "explicit instantiation refers here">; def err_explicit_instantiation_data_member_not_instantiated : Error< @@ -3225,14 +3249,20 @@ def warn_explicit_instantiation_unqualified_wrong_namespace_0x : Warning< InGroup<CXX11Compat>, DefaultIgnore; def err_explicit_instantiation_undefined_member : Error< "explicit instantiation of undefined %select{member class|member function|" - "static data member}0 %1 of class template %2">; + "static data member|static data member template}0 %1 of class template %2">; def err_explicit_instantiation_undefined_func_template : Error< "explicit instantiation of undefined function template %0">; +def err_explicit_instantiation_undefined_var_template : Error< + "explicit instantiation of undefined variable template %0">; def err_explicit_instantiation_declaration_after_definition : Error< "explicit instantiation declaration (with 'extern') follows explicit " "instantiation definition (without 'extern')">; def note_explicit_instantiation_definition_here : Note< "explicit instantiation definition is here">; +def err_invalid_var_template_spec_type : Error<"type %2 " + "of %select{explicit instantiation|explicit specialization|" + "partial specialization|redeclaration}0 of %1 does not match" + " expected type %3">; // C++ typename-specifiers def err_typename_nested_not_found : Error<"no type named %0 in %1">; @@ -3278,7 +3308,8 @@ def err_non_type_template_in_nested_name_specifier : Error< def err_template_id_not_a_type : Error< "template name refers to non-type template %0">; def note_template_declared_here : Note< - "%select{function template|class template|type alias template|template template parameter}0 " + "%select{function template|class template|variable template" + "|type alias template|template template parameter}0 " "%1 declared here">; def note_parameter_type : Note< "parameter of type %0 is declared here">; @@ -5033,6 +5064,8 @@ def err_invalid_declarator_in_function : Error< "definition or redeclaration of %0 not allowed inside a function">; def err_not_tag_in_scope : Error< "no %select{struct|interface|union|class|enum}0 named %1 in %2">; +def err_not_var_in_scope : Error< + "no variable template named %0 in %1">; def err_no_typeid_with_fno_rtti : Error< "cannot use typeid with -fno-rtti">; diff --git a/clang/include/clang/Basic/TemplateKinds.h b/clang/include/clang/Basic/TemplateKinds.h index dda011a54e1..c5218933a22 100644 --- a/clang/include/clang/Basic/TemplateKinds.h +++ b/clang/include/clang/Basic/TemplateKinds.h @@ -27,6 +27,9 @@ enum TemplateNameKind { /// type. The template itself could be a class template, template /// template parameter, or C++0x template alias. TNK_Type_template, + /// The name refers to a variable template whose specialization produces a + /// variable. + TNK_Var_template, /// The name refers to a dependent template name. Whether the /// template name is assumed to refer to a type template or a /// function template depends on the context in which the template diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index ba445ab31d1..d0a5c60cd61 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -87,6 +87,7 @@ namespace clang { class ClassTemplateDecl; class ClassTemplatePartialSpecializationDecl; class ClassTemplateSpecializationDecl; + class VarTemplatePartialSpecializationDecl; class CodeCompleteConsumer; class CodeCompletionAllocator; class CodeCompletionTUInfo; @@ -173,6 +174,7 @@ namespace clang { class UsingShadowDecl; class ValueDecl; class VarDecl; + class VarTemplateSpecializationDecl; class VisibilityAttr; class VisibleDeclConsumer; class IndirectFieldDecl; @@ -1325,6 +1327,7 @@ public: NC_Expression, NC_NestedNameSpecifier, NC_TypeTemplate, + NC_VarTemplate, NC_FunctionTemplate }; @@ -1363,6 +1366,12 @@ public: return Result; } + static NameClassification VarTemplate(TemplateName Name) { + NameClassification Result(NC_VarTemplate); + Result.Template = Name; + return Result; + } + static NameClassification FunctionTemplate(TemplateName Name) { NameClassification Result(NC_FunctionTemplate); Result.Template = Name; @@ -1382,13 +1391,22 @@ public: } TemplateName getTemplateName() const { - assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate); + assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate || + Kind == NC_VarTemplate); return Template; } TemplateNameKind getTemplateNameKind() const { - assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate); - return Kind == NC_TypeTemplate? TNK_Type_template : TNK_Function_template; + switch (Kind) { + case NC_TypeTemplate: + return TNK_Type_template; + case NC_FunctionTemplate: + return TNK_Function_template; + case NC_VarTemplate: + return TNK_Var_template; + default: + llvm_unreachable("unsuported name classification."); + } } }; @@ -1443,10 +1461,11 @@ public: LookupResult &Previous); NamedDecl* ActOnTypedefNameDecl(Scope* S, DeclContext* DC, TypedefNameDecl *D, LookupResult &Previous, bool &Redeclaration); - NamedDecl* ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, + NamedDecl *ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists); + MultiTemplateParamsArg TemplateParamLists, + bool &AddToScope); // Returns true if the variable declaration is a redeclaration bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous); void CheckVariableDeclarationType(VarDecl *NewVD); @@ -3151,11 +3170,10 @@ public: ExprValueKind VK, SourceLocation Loc, const CXXScopeSpec *SS = 0); - ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, - ExprValueKind VK, + ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, - const CXXScopeSpec *SS = 0, - NamedDecl *FoundD = 0); + const CXXScopeSpec *SS = 0, NamedDecl *FoundD = 0, + const TemplateArgumentListInfo *TemplateArgs = 0); ExprResult BuildAnonymousStructUnionMemberReference( const CXXScopeSpec &SS, @@ -3189,9 +3207,9 @@ public: ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL); - ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, - const DeclarationNameInfo &NameInfo, - NamedDecl *D, NamedDecl *FoundD = 0); + ExprResult BuildDeclarationNameExpr( + const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D, + NamedDecl *FoundD = 0, const TemplateArgumentListInfo *TemplateArgs = 0); ExprResult BuildLiteralOperatorCall(LookupResult &R, DeclarationNameInfo &SuffixInfo, @@ -4964,6 +4982,7 @@ public: /// \brief The context in which we are checking a template parameter list. enum TemplateParamListContext { TPC_ClassTemplate, + TPC_VarTemplate, TPC_FunctionTemplate, TPC_ClassTemplateMember, TPC_FriendClassTemplate, @@ -5020,6 +5039,21 @@ public: ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc); + DeclResult ActOnVarTemplateSpecialization( + Scope *S, VarTemplateDecl *VarTemplate, Declarator &D, TypeSourceInfo *DI, + SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, + StorageClass SC, bool IsPartialSpecialization); + + DeclResult CheckVarTemplateId(VarTemplateDecl *Template, + SourceLocation TemplateLoc, + SourceLocation TemplateNameLoc, + const TemplateArgumentListInfo &TemplateArgs); + + ExprResult CheckVarTemplateId(const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + VarTemplateDecl *Template, + SourceLocation TemplateLoc, + const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, @@ -5691,12 +5725,16 @@ public: sema::TemplateDeductionInfo &Info); TemplateDeductionResult - SubstituteExplicitTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - TemplateArgumentListInfo &ExplicitTemplateArgs, - SmallVectorImpl<DeducedTemplateArgument> &Deduced, - SmallVectorImpl<QualType> &ParamTypes, - QualType *FunctionType, - sema::TemplateDeductionInfo &Info); + DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + sema::TemplateDeductionInfo &Info); + + TemplateDeductionResult SubstituteExplicitTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo &ExplicitTemplateArgs, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType, + sema::TemplateDeductionInfo &Info); /// brief A function argument from which we performed template argument // deduction for a call. @@ -5789,6 +5827,10 @@ public: ClassTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); + VarTemplatePartialSpecializationDecl *getMoreSpecializedPartialSpecialization( + VarTemplatePartialSpecializationDecl *PS1, + VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); + void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, @@ -6063,6 +6105,15 @@ public: sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); + /// \brief Note that we are instantiating as part of template + /// argument deduction for a variable template partial + /// specialization. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + VarTemplatePartialSpecializationDecl *PartialSpec, + ArrayRef<TemplateArgument> TemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange = SourceRange()); + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ParmVarDecl *Param, ArrayRef<TemplateArgument> TemplateArgs, @@ -6344,6 +6395,29 @@ public: FunctionDecl *Function, bool Recursive = false, bool DefinitionRequired = false); + VarTemplateSpecializationDecl *BuildVarTemplateInstantiation( + VarTemplateDecl *VarTemplate, VarDecl *FromVar, + const TemplateArgumentList &TemplateArgList, + const TemplateArgumentListInfo &TemplateArgsInfo, + SmallVectorImpl<TemplateArgument> &Converted, + SourceLocation PointOfInstantiation, void *InsertPos, + LateInstantiatedAttrVec *LateAttrs = 0, + LocalInstantiationScope *StartingScope = 0); + VarTemplateSpecializationDecl *CompleteVarTemplateSpecializationDecl( + VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl, + const MultiLevelTemplateArgumentList &TemplateArgs); + void + BuildVariableInstantiation(VarDecl *NewVar, VarDecl *OldVar, + const MultiLevelTemplateArgumentList &TemplateArgs, + LateInstantiatedAttrVec *LateAttrs = 0, + LocalInstantiationScope *StartingScope = 0, + bool ForVarTemplate = false); + void InstantiateVariableInitializer( + VarDecl *Var, VarDecl *OldVar, + const MultiLevelTemplateArgumentList &TemplateArgs); + void InstantiateVariableDefinition(SourceLocation PointOfInstantiation, + VarDecl *Var, bool Recursive = false, + bool DefinitionRequired = false); void InstantiateStaticDataMemberDefinition( SourceLocation PointOfInstantiation, VarDecl *Var, diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index a035d4fa676..4f0550f580a 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -378,6 +378,14 @@ namespace clang { ClassTemplatePartialSpecializationDecl *>, 4> OutOfLinePartialSpecs; + /// \brief A list of out-of-line variable template partial + /// specializations that will need to be instantiated after the + /// enclosing variable's instantiation is complete. + /// FIXME: Verify that this is needed. + SmallVector< + std::pair<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *>, 4> + OutOfLineVarPartialSpecs; + public: TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs) @@ -417,6 +425,7 @@ namespace clang { Decl *VisitFunctionDecl(FunctionDecl *D, TemplateParameterList *TemplateParams); Decl *VisitDecl(Decl *D); + Decl *VisitVarDecl(VarDecl *D, bool ForVarTemplate); // Enable late instantiation of attributes. Late instantiated attributes // will be stored in LA. @@ -439,6 +448,10 @@ namespace clang { ::iterator delayed_partial_spec_iterator; + typedef SmallVectorImpl<std::pair< + VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> >::iterator + delayed_var_partial_spec_iterator; + /// \brief Return an iterator to the beginning of the set of /// "delayed" partial specializations, which must be passed to /// InstantiateClassTemplatePartialSpecialization once the class @@ -447,6 +460,10 @@ namespace clang { return OutOfLinePartialSpecs.begin(); } + delayed_var_partial_spec_iterator delayed_var_partial_spec_begin() { + return OutOfLineVarPartialSpecs.begin(); + } + /// \brief Return an iterator to the end of the set of /// "delayed" partial specializations, which must be passed to /// InstantiateClassTemplatePartialSpecialization once the class @@ -455,6 +472,10 @@ namespace clang { return OutOfLinePartialSpecs.end(); } + delayed_var_partial_spec_iterator delayed_var_partial_spec_end() { + return OutOfLineVarPartialSpecs.end(); + } + // Helper functions for instantiating methods. TypeSourceInfo *SubstFunctionType(FunctionDecl *D, SmallVectorImpl<ParmVarDecl *> &Params); @@ -468,12 +489,21 @@ namespace clang { DeclaratorDecl *NewDecl); bool SubstQualifier(const TagDecl *OldDecl, TagDecl *NewDecl); - + + Decl *VisitVarTemplateSpecializationDecl( + VarTemplateDecl *VarTemplate, VarDecl *FromVar, void *InsertPos, + const TemplateArgumentListInfo &TemplateArgsInfo, + SmallVectorImpl<TemplateArgument> &Converted); + Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias); ClassTemplatePartialSpecializationDecl * InstantiateClassTemplatePartialSpecialization( ClassTemplateDecl *ClassTemplate, ClassTemplatePartialSpecializationDecl *PartialSpec); + VarTemplatePartialSpecializationDecl * + InstantiateVarTemplatePartialSpecialization( + VarTemplateDecl *VarTemplate, + VarTemplatePartialSpecializationDecl *PartialSpec); void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern); }; } diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 7b954302a18..2bd7c132013 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1027,6 +1027,12 @@ namespace clang { DECL_CLASS_TEMPLATE_SPECIALIZATION, /// \brief A ClassTemplatePartialSpecializationDecl record. DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION, + /// \brief A VarTemplateDecl record. + DECL_VAR_TEMPLATE, + /// \brief A VarTemplateSpecializationDecl record. + DECL_VAR_TEMPLATE_SPECIALIZATION, + /// \brief A VarTemplatePartialSpecializationDecl record. + DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION, /// \brief A FunctionTemplateDecl record. DECL_FUNCTION_TEMPLATE, /// \brief A TemplateTypeParmDecl record. diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index e94b685e971..6260e34382a 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -724,6 +724,9 @@ public: virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D); virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D); + virtual void + AddedCXXTemplateSpecialization(const VarTemplateDecl *TD, + const VarTemplateSpecializationDecl *D); virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, const FunctionDecl *D); virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a3718fea338..63b1b0ead18 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -1041,13 +1041,20 @@ void ASTContext::eraseDeclAttrs(const Decl *D) { } } +// FIXME: Remove ? MemberSpecializationInfo * ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) { assert(Var->isStaticDataMember() && "Not a static data member"); - llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *>::iterator Pos - = InstantiatedFromStaticDataMember.find(Var); - if (Pos == InstantiatedFromStaticDataMember.end()) - return 0; + return getTemplateOrSpecializationInfo(Var) + .dyn_cast<MemberSpecializationInfo *>(); +} + +ASTContext::TemplateOrSpecializationInfo +ASTContext::getTemplateOrSpecializationInfo(const VarDecl *Var) { + llvm::DenseMap<const VarDecl *, TemplateOrSpecializationInfo>::iterator Pos = + TemplateOrInstantiation.find(Var); + if (Pos == TemplateOrInstantiation.end()) + return TemplateOrSpecializationInfo(); return Pos->second; } @@ -1058,10 +1065,16 @@ ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, SourceLocation PointOfInstantiation) { assert(Inst->isStaticDataMember() && "Not a static data member"); assert(Tmpl->isStaticDataMember() && "Not a static data member"); - assert(!InstantiatedFromStaticDataMember[Inst] && - "Already noted what static data member was instantiated from"); - InstantiatedFromStaticDataMember[Inst] - = new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation); + setTemplateOrSpecializationInfo(Inst, new (*this) MemberSpecializationInfo( + Tmpl, TSK, PointOfInstantiation)); +} + +void +ASTContext::setTemplateOrSpecializationInfo(VarDecl *Inst, + TemplateOrSpecializationInfo TSI) { + assert(!TemplateOrInstantiation[Inst] && + "Already noted what the variable was instantiated from"); + TemplateOrInstantiation[Inst] = TSI; } FunctionDecl *ASTContext::getClassScopeSpecializationPattern( @@ -7973,20 +7986,20 @@ MangleContext *ASTContext::createMangleContext() { CXXABI::~CXXABI() {} size_t ASTContext::getSideTableAllocatedMemory() const { - return ASTRecordLayouts.getMemorySize() - + llvm::capacity_in_bytes(ObjCLayouts) - + llvm::capacity_in_bytes(KeyFunctions) - + llvm::capacity_in_bytes(ObjCImpls) - + llvm::capacity_in_bytes(BlockVarCopyInits) - + llvm::capacity_in_bytes(DeclAttrs) - + llvm::capacity_in_bytes(InstantiatedFromStaticDataMember) - + llvm::capacity_in_bytes(InstantiatedFromUsingDecl) - + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl) - + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) - + llvm::capacity_in_bytes(OverriddenMethods) - + llvm::capacity_in_bytes(Types) - + llvm::capacity_in_bytes(VariableArrayTypes) - + llvm::capacity_in_bytes(ClassScopeSpecializationPattern); + return ASTRecordLayouts.getMemorySize() + + llvm::capacity_in_bytes(ObjCLayouts) + + llvm::capacity_in_bytes(KeyFunctions) + + llvm::capacity_in_bytes(ObjCImpls) + + llvm::capacity_in_bytes(BlockVarCopyInits) + + llvm::capacity_in_bytes(DeclAttrs) + + llvm::capacity_in_bytes(TemplateOrInstantiation) + + llvm::capacity_in_bytes(InstantiatedFromUsingDecl) + + llvm::capacity_in_bytes(InstantiatedFromUsingShadowDecl) + + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl) + + llvm::capacity_in_bytes(OverriddenMethods) + + llvm::capacity_in_bytes(Types) + + llvm::capacity_in_bytes(VariableArrayTypes) + + llvm::capacity_in_bytes(ClassScopeSpecializationPattern); } void ASTContext::setManglingNumber(const NamedDecl *ND, unsigned Number) { diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index deac0c5dfbe..922172701f0 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -106,6 +106,8 @@ namespace clang { bool ImportDefinition(RecordDecl *From, RecordDecl *To, ImportDefinitionKind Kind = IDK_Default); + bool ImportDefinition(VarDecl *From, VarDecl *To, + ImportDefinitionKind Kind = IDK_Default); bool ImportDefinition(EnumDecl *From, EnumDecl *To, ImportDefinitionKind Kind = IDK_Default); bool ImportDefinition(ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, @@ -120,9 +122,12 @@ namespace clang { SmallVectorImpl<TemplateArgument> &ToArgs); bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, bool Complain = true); + bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, + bool Complain = true); bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC); bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); + bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To); Decl *VisitDecl(Decl *D); Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D); Decl *VisitNamespaceDecl(NamespaceDecl *D); @@ -157,7 +162,9 @@ namespace clang { Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); Decl *VisitClassTemplateSpecializationDecl( ClassTemplateSpecializationDecl *D); - + Decl *VisitVarTemplateDecl(VarTemplateDecl *D); + Decl *VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D); + // Importing statements Stmt *VisitStmt(Stmt *S); @@ -2017,6 +2024,21 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, return false; } +bool ASTNodeImporter::ImportDefinition(VarDecl *From, VarDecl *To, + ImportDefinitionKind Kind) { + if (To->getDefinition()) + return false; + + // FIXME: Can we really import any initializer? Alternatively, we could force + // ourselves to import every declaration of a variable and then only use + // getInit() here. + To->setInit(Importer.Import(const_cast<Expr *>(From->getAnyInitializer()))); + + // FIXME: Other bits to merge? + + return false; +} + bool ASTNodeImporter::ImportDefinition(EnumDecl *From, EnumDecl *To, ImportDefinitionKind Kind) { if (To->getDefinition() || To->isBeingDefined()) { @@ -2162,6 +2184,14 @@ bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, return Ctx.IsStructurallyEquivalent(FromRecord, ToRecord); } +bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, + bool Complain) { + StructuralEquivalenceContext Ctx( + Importer.getFromContext(), Importer.getToContext(), + Importer.getNonEquivalentDecls(), false, Complain); + return Ctx.IsStructurallyEquivalent(FromVar, ToVar); +} + bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { StructuralEquivalenceContext Ctx(Importer.getFromContext(), Importer.getToContext(), @@ -2188,6 +2218,14 @@ bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, return Ctx.IsStructurallyEquivalent(From, To); } +bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From, + VarTemplateDecl *To) { + StructuralEquivalenceContext Ctx(Importer.getFromContext(), + Importer.getToContext(), + Importer.getNonEquivalentDecls()); + return Ctx.IsStructurallyEquivalent(From, To); +} + Decl *ASTNodeImporter::VisitDecl(Decl *D) { Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) << D->getDeclKindName(); @@ -3092,13 +3130,9 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { LexicalDC->addDeclInternal(ToVar); // Merge the initializer. - // FIXME: Can we really import any initializer? Alternatively, we could force - // ourselves to import every declaration of a variable and then only use - // getInit() here. - ToVar->setInit(Importer.Import(const_cast<Expr *>(D->getAnyInitializer()))); + if (ImportDefinition(D, ToVar)) + return 0; - // FIXME: Other bits to merge? - return ToVar; } @@ -4112,6 +4146,205 @@ Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( return D2; } +Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { + // If this variable has a definition in the translation unit we're coming + // from, + // but this particular declaration is not that definition, import the + // definition and map to that. + VarDecl *Definition = + cast_or_null<VarDecl>(D->getTemplatedDecl()->getDefinition()); + if (Definition && Definition != D->getTemplatedDecl()) { + Decl *ImportedDef = Importer.Import(Definition->getDescribedVarTemplate()); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + // Import the major distinguishing characteristics of this variable template. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // We may already have a template of the same name; try to find and match it. + assert(!DC->isFunctionOrMethod() && + "Variable templates cannot be declared at function scope"); + SmallVector<NamedDecl *, 4> ConflictingDecls; + SmallVector<NamedDecl *, 2> FoundDecls; + DC->localUncachedLookup(Name, FoundDecls); + for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { + if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + continue; + + Decl *Found = FoundDecls[I]; + if (VarTemplateDecl *FoundTemplate = dyn_cast<VarTemplateDecl>(Found)) { + if (IsStructuralMatch(D, FoundTemplate)) { + // The variable templates structurally match; call it the same template. + Importer.Imported(D->getTemplatedDecl(), + FoundTemplate->getTemplatedDecl()); + return Importer.Imported(D, FoundTemplate); + } + } + + ConflictingDecls.push_back(FoundDecls[I]); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary, + ConflictingDecls.data(), + ConflictingDecls.size()); + } + + if (!Name) + return 0; + + VarDecl *DTemplated = D->getTemplatedDecl(); + + // Import the type. + QualType T = Importer.Import(DTemplated->getType()); + if (T.isNull()) + return 0; + + // Create the declaration that is being templated. + SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart()); + SourceLocation IdLoc = Importer.Import(DTemplated->getLocation()); + TypeSourceInfo *TInfo = Importer.Import(DTemplated->getTypeSourceInfo()); + VarDecl *D2Templated = VarDecl::Create(Importer.getToContext(), DC, StartLoc, + IdLoc, Name.getAsIdentifierInfo(), T, + TInfo, DTemplated->getStorageClass()); + D2Templated->setAccess(DTemplated->getAccess()); + D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc())); + D2Templated->setLexicalDeclContext(LexicalDC); + + // Importer.Imported(DTemplated, D2Templated); + // LexicalDC->addDeclInternal(D2Templated); + + // Merge the initializer. + if (ImportDefinition(DTemplated, D2Templated)) + return 0; + + // Create the variable template declaration itself. + TemplateParameterList *TemplateParams = + ImportTemplateParameterList(D->getTemplateParameters()); + if (!TemplateParams) + return 0; + + VarTemplateDecl *D2 = VarTemplateDecl::Create( + Importer.getToContext(), DC, Loc, Name, TemplateParams, D2Templated, + /*PrevDecl=*/0); + D2Templated->setDescribedVarTemplate(D2); + + D2->setAccess(D->getAccess()); + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(D2); + + // Note the relationship between the variable templates. + Importer.Imported(D, D2); + Importer.Imported(DTemplated, D2Templated); + + if (DTemplated->isThisDeclarationADefinition() && + !D2Templated->isThisDeclarationADefinition()) { + // FIXME: Import definition! + } + + return D2; +} + +Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl( + VarTemplateSpecializationDecl *D) { + // If this record has a definition in the translation unit we're coming from, + // but this particular declaration is not that definition, import the + // definition and map to that. + VarDecl *Definition = D->getDefinition(); + if (Definition && Definition != D) { + Decl *ImportedDef = Importer.Import(Definition); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + VarTemplateDecl *VarTemplate = cast_or_null<VarTemplateDecl>( + Importer.Import(D->getSpecializedTemplate())); + if (!VarTemplate) + return 0; + + // Import the context of this declaration. + DeclContext *DC = VarTemplate->getDeclContext(); + if (!DC) + return 0; + + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + } + + // Import the location of this declaration. + SourceLocation StartLoc = Importer.Import(D->getLocStart()); + SourceLocation IdLoc = Importer.Import(D->getLocation()); + + // Import template arguments. + SmallVector<TemplateArgument, 2> TemplateArgs; + if (ImportTemplateArguments(D->getTemplateArgs().data(), + D->getTemplateArgs().size(), TemplateArgs)) + return 0; + + // Try to find an existing specialization with these template arguments. + void *InsertPos = 0; + VarTemplateSpecializationDecl *D2 = VarTemplate->findSpecialization( + TemplateArgs.data(), TemplateArgs.size(), InsertPos); + if (D2) { + // We already have a variable template specialization with these template + // arguments. + + // FIXME: Check for specialization vs. instantiation errors. + + if (VarDecl *FoundDef = D2->getDefinition()) { + if (!D->isThisDeclarationADefinition() || + IsStructuralMatch(D, FoundDef)) { + // The record types structurally match, or the "from" translation + // unit only had a forward declaration anyway; call it the same + // variable. + return Importer.Imported(D, FoundDef); + } + } + } else { + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + + // Create a new specialization. + D2 = VarTemplateSpecializationDecl::Create( + Importer.getToContext(), DC, StartLoc, IdLoc, VarTemplate, T, TInfo, + D->getStorageClass(), TemplateArgs.data(), TemplateArgs.size()); + D2->setSpecializationKind(D->getSpecializationKind()); + D2->setTemplateArgsInfo(D->getTemplateArgsInfo()); + + // Add this specialization to the class template. + VarTemplate->AddSpecialization(D2, InsertPos); + + // Import the qualifier, if any. + D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); + + // Add the specialization to this context. + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(D2); + } + Importer.Imported(D, D2); + + if (D->isThisDeclarationADefinition() && ImportDefinition(D, D2)) + return 0; + + return D2; +} + //---------------------------------------------------------------------------- // Import Statements //---------------------------------------------------------------------------- diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 772f7353c36..9562879de6a 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1557,6 +1557,17 @@ const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { llvm_unreachable("Invalid storage class"); } +VarDecl::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. +} + VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartL, SourceLocation IdL, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, @@ -1952,28 +1963,63 @@ VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { } TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const { + if (const VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(this)) + return Spec->getSpecializationKind(); + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) return MSI->getTemplateSpecializationKind(); return TSK_Undeclared; } +VarTemplateDecl *VarDecl::getDescribedVarTemplate() const { + return getASTContext().getTemplateOrSpecializationInfo(this) + .dyn_cast<VarTemplateDecl *>(); +} + +void VarDecl::setDescribedVarTemplate(VarTemplateDecl *Template) { + getASTContext().setTemplateOrSpecializationInfo(this, Template); +} + MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const { if (isStaticDataMember()) - return getASTContext().getInstantiatedFromStaticDataMember(this); - + // FIXME: Remove ? + // return getASTContext().getInstantiatedFromStaticDataMember(this); + return getASTContext().getTemplateOrSpecializationInfo(this) + .dyn_cast<MemberSpecializationInfo *>(); return 0; } void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, SourceLocation PointOfInstantiation) { - MemberSpecializationInfo *MSI = getMemberSpecializationInfo(); - assert(MSI && "Not an instantiated static data member?"); - MSI->setTemplateSpecializationKind(TSK); - if (TSK != TSK_ExplicitSpecialization && - PointOfInstantiation.isValid() && - MSI->getPointOfInstantiation().isInvalid()) - MSI->setPointOfInstantiation(PointOfInstantiation); + if (VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(this)) { + Spec->setSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && + Spec->getPointOfInstantiation().isInvalid()) + Spec->setPointOfInstantiation(PointOfInstantiation); + return; + } + + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) { + MSI->setTemplateSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && PointOfInstantiation.isValid() && + MSI->getPointOfInstantiation().isInvalid()) + MSI->setPointOfInstantiation(PointOfInstantiation); + return; + } + + llvm_unreachable( + "Not a variable or static data member template specialization"); +} + +void +VarDecl::setInstantiationOfStaticDataMember(VarDecl *VD, + TemplateSpecializationKind TSK) { + assert(getASTContext().getTemplateOrSpecializationInfo(this).isNull() && + "Previous template or instantiation?"); + getASTContext().setInstantiatedFromStaticDataMember(this, VD, TSK); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 13bde4ca860..e99f7ec5b06 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -538,6 +538,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { return IDNS_Namespace; case FunctionTemplate: + case VarTemplate: return IDNS_Ordinary; case ClassTemplate: @@ -560,6 +561,8 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ClassTemplateSpecialization: case ClassTemplatePartialSpecialization: case ClassScopeFunctionSpecialization: + case VarTemplateSpecialization: + case VarTemplatePartialSpecialization: case ObjCImplementation: case ObjCCategory: case ObjCCategoryImpl: diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index ac0d54f5011..555800a8bef 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -958,3 +958,248 @@ ClassScopeFunctionSpecializationDecl::CreateDeserialized(ASTContext &C, return new (Mem) ClassScopeFunctionSpecializationDecl(0, SourceLocation(), 0, false, TemplateArgumentListInfo()); } + +//===----------------------------------------------------------------------===// +// VarTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +void VarTemplateDecl::DeallocateCommon(void *Ptr) { + static_cast<Common *>(Ptr)->~Common(); +} + +VarTemplateDecl *VarTemplateDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl, + VarTemplateDecl *PrevDecl) { + VarTemplateDecl *New = new (C) VarTemplateDecl(DC, L, Name, Params, Decl); + New->setPreviousDeclaration(PrevDecl); + return New; +} + +VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + void *Mem = AllocateDeserializedDecl(C, ID, sizeof(VarTemplateDecl)); + return new (Mem) VarTemplateDecl(EmptyShell()); +} + +// FIXME: Should this be unified accross class, function and variable +// templates? Perhaps also moved to RedeclarableTemplateDecl? +void VarTemplateDecl::LoadLazySpecializations() const { + Common *CommonPtr = getCommonPtr(); + if (CommonPtr->LazySpecializations) { + ASTContext &Context = getASTContext(); + uint32_t *Specs = CommonPtr->LazySpecializations; + CommonPtr->LazySpecializations = 0; + for (uint32_t I = 0, N = *Specs++; I != N; ++I) + (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); + } +} + +llvm::FoldingSetVector<VarTemplateSpecializationDecl> & +VarTemplateDecl::getSpecializations() const { + LoadLazySpecializations(); + return getCommonPtr()->Specializations; +} + +llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> & +VarTemplateDecl::getPartialSpecializations() { + LoadLazySpecializations(); + return getCommonPtr()->PartialSpecializations; +} + +RedeclarableTemplateDecl::CommonBase * +VarTemplateDecl::newCommon(ASTContext &C) const { + Common *CommonPtr = new (C) Common; + C.AddDeallocation(DeallocateCommon, CommonPtr); + return CommonPtr; +} + +VarTemplateSpecializationDecl * +VarTemplateDecl::findSpecialization(const TemplateArgument *Args, + unsigned NumArgs, void *&InsertPos) { + return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos); +} + +void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D, + void *InsertPos) { + if (InsertPos) + getSpecializations().InsertNode(D, InsertPos); + else { + VarTemplateSpecializationDecl *Existing = + getSpecializations().GetOrInsertNode(D); + (void)Existing; + assert(Existing->isCanonicalDecl() && "Non-canonical specialization?"); + } + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, D); +} + +VarTemplatePartialSpecializationDecl * +VarTemplateDecl::findPartialSpecialization(const TemplateArgument *Args, + unsigned NumArgs, void *&InsertPos) { + return findSpecializationImpl(getPartialSpecializations(), Args, NumArgs, + InsertPos); +} + +void VarTemplateDecl::AddPartialSpecialization( + VarTemplatePartialSpecializationDecl *D, void *InsertPos) { + if (InsertPos) + getPartialSpecializations().InsertNode(D, InsertPos); + else { + VarTemplatePartialSpecializationDecl *Existing = + getPartialSpecializations().GetOrInsertNode(D); + (void)Existing; + assert(Existing->isCanonicalDecl() && "Non-canonical specialization?"); + } + + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, D); +} + +void VarTemplateDecl::getPartialSpecializations( + SmallVectorImpl<VarTemplatePartialSpecializationDecl *> &PS) { + llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> &PartialSpecs = + getPartialSpecializations(); + PS.clear(); + PS.resize(PartialSpecs.size()); + for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator + P = PartialSpecs.begin(), + PEnd = PartialSpecs.end(); + P != PEnd; ++P) { + assert(!PS[P->getSequenceNumber()]); + PS[P->getSequenceNumber()] = P->getMostRecentDecl(); + } +} + +VarTemplatePartialSpecializationDecl * +VarTemplateDecl::findPartialSpecInstantiatedFromMember( + VarTemplatePartialSpecializationDecl *D) { + Decl *DCanon = D->getCanonicalDecl(); + for (llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl>::iterator + P = getPartialSpecializations().begin(), + PEnd = getPartialSpecializations().end(); + P != PEnd; ++P) { + if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) + return P->getMostRecentDecl(); + } + + return 0; +} + +//===----------------------------------------------------------------------===// +// VarTemplateSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +VarTemplateSpecializationDecl::VarTemplateSpecializationDecl( + ASTContext &Context, Kind DK, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T, + TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args, + unsigned NumArgs) + : VarDecl(DK, DC, StartLoc, IdLoc, SpecializedTemplate->getIdentifier(), T, + TInfo, S), + SpecializedTemplate(SpecializedTemplate), ExplicitInfo(0), + TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args, NumArgs)), + SpecializationKind(TSK_Undeclared) {} + +VarTemplateSpecializationDecl::VarTemplateSpecializationDecl(Kind DK) + : VarDecl(DK, 0, SourceLocation(), SourceLocation(), 0, QualType(), 0, + SC_None), + ExplicitInfo(0), SpecializationKind(TSK_Undeclared) {} + +VarTemplateSpecializationDecl *VarTemplateSpecializationDecl::Create( + ASTContext &Context, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, VarTemplateDecl *SpecializedTemplate, QualType T, + TypeSourceInfo *TInfo, StorageClass S, const TemplateArgument *Args, + unsigned NumArgs) { + VarTemplateSpecializationDecl *Result = new (Context) + VarTemplateSpecializationDecl(Context, VarTemplateSpecialization, DC, + StartLoc, IdLoc, SpecializedTemplate, T, + TInfo, S, Args, NumArgs); + return Result; +} + +VarTemplateSpecializationDecl * +VarTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, unsigned ID) { + void *Mem = + AllocateDeserializedDecl(C, ID, sizeof(VarTemplateSpecializationDecl)); + VarTemplateSpecializationDecl *Result = + new (Mem) VarTemplateSpecializationDecl(VarTemplateSpecialization); + return Result; +} + +void VarTemplateSpecializationDecl::getNameForDiagnostic( + raw_ostream &OS, const PrintingPolicy &Policy, bool Qualified) const { + NamedDecl::getNameForDiagnostic(OS, Policy, Qualified); + + const TemplateArgumentList &TemplateArgs = getTemplateArgs(); + TemplateSpecializationType::PrintTemplateArgumentList( + OS, TemplateArgs.data(), TemplateArgs.size(), Policy); +} + +VarTemplateDecl *VarTemplateSpecializationDecl::getSpecializedTemplate() const { + if (SpecializedPartialSpecialization *PartialSpec = + SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization *>()) + return PartialSpec->PartialSpecialization->getSpecializedTemplate(); + return SpecializedTemplate.get<VarTemplateDecl *>(); +} + +void VarTemplateSpecializationDecl::setTemplateArgsInfo( + const TemplateArgumentListInfo &ArgsInfo) { + unsigned N = ArgsInfo.size(); + TemplateArgsInfo.setLAngleLoc(ArgsInfo.getLAngleLoc()); + TemplateArgsInfo.setRAngleLoc(ArgsInfo.getRAngleLoc()); + for (unsigned I = 0; I != N; ++I) + TemplateArgsInfo.addArgument(ArgsInfo[I]); +} + +//===----------------------------------------------------------------------===// +// VarTemplatePartialSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +void VarTemplatePartialSpecializationDecl::anchor() {} + +VarTemplatePartialSpecializationDecl::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) + : VarTemplateSpecializationDecl(Context, VarTemplatePartialSpecialization, + DC, StartLoc, IdLoc, SpecializedTemplate, T, + TInfo, S, Args, NumArgs), + TemplateParams(Params), ArgsAsWritten(ArgInfos), + NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber), + InstantiatedFromMember(0, false) { + // TODO: The template parameters should be in DC by now. Verify. + // AdoptTemplateParameterList(Params, DC); +} + +VarTemplatePartialSpecializationDecl * +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) { + unsigned N = ArgInfos.size(); + TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N]; + for (unsigned I = 0; I != N; ++I) + ClonedArgs[I] = ArgInfos[I]; + + VarTemplatePartialSpecializationDecl *Result = + new (Context) VarTemplatePartialSpecializationDecl( + Context, DC, StartLoc, IdLoc, Params, SpecializedTemplate, T, TInfo, + S, Args, NumArgs, ClonedArgs, N, SequenceNumber); + Result->setSpecializationKind(TSK_ExplicitSpecialization); + return Result; +} + +VarTemplatePartialSpecializationDecl * +VarTemplatePartialSpecializationDecl::CreateDeserialized(ASTContext &C, + unsigned ID) { + void *Mem = AllocateDeserializedDecl( + C, ID, sizeof(VarTemplatePartialSpecializationDecl)); + VarTemplatePartialSpecializationDecl *Result = + new (Mem) VarTemplatePartialSpecializationDecl(); + return Result; +} diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 9bce9a0fa3b..ac551d8695b 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -432,7 +432,8 @@ bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) { if (DC->isFunctionOrMethod() && D->hasLinkage()) while (!DC->isNamespace() && !DC->isTranslationUnit()) DC = getEffectiveParentContext(DC); - if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage) + if (DC->isTranslationUnit() && D->getFormalLinkage() != InternalLinkage && + !isa<VarTemplateSpecializationDecl>(D)) return false; } @@ -554,6 +555,13 @@ isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { return Spec->getSpecializedTemplate(); } + // Check if we have a variable template. + if (const VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(ND)) { + TemplateArgs = &Spec->getTemplateArgs(); + return Spec->getSpecializedTemplate(); + } + return 0; } diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 49364e6b563..970f9781b78 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -37,6 +37,8 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::UnresolvedUsingTypename: case Decl::ClassTemplateSpecialization: case Decl::ClassTemplatePartialSpecialization: + case Decl::VarTemplateSpecialization: + case Decl::VarTemplatePartialSpecialization: case Decl::TemplateTypeParm: case Decl::UnresolvedUsingValue: case Decl::NonTypeTemplateParm: @@ -52,6 +54,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::ParmVar: case Decl::ImplicitParam: case Decl::ClassTemplate: + case Decl::VarTemplate: case Decl::FunctionTemplate: case Decl::TypeAliasTemplate: case Decl::TemplateTemplateParm: diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 21edc7e6513..dbdf016b31b 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2841,8 +2841,12 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { EmitGlobal(cast<FunctionDecl>(D)); break; - + case Decl::Var: + // Skip variable templates + if (cast<VarDecl>(D)->getDescribedVarTemplate()) + return; + case Decl::VarTemplateSpecialization: EmitGlobal(cast<VarDecl>(D)); break; @@ -2859,6 +2863,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::UsingShadow: case Decl::Using: case Decl::ClassTemplate: + case Decl::VarTemplate: + case Decl::VarTemplatePartialSpecialization: case Decl::FunctionTemplate: case Decl::TypeAliasTemplate: case Decl::Block: diff --git a/clang/lib/Frontend/MultiplexConsumer.cpp b/clang/lib/Frontend/MultiplexConsumer.cpp index 7ed9d36ca3b..f8ee36a50dc 100644 --- a/clang/lib/Frontend/MultiplexConsumer.cpp +++ b/clang/lib/Frontend/MultiplexConsumer.cpp @@ -94,6 +94,9 @@ public: virtual void AddedCXXImplicitMember(const CXXRecordDecl *RD, const Decl *D); virtual void AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, const ClassTemplateSpecializationDecl *D); + virtual void + AddedCXXTemplateSpecialization(const VarTemplateDecl *TD, + const VarTemplateSpecializationDecl *D); virtual void AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, const FunctionDecl *D); virtual void DeducedReturnType(const FunctionDecl *FD, QualType ReturnType); @@ -135,6 +138,11 @@ void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( Listeners[i]->AddedCXXTemplateSpecialization(TD, D); } void MultiplexASTMutationListener::AddedCXXTemplateSpecialization( + const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) { + 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); diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index e04685cfa4d..9f832e5195e 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -55,11 +55,11 @@ NamedDecl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, TemplateParams, 0, VS, ICIS_NoInit); if (FnD) { - Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, - false, true); + Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, false, + true); bool TypeSpecContainsAuto = D.getDeclSpec().containsPlaceholderType(); if (Init.isUsable()) - Actions.AddInitializerToDecl(FnD, Init.get(), false, + Actions.AddInitializerToDecl(FnD, Init.get(), false, TypeSpecContainsAuto); else Actions.ActOnUninitializedDecl(FnD, TypeSpecContainsAuto); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 0b276d0b58f..80fab62f41e 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1797,24 +1797,69 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, break; case ParsedTemplateInfo::Template: - case ParsedTemplateInfo::ExplicitSpecialization: + case ParsedTemplateInfo::ExplicitSpecialization: { ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(), *TemplateInfo.TemplateParams, D); - break; - case ParsedTemplateInfo::ExplicitInstantiation: { - DeclResult ThisRes - = Actions.ActOnExplicitInstantiation(getCurScope(), - TemplateInfo.ExternLoc, - TemplateInfo.TemplateLoc, - D); - if (ThisRes.isInvalid()) { + // If this is a forward declaration of a variable template or variable + // template partial specialization with nested name specifier, complain. + // FIXME: Move to Sema. + CXXScopeSpec &SS = D.getCXXScopeSpec(); + if (Tok.is(tok::semi) && ThisDecl && SS.isNotEmpty() && + (isa<VarTemplateDecl>(ThisDecl) || + isa<VarTemplatePartialSpecializationDecl>(ThisDecl))) { + Diag(SS.getBeginLoc(), diag::err_forward_var_nested_name_specifier) + << isa<VarTemplatePartialSpecializationDecl>(ThisDecl) + << SS.getRange(); SkipUntil(tok::semi, true, true); return 0; } - ThisDecl = ThisRes.get(); + if (VarTemplateDecl *VT = + ThisDecl ? dyn_cast<VarTemplateDecl>(ThisDecl) : 0) + // Re-direct this decl to refer to the templated decl so that we can + // initialize it. + ThisDecl = VT->getTemplatedDecl(); + break; + } + case ParsedTemplateInfo::ExplicitInstantiation: { + if (Tok.is(tok::semi)) { + DeclResult ThisRes = Actions.ActOnExplicitInstantiation( + getCurScope(), TemplateInfo.ExternLoc, TemplateInfo.TemplateLoc, D); + if (ThisRes.isInvalid()) { + SkipUntil(tok::semi, true, true); + return 0; + } + ThisDecl = ThisRes.get(); + } else { + // FIXME: This check should be for a variable template instantiation only. + + // Check that this is a valid instantiation + if (D.getName().getKind() != UnqualifiedId::IK_TemplateId) { + // If the declarator-id is not a template-id, issue a diagnostic and + // recover by ignoring the 'template' keyword. + Diag(Tok, diag::err_template_defn_explicit_instantiation) + << 2 << FixItHint::CreateRemoval(TemplateInfo.TemplateLoc); + ThisDecl = Actions.ActOnDeclarator(getCurScope(), D); + } else { + SourceLocation LAngleLoc = + PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); + Diag(D.getIdentifierLoc(), + diag::err_explicit_instantiation_with_definition) + << SourceRange(TemplateInfo.TemplateLoc) + << FixItHint::CreateInsertion(LAngleLoc, "<>"); + + // Recover as if it were an explicit specialization. + TemplateParameterLists FakedParamLists; + FakedParamLists.push_back(Actions.ActOnTemplateParameterList( + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0, + LAngleLoc)); + + ThisDecl = + Actions.ActOnTemplateDeclarator(getCurScope(), FakedParamLists, D); + } + } break; } } @@ -1825,6 +1870,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, // If a '==' or '+=' is found, suggest a fixit to '='. if (isTokenEqualOrEqualTypo()) { ConsumeToken(); + if (Tok.is(tok::kw_delete)) { if (D.isFunctionDeclarator()) Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 8df15ba75df..e62be697893 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -15,6 +15,7 @@ #include "RAIIObjectsForParser.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/OperatorKinds.h" +#include "clang/AST/DeclTemplate.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" @@ -2264,6 +2265,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, TemplateParams, BitfieldSize.release(), VS, HasInClassInit); + + if (VarTemplateDecl *VT = + ThisDecl ? dyn_cast<VarTemplateDecl>(ThisDecl) : 0) + // Re-direct this decl to refer to the templated decl so that we can + // initialize it. + ThisDecl = VT->getTemplatedDecl(); + if (ThisDecl && AccessAttrs) Actions.ProcessDeclAttributeList(getCurScope(), ThisDecl, AccessAttrs, false, true); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 9704b98d48e..d4a83fb0c9c 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -465,8 +465,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, TemplateName, false)) return true; continue; - } - + } + if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && (IsTypename || IsTemplateArgumentList(1))) { // We have something like t::getAs<T>, where getAs is a @@ -561,6 +561,12 @@ ExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) { // '::' unqualified-id // CXXScopeSpec SS; + if (Tok.getKind() == tok::annot_template_id) { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + // FIXME: This is a hack for now. It may need to be done from within + // ParseUnqualifiedId(), or most likely ParseOptionalCXXScopeSpecifier(); + SS = TemplateId->SS; + } ParseOptionalCXXScopeSpecifier(SS, ParsedType(), /*EnteringContext=*/false); SourceLocation TemplateKWLoc; diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index d8ad2597115..fa23bd1face 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -242,32 +242,31 @@ Parser::ParseSingleDeclarationAfterTemplate( // If the declarator-id is not a template-id, issue a diagnostic and // recover by ignoring the 'template' keyword. Diag(Tok, diag::err_template_defn_explicit_instantiation) << 0; - return ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo(), - &LateParsedAttrs); + return ParseFunctionDefinition(DeclaratorInfo, ParsedTemplateInfo(), + &LateParsedAttrs); } else { SourceLocation LAngleLoc = PP.getLocForEndOfToken(TemplateInfo.TemplateLoc); - Diag(DeclaratorInfo.getIdentifierLoc(), + Diag(DeclaratorInfo.getIdentifierLoc(), diag::err_explicit_instantiation_with_definition) - << SourceRange(TemplateInfo.TemplateLoc) - << FixItHint::CreateInsertion(LAngleLoc, "<>"); + << SourceRange(TemplateInfo.TemplateLoc) + << FixItHint::CreateInsertion(LAngleLoc, "<>"); - // Recover as if it were an explicit specialization. + // Recover as if it were an explicit specialization. TemplateParameterLists FakedParamLists; - FakedParamLists.push_back( - Actions.ActOnTemplateParameterList(0, SourceLocation(), - TemplateInfo.TemplateLoc, - LAngleLoc, 0, 0, LAngleLoc)); - - return ParseFunctionDefinition(DeclaratorInfo, - ParsedTemplateInfo(&FakedParamLists, - /*isSpecialization=*/true, - /*LastParamListWasEmpty=*/true), - &LateParsedAttrs); + FakedParamLists.push_back(Actions.ActOnTemplateParameterList( + 0, SourceLocation(), TemplateInfo.TemplateLoc, LAngleLoc, 0, 0, + LAngleLoc)); + + return ParseFunctionDefinition( + DeclaratorInfo, ParsedTemplateInfo(&FakedParamLists, + /*isSpecialization=*/true, + /*LastParamListWasEmpty=*/true), + &LateParsedAttrs); } } return ParseFunctionDefinition(DeclaratorInfo, TemplateInfo, - &LateParsedAttrs); + &LateParsedAttrs); } // Parse this declaration. diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 036278f72ed..8f894818bb4 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1437,8 +1437,9 @@ Parser::TryAnnotateName(bool IsAddressOfOperand, return ANK_TemplateName; } // Fall through. + case Sema::NC_VarTemplate: case Sema::NC_FunctionTemplate: { - // We have a type or function template followed by '<'. + // We have a type, variable or function template followed by '<'. ConsumeToken(); UnqualifiedId Id; Id.setIdentifier(Name, NameLoc); @@ -1653,7 +1654,8 @@ bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext, // annotation token to a type annotation token now. AnnotateTemplateIdTokenAsType(); return false; - } + } else if (TemplateId->Kind == TNK_Var_template) + return false; } if (SS.isEmpty()) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index aca71b05928..80ac1167ffa 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -799,6 +799,7 @@ Corrected: if (!Result.empty()) { bool IsFunctionTemplate; + bool IsVarTemplate; TemplateName Template; if (Result.end() - Result.begin() > 1) { IsFunctionTemplate = true; @@ -808,7 +809,8 @@ Corrected: TemplateDecl *TD = cast<TemplateDecl>((*Result.begin())->getUnderlyingDecl()); IsFunctionTemplate = isa<FunctionTemplateDecl>(TD); - + IsVarTemplate = isa<VarTemplateDecl>(TD); + if (SS.isSet() && !SS.isInvalid()) Template = Context.getQualifiedTemplateName(SS.getScopeRep(), /*TemplateKeyword=*/false, @@ -825,8 +827,9 @@ Corrected: return NameClassification::FunctionTemplate(Template); } - - return NameClassification::TypeTemplate(Template); + + return IsVarTemplate ? NameClassification::VarTemplate(Template) + : NameClassification::TypeTemplate(Template); } } @@ -3013,8 +3016,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous, if (getLangOpts().CPlusPlus && New->isThisDeclarationADefinition() == VarDecl::Definition && (Def = Old->getDefinition())) { - Diag(New->getLocation(), diag::err_redefinition) - << New->getDeclName(); + Diag(New->getLocation(), diag::err_redefinition) << New; Diag(Def->getLocation(), diag::note_previous_definition); New->setInvalidDecl(); return; @@ -4258,8 +4260,8 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, TemplateParamLists, AddToScope); } else { - New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, - TemplateParamLists); + New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, TemplateParamLists, + AddToScope); } if (New == 0) @@ -4768,10 +4770,11 @@ static bool shouldConsiderLinkage(const FunctionDecl *FD) { llvm_unreachable("Unexpected context"); } -NamedDecl* +NamedDecl * Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists) { + MultiTemplateParamsArg TemplateParamLists, + bool &AddToScope) { QualType R = TInfo->getType(); DeclarationName Name = GetNameForDeclarator(D).getName(); @@ -4862,7 +4865,12 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - bool isExplicitSpecialization = false; + bool IsExplicitSpecialization = false; + bool IsVariableTemplateSpecialization = false; + bool IsPartialSpecialization = false; + bool Invalid = false; // TODO: Can we remove this (error-prone)? + TemplateParameterList *TemplateParams = 0; + VarTemplateDecl *PrevVarTemplate = 0; VarDecl *NewVD; if (!getLangOpts().CPlusPlus) { NewVD = VarDecl::Create(Context, DC, D.getLocStart(), @@ -4922,23 +4930,20 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } + NamedDecl *PrevDecl = 0; + if (Previous.begin() != Previous.end()) + PrevDecl = (*Previous.begin())->getUnderlyingDecl(); + PrevVarTemplate = dyn_cast_or_null<VarTemplateDecl>(PrevDecl); + // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. - isExplicitSpecialization = false; - bool Invalid = false; - if (TemplateParameterList *TemplateParams = - MatchTemplateParametersToScopeSpecifier( - D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), - D.getCXXScopeSpec(), TemplateParamLists, - /*never a friend*/ false, isExplicitSpecialization, Invalid)) { - if (TemplateParams->size() > 0) { - // There is no such thing as a variable template. - Diag(D.getIdentifierLoc(), diag::err_template_variable) - << II - << SourceRange(TemplateParams->getTemplateLoc(), - TemplateParams->getRAngleLoc()); - return 0; - } else { + TemplateParams = MatchTemplateParametersToScopeSpecifier( + D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), + D.getCXXScopeSpec(), TemplateParamLists, + /*never a friend*/ false, IsExplicitSpecialization, Invalid); + if (TemplateParams) { + if (!TemplateParams->size() && + D.getName().getKind() != UnqualifiedId::IK_TemplateId) { // There is an extraneous 'template<>' for this variable. Complain // about it, but allow the declaration of the variable. Diag(TemplateParams->getTemplateLoc(), @@ -4946,12 +4951,116 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, << II << SourceRange(TemplateParams->getTemplateLoc(), TemplateParams->getRAngleLoc()); + } else { + // Only C++1y supports variable templates (N3651). + Diag(D.getIdentifierLoc(), + getLangOpts().CPlusPlus1y + ? diag::warn_cxx11_compat_variable_template + : diag::ext_variable_template); + + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + // This is an explicit specialization or a partial specialization. + // Check that we can declare a specialization here + + IsVariableTemplateSpecialization = true; + IsPartialSpecialization = TemplateParams->size() > 0; + + } else { // if (TemplateParams->size() > 0) + // This is a template declaration. + + // Check that we can declare a template here. + if (CheckTemplateDeclScope(S, TemplateParams)) + return 0; + + // If there is a previous declaration with the same name, check + // whether this is a valid redeclaration. + if (PrevDecl && !isDeclInScope(PrevDecl, DC, S)) + PrevDecl = PrevVarTemplate = 0; + + if (PrevVarTemplate) { + // Ensure that the template parameter lists are compatible. + if (!TemplateParameterListsAreEqual( + TemplateParams, PrevVarTemplate->getTemplateParameters(), + /*Complain=*/true, TPL_TemplateMatch)) + return 0; + } else if (PrevDecl && PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); + + // Just pretend that we didn't see the previous declaration. + PrevDecl = 0; + } else if (PrevDecl) { + // C++ [temp]p5: + // ... a template name declared in namespace scope or in class + // scope shall be unique in that scope. + Diag(D.getIdentifierLoc(), diag::err_redefinition_different_kind) + << Name; + Diag(PrevDecl->getLocation(), diag::note_previous_definition); + return 0; + } + + // Check the template parameter list of this declaration, possibly + // merging in the template parameter list from the previous variable + // template declaration. + if (CheckTemplateParameterList( + TemplateParams, + PrevVarTemplate ? PrevVarTemplate->getTemplateParameters() + : 0, + (D.getCXXScopeSpec().isSet() && DC && DC->isRecord() && + DC->isDependentContext()) + ? TPC_ClassTemplateMember + : TPC_VarTemplate)) + Invalid = true; + + if (D.getCXXScopeSpec().isSet()) { + // If the name of the template was qualified, we must be defining + // the template out-of-line. + if (!D.getCXXScopeSpec().isInvalid() && !Invalid && + !PrevVarTemplate) { + Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match) + << Name << DC << D.getCXXScopeSpec().getRange(); + Invalid = true; + } + } + } } + } else if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; + + // We have encountered something that the user meant to be a + // specialization (because it has explicitly-specified template + // arguments) but that was not introduced with a "template<>" (or had + // too few of them). + // FIXME: Differentiate between attempts for explicit instantiations + // (starting with "template") and the rest. + Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) + << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) + << FixItHint::CreateInsertion(D.getDeclSpec().getLocStart(), + "template<> "); + IsVariableTemplateSpecialization = true; } - NewVD = VarDecl::Create(Context, DC, D.getLocStart(), - D.getIdentifierLoc(), II, - R, TInfo, SC); + if (IsVariableTemplateSpecialization) { + if (!PrevVarTemplate) { + Diag(D.getIdentifierLoc(), diag::err_var_spec_no_template) + << IsPartialSpecialization; + return 0; + } + + SourceLocation TemplateKWLoc = + TemplateParamLists.size() > 0 + ? TemplateParamLists[0]->getTemplateLoc() + : SourceLocation(); + DeclResult Res = ActOnVarTemplateSpecialization( + S, PrevVarTemplate, D, TInfo, TemplateKWLoc, TemplateParams, SC, + IsPartialSpecialization); + if (Res.isInvalid()) + return 0; + NewVD = cast<VarDecl>(Res.get()); + AddToScope = false; + } else + NewVD = VarDecl::Create(Context, DC, D.getLocStart(), + D.getIdentifierLoc(), II, R, TInfo, SC); // If this decl has an auto type in need of deduction, make a note of the // Decl so we can diagnose uses of it in its own initializer. @@ -4963,7 +5072,14 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, SetNestedNameSpecifier(NewVD, D); - if (TemplateParamLists.size() > 0 && D.getCXXScopeSpec().isSet()) { + // FIXME: Do we need D.getCXXScopeSpec().isSet()? + if (TemplateParams && TemplateParamLists.size() > 1 && + (!IsVariableTemplateSpecialization || D.getCXXScopeSpec().isSet())) { + NewVD->setTemplateParameterListsInfo( + Context, TemplateParamLists.size() - 1, TemplateParamLists.data()); + } else if (IsVariableTemplateSpecialization || + (!TemplateParams && TemplateParamLists.size() > 0 && + (D.getCXXScopeSpec().isSet()))) { NewVD->setTemplateParameterListsInfo(Context, TemplateParamLists.size(), TemplateParamLists.data()); @@ -5020,7 +5136,12 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } if (D.getDeclSpec().isModulePrivateSpecified()) { - if (isExplicitSpecialization) + if (IsVariableTemplateSpecialization) + Diag(NewVD->getLocation(), diag::err_module_private_specialization) + << (IsPartialSpecialization ? 1 : 0) + << FixItHint::CreateRemoval( + D.getDeclSpec().getModulePrivateSpecLoc()); + else if (IsExplicitSpecialization) Diag(NewVD->getLocation(), diag::err_module_private_specialization) << 2 << FixItHint::CreateRemoval(D.getDeclSpec().getModulePrivateSpecLoc()); @@ -5089,15 +5210,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // Diagnose shadowed variables before filtering for scope. + // FIXME: Special treatment for static variable template members (?). if (!D.getCXXScopeSpec().isSet()) CheckShadow(S, NewVD, Previous); // Don't consider existing declarations that are in a different // scope and are out-of-semantic-context declarations (if the new // declaration has linkage). - FilterLookupForScope(Previous, DC, S, shouldConsiderLinkage(NewVD), - isExplicitSpecialization); - + FilterLookupForScope( + Previous, DC, S, shouldConsiderLinkage(NewVD), + IsExplicitSpecialization || IsVariableTemplateSpecialization); + if (!getLangOpts().CPlusPlus) { D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); } else { @@ -5121,10 +5244,19 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewVD->setInvalidDecl(); } - D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); + if (!IsVariableTemplateSpecialization) { + if (PrevVarTemplate) { + LookupResult PrevDecl(*this, GetNameForDeclarator(D), + LookupOrdinaryName, ForRedeclaration); + PrevDecl.addDecl(PrevVarTemplate->getTemplatedDecl()); + D.setRedeclaration(CheckVariableDeclaration(NewVD, PrevDecl)); + } else + D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); + } // This is an explicit specialization of a static data member. Check it. - if (isExplicitSpecialization && !NewVD->isInvalidDecl() && + // FIXME: Special treatment for static variable template members (?). + if (IsExplicitSpecialization && !NewVD->isInvalidDecl() && CheckMemberSpecialization(NewVD, Previous)) NewVD->setInvalidDecl(); } @@ -5147,7 +5279,45 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - return NewVD; + // If this is not a variable template, return it now + if (!TemplateParams || IsVariableTemplateSpecialization) + return NewVD; + + // If this is supposed to be a variable template, create it as such. + VarTemplateDecl *NewTemplate = + VarTemplateDecl::Create(Context, DC, D.getIdentifierLoc(), Name, + TemplateParams, NewVD, PrevVarTemplate); + NewVD->setDescribedVarTemplate(NewTemplate); + + if (D.getDeclSpec().isModulePrivateSpecified()) + NewTemplate->setModulePrivate(); + + // If we are providing an explicit specialization of a static variable + // template, make a note of that. + if (PrevVarTemplate && PrevVarTemplate->getInstantiatedFromMemberTemplate()) + NewTemplate->setMemberSpecialization(); + + // Set the lexical context of this template + NewTemplate->setLexicalDeclContext(CurContext); + if (NewVD->isStaticDataMember() && NewVD->isOutOfLine()) + NewTemplate->setAccess(NewVD->getAccess()); + + if (PrevVarTemplate) + mergeDeclAttributes(NewVD, PrevVarTemplate->getTemplatedDecl()); + + AddPushedVisibilityAttribute(NewVD); + + PushOnScopeChains(NewTemplate, S); + AddToScope = false; + + if (Invalid) { + NewTemplate->setInvalidDecl(); + NewVD->setInvalidDecl(); + } + + ActOnDocumentableDecl(NewTemplate); + + return NewTemplate; } /// \brief Diagnose variable or built-in function shadowing. Implements @@ -6705,6 +6875,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // specialization (because it has explicitly-specified template // arguments) but that was not introduced with a "template<>" (or had // too few of them). + // FIXME: Differentiate between attempts for explicit instantiations + // (starting with "template") and the rest. Diag(D.getIdentifierLoc(), diag::err_template_spec_needs_header) << SourceRange(TemplateId->LAngleLoc, TemplateId->RAngleLoc) << FixItHint::CreateInsertion( @@ -7666,7 +7838,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, RealDecl->setInvalidDecl(); return; } - ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init); // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 3df0472df6b..bd8b566769c 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2001,10 +2001,12 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Member->setAccess(AS); - // If we have declared a member function template, set the access of the - // templated declaration as well. + // If we have declared a member function template or static data member + // template, set the access of the templated declaration as well. if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Member)) FunTmpl->getTemplatedDecl()->setAccess(AS); + else if (VarTemplateDecl *VarTmpl = dyn_cast<VarTemplateDecl>(Member)) + VarTmpl->getTemplatedDecl()->setAccess(AS); } if (VS.isOverrideSpecified()) diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 8d370ce9063..8038a4502ab 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1559,7 +1559,8 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, ExprResult Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, - const CXXScopeSpec *SS, NamedDecl *FoundD) { + const CXXScopeSpec *SS, NamedDecl *FoundD, + const TemplateArgumentListInfo *TemplateArgs) { if (getLangOpts().CUDA) if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) if (const FunctionDecl *Callee = dyn_cast<FunctionDecl>(D)) { @@ -1578,12 +1579,24 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, (CurContext != D->getDeclContext() && D->getDeclContext()->isFunctionOrMethod()); - DeclRefExpr *E = DeclRefExpr::Create(Context, - SS ? SS->getWithLocInContext(Context) - : NestedNameSpecifierLoc(), - SourceLocation(), - D, refersToEnclosingScope, - NameInfo, Ty, VK, FoundD); + DeclRefExpr *E; + if (isa<VarTemplateSpecializationDecl>(D)) { + VarTemplateSpecializationDecl *VarSpec = + cast<VarTemplateSpecializationDecl>(D); + + E = DeclRefExpr::Create( + Context, + SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(), + VarSpec->getTemplateKeywordLoc(), D, refersToEnclosingScope, + NameInfo.getLoc(), Ty, VK, FoundD, TemplateArgs); + } else { + assert(!TemplateArgs && "No template arguments for non-variable" + " template specialization referrences"); + E = DeclRefExpr::Create( + Context, + SS ? SS->getWithLocInContext(Context) : NestedNameSpecifierLoc(), + SourceLocation(), D, refersToEnclosingScope, NameInfo, Ty, VK, FoundD); + } MarkDeclRefReferenced(E); @@ -1870,7 +1883,6 @@ ExprResult Sema::ActOnIdExpression(Scope *S, bool IsInlineAsmIdentifier) { assert(!(IsAddressOfOperand && HasTrailingLParen) && "cannot be direct & operand and have a trailing lparen"); - if (SS.isInvalid()) return ExprError(); @@ -1961,6 +1973,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, bool ADL = UseArgumentDependentLookup(SS, R, HasTrailingLParen); if (R.empty() && !ADL) { + // Otherwise, this could be an implicitly declared function reference (legal // in C90, extension in C99, forbidden in C++). if (HasTrailingLParen && II && !getLangOpts().CPlusPlus) { @@ -2056,8 +2069,19 @@ ExprResult Sema::ActOnIdExpression(Scope *S, R, TemplateArgs); } - if (TemplateArgs || TemplateKWLoc.isValid()) + if (TemplateArgs || TemplateKWLoc.isValid()) { + + // In C++1y, if this is a variable template id, then check it + // in BuildTemplateIdExpr(). + // The single lookup result must be a variable template declaration. + if (Id.getKind() == UnqualifiedId::IK_TemplateId && Id.TemplateId && + Id.TemplateId->Kind == TNK_Var_template) { + assert(R.getAsSingle<VarTemplateDecl>() && + "There should only be one declaration found."); + } + return BuildTemplateIdExpr(SS, TemplateKWLoc, R, ADL, TemplateArgs); + } return BuildDeclarationNameExpr(SS, R, ADL); } @@ -2524,10 +2548,9 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, } /// \brief Complete semantic analysis for a reference to the given declaration. -ExprResult -Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, - const DeclarationNameInfo &NameInfo, - NamedDecl *D, NamedDecl *FoundD) { +ExprResult Sema::BuildDeclarationNameExpr( + const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D, + NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs) { assert(D && "Cannot refer to a NULL declaration"); assert(!isa<FunctionTemplateDecl>(D) && "Cannot refer unambiguously to a function template"); @@ -2539,8 +2562,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, if (TemplateDecl *Template = dyn_cast<TemplateDecl>(D)) { // Specifically diagnose references to class templates that are missing // a template argument list. - Diag(Loc, diag::err_template_decl_ref) - << Template << SS.getRange(); + Diag(Loc, diag::err_template_decl_ref) << (isa<VarTemplateDecl>(D) ? 1 : 0) + << Template << SS.getRange(); Diag(Template->getLocation(), diag::note_template_decl_here); return ExprError(); } @@ -2630,6 +2653,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, } case Decl::Var: + case Decl::VarTemplateSpecialization: + case Decl::VarTemplatePartialSpecialization: // In C, "extern void blah;" is valid and is an r-value. if (!getLangOpts().CPlusPlus && !type.hasQualifiers() && @@ -2727,7 +2752,8 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, break; } - return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD); + return BuildDeclRefExpr(VD, type, valueKind, NameInfo, &SS, FoundD, + TemplateArgs); } } @@ -11690,28 +11716,64 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, if (!IsPotentiallyEvaluatedContext(SemaRef)) return; - // Implicit instantiation of static data members of class templates. - if (Var->isStaticDataMember() && Var->getInstantiatedFromStaticDataMember()) { + VarTemplateSpecializationDecl *VarSpec = + dyn_cast<VarTemplateSpecializationDecl>(Var); + + // Implicit instantiation of static data members, static data member + // templates of class templates, and variable template specializations. + // Delay instantiations of variable templates, except for those + // that could be used in a constant expression. + if (VarSpec || (Var->isStaticDataMember() && + Var->getInstantiatedFromStaticDataMember())) { MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo(); - assert(MSInfo && "Missing member specialization information?"); - bool AlreadyInstantiated = !MSInfo->getPointOfInstantiation().isInvalid(); - if (MSInfo->getTemplateSpecializationKind() == TSK_ImplicitInstantiation && - (!AlreadyInstantiated || - Var->isUsableInConstantExpressions(SemaRef.Context))) { - if (!AlreadyInstantiated) { - // This is a modification of an existing AST node. Notify listeners. - if (ASTMutationListener *L = SemaRef.getASTMutationListener()) - L->StaticDataMemberInstantiated(Var); - MSInfo->setPointOfInstantiation(Loc); + if (VarSpec) + assert(!isa<VarTemplatePartialSpecializationDecl>(Var) && + "Can't instantiate a partial template specialization."); + if (Var->isStaticDataMember()) + assert(MSInfo && "Missing member specialization information?"); + + SourceLocation PointOfInstantiation; + bool InstantiationIsOkay = true; + if (MSInfo) { + bool AlreadyInstantiated = !MSInfo->getPointOfInstantiation().isInvalid(); + TemplateSpecializationKind TSK = MSInfo->getTemplateSpecializationKind(); + + if (TSK == TSK_ImplicitInstantiation && + (!AlreadyInstantiated || + Var->isUsableInConstantExpressions(SemaRef.Context))) { + if (!AlreadyInstantiated) { + // This is a modification of an existing AST node. Notify listeners. + if (ASTMutationListener *L = SemaRef.getASTMutationListener()) + L->StaticDataMemberInstantiated(Var); + MSInfo->setPointOfInstantiation(Loc); + } + PointOfInstantiation = MSInfo->getPointOfInstantiation(); + } else + InstantiationIsOkay = false; + } else { + if (VarSpec->getPointOfInstantiation().isInvalid()) + VarSpec->setPointOfInstantiation(Loc); + PointOfInstantiation = VarSpec->getPointOfInstantiation(); + } + + if (InstantiationIsOkay) { + bool InstantiationDependent = false; + bool IsNonDependent = + VarSpec ? !TemplateSpecializationType::anyDependentTemplateArguments( + VarSpec->getTemplateArgsInfo(), InstantiationDependent) + : true; + + // Do not instantiate specializations that are still type-dependent. + if (IsNonDependent) { + if (Var->isUsableInConstantExpressions(SemaRef.Context)) { + // Do not defer instantiations of variables which could be used in a + // constant expression. + SemaRef.InstantiateVariableDefinition(PointOfInstantiation, Var); + } else { + SemaRef.PendingInstantiations + .push_back(std::make_pair(Var, PointOfInstantiation)); + } } - SourceLocation PointOfInstantiation = MSInfo->getPointOfInstantiation(); - if (Var->isUsableInConstantExpressions(SemaRef.Context)) - // Do not defer instantiations of variables which could be used in a - // constant expression. - SemaRef.InstantiateStaticDataMemberDefinition(PointOfInstantiation,Var); - else - SemaRef.PendingInstantiations.push_back( - std::make_pair(Var, PointOfInstantiation)); } } diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index af0eb08f203..098187244a6 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -11,6 +11,7 @@ #include "TreeTransform.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTConsumer.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" @@ -207,8 +208,9 @@ TemplateNameKind Sema::isTemplateName(Scope *S, R.suppressDiagnostics(); } else { assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) || - isa<TypeAliasTemplateDecl>(TD)); - TemplateKind = TNK_Type_template; + isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD)); + TemplateKind = + isa<VarTemplateDecl>(TD) ? TNK_Var_template : TNK_Type_template; } } @@ -1159,6 +1161,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S, SourceRange DefArgRange) { switch (TPC) { case Sema::TPC_ClassTemplate: + case Sema::TPC_VarTemplate: case Sema::TPC_TypeAliasTemplate: return false; @@ -1430,7 +1433,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, // If a template parameter of a primary class template or alias template // is a template parameter pack, it shall be the last template parameter. if (SawParameterPack && (NewParam + 1) != NewParamEnd && - (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) { + (TPC == TPC_ClassTemplate || TPC == TPC_VarTemplate || + TPC == TPC_TypeAliasTemplate)) { Diag((*NewParam)->getLocation(), diag::err_template_param_pack_must_be_last_template_parameter); Invalid = true; @@ -1924,11 +1928,14 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( void Sema::NoteAllFoundTemplates(TemplateName Name) { if (TemplateDecl *Template = Name.getAsTemplateDecl()) { Diag(Template->getLocation(), diag::note_template_declared_here) - << (isa<FunctionTemplateDecl>(Template)? 0 - : isa<ClassTemplateDecl>(Template)? 1 - : isa<TypeAliasTemplateDecl>(Template)? 2 - : 3) - << Template->getDeclName(); + << (isa<FunctionTemplateDecl>(Template) + ? 0 + : isa<ClassTemplateDecl>(Template) + ? 1 + : isa<VarTemplateDecl>(Template) + ? 2 + : isa<TypeAliasTemplateDecl>(Template) ? 3 : 4) + << Template->getDeclName(); return; } @@ -2263,6 +2270,452 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); } +static bool CheckTemplatePartialSpecializationArgs( + Sema &S, TemplateParameterList *TemplateParams, + SmallVectorImpl<TemplateArgument> &TemplateArgs); + +static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized, + NamedDecl *PrevDecl, + SourceLocation Loc, + bool IsPartialSpecialization); + +static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D); +/* +/// \brief Check the new variable specialization against the parsed input. +/// +/// FIXME: Model this against function specializations where +/// a new function declaration is checked against the specialization +/// as candidate for redefinition... (?) +static bool CheckVariableTemplateSpecializationType() { + + if (ExpectedType is undeduced && ParsedType is not undeduced) + ExpectedType = dedudeType(); + + if (both types are undeduced) + ???; + + bool CheckType = !ExpectedType()-> + + if (!Context.hasSameType(DI->getType(), ExpectedDI->getType())) { + unsigned ErrStr = IsPartialSpecialization ? 2 : 1; + Diag(D.getIdentifierLoc(), diag::err_invalid_var_template_spec_type) + << ErrStr << VarTemplate << DI->getType() << ExpectedDI->getType(); + Diag(VarTemplate->getLocation(), diag::note_template_declared_here) + << 2 << VarTemplate->getDeclName(); + return true; + } +} +*/ + +DeclResult Sema::ActOnVarTemplateSpecialization( + Scope *S, VarTemplateDecl *VarTemplate, Declarator &D, TypeSourceInfo *DI, + SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, + VarDecl::StorageClass SC, bool IsPartialSpecialization) { + assert(VarTemplate && "A variable template id without template?"); + + // D must be variable template id. + assert(D.getName().getKind() == UnqualifiedId::IK_TemplateId && + "Variable template specialization is declared with a template it."); + + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; + SourceLocation TemplateNameLoc = D.getIdentifierLoc(); + SourceLocation LAngleLoc = TemplateId->LAngleLoc; + SourceLocation RAngleLoc = TemplateId->RAngleLoc; + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); + translateTemplateArguments(TemplateArgsPtr, TemplateArgs); + TemplateName Name(VarTemplate); + + // Check for unexpanded parameter packs in any of the template arguments. + for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) + if (DiagnoseUnexpandedParameterPack(TemplateArgs[I], + UPPC_PartialSpecialization)) + return true; + + // Check that the template argument list is well-formed for this + // template. + SmallVector<TemplateArgument, 4> Converted; + if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs, + false, Converted)) + return true; + + // Check that the type of this variable template specialization + // matches the expected type. + TypeSourceInfo *ExpectedDI; + { + // Do substitution on the type of the declaration + TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); + InstantiatingTemplate Inst(*this, TemplateKWLoc, VarTemplate); + if (Inst) + return true; + VarDecl *Templated = VarTemplate->getTemplatedDecl(); + ExpectedDI = + SubstType(Templated->getTypeSourceInfo(), + MultiLevelTemplateArgumentList(TemplateArgList), + Templated->getTypeSpecStartLoc(), Templated->getDeclName()); + } + if (!ExpectedDI) + return true; + + /* + // Check the new variable specialization against the parsed input. + // (Attributes are merged later below.) + if (CheckVariableTemplateSpecializationType()) + return true; + */ + + // Find the variable template (partial) specialization declaration that + // corresponds to these arguments. + if (IsPartialSpecialization) { + if (CheckTemplatePartialSpecializationArgs( + *this, VarTemplate->getTemplateParameters(), Converted)) + return true; + + bool InstantiationDependent; + if (!Name.isDependent() && + !TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs.getArgumentArray(), TemplateArgs.size(), + InstantiationDependent)) { + Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized) + << VarTemplate->getDeclName(); + IsPartialSpecialization = false; + } + } + + void *InsertPos = 0; + VarTemplateSpecializationDecl *PrevDecl = 0; + + if (IsPartialSpecialization) + // FIXME: Template parameter list matters too + PrevDecl = VarTemplate->findPartialSpecialization( + Converted.data(), Converted.size(), InsertPos); + else + PrevDecl = VarTemplate->findSpecialization(Converted.data(), + Converted.size(), InsertPos); + + VarTemplateSpecializationDecl *Specialization = 0; + + // Check whether we can declare a variable template specialization in + // the current scope. + if (CheckTemplateSpecializationScope(*this, VarTemplate, PrevDecl, + TemplateNameLoc, + IsPartialSpecialization)) + return true; + + if (PrevDecl && PrevDecl->getSpecializationKind() == TSK_Undeclared) { + // Since the only prior variable template specialization with these + // arguments was referenced but not declared, reuse that + // declaration node as our own, updating its source location and + // the list of outer template parameters to reflect our new declaration. + Specialization = PrevDecl; + Specialization->setLocation(TemplateNameLoc); + PrevDecl = 0; + } else if (IsPartialSpecialization) { + // Create a new class template partial specialization declaration node. + VarTemplatePartialSpecializationDecl *PrevPartial = + cast_or_null<VarTemplatePartialSpecializationDecl>(PrevDecl); + unsigned SequenceNumber = + PrevPartial ? PrevPartial->getSequenceNumber() + : VarTemplate->getNextPartialSpecSequenceNumber(); + VarTemplatePartialSpecializationDecl *Partial = + VarTemplatePartialSpecializationDecl::Create( + Context, VarTemplate->getDeclContext(), TemplateKWLoc, + TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC, + Converted.data(), Converted.size(), TemplateArgs, SequenceNumber); + + if (!PrevPartial) + VarTemplate->AddPartialSpecialization(Partial, InsertPos); + Specialization = Partial; + + // If we are providing an explicit specialization of a member variable + // template specialization, make a note of that. + if (PrevPartial && PrevPartial->getInstantiatedFromMember()) + Partial->setMemberSpecialization(); + + // Check that all of the template parameters of the variable template + // partial specialization are deducible from the template + // arguments. If not, this variable template partial specialization + // will never be used. + llvm::SmallBitVector DeducibleParams(TemplateParams->size()); + MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, + TemplateParams->getDepth(), DeducibleParams); + + if (!DeducibleParams.all()) { + unsigned NumNonDeducible = + DeducibleParams.size() - DeducibleParams.count(); + Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible) + << (NumNonDeducible > 1) << SourceRange(TemplateNameLoc, RAngleLoc); + for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { + if (!DeducibleParams[I]) { + NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); + if (Param->getDeclName()) + Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter) + << Param->getDeclName(); + else + Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter) + << "<anonymous>"; + } + } + } + } else { + // Create a new class template specialization declaration node for + // this explicit specialization or friend declaration. + Specialization = VarTemplateSpecializationDecl::Create( + Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc, + VarTemplate, DI->getType(), DI, SC, Converted.data(), Converted.size()); + Specialization->setTemplateArgsInfo(TemplateArgs); + + if (!PrevDecl) + VarTemplate->AddSpecialization(Specialization, InsertPos); + } + + // C++ [temp.expl.spec]p6: + // If a template, a member template or the member of a class template is + // explicitly specialized then that specialization shall be declared + // before the first use of that specialization that would cause an implicit + // instantiation to take place, in every translation unit in which such a + // use occurs; no diagnostic is required. + if (PrevDecl && PrevDecl->getPointOfInstantiation().isValid()) { + bool Okay = false; + for (Decl *Prev = PrevDecl; Prev; Prev = Prev->getPreviousDecl()) { + // Is there any previous explicit specialization declaration? + if (getTemplateSpecializationKind(Prev) == TSK_ExplicitSpecialization) { + Okay = true; + break; + } + } + + if (!Okay) { + SourceRange Range(TemplateNameLoc, RAngleLoc); + Diag(TemplateNameLoc, diag::err_specialization_after_instantiation) + << Name << Range; + + Diag(PrevDecl->getPointOfInstantiation(), + diag::note_instantiation_required_here) + << (PrevDecl->getTemplateSpecializationKind() != + TSK_ImplicitInstantiation); + return true; + } + } + + Specialization->setTemplateKeywordLoc(TemplateKWLoc); + Specialization->setLexicalDeclContext(CurContext); + + // Add the specialization into its lexical context, so that it can + // be seen when iterating through the list of declarations in that + // context. However, specializations are not found by name lookup. + CurContext->addDecl(Specialization); + + // Note that this is an explicit specialization. + Specialization->setSpecializationKind(TSK_ExplicitSpecialization); + + if (PrevDecl) { + // Check that this isn't a redefinition of this specialization, + // merging with previous declarations. + LookupResult PrevSpec(*this, GetNameForDeclarator(D), LookupOrdinaryName, + ForRedeclaration); + PrevSpec.addDecl(PrevDecl); + D.setRedeclaration(CheckVariableDeclaration(Specialization, PrevSpec)); + } + + // Link instantiations of static data members back to the template from + // which they were instantiated. + if (Specialization->isStaticDataMember()) + Specialization->setInstantiationOfStaticDataMember( + VarTemplate->getTemplatedDecl(), + Specialization->getSpecializationKind()); + + return Specialization; +} + +namespace { +/// \brief A partial specialization whose template arguments have matched +/// a given template-id. +struct PartialSpecMatchResult { + VarTemplatePartialSpecializationDecl *Partial; + TemplateArgumentList *Args; +}; +} + +DeclResult +Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, + SourceLocation TemplateNameLoc, + const TemplateArgumentListInfo &TemplateArgs) { + assert(Template && "A variable template id without template?"); + + // Check that the template argument list is well-formed for this template. + SmallVector<TemplateArgument, 4> Converted; + bool ExpansionIntoFixedList = false; + if (CheckTemplateArgumentList( + Template, TemplateNameLoc, + const_cast<TemplateArgumentListInfo &>(TemplateArgs), false, + Converted, &ExpansionIntoFixedList)) + return true; + + // Find the variable template specialization declaration that + // corresponds to these arguments. + void *InsertPos = 0; + if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization( + Converted.data(), Converted.size(), InsertPos)) + // If we already have a variable template specialization, return it. + return Spec; + + // This is the first time we have referenced this variable template + // specialization. Create the canonical declaration and add it to + // the set of specializations, based on the closest partial specialization + // that it represents. That is, + VarDecl *InstantiationPattern = Template->getTemplatedDecl(); + TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); + TemplateArgumentList *InstantiationArgs = &TemplateArgList; + bool AmbiguousPartialSpec = false; + typedef PartialSpecMatchResult MatchResult; + SmallVector<MatchResult, 4> Matched; + SourceLocation PointOfInstantiation = TemplateNameLoc; + TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation); + + // 1. Attempt to find the closest partial specialization that this + // specializes, if any. + // If any of the template arguments is dependent, then this is probably + // a placeholder for an incomplete declarative context; which must be + // complete by instantiation time. Thus, do not search through the partial + // specializations yet. + // FIXME: Unify with InstantiateClassTemplateSpecialization()? + bool InstantiationDependent = false; + if (!TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs, InstantiationDependent)) { + + SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs; + Template->getPartialSpecializations(PartialSpecs); + + for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { + VarTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; + TemplateDeductionInfo Info(FailedCandidates.getLocation()); + + if (TemplateDeductionResult Result = + DeduceTemplateArguments(Partial, TemplateArgList, Info)) { + // Store the failed-deduction information for use in diagnostics, later. + FailedCandidates.addCandidate() + .set(Partial, MakeDeductionFailureInfo(Context, Result, Info)); + (void)Result; + } else { + Matched.push_back(PartialSpecMatchResult()); + Matched.back().Partial = Partial; + Matched.back().Args = Info.take(); + } + } + + // If we're dealing with a member template where the template parameters + // have been instantiated, this provides the original template parameters + // from which the member template's parameters were instantiated. + SmallVector<const NamedDecl *, 4> InstantiatedTemplateParameters; + + if (Matched.size() >= 1) { + SmallVector<MatchResult, 4>::iterator Best = Matched.begin(); + if (Matched.size() == 1) { + // -- If exactly one matching specialization is found, the + // instantiation is generated from that specialization. + // We don't need to do anything for this. + } else { + // -- If more than one matching specialization is found, the + // partial order rules (14.5.4.2) are used to determine + // whether one of the specializations is more specialized + // than the others. If none of the specializations is more + // specialized than all of the other matching + // specializations, then the use of the variable template is + // ambiguous and the program is ill-formed. + for (SmallVector<MatchResult, 4>::iterator P = Best + 1, + PEnd = Matched.end(); + P != PEnd; ++P) { + if (getMoreSpecializedPartialSpecialization(P->Partial, Best->Partial, + PointOfInstantiation) == + P->Partial) + Best = P; + } + + // Determine if the best partial specialization is more specialized than + // the others. + for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(), + PEnd = Matched.end(); + P != PEnd; ++P) { + if (P != Best && getMoreSpecializedPartialSpecialization( + P->Partial, Best->Partial, + PointOfInstantiation) != Best->Partial) { + AmbiguousPartialSpec = true; + break; + } + } + } + + // Instantiate using the best variable template partial specialization. + InstantiationPattern = Best->Partial; + InstantiationArgs = Best->Args; + } else { + // -- If no match is found, the instantiation is generated + // from the primary template. + // InstantiationPattern = Template->getTemplatedDecl(); + } + } + + // FIXME: Actually use FailedCandidates. + + // 2. Create the canonical declaration. + // Note that we do not instantiate the variable just yet, since + // instantiation is handled in DoMarkVarDeclReferenced(). + // FIXME: LateAttrs et al.? + VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation( + Template, InstantiationPattern, *InstantiationArgs, TemplateArgs, + Converted, TemplateNameLoc, InsertPos /*, LateAttrs, StartingScope*/); + if (!Decl) + return true; + + if (AmbiguousPartialSpec) { + // Partial ordering did not produce a clear winner. Complain. + Decl->setInvalidDecl(); + Diag(PointOfInstantiation, diag::err_partial_spec_ordering_ambiguous) + << Decl; + + // Print the matching partial specializations. + for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(), + PEnd = Matched.end(); + P != PEnd; ++P) + Diag(P->Partial->getLocation(), diag::note_partial_spec_match) + << getTemplateArgumentBindingsText( + P->Partial->getTemplateParameters(), *P->Args); + return true; + } + + if (VarTemplatePartialSpecializationDecl *D = + dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern)) + Decl->setInstantiationOf(D, InstantiationArgs); + + assert(Decl && "No variable template specialization?"); + return Decl; +} + +ExprResult +Sema::CheckVarTemplateId(const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + VarTemplateDecl *Template, SourceLocation TemplateLoc, + const TemplateArgumentListInfo *TemplateArgs) { + + DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(), + *TemplateArgs); + if (Decl.isInvalid()) + return ExprError(); + + VarDecl *Var = cast<VarDecl>(Decl.get()); + if (!Var->getTemplateSpecializationKind()) + Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, + NameInfo.getLoc()); + + // Build an ordinary singleton decl ref. + return BuildDeclarationNameExpr(SS, NameInfo, Var, + /*FoundD=*/0, TemplateArgs); +} + ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, @@ -2282,6 +2735,13 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, assert(!R.empty() && "empty lookup results when building templateid"); assert(!R.isAmbiguous() && "ambiguous lookup when building templateid"); + // In C++1y, check variable template ids. + if (R.getAsSingle<VarTemplateDecl>()) { + return Owned(CheckVarTemplateId(SS, R.getLookupNameInfo(), + R.getAsSingle<VarTemplateDecl>(), + TemplateKWLoc, TemplateArgs)); + } + // We don't want lookup warnings at this point. R.suppressDiagnostics(); @@ -2302,6 +2762,7 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs) { + assert(TemplateArgs || TemplateKWLoc.isValid()); DeclContext *DC; if (!(DC = computeDeclContext(SS, false)) || @@ -4962,16 +5423,18 @@ static bool CheckTemplateSpecializationScope(Sema &S, int EntityKind = 0; if (isa<ClassTemplateDecl>(Specialized)) EntityKind = IsPartialSpecialization? 1 : 0; + else if (isa<VarTemplateDecl>(Specialized)) + EntityKind = IsPartialSpecialization ? 3 : 2; else if (isa<FunctionTemplateDecl>(Specialized)) - EntityKind = 2; + EntityKind = 4; else if (isa<CXXMethodDecl>(Specialized)) - EntityKind = 3; + EntityKind = 5; else if (isa<VarDecl>(Specialized)) - EntityKind = 4; + EntityKind = 6; else if (isa<RecordDecl>(Specialized)) - EntityKind = 5; + EntityKind = 7; else if (isa<EnumDecl>(Specialized) && S.getLangOpts().CPlusPlus11) - EntityKind = 6; + EntityKind = 8; else { S.Diag(Loc, diag::err_template_spec_unknown_kind) << S.getLangOpts().CPlusPlus11; @@ -5095,17 +5558,15 @@ static bool CheckTemplateSpecializationScope(Sema &S, return false; } -/// \brief Subroutine of Sema::CheckClassTemplatePartialSpecializationArgs +/// \brief Subroutine of Sema::CheckTemplatePartialSpecializationArgs /// that checks non-type template partial specialization arguments. -static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S, - NonTypeTemplateParmDecl *Param, - const TemplateArgument *Args, - unsigned NumArgs) { +static bool CheckNonTypeTemplatePartialSpecializationArgs( + Sema &S, NonTypeTemplateParmDecl *Param, const TemplateArgument *Args, + unsigned NumArgs) { for (unsigned I = 0; I != NumArgs; ++I) { if (Args[I].getKind() == TemplateArgument::Pack) { - if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param, - Args[I].pack_begin(), - Args[I].pack_size())) + if (CheckNonTypeTemplatePartialSpecializationArgs( + S, Param, Args[I].pack_begin(), Args[I].pack_size())) return true; continue; @@ -5176,9 +5637,9 @@ static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S, /// partial specialization. /// /// \returns true if there was an error, false otherwise. -static bool CheckClassTemplatePartialSpecializationArgs(Sema &S, - TemplateParameterList *TemplateParams, - SmallVectorImpl<TemplateArgument> &TemplateArgs) { +static bool CheckTemplatePartialSpecializationArgs( + Sema &S, TemplateParameterList *TemplateParams, + SmallVectorImpl<TemplateArgument> &TemplateArgs) { const TemplateArgument *ArgList = TemplateArgs.data(); for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { @@ -5187,8 +5648,7 @@ static bool CheckClassTemplatePartialSpecializationArgs(Sema &S, if (!Param) continue; - if (CheckNonTypeClassTemplatePartialSpecializationArgs(S, Param, - &ArgList[I], 1)) + if (CheckNonTypeTemplatePartialSpecializationArgs(S, Param, &ArgList[I], 1)) return true; } @@ -5334,9 +5794,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Find the class template (partial) specialization declaration that // corresponds to these arguments. if (isPartialSpecialization) { - if (CheckClassTemplatePartialSpecializationArgs(*this, - ClassTemplate->getTemplateParameters(), - Converted)) + if (CheckTemplatePartialSpecializationArgs( + *this, ClassTemplate->getTemplateParameters(), Converted)) return true; bool InstantiationDependent; @@ -6207,9 +6666,8 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { InstantiationVar->setLocation(Member->getLocation()); } - Context.setInstantiatedFromStaticDataMember(cast<VarDecl>(Member), - cast<VarDecl>(InstantiatedFrom), - TSK_ExplicitSpecialization); + cast<VarDecl>(Member)->setInstantiationOfStaticDataMember( + cast<VarDecl>(InstantiatedFrom), TSK_ExplicitSpecialization); MarkUnusedFileScopedDecl(InstantiationVar); } else if (isa<CXXRecordDecl>(Member)) { CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation); @@ -6697,7 +7155,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, diag::err_explicit_instantiation_inline : diag::warn_explicit_instantiation_inline_0x) << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); - if (D.getDeclSpec().isConstexprSpecified()) + if (D.getDeclSpec().isConstexprSpecified() && R->isFunctionType()) // FIXME: Add a fix-it to remove the 'constexpr' and add a 'const' if one is // not already specified. Diag(D.getDeclSpec().getConstexprSpecLoc(), @@ -6719,28 +7177,68 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // A [...] static data member of a class template can be explicitly // instantiated from the member definition associated with its class // template. + // C++1y [temp.explicit]p1: + // A [...] variable [...] template specialization can be explicitly + // instantiated from its template. if (Previous.isAmbiguous()) return true; VarDecl *Prev = Previous.getAsSingle<VarDecl>(); - if (!Prev || !Prev->isStaticDataMember()) { - // We expect to see a data data member here. - Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known) - << Name; - for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); - P != PEnd; ++P) - Diag((*P)->getLocation(), diag::note_explicit_instantiation_here); - return true; - } + VarTemplateDecl *PrevTemplate = Previous.getAsSingle<VarTemplateDecl>(); + + if (!PrevTemplate) { + if (!Prev || !Prev->isStaticDataMember()) { + // We expect to see a data data member here. + Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known) + << Name; + for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); + P != PEnd; ++P) + Diag((*P)->getLocation(), diag::note_explicit_instantiation_here); + return true; + } - if (!Prev->getInstantiatedFromStaticDataMember()) { - // FIXME: Check for explicit specialization? - Diag(D.getIdentifierLoc(), - diag::err_explicit_instantiation_data_member_not_instantiated) - << Prev; - Diag(Prev->getLocation(), diag::note_explicit_instantiation_here); - // FIXME: Can we provide a note showing where this was declared? - return true; + if (!Prev->getInstantiatedFromStaticDataMember()) { + // FIXME: Check for explicit specialization? + Diag(D.getIdentifierLoc(), + diag::err_explicit_instantiation_data_member_not_instantiated) + << Prev; + Diag(Prev->getLocation(), diag::note_explicit_instantiation_here); + // FIXME: Can we provide a note showing where this was declared? + return true; + } + } else { + // Explicitly instantiate a variable template. + + // C++1y [dcl.spec.auto]p6: + // ... A program that uses auto or decltype(auto) in a context not + // explicitly allowed in this section is ill-formed. + // + // This includes auto-typed variable template instantiations. + if (R->isUndeducedType()) { + Diag(T->getTypeLoc().getLocStart(), + diag::err_auto_not_allowed_var_inst); + return true; + } + + TemplateArgumentListInfo TemplateArgs; + if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { + // Translate the parser's template argument list into our AST format. + TemplateIdAnnotation *TemplateId = D.getName().TemplateId; + TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); + TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + translateTemplateArguments(TemplateArgsPtr, TemplateArgs); + } + + DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc, + D.getIdentifierLoc(), TemplateArgs); + if (Res.isInvalid()) + return true; + + // Ignore access control bits, we don't need them for redeclaration + // checking. + Prev = cast<VarDecl>(Res.get()); } // C++0x [temp.explicit]p2: @@ -6750,7 +7248,13 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // name shall be a simple-template-id. // // C++98 has the same restriction, just worded differently. - if (!ScopeSpecifierHasTemplateId(D.getCXXScopeSpec())) + // + // C++1y If the explicit instantiation is for a variable, the + // unqualified-id in the declaration shall be a template-id. + if (!ScopeSpecifierHasTemplateId(D.getCXXScopeSpec()) && + (!PrevTemplate || + (D.getName().getKind() != UnqualifiedId::IK_TemplateId && + D.getCXXScopeSpec().isSet()))) Diag(D.getIdentifierLoc(), diag::ext_explicit_instantiation_without_qualified_id) << Prev << D.getCXXScopeSpec().getRange(); @@ -6760,20 +7264,39 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // Verify that it is okay to explicitly instantiate here. MemberSpecializationInfo *MSInfo = Prev->getMemberSpecializationInfo(); - assert(MSInfo && "Missing static data member specialization info?"); + TemplateSpecializationKind PrevTSK = + MSInfo ? MSInfo->getTemplateSpecializationKind() + : Prev->getTemplateSpecializationKind(); + SourceLocation POI = MSInfo ? MSInfo->getPointOfInstantiation() + : cast<VarTemplateSpecializationDecl>(Prev) + ->getPointOfInstantiation(); bool HasNoEffect = false; if (CheckSpecializationInstantiationRedecl(D.getIdentifierLoc(), TSK, Prev, - MSInfo->getTemplateSpecializationKind(), - MSInfo->getPointOfInstantiation(), - HasNoEffect)) + PrevTSK, POI, HasNoEffect)) return true; - if (HasNoEffect) - return (Decl*) 0; - // Instantiate static data member. - Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); - if (TSK == TSK_ExplicitInstantiationDefinition) - InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev); + if (!HasNoEffect) { + // Instantiate static data member or variable template. + + Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); + if (PrevTemplate) { + // Merge attributes. + if (AttributeList *Attr = D.getDeclSpec().getAttributes().getList()) + ProcessDeclAttributeList(S, Prev, Attr); + } + if (TSK == TSK_ExplicitInstantiationDefinition) + InstantiateVariableDefinition(D.getIdentifierLoc(), Prev); + } + + // Check the new variable specialization against the parsed input. + if (PrevTemplate && Prev && !Context.hasSameType(Prev->getType(), R)) { + Diag(T->getTypeLoc().getLocStart(), + diag::err_invalid_var_template_spec_type) + << 0 << PrevTemplate << R << Prev->getType(); + Diag(PrevTemplate->getLocation(), diag::note_template_declared_here) + << 2 << PrevTemplate->getDeclName(); + return true; + } // FIXME: Create an ExplicitInstantiation node? return (Decl*) 0; diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 8d6aaa096df..e87354663b0 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2246,7 +2246,7 @@ FinishTemplateArgumentDeduction(Sema &S, } /// \brief Perform template argument deduction to determine whether -/// the given template arguments match the given class template +/// the given template arguments match the given variable template /// partial specialization per C++ [temp.class.spec.match]. Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, @@ -2287,6 +2287,160 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, Deduced, Info); } +/// Complete template argument deduction for a variable template partial +/// specialization. +/// TODO: Unify with ClassTemplatePartialSpecializationDecl version. +static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( + Sema &S, VarTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + TemplateDeductionInfo &Info) { + // Unevaluated SFINAE context. + EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); + Sema::SFINAETrap Trap(S); + + // C++ [temp.deduct.type]p2: + // [...] or if any template argument remains neither deduced nor + // explicitly specified, template argument deduction fails. + SmallVector<TemplateArgument, 4> Builder; + TemplateParameterList *PartialParams = Partial->getTemplateParameters(); + for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) { + NamedDecl *Param = PartialParams->getParam(I); + if (Deduced[I].isNull()) { + Info.Param = makeTemplateParameter(Param); + return Sema::TDK_Incomplete; + } + + // We have deduced this argument, so it still needs to be + // checked and converted. + + // First, for a non-type template parameter type that is + // initialized by a declaration, we need the type of the + // corresponding non-type template parameter. + QualType NTTPType; + if (NonTypeTemplateParmDecl *NTTP = + dyn_cast<NonTypeTemplateParmDecl>(Param)) { + NTTPType = NTTP->getType(); + if (NTTPType->isDependentType()) { + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Builder.data(), Builder.size()); + NTTPType = + S.SubstType(NTTPType, MultiLevelTemplateArgumentList(TemplateArgs), + NTTP->getLocation(), NTTP->getDeclName()); + if (NTTPType.isNull()) { + Info.Param = makeTemplateParameter(Param); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(), + Builder.size())); + return Sema::TDK_SubstitutionFailure; + } + } + } + + if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Partial, NTTPType, + 0, Info, false, Builder)) { + Info.Param = makeTemplateParameter(Param); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(), + Builder.size())); + return Sema::TDK_SubstitutionFailure; + } + } + + // Form the template argument list from the deduced template arguments. + TemplateArgumentList *DeducedArgumentList = TemplateArgumentList::CreateCopy( + S.Context, Builder.data(), Builder.size()); + + Info.reset(DeducedArgumentList); + + // Substitute the deduced template arguments into the template + // arguments of the class template partial specialization, and + // verify that the instantiated template arguments are both valid + // and are equivalent to the template arguments originally provided + // to the class template. + LocalInstantiationScope InstScope(S); + VarTemplateDecl *VarTemplate = Partial->getSpecializedTemplate(); + const TemplateArgumentLoc *PartialTemplateArgs = + Partial->getTemplateArgsAsWritten(); + + // Note that we don't provide the langle and rangle locations. + TemplateArgumentListInfo InstArgs; + + if (S.Subst(PartialTemplateArgs, Partial->getNumTemplateArgsAsWritten(), + InstArgs, MultiLevelTemplateArgumentList(*DeducedArgumentList))) { + unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx; + if (ParamIdx >= Partial->getTemplateParameters()->size()) + ParamIdx = Partial->getTemplateParameters()->size() - 1; + + Decl *Param = const_cast<NamedDecl *>( + Partial->getTemplateParameters()->getParam(ParamIdx)); + Info.Param = makeTemplateParameter(Param); + Info.FirstArg = PartialTemplateArgs[ArgIdx].getArgument(); + return Sema::TDK_SubstitutionFailure; + } + SmallVector<TemplateArgument, 4> ConvertedInstArgs; + if (S.CheckTemplateArgumentList(VarTemplate, Partial->getLocation(), InstArgs, + false, ConvertedInstArgs)) + return Sema::TDK_SubstitutionFailure; + + TemplateParameterList *TemplateParams = VarTemplate->getTemplateParameters(); + for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { + TemplateArgument InstArg = ConvertedInstArgs.data()[I]; + if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) { + Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); + Info.FirstArg = TemplateArgs[I]; + Info.SecondArg = InstArg; + return Sema::TDK_NonDeducedMismatch; + } + } + + if (Trap.hasErrorOccurred()) + return Sema::TDK_SubstitutionFailure; + + return Sema::TDK_Success; +} + +/// \brief Perform template argument deduction to determine whether +/// the given template arguments match the given variable template +/// partial specialization per C++ [temp.class.spec.match]. +/// TODO: Unify with ClassTemplatePartialSpecializationDecl version. +Sema::TemplateDeductionResult +Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, + const TemplateArgumentList &TemplateArgs, + TemplateDeductionInfo &Info) { + if (Partial->isInvalidDecl()) + return TDK_Invalid; + + // C++ [temp.class.spec.match]p2: + // A partial specialization matches a given actual template + // argument list if the template arguments of the partial + // specialization can be deduced from the actual template argument + // list (14.8.2). + + // Unevaluated SFINAE context. + EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); + SFINAETrap Trap(*this); + + SmallVector<DeducedTemplateArgument, 4> Deduced; + Deduced.resize(Partial->getTemplateParameters()->size()); + if (TemplateDeductionResult Result = ::DeduceTemplateArguments( + *this, Partial->getTemplateParameters(), Partial->getTemplateArgs(), + TemplateArgs, Info, Deduced)) + return Result; + + SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), Deduced.end()); + InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial, + DeducedArgs, Info); + if (Inst) + return TDK_InstantiationDepth; + + if (Trap.hasErrorOccurred()) + return Sema::TDK_SubstitutionFailure; + + return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs, + Deduced, Info); +} + /// \brief Determine whether the given type T is a simple-template-id type. static bool isSimpleTemplateIdType(QualType T) { if (const TemplateSpecializationType *Spec @@ -4278,6 +4432,63 @@ Sema::getMoreSpecializedPartialSpecialization( /*RefParamComparisons=*/0); if (Better1) { SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),Deduced.end()); + InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2, DeducedArgs, + Info); + Better1 = !::FinishTemplateArgumentDeduction( + *this, PS2, PS1->getTemplateArgs(), Deduced, Info); + } + + // Determine whether PS2 is at least as specialized as PS1 + Deduced.clear(); + Deduced.resize(PS1->getTemplateParameters()->size()); + bool Better2 = !DeduceTemplateArgumentsByTypeMatch( + *this, PS1->getTemplateParameters(), PT1, PT2, Info, Deduced, TDF_None, + /*PartialOrdering=*/true, + /*RefParamComparisons=*/0); + if (Better2) { + SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), + Deduced.end()); + InstantiatingTemplate Inst(*this, PS1->getLocation(), PS1, DeducedArgs, + Info); + Better2 = !::FinishTemplateArgumentDeduction( + *this, PS1, PS2->getTemplateArgs(), Deduced, Info); + } + + if (Better1 == Better2) + return 0; + + return Better1 ? PS1 : PS2; +} + +/// TODO: Unify with ClassTemplatePartialSpecializationDecl version. +VarTemplatePartialSpecializationDecl * +Sema::getMoreSpecializedPartialSpecialization( + VarTemplatePartialSpecializationDecl *PS1, + VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc) { + SmallVector<DeducedTemplateArgument, 4> Deduced; + TemplateDeductionInfo Info(Loc); + + assert(PS1->getSpecializedTemplate() == PS1->getSpecializedTemplate() && + "the partial specializations being compared should specialize" + " the same template."); + TemplateName Name(PS1->getSpecializedTemplate()); + TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); + QualType PT1 = Context.getTemplateSpecializationType( + CanonTemplate, PS1->getTemplateArgs().data(), + PS1->getTemplateArgs().size()); + QualType PT2 = Context.getTemplateSpecializationType( + CanonTemplate, PS2->getTemplateArgs().data(), + PS2->getTemplateArgs().size()); + + // Determine whether PS1 is at least as specialized as PS2 + Deduced.resize(PS2->getTemplateParameters()->size()); + bool Better1 = !DeduceTemplateArgumentsByTypeMatch( + *this, PS2->getTemplateParameters(), PT2, PT1, Info, Deduced, TDF_None, + /*PartialOrdering=*/true, + /*RefParamComparisons=*/0); + if (Better1) { + SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), + Deduced.end()); InstantiatingTemplate Inst(*this, PS2->getLocation(), PS2, DeducedArgs, Info); Better1 = !::FinishTemplateArgumentDeduction(*this, PS2, diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 57eb64d127a..25eb72ce1cb 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -61,7 +61,24 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, DeclContext *Ctx = dyn_cast<DeclContext>(D); if (!Ctx) { Ctx = D->getDeclContext(); - + + // Add template arguments from a variable template instantiation. + if (VarTemplateSpecializationDecl *Spec = + dyn_cast<VarTemplateSpecializationDecl>(D)) { + // We're done when we hit an explicit specialization. + if (Spec->getSpecializationKind() == TSK_ExplicitSpecialization && + !isa<VarTemplatePartialSpecializationDecl>(Spec)) + return Result; + + Result.addOuterTemplateArguments(&Spec->getTemplateInstantiationArgs()); + + // If this variable template specialization was instantiated from a + // specialized member that is a variable template, we're done. + assert(Spec->getSpecializedTemplate() && "No variable template?"); + if (Spec->getSpecializedTemplate()->isMemberSpecialization()) + return Result; + } + // If we have a template template parameter with translation unit context, // then we're performing substitution into a default template argument of // this template template parameter before we've constructed the template @@ -292,6 +309,29 @@ InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, } } +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, + VarTemplatePartialSpecializationDecl *PartialSpec, + ArrayRef<TemplateArgument> TemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) + : SemaRef(SemaRef), SavedInNonInstantiationSFINAEContext( + SemaRef.InNonInstantiationSFINAEContext) { + Invalid = CheckInstantiationDepth(PointOfInstantiation, InstantiationRange); + if (!Invalid) { + ActiveTemplateInstantiation Inst; + Inst.Kind = + ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution; + Inst.PointOfInstantiation = PointOfInstantiation; + Inst.Entity = PartialSpec; + Inst.TemplateArgs = TemplateArgs.data(); + Inst.NumTemplateArgs = TemplateArgs.size(); + Inst.DeductionInfo = &DeductionInfo; + Inst.InstantiationRange = InstantiationRange; + SemaRef.InNonInstantiationSFINAEContext = false; + SemaRef.ActiveTemplateInstantiations.push_back(Inst); + } +} + Sema::InstantiatingTemplate:: InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ParmVarDecl *Param, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 52075229971..b93fe9a966a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -318,7 +318,13 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { return Inst; } +// FIXME: Revise for static member templates. Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { + return VisitVarDecl(D, /*ForVarTemplate=*/false); +} + +Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, bool ForVarTemplate) { + // If this is the variable for an anonymous struct or union, // instantiate the anonymous struct/union type first. if (const RecordType *RecordTy = D->getType()->getAs<RecordType>()) @@ -340,105 +346,22 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { return 0; } - // Build the instantiated declaration - VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, - D->getInnerLocStart(), + // Build the instantiated declaration. + VarDecl *Var = VarDecl::Create(SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), D->getIdentifier(), - DI->getType(), DI, - D->getStorageClass()); - Var->setTSCSpec(D->getTSCSpec()); - Var->setInitStyle(D->getInitStyle()); - Var->setCXXForRangeDecl(D->isCXXForRangeDecl()); - Var->setConstexpr(D->isConstexpr()); + DI->getType(), DI, D->getStorageClass()); - // Substitute the nested name specifier, if any. - if (SubstQualifier(D, Var)) - return 0; - - // If we are instantiating a static data member defined - // out-of-line, the instantiation will have the same lexical - // context (which will be a namespace scope) as the template. - if (D->isOutOfLine()) - Var->setLexicalDeclContext(D->getLexicalDeclContext()); - - Var->setAccess(D->getAccess()); - - if (!D->isStaticDataMember()) { - Var->setUsed(D->isUsed(false)); - Var->setReferenced(D->isReferenced()); - } - - SemaRef.InstantiateAttrs(TemplateArgs, D, Var, LateAttrs, StartingScope); - - if (Var->hasAttrs()) - SemaRef.CheckAlignasUnderalignment(Var); - - // FIXME: In theory, we could have a previous declaration for variables that - // are not static data members. - // FIXME: having to fake up a LookupResult is dumb. - LookupResult Previous(SemaRef, Var->getDeclName(), Var->getLocation(), - Sema::LookupOrdinaryName, Sema::ForRedeclaration); - if (D->isStaticDataMember()) - SemaRef.LookupQualifiedName(Previous, Owner, false); - // In ARC, infer 'retaining' for variables of retainable type. if (SemaRef.getLangOpts().ObjCAutoRefCount && SemaRef.inferObjCARCLifetime(Var)) Var->setInvalidDecl(); - SemaRef.CheckVariableDeclaration(Var, Previous); - - if (D->isOutOfLine()) { - D->getLexicalDeclContext()->addDecl(Var); - Owner->makeDeclVisibleInContext(Var); - } else { - Owner->addDecl(Var); - if (Owner->isFunctionOrMethod()) - SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Var); - } - - // Link instantiations of static data members back to the template from - // which they were instantiated. - if (Var->isStaticDataMember()) - SemaRef.Context.setInstantiatedFromStaticDataMember(Var, D, - TSK_ImplicitInstantiation); - - if (Var->getAnyInitializer()) { - // We already have an initializer in the class. - } else if (D->getInit()) { - if (Var->isStaticDataMember() && !D->isOutOfLine()) - SemaRef.PushExpressionEvaluationContext(Sema::ConstantEvaluated, D); - else - SemaRef.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, D); - - // Instantiate the initializer. - ExprResult Init = SemaRef.SubstInitializer(D->getInit(), TemplateArgs, - D->getInitStyle() == VarDecl::CallInit); - if (!Init.isInvalid()) { - bool TypeMayContainAuto = true; - if (Init.get()) { - bool DirectInit = D->isDirectInit(); - SemaRef.AddInitializerToDecl(Var, Init.take(), DirectInit, - TypeMayContainAuto); - } else - SemaRef.ActOnUninitializedDecl(Var, TypeMayContainAuto); - } else { - // FIXME: Not too happy about invalidating the declaration - // because of a bogus initializer. - Var->setInvalidDecl(); - } - - SemaRef.PopExpressionEvaluationContext(); - } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) && - !Var->isCXXForRangeDecl()) - SemaRef.ActOnUninitializedDecl(Var, false); - - // Diagnose unused local variables with dependent types, where the diagnostic - // will have been deferred. - if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed() && - D->getType()->isDependentType()) - SemaRef.DiagnoseUnusedDecl(Var); + // Substitute the nested name specifier, if any. + if (SubstQualifier(D, Var)) + return 0; + SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, + StartingScope, ForVarTemplate); return Var; } @@ -1026,6 +949,102 @@ TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl( return InstantiateClassTemplatePartialSpecialization(InstClassTemplate, D); } +Decl *TemplateDeclInstantiator::VisitVarTemplateDecl(VarTemplateDecl *D) { + assert(D->getTemplatedDecl()->isStaticDataMember() && + "Only static data member templates are allowed."); + // FIXME: Also only when instantiating a class? + + // Create a local instantiation scope for this variable template, which + // will contain the instantiations of the template parameters. + LocalInstantiationScope Scope(SemaRef); + TemplateParameterList *TempParams = D->getTemplateParameters(); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return NULL; + + VarDecl *Pattern = D->getTemplatedDecl(); + VarTemplateDecl *PrevVarTemplate = 0; + + if (Pattern->getPreviousDecl()) { + DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName()); + if (!Found.empty()) + PrevVarTemplate = dyn_cast<VarTemplateDecl>(Found.front()); + } + + // FIXME: This, and ForVarTemplate, is a hack that is probably unnecessary. + // We should use a simplified version of VisitVarDecl. + VarDecl *VarInst = cast_or_null<VarDecl>(VisitVarDecl(Pattern, /*ForVarTemplate=*/true)); + + DeclContext *DC = Owner; + + /* FIXME: This should be handled in VisitVarDecl, as used to produce + VarInst above. + // Instantiate the qualifier. + NestedNameSpecifierLoc QualifierLoc = Pattern->getQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = + SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs); + if (!QualifierLoc) + return 0; + } + + if (QualifierLoc) + VarInst->setQualifierInfo(QualifierLoc); + */ + + VarTemplateDecl *Inst = VarTemplateDecl::Create( + SemaRef.Context, DC, D->getLocation(), D->getIdentifier(), InstParams, + VarInst, PrevVarTemplate); + VarInst->setDescribedVarTemplate(Inst); + + Inst->setAccess(D->getAccess()); + if (!PrevVarTemplate) + Inst->setInstantiatedFromMemberTemplate(D); + + if (D->isOutOfLine()) { + Inst->setLexicalDeclContext(D->getLexicalDeclContext()); + VarInst->setLexicalDeclContext(D->getLexicalDeclContext()); + } + + Owner->addDecl(Inst); + + if (!PrevVarTemplate) { + // Queue up any out-of-line partial specializations of this member + // variable template; the client will force their instantiation once + // the enclosing class has been instantiated. + SmallVector<VarTemplatePartialSpecializationDecl *, 4> PartialSpecs; + D->getPartialSpecializations(PartialSpecs); + for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) + if (PartialSpecs[I]->isOutOfLine()) + OutOfLineVarPartialSpecs.push_back( + std::make_pair(Inst, PartialSpecs[I])); + } + + return Inst; +} + +Decl *TemplateDeclInstantiator::VisitVarTemplatePartialSpecializationDecl( + VarTemplatePartialSpecializationDecl *D) { + assert(D->isStaticDataMember() && + "Only static data member templates are allowed."); + // FIXME: Also only when instantiating a class? + + VarTemplateDecl *VarTemplate = D->getSpecializedTemplate(); + + // Lookup the already-instantiated declaration and return that. + DeclContext::lookup_result Found = Owner->lookup(VarTemplate->getDeclName()); + assert(!Found.empty() && "Instantiation found nothing?"); + + VarTemplateDecl *InstVarTemplate = dyn_cast<VarTemplateDecl>(Found.front()); + assert(InstVarTemplate && "Instantiation did not find a variable template?"); + + if (VarTemplatePartialSpecializationDecl *Result = + InstVarTemplate->findPartialSpecInstantiatedFromMember(D)) + return Result; + + return InstantiateVarTemplatePartialSpecialization(InstVarTemplate, D); +} + Decl * TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { // Create a local instantiation scope for this function template, which @@ -2256,6 +2275,87 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( "inside templates"); } +Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( + VarTemplateSpecializationDecl *D) { + + TemplateArgumentListInfo VarTemplateArgsInfo; + VarTemplateDecl *VarTemplate = D->getSpecializedTemplate(); + assert(VarTemplate && + "A template specialization without specialized template?"); + + // Substitute the current template arguments. + const TemplateArgumentListInfo &TemplateArgsInfo = D->getTemplateArgsInfo(); + VarTemplateArgsInfo.setLAngleLoc(TemplateArgsInfo.getLAngleLoc()); + VarTemplateArgsInfo.setRAngleLoc(TemplateArgsInfo.getRAngleLoc()); + + if (SemaRef.Subst(TemplateArgsInfo.getArgumentArray(), + TemplateArgsInfo.size(), VarTemplateArgsInfo, TemplateArgs)) + return 0; + + // Check that the template argument list is well-formed for this template. + SmallVector<TemplateArgument, 4> Converted; + bool ExpansionIntoFixedList = false; + if (SemaRef.CheckTemplateArgumentList( + VarTemplate, VarTemplate->getLocStart(), + const_cast<TemplateArgumentListInfo &>(VarTemplateArgsInfo), false, + Converted, &ExpansionIntoFixedList)) + return 0; + + // Find the variable template specialization declaration that + // corresponds to these arguments. + void *InsertPos = 0; + if (VarTemplateSpecializationDecl *VarSpec = VarTemplate->findSpecialization( + Converted.data(), Converted.size(), InsertPos)) + // If we already have a variable template specialization, return it. + return VarSpec; + + return VisitVarTemplateSpecializationDecl(VarTemplate, D, InsertPos, + VarTemplateArgsInfo, Converted); +} + +Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( + VarTemplateDecl *VarTemplate, VarDecl *D, void *InsertPos, + const TemplateArgumentListInfo &TemplateArgsInfo, + SmallVectorImpl<TemplateArgument> &Converted) { + + // If this is the variable for an anonymous struct or union, + // instantiate the anonymous struct/union type first. + if (const RecordType *RecordTy = D->getType()->getAs<RecordType>()) + if (RecordTy->getDecl()->isAnonymousStructOrUnion()) + if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl()))) + return 0; + + // Do substitution on the type of the declaration + TypeSourceInfo *DI = + SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, + D->getTypeSpecStartLoc(), D->getDeclName()); + if (!DI) + return 0; + + if (DI->getType()->isFunctionType()) { + SemaRef.Diag(D->getLocation(), diag::err_variable_instantiates_to_function) + << D->isStaticDataMember() << DI->getType(); + return 0; + } + + // Build the instantiated declaration + VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create( + SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), + VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted.data(), + Converted.size()); + Var->setTemplateArgsInfo(TemplateArgsInfo); + VarTemplate->AddSpecialization(Var, InsertPos); + + // Substitute the nested name specifier, if any. + if (SubstQualifier(D, Var)) + return 0; + + SemaRef.BuildVariableInstantiation(Var, D, TemplateArgs, LateAttrs, + StartingScope); + + return Var; +} + Decl *TemplateDeclInstantiator::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *D) { llvm_unreachable("@defs is not supported in Objective-C++"); } @@ -2442,6 +2542,134 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( return InstPartialSpec; } +/// \brief Instantiate the declaration of a variable template partial +/// specialization. +/// +/// \param VarTemplate the (instantiated) variable template that is partially +/// specialized by the instantiation of \p PartialSpec. +/// +/// \param PartialSpec the (uninstantiated) variable template partial +/// specialization that we are instantiating. +/// +/// \returns The instantiated partial specialization, if successful; otherwise, +/// NULL to indicate an error. +VarTemplatePartialSpecializationDecl * +TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( + VarTemplateDecl *VarTemplate, + VarTemplatePartialSpecializationDecl *PartialSpec) { + // Create a local instantiation scope for this variable template partial + // specialization, which will contain the instantiations of the template + // parameters. + LocalInstantiationScope Scope(SemaRef); + + // Substitute into the template parameters of the variable template partial + // specialization. + TemplateParameterList *TempParams = PartialSpec->getTemplateParameters(); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return 0; + + // Substitute into the template arguments of the variable template partial + // specialization. + TemplateArgumentListInfo InstTemplateArgs; // no angle locations + if (SemaRef.Subst(PartialSpec->getTemplateArgsAsWritten(), + PartialSpec->getNumTemplateArgsAsWritten(), + InstTemplateArgs, TemplateArgs)) + return 0; + + // Check that the template argument list is well-formed for this + // class template. + SmallVector<TemplateArgument, 4> Converted; + if (SemaRef.CheckTemplateArgumentList(VarTemplate, PartialSpec->getLocation(), + InstTemplateArgs, false, Converted)) + return 0; + + // Figure out where to insert this variable template partial specialization + // in the member template's set of variable template partial specializations. + void *InsertPos = 0; + VarTemplateSpecializationDecl *PrevDecl = + VarTemplate->findPartialSpecialization(Converted.data(), Converted.size(), + InsertPos); + + // Build the canonical type that describes the converted template + // arguments of the variable template partial specialization. + QualType CanonType = SemaRef.Context.getTemplateSpecializationType( + TemplateName(VarTemplate), Converted.data(), Converted.size()); + + // Build the fully-sugared type for this variable template + // specialization as the user wrote in the specialization + // itself. This means that we'll pretty-print the type retrieved + // from the specialization's declaration the way that the user + // actually wrote the specialization, rather than formatting the + // name based on the "canonical" representation used to store the + // template arguments in the specialization. + TypeSourceInfo *WrittenTy = SemaRef.Context.getTemplateSpecializationTypeInfo( + TemplateName(VarTemplate), PartialSpec->getLocation(), InstTemplateArgs, + CanonType); + + if (PrevDecl) { + // We've already seen a partial specialization with the same template + // parameters and template arguments. This can happen, for example, when + // substituting the outer template arguments ends up causing two + // variable template partial specializations of a member variable template + // to have identical forms, e.g., + // + // template<typename T, typename U> + // struct Outer { + // template<typename X, typename Y> pair<X,Y> p; + // template<typename Y> pair<T, Y> p; + // template<typename Y> pair<U, Y> p; + // }; + // + // Outer<int, int> outer; // error: the partial specializations of Inner + // // have the same signature. + SemaRef.Diag(PartialSpec->getLocation(), + diag::err_var_partial_spec_redeclared) + << WrittenTy->getType(); + SemaRef.Diag(PrevDecl->getLocation(), + diag::note_var_prev_partial_spec_here); + return 0; + } + + // Do substitution on the type of the declaration + TypeSourceInfo *DI = SemaRef.SubstType( + PartialSpec->getTypeSourceInfo(), TemplateArgs, + PartialSpec->getTypeSpecStartLoc(), PartialSpec->getDeclName()); + if (!DI) + return 0; + + if (DI->getType()->isFunctionType()) { + SemaRef.Diag(PartialSpec->getLocation(), + diag::err_variable_instantiates_to_function) + << PartialSpec->isStaticDataMember() << DI->getType(); + return 0; + } + + // Create the variable template partial specialization declaration. + VarTemplatePartialSpecializationDecl *InstPartialSpec = + VarTemplatePartialSpecializationDecl::Create( + SemaRef.Context, Owner, PartialSpec->getInnerLocStart(), + PartialSpec->getLocation(), InstParams, VarTemplate, DI->getType(), + DI, PartialSpec->getStorageClass(), Converted.data(), + Converted.size(), InstTemplateArgs, + VarTemplate->getNextPartialSpecSequenceNumber()); + + // Substitute the nested name specifier, if any. + if (SubstQualifier(PartialSpec, InstPartialSpec)) + return 0; + + InstPartialSpec->setInstantiatedFromMember(PartialSpec); + InstPartialSpec->setTypeAsWritten(WrittenTy); + + InstPartialSpec->setAccess(PartialSpec->getAccess()); + // FIXME: How much of BuildVariableInstantiation() should go in here? + + // Add this partial specialization to the set of variable template partial + // specializations. The instantiation of the initializer is not necessary. + VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/0); + return InstPartialSpec; +} + TypeSourceInfo* TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, SmallVectorImpl<ParmVarDecl *> &Params) { @@ -3026,6 +3254,167 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, PendingLocalImplicitInstantiations); } +VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation( + VarTemplateDecl *VarTemplate, VarDecl *FromVar, + const TemplateArgumentList &TemplateArgList, + const TemplateArgumentListInfo &TemplateArgsInfo, + SmallVectorImpl<TemplateArgument> &Converted, + SourceLocation PointOfInstantiation, void *InsertPos, + LateInstantiatedAttrVec *LateAttrs, + LocalInstantiationScope *StartingScope) { + if (FromVar->isInvalidDecl()) + return 0; + + InstantiatingTemplate Inst(*this, PointOfInstantiation, FromVar); + if (Inst) + return 0; + + MultiLevelTemplateArgumentList TemplateArgLists; + TemplateArgLists.addOuterTemplateArguments(&TemplateArgList); + + TemplateDeclInstantiator Instantiator( + *this, VarTemplate->getDeclContext(), + MultiLevelTemplateArgumentList(TemplateArgList)); + + // TODO: Set LateAttrs and StartingScope ... + + return cast_or_null<VarTemplateSpecializationDecl>( + Instantiator.VisitVarTemplateSpecializationDecl( + VarTemplate, FromVar, InsertPos, TemplateArgsInfo, Converted)); +} + +/// \brief Instantiates a variable template specialization by completing it +/// with appropriate type information and initializer. +VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl( + VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl, + const MultiLevelTemplateArgumentList &TemplateArgs) { + + // Do substitution on the type of the declaration + TypeSourceInfo *DI = + SubstType(PatternDecl->getTypeSourceInfo(), TemplateArgs, + PatternDecl->getTypeSpecStartLoc(), PatternDecl->getDeclName()); + if (!DI) + return 0; + + // Update the type of this variable template specialization. + VarSpec->setType(DI->getType()); + + // Instantiate the initializer. + InstantiateVariableInitializer(VarSpec, PatternDecl, TemplateArgs); + + return VarSpec; +} + +/// BuildVariableInstantiation - Used after a new variable has been created. +/// Sets basic variable data and decides whether to postpone the +/// variable instantiation. +void Sema::BuildVariableInstantiation( + VarDecl *NewVar, VarDecl *OldVar, + const MultiLevelTemplateArgumentList &TemplateArgs, + LateInstantiatedAttrVec *LateAttrs, + LocalInstantiationScope *StartingScope, + bool ForVarTemplate) { + + // If we are instantiating a static data member defined + // out-of-line, the instantiation will have the same lexical + // context (which will be a namespace scope) as the template. + if (OldVar->isOutOfLine()) + NewVar->setLexicalDeclContext(OldVar->getLexicalDeclContext()); + NewVar->setTSCSpec(OldVar->getTSCSpec()); + NewVar->setInitStyle(OldVar->getInitStyle()); + NewVar->setCXXForRangeDecl(OldVar->isCXXForRangeDecl()); + NewVar->setConstexpr(OldVar->isConstexpr()); + NewVar->setAccess(OldVar->getAccess()); + + if (!OldVar->isStaticDataMember()) { + NewVar->setUsed(OldVar->isUsed(false)); + NewVar->setReferenced(OldVar->isReferenced()); + } + + InstantiateAttrs(TemplateArgs, OldVar, NewVar, LateAttrs, StartingScope); + + if (NewVar->hasAttrs()) + CheckAlignasUnderalignment(NewVar); + + // FIXME: In theory, we could have a previous declaration for variables that + // are not static data members. + // FIXME: having to fake up a LookupResult is dumb. + LookupResult Previous(*this, NewVar->getDeclName(), NewVar->getLocation(), + Sema::LookupOrdinaryName, Sema::ForRedeclaration); + + if (!isa<VarTemplateSpecializationDecl>(NewVar)) + LookupQualifiedName(Previous, NewVar->getDeclContext(), false); + + CheckVariableDeclaration(NewVar, Previous); + + if (OldVar->isOutOfLine()) { + OldVar->getLexicalDeclContext()->addDecl(NewVar); + if (!ForVarTemplate) + NewVar->getDeclContext()->makeDeclVisibleInContext(NewVar); + } else { + if (!ForVarTemplate) + NewVar->getDeclContext()->addDecl(NewVar); + if (NewVar->getDeclContext()->isFunctionOrMethod()) + CurrentInstantiationScope->InstantiatedLocal(OldVar, NewVar); + } + + // Link instantiations of static data members back to the template from + // which they were instantiated. + if (NewVar->isStaticDataMember() && !ForVarTemplate) + NewVar->setInstantiationOfStaticDataMember(OldVar, + TSK_ImplicitInstantiation); + + if (isa<VarTemplateSpecializationDecl>(NewVar)) { + // Do not instantiate the variable just yet. + } else + InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs); + + // Diagnose unused local variables with dependent types, where the diagnostic + // will have been deferred. + if (!NewVar->isInvalidDecl() && + NewVar->getDeclContext()->isFunctionOrMethod() && !NewVar->isUsed() && + OldVar->getType()->isDependentType()) + DiagnoseUnusedDecl(NewVar); +} + +/// \brief Instantiate the initializer of a variable. +void Sema::InstantiateVariableInitializer( + VarDecl *Var, VarDecl *OldVar, + const MultiLevelTemplateArgumentList &TemplateArgs) { + + if (Var->getAnyInitializer()) + // We already have an initializer in the class. + return; + + if (OldVar->getInit()) { + if (Var->isStaticDataMember() && !OldVar->isOutOfLine()) + PushExpressionEvaluationContext(Sema::ConstantEvaluated, OldVar); + else + PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, OldVar); + + // Instantiate the initializer. + ExprResult Init = + SubstInitializer(OldVar->getInit(), TemplateArgs, + OldVar->getInitStyle() == VarDecl::CallInit); + if (!Init.isInvalid()) { + bool TypeMayContainAuto = true; + if (Init.get()) { + bool DirectInit = OldVar->isDirectInit(); + AddInitializerToDecl(Var, Init.take(), DirectInit, TypeMayContainAuto); + } else + ActOnUninitializedDecl(Var, TypeMayContainAuto); + } else { + // FIXME: Not too happy about invalidating the declaration + // because of a bogus initializer. + Var->setInvalidDecl(); + } + + PopExpressionEvaluationContext(); + } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) && + !Var->isCXXForRangeDecl()) + ActOnUninitializedDecl(Var, false); +} + /// \brief Instantiate the definition of the given variable from its /// template. /// @@ -3047,26 +3436,76 @@ void Sema::InstantiateStaticDataMemberDefinition( VarDecl *Var, bool Recursive, bool DefinitionRequired) { + InstantiateVariableDefinition(PointOfInstantiation, Var, Recursive, + DefinitionRequired); +} + +void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, + VarDecl *Var, bool Recursive, + bool DefinitionRequired) { + if (Var->isInvalidDecl()) return; - // Find the out-of-line definition of this static data member. + VarTemplateSpecializationDecl *VarSpec = + dyn_cast<VarTemplateSpecializationDecl>(Var); + assert((VarSpec || Var->isStaticDataMember()) && + "Not a static data member, nor a variable template specialization?"); + VarDecl *PatternDecl = 0; + + // If this is a variable template specialization, make sure that it is + // non-dependent, then find its instantiation pattern. + if (VarSpec) { + bool InstantiationDependent = false; + assert(!TemplateSpecializationType::anyDependentTemplateArguments( + VarSpec->getTemplateArgsInfo(), InstantiationDependent) && + "Only instantiate variable template specializations that are " + "not type-dependent"); + + // Find the variable initialization that we'll be substituting. + assert(VarSpec->getSpecializedTemplate() && + "Specialization without specialized template?"); + llvm::PointerUnion<VarTemplateDecl *, + VarTemplatePartialSpecializationDecl *> PatternPtr = + VarSpec->getSpecializedTemplateOrPartial(); + if (PatternPtr.is<VarTemplatePartialSpecializationDecl *>()) + PatternDecl = cast<VarDecl>( + PatternPtr.get<VarTemplatePartialSpecializationDecl *>()); + else + PatternDecl = (PatternPtr.get<VarTemplateDecl *>())->getTemplatedDecl(); + assert(PatternDecl && "instantiating a non-template"); + } + + // If this is a static data member, find its out-of-line definition. VarDecl *Def = Var->getInstantiatedFromStaticDataMember(); - assert(Def && "This data member was not instantiated from a template?"); - assert(Def->isStaticDataMember() && "Not a static data member?"); - Def = Def->getOutOfLineDefinition(); - - if (!Def) { - // We did not find an out-of-line definition of this static data member, - // so we won't perform any instantiation. Rather, we rely on the user to - // instantiate this definition (or provide a specialization for it) in - // another translation unit. + if (Var->isStaticDataMember()) { + assert(Def && "This data member was not instantiated from a template?"); + assert(Def->isStaticDataMember() && "Not a static data member?"); + Def = Def->getOutOfLineDefinition(); + } + + // If the instantiation pattern does not have an initializer, or if an + // out-of-line definition is not found, we won't perform any instantiation. + // Rather, we rely on the user to instantiate this definition (or provide + // a specialization for it) in another translation unit. + if ((VarSpec && !PatternDecl->getInit()) || + (!VarSpec && Var->isStaticDataMember() && !Def)) { if (DefinitionRequired) { - Def = Var->getInstantiatedFromStaticDataMember(); - Diag(PointOfInstantiation, - diag::err_explicit_instantiation_undefined_member) - << 2 << Var->getDeclName() << Var->getDeclContext(); - Diag(Def->getLocation(), diag::note_explicit_instantiation_here); + if (!Var->isStaticDataMember()) { + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_var_template) + << PatternDecl; + Diag(PatternDecl->getLocation(), + diag::note_explicit_instantiation_here); + } else { + Def = Var->getInstantiatedFromStaticDataMember(); + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_member) + << 3 << Var->getDeclName() << Var->getDeclContext(); + Diag(Def->getLocation(), diag::note_explicit_instantiation_here); + } + if (VarSpec) + Var->setInvalidDecl(); } else if (Var->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition) { PendingInstantiations.push_back( @@ -3086,6 +3525,11 @@ void Sema::InstantiateStaticDataMemberDefinition( // Except for inline functions, other explicit instantiation declarations // have the effect of suppressing the implicit instantiation of the entity // to which they refer. + // + // C++11 [temp.explicit]p10: + // Except for inline functions, [...] explicit instantiation declarations + // have the effect of suppressing the implicit instantiation of the entity + // to which they refer. if (TSK == TSK_ExplicitInstantiationDeclaration) return; @@ -3098,17 +3542,24 @@ void Sema::InstantiateStaticDataMemberDefinition( : Consumer(Consumer), Var(Var) { } ~PassToConsumerRAII() { - Consumer.HandleCXXStaticMemberVarInstantiation(Var); + if (Var->isStaticDataMember()) + Consumer.HandleCXXStaticMemberVarInstantiation(Var); + else { + DeclGroupRef DG(Var); + Consumer.HandleTopLevelDecl(DG); + } } } PassToConsumerRAII(Consumer, Var); - // If we already have a definition, we're done. - if (VarDecl *Def = Var->getDefinition()) { - // We may be explicitly instantiating something we've already implicitly - // instantiated. - Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(), - PointOfInstantiation); - return; + if (!VarSpec) { + // If we already have a definition, we're done. + if (VarDecl *Def = Var->getDefinition()) { + // We may be explicitly instantiating something we've already implicitly + // instantiated. + Def->setTemplateSpecializationKind(Var->getTemplateSpecializationKind(), + PointOfInstantiation); + return; + } } InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); @@ -3127,22 +3578,41 @@ void Sema::InstantiateStaticDataMemberDefinition( // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. - ContextRAII previousContext(*this, Var->getDeclContext()); + ContextRAII PreviousContext(*this, Var->getDeclContext()); LocalInstantiationScope Local(*this); - + VarDecl *OldVar = Var; - Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(), - getTemplateInstantiationArgs(Var))); + if (!VarSpec) + Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(), + getTemplateInstantiationArgs(Var))); + else + // Construct a VarTemplateSpecializationDecl to avoid name clashing with + // the primary template. (Note that unlike function declarations, variable + // declarations cannot be overloaded.) + // In fact, there is no need to construct a new declaration from scratch. + // Thus, simply complete its definition with an appropriately substituted + // type and initializer. + Var = CompleteVarTemplateSpecializationDecl( + VarSpec, PatternDecl, getTemplateInstantiationArgs(Var)); - previousContext.pop(); + PreviousContext.pop(); if (Var) { - PassToConsumerRAII.Var = Var; MemberSpecializationInfo *MSInfo = OldVar->getMemberSpecializationInfo(); - assert(MSInfo && "Missing member specialization information?"); - Var->setTemplateSpecializationKind(MSInfo->getTemplateSpecializationKind(), - MSInfo->getPointOfInstantiation()); + if (!VarSpec) + assert(MSInfo && "Missing member specialization information?"); + + PassToConsumerRAII.Var = Var; + if (MSInfo) + Var->setTemplateSpecializationKind( + MSInfo->getTemplateSpecializationKind(), + MSInfo->getPointOfInstantiation()); } + + // This variable may have local implicit instantiations that need to be + // instantiated within this scope. + PerformPendingInstantiations(/*LocalOnly=*/true); + Local.Exit(); if (Recursive) { @@ -3155,14 +3625,12 @@ void Sema::InstantiateStaticDataMemberDefinition( // Restore the set of pending vtables. assert(VTableUses.empty() && - "VTableUses should be empty before it is discarded, " - "while instantiating static data member."); + "VTableUses should be empty before it is discarded."); VTableUses.swap(SavedVTableUses); // Restore the set of pending implicit instantiations. assert(PendingInstantiations.empty() && - "PendingInstantiations should be empty before it is discarded, " - "while instantiating static data member."); + "PendingInstantiations should be empty before it is discarded."); PendingInstantiations.swap(SavedPendingInstantiations); } } @@ -3593,6 +4061,20 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, return cast<LabelDecl>(Inst); } + // For variable template specializations, update those that are still + // type-dependent. + if (VarTemplateSpecializationDecl *VarSpec = + dyn_cast<VarTemplateSpecializationDecl>(D)) { + bool InstantiationDependent = false; + const TemplateArgumentListInfo &VarTemplateArgs = + VarSpec->getTemplateArgsInfo(); + if (TemplateSpecializationType::anyDependentTemplateArguments( + VarTemplateArgs, InstantiationDependent)) + D = cast<NamedDecl>( + SubstDecl(D, VarSpec->getDeclContext(), TemplateArgs)); + return D; + } + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(D)) { if (!Record->isDependentContext()) return D; @@ -3605,7 +4087,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, else if (ClassTemplatePartialSpecializationDecl *PartialSpec = dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) ClassTemplate = PartialSpec->getSpecializedTemplate()->getCanonicalDecl(); - + // Walk the current context to find either the record or an instantiation of // it. DeclContext *DC = CurContext; @@ -3614,7 +4096,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // definition, we'll find our own context. We're done. if (DC->Equals(Record)) return Record; - + if (CXXRecordDecl *InstRecord = dyn_cast<CXXRecordDecl>(DC)) { // Check whether we're in the process of instantiating a class template // specialization of the template we're mapping. @@ -3624,13 +4106,12 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (ClassTemplate && isInstantiationOf(ClassTemplate, SpecTemplate)) return InstRecord; } - + // Check whether we're in the process of instantiating a member class. if (isInstantiationOf(Record, InstRecord)) return InstRecord; } - - + // Move to the outer template scope. if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) { if (FD->getFriendObjectKind() && FD->getDeclContext()->isFileContext()){ @@ -3638,7 +4119,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, continue; } } - + DC = DC->getParent(); } @@ -3771,9 +4252,13 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { continue; } - // Instantiate static data member definitions. + // Instantiate variable definitions VarDecl *Var = cast<VarDecl>(Inst.first); - assert(Var->isStaticDataMember() && "Not a static data member?"); + + assert((Var->isStaticDataMember() || + isa<VarTemplateSpecializationDecl>(Var)) && + "Not a static data member, nor a variable template" + " specialization?"); // Don't try to instantiate declarations if the most recent redeclaration // is invalid. @@ -3796,14 +4281,15 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { break; } - PrettyDeclStackTraceEntry CrashInfo(*this, Var, Var->getLocation(), - "instantiating static data member " - "definition"); - + PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(), + "instantiating variable definition"); bool DefinitionRequired = Var->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition; - InstantiateStaticDataMemberDefinition(/*FIXME:*/Inst.second, Var, true, - DefinitionRequired); + + // Instantiate static data member definitions or variable template + // specializations. + InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true, + DefinitionRequired); } } diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index 24b268f36df..79bba0cb94f 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -158,6 +158,8 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::CXXRecord: case Decl::ClassTemplateSpecialization: case Decl::ClassTemplatePartialSpecialization: + case Decl::VarTemplateSpecialization: + case Decl::VarTemplatePartialSpecialization: case Decl::Function: case Decl::CXXMethod: case Decl::CXXConstructor: @@ -166,6 +168,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::Var: case Decl::FunctionTemplate: case Decl::ClassTemplate: + case Decl::VarTemplate: case Decl::TypeAliasTemplate: case Decl::ObjCProtocol: case Decl::ObjCInterface: diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 122865b4686..6694192c880 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -239,6 +239,13 @@ namespace clang { ClassTemplatePartialSpecializationDecl *D); void VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *D); + RedeclarableResult + VisitVarTemplateSpecializationDeclImpl(VarTemplateSpecializationDecl *D); + void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) { + VisitVarTemplateSpecializationDeclImpl(D); + } + void VisitVarTemplatePartialSpecializationDecl( + VarTemplatePartialSpecializationDecl *D); void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitValueDecl(ValueDecl *VD); void VisitEnumConstantDecl(EnumConstantDecl *ECD); @@ -252,13 +259,15 @@ namespace clang { void VisitFieldDecl(FieldDecl *FD); void VisitMSPropertyDecl(MSPropertyDecl *FD); void VisitIndirectFieldDecl(IndirectFieldDecl *FD); - void VisitVarDecl(VarDecl *VD); + RedeclarableResult VisitVarDeclImpl(VarDecl *D); + void VisitVarDecl(VarDecl *VD) { VisitVarDeclImpl(VD); } void VisitImplicitParamDecl(ImplicitParamDecl *PD); void VisitParmVarDecl(ParmVarDecl *PD); void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); void VisitTemplateDecl(TemplateDecl *D); RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); void VisitClassTemplateDecl(ClassTemplateDecl *D); + void VisitVarTemplateDecl(VarTemplateDecl *D); void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); @@ -917,7 +926,7 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { FD->Chaining[I] = ReadDeclAs<NamedDecl>(Record, Idx); } -void ASTDeclReader::VisitVarDecl(VarDecl *VD) { +ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { RedeclarableResult Redecl = VisitRedeclarable(VD); VisitDeclaratorDecl(VD); @@ -950,6 +959,8 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) { SourceLocation POI = ReadSourceLocation(Record, Idx); Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI); } + + return Redecl; } void ASTDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) { @@ -1418,6 +1429,40 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { } } +void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) { + RedeclarableResult Redecl = VisitRedeclarableTemplateDecl(D); + + if (ThisDeclID == Redecl.getFirstID()) { + // This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of + // the specializations. + SmallVector<serialization::DeclID, 2> SpecIDs; + SpecIDs.push_back(0); + + // Specializations. + unsigned Size = Record[Idx++]; + SpecIDs[0] += Size; + for (unsigned I = 0; I != Size; ++I) + SpecIDs.push_back(ReadDeclID(Record, Idx)); + + // Partial specializations. + Size = Record[Idx++]; + SpecIDs[0] += Size; + for (unsigned I = 0; I != Size; ++I) + SpecIDs.push_back(ReadDeclID(Record, Idx)); + + VarTemplateDecl::Common *CommonPtr = D->getCommonPtr(); + if (SpecIDs[0]) { + typedef serialization::DeclID DeclID; + + // FIXME: Append specializations! + CommonPtr->LazySpecializations = + new (Reader.getContext()) DeclID[SpecIDs.size()]; + memcpy(CommonPtr->LazySpecializations, SpecIDs.data(), + SpecIDs.size() * sizeof(DeclID)); + } + } +} + ASTDeclReader::RedeclarableResult ASTDeclReader::VisitClassTemplateSpecializationDeclImpl( ClassTemplateSpecializationDecl *D) { @@ -1528,6 +1573,89 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { } } +ASTDeclReader::RedeclarableResult +ASTDeclReader::VisitVarTemplateSpecializationDeclImpl( + VarTemplateSpecializationDecl *D) { + RedeclarableResult Redecl = VisitVarDeclImpl(D); + + ASTContext &C = Reader.getContext(); + if (Decl *InstD = ReadDecl(Record, Idx)) { + if (VarTemplateDecl *VTD = dyn_cast<VarTemplateDecl>(InstD)) { + D->SpecializedTemplate = VTD; + } else { + SmallVector<TemplateArgument, 8> TemplArgs; + Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx); + TemplateArgumentList *ArgList = TemplateArgumentList::CreateCopy( + C, TemplArgs.data(), TemplArgs.size()); + VarTemplateSpecializationDecl::SpecializedPartialSpecialization *PS = + new (C) + VarTemplateSpecializationDecl::SpecializedPartialSpecialization(); + PS->PartialSpecialization = + cast<VarTemplatePartialSpecializationDecl>(InstD); + PS->TemplateArgs = ArgList; + D->SpecializedTemplate = PS; + } + } + + // Explicit info. + if (TypeSourceInfo *TyInfo = GetTypeSourceInfo(Record, Idx)) { + VarTemplateSpecializationDecl::ExplicitSpecializationInfo *ExplicitInfo = + new (C) VarTemplateSpecializationDecl::ExplicitSpecializationInfo; + ExplicitInfo->TypeAsWritten = TyInfo; + ExplicitInfo->ExternLoc = ReadSourceLocation(Record, Idx); + ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(Record, Idx); + D->ExplicitInfo = ExplicitInfo; + } + + SmallVector<TemplateArgument, 8> TemplArgs; + Reader.ReadTemplateArgumentList(TemplArgs, F, Record, Idx); + D->TemplateArgs = + TemplateArgumentList::CreateCopy(C, TemplArgs.data(), TemplArgs.size()); + D->PointOfInstantiation = ReadSourceLocation(Record, Idx); + D->SpecializationKind = (TemplateSpecializationKind)Record[Idx++]; + + bool writtenAsCanonicalDecl = Record[Idx++]; + if (writtenAsCanonicalDecl) { + VarTemplateDecl *CanonPattern = ReadDeclAs<VarTemplateDecl>(Record, Idx); + if (D->isCanonicalDecl()) { // It's kept in the folding set. + if (VarTemplatePartialSpecializationDecl *Partial = + dyn_cast<VarTemplatePartialSpecializationDecl>(D)) { + Partial->SequenceNumber = + CanonPattern->getNextPartialSpecSequenceNumber(); + CanonPattern->getCommonPtr()->PartialSpecializations + .GetOrInsertNode(Partial); + } else { + CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D); + } + } + } + + return Redecl; +} + +void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl( + VarTemplatePartialSpecializationDecl *D) { + RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D); + + ASTContext &C = Reader.getContext(); + D->TemplateParams = Reader.ReadTemplateParameterList(F, Record, Idx); + + unsigned NumArgs = Record[Idx++]; + if (NumArgs) { + D->NumArgsAsWritten = NumArgs; + D->ArgsAsWritten = new (C) TemplateArgumentLoc[NumArgs]; + for (unsigned i = 0; i != NumArgs; ++i) + D->ArgsAsWritten[i] = Reader.ReadTemplateArgumentLoc(F, Record, Idx); + } + + // These are read/set from/to the first declaration. + if (ThisDeclID == Redecl.getFirstID()) { + D->InstantiatedFromMember.setPointer( + ReadDeclAs<VarTemplatePartialSpecializationDecl>(Record, Idx)); + D->InstantiatedFromMember.setInt(Record[Idx++]); + } +} + void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { VisitTypeDecl(D); @@ -2178,6 +2306,15 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION: D = ClassTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID); break; + case DECL_VAR_TEMPLATE: + D = VarTemplateDecl::CreateDeserialized(Context, ID); + break; + case DECL_VAR_TEMPLATE_SPECIALIZATION: + D = VarTemplateSpecializationDecl::CreateDeserialized(Context, ID); + break; + case DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION: + D = VarTemplatePartialSpecializationDecl::CreateDeserialized(Context, ID); + break; case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION: D = ClassScopeFunctionSpecializationDecl::CreateDeserialized(Context, ID); break; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 08d7f96fadd..142e7b12671 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -946,6 +946,9 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(DECL_CLASS_TEMPLATE); RECORD(DECL_CLASS_TEMPLATE_SPECIALIZATION); RECORD(DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION); + RECORD(DECL_VAR_TEMPLATE); + RECORD(DECL_VAR_TEMPLATE_SPECIALIZATION); + RECORD(DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION); RECORD(DECL_FUNCTION_TEMPLATE); RECORD(DECL_TEMPLATE_TYPE_PARM); RECORD(DECL_NON_TYPE_TEMPLATE_PARM); @@ -5235,6 +5238,19 @@ void ASTWriter::AddedCXXTemplateSpecialization(const ClassTemplateDecl *TD, Record.push_back(reinterpret_cast<uint64_t>(D)); } +void ASTWriter::AddedCXXTemplateSpecialization( + const VarTemplateDecl *TD, const VarTemplateSpecializationDecl *D) { + // The specializations set is kept in the canonical template. + assert(!WritingAST && "Already writing the AST!"); + TD = TD->getCanonicalDecl(); + if (!(!D->isFromASTFile() && TD->isFromASTFile())) + return; // Not a source specialization added to a template from PCH. + + UpdateRecord &Record = DeclUpdates[TD]; + Record.push_back(UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION); + Record.push_back(reinterpret_cast<uint64_t>(D)); +} + void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, const FunctionDecl *D) { // The specializations set is kept in the canonical template. diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 87398e99aec..a3e883f057e 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -68,6 +68,9 @@ namespace clang { ClassTemplateSpecializationDecl *D); void VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D); + void VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D); + void VisitVarTemplatePartialSpecializationDecl( + VarTemplatePartialSpecializationDecl *D); void VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *D); void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); @@ -90,6 +93,7 @@ namespace clang { void VisitTemplateDecl(TemplateDecl *D); void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D); void VisitClassTemplateDecl(ClassTemplateDecl *D); + void VisitVarTemplateDecl(VarTemplateDecl *D); void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); @@ -1184,6 +1188,87 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl( Code = serialization::DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION; } +void ASTDeclWriter::VisitVarTemplateDecl(VarTemplateDecl *D) { + VisitRedeclarableTemplateDecl(D); + + if (D->isFirstDeclaration()) { + typedef llvm::FoldingSetVector<VarTemplateSpecializationDecl> VTSDSetTy; + VTSDSetTy &VTSDSet = D->getSpecializations(); + Record.push_back(VTSDSet.size()); + for (VTSDSetTy::iterator I = VTSDSet.begin(), E = VTSDSet.end(); I != E; + ++I) { + assert(I->isCanonicalDecl() && "Expected only canonical decls in set"); + Writer.AddDeclRef(&*I, Record); + } + + typedef llvm::FoldingSetVector<VarTemplatePartialSpecializationDecl> + VTPSDSetTy; + VTPSDSetTy &VTPSDSet = D->getPartialSpecializations(); + Record.push_back(VTPSDSet.size()); + for (VTPSDSetTy::iterator I = VTPSDSet.begin(), E = VTPSDSet.end(); I != E; + ++I) { + assert(I->isCanonicalDecl() && "Expected only canonical decls in set"); + Writer.AddDeclRef(&*I, Record); + } + } + Code = serialization::DECL_VAR_TEMPLATE; +} + +void ASTDeclWriter::VisitVarTemplateSpecializationDecl( + VarTemplateSpecializationDecl *D) { + VisitVarDecl(D); + + llvm::PointerUnion<VarTemplateDecl *, VarTemplatePartialSpecializationDecl *> + InstFrom = D->getSpecializedTemplateOrPartial(); + if (Decl *InstFromD = InstFrom.dyn_cast<VarTemplateDecl *>()) { + Writer.AddDeclRef(InstFromD, Record); + } else { + Writer.AddDeclRef(InstFrom.get<VarTemplatePartialSpecializationDecl *>(), + 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()); + Record.push_back(D->isCanonicalDecl()); + + if (D->isCanonicalDecl()) { + // When reading, we'll add it to the folding set of the following template. + Writer.AddDeclRef(D->getSpecializedTemplate()->getCanonicalDecl(), Record); + } + + Code = serialization::DECL_VAR_TEMPLATE_SPECIALIZATION; +} + +void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl( + VarTemplatePartialSpecializationDecl *D) { + VisitVarTemplateSpecializationDecl(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->getPreviousDecl() == 0) { + Writer.AddDeclRef(D->getInstantiatedFromMember(), Record); + Record.push_back(D->isMemberSpecialization()); + } + + Code = serialization::DECL_VAR_TEMPLATE_PARTIAL_SPECIALIZATION; +} + void ASTDeclWriter::VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *D) { VisitDecl(D); diff --git a/clang/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp b/clang/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp index 2eae1125c0d..8a3168e5f80 100644 --- a/clang/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.class/temp.static/p1.cpp @@ -23,4 +23,4 @@ X2& get_X2() { return X0<X2>::value; // expected-note{{instantiation}} } -template<typename T> T x; // expected-error{{variable 'x' declared as a template}} +template<typename T> T x; // expected-warning{{variable templates are a C++1y extension}} diff --git a/clang/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp b/clang/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp new file mode 100644 index 00000000000..4cff1e2e9df --- /dev/null +++ b/clang/test/CXX/temp/temp.spec/cxx1y-variable-template-no-body.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 --std=c++1y -fsyntax-only -verify %s +// RUN: cp %s %t +// RUN: not %clang_cc1 --std=c++1y -x c++ -fixit %t -DFIXING +// RUN: %clang_cc1 --std=c++1y -x c++ %t -DFIXING + +template<typename T> +T pi = T(3.1415926535897932385); // expected-note {{template is declared here}} + +template int pi<int>; + +#ifndef FIXING +template float pi; // expected-error {{too few template arguments for template 'pi'}} +template double pi_var0; // expected-error {{explicit instantiation of 'pi_var0' does not refer to a function template, variable template, member function, member class, or static data member}} +#endif + +// Should recover as if definition +template double pi_var = 5; // expected-error {{variable cannot be defined in an explicit instantiation; if this declaration is meant to be a variable definition, remove the 'template' keyword}} +#ifndef FIXING +template<typename T> +T pi0 = T(3.1415926535897932385); // expected-note {{previous definition is here}} + +template int pi0 = 10; // expected-error {{variable cannot be defined in an explicit instantiation; if this declaration is meant to be a variable definition, remove the 'template' keyword}} \ + expected-error{{redefinition of 'pi0' with a different type: 'int' vs 'T'}} +#endif + +template<typename T> +T pi1 = T(3.1415926535897932385); + +// Should recover as if specialization +template float pi1<float> = 1.0; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} +#ifndef FIXING +namespace expected_global { + template<> double pi1<double> = 1.5; // expected-error {{no variable template matches specialization}} + template int pi1<int> = 10; // expected-error {{explicit template instantiation cannot have a definition; if this definition is meant to be an explicit specialization, add '<>' after the 'template' keyword}} \ + expected-error {{no variable template matches specialization}} +} +#endif diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp index aecbfb5649f..3844ec99458 100644 --- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp +++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/examples.cpp @@ -163,7 +163,8 @@ namespace PR9877 { template<> struct X<1>::Y { static const int Z = 1; }; const int X<0>::Y::Z; - template<> const int X<1>::Y::Z; // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}} + template<> const int X<1>::Y::Z; // expected-error{{extraneous 'template<>' in declaration of variable 'Z'}} \ + // expected-error{{forward declaration of variable template cannot have a nested name specifier}} } namespace PR9913 { diff --git a/clang/test/SemaCXX/conversion-function.cpp b/clang/test/SemaCXX/conversion-function.cpp index 0e7c3916171..7eaed54934b 100644 --- a/clang/test/SemaCXX/conversion-function.cpp +++ b/clang/test/SemaCXX/conversion-function.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -verify %s class X { public: operator bool(); diff --git a/clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp b/clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp new file mode 100644 index 00000000000..7f2823c5c2c --- /dev/null +++ b/clang/test/SemaCXX/cxx1y-variable-templates_in_class.cpp @@ -0,0 +1,159 @@ +// RUN: %clang_cc1 -verify -fsyntax-only %s -Wno-c++11-extensions -Wno-c++1y-extensions -DPRECXX11 +// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only -Wno-c++1y-extensions %s +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s + +class A { + template<typename T> const T wrong; // expected-error {{member 'wrong' declared as a template}} + template<typename T> const T wrong_init = 5; // expected-error {{member 'wrong_init' declared as a template}} + template<typename T, typename T0> static const T right = T(100); + template<typename T> static const T right<T,int> = 5; + template<typename T> const int right<int,T>; // expected-error {{member 'right' declared as a template}} + template<typename T> const float right<float,T> = 5; // expected-error {{member 'right' declared as a template}} + template<> static const int right<int,int> = 7; // expected-error {{explicit specialization of 'right' in class scope}} + template<> static const float right<float,int>; // expected-error {{explicit specialization of 'right' in class scope}} + template static const int right<int,int>; // expected-error {{template specialization requires 'template<>'}} \ + // expected-error {{explicit specialization of 'right' in class scope}} +}; + +namespace out_of_line { + class B0 { + template<typename T, typename T0> static const T right = T(100); + template<typename T> static const T right<T,int> = T(5); + }; + template<> const int B0::right<int,int> = 7; + template const int B0::right<int,int>; + template<> const int B0::right<int,float>; + template const int B0::right<int,float>; + + class B1 { + template<typename T, typename T0> static const T right; + template<typename T> static const T right<T,int>; + }; + template<typename T, typename T0> const T B1::right = T(100); + template<typename T> const T B1::right<T,int> = T(5); + + class B2 { + template<typename T, typename T0> static const T right = T(100); // expected-note {{previous definition is here}} + template<typename T> static const T right<T,int> = T(5); // expected-note {{previous definition is here}} + }; + template<typename T, typename T0> const T B2::right = T(100); // expected-error {{redefinition of 'right'}} + template<typename T> const T B2::right<T,int> = T(5); // expected-error {{redefinition of 'right'}} + + class B3 { + template<typename T, typename T0> static const T right = T(100); + template<typename T> static const T right<T,int> = T(5); + }; + template<typename T, typename T0> const T B3::right; // expected-error {{forward declaration of variable template cannot have a nested name specifier}} + template<typename T> const T B3::right<T,int>; // expected-error {{forward declaration of variable template partial specialization cannot have a nested name specifier}} + + class B4 { + template<typename T, typename T0> static const T right; + template<typename T> static const T right<T,int>; + template<typename T, typename T0> static const T right_def = T(100); + template<typename T> static const T right_def<T,int>; // expected-note {{explicit instantiation refers here}} + }; + template<typename T, typename T0> const T B4::right; // expected-error {{forward declaration of variable template cannot have a nested name specifier}} + template<typename T> const T B4::right<T,int>; // expected-error {{forward declaration of variable template partial specialization cannot have a nested name specifier}} \ + // expected-note {{explicit instantiation refers here}} + template const int B4::right<int,int>; // expected-error {{explicit instantiation of undefined static data member template 'right' of class}} + template const int B4::right_def<int,int>; // expected-error {{explicit instantiation of undefined static data member template 'right_def' of class}} +} + +namespace non_const_init { + class A { + template<typename T> static T wrong_inst = T(10); // expected-error {{non-const static data member must be initialized out of line}} + template<typename T> static T wrong_inst_fixed; + }; + template int A::wrong_inst<int>; // expected-note {{in instantiation of static data member 'non_const_init::A::wrong_inst<int>' requested here}} + template<typename T> T A::wrong_inst_fixed = T(10); + template int A::wrong_inst_fixed<int>; + + class B { + template<typename T> static T wrong_inst; + template<typename T> static T wrong_inst<T*> = T(100); // expected-error {{non-const static data member must be initialized out of line}} + + template<typename T> static T wrong_inst_fixed; + template<typename T> static T wrong_inst_fixed<T*>; + }; + template int B::wrong_inst<int*>; // expected-note {{in instantiation of static data member 'non_const_init::B::wrong_inst<int *>' requested here}} + template<typename T> T B::wrong_inst_fixed = T(100); + template int B::wrong_inst_fixed<int>; + + class C { + template<typename T> static const T right_inst = T(10); + template<typename T> static const T right_inst<T*> = T(100); + }; + template const int C::right_inst<int>; + template const int C::right_inst<int*>; + + namespace pointers { + + struct C0 { + template<typename U> static U Data; + template<typename U> static const U Data<U*> = U(); // Okay + }; + template const int C0::Data<int*>; + + struct C1a { + template<typename U> static U Data; + template<typename U> static U* Data<U>; // Okay, with out-of-line definition + }; + template<typename T> T* C1a::Data<T> = new T(); + template int* C1a::Data<int>; + + struct C1b { + template<typename U> static U Data; + template<typename U> static const U* Data<U>; // Okay, with out-of-line definition + }; + template<typename T> const T* C1b::Data<T> = (T*)(0); + template const int* C1b::Data<int>; + + struct C2a { + template<typename U> static U Data; + template<typename U> static U* Data<U> = new U(); // expected-error {{non-const static data member must be initialized out of line}} + }; + template int* C2a::Data<int>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2a::Data<int>' requested here}} + + struct C2b { // FIXME: ?!? Should this be an error? pointer-types are automatically non-const? + template<typename U> static U Data; + template<typename U> static const U* Data<U> = (U*)(0); // expected-error {{non-const static data member must be initialized out of line}} + }; + template const int* C2b::Data<int>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2b::Data<int>' requested here}} + } +} + +struct matrix_constants { + // TODO: (?) +}; + +namespace in_class_template { + // FIXME: member data templates of class templates are not well supported yet. + + template<typename T> + class D0 { + template<typename U> static U Data; + template<typename U> static const U Data<U*> = U(); + }; + + template<typename T> + class D1 { + template<typename U> static U Data; + template<typename U> static U* Data<U*>; + }; + template<typename T> + template<typename U> U* D1<T>::Data<U*> = (U*)(0); + + namespace to_be_fixed { + // FIXME: The following generate runtime exceptions! + + //template<> + //template<typename U> U* D1<float>::Data<U*> = (U*)(0) + 1; + //template const int D0<float>::Data<int*>; + //template int* D1<float>::Data<int*>; + } +} + +namespace in_nested_classes { + // TODO: +} + diff --git a/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp b/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp new file mode 100644 index 00000000000..66ee4e1d4ab --- /dev/null +++ b/clang/test/SemaCXX/cxx1y-variable-templates_top_level.cpp @@ -0,0 +1,415 @@ +// RUN: %clang_cc1 -verify -fsyntax-only -Wno-c++11-extensions -Wno-c++1y-extensions %s +// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only -Wno-c++1y-extensions %s -DCXX11 +// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s -DCXX11 + +#ifdef CXX11 + #define CONST constexpr +#else + #define CONST const +#endif + +template<typename T> +T pi = T(3.1415926535897932385); // expected-note {{template is declared here}} + +template<typename T> +CONST T cpi = T(3.1415926535897932385); // expected-note {{template is declared here}} + +namespace use_in_top_level_funcs { + + void good() { + int ipi = pi<int>; + int icpi = cpi<int>; + double dpi = pi<double>; + double dcpi = cpi<double>; + } + + void no_deduce() { + // template arguments are not deduced for uses of variable templates. + int ipi = pi; // expected-error {{cannot refer to variable template 'pi' without a template argument list}} + int icpi = cpi; // expected-error {{cannot refer to variable template 'cpi' without a template argument list}} + } + + template<typename T> + T circular_area(T r) { + return pi<T> * r * r; + } + + template<typename T> + CONST T const_circular_area(T r) { + return cpi<T> * r * r; + } + + double use_circular_area(double r) { + CONST float t = const_circular_area(2.0) - 12; +#ifdef CXX11 + static_assert(const_circular_area(2) == 12, ""); + CONST int test = (t > 0) && (t < 1); + static_assert(test, ""); +#endif + return circular_area(r); + } +} + +namespace shadow { + void foo() { + int ipi0 = pi<int>; + int pi; + int a = pi; + int ipi = pi<int>; // expected-error {{expected '(' for function-style cast or type construction}} \ + // expected-error {{expected expression}} + } +} + +namespace odr_tmpl { + namespace pv_cvt { + int v; // expected-note {{previous definition is here}} + template<typename T> T v; // expected-error {{redefinition of 'v' as different kind of symbol}} + } + namespace pvt_cv { + template<typename T> T v; // expected-note {{previous definition is here}} + int v; // expected-error {{redefinition of 'v' with a different type: 'int' vs 'T'}} + } + namespace pvt_cvt { + template<typename T> T v0; // expected-note {{previous definition is here}} + template<typename T> T v0; // expected-error {{redefinition of 'v0'}} + + template<typename T> T v; // expected-note {{previous definition is here}} + template<typename T> int v; // expected-error {{redefinition of 'v'}} + + template<typename T> int v1; // expected-note {{previous template declaration is here}} + template<int I> int v1; // expected-error {{template parameter has a different kind in template redeclaration}} + } + namespace pvt_use { + template<typename T> T v; + v = 10; // expected-error {{C++ requires a type specifier for all declarations}} + } + + namespace pvt_diff_params { + // FIXME: (?) Redefinitions should simply be not allowed, whether the + // template parameters match or not. However, this current behaviour also + // matches that of class templates... + template<typename T, typename> T v; // expected-note 2{{previous template declaration is here}} + template<typename T> T v; // expected-error {{too few template parameters in template redeclaration}} + template<typename T, typename, typename> T v; // expected-error {{too many template parameters in template redeclaration}} + } + + namespace pvt_extern { + template<typename T> T v = T(); + template<typename T> extern T v; // redeclaration is allowed \ + // expected-note {{previous definition is here}} + template<typename T> extern int v; // expected-error {{redefinition of 'v' with a different type: 'int' vs 'T'}} + +#ifdef CXX11 + template<typename T> extern auto v; // expected-error {{declaration of variable 'v' with type 'auto' requires an initializer}} +#endif + } + +#ifdef CXX11 + namespace pvt_auto { + template<typename T> auto v0; // expected-error {{declaration of variable 'v0' with type 'auto' requires an initializer}} + template<typename T> auto v1 = T(); // expected-note {{previous definition is here}} + template<typename T> int v1; // expected-error {{redefinition of 'v1' with a different type: 'int' vs 'auto'}} + template<typename T> auto v2 = T(); // expected-note {{previous definition is here}} + template<typename T> T v2; // expected-error {{redefinition of 'v2'}} + template<typename T> auto v3 = T(); // expected-note {{previous definition is here}} + template<typename T> extern T v3; // expected-error {{redefinition of 'v3' with a different type: 'T' vs 'auto'}} + template<typename T> auto v4 = T(); + template<typename T> extern auto v4; // expected-error {{declaration of variable 'v4' with type 'auto' requires an initializer}} + } +#endif + +} + +namespace explicit_instantiation { + template<typename T> + T pi0a = T(3.1415926535897932385); // expected-note {{variable template 'pi0a' declared here}} + template float pi0a<int>; // expected-error {{type 'float' of explicit instantiation of 'pi0a' does not match expected type 'int'}} + + template<typename T> + T pi0b = T(3.1415926535897932385); // expected-note {{variable template 'pi0b' declared here}} + template CONST int pi0b<int>; // expected-error {{type 'const int' of explicit instantiation of 'pi0b' does not match expected type 'int'}} + + template<typename T> + T pi0c = T(3.1415926535897932385); // expected-note {{variable template 'pi0c' declared here}} + template int pi0c<const int>; // expected-error {{type 'int' of explicit instantiation of 'pi0c' does not match expected type 'const int'}} + + template<typename T> + T pi0 = T(3.1415926535897932385); + template int pi0<int>; // expected-note {{previous explicit instantiation is here}} + template int pi0<int>; // expected-error {{duplicate explicit instantiation of 'pi0<int>'}} + + template<typename T> + CONST T pi1a = T(3.1415926535897932385); // expected-note {{variable template 'pi1a' declared here}} + template int pi1a<int>; // expected-error {{type 'int' of explicit instantiation of 'pi1a' does not match expected type 'const int'}} + + template<typename T> + CONST T pi1b = T(3.1415926535897932385); // expected-note {{variable template 'pi1b' declared here}} + template int pi1b<const int>; // expected-error {{type 'int' of explicit instantiation of 'pi1b' does not match expected type 'const const int'}} + + template<typename T> + CONST T pi1 = T(3.1415926535897932385); + template CONST int pi1<int>; // expected-note {{previous explicit instantiation is here}} + template CONST int pi1<int>; // expected-error {{duplicate explicit instantiation of 'pi1<int>'}} + +#ifdef CXX11 + namespace auto_var { + template<typename T> auto var0 = T(); + template auto var0<int>; // expected-error {{'auto' variable template instantiation is not allowed}} + + template<typename T> auto var = T(); + template int var<int>; + } +#endif + + namespace extern_var { + // TODO: + } +} + +namespace explicit_specialization { + + namespace good { + template<typename T1, typename T2> + CONST int pi2 = 1; + + template<typename T> + CONST int pi2<T,int> = 2; + + template<typename T> + CONST int pi2<int,T> = 3; + + template<> CONST int pi2<int,int> = 4; + +#ifdef CXX11 + void foo() { + static_assert(pi2<int,int> == 4, ""); + static_assert(pi2<float,int> == 2, ""); + static_assert(pi2<int,float> == 3, ""); + static_assert(pi2<int,float> == pi2<int,double>, ""); + static_assert(pi2<float,float> == 1, ""); + static_assert(pi2<float,float> == pi2<float,double>, ""); + } +#endif + } + + namespace ambiguous { + + template<typename T1, typename T2> + CONST int pi2 = 1; + + template<typename T> + CONST int pi2<T,int> = 2; // expected-note {{partial specialization matches [with T = int]}} + + template<typename T> + CONST int pi2<int,T> = 3; // expected-note {{partial specialization matches [with T = int]}} + + void foo() { + int a = pi2<int,int>; // expected-error {{ambiguous partial specializations of 'pi2<int, int>'}} + } + } + + namespace type_changes { + + template<typename T> + T pi0 = T(3.1415926535897932385); + + template<> float pi0<int> = 10; + template<> int pi0<const int> = 10; + + template<typename T> + T pi1 = T(3.1415926535897932385); + template<> CONST int pi1<int> = 10; + + template<typename T> + T pi2 = T(3.1415926535897932385); + template<> int pi2<const int> = 10; + + template<typename T> + CONST T pi4 = T(3.1415926535897932385); + template<> int pi4<int> = 10; + } + + namespace redefinition { + template<typename T> + T pi0 = T(3.1415926535897932385); + + template<> int pi0<int> = 10; // expected-note 3{{previous definition is here}} +#ifdef CXX11 +// expected-note@-2 {{previous definition is here}} +#endif + template<> int pi0<int> = 10; // expected-error {{redefinition of 'pi0<int>'}} + template<> CONST int pi0<int> = 10; // expected-error {{redefinition of 'pi0' with a different type: 'const int' vs 'int'}} + template<> float pi0<int> = 10; // expected-error {{redefinition of 'pi0' with a different type: 'float' vs 'int'}} +#ifdef CXX11 + template<> auto pi0<int> = 10; // expected-error {{redefinition of 'pi0<int>'}} +#endif + + + template<typename T> + CONST T pi1 = T(3.1415926535897932385); + + template<> CONST int pi1<int> = 10; // expected-note {{previous definition is here}} + template<> CONST int pi1<int> = 10; // expected-error {{redefinition of 'pi1<int>'}} + } + + namespace before_instantiation { + template<typename T> + T pi0 = T(3.1415926535897932385); // expected-note {{variable template 'pi0' declared here}} + + template<> int pi0<int> = 10; + template int pi0<int>; + template float pi0<int>; // expected-error {{type 'float' of explicit instantiation of 'pi0' does not match expected type}} + + template<typename T1, typename T2> + CONST int pi2 = 1; + + template<typename T> CONST int pi2<T,int> = 2; + template CONST int pi2<int,int>; + } + namespace after_instantiation { + template<typename T> + T pi0 = T(3.1415926535897932385); + + template int pi0<int>; // expected-note 2{{explicit instantiation first required here}} + template<> int pi0<int> = 10; // expected-error {{explicit specialization of 'pi0' after instantiation}} + template<> float pi0<int>; // expected-error {{explicit specialization of 'pi0' after instantiation}} + + template<typename T1, typename T2> + CONST int pi2 = 1; + + template CONST int pi2<int,int>; + template<typename T> CONST int pi2<T,int> = 2; + } + +#ifdef CXX11 + namespace auto_var { + template<typename T, typename> auto var0 = T(); + template<typename T> auto var0<T,int> = T(); + template<> auto var0<int,int> = 7; + + template<typename T, typename> auto var = T(); + template<typename T> T var<T,int> = T(5); + template<> int var<int,int> = 7; + + void foo() { + int i0 = var0<int,int>; + int b = var<int,int>; + } + } +#endif + + namespace extern_var { + // TODO: + } + + namespace diff_type { + // TODO: + template<typename T> T var = T(); + template<typename T> T* var<T> = new T(); +#ifdef CXX11 + template<typename T> auto var<T*> = T(); // expected-note {{previous definition is here}} + template<typename T> T var<T*> = T(); // expected-error {{redefinition of 'var' with a different type: 'T' vs 'auto'}} +#endif + } +} + +namespace use_in_structs { + // TODO: +} + +namespace attributes { + // TODO: +} + +#ifdef CXX11 +namespace arrays { + template<typename T> + T* arr = new T[10]{T(10), T(23)}; + + float f = 10.5; + template<> float* arr<float> = &f; + + void bar() { + int *iarr = arr<int>; + iarr[0] = 1; + iarr[2] = 3; + iarr[6] = -2; + + float ff = *arr<float>; + float nof = arr<float>[3]; // No bounds-check in C++ + } +} +#endif + +namespace nested { + + namespace n0a { + template<typename T> + T pi0a = T(3.1415926535897932385); + } + + using namespace n0a; + int i0a = pi0a<int>; + + template float pi0a<float>; + float f0a = pi0a<float>; + + template<> double pi0a<double> = 5.2; + double d0a = pi0a<double>; + + namespace n0b { + template<typename T> + T pi0b = T(3.1415926535897932385); + } + + int i0b = n0b::pi0b<int>; + + template float n0b::pi0b<float>; + float f0b = n0b::pi0b<float>; + + template<> double n0b::pi0b<double> = 5.2; + double d0b = n0b::pi0b<double>; + + namespace n1 { + template<typename T> + T pi1a = T(3.1415926535897932385); +#ifdef CXX11 +// expected-note@-2 {{explicit instantiation refers here}} +#endif + + template<typename T> + T pi1b = T(3.1415926535897932385); // expected-note {{explicitly specialized declaration is here}} +#ifdef CXX11 +// expected-note@-2 {{explicit instantiation refers here}} +#endif + } + + namespace use_n1a { + using namespace n1; + int i1 = pi1a<int>; + + template float pi1a<float>; +#ifdef CXX11 +// expected-error@-2 {{explicit instantiation of 'pi1a<float>' not in a namespace enclosing 'n1'}} +#endif + float f1 = pi1a<float>; + + template<> double pi1a<double> = 5.2; // expected-error {{no variable template matches specialization}} + double d1 = pi1a<double>; + } + + namespace use_n1b { + int i1 = n1::pi1b<int>; + + template float n1::pi1b<float>; +#ifdef CXX11 +// expected-error@-2 {{explicit instantiation of 'pi1b<float>' not in a namespace enclosing 'n1'}} +#endif + float f1 = n1::pi1b<float>; + + template<> double n1::pi1b<double> = 5.2; // expected-error {{cannot define or redeclare 'pi1b' here because namespace 'use_n1b' does not enclose namespace 'n1'}} \ + // expected-error {{variable template specialization of 'pi1b' must originally be declared in namespace 'n1'}} + double d1 = n1::pi1b<double>; + } +} + diff --git a/clang/test/SemaCXX/cxx98-compat.cpp b/clang/test/SemaCXX/cxx98-compat.cpp index 7ab92f01d8d..eeef1364af1 100644 --- a/clang/test/SemaCXX/cxx98-compat.cpp +++ b/clang/test/SemaCXX/cxx98-compat.cpp @@ -1,5 +1,8 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s // RUN: %clang_cc1 -fsyntax-only -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -std=c++1y -Wc++98-c++11-compat -verify %s -DCXX1YCOMPAT + +#ifndef CXX1YCOMPAT namespace std { struct type_info; @@ -378,3 +381,77 @@ namespace rdar11736429 { X x; // expected-warning{{union member 'x' with a non-trivial constructor is incompatible with C++98}} }; } +#endif + +template<typename T> T var = T(10); +#ifdef CXX1YCOMPAT +// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}} +#else +// expected-warning@-4 {{variable templates are a C++1y extension}} +#endif + +template<typename T> T* var<T*> = new T(); +#ifdef CXX1YCOMPAT +// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}} +#else +// expected-warning@-4 {{variable templates are a C++1y extension}} +#endif + +template<> int var<int> = 10; +#ifdef CXX1YCOMPAT +// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}} +#else +// expected-warning@-4 {{variable templates are a C++1y extension}} +#endif + +template int var<int>; +float fvar = var<float>; + +class A { + template<typename T> static T var = T(10); +#ifdef CXX1YCOMPAT +// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}} +#else +// expected-warning@-4 {{variable templates are a C++1y extension}} +#endif + + template<typename T> static T* var<T*> = new T(); +#ifdef CXX1YCOMPAT +// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}} +#else +// expected-warning@-4 {{variable templates are a C++1y extension}} +#endif + +}; + +struct B { template<typename T> static T v; }; +#ifdef CXX1YCOMPAT +// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}} +#else +// expected-warning@-4 {{variable templates are a C++1y extension}} +#endif + +template<typename T> T B::v = T(); +#ifdef CXX1YCOMPAT +// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}} +#else +// expected-warning@-4 {{variable templates are a C++1y extension}} +#endif + +template<typename T> T* B::v<T*> = new T(); +#ifdef CXX1YCOMPAT +// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}} +#else +// expected-warning@-4 {{variable templates are a C++1y extension}} +#endif + +template<> int B::v<int> = 10; +#ifdef CXX1YCOMPAT +// expected-warning@-2 {{variable templates are incompatible with C++ standards before C++1y}} +#else +// expected-warning@-4 {{variable templates are a C++1y extension}} +#endif + +template int B::v<int>; +float fsvar = B::v<float>; + diff --git a/clang/test/SemaCXX/for-range-examples.cpp b/clang/test/SemaCXX/for-range-examples.cpp index 953c98b4c81..ca505e02455 100644 --- a/clang/test/SemaCXX/for-range-examples.cpp +++ b/clang/test/SemaCXX/for-range-examples.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 namespace value_range_detail { template<typename T> diff --git a/clang/test/SemaCXX/unknown-type-name.cpp b/clang/test/SemaCXX/unknown-type-name.cpp index ce5972bf2dc..f2c84df242f 100644 --- a/clang/test/SemaCXX/unknown-type-name.cpp +++ b/clang/test/SemaCXX/unknown-type-name.cpp @@ -93,14 +93,14 @@ template<typename T> int A<T>::h(T::type x, char) {} // expected-error{{missing template<typename T> int h(T::type, int); // expected-error{{missing 'typename'}} template<typename T> int h(T::type x, char); // expected-error{{missing 'typename'}} -template<typename T> int junk1(T::junk); // expected-error{{declared as a template}} +template<typename T> int junk1(T::junk); // expected-warning{{variable templates are a C++1y extension}} template<typename T> int junk2(T::junk) throw(); // expected-error{{missing 'typename'}} template<typename T> int junk3(T::junk) = delete; // expected-error{{missing 'typename'}} expected-warning{{C++11}} template<typename T> int junk4(T::junk j); // expected-error{{missing 'typename'}} // FIXME: We can tell this was intended to be a function because it does not // have a dependent nested name specifier. -template<typename T> int i(T::type, int()); // expected-error{{variable 'i' declared as a template}} +template<typename T> int i(T::type, int()); // expected-warning{{variable templates are a C++1y extension}} // FIXME: We know which type specifier should have been specified here. Provide // a fix-it to add 'typename A<T>::type' diff --git a/clang/test/SemaTemplate/class-template-decl.cpp b/clang/test/SemaTemplate/class-template-decl.cpp index fe23d924110..e65da2b312f 100644 --- a/clang/test/SemaTemplate/class-template-decl.cpp +++ b/clang/test/SemaTemplate/class-template-decl.cpp @@ -50,7 +50,9 @@ void f() { template<typename T> class X; // expected-error{{expression}} } -template<typename T> class X1 var; // expected-error{{declared as a template}} +template<typename T> class X1 var; // expected-warning{{variable templates are a C++1y extension}} \ + // expected-error {{variable has incomplete type 'class X1'}} \ + // expected-note {{forward declaration of 'X1'}} namespace M { } diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 20079510620..0db94d6121f 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -4582,7 +4582,9 @@ CXCursor clang_getCursorDefinition(CXCursor C) { return clang_getNullCursor(); } - case Decl::Var: { + case Decl::Var: + case Decl::VarTemplateSpecialization: + case Decl::VarTemplatePartialSpecialization: { // Ask the variable if it has a definition. if (const VarDecl *Def = cast<VarDecl>(D)->getDefinition()) return MakeCXCursor(Def, TU); @@ -4604,6 +4606,13 @@ CXCursor clang_getCursorDefinition(CXCursor C) { return clang_getNullCursor(); } + case Decl::VarTemplate: { + if (VarDecl *Def = + cast<VarTemplateDecl>(D)->getTemplatedDecl()->getDefinition()) + return MakeCXCursor(cast<VarDecl>(Def)->getDescribedVarTemplate(), TU); + return clang_getNullCursor(); + } + case Decl::Using: return MakeCursorOverloadedDeclRef(cast<UsingDecl>(D), D->getLocation(), TU); diff --git a/clang/tools/libclang/RecursiveASTVisitor.h b/clang/tools/libclang/RecursiveASTVisitor.h index 2668db54797..92a6dd743ee 100644 --- a/clang/tools/libclang/RecursiveASTVisitor.h +++ b/clang/tools/libclang/RecursiveASTVisitor.h @@ -395,6 +395,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); @@ -1418,6 +1419,57 @@ DEF_TRAVERSE_DECL(ClassTemplateDecl, { // it was instantiated, and thus should not be traversed. }) +// A helper method for traversing the implicit instantiations of a +// class template. +template <typename Derived> +bool RecursiveASTVisitor<Derived>::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; +} + +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 + // variable templates since they do not appear in the user code. The + // following code optionally traverses them. + // + // We only traverse the variable 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<typename Derived> @@ -1744,6 +1796,43 @@ 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 remains 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)); }) |