Fix deserializing of class template partial specializations. Assign sequence
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 25 Jun 2013 01:25:15 +0000 (01:25 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 25 Jun 2013 01:25:15 +0000 (01:25 +0000)
numbers as we deserialize class template partial specializations. We can't
assume that the old sequence numbers will work.

The sequence numbers are still deterministic, but are now a lot less
predictable for class template partial specializations in modules/PCH.

llvm-svn: 184811

clang/include/clang/AST/DeclTemplate.h
clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/Modules/Inputs/cxx-templates-a.h
clang/test/Modules/Inputs/cxx-templates-b.h
clang/test/Modules/Inputs/cxx-templates-common.h [new file with mode: 0644]
clang/test/Modules/Inputs/module.map
clang/test/Modules/cxx-templates.cpp

index d301da8..89c0f05 100644 (file)
@@ -1711,7 +1711,8 @@ public:
   }
 
   /// \brief Get the sequence number for this class template partial
-  /// specialization.
+  /// specialization. Internal, only valid for specializations which
+  /// are in the specialized class template's folding set.
   unsigned getSequenceNumber() const { return SequenceNumber; }
 
   /// \brief Retrieve the member class template partial specialization from
@@ -1928,7 +1929,9 @@ public:
 
   /// \brief Return the next partial specialization sequence number.
   unsigned getNextPartialSpecSequenceNumber() {
-    return getPartialSpecializations().size();
+    // Do not load lazy specializations here. They get numbered as they are
+    // loaded.
+    return getCommonPtr()->PartialSpecializations.size();
   }
 
   /// \brief Retrieve the partial specializations as an ordered list.
