]> granicus.if.org Git - clang/commitdiff
Fix an issue with writing to PCH another included PCH, introduced by the "using an...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Fri, 20 Aug 2010 23:35:55 +0000 (23:35 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Fri, 20 Aug 2010 23:35:55 +0000 (23:35 +0000)
When including a PCH and later re-emitting to another PCH, the name lookup tables of DeclContexts
may be incomplete, since we now lazily deserialize the visible decls of a particular name.
Fix the issue by iterating over the un-deserialized visible decls and completing the lookup tables
of DeclContexts before writing them out.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@111698 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/DeclBase.h
include/clang/AST/ExternalASTSource.h
include/clang/Serialization/ASTReader.h
lib/AST/DeclBase.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTWriter.cpp
test/PCH/reinclude.cpp [new file with mode: 0644]
test/PCH/reinclude1.h [new file with mode: 0644]
test/PCH/reinclude2.h [new file with mode: 0644]

index 34092c79931a68f273936697f1d0297e7bc756c5..999e45a94a2c3d3969f141434e0cb3c4ddb75559 100644 (file)
@@ -1095,6 +1095,14 @@ public:
   /// the declaration chains.
   void makeDeclVisibleInContext(NamedDecl *D, bool Recoverable = true);
 
+  /// \brief Deserialize all the visible declarations from external storage.
+  ///
+  /// Name lookup deserializes visible declarations lazily, thus a DeclContext
+  /// may not have a complete name lookup table. This function deserializes
+  /// the rest of visible declarations from the external storage and completes
+  /// the name lookup table.
+  void MaterializeVisibleDeclsFromExternalStorage();
+
   /// udir_iterator - Iterates through the using-directives stored
   /// within this context.
   typedef UsingDirectiveDecl * const * udir_iterator;
@@ -1152,7 +1160,6 @@ public:
 
 private:
   void LoadLexicalDeclsFromExternalStorage() const;
-  void LoadVisibleDeclsFromExternalStorage() const;
 
   friend class DependentDiagnostic;
   StoredDeclsMap *CreateStoredDeclsMap(ASTContext &C) const;
index 24d9bc5bca2b3148963a73dfbe0f63e47665041a..6bd72529e61df55a571bc0588f2a3f9a9852ff0c 100644 (file)
@@ -95,6 +95,14 @@ public:
   FindExternalVisibleDeclsByName(const DeclContext *DC,
                                  DeclarationName Name) = 0;
 
+  /// \brief Deserialize all the visible declarations from external storage.
+  ///
+  /// Name lookup deserializes visible declarations lazily, thus a DeclContext
+  /// may not have a complete name lookup table. This function deserializes
+  /// the rest of visible declarations from the external storage and completes
+  /// the name lookup table of the DeclContext.
+  virtual void MaterializeVisibleDecls(const DeclContext *DC) = 0;
+
   /// \brief Finds all declarations lexically contained within the given
   /// DeclContext.
   ///
@@ -136,6 +144,10 @@ protected:
   static DeclContext::lookup_result
   SetNoExternalVisibleDeclsForName(const DeclContext *DC,
                                    DeclarationName Name);
+
+  void MaterializeVisibleDeclsForName(const DeclContext *DC,
+                                 DeclarationName Name,
+                                 llvm::SmallVectorImpl<NamedDecl*> &Decls);
 };
 
 /// \brief A lazy pointer to an AST node (of base type T) that resides
index 3f7480cee7b7dfd7601fb903358aba831c84ad79..f28eb26d93c623795efce9964c8ddf00e19e897f 100644 (file)
@@ -763,6 +763,8 @@ public:
   FindExternalVisibleDeclsByName(const DeclContext *DC,
                                  DeclarationName Name);
 
+  virtual void MaterializeVisibleDecls(const DeclContext *DC);
+
   /// \brief Read all of the declarations lexically stored in a
   /// declaration context.
   ///
index 30d540a00a9b525fe46470dfc7313e3e1092d93f..3dd7abab0c451eb7072931b84043fea94c9b1b7d 100644 (file)
@@ -667,6 +667,25 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC,
   return List.getLookupResult();
 }
 
+void ExternalASTSource::MaterializeVisibleDeclsForName(const DeclContext *DC,
+                                                       DeclarationName Name,
+                                     llvm::SmallVectorImpl<NamedDecl*> &Decls) {
+  assert(DC->LookupPtr);
+  StoredDeclsMap &Map = *DC->LookupPtr;
+
+  // If there's an entry in the table the visible decls for this name have
+  // already been deserialized.
+  if (Map.find(Name) == Map.end()) {
+    StoredDeclsList &List = Map[Name];
+    for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+      if (List.isNull())
+        List.setOnlyValue(Decls[I]);
+      else
+        List.AddSubsequentDecl(Decls[I]);
+    }
+  }
+}
+
 DeclContext::decl_iterator DeclContext::noload_decls_begin() const {
   return decl_iterator(FirstDecl);
 }
@@ -916,6 +935,15 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
   DeclNameEntries.AddSubsequentDecl(D);
 }
 
+void DeclContext::MaterializeVisibleDeclsFromExternalStorage() {
+  ExternalASTSource *Source = getParentASTContext().getExternalSource();
+  assert(hasExternalVisibleStorage() && Source && "No external storage?");
+
+  if (!LookupPtr)
+    CreateStoredDeclsMap(getParentASTContext());
+  Source->MaterializeVisibleDecls(this);
+}
+
 /// Returns iterator range [First, Last) of UsingDirectiveDecls stored within
 /// this context.
 DeclContext::udir_iterator_range
