r237871 - [modules] If we re-enter a submodule from within itself (when submodule

Richard Smith richard-llvm at metafoo.co.uk
Wed May 20 18:20:11 PDT 2015


Author: rsmith
Date: Wed May 20 20:20:10 2015
New Revision: 237871

URL: http://llvm.org/viewvc/llvm-project?rev=237871&view=rev
Log:
[modules] If we re-enter a submodule from within itself (when submodule
visibility is enabled) or leave and re-enter it, restore the macro and module
visibility state from last time we were in that submodule.

This allows mutually-#including header files to stand a chance at being
modularized with local visibility enabled.

Added:
    cfe/trunk/test/Modules/Inputs/submodule-visibility/cycle1.h
    cfe/trunk/test/Modules/Inputs/submodule-visibility/cycle2.h
    cfe/trunk/test/Modules/submodule-visibility-cycles.cpp
Modified:
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/lib/Lex/PPLexerChange.cpp
    cfe/trunk/lib/Lex/PPMacroExpansion.cpp
    cfe/trunk/lib/Lex/Preprocessor.cpp
    cfe/trunk/test/Modules/Inputs/submodule-visibility/module.modulemap

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=237871&r1=237870&r2=237871&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Wed May 20 20:20:10 2015
@@ -391,7 +391,7 @@ class Preprocessor : public RefCountedBa
       // FIXME: Find a spare bit on IdentifierInfo and store a
       //        HasModuleMacros flag.
       if (!II->hasMacroDefinition() || !PP.getLangOpts().Modules ||
-          !PP.VisibleModules.getGeneration())
+          !PP.CurSubmoduleState->VisibleModules.getGeneration())
         return nullptr;
 
       auto *Info = State.dyn_cast<ModuleMacroInfo*>();
@@ -401,7 +401,7 @@ class Preprocessor : public RefCountedBa
         State = Info;
       }
 
-      if (PP.VisibleModules.getGeneration() !=
+      if (PP.CurSubmoduleState->VisibleModules.getGeneration() !=
           Info->ActiveModuleMacrosGeneration)
         PP.updateModuleMacroInfo(II, *Info);
       return Info;
@@ -483,33 +483,50 @@ class Preprocessor : public RefCountedBa
     }
   };
 
-  typedef llvm::DenseMap<const IdentifierInfo *, MacroState> MacroMap;
-
   /// For each IdentifierInfo that was associated with a macro, we
   /// keep a mapping to the history of all macro definitions and #undefs in
   /// the reverse order (the latest one is in the head of the list).
-  MacroMap Macros;
+  ///
+  /// This mapping lives within the \p CurSubmoduleState.
+  typedef llvm::DenseMap<const IdentifierInfo *, MacroState> MacroMap;
 
   friend class ASTReader;
 
+  struct SubmoduleState;
+
   /// \brief Information about a submodule that we're currently building.
   struct BuildingSubmoduleInfo {
-    BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc)
-        : M(M), ImportLoc(ImportLoc) {}
+    BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc,
+                          SubmoduleState *OuterSubmoduleState)
+        : M(M), ImportLoc(ImportLoc), OuterSubmoduleState(OuterSubmoduleState) {
+    }
 
     /// The module that we are building.
     Module *M;
     /// The location at which the module was included.
     SourceLocation ImportLoc;
-    /// The macros that were visible before we entered the module.
+    /// The previous SubmoduleState.
+    SubmoduleState *OuterSubmoduleState;
+  };
+  SmallVector<BuildingSubmoduleInfo, 8> BuildingSubmoduleStack;
+
+  /// \brief Information about a submodule's preprocessor state.
+  struct SubmoduleState {
+    /// The macros for the submodule.
     MacroMap Macros;
-    /// The set of modules that was visible in the surrounding submodule.
+    /// The set of modules that are visible within the submodule.
     VisibleModuleSet VisibleModules;
-
     // FIXME: CounterValue?
     // FIXME: PragmaPushMacroInfo?
   };
-  SmallVector<BuildingSubmoduleInfo, 8> BuildingSubmoduleStack;
+  std::map<Module*, SubmoduleState> Submodules;
+
+  /// The preprocessor state for preprocessing outside of any submodule.
+  SubmoduleState NullSubmoduleState;
+
+  /// The current submodule state. Will be \p NullSubmoduleState if we're not
+  /// in a submodule.
+  SubmoduleState *CurSubmoduleState;
 
   /// The set of known macros exported from modules.
   llvm::FoldingSet<ModuleMacro> ModuleMacros;
