summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclTemplate.h3
-rw-r--r--lib/AST/ASTImporter.cpp3
-rw-r--r--lib/AST/DeclTemplate.cpp4
-rw-r--r--lib/Sema/SemaTemplate.cpp16
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp6
-rw-r--r--test/Misc/ast-dump-decl.cpp1
-rw-r--r--test/Modules/Inputs/PR31469/empty.h1
-rw-r--r--test/Modules/Inputs/PR31469/module.modulemap5
-rw-r--r--test/Modules/Inputs/PR31469/textual.h17
-rw-r--r--test/Modules/Inputs/PR31469/textual_file_shadow.h2
-rw-r--r--test/Modules/pr31469.cpp15
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