From fd7c225530b0c42e95bf5f9c22314a4479748cf9 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 4 Mar 2011 17:52:15 +0000 Subject: [PATCH] Make sure to put template parameters into their owning template's DeclContext once we've created it. This mirrors what we do for function parameters, where the parameters start out with translation-unit context and then are adopted by the appropriate DeclContext when it is created. Also give template parameters public access and make sure that they don't show up for the purposes of name lookup. Fixes PR9400, a regression introduced by r126920, which implemented substitution of default template arguments provided in template template parameters (C++ core issue 150). How on earth could the DeclContext of a template parameter affect the handling of default template arguments? I'm so glad you asked! The link is Sema::getTemplateInstantiationArgs(), which determines the outer template argument lists that correspond to a given declaration. When we're instantiating a default template argument for a template template parameter within the body of a template definition (not it's instantiation, per core issue 150), we weren't getting any outer template arguments because the context of the template template parameter was the translation unit. Now that the context of the template template parameter is its owning template, we get the template arguments from the injected-class-name of the owning template, so substitution works as it should. llvm-svn: 127004 --- clang/include/clang/AST/DeclTemplate.h | 21 ++++--- clang/lib/AST/DeclBase.cpp | 4 +- clang/lib/AST/DeclTemplate.cpp | 47 +++++++++++++++ clang/lib/Sema/SemaTemplate.cpp | 7 ++- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 5 +- clang/lib/Serialization/ASTReaderDecl.cpp | 8 +-- clang/test/SemaTemplate/issue150.cpp | 58 +++++++++++++++++++ 7 files changed, 131 insertions(+), 19 deletions(-) diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 28021564cb75..9c20969c1f58 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -844,13 +844,16 @@ public: return makeSpecIterator(getSpecializations(), true); } - /// Create a template function node. + /// \brief Create a function template node. static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl); + /// \brief Create an empty function template node. + static FunctionTemplateDecl *Create(ASTContext &C, EmptyShell); + // Implement isa/cast/dyncast support static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const FunctionTemplateDecl *D) { return true; } @@ -1556,14 +1559,7 @@ class ClassTemplatePartialSpecializationDecl TemplateArgumentLoc *ArgInfos, unsigned NumArgInfos, ClassTemplatePartialSpecializationDecl *PrevDecl, - unsigned SequenceNumber) - : ClassTemplateSpecializationDecl(Context, - ClassTemplatePartialSpecialization, - TK, DC, L, SpecializedTemplate, - Args, NumArgs, PrevDecl), - TemplateParams(Params), ArgsAsWritten(ArgInfos), - NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber), - InstantiatedFromMember(0, false) { } + unsigned SequenceNumber); ClassTemplatePartialSpecializationDecl() : ClassTemplateSpecializationDecl(ClassTemplatePartialSpecialization), @@ -1746,6 +1742,10 @@ protected: TemplateParameterList *Params, NamedDecl *Decl) : RedeclarableTemplateDecl(ClassTemplate, DC, L, Name, Params, Decl) { } + ClassTemplateDecl(EmptyShell Empty) + : RedeclarableTemplateDecl(ClassTemplate, 0, SourceLocation(), + DeclarationName(), 0, 0) { } + CommonBase *newCommon(ASTContext &C); Common *getCommonPtr() { @@ -1772,6 +1772,9 @@ public: NamedDecl *Decl, ClassTemplateDecl *PrevDecl); + /// Create an empty class template node. + static ClassTemplateDecl *Create(ASTContext &C, EmptyShell); + /// \brief Return the specialization with the provided arguments if it exists, /// otherwise return the insertion point. ClassTemplateSpecializationDecl * diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 81df00d6c7e8..0642f423c6f3 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -960,7 +960,7 @@ void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) { // FIXME: This feels like a hack. Should DeclarationName support // template-ids, or is there a better way to keep specializations // from being visible? - if (isa(D)) + if (isa(D) || D->isTemplateParameter()) return; if (FunctionDecl *FD = dyn_cast(D)) if (FD->isFunctionTemplateSpecialization()) @@ -999,7 +999,7 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { // FIXME: This feels like a hack. Should DeclarationName support // template-ids, or is there a better way to keep specializations // from being visible? - if (isa(D)) + if (isa(D) || D->isTemplateParameter()) return; ASTContext *C = 0; diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 0554cfca3a63..266d913ff4bd 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -165,9 +165,20 @@ FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, DeclarationName Name, TemplateParameterList *Params, NamedDecl *Decl) { + // Take ownership of the template parameters. + for (TemplateParameterList::iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) + (*P)->setDeclContext(cast(Decl)); + return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl); } +FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, EmptyShell) { + return new (C) FunctionTemplateDecl(0, SourceLocation(), DeclarationName(), + 0, 0); +} + RedeclarableTemplateDecl::CommonBase * FunctionTemplateDecl::newCommon(ASTContext &C) { Common *CommonPtr = new (C) Common; @@ -196,11 +207,21 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, TemplateParameterList *Params, NamedDecl *Decl, ClassTemplateDecl *PrevDecl) { + // Take ownership of the template parameters. + for (TemplateParameterList::iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) + (*P)->setDeclContext(cast(Decl)); + ClassTemplateDecl *New = new (C) ClassTemplateDecl(DC, L, Name, Params, Decl); New->setPreviousDeclaration(PrevDecl); return New; } +ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, EmptyShell Empty) { + return new (C) ClassTemplateDecl(Empty); +} + void ClassTemplateDecl::LoadLazySpecializations() { Common *CommonPtr = getCommonPtr(); if (CommonPtr->LazySpecializations) { @@ -593,6 +614,32 @@ ClassTemplateSpecializationDecl::getSourceRange() const { //===----------------------------------------------------------------------===// // ClassTemplatePartialSpecializationDecl Implementation //===----------------------------------------------------------------------===// +ClassTemplatePartialSpecializationDecl:: +ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK, + DeclContext *DC, SourceLocation L, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + TemplateArgumentLoc *ArgInfos, + unsigned NumArgInfos, + ClassTemplatePartialSpecializationDecl *PrevDecl, + unsigned SequenceNumber) + : ClassTemplateSpecializationDecl(Context, + ClassTemplatePartialSpecialization, + TK, DC, L, SpecializedTemplate, + Args, NumArgs, PrevDecl), + TemplateParams(Params), ArgsAsWritten(ArgInfos), + NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber), + InstantiatedFromMember(0, false) +{ + // Take ownership of the template parameters. + for (TemplateParameterList::iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) + (*P)->setDeclContext(this); +} + ClassTemplatePartialSpecializationDecl * ClassTemplatePartialSpecializationDecl:: Create(ASTContext &Context, TagKind TK,DeclContext *DC, SourceLocation L, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 9b0d2611ceef..f70efc1c8e1d 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -527,6 +527,7 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(), Loc, Depth, Position, ParamName, Typename, Ellipsis); + Param->setAccess(AS_public); if (Invalid) Param->setInvalidDecl(); @@ -652,6 +653,8 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, D.getIdentifierLoc(), Depth, Position, ParamName, T, IsParameterPack, TInfo); + Param->setAccess(AS_public); + if (Invalid) Param->setInvalidDecl(); @@ -705,13 +708,13 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, // Construct the parameter object. bool IsParameterPack = EllipsisLoc.isValid(); - // FIXME: Pack-ness is dropped TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), NameLoc.isInvalid()? TmpLoc : NameLoc, Depth, Position, IsParameterPack, Name, Params); - + Param->setAccess(AS_public); + // If the template template parameter has a name, then link the identifier // into the scope and lookup mechanisms. if (Name) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index cbbc2d9f89f4..01c88057ea4f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1447,7 +1447,8 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( TTPT->getIndex(), D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack()); - + Inst->setAccess(AS_public); + if (D->hasDefaultArgument()) Inst->setDefaultArgument(D->getDefaultArgumentInfo(), false); @@ -1595,6 +1596,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( D->getIdentifier(), T, D->isParameterPack(), DI); + Param->setAccess(AS_public); if (Invalid) Param->setInvalidDecl(); @@ -1628,6 +1630,7 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( D->getPosition(), D->isParameterPack(), D->getIdentifier(), InstParams); Param->setDefaultArgument(D->getDefaultArgument(), false); + Param->setAccess(AS_public); // Introduce this template parameter's instantiation into the instantiation // scope. diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 046d901407f0..1e4ff83d5fc3 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -1485,19 +1485,17 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { D = FriendTemplateDecl::Create(*Context, Decl::EmptyShell()); break; case DECL_CLASS_TEMPLATE: - D = ClassTemplateDecl::Create(*Context, 0, SourceLocation(), - DeclarationName(), 0, 0, 0); + D = ClassTemplateDecl::Create(*Context, Decl::EmptyShell()); break; case DECL_CLASS_TEMPLATE_SPECIALIZATION: D = ClassTemplateSpecializationDecl::Create(*Context, Decl::EmptyShell()); break; case DECL_CLASS_TEMPLATE_PARTIAL_SPECIALIZATION: D = ClassTemplatePartialSpecializationDecl::Create(*Context, - Decl::EmptyShell()); + Decl::EmptyShell()); break; case DECL_FUNCTION_TEMPLATE: - D = FunctionTemplateDecl::Create(*Context, 0, SourceLocation(), - DeclarationName(), 0, 0); + D = FunctionTemplateDecl::Create(*Context, Decl::EmptyShell()); break; case DECL_TEMPLATE_TYPE_PARM: D = TemplateTypeParmDecl::Create(*Context, Decl::EmptyShell()); diff --git a/clang/test/SemaTemplate/issue150.cpp b/clang/test/SemaTemplate/issue150.cpp index 647df2cc0b7d..0d7930723fca 100644 --- a/clang/test/SemaTemplate/issue150.cpp +++ b/clang/test/SemaTemplate/issue150.cpp @@ -2,6 +2,16 @@ // Core issue 150: Template template parameters and default arguments +template +struct is_same { + static const bool value = false; +}; + +template +struct is_same { + static const bool value = true; +}; + namespace PR9353 { template class IM; @@ -11,3 +21,51 @@ namespace PR9353 { void f(IM* m) { foo(m); } } + +namespace PR9400 { + template