@@ -519,9 +536,6 @@ class Preprocessor : public RefCountedBa
   llvm::DenseMap<const IdentifierInfo *, llvm::TinyPtrVector<ModuleMacro*>>
       LeafModuleMacros;
 
-  /// The current set of visible modules.
-  VisibleModuleSet VisibleModules;
-
   /// \brief Macros that we want to warn because they are not used at the end
   /// of the translation unit.
   ///
@@ -767,7 +781,7 @@ public:
     if (!II->hasMacroDefinition())
       return MacroDefinition();
 
-    MacroState &S = Macros[II];
+    MacroState &S = CurSubmoduleState->Macros[II];
     auto *MD = S.getLatest();
     while (MD && isa<VisibilityMacroDirective>(MD))
       MD = MD->getPrevious();
@@ -781,7 +795,7 @@ public:
     if (!II->hadMacroDefinition())
       return MacroDefinition();
 
-    MacroState &S = Macros[II];
+    MacroState &S = CurSubmoduleState->Macros[II];
     MacroDirective::DefInfo DI;
     if (auto *MD = S.getLatest())
       DI = MD->findDirectiveAtLoc(Loc, getSourceManager());
@@ -1018,7 +1032,7 @@ public:
   void makeModuleVisible(Module *M, SourceLocation Loc);
 
   SourceLocation getModuleImportLoc(Module *M) const {
-    return VisibleModules.getImportLoc(M);
+    return CurSubmoduleState->VisibleModules.getImportLoc(M);
   }
 
   /// \brief Lex a string literal, which may be the concatenation of multiple

