Basic nested-template implementation.

llvm-svn: 79504
This commit is contained in:
John McCall 2009-08-20 01:44:21 +00:00
parent 30584ea4a4
commit 87a44eb98a
5 changed files with 185 additions and 0 deletions

View File

@ -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; }

View File

@ -2846,6 +2846,10 @@ public:
CXXRecordDecl *Pattern,
const TemplateArgumentList &TemplateArgs);
bool
InstantiateTemplatePattern(SourceLocation PointOfInstantiation,
CXXRecordDecl *Pattern);
bool
InstantiateClass(SourceLocation PointOfInstantiation,
CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,

View File

@ -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
@ -592,6 +624,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
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));
if (!PatternDef) {

View File

@ -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.
///

View File

@ -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);
}