summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2009-08-20 01:44:21 +0000
committerJohn McCall <rjmccall@apple.com>2009-08-20 01:44:21 +0000
commite29ba20148e9b7835ad463b39cd4ee9223eafbbf (patch)
tree44ca1980c3f24bd369f292437f96d1fc06690cae
parentfafd3834754d2093e0ad7a1c005860fd527ecb7f (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.h35
-rw-r--r--lib/Sema/Sema.h4
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp36
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp94
-rw-r--r--test/CXX/temp/temp.decls/temp.mem/p1.cpp16
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);
+}