oontvoo updated this revision to Diff 254321.
oontvoo added a comment.

clean up ... Ready to review. PTAL! =)


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D75951/new/

https://reviews.llvm.org/D75951

Files:
  clang/include/clang/Lex/HeaderSearch.h
  clang/include/clang/Lex/Preprocessor.h
  clang/include/clang/Serialization/ASTBitCodes.h
  clang/include/clang/Serialization/ASTReader.h
  clang/include/clang/Serialization/ASTWriter.h
  clang/lib/Lex/HeaderSearch.cpp
  clang/lib/Lex/PPDirectives.cpp
  clang/lib/Lex/PPLexerChange.cpp
  clang/lib/Lex/Preprocessor.cpp
  clang/lib/Serialization/ASTReader.cpp
  clang/lib/Serialization/ASTWriter.cpp
  clang/test/Modules/Inputs/dummy_pragma_once.h
  clang/test/Modules/Inputs/dummy_textual_header.h
  clang/test/Modules/Inputs/header_in_imported_module.h
  clang/test/Modules/Inputs/imported_module.cppm
  clang/test/Modules/Inputs/module.map
  clang/test/Modules/header-in-imported-module.c
  clang/test/Modules/import-pragma-once.c

Index: clang/test/Modules/import-pragma-once.c
===================================================================
--- /dev/null
+++ clang/test/Modules/import-pragma-once.c
@@ -0,0 +1,8 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -fimplicit-module-maps -I%S/Inputs -verify -x c %s
+// expected-no-diagnostics
+#include "dummy_pragma_once.h"
+#include "dummy_textual_header.h"
+
+void *p = &x;
+void *q = &y;
Index: clang/test/Modules/header-in-imported-module.c
===================================================================
--- /dev/null
+++ clang/test/Modules/header-in-imported-module.c
@@ -0,0 +1,14 @@
+// RUN: rm -rf %t
+// RUN: %clang -fmodules -x c++ -fmodules-ts --precompile -o %t/ModuleB39206.pcm %S/Inputs/imported_module.cppm
+// RUN: %clang -fmodules -x c++ -fmodules-ts -c %t/ModuleB39206.pcm -o %t/ModuleB39206.o
+// RUN: %clang -fmodules -x c++ -fmodules-ts -fmodule-file=%t/ModuleB39206.pcm -verify  -c %s
+// expected-no-diagnostics
+
+// Bug 39206
+
+#include "header_in_imported_module.h"
+module ModuleB39206;
+
+#ifndef ALL_GOOD
+#error "missing macro in impl"
+#endif
Index: clang/test/Modules/Inputs/module.map
===================================================================
--- clang/test/Modules/Inputs/module.map
+++ clang/test/Modules/Inputs/module.map
@@ -282,6 +282,11 @@
   header "dummy.h"
 }
 
