diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 27 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 2 | ||||
-rw-r--r-- | test/SemaTemplate/fibonacci.cpp | 18 | ||||
-rw-r--r-- | test/SemaTemplate/injected-class-name.cpp | 17 |
6 files changed, 64 insertions, 5 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index f4df88c94c..991102e24e 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -515,7 +515,8 @@ public: /// the first declaration of that tag. TagDecl *getCanonicalDecl(TagDecl *Tag) { QualType T = getTagDeclType(Tag); - return cast<TagDecl>(cast<TagType>(T)->getDecl()); + return cast<TagDecl>(cast<TagType>(T.getTypePtr()->CanonicalType) + ->getDecl()); } /// Type Query functions. If the type is an instance of the specified class, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 835792ee2d..88c08b0f75 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3425,6 +3425,8 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclTy *TagD) { 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 24b35ee5f5..c0476a8d3f 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -42,6 +42,28 @@ TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S, 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 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, // 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 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, = 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 46076f261a..adddb2997a 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -279,6 +279,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { if (!D->isInjectedClassName()) Record->setInstantiationOfMemberClass(D); + else + Record->setDescribedClassTemplate(D->getDescribedClassTemplate()); Owner->addDecl(Record); return Record; diff --git a/test/SemaTemplate/fibonacci.cpp b/test/SemaTemplate/fibonacci.cpp index e8a1ec772e..6cd50157e2 100644 --- a/test/SemaTemplate/fibonacci.cpp +++ b/test/SemaTemplate/fibonacci.cpp @@ -1,7 +1,5 @@ // RUN: clang-cc -fsyntax-only %s -// FIXME: The Fibonacci/FibonacciEval dance is here to work around our -// inability to parse injected-class-name<template-argument-list>. template<unsigned I> struct FibonacciEval; @@ -50,3 +48,19 @@ template<> struct Fibonacci2<1> { int array5_2[Fibonacci2<5>::value == 5? 1 : -1]; int array10_2[Fibonacci2<10>::value == 55? 1 : -1]; + +template<unsigned I> +struct Fibonacci3 { + static const unsigned value = Fibonacci3<I-1>::value + Fibonacci3<I-2>::value; +}; + +template<> struct Fibonacci3<0> { + static const unsigned value = 0; +}; + +template<> struct Fibonacci3<1> { + static const unsigned value = 1; +}; + +int array5_3[Fibonacci3<5>::value == 5? 1 : -1]; +int array10_3[Fibonacci3<10>::value == 55? 1 : -1]; diff --git a/test/SemaTemplate/injected-class-name.cpp b/test/SemaTemplate/injected-class-name.cpp new file mode 100644 index 0000000000..43fb454bca --- /dev/null +++ b/test/SemaTemplate/injected-class-name.cpp @@ -0,0 +1,17 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template<typename T> +struct X { + X<T*> *ptr; +}; + +X<int> x; + +template<> +struct X<int***> { + typedef X<int***> *ptr; +}; + +// FIXME: EDG rejects this in their strict-conformance mode, but I +// don't see any wording making this ill-formed. +X<float>::X<int> xi = x; |