diff options
author | John McCall <rjmccall@apple.com> | 2009-08-20 01:44:21 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2009-08-20 01:44:21 +0000 |
commit | e29ba20148e9b7835ad463b39cd4ee9223eafbbf (patch) | |
tree | 44ca1980c3f24bd369f292437f96d1fc06690cae | |
parent | fafd3834754d2093e0ad7a1c005860fd527ecb7f (diff) |
Basic nested-template implementation.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79504 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 35 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 36 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 94 | ||||
-rw-r--r-- | test/CXX/temp/temp.decls/temp.mem/p1.cpp | 16 |
5 files changed, 185 insertions, 0 deletions
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 9712b40908..14bf041b7a 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -1061,6 +1061,8 @@ protected: /// \brief Data that is common to all of the declarations of a given /// class template. struct Common { + Common() : InstantiatedFromMember(0) {} + /// \brief The class template specializations for this class /// template, including explicit specializations and instantiations. llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations; @@ -1072,6 +1074,10 @@ protected: /// \brief The injected-class-name type for this class template. QualType InjectedClassNameType; + + /// \brief The templated member class from which this was most + /// directly instantiated (or null). + ClassTemplateDecl *InstantiatedFromMember; }; /// \brief Previous declaration of this class template. @@ -1151,6 +1157,35 @@ public: /// \endcode QualType getInjectedClassNameType(ASTContext &Context); + /// \brief Retrieve the member class template that this class template was + /// derived from. + /// + /// This routine will return non-NULL for templated member classes of + /// class templates. For example, given: + /// + /// \code + /// template <typename T> + /// struct X { + /// template <typename U> struct A {}; + /// }; + /// \endcode + /// + /// X<int>::A<float> is a ClassTemplateSpecializationDecl (whose parent + /// is X<int>, also a CTSD) for which getSpecializedTemplate() will + /// return X<int>::A<U>, a TemplateClassDecl (whose parent is again + /// X<int>) for which getInstantiatedFromMemberTemplate() will return + /// X<T>::A<U>, a TemplateClassDecl (whose parent is X<T>, also a TCD). + /// + /// \returns null if this is not an instantiation of a member class template. + ClassTemplateDecl *getInstantiatedFromMemberTemplate() const { + return CommonPtr->InstantiatedFromMember; + } + + void setInstantiatedFromMemberTemplate(ClassTemplateDecl *CTD) { + assert(!CommonPtr->InstantiatedFromMember); + CommonPtr->InstantiatedFromMember = CTD; + } + // Implement isa/cast/dyncast support static bool classof(const Decl *D) { return D->getKind() == ClassTemplate; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index f3ec417235..12ab47c81a 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2847,6 +2847,10 @@ public: const TemplateArgumentList &TemplateArgs); bool + InstantiateTemplatePattern(SourceLocation PointOfInstantiation, + CXXRecordDecl *Pattern); + + bool InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const TemplateArgumentList &TemplateArgs, diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 4d164ea12e..45214bfd6c 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -568,6 +568,38 @@ Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation, return Invalid; } +/// \brief Force a template's pattern class to be instantiated. +/// +/// \returns true if an error occurred +bool Sema::InstantiateTemplatePattern(SourceLocation PointOfInstantiation, + CXXRecordDecl *Pattern) { + if (Pattern->getDefinition(Context)) return false; + + ClassTemplateDecl *PatternTemp = Pattern->getDescribedClassTemplate(); + if (!PatternTemp) return false; + + // Check whether this template is a lazy instantiation of a + // dependent member template, e.g. Inner<U> in + // Outer<int>::Inner<U>. + ClassTemplateDecl *PatternPatternTemp + = PatternTemp->getInstantiatedFromMemberTemplate(); + if (!PatternPatternTemp) return false; + + ClassTemplateSpecializationDecl *Spec = 0; + for (DeclContext *Parent = Pattern->getDeclContext(); + Parent && !Spec; Parent = Parent->getParent()) + Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent); + assert(Spec && "Not a member of a class template specialization?"); + + // TODO: the error message from a nested failure here is probably + // not ideal. + return InstantiateClass(PointOfInstantiation, + Pattern, + PatternPatternTemp->getTemplatedDecl(), + Spec->getTemplateArgs(), + /* ExplicitInstantiation = */ false); +} + /// \brief Instantiate the definition of a class from a given pattern. /// /// \param PointOfInstantiation The point of instantiation within the @@ -591,6 +623,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, const TemplateArgumentList &TemplateArgs, bool ExplicitInstantiation) { bool Invalid = false; + + // Lazily instantiate member templates here. + if (InstantiateTemplatePattern(PointOfInstantiation, Pattern)) + return true; CXXRecordDecl *PatternDef = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 30d7b6acd6..23256a853c 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -53,6 +53,8 @@ namespace { Decl *VisitCXXConversionDecl(CXXConversionDecl *D); ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D); Decl *VisitOriginalParmVarDecl(OriginalParmVarDecl *D); + Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); + Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); // Base case. FIXME: Remove once we can instantiate everything. Decl *VisitDecl(Decl *) { @@ -69,6 +71,9 @@ namespace { llvm::SmallVectorImpl<ParmVarDecl *> &Params); bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl); bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl); + + TemplateParameterList * + InstantiateTemplateParams(TemplateParameterList *List); }; } @@ -322,6 +327,28 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) { return 0; } +Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { + TemplateParameterList *TempParams = D->getTemplateParameters(); + TemplateParameterList *InstParams = InstantiateTemplateParams(TempParams); + if (!InstParams) return NULL; + + CXXRecordDecl *Pattern = D->getTemplatedDecl(); + CXXRecordDecl *RecordInst + = CXXRecordDecl::Create(SemaRef.Context, Pattern->getTagKind(), Owner, + Pattern->getLocation(), Pattern->getIdentifier(), + Pattern->getTagKeywordLoc(), /*PrevDecl=*/ NULL); + + ClassTemplateDecl *Inst + = ClassTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getIdentifier(), InstParams, RecordInst, 0); + RecordInst->setDescribedClassTemplate(Inst); + Inst->setAccess(D->getAccess()); + Inst->setInstantiatedFromMemberTemplate(D); + + Owner->addDecl(Inst); + return Inst; +} + Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { CXXRecordDecl *PrevDecl = 0; if (D->isInjectedClassName()) @@ -639,12 +666,79 @@ TemplateDeclInstantiator::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) { return VisitParmVarDecl(D); } +Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( + TemplateTypeParmDecl *D) { + // TODO: don't always clone when decls are refcounted. + const Type* T = D->getTypeForDecl(); + assert(T->isTemplateTypeParmType()); + const TemplateTypeParmType *TTPT = T->getAs<TemplateTypeParmType>(); + + TemplateTypeParmDecl *Inst = + TemplateTypeParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), + TTPT->getDepth(), TTPT->getIndex(), + TTPT->getName(), + D->wasDeclaredWithTypename(), + D->isParameterPack()); + + if (D->hasDefaultArgument()) { + QualType DefaultPattern = D->getDefaultArgument(); + QualType DefaultInst + = SemaRef.InstantiateType(DefaultPattern, TemplateArgs, + D->getDefaultArgumentLoc(), + D->getDeclName()); + + Inst->setDefaultArgument(DefaultInst, + D->getDefaultArgumentLoc(), + D->defaultArgumentWasInherited() /* preserve? */); + } + + return Inst; +} + Decl *Sema::InstantiateDecl(Decl *D, DeclContext *Owner, const TemplateArgumentList &TemplateArgs) { TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs); return Instantiator.Visit(D); } +/// \brief Instantiates a nested template parameter list in the current +/// instantiation context. +/// +/// \param L The parameter list to instantiate +/// +/// \returns NULL if there was an error +TemplateParameterList * +TemplateDeclInstantiator::InstantiateTemplateParams(TemplateParameterList *L) { + // Get errors for all the parameters before bailing out. + bool Invalid = false; + + unsigned N = L->size(); + typedef llvm::SmallVector<Decl*,8> ParamVector; + ParamVector Params; + Params.reserve(N); + for (TemplateParameterList::iterator PI = L->begin(), PE = L->end(); + PI != PE; ++PI) { + Decl *D = Visit(*PI); + Params.push_back(D); + Invalid = Invalid || !D; + } + + // Clean up if we had an error. + if (Invalid) { + for (ParamVector::iterator PI = Params.begin(), PE = Params.end(); + PI != PE; ++PI) + if (*PI) + (*PI)->Destroy(SemaRef.Context); + return NULL; + } + + TemplateParameterList *InstL + = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(), + L->getLAngleLoc(), &Params.front(), N, + L->getRAngleLoc()); + return InstL; +} + /// \brief Instantiates the type of the given function, including /// instantiating all of the function parameters. /// diff --git a/test/CXX/temp/temp.decls/temp.mem/p1.cpp b/test/CXX/temp/temp.decls/temp.mem/p1.cpp new file mode 100644 index 0000000000..80b18467a3 --- /dev/null +++ b/test/CXX/temp/temp.decls/temp.mem/p1.cpp @@ -0,0 +1,16 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template <class T> struct A { + static T cond; + + template <class U> struct B { + static T twice(U value) { + return (cond ? value + value : value); + } + }; +}; + +int foo() { + A<bool>::cond = true; + return A<bool>::B<int>::twice(4); +} |