+module dummy_pragma_once {
+  header "dummy_pragma_once.h"
+  textual header "dummy_textual_header.h"
+}
+
 module builtin {
   header "builtin.h"
   explicit module sub {
Index: clang/test/Modules/Inputs/imported_module.cppm
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/imported_module.cppm
@@ -0,0 +1,5 @@
+export module ModuleB39206;
+#include "header.h"
+
+#ifndef ALL_GOOD
+#error "Missing macro in module decl"
\ No newline at end of file
Index: clang/test/Modules/Inputs/header_in_imported_module.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/header_in_imported_module.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#define ALL_GOOD
Index: clang/test/Modules/Inputs/dummy_textual_header.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/dummy_textual_header.h
@@ -0,0 +1,2 @@
+#pragma once
+int y = 6;
Index: clang/test/Modules/Inputs/dummy_pragma_once.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/dummy_pragma_once.h
@@ -0,0 +1,3 @@
+#include "dummy_textual_header.h"
+
+int x = 5;
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -1621,7 +1621,7 @@
       endian::Writer LE(Out, little);
       unsigned KeyLen = key.Filename.size() + 1 + 8 + 8;
       LE.write<uint16_t>(KeyLen);
-      unsigned DataLen = 1 + 2 + 4 + 4;
+      unsigned DataLen = 1 + 2 + 4 + 4 + 4;
       for (auto ModInfo : Data.KnownHeaders)
         if (Writer.getLocalOrImportedSubmoduleID(ModInfo.getModule()))
           DataLen += 4;
@@ -1678,6 +1678,9 @@
       }
       LE.write<uint32_t>(Offset);
 
+      // Write this file UID.
+      LE.write<uint32_t>(Data.HFI.UID);
+
       auto EmitModule = [&](Module *M, ModuleMap::ModuleHeaderRole Role) {
         if (uint32_t ModID = Writer.getLocalOrImportedSubmoduleID(M)) {
           uint32_t Value = (ModID << 2) | (unsigned)Role;
@@ -1705,7 +1708,7 @@
 /// Write the header search block for the list of files that
 ///
 /// \param HS The header search structure to save.
-void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS) {
+void ASTWriter::WriteHeaderSearch(HeaderSearch &HS) {
   HeaderFileInfoTrait GeneratorTrait(*this);
   llvm::OnDiskChainedHashTableGenerator<HeaderFileInfoTrait> Generator;
   SmallVector<const char *, 4> SavedStrings;
@@ -1783,8 +1786,7 @@
     // changed since it was loaded. Also skip it if it's for a modular header
     // from a different module; in that case, we rely on the module(s)
     // containing the header to provide this information.
-    const HeaderFileInfo *HFI =
-        HS.getExistingFileInfo(File, /*WantExternal*/!Chain);
+    HeaderFileInfo *HFI = HS.getExistingFileInfo(File, /*WantExternal*/ !Chain);
     if (!HFI || (HFI->isModuleHeader && !HFI->isCompilingModuleHeader))
       continue;
 
@@ -1801,8 +1803,13 @@
     HeaderFileInfoTrait::key_type Key = {
       Filename, File->getSize(), getTimestampForOutput(File)
     };
+    // Set the UID for this HFI so that its importers could use it
+    // when serializing.
+    HFI->UID = UID;
     HeaderFileInfoTrait::data_type Data = {
-      *HFI, HS.getModuleMap().findAllModulesForHeader(File), {}
+        *HFI,
+        HS.getModuleMap().findAllModulesForHeader(File),
+        {},
     };
     Generator.insert(Key, Data, GeneratorTrait);
     ++NumHeaderSearchEntries;
@@ -2636,6 +2643,25 @@
       Stream.EmitRecord(SUBMODULE_IMPORTS, Record);
     }
 
+    // Emit the imported header's UIDs.
+    {
+      auto it = PP->Submodules.find(Mod);
+      if (it != PP->Submodules.end() && !it->second.IncludedFiles.empty()) {
+        RecordData Record;
+        for (unsigned UID : it->second.IncludedFiles) {
+          // Only save it if the header is actually import/pragma once.
+          // FIXME When we first see a header, it always goes into the mod's
+          // list of included, regardless of whether it was pragma-once or not.
+          // Maybe better to fix that earlier?
+          auto HFI = PP->getHeaderSearchInfo().FileInfo[UID];
+          if (HFI.isImport || HFI.isPragmaOnce) {
+            Record.push_back(HFI.UID);
+          }
+        }
+        Stream.EmitRecord(SUBMODULE_IMPORTED_HEADERS, Record);
+      }
+    }
+
     // Emit the exports.
     if (!Mod->Exports.empty()) {
       RecordData Record;
@@ -4722,6 +4748,23 @@
   if (WritingModule)
     WriteSubmodules(WritingModule);
 
+  // Write the imported headers, only for the precompiled header (ie, no
+  // modules) because the modules will have emitted their own imported headers.
+  if (!WritingModule && !PP.CurSubmoduleState->IncludedFiles.empty()) {
+    RecordData Record;
+    for (unsigned UID : PP.CurSubmoduleState->IncludedFiles) {
+      // Only save it if the header is actually import/pragma once.
+      // FIXME When we first see a header, it always goes into the
+      // list of included, regardless of whether it was pragma-once or not.
+      // Maybe better to fix that earlier?
+      auto HFI = PP.getHeaderSearchInfo().FileInfo[UID];
+      if (HFI.isImport || HFI.isPragmaOnce) {
+        Record.push_back(HFI.UID);
+      }
+    }
+    Stream.EmitRecord(PP_IMPORTED_HEADERS, Record);
+  }
+
   // We need to have information about submodules to correctly deserialize
   // decls from OpenCLExtensionDecls block
   WriteOpenCLExtensionDecls(SemaRef);
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -1898,6 +1898,10 @@
     HFI.Framework = HS->getUniqueFrameworkName(FrameworkName);
   }
 
+  // Read the file old UID
+  HFI.OldUID = endian::readNext<uint32_t, little, unaligned>(d);
+  HFI.UIDSet = true;
+
   assert((End - d) % 4 == 0 &&
          "Wrong data length in HeaderFileInfo deserialization");
   while (d != End) {
@@ -3081,6 +3085,7 @@
       case HEADER_SEARCH_TABLE:
       case IMPORTED_MODULES:
       case MACRO_OFFSET:
+      case PP_IMPORTED_HEADERS:
         break;
       default:
         continue;
@@ -3530,6 +3535,12 @@
       break;
     }
 
+    case PP_IMPORTED_HEADERS: {
+      for (unsigned Idx = 0; Idx < Record.size(); ++Idx) {
+        PendingImportedHeaders.insert(Record[Idx]);
+      }
+      break;
+    }
     case DECL_UPDATE_OFFSETS:
       if (Record.size() % 2 != 0) {
         Error("invalid DECL_UPDATE_OFFSETS block in AST file");
@@ -5620,6 +5631,11 @@
       }
       break;
 
+    case SUBMODULE_IMPORTED_HEADERS:
+      for (unsigned Idx = 0; Idx < Record.size(); ++Idx) {
+        PendingImportedHeadersForModuleFiles[&F].insert(Record[Idx]);
+      }
+      break;
     case SUBMODULE_EXPORTS:
       for (unsigned Idx = 0; Idx + 1 < Record.size(); Idx += 2) {
         UnresolvedModuleRef Unresolved;
@@ -6171,6 +6187,8 @@
   return HeaderFileInfo();
 }
 
+void ASTReader::ResolvePendings() { resolvePendingImportedHeaders(); }
+
 void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
   using DiagState = DiagnosticsEngine::DiagState;
   SmallVector<DiagState *, 32> DiagStates;
@@ -9292,6 +9310,97 @@
   for (auto *ND : PendingMergedDefinitionsToDeduplicate)
     getContext().deduplicateMergedDefinitonsFor(ND);
   PendingMergedDefinitionsToDeduplicate.clear();
+
+  // Have to be done last because we need the modules
+  // and other PP info.
+  {
+    // First, Map ModuleFile* to Module* for more convenient lookup.
+    const auto &Iter = PendingImportedHeadersForModuleFiles.begin();
+    for (unsigned I = 0; I < PendingImportedHeadersForModuleFiles.size(); ++I) {
+      ModuleFile *ModFile = Iter[I].first;
+      auto &HeaderUIDs = Iter[I].second;
+      Module *Mod = PP.getHeaderSearchInfo().lookupModule(ModFile->ModuleName);
+
+      PendingImportedHeadersForModules.insert({Mod, {std::move(HeaderUIDs)}});
+    }
+    PendingImportedHeadersForModuleFiles.clear();
+    resolvePendingImportedHeaders();
+  }
+}
+
+void ASTReader::resolvePendingImportedHeaders() {
+  if (PP.getHeaderSearchInfo().FileInfo.empty()) {
+    return;
+  }
+
+  if (!PendingImportedHeadersForModules.empty() ||
+      !PendingImportedHeaders.empty()) {
+
+    // These HFIs were deserialized and assigned their "old"
+    // UID.
+    HeaderSearch &HS = PP.getHeaderSearchInfo();
+    // TODO: maybe only do this update, if it's out of date
+    std::map<unsigned, unsigned> OldToNewUIDMapping;
+    for (unsigned Idx = 0; Idx < HS.FileInfo.size(); ++Idx) {
+      if (!HS.FileInfo[Idx].UIDSet) {
+        continue;
+      }
+      OldToNewUIDMapping[HS.FileInfo[Idx].OldUID] = Idx;
+    }
+
+    if (OldToNewUIDMapping.empty())
+      return;
+
+    const auto &Iter = PendingImportedHeadersForModules.begin();
+    bool Unresolved = false;
+    for (unsigned I = 0; I < PendingImportedHeadersForModules.size(); ++I) {
+      auto &HeaderUIDs = Iter[I].second;
+      Module *M = Iter[I].first;
+
+      Preprocessor::SubmoduleState &SubState = PP.Submodules[M];
+      for (auto OldUIDItr = HeaderUIDs.begin();
+           OldUIDItr != HeaderUIDs.end();) {
+        auto IdxIt = OldToNewUIDMapping.find(*OldUIDItr);
+        if (IdxIt == OldToNewUIDMapping.end()) {
+          Unresolved = true;
+          ++OldUIDItr;
+          continue;
+        }
+        OldUIDItr = HeaderUIDs.erase(OldUIDItr);
+        SubState.IncludedFiles.insert(IdxIt->second);
+      }
+    }
+    if (!Unresolved)
+      PendingImportedHeadersForModules.clear();
+
+    if (!PendingImportedHeaders.empty()) {
+      std::set<unsigned> Remaining;
+      for (auto OldUIDItr = PendingImportedHeaders.begin();
+           OldUIDItr != PendingImportedHeaders.end();) {
+        auto IdxIt = OldToNewUIDMapping.find(*OldUIDItr);
+        if (IdxIt == OldToNewUIDMapping.end()) {
+          Unresolved = true;
+          ++OldUIDItr;
+          continue;
+        }
+        OldUIDItr = PendingImportedHeaders.erase(OldUIDItr);
+        PP.CurSubmoduleState->IncludedFiles.insert(IdxIt->second);
+      }
+    }
+  }
+}
+
+void ASTReader::ImportPendingIncludedFiles(Module *FromMod, Module *ToMod) {
+  auto Iter = PendingImportedHeadersForModules.find(FromMod);
+  if (Iter == PendingImportedHeadersForModules.end() || Iter->second.empty())
+    return;
+
+  auto &TargetUIDVector = ToMod == nullptr
+                              ? PendingImportedHeaders
+                              : PendingImportedHeadersForModules[ToMod];
+  for (unsigned UID : Iter->second) {
+    TargetUIDVector.insert(UID);
+  }
 }
 
 void ASTReader::diagnoseOdrViolations() {
Index: clang/lib/Lex/Preprocessor.cpp
===================================================================
--- clang/lib/Lex/Preprocessor.cpp
+++ clang/lib/Lex/Preprocessor.cpp
@@ -554,8 +554,9 @@
 
     // Tell the header info that the main file was entered.  If the file is later
     // #imported, it won't be re-entered.
-    if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID))
-      HeaderInfo.IncrementIncludeCount(FE);
+    if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID)) {
+      HeaderInfo.MarkAsIncluded(*this, FE);
+    }
   }
 
   // Preprocess Predefines to populate the initial preprocessor state.
