Instantiate class member template partial specialization declarations

in the order they occur within the class template, delaying
out-of-line member template partial specializations until after the
class has been fully instantiated. This fixes a regression introduced
by r118454 (itself a fix for PR8001).

llvm-svn: 118704
This commit is contained in:
Douglas Gregor 2010-11-10 19:44:59 +00:00
parent cf7e9a0485
commit 869853eea1
5 changed files with 181 additions and 102 deletions

View File

@ -13,8 +13,10 @@
#define LLVM_CLANG_SEMA_TEMPLATE_H #define LLVM_CLANG_SEMA_TEMPLATE_H
#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclTemplate.h"
#include "clang/AST/DeclVisitor.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include <cassert> #include <cassert>
#include <utility>
namespace clang { namespace clang {
/// \brief Data structure that captures multiple levels of template argument /// \brief Data structure that captures multiple levels of template argument
@ -238,6 +240,113 @@ namespace clang {
void InstantiatedLocal(const Decl *D, Decl *Inst); void InstantiatedLocal(const Decl *D, Decl *Inst);
}; };
class TemplateDeclInstantiator
: public DeclVisitor<TemplateDeclInstantiator, Decl *> {
Sema &SemaRef;
DeclContext *Owner;
const MultiLevelTemplateArgumentList &TemplateArgs;
/// \brief A list of out-of-line class template partial
/// specializations that will need to be instantiated after the
/// enclosing class's instantiation is complete.
llvm::SmallVector<std::pair<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *>, 4>
OutOfLinePartialSpecs;
public:
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs)
: SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs) { }
// FIXME: Once we get closer to completion, replace these manually-written
// declarations with automatically-generated ones from
// clang/AST/DeclNodes.inc.
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
Decl *VisitTypedefDecl(TypedefDecl *D);
Decl *VisitVarDecl(VarDecl *D);
Decl *VisitAccessSpecDecl(AccessSpecDecl *D);
Decl *VisitFieldDecl(FieldDecl *D);
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
Decl *VisitFriendDecl(FriendDecl *D);
Decl *VisitFunctionDecl(FunctionDecl *D,
TemplateParameterList *TemplateParams = 0);
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
TemplateParameterList *TemplateParams = 0);
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
Decl *VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D);
Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
Decl *VisitUsingDecl(UsingDecl *D);
Decl *VisitUsingShadowDecl(UsingShadowDecl *D);
Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
// Base case. FIXME: Remove once we can instantiate everything.
Decl *VisitDecl(Decl *D) {
unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID(
Diagnostic::Error,
"cannot instantiate %0 yet");
SemaRef.Diag(D->getLocation(), DiagID)
<< D->getDeclKindName();
return 0;
}
typedef
llvm::SmallVectorImpl<std::pair<ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *> >
::iterator
delayed_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
/// definition has been completed.
delayed_partial_spec_iterator delayed_partial_spec_begin() {
return OutOfLinePartialSpecs.begin();
}
/// \brief Return an iterator to the end of the set of
/// "delayed" partial specializations, which must be passed to
/// InstantiateClassTemplatePartialSpecialization once the class
/// definition has been completed.
delayed_partial_spec_iterator delayed_partial_spec_end() {
return OutOfLinePartialSpecs.end();
}
// Helper functions for instantiating methods.
TypeSourceInfo *SubstFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params);
bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
TemplateParameterList *
SubstTemplateParams(TemplateParameterList *List);
bool SubstQualifier(const DeclaratorDecl *OldDecl,
DeclaratorDecl *NewDecl);
bool SubstQualifier(const TagDecl *OldDecl,
TagDecl *NewDecl);
ClassTemplatePartialSpecializationDecl *
InstantiateClassTemplatePartialSpecialization(
ClassTemplateDecl *ClassTemplate,
ClassTemplatePartialSpecializationDecl *PartialSpec);
};
} }
#endif // LLVM_CLANG_SEMA_TEMPLATE_H #endif // LLVM_CLANG_SEMA_TEMPLATE_H

View File

