Fix PR18307: Properly (de)serialize inherited constructors and their using declarations
authorStephan Tolksdorf <st@quanttec.com>
Thu, 27 Mar 2014 19:22:19 +0000 (19:22 +0000)
committerStephan Tolksdorf <st@quanttec.com>
Thu, 27 Mar 2014 19:22:19 +0000 (19:22 +0000)
Reviewed in http://llvm-reviews.chandlerc.com/D3102

llvm-svn: 204951

clang/lib/Serialization/ASTReaderDecl.cpp
clang/lib/Serialization/ASTWriter.cpp
clang/lib/Serialization/ASTWriterDecl.cpp
clang/test/PCH/cxx11-inheriting-ctors.cpp [new file with mode: 0644]

index f266eba..7d95072 100644 (file)
@@ -1348,7 +1348,9 @@ void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
 
 void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
   VisitCXXMethodDecl(D);
-  
+
+  if (auto *CD = ReadDeclAs<CXXConstructorDecl>(Record, Idx))
+    D->setInheritedConstructor(CD);
   D->IsExplicitSpecified = Record[Idx++];
   std::tie(D->CtorInitializers, D->NumCtorInitializers) =
       Reader.ReadCXXCtorInitializers(F, Record, Idx);
index 33f7e56..30eaa3a 100644 (file)
@@ -3411,7 +3411,9 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *DC,
   ASTDeclContextNameLookupTrait Trait(*this);
 
   // Create the on-disk hash table representation.
+  DeclarationName ConstructorName;
   DeclarationName ConversionName;
+  SmallVector<NamedDecl *, 8> ConstructorDecls;
   SmallVector<NamedDecl *, 4> ConversionDecls;
 
   auto AddLookupResult = [&](DeclarationName Name,
@@ -3419,16 +3421,25 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *DC,
     if (Result.empty())
       return;
 
-    if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) {
-      // Hash all conversion function names to the same name. The actual
-      // type information in conversion function name is not used in the
-      // key (since such type information is not stable across different
-      // modules), so the intended effect is to coalesce all of the conversion
-      // functions under a single key.
+    // Different DeclarationName values of certain kinds are mapped to
+    // identical serialized keys, because we don't want to use type
+    // identifiers in the keys (since type ids are local to the module).
+    switch (Name.getNameKind()) {
+    case DeclarationName::CXXConstructorName:
+      // There may be different CXXConstructorName DeclarationName values
+      // in a DeclContext because a UsingDecl that inherits constructors
+      // has the DeclarationName of the inherited constructors.
+      if (!ConstructorName)
+        ConstructorName = Name;
+      ConstructorDecls.append(Result.begin(), Result.end());
+      return;
+    case DeclarationName::CXXConversionFunctionName:
       if (!ConversionName)
         ConversionName = Name;
       ConversionDecls.append(Result.begin(), Result.end());
       return;
+    default:
+      break;
     }
 
     Generator.insert(Name, Result, Trait);
@@ -3458,7 +3469,14 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *DC,
     // FIXME: const_cast since OnDiskHashTable wants a non-const lookup result.
     AddLookupResult(Name, const_cast<DeclContext*>(DC)->lookup(Name));
 
-  // Add the conversion functions
+  // Add the constructors.
+  if (!ConstructorDecls.empty()) {
+    Generator.insert(ConstructorName,
+                     DeclContext::lookup_result(ConstructorDecls.begin(),
+                                                ConstructorDecls.end()),
+                     Trait);
+  }
+  // Add the conversion functions.
   if (!ConversionDecls.empty()) {
     Generator.insert(ConversionName,
                      DeclContext::lookup_result(ConversionDecls.begin(),
index f0b0312..14304ab 100644 (file)
@@ -1030,6 +1030,7 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
 void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
   VisitCXXMethodDecl(D);
 
+  Writer.AddDeclRef(D->getInheritedConstructor(), Record);
   Record.push_back(D->IsExplicitSpecified);
   Writer.AddCXXCtorInitializers(D->CtorInitializers, D->NumCtorInitializers,
                                 Record);
diff --git a/clang/test/PCH/cxx11-inheriting-ctors.cpp b/clang/test/PCH/cxx11-inheriting-ctors.cpp
new file mode 100644 (file)
index 0000000..79f78ba
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -std=c++11 -emit-pch -o %t %s
+// RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s
+
+// expected-no-diagnostics
+
+#ifndef HEADER_INCLUDED
+#define HEADER_INCLUDED
+
+struct Base {
+  Base(int) {}
+
+  template <typename T>
+  Base(T) {}
+};
+
+struct Test : Base {
+  using Base::Base;
+};
+
+template <typename T>
+struct Test2 : Base {
+  using Base::Base;
+};
+
+template <typename B>
+struct Test3 : B {
+  using B::B;
+};
+
+#else
+
+Test test1a(42);
+Test test1b(nullptr);
+Test2<int> test2a(42);
+Test2<int> test2b(nullptr);
+Test3<Base> test3a(42);
+Test3<Base> test3b(nullptr);
+
+#endif // HEADER_INCLUDED