Index: clang/lib/Lex/PPLexerChange.cpp
===================================================================
--- clang/lib/Lex/PPLexerChange.cpp
+++ clang/lib/Lex/PPLexerChange.cpp
@@ -642,10 +642,13 @@
 void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc,
                                   bool ForPragma) {
   if (!getLangOpts().ModulesLocalVisibility) {
-    // Just track that we entered this submodule.
+    // Just track that we entered this submodule (and track the imports)
     BuildingSubmoduleStack.push_back(
         BuildingSubmoduleInfo(M, ImportLoc, ForPragma, CurSubmoduleState,
                               PendingModuleMacroNames.size()));
+    auto R = Submodules.insert(std::make_pair(M, SubmoduleState()));
+    auto &State = R.first->second;
+    CurSubmoduleState = &State;
     if (Callbacks)
       Callbacks->EnteredSubmodule(M, ImportLoc, ForPragma);
     return;
@@ -731,6 +734,7 @@
   if (!needModuleMacros() ||
       (!getLangOpts().ModulesLocalVisibility &&
        LeavingMod->getTopLevelModuleName() != getLangOpts().CurrentModule)) {
+    CurSubmoduleState = Info.OuterSubmoduleState;
     // If we don't need module macros, or this is not a module for which we
     // are tracking macro visibility, don't build any, and preserve the list
     // of pending names for the surrounding submodule.
Index: clang/lib/Lex/PPDirectives.cpp
===================================================================
--- clang/lib/Lex/PPDirectives.cpp
+++ clang/lib/Lex/PPDirectives.cpp
@@ -2013,6 +2013,14 @@
 
     if (Imported) {
       Action = Import;
+      Module *ImportedMod = (Imported);
+      // If we're auto importing this module, also import the hdrs.
+      for (auto UID : Submodules[ImportedMod].IncludedFiles) {
+        setIncludeVisible(UID);
+      }
+      // Also import the pendings.
+      getHeaderSearchInfo().ImportPendingIncludedFiles(ImportedMod,
+                                                       getCurrentModule());
     } else if (Imported.isMissingExpected()) {
       // We failed to find a submodule that we assumed would exist (because it
       // was in the directory of an umbrella header, for instance), but no
Index: clang/lib/Lex/HeaderSearch.cpp
===================================================================
--- clang/lib/Lex/HeaderSearch.cpp
+++ clang/lib/Lex/HeaderSearch.cpp
@@ -1156,16 +1156,22 @@
 
   if (HFI.Framework.empty())
     HFI.Framework = OtherHFI.Framework;
+
+  HFI.UID = OtherHFI.UID;
+  HFI.UIDSet = OtherHFI.UIDSet;
+  HFI.OldUID = OtherHFI.OldUID;
 }
 
 /// getFileInfo - Return the HeaderFileInfo structure for the specified
 /// FileEntry.
 HeaderFileInfo &HeaderSearch::getFileInfo(const FileEntry *FE) {
-  if (FE->getUID() >= FileInfo.size())
+  if (FE->getUID() >= FileInfo.size()) {
     FileInfo.resize(FE->getUID() + 1);
+  }
 
   HeaderFileInfo *HFI = &FileInfo[FE->getUID()];
-  // FIXME: Use a generation count to check whether this is really up to date.
+  HFI->UID = FE->getUID();
+
   if (ExternalSource && !HFI->Resolved) {
     HFI->Resolved = true;
     auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE);
@@ -1182,9 +1188,8 @@
   return *HFI;
 }
 
-const HeaderFileInfo *
-HeaderSearch::getExistingFileInfo(const FileEntry *FE,
-                                  bool WantExternal) const {
+HeaderFileInfo *HeaderSearch::getExistingFileInfo(const FileEntry *FE,
+                                                  bool WantExternal) const {
   // If we have an external source, ensure we have the latest information.
   // FIXME: Use a generation count to check whether this is really up to date.
   HeaderFileInfo *HFI;
@@ -1196,6 +1201,8 @@
     }
 
     HFI = &FileInfo[FE->getUID()];
+    HFI->UID = FE->getUID();
+
     if (!WantExternal && (!HFI->IsValid || HFI->External))
       return nullptr;
     if (!HFI->Resolved) {
@@ -1245,68 +1252,58 @@
   HFI.isCompilingModuleHeader |= isCompilingModuleHeader;
 }
 
+void HeaderSearch::MarkAsIncluded(Preprocessor &PP, const FileEntry *File) {
+  HeaderFileInfo HFI = getFileInfo(File);
+  ++HFI.NumIncludes;
+  PP.setIncludeVisible(HFI.UID);
+}
+
 bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP,
                                           const FileEntry *File, bool isImport,
                                           bool ModulesEnabled, Module *M) {
   ++NumIncluded; // Count # of attempted #includes.
 
+  // Make sure everything is up to date.
+  ModMap.resolveHeaderDirectives(File);
+
+  const bool SeenBefore =
+      getExistingFileInfo(File, /*WantExernal=*/true) != nullptr;
+
   // Get information about this file.
   HeaderFileInfo &FileInfo = getFileInfo(File);
 
-  // FIXME: this is a workaround for the lack of proper modules-aware support
-  // for #import / #pragma once
-  auto TryEnterImported = [&]() -> bool {
-    if (!ModulesEnabled)
-      return false;
-    // Ensure FileInfo bits are up to date.
-    ModMap.resolveHeaderDirectives(File);
-    // Modules with builtins are special; multiple modules use builtins as
-    // modular headers, example:
-    //
-    //    module stddef { header "stddef.h" export * }
-    //
-    // After module map parsing, this expands to:
-    //
-    //    module stddef {
-    //      header "/path_to_builtin_dirs/stddef.h"
-    //      textual "stddef.h"
-    //    }
-    //
-    // It's common that libc++ and system modules will both define such
-    // submodules. Make sure cached results for a builtin header won't
-    // prevent other builtin modules to potentially enter the builtin header.
-    // Note that builtins are header guarded and the decision to actually
-    // enter them is postponed to the controlling macros logic below.
-    bool TryEnterHdr = false;
-    if (FileInfo.isCompilingModuleHeader && FileInfo.isModuleHeader)
-      TryEnterHdr = File->getDir() == ModMap.getBuiltinDir() &&
-                    ModuleMap::isBuiltinHeader(
-                        llvm::sys::path::filename(File->getName()));
-
-    // Textual headers can be #imported from different modules. Since ObjC
-    // headers find in the wild might rely only on #import and do not contain
-    // controlling macros, be conservative and only try to enter textual headers
-    // if such macro is present.
-    if (!FileInfo.isModuleHeader &&
-        FileInfo.getControllingMacro(ExternalLookup))
-      TryEnterHdr = true;
-    return TryEnterHdr;
-  };
+  // Resolve any pendings before we do calculations.
+  if (ExternalSource) {
+    ExternalSource->ResolvePendings();
+  }
 
-  // If this is a #import directive, check that we have not already imported
-  // this header.
   if (isImport) {
     // If this has already been imported, don't import it again.
     FileInfo.isImport = true;
+  }
 
-    // Has this already been #import'ed or #include'd?
-    if (FileInfo.NumIncludes && !TryEnterImported())
+  if (!SeenBefore || FileInfo.NumIncludes == 0 || FileInfo.isPragmaOnce ||
+      FileInfo.isImport) {
+    if (PP.isIncludeVisible(FileInfo.UID)) {
       return false;
-  } else {
-    // Otherwise, if this is a #include of a file that was previously #import'd
-    // or if this is the second #include of a #pragma once file, ignore it.
-    if (FileInfo.isImport && !TryEnterImported())
+    } else if (FileInfo.isModuleHeader && FileInfo.isCompilingModuleHeader &&
+               PP.isIncludeVisibleFromOuterModule(FileInfo.UID)) {
       return false;
+    } else {
+      // Mark as 'included'.
+      PP.setIncludeVisible(FileInfo.UID);
+
+      // FIXME: This is kind of hack to handle textual-header in ObjC
+      // Textual headers can be #imported from different modules.
+      // ObjC headers rely only on #import and do not contain
+      // controlling macros. Hence we won't enter the header if
+      // macro is absent.
+      if (isImport && FileInfo.NumIncludes &&
+          (FileInfo.isModuleHeader ||
+           !FileInfo.getControllingMacro(ExternalLookup))) {
+        return false;
+      }
+    }
   }
 
   // Next, check to see if the file is wrapped with #ifndef guards.  If so, and
@@ -1325,7 +1322,6 @@
 
   // Increment the number of times this file has been included.
   ++FileInfo.NumIncludes;
-
   return true;
 }
 
Index: clang/include/clang/Serialization/ASTWriter.h
===================================================================
--- clang/include/clang/Serialization/ASTWriter.h
+++ clang/include/clang/Serialization/ASTWriter.h
@@ -463,7 +463,7 @@
   void WriteSourceManagerBlock(SourceManager &SourceMgr,
                                const Preprocessor &PP);
   void WritePreprocessor(const Preprocessor &PP, bool IsModule);
-  void WriteHeaderSearch(const HeaderSearch &HS);
+  void WriteHeaderSearch(HeaderSearch &HS);
   void WritePreprocessorDetail(PreprocessingRecord &PPRec);
   void WriteSubmodules(Module *WritingModule);
 
Index: clang/include/clang/Serialization/ASTReader.h
===================================================================
--- clang/include/clang/Serialization/ASTReader.h
+++ clang/include/clang/Serialization/ASTReader.h
@@ -736,6 +736,16 @@
   /// IDs have not yet been deserialized to the global IDs of those macros.
   PendingMacroIDsMap PendingMacroIDs;
 
+  /// Mapping from ModuleFile to a list of its imported headers' (old) UID.
+  /// These UIDs are yet to be mapped to their corresponding HeaderFileInfo
+  llvm::MapVector<ModuleFile *, std::set<unsigned>>
+      PendingImportedHeadersForModuleFiles;
+  llvm::MapVector<Module *, std::set<unsigned>>
+      PendingImportedHeadersForModules;
+
+  /// List of a PCH imported headers' (old)UID.
+  std::set<unsigned> PendingImportedHeaders;
+
   using GlobalPreprocessedEntityMapType =
       ContinuousRangeMap<unsigned, ModuleFile *, 4>;
 
@@ -1416,6 +1426,8 @@
   void PassInterestingDeclsToConsumer();
   void PassInterestingDeclToConsumer(Decl *D);
 
+  void resolvePendingImportedHeaders();
+
   void finishPendingActions();
   void diagnoseOdrViolations();
 
@@ -1722,6 +1734,12 @@
   /// Read the header file information for the given file entry.
   HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE) override;
 
+  /// Resolve as many pending 'included' headers as possible.
+  void ResolvePendings() override;
+
+  /// Import pending included headers from FromMod to ToMod.
+  void ImportPendingIncludedFiles(Module *FromMod, Module *ToMod) override;
+
   void ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag);
 
   /// Returns the number of source locations found in the chain.
Index: clang/include/clang/Serialization/ASTBitCodes.h
===================================================================
--- clang/include/clang/Serialization/ASTBitCodes.h
+++ clang/include/clang/Serialization/ASTBitCodes.h
@@ -654,6 +654,9 @@
 
       /// Record code for the Decls to be checked for deferred diags.
       DECLS_TO_CHECK_FOR_DEFERRED_DIAGS = 64,
+
+      /// List of imported headers' UID for a PCH
+      PP_IMPORTED_HEADERS = 65,
     };
 
     /// Record types used within a source manager block.
