]> granicus.if.org Git - clang/commitdiff
PR31469: Don't add friend template class decls to redecl chain in dependent contexts.
authorVassil Vassilev <v.g.vassilev@gmail.com>
Thu, 12 Jan 2017 09:16:26 +0000 (09:16 +0000)
committerVassil Vassilev <v.g.vassilev@gmail.com>
Thu, 12 Jan 2017 09:16:26 +0000 (09:16 +0000)
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

include/clang/AST/DeclTemplate.h
lib/AST/ASTImporter.cpp
lib/AST/DeclTemplate.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
test/Misc/ast-dump-decl.cpp
test/Modules/Inputs/PR31469/empty.h [new file with mode: 0644]
test/Modules/Inputs/PR31469/module.modulemap [new file with mode: 0644]
test/Modules/Inputs/PR31469/textual.h [new file with mode: 0644]
test/Modules/Inputs/PR31469/textual_file_shadow.h [new file with mode: 0644]
test/Modules/pr31469.cpp [new file with mode: 0644]

index 2af95c02c46032d292dbd6eeef212e6bac41dbc6..dc50a190de42d21d98190fd345892d64ed778e30 100644 (file)
@@ -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);
index 67e96ea828bdf2521250d1b67e715f84b7bcef39..1ccb746633a765fe21642da77228b7331484394b 100644 (file)
@@ -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());
index 8643cbfcd960accf50613c7743a0dd1999d8d590..a5fbb0a3baecef24ef47e2d73ac904be7d7a0ed0 100644 (file)
@@ -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;
 }
 
index 447ed890d60f357fd41ee1680e38a36dc6bbea9f..7edef7075cc850d331b5f6fb2919e5aab145c7e7 100644 (file)
@@ -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())
index 7042400aeb372870ccbc46fcc9cac275ba2ca1b0..48d8b94af1539e96e17830f5346af80ed9bfb3c9 100644 (file)
@@ -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) {
index 1cfcd509efabdf91f39dd1ed92957dd1cf6aae11..c966e133eb5dda81910d51a42d76d04180b9c4be 100644 (file)
@@ -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 (file)
index 0000000..51e115f
--- /dev/null
@@ -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 (file)
index 0000000..bada81d
--- /dev/null
@@ -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 (file)
index 0000000..abdc662
--- /dev/null
@@ -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 (file)
index 0000000..48a53dd
--- /dev/null
@@ -0,0 +1,2 @@
+#include "textual.h"
+
diff --git a/test/Modules/pr31469.cpp b/test/Modules/pr31469.cpp
new file mode 100644 (file)
index 0000000..8f7d522
--- /dev/null
@@ -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