r321855 - Reapply r321781: [Modules] Allow modules specified by -fmodule-map-file to shadow implicitly found ones

Bruno Cardoso Lopes via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 4 18:33:19 PST 2018


Author: bruno
Date: Thu Jan  4 18:33:18 2018
New Revision: 321855

URL: http://llvm.org/viewvc/llvm-project?rev=321855&view=rev
Log:
Reapply r321781: [Modules] Allow modules specified by -fmodule-map-file to shadow implicitly found ones

When modules come from module map files explicitly specified by
-fmodule-map-file= arguments, allow those to override/shadow modules
with the same name that are found implicitly by header search. If such a
module is looked up by name (e.g. @import), we will always find the one
from -fmodule-map-file. If we try to use a shadowed module by including
one of its headers report an error.

This enables developers to force use of a specific copy of their module
to be used if there are multiple copies that would otherwise be visible,
for example if they develop modules that are installed in the default
search paths.

Patch originally by Ben Langmuir,
http://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20151116/143425.html

Based on cfe-dev discussion:
http://lists.llvm.org/pipermail/cfe-dev/2015-November/046164.html

Differential Revision: https://reviews.llvm.org/D31269

rdar://problem/23612102

Added:
    cfe/trunk/test/Modules/Inputs/shadow/A1/A.h
    cfe/trunk/test/Modules/Inputs/shadow/A1/module.modulemap
    cfe/trunk/test/Modules/Inputs/shadow/A2/A.h
    cfe/trunk/test/Modules/Inputs/shadow/A2/module.modulemap
    cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/Foo.h
    cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/module.modulemap
    cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/sys/A.h
    cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/sys/A2.h
    cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/Foo.h
    cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/module.modulemap
    cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/sys/A.h
    cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/sys/A2.h
    cfe/trunk/test/Modules/Inputs/shadowed-submodule/Foo/module.modulemap
    cfe/trunk/test/Modules/shadow.m
    cfe/trunk/test/Modules/shadowed-submodule.m
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
    cfe/trunk/include/clang/Basic/Module.h
    cfe/trunk/include/clang/Lex/HeaderSearch.h
    cfe/trunk/include/clang/Lex/ModuleMap.h
    cfe/trunk/lib/Basic/Module.cpp
    cfe/trunk/lib/Lex/HeaderSearch.cpp
    cfe/trunk/lib/Lex/ModuleMap.cpp
    cfe/trunk/lib/Lex/PPDirectives.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td?rev=321855&r1=321854&r2=321855&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td Thu Jan  4 18:33:18 2018
@@ -94,6 +94,9 @@ def remark_module_lock_failure : Remark<
   "could not acquire lock file for module '%0': %1">, InGroup<ModuleBuild>;
 def remark_module_lock_timeout : Remark<
   "timed out waiting to acquire lock file for module '%0'">, InGroup<ModuleBuild>;
+def err_module_shadowed : Error<"import of shadowed module '%0'">, DefaultFatal;
+def err_module_build_shadowed_submodule : Error<
+  "build a shadowed submodule '%0'">, DefaultFatal;
 def err_module_cycle : Error<"cyclic dependency in module '%0': %1">, 
   DefaultFatal;
 def err_module_prebuilt : Error<

Modified: cfe/trunk/include/clang/Basic/Module.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Module.h?rev=321855&r1=321854&r2=321855&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Module.h (original)
+++ cfe/trunk/include/clang/Basic/Module.h Thu Jan  4 18:33:18 2018
@@ -197,6 +197,9 @@ public:
   /// will be false to indicate that this (sub)module is not available.
   SmallVector<Requirement, 2> Requirements;
 
+  /// \brief A module with the same name that shadows this module.
+  Module *ShadowingModule = nullptr;
+
   /// \brief Whether this module is missing a feature from \c Requirements.
   unsigned IsMissingRequirement : 1;
 
@@ -375,13 +378,20 @@ public:
   ///
   /// \param Target The target options used for the current translation unit.
   ///
