summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVassil Vassilev <v.g.vassilev@gmail.com>2017-01-12 09:16:26 +0000
committerVassil Vassilev <v.g.vassilev@gmail.com>2017-01-12 09:16:26 +0000
commitde0c61bab9ebf86a08a18b281fe018f3a5eed358 (patch)
treede8c2c169d326c4dc2869794d3f250e7db944db6
parent5ceef6b013ae141fdda2dcda40d5f65e44693075 (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.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