From 37d93e9252026d4fb836d9c05d0122a2d46e56be Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sun, 2 Aug 2009 23:24:31 +0000 Subject: [PATCH] Keep track of the template arguments deduced when matching a class template partial specialization. Then, use those template arguments when instantiating members of that class template partial specialization. Fixes PR4607. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77925 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclTemplate.h | 75 ++++++++++++++++++- lib/AST/DeclTemplate.cpp | 16 ++++ lib/Sema/SemaTemplateInstantiate.cpp | 5 +- .../SemaTemplate/partial-spec-instantiate.cpp | 20 +++++ 4 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 test/SemaTemplate/partial-spec-instantiate.cpp diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 501f82d6ba..fdd4d150f6 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -869,8 +869,23 @@ enum TemplateSpecializationKind { /// \endcode class ClassTemplateSpecializationDecl : public CXXRecordDecl, public llvm::FoldingSetNode { + + /// \brief Structure that stores information about a class template + /// specialization that was instantiated from a class template partial + /// specialization. + struct SpecializedPartialSpecialization { + /// \brief The class template partial specialization from which this + /// class template specialization was instantiated. + ClassTemplatePartialSpecializationDecl *PartialSpecialization; + + /// \brief The template argument list deduced for the class template + /// partial specialization itself. + TemplateArgumentList *TemplateArgs; + }; + /// \brief The template that this specialization specializes - ClassTemplateDecl *SpecializedTemplate; + llvm::PointerUnion + SpecializedTemplate; /// \brief The template arguments used to describe this specialization. TemplateArgumentList TemplateArgs; @@ -893,11 +908,13 @@ public: TemplateArgumentListBuilder &Builder, ClassTemplateSpecializationDecl *PrevDecl); + virtual void Destroy(ASTContext& C); + /// \brief Retrieve the template that this specialization specializes. - ClassTemplateDecl *getSpecializedTemplate() const { - return SpecializedTemplate; - } + ClassTemplateDecl *getSpecializedTemplate() const; + /// \brief Retrieve the template arguments of the class template + /// specialization. const TemplateArgumentList &getTemplateArgs() const { return TemplateArgs; } @@ -912,6 +929,56 @@ public: SpecializationKind = TSK; } + /// \brief If this class template specialization is an instantiation of + /// a template (rather than an explicit specialization), return the + /// class template or class template partial specialization from which it + /// was instantiated. + llvm::PointerUnion + getInstantiatedFrom() const { + if (getSpecializationKind() != TSK_ImplicitInstantiation && + getSpecializationKind() != TSK_ExplicitInstantiation) + return (ClassTemplateDecl*)0; + + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast()) + return PartialSpec->PartialSpecialization; + + return const_cast( + SpecializedTemplate.get()); + } + + /// \brief Retrieve the set of template arguments that should be used + /// to instantiate members of the class template or class template partial + /// specialization from which this class template specialization was + /// instantiated. + /// + /// \returns For a class template specialization instantiated from the primary + /// template, this function will return the same template arguments as + /// getTemplateArgs(). For a class template specialization instantiated from + /// a class template partial specialization, this function will return the + /// deduced template arguments for the class template partial specialization + /// itself. + const TemplateArgumentList &getTemplateInstantiationArgs() const { + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast()) + return *PartialSpec->TemplateArgs; + + return getTemplateArgs(); + } + + /// \brief Note that this class template specialization is actually an + /// instantiation of the given class template partial specialization whose + /// template arguments have been deduced. + void setInstantiationOf(ClassTemplatePartialSpecializationDecl *PartialSpec, + TemplateArgumentList *TemplateArgs) { + SpecializedPartialSpecialization *PS + = new (getASTContext()) SpecializedPartialSpecialization(); + PS->PartialSpecialization = PartialSpec; + PS->TemplateArgs = TemplateArgs; + SpecializedTemplate = PS; + } + /// \brief Sets the type of this specialization as it was written by /// the user. This will be a class template specialization type. void setTypeAsWritten(QualType T) { diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 6b3ea437ab..f5f7bfec5f 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -415,6 +415,22 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, return Result; } +void ClassTemplateSpecializationDecl::Destroy(ASTContext &C) { + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast()) + C.Deallocate(PartialSpec); + + CXXRecordDecl::Destroy(C); +} + +ClassTemplateDecl * +ClassTemplateSpecializationDecl::getSpecializedTemplate() const { + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast()) + return PartialSpec->PartialSpecialization->getSpecializedTemplate(); + return SpecializedTemplate.get(); +} + //===----------------------------------------------------------------------===// // ClassTemplatePartialSpecializationDecl Implementation //===----------------------------------------------------------------------===// diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index cb43f1c6a0..ae16c7124c 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -32,7 +32,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D) { // Template arguments for a class template specialization. if (ClassTemplateSpecializationDecl *Spec = dyn_cast(D)) - return Spec->getTemplateArgs(); + return Spec->getTemplateInstantiationArgs(); // Template arguments for a function template specialization. if (FunctionDecl *Function = dyn_cast(D)) @@ -50,7 +50,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D) { ClassTemplateSpecializationDecl *EnclosingTemplate = cast(EnclosingTemplateCtx); - return EnclosingTemplate->getTemplateArgs(); + return EnclosingTemplate->getTemplateInstantiationArgs(); } Sema::InstantiatingTemplate:: @@ -1011,6 +1011,7 @@ Sema::InstantiateClassTemplateSpecialization( // instantiation is generated from that specialization. Pattern = Matched[0].first; TemplateArgs = Matched[0].second; + ClassTemplateSpec->setInstantiationOf(Matched[0].first, Matched[0].second); } else if (Matched.size() > 1) { // -- If more than one matching specialization is found, the // partial order rules (14.5.4.2) are used to determine diff --git a/test/SemaTemplate/partial-spec-instantiate.cpp b/test/SemaTemplate/partial-spec-instantiate.cpp new file mode 100644 index 0000000000..8d1ae23897 --- /dev/null +++ b/test/SemaTemplate/partial-spec-instantiate.cpp @@ -0,0 +1,20 @@ +// RUN: clang-cc -fsyntax-only %s + +// PR4607 +template struct X {}; + +template <> struct X +{ + static char* g(); +}; + +template struct X2 {}; + +template +struct X2 { + static void f() { + X::g(); + } +}; + +void a(char *a, char *b) {X2::f();} -- 2.40.0