@ -1221,6 +1221,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs)) if (SubstBaseSpecifiers(Instantiation, Pattern, TemplateArgs))
Invalid = true; Invalid = true;
TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
llvm::SmallVector<Decl*, 4> Fields; llvm::SmallVector<Decl*, 4> Fields;
for (RecordDecl::decl_iterator Member = Pattern->decls_begin(), for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
MemberEnd = Pattern->decls_end(); MemberEnd = Pattern->decls_end();
@ -1237,7 +1238,12 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
if ((*Member)->getDeclContext() != Pattern) if ((*Member)->getDeclContext() != Pattern)
continue; continue;
Decl *NewMember = SubstDecl(*Member, Instantiation, TemplateArgs); if ((*Member)->isInvalidDecl()) {
Invalid = true;
continue;
}
Decl *NewMember = Instantiator.Visit(*Member);
if (NewMember) { if (NewMember) {
if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember)) if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
Fields.push_back(Field); Fields.push_back(Field);
@ -1257,7 +1263,22 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
CheckCompletedCXXClass(Instantiation); CheckCompletedCXXClass(Instantiation);
if (Instantiation->isInvalidDecl()) if (Instantiation->isInvalidDecl())
Invalid = true; Invalid = true;
else {
// Instantiate any out-of-line class template partial
// specializations now.
for (TemplateDeclInstantiator::delayed_partial_spec_iterator
P = Instantiator.delayed_partial_spec_begin(),
PEnd = Instantiator.delayed_partial_spec_end();
P != PEnd; ++P) {
if (!Instantiator.InstantiateClassTemplatePartialSpecialization(
P->first,
P->second)) {
Invalid = true;
break;
}
}
}
// Exit the scope of this instantiation. // Exit the scope of this instantiation.
SavedContext.pop(); SavedContext.pop();

View File

@ -25,85 +25,6 @@
using namespace clang; using namespace clang;
namespace {
class TemplateDeclInstantiator
: public DeclVisitor<TemplateDeclInstantiator, Decl *> {
Sema &SemaRef;
DeclContext *Owner;
const MultiLevelTemplateArgumentList &TemplateArgs;
public:
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
const MultiLevelTemplateArgumentList &TemplateArgs)
: SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs) { }
// FIXME: Once we get closer to completion, replace these manually-written
// declarations with automatically-generated ones from
// clang/AST/DeclNodes.inc.
Decl *VisitTranslationUnitDecl(TranslationUnitDecl *D);
Decl *VisitNamespaceDecl(NamespaceDecl *D);
Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D);
Decl *VisitTypedefDecl(TypedefDecl *D);
Decl *VisitVarDecl(VarDecl *D);
Decl *VisitAccessSpecDecl(AccessSpecDecl *D);
Decl *VisitFieldDecl(FieldDecl *D);
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
Decl *VisitFriendDecl(FriendDecl *D);
Decl *VisitFunctionDecl(FunctionDecl *D,
TemplateParameterList *TemplateParams = 0);
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
TemplateParameterList *TemplateParams = 0);
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
ParmVarDecl *VisitParmVarDecl(ParmVarDecl *D);
Decl *VisitClassTemplateDecl(ClassTemplateDecl *D);
Decl *VisitClassTemplatePartialSpecializationDecl(
ClassTemplatePartialSpecializationDecl *D);
Decl *VisitFunctionTemplateDecl(FunctionTemplateDecl *D);
Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D);
Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D);
Decl *VisitUsingDirectiveDecl(UsingDirectiveDecl *D);
Decl *VisitUsingDecl(UsingDecl *D);
Decl *VisitUsingShadowDecl(UsingShadowDecl *D);
Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
// Base case. FIXME: Remove once we can instantiate everything.
Decl *VisitDecl(Decl *D) {
unsigned DiagID = SemaRef.getDiagnostics().getCustomDiagID(
Diagnostic::Error,
"cannot instantiate %0 yet");
SemaRef.Diag(D->getLocation(), DiagID)
<< D->getDeclKindName();
return 0;
}
// Helper functions for instantiating methods.
TypeSourceInfo *SubstFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params);
bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
TemplateParameterList *
SubstTemplateParams(TemplateParameterList *List);
bool SubstQualifier(const DeclaratorDecl *OldDecl,
DeclaratorDecl *NewDecl);
bool SubstQualifier(const TagDecl *OldDecl,
TagDecl *NewDecl);
bool InstantiateClassTemplatePartialSpecialization(
ClassTemplateDecl *ClassTemplate,
ClassTemplatePartialSpecializationDecl *PartialSpec);
};
}
bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl, bool TemplateDeclInstantiator::SubstQualifier(const DeclaratorDecl *OldDecl,
DeclaratorDecl *NewDecl) { DeclaratorDecl *NewDecl) {
NestedNameSpecifier *OldQual = OldDecl->getQualifier(); NestedNameSpecifier *OldQual = OldDecl->getQualifier();
@ -860,14 +781,18 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
} }
Owner->addDecl(Inst); Owner->addDecl(Inst);
// Instantiate all of the partial specializations of this member class if (!PrevClassTemplate) {
// template. // Queue up any out-of-line partial specializations of this member
llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs; // class template; the client will force their instantiation once
D->getPartialSpecializations(PartialSpecs); // the enclosing class has been instantiated.
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
InstantiateClassTemplatePartialSpecialization(Inst, PartialSpecs[I]); D->getPartialSpecializations(PartialSpecs);
for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
if (PartialSpecs[I]->isOutOfLine())
OutOfLinePartialSpecs.push_back(std::make_pair(Inst, PartialSpecs[I]));
}
return Inst; return Inst;
} }
@ -888,7 +813,11 @@ TemplateDeclInstantiator::VisitClassTemplatePartialSpecializationDecl(
if (!InstClassTemplate) if (!InstClassTemplate)
return 0; return 0;
return InstClassTemplate->findPartialSpecInstantiatedFromMember(D); if (ClassTemplatePartialSpecializationDecl *Result
= InstClassTemplate->findPartialSpecInstantiatedFromMember(D))
return Result;
return InstantiateClassTemplatePartialSpecialization(InstClassTemplate, D);
} }
Decl * Decl *
@ -1818,8 +1747,9 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) {
/// \param PartialSpec the (uninstantiated) class template partial /// \param PartialSpec the (uninstantiated) class template partial
/// specialization that we are instantiating. /// specialization that we are instantiating.
/// ///
/// \returns true if there was an error, false otherwise. /// \returns The instantiated partial specialization, if successful; otherwise,
bool /// NULL to indicate an error.
ClassTemplatePartialSpecializationDecl *
TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
ClassTemplateDecl *ClassTemplate, ClassTemplateDecl *ClassTemplate,
ClassTemplatePartialSpecializationDecl *PartialSpec) { ClassTemplatePartialSpecializationDecl *PartialSpec) {
@ -1833,7 +1763,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
TemplateParameterList *TempParams = PartialSpec->getTemplateParameters(); TemplateParameterList *TempParams = PartialSpec->getTemplateParameters();
TemplateParameterList *InstParams = SubstTemplateParams(TempParams); TemplateParameterList *InstParams = SubstTemplateParams(TempParams);
if (!InstParams) if (!InstParams)
return true; return 0;
// Substitute into the template arguments of the class template partial // Substitute into the template arguments of the class template partial
// specialization. // specialization.
@ -1845,7 +1775,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
for (unsigned I = 0; I != N; ++I) { for (unsigned I = 0; I != N; ++I) {
TemplateArgumentLoc Loc; TemplateArgumentLoc Loc;
if (SemaRef.Subst(PartialSpecTemplateArgs[I], Loc, TemplateArgs)) if (SemaRef.Subst(PartialSpecTemplateArgs[I], Loc, TemplateArgs))
return true; return 0;
InstTemplateArgs.addArgument(Loc); InstTemplateArgs.addArgument(Loc);
} }
@ -1858,7 +1788,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
InstTemplateArgs, InstTemplateArgs,
false, false,
Converted)) Converted))
return true; return 0;
// Figure out where to insert this class template partial specialization // Figure out where to insert this class template partial specialization
// in the member template's set of class template partial specializations. // in the member template's set of class template partial specializations.
@ -1905,10 +1835,10 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
// Outer<int, int> outer; // error: the partial specializations of Inner // Outer<int, int> outer; // error: the partial specializations of Inner
// // have the same signature. // // have the same signature.
SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared) SemaRef.Diag(PartialSpec->getLocation(), diag::err_partial_spec_redeclared)
<< WrittenTy; << WrittenTy->getType();
SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here) SemaRef.Diag(PrevDecl->getLocation(), diag::note_prev_partial_spec_here)
<< SemaRef.Context.getTypeDeclType(PrevDecl); << SemaRef.Context.getTypeDeclType(PrevDecl);
return true; return 0;
} }
@ -1936,7 +1866,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
// Add this partial specialization to the set of class template partial // Add this partial specialization to the set of class template partial
// specializations. // specializations.
ClassTemplate->AddPartialSpecialization(InstPartialSpec, InsertPos); ClassTemplate->AddPartialSpecialization(InstPartialSpec, InsertPos);
return false; return InstPartialSpec;
} }
TypeSourceInfo* TypeSourceInfo*