-  /// \param Req If this module is unavailable, this parameter
-  /// will be set to one of the requirements that is not met for use of
-  /// this module.
+  /// \param Req If this module is unavailable because of a missing requirement,
+  /// this parameter will be set to one of the requirements that is not met for
+  /// use of this module.
+  ///
+  /// \param MissingHeader If this module is unavailable because of a missing
+  /// header, this parameter will be set to one of the missing headers.
+  ///
+  /// \param ShadowingModule If this module is unavailable because it is
+  /// shadowed, this parameter will be set to the shadowing module.
   bool isAvailable(const LangOptions &LangOpts, 
                    const TargetInfo &Target,
                    Requirement &Req,
-                   UnresolvedHeaderDirective &MissingHeader) const;
+                   UnresolvedHeaderDirective &MissingHeader,
+                   Module *&ShadowingModule) const;
 
   /// \brief Determine whether this module is a submodule.
   bool isSubModule() const { return Parent != nullptr; }

Modified: cfe/trunk/include/clang/Lex/HeaderSearch.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/HeaderSearch.h?rev=321855&r1=321854&r2=321855&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/HeaderSearch.h (original)
+++ cfe/trunk/include/clang/Lex/HeaderSearch.h Thu Jan  4 18:33:18 2018
@@ -726,6 +726,7 @@ private:
   LoadModuleMapResult loadModuleMapFileImpl(const FileEntry *File,
                                             bool IsSystem,
                                             const DirectoryEntry *Dir,
+                                            bool IsExplicitlyProvided,
                                             FileID ID = FileID(),
                                             unsigned *Offset = nullptr);
 