Modified: cfe/trunk/lib/Lex/PPLexerChange.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPLexerChange.cpp?rev=237871&r1=237870&r2=237871&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPLexerChange.cpp (original)
+++ cfe/trunk/lib/Lex/PPLexerChange.cpp Wed May 20 20:20:10 2015
@@ -610,39 +610,51 @@ void Preprocessor::HandleMicrosoftCommen
 }
 
 void Preprocessor::EnterSubmodule(Module *M, SourceLocation ImportLoc) {
-  // Save the current state for future imports.
-  BuildingSubmoduleStack.push_back(BuildingSubmoduleInfo(M, ImportLoc));
-  auto &Info = BuildingSubmoduleStack.back();
-  Info.Macros.swap(Macros);
-  // Save our visible modules set. This is guaranteed to clear the set.
-  if (getLangOpts().ModulesLocalVisibility) {
-    Info.VisibleModules = std::move(VisibleModules);
-
-    // Resolve as much of the module definition as we can now, before we enter
-    // one if its headers.
-    // FIXME: Can we enable Complain here?
-    ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
-    ModMap.resolveExports(M, /*Complain=*/false);
-    ModMap.resolveUses(M, /*Complain=*/false);
-    ModMap.resolveConflicts(M, /*Complain=*/false);
-
-    // This module is visible to itself.
-    makeModuleVisible(M, ImportLoc);
+  if (!getLangOpts().ModulesLocalVisibility) {
+    // Just track that we entered this submodule.
+    BuildingSubmoduleStack.push_back(
+        BuildingSubmoduleInfo(M, ImportLoc, CurSubmoduleState));
+    return;
   }
 
-  // Determine the set of starting macros for this submodule.
-  // FIXME: If we re-enter a submodule, should we restore its MacroDirectives?
-  auto &StartingMacros = getLangOpts().ModulesLocalVisibility
-                             ? BuildingSubmoduleStack[0].Macros
-                             : Info.Macros;
-
-  // Restore to the starting state.
-  // FIXME: Do this lazily, when each macro name is first referenced.
-  for (auto &Macro : StartingMacros) {
-    MacroState MS(Macro.second.getLatest());
-    MS.setOverriddenMacros(*this, Macro.second.getOverriddenMacros());
-    Macros.insert(std::make_pair(Macro.first, std::move(MS)));
+  // Resolve as much of the module definition as we can now, before we enter
+  // one of its headers.
+  // FIXME: Can we enable Complain here?
+  // FIXME: Can we do this when local visibility is disabled?
+  ModuleMap &ModMap = getHeaderSearchInfo().getModuleMap();
+  ModMap.resolveExports(M, /*Complain=*/false);
+  ModMap.resolveUses(M, /*Complain=*/false);
+  ModMap.resolveConflicts(M, /*Complain=*/false);
+
+  // If this is the first time we've entered this module, set up its state.
+  auto R = Submodules.emplace(std::piecewise_construct, std::make_tuple(M),
+                              std::make_tuple());
+  auto &State = R.first->second;
+  bool FirstTime = R.second;
+  if (FirstTime) {
+    // Determine the set of starting macros for this submodule; take these
+    // from the "null" module (the predefines buffer).
+    auto &StartingMacros = NullSubmoduleState.Macros;
+
+    // Restore to the starting state.
+    // FIXME: Do this lazily, when each macro name is first referenced.
+    for (auto &Macro : StartingMacros) {
+      MacroState MS(Macro.second.getLatest());
+      MS.setOverriddenMacros(*this, Macro.second.getOverriddenMacros());
+      State.Macros.insert(std::make_pair(Macro.first, std::move(MS)));
+    }
   }
+
+  // Track that we entered this module.
+  BuildingSubmoduleStack.push_back(
+      BuildingSubmoduleInfo(M, ImportLoc, CurSubmoduleState));
+
+  // Switch to this submodule as the current submodule.
+  CurSubmoduleState = &State;
+
+  // This module is visible to itself.
+  if (FirstTime)
+    makeModuleVisible(M, ImportLoc);
 }
 
 void Preprocessor::LeaveSubmodule() {
@@ -652,15 +664,15 @@ void Preprocessor::LeaveSubmodule() {
   SourceLocation ImportLoc = Info.ImportLoc;
 
   // Create ModuleMacros for any macros defined in this submodule.
-  for (auto &Macro : Macros) {
+  for (auto &Macro : CurSubmoduleState->Macros) {
     auto *II = const_cast<IdentifierInfo*>(Macro.first);
-    auto &OuterInfo = Info.Macros[II];
 
     // Find the starting point for the MacroDirective chain in this submodule.
-    auto *OldMD = OuterInfo.getLatest();
-    if (getLangOpts().ModulesLocalVisibility &&
-        BuildingSubmoduleStack.size() > 1) {
-      auto &PredefMacros = BuildingSubmoduleStack[0].Macros;
+    MacroDirective *OldMD = nullptr;
+    if (getLangOpts().ModulesLocalVisibility) {
+      // FIXME: It'd be better to start at the state from when we most recently
+      // entered this submodule, but it doesn't really matter.
+      auto &PredefMacros = NullSubmoduleState.Macros;
       auto PredefMacroIt = PredefMacros.find(Macro.first);
       if (PredefMacroIt == PredefMacros.end())
         OldMD = nullptr;
@@ -708,23 +720,15 @@ void Preprocessor::LeaveSubmodule() {
         break;
       }
     }
-
-    // Maintain a single macro directive chain if we're not tracking
-    // per-submodule macro visibility.
-    if (!getLangOpts().ModulesLocalVisibility)
-      OuterInfo.setLatest(Macro.second.getLatest());
   }
 
-  // Put back the old macros.
-  std::swap(Info.Macros, Macros);
-
+  // Put back the outer module's state, if we're tracking it.
   if (getLangOpts().ModulesLocalVisibility)
-    VisibleModules = std::move(Info.VisibleModules);
+    CurSubmoduleState = Info.OuterSubmoduleState;
 
   BuildingSubmoduleStack.pop_back();
 
   // A nested #include makes the included submodule visible.
-  if (!BuildingSubmoduleStack.empty() ||
-      !getLangOpts().ModulesLocalVisibility)
+  if (!BuildingSubmoduleStack.empty() || !getLangOpts().ModulesLocalVisibility)
     makeModuleVisible(LeavingMod, ImportLoc);
 }

Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=237871&r1=237870&r2=237871&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
+++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Wed May 20 20:20:10 2015
@@ -37,15 +37,16 @@ MacroDirective *
 Preprocessor::getLocalMacroDirectiveHistory(const IdentifierInfo *II) const {
   if (!II->hadMacroDefinition())
     return nullptr;
-  auto Pos = Macros.find(II);
-  return Pos == Macros.end() ? nullptr : Pos->second.getLatest();
+  auto Pos = CurSubmoduleState->Macros.find(II);
+  return Pos == CurSubmoduleState->Macros.end() ? nullptr
+                                                : Pos->second.getLatest();
 }
 
 void Preprocessor::appendMacroDirective(IdentifierInfo *II, MacroDirective *MD){
   assert(MD && "MacroDirective should be non-zero!");
   assert(!MD->getPrevious() && "Already attached to a MacroDirective history.");
 
-  MacroState &StoredMD = Macros[II];
+  MacroState &StoredMD = CurSubmoduleState->Macros[II];
   auto *OldMD = StoredMD.getLatest();
   MD->setPrevious(OldMD);
   StoredMD.setLatest(MD);
@@ -62,7 +63,7 @@ void Preprocessor::appendMacroDirective(
 void Preprocessor::setLoadedMacroDirective(IdentifierInfo *II,
                                            MacroDirective *MD) {
   assert(II && MD);
-  MacroState &StoredMD = Macros[II];
+  MacroState &StoredMD = CurSubmoduleState->Macros[II];
   assert(!StoredMD.getLatest() &&
          "the macro history was modified before initializing it from a pch");
   StoredMD = MD;
@@ -124,9 +125,11 @@ ModuleMacro *Preprocessor::getModuleMacr
 
 void Preprocessor::updateModuleMacroInfo(const IdentifierInfo *II,
                                          ModuleMacroInfo &Info) {
-  assert(Info.ActiveModuleMacrosGeneration != VisibleModules.getGeneration() &&
+  assert(Info.ActiveModuleMacrosGeneration !=
+             CurSubmoduleState->VisibleModules.getGeneration() &&
          "don't need to update this macro name info");
-  Info.ActiveModuleMacrosGeneration = VisibleModules.getGeneration();
+  Info.ActiveModuleMacrosGeneration =
+      CurSubmoduleState->VisibleModules.getGeneration();
 
   auto Leaf = LeafModuleMacros.find(II);
   if (Leaf == LeafModuleMacros.end()) {
@@ -146,7 +149,7 @@ void Preprocessor::updateModuleMacroInfo
                                                 Leaf->second.end());
   while (!Worklist.empty()) {
     auto *MM = Worklist.pop_back_val();
-    if (VisibleModules.isVisible(MM->getOwningModule())) {
+    if (CurSubmoduleState->VisibleModules.isVisible(MM->getOwningModule())) {
       // We only care about collecting definitions; undefinitions only act
       // to override other definitions.
       if (MM->getMacroInfo())
@@ -200,8 +203,8 @@ void Preprocessor::dumpMacroInfo(const I
   if (LeafIt != LeafModuleMacros.end())
     Leaf = LeafIt->second;
   const MacroState *State = nullptr;
-  auto Pos = Macros.find(II);
-  if (Pos != Macros.end())
+  auto Pos = CurSubmoduleState->Macros.find(II);
+  if (Pos != CurSubmoduleState->Macros.end())
     State = &Pos->second;
 
   llvm::errs() << "MacroState " << State << " " << II->getNameStart();
@@ -236,7 +239,8 @@ void Preprocessor::dumpMacroInfo(const I
 
     if (Active.count(MM))
       llvm::errs() << " active";
-    else if (!VisibleModules.isVisible(MM->getOwningModule()))
+    else if (!CurSubmoduleState->VisibleModules.isVisible(
+                 MM->getOwningModule()))
       llvm::errs() << " hidden";
     else if (MM->getMacroInfo())
       llvm::errs() << " overridden";

Modified: cfe/trunk/lib/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Preprocessor.cpp?rev=237871&r1=237870&r2=237871&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/lib/Lex/Preprocessor.cpp Wed May 20 20:20:10 2015
@@ -73,7 +73,8 @@ Preprocessor::Preprocessor(IntrusiveRefC
       ModuleImportExpectsIdentifier(false), CodeCompletionReached(0),
       MainFileDir(nullptr), SkipMainFilePreamble(0, true), CurPPLexer(nullptr),
       CurDirLookup(nullptr), CurLexerKind(CLK_Lexer), CurSubmodule(nullptr),
-      Callbacks(nullptr), MacroArgCache(nullptr), Record(nullptr),
+      Callbacks(nullptr), CurSubmoduleState(&NullSubmoduleState),
+      MacroArgCache(nullptr), Record(nullptr),
       MIChainHead(nullptr), DeserialMIChainHead(nullptr) {
   OwnsHeaderSearch = OwnsHeaders;
   
@@ -266,7 +267,9 @@ void Preprocessor::PrintStats() {
   llvm::errs() << "\n  Macro Expanded Tokens: "
                << llvm::capacity_in_bytes(MacroExpandedTokens);
   llvm::errs() << "\n  Predefines Buffer: " << Predefines.capacity();
-  llvm::errs() << "\n  Macros: " << llvm::capacity_in_bytes(Macros);
+  // FIXME: List information for all submodules.
+  llvm::errs() << "\n  Macros: "
+               << llvm::capacity_in_bytes(CurSubmoduleState->Macros);
   llvm::errs() << "\n  #pragma push_macro Info: "
                << llvm::capacity_in_bytes(PragmaPushMacroInfo);
   llvm::errs() << "\n  Poison Reasons: "
@@ -283,14 +286,16 @@ Preprocessor::macro_begin(bool IncludeEx
     ExternalSource->ReadDefinedMacros();
   }
 
-  return Macros.begin();
+  return CurSubmoduleState->Macros.begin();
 }
 
 size_t Preprocessor::getTotalMemory() const {
   return BP.getTotalMemory()
     + llvm::capacity_in_bytes(MacroExpandedTokens)
     + Predefines.capacity() /* Predefines buffer. */
-    + llvm::capacity_in_bytes(Macros)
+    // FIXME: Include sizes from all submodules, and include MacroInfo sizes,
+    // and ModuleMacros.
+    + llvm::capacity_in_bytes(CurSubmoduleState->Macros)
     + llvm::capacity_in_bytes(PragmaPushMacroInfo)
     + llvm::capacity_in_bytes(PoisonReasons)
     + llvm::capacity_in_bytes(CommentHandlers);
@@ -304,7 +309,7 @@ Preprocessor::macro_end(bool IncludeExte
     ExternalSource->ReadDefinedMacros();
   }
 
-  return Macros.end();
+  return CurSubmoduleState->Macros.end();
 }
 
 /// \brief Compares macro tokens with a specified token value sequence.
@@ -781,7 +786,7 @@ void Preprocessor::LexAfterModuleImport(
 }
 
 void Preprocessor::makeModuleVisible(Module *M, SourceLocation Loc) {
-  VisibleModules.setVisible(
+  CurSubmoduleState->VisibleModules.setVisible(
       M, Loc, [](Module *) {},
       [&](ArrayRef<Module *> Path, Module *Conflict, StringRef Message) {
         // FIXME: Include the path in the diagnostic.

Added: cfe/trunk/test/Modules/Inputs/submodule-visibility/cycle1.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/submodule-visibility/cycle1.h?rev=237871&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/submodule-visibility/cycle1.h (added)
+++ cfe/trunk/test/Modules/Inputs/submodule-visibility/cycle1.h Wed May 20 20:20:10 2015
@@ -0,0 +1,8 @@
+#ifndef CYCLE1
+#define CYCLE1
+
+#include "cycle2.h"
+
+struct C1 {};
+
+#endif

Added: cfe/trunk/test/Modules/Inputs/submodule-visibility/cycle2.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/submodule-visibility/cycle2.h?rev=237871&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/submodule-visibility/cycle2.h (added)
+++ cfe/trunk/test/Modules/Inputs/submodule-visibility/cycle2.h Wed May 20 20:20:10 2015
@@ -0,0 +1,8 @@
+#ifndef CYCLE2
+#define CYCLE2
+
+#include "cycle1.h"
+
+struct C2 {};
+
+#endif

Modified: cfe/trunk/test/Modules/Inputs/submodule-visibility/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/submodule-visibility/module.modulemap?rev=237871&r1=237870&r2=237871&view=diff
==============================================================================
--- cfe/trunk/test/Modules/Inputs/submodule-visibility/module.modulemap (original)
+++ cfe/trunk/test/Modules/Inputs/submodule-visibility/module.modulemap Wed May 20 20:20:10 2015
@@ -1 +1,6 @@
 module x { module a { header "a.h" } module b { header "b.h" } }
+
+module cycles {
+  module cycle1 { header "cycle1.h" }
+  module cycle2 { header "cycle2.h" }
+}

Added: cfe/trunk/test/Modules/submodule-visibility-cycles.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/submodule-visibility-cycles.cpp?rev=237871&view=auto
==============================================================================
--- cfe/trunk/test/Modules/submodule-visibility-cycles.cpp (added)
+++ cfe/trunk/test/Modules/submodule-visibility-cycles.cpp Wed May 20 20:20:10 2015
@@ -0,0 +1,10 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fno-modules-error-recovery -fmodules-local-submodule-visibility -fmodules-cache-path=%t -I%S/Inputs/submodule-visibility -verify %s
+
+#include "cycle1.h"
+C1 c1;
+C2 c2; // expected-error {{must be imported}} expected-error {{}}
+// expected-note at cycle2.h:6 {{here}}
+
+#include "cycle2.h"
+C2 c3;





More information about the cfe-commits mailing list