From da41d0cf5b8d5ea65f2a7aa7bbf1d9e706743659 Mon Sep 17 00:00:00 2001 From: Abramo Bagnara Date: Sat, 12 Jun 2010 08:15:14 +0000 Subject: [PATCH] Added template parameters info for out-of-line definitions of class template methods. llvm-svn: 105882 --- clang/include/clang/AST/Decl.h | 82 ++++++++++++++++++++++++++------- clang/lib/AST/Decl.cpp | 23 +++++++++ clang/lib/Sema/SemaDecl.cpp | 33 ++++++++++--- clang/lib/Sema/SemaTemplate.cpp | 13 ++++++ 4 files changed, 128 insertions(+), 23 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 1e507a5d25e5..2c7dfecab97d 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -28,6 +28,8 @@ class FunctionTemplateDecl; class Stmt; class CompoundStmt; class StringLiteral; +class NestedNameSpecifier; +class TemplateParameterList; class TemplateArgumentList; class MemberSpecializationInfo; class FunctionTemplateSpecializationInfo; @@ -364,15 +366,42 @@ public: static bool classofKind(Kind K) { return K >= firstValue && K <= lastValue; } }; +/// QualifierInfo - A struct with extended info about a syntactic +/// name qualifier, to be used for the case of out-of-line declarations. +struct QualifierInfo { + /// NNS - The syntactic name qualifier. + NestedNameSpecifier *NNS; + /// NNSRange - The source range for the qualifier. + SourceRange NNSRange; + /// NumTemplParamLists - The number of template parameter lists + /// that were matched against the template-ids occurring into the NNS. + unsigned NumTemplParamLists; + /// TemplParamLists - A new-allocated array of size NumTemplParamLists, + /// containing pointers to the matched template parameter lists. + TemplateParameterList** TemplParamLists; + + /// Default constructor. + QualifierInfo() + : NNS(0), NNSRange(), NumTemplParamLists(0), TemplParamLists(0) {} + /// setTemplateParameterListsInfo - Sets info about matched template + /// parameter lists. + void setTemplateParameterListsInfo(unsigned NumTPLists, + TemplateParameterList **TPLists); + /// Destructor: frees the array of template parameter lists pointers. + ~QualifierInfo() { delete[] TemplParamLists; } +private: + // Copy constructor and copy assignment are disabled. + QualifierInfo(const QualifierInfo&); + QualifierInfo& operator=(const QualifierInfo&); +}; + /// \brief Represents a ValueDecl that came out of a declarator. /// Contains type source information through TypeSourceInfo. class DeclaratorDecl : public ValueDecl { // A struct representing both a TInfo and a syntactic qualifier, // to be used for the (uncommon) case of out-of-line declarations. - struct ExtInfo { + struct ExtInfo : public QualifierInfo { TypeSourceInfo *TInfo; - NestedNameSpecifier *NNS; - SourceRange NNSRange; }; llvm::PointerUnion DeclInfo; @@ -392,25 +421,37 @@ public: TypeSourceInfo *getTypeSourceInfo() const { return hasExtInfo() - ? DeclInfo.get()->TInfo + ? getExtInfo()->TInfo : DeclInfo.get(); } void setTypeSourceInfo(TypeSourceInfo *TI) { if (hasExtInfo()) - DeclInfo.get()->TInfo = TI; + getExtInfo()->TInfo = TI; else DeclInfo = TI; } NestedNameSpecifier *getQualifier() const { - return hasExtInfo() ? DeclInfo.get()->NNS : 0; + return hasExtInfo() ? getExtInfo()->NNS : 0; } SourceRange getQualifierRange() const { - return hasExtInfo() ? DeclInfo.get()->NNSRange : SourceRange(); + return hasExtInfo() ? getExtInfo()->NNSRange : SourceRange(); } void setQualifierInfo(NestedNameSpecifier *Qualifier, SourceRange QualifierRange); + unsigned getNumTemplateParameterLists() const { + return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0; + } + TemplateParameterList *getTemplateParameterList(unsigned index) const { + assert(index < getNumTemplateParameterLists()); + return getExtInfo()->TemplParamLists[index]; + } + void setTemplateParameterListsInfo(unsigned NumTPLists, + TemplateParameterList **TPLists) { + getExtInfo()->setTemplateParameterListsInfo(NumTPLists, TPLists); + } + SourceLocation getTypeSpecStartLoc() const; // Implement isa/cast/dyncast/etc. @@ -1715,10 +1756,7 @@ private: // A struct representing syntactic qualifier info, // to be used for the (uncommon) case of out-of-line declarations. - struct ExtInfo { - NestedNameSpecifier *NNS; - SourceRange NNSRange; - }; + typedef QualifierInfo ExtInfo; /// TypedefDeclOrQualifier - If the (out-of-line) tag declaration name /// is qualified, it points to the qualifier info (nns and range); @@ -1830,20 +1868,30 @@ public: TypedefDecl *getTypedefForAnonDecl() const { return hasExtInfo() ? 0 : TypedefDeclOrQualifier.get(); } - + void setTypedefForAnonDecl(TypedefDecl *TDD); - + NestedNameSpecifier *getQualifier() const { - return hasExtInfo() ? TypedefDeclOrQualifier.get()->NNS : 0; + return hasExtInfo() ? getExtInfo()->NNS : 0; } SourceRange getQualifierRange() const { - return hasExtInfo() - ? TypedefDeclOrQualifier.get()->NNSRange - : SourceRange(); + return hasExtInfo() ? getExtInfo()->NNSRange : SourceRange(); } void setQualifierInfo(NestedNameSpecifier *Qualifier, SourceRange QualifierRange); + unsigned getNumTemplateParameterLists() const { + return hasExtInfo() ? getExtInfo()->NumTemplParamLists : 0; + } + TemplateParameterList *getTemplateParameterList(unsigned i) const { + assert(i < getNumTemplateParameterLists()); + return getExtInfo()->TemplParamLists[i]; + } + void setTemplateParameterListsInfo(unsigned NumTPLists, + TemplateParameterList **TPLists) { + getExtInfo()->setTemplateParameterListsInfo(NumTPLists, TPLists); + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const TagDecl *D) { return true; } diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 4d13f7f3abb6..cad7f1f88a85 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -566,6 +566,29 @@ void DeclaratorDecl::setQualifierInfo(NestedNameSpecifier *Qualifier, } } +void +QualifierInfo::setTemplateParameterListsInfo(unsigned NumTPLists, + TemplateParameterList **TPLists) { + assert((NumTPLists == 0 || TPLists != 0) && + "Empty array of template parameters with positive size!"); + assert((NumTPLists == 0 || NNS) && + "Nonempty array of template parameters with no qualifier!"); + + // Free previous template parameters (if any). + if (NumTemplParamLists > 0) { + delete[] TemplParamLists; + TemplParamLists = 0; + NumTemplParamLists = 0; + } + // Set info on matched template parameter lists (if any). + if (NumTPLists > 0) { + TemplParamLists = new TemplateParameterList*[NumTPLists]; + NumTemplParamLists = NumTPLists; + for (unsigned i = NumTPLists; i-- > 0; ) + TemplParamLists[i] = TPLists[i]; + } +} + //===----------------------------------------------------------------------===// // VarDecl Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 6bad5da9c45e..9ba3ee6ca40c 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2532,6 +2532,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. bool isExplicitSpecialization = false; + unsigned NumMatchedTemplateParamLists = TemplateParamLists.size(); if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getSourceRange().getBegin(), @@ -2540,6 +2541,9 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, TemplateParamLists.size(), /*never a friend*/ false, isExplicitSpecialization)) { + // All but one template parameter lists have been matching. + --NumMatchedTemplateParamLists; + if (TemplateParams->size() > 0) { // There is no such thing as a variable template. Diag(D.getIdentifierLoc(), diag::err_template_variable) @@ -2568,6 +2572,11 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, SetNestedNameSpecifier(NewVD, D); + if (NumMatchedTemplateParamLists > 0) { + NewVD->setTemplateParameterListsInfo(NumMatchedTemplateParamLists, + (TemplateParameterList**)TemplateParamLists.release()); + } + if (D.getDeclSpec().isThreadSpecified()) { if (NewVD->hasLocalStorage()) Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_thread_non_global); @@ -3088,6 +3097,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, FunctionTemplateDecl *FunctionTemplate = 0; bool isExplicitSpecialization = false; bool isFunctionTemplateSpecialization = false; + unsigned NumMatchedTemplateParamLists = TemplateParamLists.size(); if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getSourceRange().getBegin(), @@ -3096,6 +3106,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, TemplateParamLists.size(), isFriend, isExplicitSpecialization)) { + // All but one template parameter lists have been matching. + --NumMatchedTemplateParamLists; + if (TemplateParams->size() > 0) { // This is a function template @@ -3135,11 +3148,13 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, << FixItHint::CreateInsertion(InsertLoc, "<>"); } } - - // FIXME: Free this memory properly. - TemplateParamLists.release(); } - + + if (NumMatchedTemplateParamLists > 0) { + NewFD->setTemplateParameterListsInfo(NumMatchedTemplateParamLists, + (TemplateParameterList**)TemplateParamLists.release()); + } + // C++ [dcl.fct.spec]p5: // The virtual specifier shall only be used in declarations of // nonstatic class member functions that appear within a @@ -4965,6 +4980,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // FIXME: Check explicit specializations more carefully. bool isExplicitSpecialization = false; + unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size(); if (TUK != TUK_Reference) { if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier(KWLoc, SS, @@ -4972,6 +4988,9 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, TemplateParameterLists.size(), TUK == TUK_Friend, isExplicitSpecialization)) { + // All but one template parameter lists have been matching. + --NumMatchedTemplateParamLists; + if (TemplateParams->size() > 0) { // This is a declaration or definition of a class template (which may // be a member of another template). @@ -4989,8 +5008,6 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, isExplicitSpecialization = true; } } - - TemplateParameterLists.release(); } DeclContext *SearchDC = CurContext; @@ -5394,6 +5411,10 @@ CreateNewDecl: NestedNameSpecifier *NNS = static_cast(SS.getScopeRep()); New->setQualifierInfo(NNS, SS.getRange()); + if (NumMatchedTemplateParamLists > 0) { + New->setTemplateParameterListsInfo(NumMatchedTemplateParamLists, + (TemplateParameterList**) TemplateParameterLists.release()); + } } else Invalid = true; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 44e3a40245a3..6be74a089782 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -3666,6 +3666,10 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateParameterLists.size(), TUK == TUK_Friend, isExplicitSpecialization); + unsigned NumMatchedTemplateParamLists = TemplateParameterLists.size(); + if (TemplateParams) + --NumMatchedTemplateParamLists; + if (TemplateParams && TemplateParams->size() > 0) { isPartialSpecialization = true; @@ -3857,6 +3861,10 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, PrevPartial, SequenceNumber); SetNestedNameSpecifier(Partial, SS); + if (NumMatchedTemplateParamLists > 0) { + Partial->setTemplateParameterListsInfo(NumMatchedTemplateParamLists, + (TemplateParameterList**) TemplateParameterLists.release()); + } if (PrevPartial) { ClassTemplate->getPartialSpecializations().RemoveNode(PrevPartial); @@ -3914,6 +3922,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Converted, PrevDecl); SetNestedNameSpecifier(Specialization, SS); + if (NumMatchedTemplateParamLists > 0) { + Specialization->setTemplateParameterListsInfo( + NumMatchedTemplateParamLists, + (TemplateParameterList**) TemplateParameterLists.release()); + } if (PrevDecl) { ClassTemplate->getSpecializations().RemoveNode(PrevDecl);