Modified: cfe/trunk/include/clang/Lex/ModuleMap.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleMap.h?rev=321855&r1=321854&r2=321855&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/ModuleMap.h (original)
+++ cfe/trunk/include/clang/Lex/ModuleMap.h Thu Jan  4 18:33:18 2018
@@ -98,6 +98,9 @@ class ModuleMap {
   /// \brief The top-level modules that are known.
   llvm::StringMap<Module *> Modules;
 
+  /// Shadow modules created while building this module map.
+  llvm::SmallVector<Module*, 2> ShadowModules;
+
   /// \brief The number of modules we have created in total.
   unsigned NumCreatedModules = 0;
 
@@ -195,6 +198,17 @@ private:
   /// header.
   llvm::DenseMap<const DirectoryEntry *, Module *> UmbrellaDirs;
 
+  /// \brief The set of modules provided explicitly (e.g. by -fmodule-map-file),
+  /// which are allowed to shadow other implicitly discovered modules.
+  llvm::DenseSet<const Module *> ExplicitlyProvidedModules;
+
+  bool mayShadowModuleBeingParsed(Module *ExistingModule,
+                                  bool IsExplicitlyProvided) {
+    assert(!ExistingModule->Parent && "expected top-level module");
+    return !IsExplicitlyProvided &&
+           ExplicitlyProvidedModules.count(ExistingModule);
+  }
+
   /// \brief The set of attributes that can be attached to a module.
   struct Attributes {
     /// \brief Whether this is a system module.
@@ -475,9 +489,9 @@ public:
   ///
   /// \returns The found or newly-created module, along with a boolean value
   /// that will be true if the module is newly-created.
-  std::pair<Module *, bool> findOrCreateModule(StringRef Name, Module *Parent,
-                                               bool IsFramework,
-                                               bool IsExplicit);
+  std::pair<Module *, bool>
+  findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
+                     bool IsExplicit, bool UsesExplicitModuleMapFile = false);
 
   /// \brief Create a 'global module' for a C++ Modules TS module interface
   /// unit.
@@ -502,6 +516,11 @@ public:
   Module *inferFrameworkModule(const DirectoryEntry *FrameworkDir,
                                bool IsSystem, Module *Parent);
 
+  /// \brief Create a new top-level module that is shadowed by
+  /// \p ShadowingModule.
+  Module *createShadowedModule(StringRef Name, bool IsFramework,
+                               Module *ShadowingModule);
+
   /// \brief Retrieve the module map file containing the definition of the given
   /// module.
   ///
@@ -587,6 +606,8 @@ public:
   /// \brief Marks this header as being excluded from the given module.
   void excludeHeader(Module *Mod, Module::Header Header);
 
+  void setExplicitlyProvided(Module *Mod);
+
   /// \brief Parse the given module map file, and record any modules we 
   /// encounter.
   ///
@@ -606,10 +627,15 @@ public:
   /// \param ExternModuleLoc The location of the "extern module" declaration
   ///        that caused us to load this module map file, if any.
   ///
+  /// \param IsExplicitlyProvided Whether this module map file was provided
+  /// explicitly by the user (e.g. -fmodule-map-file), rather than found
+  /// implicitly.
+  ///
   /// \returns true if an error occurred, false otherwise.
   bool parseModuleMapFile(const FileEntry *File, bool IsSystem,
-                          const DirectoryEntry *HomeDir, FileID ID = FileID(),
-                          unsigned *Offset = nullptr,
+                          const DirectoryEntry *HomeDir,
+                          bool IsExplicitlyProvided = false,
+                          FileID ID = FileID(), unsigned *Offset = nullptr,
                           SourceLocation ExternModuleLoc = SourceLocation());
 
   /// \brief Dump the contents of the module map, for debugging purposes.

Modified: cfe/trunk/lib/Basic/Module.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Module.cpp?rev=321855&r1=321854&r2=321855&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Module.cpp (original)
+++ cfe/trunk/lib/Basic/Module.cpp Thu Jan  4 18:33:18 2018
@@ -95,11 +95,16 @@ static bool hasFeature(StringRef Feature
 
 bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target,
                          Requirement &Req,
-                         UnresolvedHeaderDirective &MissingHeader) const {
+                         UnresolvedHeaderDirective &MissingHeader,
+                         Module *&ShadowingModule) const {
   if (IsAvailable)
     return true;
 
   for (const Module *Current = this; Current; Current = Current->Parent) {
+    if (Current->ShadowingModule) {
+      ShadowingModule = Current->ShadowingModule;
+      return false;
+    }
     for (unsigned I = 0, N = Current->Requirements.size(); I != N; ++I) {
       if (hasFeature(Current->Requirements[I].first, LangOpts, Target) !=
               Current->Requirements[I].second) {

Modified: cfe/trunk/lib/Lex/HeaderSearch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/HeaderSearch.cpp?rev=321855&r1=321854&r2=321855&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/HeaderSearch.cpp (original)
+++ cfe/trunk/lib/Lex/HeaderSearch.cpp Thu Jan  4 18:33:18 2018
@@ -1367,7 +1367,8 @@ bool HeaderSearch::loadModuleMapFile(con
     }
   }
 
-  switch (loadModuleMapFileImpl(File, IsSystem, Dir, ID, Offset)) {
+  switch (loadModuleMapFileImpl(File, IsSystem, Dir,
+                                /*IsExplictlyProvided=*/true, ID, Offset)) {
   case LMM_AlreadyLoaded:
   case LMM_NewlyLoaded:
     return false;
@@ -1378,10 +1379,9 @@ bool HeaderSearch::loadModuleMapFile(con
   llvm_unreachable("Unknown load module map result");
 }
 
-HeaderSearch::LoadModuleMapResult
-HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem,
-                                    const DirectoryEntry *Dir, FileID ID,
-                                    unsigned *Offset) {
+HeaderSearch::LoadModuleMapResult HeaderSearch::loadModuleMapFileImpl(
+    const FileEntry *File, bool IsSystem, const DirectoryEntry *Dir,
+    bool IsExplicitlyProvided, FileID ID, unsigned *Offset) {
   assert(File && "expected FileEntry");
 
   // Check whether we've already loaded this module map, and mark it as being
@@ -1390,14 +1390,16 @@ HeaderSearch::loadModuleMapFileImpl(cons
   if (!AddResult.second)
     return AddResult.first->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
 
-  if (ModMap.parseModuleMapFile(File, IsSystem, Dir, ID, Offset)) {
+  if (ModMap.parseModuleMapFile(File, IsSystem, Dir, IsExplicitlyProvided, ID,
+                                Offset)) {
     LoadedModuleMaps[File] = false;
     return LMM_InvalidModuleMap;
   }
 
   // Try to load a corresponding private module map.
   if (const FileEntry *PMMFile = getPrivateModuleMap(File, FileMgr)) {
-    if (ModMap.parseModuleMapFile(PMMFile, IsSystem, Dir)) {
+    if (ModMap.parseModuleMapFile(PMMFile, IsSystem, Dir,
+                                  IsExplicitlyProvided)) {
       LoadedModuleMaps[File] = false;
       return LMM_InvalidModuleMap;
     }
@@ -1468,8 +1470,8 @@ HeaderSearch::loadModuleMapFile(const Di
     return KnownDir->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
 
   if (const FileEntry *ModuleMapFile = lookupModuleMapFile(Dir, IsFramework)) {
-    LoadModuleMapResult Result =
-        loadModuleMapFileImpl(ModuleMapFile, IsSystem, Dir);
+    LoadModuleMapResult Result = loadModuleMapFileImpl(
+        ModuleMapFile, IsSystem, Dir, /*IsExplicitlyProvided=*/false);
     // Add Dir explicitly in case ModuleMapFile is in a subdirectory.
     // E.g. Foo.framework/Modules/module.modulemap
     //      ^Dir                  ^ModuleMapFile

Modified: cfe/trunk/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=321855&r1=321854&r2=321855&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Thu Jan  4 18:33:18 2018
@@ -281,6 +281,8 @@ ModuleMap::ModuleMap(SourceManager &Sour
 ModuleMap::~ModuleMap() {
   for (auto &M : Modules)
     delete M.getValue();
+  for (auto *M : ShadowModules)
+    delete M;
 }
 
 void ModuleMap::setTarget(const TargetInfo &Target) {
@@ -744,14 +746,13 @@ Module *ModuleMap::lookupModuleQualified
   return Context->findSubmodule(Name);
 }
 
-std::pair<Module *, bool> ModuleMap::findOrCreateModule(StringRef Name,
-                                                        Module *Parent,
-                                                        bool IsFramework,
-                                                        bool IsExplicit) {
+std::pair<Module *, bool>
+ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework,
+                              bool IsExplicit, bool UsesExplicitModuleMapFile) {
   // Try to find an existing module with this name.
   if (Module *Sub = lookupModuleQualified(Name, Parent))
     return std::make_pair(Sub, false);
-  
+
   // Create a new module with this name.
   Module *Result = new Module(Name, SourceLocation(), Parent, IsFramework,
                               IsExplicit, NumCreatedModules++);
@@ -759,6 +760,8 @@ std::pair<Module *, bool> ModuleMap::fin
     if (LangOpts.CurrentModule == Name)
       SourceModule = Result;
     Modules[Name] = Result;
+    if (UsesExplicitModuleMapFile)
+      ExplicitlyProvidedModules.insert(Result);
   }
   return std::make_pair(Result, true);
 }
@@ -999,6 +1002,20 @@ Module *ModuleMap::inferFrameworkModule(
   return Result;
 }
 
+Module *ModuleMap::createShadowedModule(StringRef Name, bool IsFramework,
+                                        Module *ShadowingModule) {
+
+  // Create a new module with this name.
+  Module *Result =
+      new Module(Name, SourceLocation(), /*Parent=*/nullptr, IsFramework,
+                 /*IsExplicit=*/false, NumCreatedModules++);
+  Result->ShadowingModule = ShadowingModule;
+  Result->IsAvailable = false;
+  ShadowModules.push_back(Result);
+
+  return Result;
+}
+
 void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader,
                                   Twine NameAsWritten) {
   Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader));
@@ -1116,6 +1133,11 @@ void ModuleMap::excludeHeader(Module *Mo
   Mod->Headers[Module::HK_Excluded].push_back(std::move(Header));
 }
 
+void ModuleMap::setExplicitlyProvided(Module *Mod) {
+  assert(Modules[Mod->Name] == Mod && "explicitly provided module is shadowed");
+  ExplicitlyProvidedModules.insert(Mod);
+}
+
 const FileEntry *
 ModuleMap::getContainingModuleMapFile(const Module *Module) const {
   if (Module->DefinitionLoc.isInvalid())
@@ -1319,7 +1341,9 @@ namespace clang {
 
     /// \brief Consume the current token and return its location.
     SourceLocation consumeToken();
-    
+
+    bool UsesExplicitModuleMapFile = false;
+
     /// \brief Skip tokens until we reach the a token with the given kind
     /// (or the end of the file).
     void skipUntil(MMToken::TokenKind K);
@@ -1345,20 +1369,19 @@ namespace clang {
     bool parseOptionalAttributes(Attributes &Attrs);
     
   public:
-    explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr, 
-                             const TargetInfo *Target,
-                             DiagnosticsEngine &Diags,
-                             ModuleMap &Map,
-                             const FileEntry *ModuleMapFile,
-                             const DirectoryEntry *Directory,
-                             bool IsSystem)
+    explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
+                             const TargetInfo *Target, DiagnosticsEngine &Diags,
+                             ModuleMap &Map, const FileEntry *ModuleMapFile,
+                             const DirectoryEntry *Directory, bool IsSystem,
+                             bool UsesExplicitModuleMapFile)
         : L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map),
           ModuleMapFile(ModuleMapFile), Directory(Directory),
-          IsSystem(IsSystem) {
+          IsSystem(IsSystem),
+          UsesExplicitModuleMapFile(UsesExplicitModuleMapFile) {
       Tok.clear();
       consumeToken();
     }
-    
+
     bool parseModuleMapFile();
 
     bool terminatedByDirective() { return false; }
@@ -1787,6 +1810,7 @@ void ModuleMapParser::parseModuleDecl()
   SourceLocation LBraceLoc = consumeToken();
   
   // Determine whether this (sub)module has already been defined.
+  Module *ShadowingModule = nullptr;
   if (Module *Existing = Map.lookupModuleQualified(ModuleName, ActiveModule)) {
     // We might see a (re)definition of a module that we already have a
     // definition for in two cases:
@@ -1812,23 +1836,36 @@ void ModuleMapParser::parseModuleDecl()
       }
       return;
     }
-    
-    Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition)
-      << ModuleName;
-    Diags.Report(Existing->DefinitionLoc, diag::note_mmap_prev_definition);
-    
-    // Skip the module definition.
-    skipUntil(MMToken::RBrace);
-    if (Tok.is(MMToken::RBrace))
-      consumeToken();
-    
-    HadError = true;
-    return;
+
+    if (!Existing->Parent &&
+        Map.mayShadowModuleBeingParsed(Existing, UsesExplicitModuleMapFile)) {
+      ShadowingModule = Existing;
+    } else {
+      // This is not a shawdowed module decl, it is an illegal redefinition.
+      Diags.Report(ModuleNameLoc, diag::err_mmap_module_redefinition)
+          << ModuleName;
+      Diags.Report(Existing->DefinitionLoc, diag::note_mmap_prev_definition);
+
+      // Skip the module definition.
+      skipUntil(MMToken::RBrace);
+      if (Tok.is(MMToken::RBrace))
+        consumeToken();
+
+      HadError = true;
+      return;
+    }
   }
 
   // Start defining this module.
-  ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework,
-                                        Explicit).first;
+  if (ShadowingModule) {
+    ActiveModule =
+        Map.createShadowedModule(ModuleName, Framework, ShadowingModule);
+  } else {
+    ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework,
+                                          Explicit, UsesExplicitModuleMapFile)
+                       .first;
+  }
+
   ActiveModule->DefinitionLoc = ModuleNameLoc;
   if (Attrs.IsSystem || IsSystem)
     ActiveModule->IsSystem = true;
@@ -2004,7 +2041,7 @@ void ModuleMapParser::parseExternModuleD
         Map.HeaderInfo.getHeaderSearchOpts().ModuleMapFileHomeIsCwd
             ? Directory
             : File->getDir(),
-        FileID(), nullptr, ExternLoc);
+        false /*IsExplicitlyProvided*/, FileID(), nullptr, ExternLoc);
 }
 
 /// Whether to add the requirement \p Feature to the module \p M.
@@ -2811,7 +2848,8 @@ bool ModuleMapParser::parseModuleMapFile
 }
 
 bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem,
-                                   const DirectoryEntry *Dir, FileID ID,
+                                   const DirectoryEntry *Dir,
+                                   bool IsExplicitlyProvided, FileID ID,
                                    unsigned *Offset,
                                    SourceLocation ExternModuleLoc) {
   assert(Target && "Missing target information");
@@ -2841,7 +2879,7 @@ bool ModuleMap::parseModuleMapFile(const
           Buffer->getBufferEnd());
   SourceLocation Start = L.getSourceLocation();
   ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir,
-                         IsSystem);
+                         IsSystem, IsExplicitlyProvided);
   bool Result = Parser.parseModuleMapFile();
   ParsedModuleMap[File] = Result;
 
@@ -2854,5 +2892,6 @@ bool ModuleMap::parseModuleMapFile(const
   // Notify callbacks that we parsed it.
   for (const auto &Cb : Callbacks)
     Cb->moduleMapFileRead(Start, *File, IsSystem);
+
   return Result;
 }

Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=321855&r1=321854&r2=321855&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
+++ cfe/trunk/lib/Lex/PPDirectives.cpp Thu Jan  4 18:33:18 2018
@@ -1655,12 +1655,18 @@ bool Preprocessor::checkModuleIsAvailabl
                                           DiagnosticsEngine &Diags, Module *M) {
   Module::Requirement Requirement;
   Module::UnresolvedHeaderDirective MissingHeader;
-  if (M->isAvailable(LangOpts, TargetInfo, Requirement, MissingHeader))
+  Module *ShadowingModule = nullptr;
+  if (M->isAvailable(LangOpts, TargetInfo, Requirement, MissingHeader,
+                     ShadowingModule))
     return false;
 
   if (MissingHeader.FileNameLoc.isValid()) {
     Diags.Report(MissingHeader.FileNameLoc, diag::err_module_header_missing)
         << MissingHeader.IsUmbrella << MissingHeader.FileName;
+  } else if (ShadowingModule) {
+    Diags.Report(M->DefinitionLoc, diag::err_module_shadowed) << M->Name;
+    Diags.Report(ShadowingModule->DefinitionLoc,
+                 diag::note_previous_definition);
   } else {
     // FIXME: Track the location at which the requirement was specified, and
     // use it here.
@@ -2024,6 +2030,15 @@ void Preprocessor::HandleIncludeDirectiv
 
   // Determine if we're switching to building a new submodule, and which one.
   if (auto *M = SuggestedModule.getModule()) {
+    if (M->getTopLevelModule()->ShadowingModule) {
+      // We are building a submodule that belongs to a shadowed module. This
+      // means we find header files in the shadowed module.
+      Diag(M->DefinitionLoc, diag::err_module_build_shadowed_submodule)
+        << M->getFullModuleName();
+      Diag(M->getTopLevelModule()->ShadowingModule->DefinitionLoc,
+           diag::note_previous_definition);
+      return;
+    }
     // When building a pch, -fmodule-name tells the compiler to textually
     // include headers in the specified module. We are not building the
     // specified module.

Added: cfe/trunk/test/Modules/Inputs/shadow/A1/A.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/shadow/A1/A.h?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/shadow/A1/A.h (added)
+++ cfe/trunk/test/Modules/Inputs/shadow/A1/A.h Thu Jan  4 18:33:18 2018
@@ -0,0 +1 @@
+#define A1_A_h

Added: cfe/trunk/test/Modules/Inputs/shadow/A1/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/shadow/A1/module.modulemap?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/shadow/A1/module.modulemap (added)
+++ cfe/trunk/test/Modules/Inputs/shadow/A1/module.modulemap Thu Jan  4 18:33:18 2018
@@ -0,0 +1,5 @@
+module A {
+  header "A.h"
+}
+
+module A1 {}

Added: cfe/trunk/test/Modules/Inputs/shadow/A2/A.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/shadow/A2/A.h?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/shadow/A2/A.h (added)
+++ cfe/trunk/test/Modules/Inputs/shadow/A2/A.h Thu Jan  4 18:33:18 2018
@@ -0,0 +1 @@
+#define A2_A_h

Added: cfe/trunk/test/Modules/Inputs/shadow/A2/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/shadow/A2/module.modulemap?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/shadow/A2/module.modulemap (added)
+++ cfe/trunk/test/Modules/Inputs/shadow/A2/module.modulemap Thu Jan  4 18:33:18 2018
@@ -0,0 +1,5 @@
+module A {
+  header "A.h"
+}
+
+module A2 {}

Added: cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/Foo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/Foo.h?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/Foo.h (added)
+++ cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/Foo.h Thu Jan  4 18:33:18 2018
@@ -0,0 +1 @@
+#include <stdarg.h> // expected-error {{could not build module 'A'}}

Added: cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/module.modulemap?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/module.modulemap (added)
+++ cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/module.modulemap Thu Jan  4 18:33:18 2018
@@ -0,0 +1,14 @@
+module A [system] { // expected-note {{previous definition is here}}
+  module sub {
+    header "sys/A.h"
+  }
+  module sub2 {
+    header "sys/A2.h"
+  }
+  module stdarg {
+    header "stdarg.h"
+    export *
+  }
+}
+
+module A2 {}

Added: cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/sys/A.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/sys/A.h?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/sys/A.h (added)
+++ cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/sys/A.h Thu Jan  4 18:33:18 2018
@@ -0,0 +1 @@
+#include <sys/A2.h>

Added: cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/sys/A2.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/sys/A2.h?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/sys/A2.h (added)
+++ cfe/trunk/test/Modules/Inputs/shadowed-submodule/A1/sys/A2.h Thu Jan  4 18:33:18 2018
@@ -0,0 +1 @@
+// nothing

Added: cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/Foo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/Foo.h?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/Foo.h (added)
+++ cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/Foo.h Thu Jan  4 18:33:18 2018
@@ -0,0 +1 @@
+#include <stdarg.h>

Added: cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/module.modulemap?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/module.modulemap (added)
+++ cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/module.modulemap Thu Jan  4 18:33:18 2018
@@ -0,0 +1,14 @@
+module A [system] {
+  module sub {
+    header "sys/A.h"
+  }
+  module sub2 { // expected-error {{build a shadowed submodule 'A.sub2'}}
+    header "sys/A2.h"
+  }
+  module stdarg {
+    header "stdarg.h"
+    export *
+  }
+}
+
+module A2 {}

Added: cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/sys/A.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/sys/A.h?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/sys/A.h (added)
+++ cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/sys/A.h Thu Jan  4 18:33:18 2018
@@ -0,0 +1 @@
+#include <sys/A2.h>

Added: cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/sys/A2.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/sys/A2.h?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/sys/A2.h (added)
+++ cfe/trunk/test/Modules/Inputs/shadowed-submodule/A2/sys/A2.h Thu Jan  4 18:33:18 2018
@@ -0,0 +1 @@
+// nothing

Added: cfe/trunk/test/Modules/Inputs/shadowed-submodule/Foo/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/shadowed-submodule/Foo/module.modulemap?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/Inputs/shadowed-submodule/Foo/module.modulemap (added)
+++ cfe/trunk/test/Modules/Inputs/shadowed-submodule/Foo/module.modulemap Thu Jan  4 18:33:18 2018
@@ -0,0 +1,3 @@
+module Foo {
+  header "../A1/Foo.h"
+}

Added: cfe/trunk/test/Modules/shadow.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/shadow.m?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/shadow.m (added)
+++ cfe/trunk/test/Modules/shadow.m Thu Jan  4 18:33:18 2018
@@ -0,0 +1,21 @@
+// RUN: rm -rf %t
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs/shadow/A1 -I %S/Inputs/shadow/A2 %s -fsyntax-only 2>&1 | FileCheck %s -check-prefix=REDEFINITION
+// RUN: not %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -fmodule-map-file=%S/Inputs/shadow/A1/module.modulemap -fmodule-map-file=%S/Inputs/shadow/A2/module.modulemap %s -fsyntax-only 2>&1 | FileCheck %s -check-prefix=REDEFINITION
+// REDEFINITION: error: redefinition of module 'A'
+// REDEFINITION: note: previously defined
+
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -fmodule-map-file=%S/Inputs/shadow/A1/module.modulemap -I %S/Inputs/shadow %s -verify
+
+ at import A1;
+ at import A2;
+ at import A;
+
+#import "A2/A.h" // expected-note {{implicitly imported}}
+// expected-error at A2/module.modulemap:1 {{import of shadowed module 'A'}}
+// expected-note at A1/module.modulemap:1 {{previous definition}}
+
+#if defined(A2_A_h)
+#error got the wrong definition of module A
+#elif !defined(A1_A_h)
+#error missing definition from A1
+#endif

Added: cfe/trunk/test/Modules/shadowed-submodule.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/shadowed-submodule.m?rev=321855&view=auto
==============================================================================
--- cfe/trunk/test/Modules/shadowed-submodule.m (added)
+++ cfe/trunk/test/Modules/shadowed-submodule.m Thu Jan  4 18:33:18 2018
@@ -0,0 +1,5 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -I %S/Inputs/shadowed-submodule/Foo -I %S/Inputs/shadowed-submodule/A2 %s -verify
+
+ at import Foo; // expected-error {{module 'A' was built in directory}}
+             // expected-note at shadowed-submodule.m:4 {{imported by module 'Foo'}}




More information about the cfe-commits mailing list