diff options
author | Vassil Vassilev <v.g.vassilev@gmail.com> | 2017-01-12 09:16:26 +0000 |
---|---|---|
committer | Vassil Vassilev <v.g.vassilev@gmail.com> | 2017-01-12 09:16:26 +0000 |
commit | de0c61bab9ebf86a08a18b281fe018f3a5eed358 (patch) | |
tree | de8c2c169d326c4dc2869794d3f250e7db944db6 | |
parent | 5ceef6b013ae141fdda2dcda40d5f65e44693075 (diff) |
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<int> produces a TemplateSpecializationType
A::__1::list<int, allocator<type-parameter-0-0> >' failing to replace to
subsitute the default argument to allocator<int>.
Kudos Richard Smith (D28399).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@291753 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 3 | ||||
-rw-r--r-- | lib/AST/ASTImporter.cpp | 3 | ||||
-rw-r--r-- | lib/AST/DeclTemplate.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 6 | ||||
-rw-r--r-- | test/Misc/ast-dump-decl.cpp | 1 | ||||
-rw-r--r-- | test/Modules/Inputs/PR31469/empty.h | 1 | ||||
-rw-r--r-- | test/Modules/Inputs/PR31469/module.modulemap | 5 | ||||
-rw-r--r-- | test/Modules/Inputs/PR31469/textual.h | 17 | ||||
-rw-r--r-- | test/Modules/Inputs/PR31469/textual_file_shadow.h | 2 | ||||
-rw-r--r-- | test/Modules/pr31469.cpp | 15 |
11 files changed, 61 insertions, 12 deletions
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<DeclContext>(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 _Tp> class allocator; + template <class _Tp, class _Alloc = allocator<_Tp>> class list; + template <class _VoidPtr> class __list_iterator { + //template <class> friend class list; // causes another crash in ASTDeclReader::attachPreviousDecl + template <class, class> friend class list; + }; + template <class _Tp, class _Alloc> class __list_imp {}; + template <class _Tp, class _Alloc> class list : __list_imp<_Tp, _Alloc> { + public: + list() {} + }; + template <class _Tp> 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 <class _Tp> void f(); +} + +A::list<int> use; + +// expected-no-diagnostics |