From de0c61bab9ebf86a08a18b281fe018f3a5eed358 Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Thu, 12 Jan 2017 09:16:26 +0000 Subject: PR31469: Don't add friend template class decls to redecl chain in dependent contexts. Fixes a crash in modules where the template class decl becomes the most recent decl in the redeclaration chain and forcing the template instantiator try to instantiate the friend declaration, rather than the template definition. In practice, A::list produces a TemplateSpecializationType A::__1::list >' failing to replace to subsitute the default argument to allocator. Kudos Richard Smith (D28399). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@291753 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclTemplate.h | 3 +-- lib/AST/ASTImporter.cpp | 3 +-- lib/AST/DeclTemplate.cpp | 4 +--- lib/Sema/SemaTemplate.cpp | 16 ++++++++++++++-- lib/Sema/SemaTemplateInstantiateDecl.cpp | 6 ++++-- test/Misc/ast-dump-decl.cpp | 1 - test/Modules/Inputs/PR31469/empty.h | 1 + test/Modules/Inputs/PR31469/module.modulemap | 5 +++++ test/Modules/Inputs/PR31469/textual.h | 17 +++++++++++++++++ test/Modules/Inputs/PR31469/textual_file_shadow.h | 2 ++ test/Modules/pr31469.cpp | 15 +++++++++++++++ 11 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 test/Modules/Inputs/PR31469/empty.h create mode 100644 test/Modules/Inputs/PR31469/module.modulemap create mode 100644 test/Modules/Inputs/PR31469/textual.h create mode 100644 test/Modules/Inputs/PR31469/textual_file_shadow.h create mode 100644 test/Modules/pr31469.cpp diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 2af95c02c4..dc50a190de 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -2028,8 +2028,7 @@ public: SourceLocation L, DeclarationName Name, TemplateParameterList *Params, - NamedDecl *Decl, - ClassTemplateDecl *PrevDecl); + NamedDecl *Decl); /// \brief Create an empty class template node. static ClassTemplateDecl *CreateDeserialized(ASTContext &C, unsigned ID); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 67e96ea828..1ccb746633 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -4671,8 +4671,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { ClassTemplateDecl *D2 = ClassTemplateDecl::Create(Importer.getToContext(), DC, Loc, Name, TemplateParams, - D2Templated, - /*PrevDecl=*/nullptr); + D2Templated); D2Templated->setDescribedClassTemplate(D2); D2->setAccess(D->getAccess()); diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 8643cbfcd9..a5fbb0a3ba 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -297,12 +297,10 @@ ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, SourceLocation L, DeclarationName Name, TemplateParameterList *Params, - NamedDecl *Decl, - ClassTemplateDecl *PrevDecl) { + NamedDecl *Decl) { AdoptTemplateParameterList(Params, cast(Decl)); ClassTemplateDecl *New = new (C, DC) ClassTemplateDecl(C, DC, L, Name, Params, Decl); - New->setPreviousDecl(PrevDecl); return New; } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 447ed890d6..7edef7075c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1224,9 +1224,17 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, } } + // If this is a templated friend in a dependent context we should not put it + // on the redecl chain. In some cases, the templated friend can be the most + // recent declaration tricking the template instantiator to make substitutions + // there. + // FIXME: Figure out how to combine with shouldLinkDependentDeclWithPrevious + bool ShouldAddRedecl + = !(TUK == TUK_Friend && CurContext->isDependentContext()); + CXXRecordDecl *NewClass = CXXRecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name, - PrevClassTemplate? + PrevClassTemplate && ShouldAddRedecl ? PrevClassTemplate->getTemplatedDecl() : nullptr, /*DelayTypeCreation=*/true); SetNestedNameSpecifier(NewClass, SS); @@ -1245,7 +1253,11 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams, - NewClass, PrevClassTemplate); + NewClass); + + if (ShouldAddRedecl) + NewTemplate->setPreviousDecl(PrevClassTemplate); + NewClass->setDescribedClassTemplate(NewTemplate); if (ModulePrivateLoc.isValid()) diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 7042400aeb..48d8b94af1 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1219,8 +1219,10 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { ClassTemplateDecl *Inst = ClassTemplateDecl::Create(SemaRef.Context, DC, D->getLocation(), - D->getIdentifier(), InstParams, RecordInst, - PrevClassTemplate); + D->getIdentifier(), InstParams, RecordInst); + assert(!(isFriend && Owner->isDependentContext())); + Inst->setPreviousDecl(PrevClassTemplate); + RecordInst->setDescribedClassTemplate(Inst); if (isFriend) { diff --git a/test/Misc/ast-dump-decl.cpp b/test/Misc/ast-dump-decl.cpp index 1cfcd509ef..c966e133eb 100644 --- a/test/Misc/ast-dump-decl.cpp +++ b/test/Misc/ast-dump-decl.cpp @@ -336,7 +336,6 @@ namespace testCanonicalTemplate { // CHECK-NEXT: ClassTemplateDecl{{.*}} TestClassTemplate // CHECK-NEXT: TemplateTypeParmDecl // CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate - // CHECK-NEXT: ClassTemplateSpecialization{{.*}} 'TestClassTemplate' // CHECK-NEXT: ClassTemplateSpecializationDecl{{.*}} class TestClassTemplate // CHECK-NEXT: TemplateArgument{{.*}}A // CHECK-NEXT: CXXRecordDecl{{.*}} class TestClassTemplate diff --git a/test/Modules/Inputs/PR31469/empty.h b/test/Modules/Inputs/PR31469/empty.h new file mode 100644 index 0000000000..51e115f57f --- /dev/null +++ b/test/Modules/Inputs/PR31469/empty.h @@ -0,0 +1 @@ +// This file is triggers loading of module M. diff --git a/test/Modules/Inputs/PR31469/module.modulemap b/test/Modules/Inputs/PR31469/module.modulemap new file mode 100644 index 0000000000..bada81d04e --- /dev/null +++ b/test/Modules/Inputs/PR31469/module.modulemap @@ -0,0 +1,5 @@ +module M { + module "textual_shadow" { header "textual_file_shadow.h" export *} + module "trigger" { header "empty.h" export * } + export * +} diff --git a/test/Modules/Inputs/PR31469/textual.h b/test/Modules/Inputs/PR31469/textual.h new file mode 100644 index 0000000000..abdc662fb5 --- /dev/null +++ b/test/Modules/Inputs/PR31469/textual.h @@ -0,0 +1,17 @@ +namespace A { +inline +namespace __1 { + template class allocator; + template > class list; + template class __list_iterator { + //template friend class list; // causes another crash in ASTDeclReader::attachPreviousDecl + template friend class list; + }; + template class __list_imp {}; + template class list : __list_imp<_Tp, _Alloc> { + public: + list() {} + }; + template void f(list<_Tp>); +} +} diff --git a/test/Modules/Inputs/PR31469/textual_file_shadow.h b/test/Modules/Inputs/PR31469/textual_file_shadow.h new file mode 100644 index 0000000000..48a53dd4a8 --- /dev/null +++ b/test/Modules/Inputs/PR31469/textual_file_shadow.h @@ -0,0 +1,2 @@ +#include "textual.h" + diff --git a/test/Modules/pr31469.cpp b/test/Modules/pr31469.cpp new file mode 100644 index 0000000000..8f7d52285c --- /dev/null +++ b/test/Modules/pr31469.cpp @@ -0,0 +1,15 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -std=c++11 -I%S/Inputs/PR31469 -verify %s +// RUN: %clang_cc1 -std=c++11 -I%S/Inputs/PR31469 -fmodules -fmodules-local-submodule-visibility \ +// RUN: -fimplicit-module-maps -fmodules-cache-path=%t -verify %s + +#include "textual.h" +#include "empty.h" + +namespace A { + template void f(); +} + +A::list use; + +// expected-no-diagnostics -- cgit v1.2.3