The injected-class-name of class templates and class template
specializations can be treated as a template. Finally, we can parse
and process the first implementation of Fibonacci I wrote!
Note that this code does not handle all of the cases where
injected-class-names can be treated as templates. In particular,
there's an ambiguity case that we should be able to handle (but
can't), e.g.,
template <class T> struct Base { };
template <class T> struct Derived : Base<int>, Base<char> {
typename Derived::Base b; // error: ambiguous
typename Derived::Base<double> d; // OK
};
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67720 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 835792e..88c08b0 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3425,6 +3425,8 @@
Record->getIdentifier(), Record);
InjectedClassName->setImplicit();
InjectedClassName->setAccess(AS_public);
+ if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate())
+ InjectedClassName->setDescribedClassTemplate(Template);
PushOnScopeChains(InjectedClassName, S);
assert(InjectedClassName->isInjectedClassName() &&
"Broken injected-class-name");
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 24b35ee..c0476a8 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -42,6 +42,28 @@
return TNK_Template_template_parm;
else
assert(false && "Unknown TemplateDecl");
+ } else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(IIDecl)) {
+ // C++ [temp.local]p1:
+ // Like normal (non-template) classes, class templates have an
+ // injected-class-name (Clause 9). The injected-class-name
+ // can be used with or without a template-argument-list. When
+ // it is used without a template-argument-list, it is
+ // equivalent to the injected-class-name followed by the
+ // template-parameters of the class template enclosed in
+ // <>. When it is used with a template-argument-list, it
+ // refers to the specified class template specialization,
+ // which could be the current specialization or another
+ // specialization.
+ if (Record->isInjectedClassName()) {
+ Record = cast<CXXRecordDecl>(Context.getCanonicalDecl(Record));
+ if ((Template = Record->getDescribedClassTemplate()))
+ return TNK_Class_template;
+ else if (ClassTemplateSpecializationDecl *Spec
+ = dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
+ Template = Spec->getSpecializedTemplate();
+ return TNK_Class_template;
+ }
+ }
}
// FIXME: What follows is a gross hack.
@@ -469,7 +491,7 @@
// If we had a scope specifier, we better have a previous template
// declaration!
- TagDecl *NewClass =
+ CXXRecordDecl *NewClass =
CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name,
PrevClassTemplate?
PrevClassTemplate->getTemplatedDecl() : 0);
@@ -478,7 +500,8 @@
= ClassTemplateDecl::Create(Context, SemanticContext, NameLoc,
DeclarationName(Name), TemplateParams,
NewClass, PrevClassTemplate);
-
+ NewClass->setDescribedClassTemplate(NewTemplate);
+
// Set the lexical context of these templates
NewClass->setLexicalDeclContext(CurContext);
NewTemplate->setLexicalDeclContext(CurContext);
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 46076f2..adddb29 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -279,6 +279,8 @@
if (!D->isInjectedClassName())
Record->setInstantiationOfMemberClass(D);
+ else
+ Record->setDescribedClassTemplate(D->getDescribedClassTemplate());
Owner->addDecl(Record);
return Record;