index a7305c8..df6abc9 100644 (file)
@@ -1458,9 +1458,12 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
   if (writtenAsCanonicalDecl) {
     ClassTemplateDecl *CanonPattern = ReadDeclAs<ClassTemplateDecl>(Record,Idx);
     if (D->isCanonicalDecl()) { // It's kept in the folding set.
-      if (ClassTemplatePartialSpecializationDecl *Partial
-                        = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
-  CanonPattern->getCommonPtr()->PartialSpecializations.GetOrInsertNode(Partial);
+      if (ClassTemplatePartialSpecializationDecl *Partial =
+              dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
+        Partial->SequenceNumber =
+            CanonPattern->getNextPartialSpecSequenceNumber();
+        CanonPattern->getCommonPtr()->PartialSpecializations
+            .GetOrInsertNode(Partial);
       } else {
         CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D);
       }
@@ -1485,8 +1488,6 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl(
       D->ArgsAsWritten[i] = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
   }
 
-  D->SequenceNumber = Record[Idx++];
-
   // These are read/set from/to the first declaration.
   if (ThisDeclID == Redecl.getFirstID()) {
     D->InstantiatedFromMember.setPointer(
index b601064..d8d351a 100644 (file)
@@ -1174,8 +1174,6 @@ void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl(
   for (int i = 0, e = D->getNumTemplateArgsAsWritten(); i != e; ++i)
     Writer.AddTemplateArgumentLoc(D->getTemplateArgsAsWritten()[i], Record);
 
-  Record.push_back(D->getSequenceNumber());
-
   // These are read/set from/to the first declaration.
   if (D->getPreviousDecl() == 0) {
     Writer.AddDeclRef(D->getInstantiatedFromMember(), Record);
index 76997c7..7770d34 100644 (file)
@@ -1,3 +1,5 @@
+@import cxx_templates_common;
+
 template<typename T> T f() { return T(); }
 template<typename T> T f(T);
 namespace N {
@@ -8,3 +10,7 @@ namespace N {
 template<int N> int template_param_kinds_1();
 template<template<typename T, int, int> class> int template_param_kinds_2();
 template<template<typename T, typename U, T> class> int template_param_kinds_3();
+
+template<typename T> struct SomeTemplate<T*>;
+template<typename T> struct SomeTemplate<T*> {};
+typedef SomeTemplate<int*> SomeTemplateIntPtr;
index c50d705..e0f67d0 100644 (file)
@@ -1,3 +1,5 @@
+@import cxx_templates_common;
+
 template<typename T> T f();
 template<typename T> T f(T t) { return t; }
 namespace N {
@@ -8,3 +10,7 @@ namespace N {
 template<typename> int template_param_kinds_1();
 template<template<typename, int, int...> class> int template_param_kinds_2();
 template<template<typename T, typename U, U> class> int template_param_kinds_3();
+
+template<typename T> struct SomeTemplate<T&> {};
+template<typename T> struct SomeTemplate<T&>;
+typedef SomeTemplate<int&> SomeTemplateIntRef;
diff --git a/clang/test/Modules/Inputs/cxx-templates-common.h b/clang/test/Modules/Inputs/cxx-templates-common.h
new file mode 100644 (file)
index 0000000..950a2a6
--- /dev/null
@@ -0,0 +1 @@
+template<typename T> struct SomeTemplate {};
index d2ed758..a4ac5b1 100644 (file)
@@ -188,6 +188,10 @@ module cxx_linkage_cache {
   header "cxx-linkage-cache.h"
 }
 
+module cxx_templates_common {
+  header "cxx-templates-common.h"
+}
+
 module cxx_templates_a {
   header "cxx-templates-a.h"
 }
index 7d500f4..84c93df 100644 (file)
@@ -17,37 +17,44 @@ void g() {
   f<double>(1.0);
   f<int>();
   f(); // expected-error {{no matching function}}
-  // expected-note@Inputs/cxx-templates-b.h:1 {{couldn't infer template argument}}
-  // expected-note@Inputs/cxx-templates-b.h:2 {{requires single argument}}
+  // expected-note@Inputs/cxx-templates-b.h:3 {{couldn't infer template argument}}
+  // expected-note@Inputs/cxx-templates-b.h:4 {{requires single argument}}
 
   N::f(0);
   N::f<double>(1.0);
   N::f<int>();
   N::f(); // expected-error {{no matching function}}
-  // expected-note@Inputs/cxx-templates-a.h:4 {{couldn't infer template argument}}
-  // expected-note@Inputs/cxx-templates-a.h:5 {{requires 1 argument, but 0 were provided}}
+  // expected-note@Inputs/cxx-templates-a.h:6 {{couldn't infer template argument}}
+  // expected-note@Inputs/cxx-templates-a.h:7 {{requires 1 argument, but 0 were provided}}
 
   template_param_kinds_1<0>(); // ok, from cxx-templates-a.h
   template_param_kinds_1<int>(); // ok, from cxx-templates-b.h
 
   template_param_kinds_2<Tmpl_T_C>(); // expected-error {{no matching function}}
-  // expected-note@Inputs/cxx-templates-a.h:9 {{invalid explicitly-specified argument}}
-  // expected-note@Inputs/cxx-templates-b.h:9 {{invalid explicitly-specified argument}}
+  // expected-note@Inputs/cxx-templates-a.h:11 {{invalid explicitly-specified argument}}
+  // expected-note@Inputs/cxx-templates-b.h:11 {{invalid explicitly-specified argument}}
 
   template_param_kinds_2<Tmpl_T_I_I>(); // expected-error {{ambiguous}}
-  // expected-note@Inputs/cxx-templates-a.h:9 {{candidate}}
-  // expected-note@Inputs/cxx-templates-b.h:9 {{candidate}}
+  // expected-note@Inputs/cxx-templates-a.h:11 {{candidate}}
+  // expected-note@Inputs/cxx-templates-b.h:11 {{candidate}}
 
   // FIXME: This should be valid, but we incorrectly match the template template
   // argument against both template template parameters.
   template_param_kinds_3<Tmpl_T_T_A>(); // expected-error {{ambiguous}}
-  // expected-note@Inputs/cxx-templates-a.h:10 {{candidate}}
-  // expected-note@Inputs/cxx-templates-b.h:10 {{candidate}}
+  // expected-note@Inputs/cxx-templates-a.h:12 {{candidate}}
+  // expected-note@Inputs/cxx-templates-b.h:12 {{candidate}}
   template_param_kinds_3<Tmpl_T_T_B>(); // expected-error {{ambiguous}}
-  // expected-note@Inputs/cxx-templates-a.h:10 {{candidate}}
-  // expected-note@Inputs/cxx-templates-b.h:10 {{candidate}}
+  // expected-note@Inputs/cxx-templates-a.h:12 {{candidate}}
+  // expected-note@Inputs/cxx-templates-b.h:12 {{candidate}}
 }
 
+@import cxx_templates_common;
+
+typedef SomeTemplate<int*> SomeTemplateIntPtr;
+typedef SomeTemplate<int&> SomeTemplateIntRef;
+SomeTemplate<char*> some_template_char_ptr;
+SomeTemplate<char&> some_template_char_ref;
+
 // FIXME: There should only be two 'f's here.
 // CHECK-GLOBAL:      DeclarationName 'f'
 // CHECK-GLOBAL-NEXT: |-FunctionTemplate {{.*}} 'f'