Index: include/clang/AST/DeclTemplate.h =================================================================== --- include/clang/AST/DeclTemplate.h +++ include/clang/AST/DeclTemplate.h @@ -2028,8 +2028,7 @@ 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); Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -4671,8 +4671,7 @@ ClassTemplateDecl *D2 = ClassTemplateDecl::Create(Importer.getToContext(), DC, Loc, Name, TemplateParams, - D2Templated, - /*PrevDecl=*/nullptr); + D2Templated); D2Templated->setDescribedClassTemplate(D2); D2->setAccess(D->getAccess()); Index: lib/AST/DeclTemplate.cpp =================================================================== --- lib/AST/DeclTemplate.cpp +++ lib/AST/DeclTemplate.cpp @@ -297,12 +297,10 @@ 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; } Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -1224,9 +1224,17 @@ } } + // 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 @@ ClassTemplateDecl *NewTemplate = ClassTemplateDecl::Create(Context, SemanticContext, NameLoc, DeclarationName(Name), TemplateParams, - NewClass, PrevClassTemplate); + NewClass); + + if (ShouldAddRedecl) + NewTemplate->setPreviousDecl(PrevClassTemplate); + NewClass->setDescribedClassTemplate(NewTemplate); if (ModulePrivateLoc.isValid()) Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1193,8 +1193,10 @@ 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) { Index: test/Misc/ast-dump-decl.cpp =================================================================== --- test/Misc/ast-dump-decl.cpp +++ test/Misc/ast-dump-decl.cpp @@ -336,7 +336,6 @@ // 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 Index: test/Modules/Inputs/PR31469/empty.h =================================================================== --- /dev/null +++ test/Modules/Inputs/PR31469/empty.h @@ -0,0 +1 @@ +// This file is triggers loading of module M. Index: test/Modules/Inputs/PR31469/module.modulemap =================================================================== --- /dev/null +++ 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 * +} Index: test/Modules/Inputs/PR31469/textual.h =================================================================== --- /dev/null +++ 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>); +} +} Index: test/Modules/Inputs/PR31469/textual_file_shadow.h =================================================================== --- /dev/null +++ test/Modules/Inputs/PR31469/textual_file_shadow.h @@ -0,0 +1,2 @@ +#include "textual.h" + Index: test/Modules/pr31469.cpp =================================================================== --- /dev/null +++ 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