View File

@ -53,3 +53,24 @@ struct X0<float>::Inner0<Z*> {
int array3[X0<float>::Inner0<int>::value == 0? 1 : -1]; int array3[X0<float>::Inner0<int>::value == 0? 1 : -1];
int array4[X0<float>::Inner0<int*>::value == 3? 1 : -1]; int array4[X0<float>::Inner0<int*>::value == 3? 1 : -1];
int array5[X0<float>::Inner0<const int*>::value == 2? 1 : -1]; int array5[X0<float>::Inner0<const int*>::value == 2? 1 : -1];
namespace rdar8651930 {
template<typename OuterT>
struct Outer {
template<typename T, typename U>
struct Inner;
template<typename T>
struct Inner<T, T> {
static const bool value = true;
};
template<typename T, typename U>
struct Inner {
static const bool value = false;
};
};
int array0[Outer<int>::Inner<int, int>::value? 1 : -1];
int array1[Outer<int>::Inner<int, float>::value? -1 : 1];
}

View File

@ -13,11 +13,9 @@ template<> void X0<char>::f1(type);
namespace PR6161 { namespace PR6161 {
template<typename _CharT> template<typename _CharT>
class numpunct : public locale::facet // expected-error{{use of undeclared identifier 'locale'}} \ class numpunct : public locale::facet // expected-error{{use of undeclared identifier 'locale'}} \
// expected-error{{expected class name}} \ // expected-error{{expected class name}}
// expected-note{{attempt to specialize declaration here}}
{ {
static locale::id id; // expected-error{{use of undeclared identifier}} static locale::id id; // expected-error{{use of undeclared identifier}}
}; };
numpunct<char>::~numpunct(); // expected-error{{template specialization requires 'template<>'}} \ numpunct<char>::~numpunct(); // expected-error{{expected the class name after '~' to name a destructor}}
// expected-error{{specialization of member 'PR6161::numpunct<char>::~numpunct' does not specialize an instantiated member}}
} }