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.

llvm-svn: 77925
This commit is contained in:
Douglas Gregor 2009-08-02 23:24:31 +00:00
parent bbb772ace9
commit 9dc8bd327f
4 changed files with 111 additions and 7 deletions

View File

@ -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<ClassTemplateDecl *, SpecializedPartialSpecialization *>
SpecializedTemplate;
/// \brief The template arguments used to describe this specialization.
TemplateArgumentList TemplateArgs;
@ -893,11 +908,13 @@ public:
TemplateArgumentListBuilder &Builder,
ClassTemplateSpecializationDecl *PrevDecl);
/// \brief Retrieve the template that this specialization specializes.
ClassTemplateDecl *getSpecializedTemplate() const {
return SpecializedTemplate;
}
virtual void Destroy(ASTContext& C);
/// \brief Retrieve the template that this specialization specializes.
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<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *>
getInstantiatedFrom() const {
if (getSpecializationKind() != TSK_ImplicitInstantiation &&
getSpecializationKind() != TSK_ExplicitInstantiation)
return (ClassTemplateDecl*)0;
if (SpecializedPartialSpecialization *PartialSpec
= SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
return PartialSpec->PartialSpecialization;
return const_cast<ClassTemplateDecl*>(
SpecializedTemplate.get<ClassTemplateDecl*>());
}
/// \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<SpecializedPartialSpecialization*>())
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) {

View File

@ -415,6 +415,22 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context,
return Result;
}
void ClassTemplateSpecializationDecl::Destroy(ASTContext &C) {
if (SpecializedPartialSpecialization *PartialSpec
= SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
C.Deallocate(PartialSpec);
CXXRecordDecl::Destroy(C);
}
ClassTemplateDecl *
ClassTemplateSpecializationDecl::getSpecializedTemplate() const {
if (SpecializedPartialSpecialization *PartialSpec
= SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>())
return PartialSpec->PartialSpecialization->getSpecializedTemplate();
return SpecializedTemplate.get<ClassTemplateDecl*>();
}
//===----------------------------------------------------------------------===//
// ClassTemplatePartialSpecializationDecl Implementation
//===----------------------------------------------------------------------===//

View File

@ -32,7 +32,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D) {
// Template arguments for a class template specialization.
if (ClassTemplateSpecializationDecl *Spec
= dyn_cast<ClassTemplateSpecializationDecl>(D))
return Spec->getTemplateArgs();
return Spec->getTemplateInstantiationArgs();
// Template arguments for a function template specialization.
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D))
@ -50,7 +50,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D) {
ClassTemplateSpecializationDecl *EnclosingTemplate
= cast<ClassTemplateSpecializationDecl>(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

View File

@ -0,0 +1,20 @@
// RUN: clang-cc -fsyntax-only %s
// PR4607
template <class T> struct X {};
template <> struct X<char>
{
static char* g();
};
template <class T> struct X2 {};
template <class U>
struct X2<U*> {
static void f() {
X<U>::g();
}
};
void a(char *a, char *b) {X2<char*>::f();}