index b24b35309a65f770b404e17cc05efb4cbbfd33a8..6e5638b3c8630e16e897563209795e56b7ecb551 100644 (file)
@@ -790,6 +790,44 @@ public:
     return Key;
   }
 
+  external_key_type GetExternalKey(const internal_key_type& Key) const {
+    ASTContext *Context = Reader.getContext();
+    switch (Key.Kind) {
+    case DeclarationName::Identifier:
+      return DeclarationName((IdentifierInfo*)Key.Data);
+
+    case DeclarationName::ObjCZeroArgSelector:
+    case DeclarationName::ObjCOneArgSelector:
+    case DeclarationName::ObjCMultiArgSelector:
+      return DeclarationName(Selector(Key.Data));
+
+    case DeclarationName::CXXConstructorName:
+      return Context->DeclarationNames.getCXXConstructorName(
+                           Context->getCanonicalType(Reader.GetType(Key.Data)));
+
+    case DeclarationName::CXXDestructorName:
+      return Context->DeclarationNames.getCXXDestructorName(
+                           Context->getCanonicalType(Reader.GetType(Key.Data)));
+
+    case DeclarationName::CXXConversionFunctionName:
+      return Context->DeclarationNames.getCXXConversionFunctionName(
+                           Context->getCanonicalType(Reader.GetType(Key.Data)));
+
+    case DeclarationName::CXXOperatorName:
+      return Context->DeclarationNames.getCXXOperatorName(
+                                         (OverloadedOperatorKind)Key.Data);
+
+    case DeclarationName::CXXLiteralOperatorName:
+      return Context->DeclarationNames.getCXXLiteralOperatorName(
+                                                     (IdentifierInfo*)Key.Data);
+
+    case DeclarationName::CXXUsingDirective:
+      return DeclarationName::getUsingDirectiveName();
+    }
+
+    llvm_unreachable("Invalid Name Kind ?");
+  }
+
   static std::pair<unsigned, unsigned>
   ReadKeyDataLength(const unsigned char*& d) {
     using namespace clang::io;
@@ -3197,6 +3235,35 @@ ASTReader::FindExternalVisibleDeclsByName(const DeclContext *DC,
   return const_cast<DeclContext*>(DC)->lookup(Name);
 }
 
+void ASTReader::MaterializeVisibleDecls(const DeclContext *DC) {
+  assert(DC->hasExternalVisibleStorage() &&
+         "DeclContext has no visible decls in storage");
+
+  llvm::SmallVector<NamedDecl *, 64> Decls;
+  // There might be visible decls in multiple parts of the chain, for the TU
+  // and namespaces.
+  DeclContextInfos &Infos = DeclContextOffsets[DC];
+  for (DeclContextInfos::iterator I = Infos.begin(), E = Infos.end();
+       I != E; ++I) {
+    if (!I->NameLookupTableData)
+      continue;
+
+    ASTDeclContextNameLookupTable *LookupTable =
+        (ASTDeclContextNameLookupTable*)I->NameLookupTableData;
+    for (ASTDeclContextNameLookupTable::item_iterator
+           ItemI = LookupTable->item_begin(),
+           ItemEnd = LookupTable->item_end() ; ItemI != ItemEnd; ++ItemI) {
+      ASTDeclContextNameLookupTable::item_iterator::value_type Val
+          = *ItemI;
+      ASTDeclContextNameLookupTrait::data_type Data = Val.second;
+      Decls.clear();
+      for (; Data.first != Data.second; ++Data.first)
+        Decls.push_back(cast<NamedDecl>(GetDecl(*Data.first)));
+      MaterializeVisibleDeclsForName(DC, Val.first, Decls);
+    }
+  }
+}
+
 void ASTReader::PassInterestingDeclsToConsumer() {
   assert(Consumer);
   while (!InterestingDecls.empty()) {
index 5deaf3d475d44ecbf4b5739d9fa17b9979eb6215..f47ad3c4d74d65c8cdb6beb398130c91db86e573 100644 (file)
@@ -2032,7 +2032,10 @@ uint64_t ASTWriter::WriteDeclContextVisibleBlock(ASTContext &Context,
     return 0;
 
   // Force the DeclContext to build a its name-lookup table.
-  DC->lookup(DeclarationName());
+  if (DC->hasExternalVisibleStorage())
+    DC->MaterializeVisibleDeclsFromExternalStorage();
+  else
+    DC->lookup(DeclarationName());
 
   // Serialize the contents of the mapping used for lookup. Note that,
   // although we have two very different code paths, the serialized
diff --git a/test/PCH/reinclude.cpp b/test/PCH/reinclude.cpp
new file mode 100644 (file)
index 0000000..6ab1002
--- /dev/null
@@ -0,0 +1,8 @@
+// Test without PCH
+// RUN: %clang_cc1 %s -include %S/reinclude1.h -include %S/reinclude2.h -fsyntax-only -verify
+
+// RUN: %clang_cc1 -x c++-header %S/reinclude1.h -emit-pch -o %t1
+// RUN: %clang_cc1 -x c++-header %S/reinclude2.h -include-pch %t1 -emit-pch -o %t2
+// RUN: %clang_cc1 %s -include-pch %t2 -fsyntax-only -verify
+
+int q2 = A::y;
diff --git a/test/PCH/reinclude1.h b/test/PCH/reinclude1.h
new file mode 100644 (file)
index 0000000..4c8ccae
--- /dev/null
@@ -0,0 +1,4 @@
+namespace A {
+  int x;
+  int y;
+}
diff --git a/test/PCH/reinclude2.h b/test/PCH/reinclude2.h
new file mode 100644 (file)
index 0000000..2aa6d31
--- /dev/null
@@ -0,0 +1 @@
+int q1 = A::x;