@@ -784,6 +787,9 @@
       /// Specifies the name of the module that will eventually
       /// re-export the entities in this module.
       SUBMODULE_EXPORT_AS = 17,
+
+      // Specifies the headers' UID imported by this submodule.
+      SUBMODULE_IMPORTED_HEADERS = 18,
     };
 
     /// Record types used within a comments block.
Index: clang/include/clang/Lex/Preprocessor.h
===================================================================
--- clang/include/clang/Lex/Preprocessor.h
+++ clang/include/clang/Lex/Preprocessor.h
@@ -51,6 +51,7 @@
 #include <cstdint>
 #include <map>
 #include <memory>
+#include <set>
 #include <string>
 #include <utility>
 #include <vector>
@@ -128,6 +129,8 @@
 class Preprocessor {
   friend class VAOptDefinitionContext;
   friend class VariadicMacroScopeGuard;
+  friend class ASTWriter;
+  friend class ASTReader;
 
   llvm::unique_function<void(const clang::Token &)> OnToken;
   std::shared_ptr<PreprocessorOptions> PPOpts;
@@ -735,6 +738,7 @@
   };
   SmallVector<BuildingSubmoduleInfo, 8> BuildingSubmoduleStack;
 
+  //  struct HeaderFileInfo;
   /// Information about a submodule's preprocessor state.
   struct SubmoduleState {
     /// The macros for the submodule.
@@ -743,6 +747,9 @@
     /// The set of modules that are visible within the submodule.
     VisibleModuleSet VisibleModules;
 
+    /// The set of the included headers for the submodule.
+    std::set<unsigned> IncludedFiles;
+
     // FIXME: CounterValue?
     // FIXME: PragmaPushMacroInfo?
   };
