[modules] When merging a class template, also merge the definition of its pattern.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 11 Jul 2014 18:22:58 +0000 (18:22 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 11 Jul 2014 18:22:58 +0000 (18:22 +0000)
llvm-svn: 212836

clang/lib/Serialization/ASTReaderDecl.cpp
clang/test/Modules/Inputs/cxx-templates-a.h
clang/test/Modules/Inputs/cxx-templates-c.h
clang/test/Modules/cxx-templates.cpp

index f9fed46..5ef4a5c 100644 (file)
@@ -1758,11 +1758,11 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl(
             Reader.MergedDeclContexts.insert(
                 std::make_pair(D, CanonDD->Definition));
             D->IsCompleteDefinition = false;
-            D->DefinitionData = CanonSpec->DefinitionData;
           } else {
             CanonSpec->DefinitionData = D->DefinitionData;
           }
         }
+        D->DefinitionData = CanonSpec->DefinitionData;
       }
     }
   }
@@ -2037,10 +2037,27 @@ void ASTDeclReader::mergeTemplatePattern(RedeclarableTemplateDecl *D,
   auto *DPattern = D->getTemplatedDecl();
   auto *ExistingPattern = Existing->getTemplatedDecl();
   RedeclarableResult Result(Reader, DsID, DPattern->getKind());
-  if (auto *DClass = dyn_cast<CXXRecordDecl>(DPattern))
-    // FIXME: Merge definitions here, if both declarations had definitions.
+  if (auto *DClass = dyn_cast<CXXRecordDecl>(DPattern)) {
+    // Merge with any existing definition.
+    // FIXME: This is duplicated in several places. Refactor.
+    auto *ExistingClass =
+        cast<CXXRecordDecl>(ExistingPattern)->getCanonicalDecl();
+    if (auto *DDD = DClass->DefinitionData.getNotUpdated()) {
+      if (auto *ExistingDD = ExistingClass->DefinitionData.getNotUpdated()) {
+        MergeDefinitionData(ExistingClass, *DDD);
+        Reader.PendingDefinitions.erase(DClass);
+        Reader.MergedDeclContexts.insert(
+            std::make_pair(DClass, ExistingDD->Definition));
+        DClass->IsCompleteDefinition = false;
+      } else {
+        ExistingClass->DefinitionData = DClass->DefinitionData;
+      }
+    }
+    DClass->DefinitionData = ExistingClass->DefinitionData;
+
     return mergeRedeclarable(DClass, cast<TagDecl>(ExistingPattern),
                              Result);
+  }
   if (auto *DFunction = dyn_cast<FunctionDecl>(DPattern))
     return mergeRedeclarable(DFunction, cast<FunctionDecl>(ExistingPattern),
                              Result);
index 5ac1697..c95dc63 100644 (file)
@@ -67,3 +67,9 @@ template<> struct WithExplicitSpecialization<int> {
 template<typename T> template<typename U>
 constexpr int Outer<T>::Inner<U>::f() { return 1; }
 static_assert(Outer<int>::Inner<int>::f() == 1, "");
+
+template<typename T> struct MergeTemplateDefinitions {
+  static constexpr int f();
+  static constexpr int g();
+};
+template<typename T> constexpr int MergeTemplateDefinitions<T>::f() { return 1; }
index 4c0fc8a..6daffad 100644 (file)
@@ -5,3 +5,9 @@ template<typename T> struct MergeSpecializations<T[]> {
 template<> struct MergeSpecializations<bool> {
   typedef int explicitly_specialized_in_c;
 };
+
+template<typename T> struct MergeTemplateDefinitions {
+  static constexpr int f();
+  static constexpr int g();
+};
+template<typename T> constexpr int MergeTemplateDefinitions<T>::g() { return 2; }
index 679d7d1..cbe9f35 100644 (file)
@@ -110,6 +110,9 @@ void g() {
 static_assert(Outer<int>::Inner<int>::f() == 1, "");
 static_assert(Outer<int>::Inner<int>::g() == 2, "");
 
+static_assert(MergeTemplateDefinitions<int>::f() == 1, "");
+static_assert(MergeTemplateDefinitions<int>::g() == 2, "");
+
 RedeclaredAsFriend<int> raf1;
 RedeclareTemplateAsFriend<double> rtaf;
 RedeclaredAsFriend<double> raf2;