diff options
-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 |