@@ -1038,6 +1045,24 @@
     OnToken = std::move(F);
   }
 
+  void setIncludeVisible(unsigned UID) {
+    CurSubmoduleState->IncludedFiles.insert(UID);
+  }
+
+  bool isIncludeVisibleFromOuterModule(unsigned UID) {
+    if (BuildingSubmoduleStack.empty())
+      return false;
+
+    auto OuterState = BuildingSubmoduleStack.back().OuterSubmoduleState;
+    return OuterState->IncludedFiles.find(UID) !=
+           OuterState->IncludedFiles.end();
+  }
+
+  bool isIncludeVisible(unsigned UID) {
+    return CurSubmoduleState->IncludedFiles.find(UID) !=
+           CurSubmoduleState->IncludedFiles.end();
+  }
+
   bool isMacroDefined(StringRef Id) {
     return isMacroDefined(&Identifiers.get(Id));
   }
Index: clang/include/clang/Lex/HeaderSearch.h
===================================================================
--- clang/include/clang/Lex/HeaderSearch.h
+++ clang/include/clang/Lex/HeaderSearch.h
@@ -110,10 +110,17 @@
   /// of the framework.
   StringRef Framework;
 
+  /// The file UID used during [de]serialization.
+  unsigned UIDSet = false; // DO not serialize this.
+  unsigned OldUID = 0;
+
+  // CurrentUid
+  unsigned UID = 0;
+
   HeaderFileInfo()
       : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User),
         External(false), isModuleHeader(false), isCompilingModuleHeader(false),
-        Resolved(false), IndexHeaderMapHeader(false), IsValid(false)  {}
+        Resolved(false), IndexHeaderMapHeader(false), IsValid(false) {}
 
   /// Retrieve the controlling macro for this header file, if
   /// any.
@@ -140,6 +147,12 @@
   /// \c External bit set. If the file entry is not known, return a
   /// default-constructed \c HeaderFileInfo.
   virtual HeaderFileInfo GetHeaderFileInfo(const FileEntry *FE) = 0;
+
+  /// Resolve any pending imported headers.
+  virtual void ResolvePendings() = 0;
+
+  /// Add the set of pending imported from FromMod to ToMod.
+  virtual void ImportPendingIncludedFiles(Module *FromMod, Module *ToMod) = 0;
 };
 
 /// This structure is used to record entries in our framework cache.
@@ -157,6 +170,8 @@
 /// by a \#include or \#include_next, (sub-)framework lookup, etc.
 class HeaderSearch {
   friend class DirectoryLookup;
+  friend class ASTReader;
+  friend class ASTWriter;
 
   /// Header-search options used to initialize this header search.
   std::shared_ptr<HeaderSearchOptions> HSOpts;
@@ -350,6 +365,12 @@
     ExternalSource = ES;
   }
 
+  void ImportPendingIncludedFiles(Module *FromMod, Module *ToMod) {
+    if (ExternalSource) {
+      ExternalSource->ImportPendingIncludedFiles(FromMod, ToMod);
+    }
+  }
+
   /// Set the target information for the header search, if not
   /// already known.
   void setTarget(const TargetInfo &Target);
@@ -449,11 +470,9 @@
                             ModuleMap::ModuleHeaderRole Role,
                             bool isCompilingModuleHeader);
 
-  /// Increment the count for the number of times the specified
-  /// FileEntry has been entered.
-  void IncrementIncludeCount(const FileEntry *File) {
-    ++getFileInfo(File).NumIncludes;
-  }
+  /// Mark this file as included for the current so if it is
+  /// later imported, it won't be re-entered.
+  void MarkAsIncluded(Preprocessor &PP, const FileEntry *File);
 
   /// Mark the specified file as having a controlling macro.
   ///
@@ -664,8 +683,8 @@
   /// if it has ever been filled in.
   /// \param WantExternal Whether the caller wants purely-external header file
   ///        info (where \p External is true).
-  const HeaderFileInfo *getExistingFileInfo(const FileEntry *FE,
-                                            bool WantExternal = true) const;
+  HeaderFileInfo *getExistingFileInfo(const FileEntry *FE,
+                                      bool WantExternal = true) const;
 
   // Used by external tools
   using search_dir_iterator = std::vector<DirectoryLookup>::const_iterator;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to