summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/docs/Modules.rst11
-rw-r--r--clang/include/clang/Lex/HeaderSearch.h18
-rw-r--r--clang/lib/Lex/HeaderSearch.cpp154
-rw-r--r--clang/lib/Lex/ModuleMap.cpp19
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Both/a.h0
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Both/b.h1
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Both/module.map3
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Both/module.modulemap3
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/a.h1
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/b.h1
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Modules/module.modulemap3
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/module.map3
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Inferred.framework/Headers/Inferred.h0
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/a.h1
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/module.modulemap3
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Headers/a.h0
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.modulemap3
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.private.modulemap3
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/PrivateHeaders/private.h0
-rw-r--r--clang/test/Modules/Inputs/ModuleMapLocations/module.modulemap2
-rw-r--r--clang/test/Modules/modulemap-locations.m18
21 files changed, 173 insertions, 74 deletions
diff --git a/clang/docs/Modules.rst b/clang/docs/Modules.rst
index 7545bf0cc05..611a5edc23f 100644
--- a/clang/docs/Modules.rst
+++ b/clang/docs/Modules.rst
@@ -144,7 +144,7 @@ Module maps
-----------
The crucial link between modules and headers is described by a *module map*, which describes how a collection of existing headers maps on to the (logical) structure of a module. For example, one could imagine a module ``std`` covering the C standard library. Each of the C standard library headers (``<stdio.h>``, ``<stdlib.h>``, ``<math.h>``, etc.) would contribute to the ``std`` module, by placing their respective APIs into the corresponding submodule (``std.io``, ``std.lib``, ``std.math``, etc.). Having a list of the headers that are part of the ``std`` module allows the compiler to build the ``std`` module as a standalone entity, and having the mapping from header names to (sub)modules allows the automatic translation of ``#include`` directives to module imports.
-Module maps are specified as separate files (each named ``module.map``) alongside the headers they describe, which allows them to be added to existing software libraries without having to change the library headers themselves (in most cases [#]_). The actual `Module map language`_ is described in a later section.
+Module maps are specified as separate files (each named ``module.modulemap``) alongside the headers they describe, which allows them to be added to existing software libraries without having to change the library headers themselves (in most cases [#]_). The actual `Module map language`_ is described in a later section.
.. note::
@@ -237,10 +237,13 @@ Module Map Language
The module map language describes the mapping from header files to the
logical structure of modules. To enable support for using a library as
-a module, one must write a ``module.map`` file for that library. The
-``module.map`` file is placed alongside the header files themselves,
+a module, one must write a ``module.modulemap`` file for that library. The
+``module.modulemap`` file is placed alongside the header files themselves,
and is written in the module map language described below.
+.. note::
+ For compatibility with previous releases, if a module map file named ``module.modulemap`` is not found, Clang will also search for a file named ``module.map``. This behavior is deprecated and we plan to eventually remove it.
+
As an example, the module map file for the C standard library might look a bit like this:
.. parsed-literal::
@@ -319,7 +322,7 @@ The ``framework`` qualifier specifies that this module corresponds to a Darwin-s
.. parsed-literal::
Name.framework/
- module.map Module map for the framework
+ Modules/module.modulemap Module map for the framework
Headers/ Subdirectory containing framework headers
Frameworks/ Subdirectory containing embedded frameworks
Resources/ Subdirectory containing additional resources
diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h
index e326db763c4..23be9277156 100644
--- a/clang/include/clang/Lex/HeaderSearch.h
+++ b/clang/include/clang/Lex/HeaderSearch.h
@@ -502,6 +502,12 @@ public:
///
/// \returns The module with the given name.
Module *lookupModule(StringRef ModuleName, bool AllowSearch = true);
+
+
+ /// \brief Try to find a module map file in the given directory, returning
+ /// \c nullptr if none is found.
+ const FileEntry *lookupModuleMapFile(const DirectoryEntry *Dir,
+ bool IsFramework);
void IncrementFrameworkLookupCount() { ++NumFrameworkLookups; }
@@ -623,26 +629,32 @@ private:
/// invalid.
LMM_InvalidModuleMap
};
-
+
+ LoadModuleMapResult loadModuleMapFileImpl(const FileEntry *File,
+ bool IsSystem);
+
/// \brief Try to load the module map file in the given directory.
///
/// \param DirName The name of the directory where we will look for a module
/// map file.
/// \param IsSystem Whether this is a system header directory.
+ /// \param IsFramework Whether this is a framework directory.
///
/// \returns The result of attempting to load the module map file from the
/// named directory.
- LoadModuleMapResult loadModuleMapFile(StringRef DirName, bool IsSystem);
+ LoadModuleMapResult loadModuleMapFile(StringRef DirName, bool IsSystem,
+ bool IsFramework);
/// \brief Try to load the module map file in the given directory.
///
/// \param Dir The directory where we will look for a module map file.
/// \param IsSystem Whether this is a system header directory.
+ /// \param IsFramework Whether this is a framework directory.
///
/// \returns The result of attempting to load the module map file from the
/// named directory.
LoadModuleMapResult loadModuleMapFile(const DirectoryEntry *Dir,
- bool IsSystem);
+ bool IsSystem, bool IsFramework);
/// \brief Return the HeaderFileInfo structure for the specified FileEntry.
HeaderFileInfo &getFileInfo(const FileEntry *FE);
diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp
index 46d4d41b9af..cb76923f2d6 100644
--- a/clang/lib/Lex/HeaderSearch.cpp
+++ b/clang/lib/Lex/HeaderSearch.cpp
@@ -165,8 +165,8 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
bool IsSystem = SearchDirs[Idx].isSystemHeaderDirectory();
// Search for a module map file in this directory.
- if (loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem)
- == LMM_NewlyLoaded) {
+ if (loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem,
+ /*IsFramework*/false) == LMM_NewlyLoaded) {
// We just loaded a module map file; check whether the module is
// available now.
Module = ModMap.findModule(ModuleName);
@@ -179,7 +179,8 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) {
SmallString<128> NestedModuleMapDirName;
NestedModuleMapDirName = SearchDirs[Idx].getDir()->getName();
llvm::sys::path::append(NestedModuleMapDirName, ModuleName);
- if (loadModuleMapFile(NestedModuleMapDirName, IsSystem) == LMM_NewlyLoaded){
+ if (loadModuleMapFile(NestedModuleMapDirName, IsSystem,
+ /*IsFramework*/false) == LMM_NewlyLoaded){
// If we just loaded a module map file, look for the module again.
Module = ModMap.findModule(ModuleName);
if (Module)
@@ -1097,8 +1098,8 @@ bool HeaderSearch::hasModuleMap(StringRef FileName,
if (!Dir)
return false;
- // Try to load the "module.map" file in this directory.
- switch (loadModuleMapFile(Dir, IsSystem)) {
+ // Try to load the module map file in this directory.
+ switch (loadModuleMapFile(Dir, IsSystem, /*IsFramework*/false)) {
case LMM_NewlyLoaded:
case LMM_AlreadyLoaded:
// Success. All of the directories we stepped through inherit this module
@@ -1132,36 +1133,84 @@ HeaderSearch::findModuleForHeader(const FileEntry *File) const {
return ModMap.findModuleForHeader(File);
}
+static const FileEntry *getPrivateModuleMap(StringRef ModuleMapPath,
+ const DirectoryEntry *Directory,
+ FileManager &FileMgr) {
+ StringRef Filename = llvm::sys::path::filename(ModuleMapPath);
+ SmallString<128> PrivateFilename(Directory->getName());
+ if (Filename == "module.map")
+ llvm::sys::path::append(PrivateFilename, "module_private.map");
+ else if (Filename == "module.modulemap")
+ llvm::sys::path::append(PrivateFilename, "module.private.modulemap");
+ else
+ return nullptr;
+ return FileMgr.getFile(PrivateFilename);
+}
+
bool HeaderSearch::loadModuleMapFile(const FileEntry *File, bool IsSystem) {
+ switch (loadModuleMapFileImpl(File, IsSystem)) {
+ case LMM_AlreadyLoaded:
+ case LMM_NewlyLoaded:
+ return false;
+ case LMM_NoDirectory:
+ case LMM_InvalidModuleMap:
+ return true;
+ }
+}
+
+HeaderSearch::LoadModuleMapResult
+HeaderSearch::loadModuleMapFileImpl(const FileEntry *File, bool IsSystem) {
+ assert(File && "expected FileEntry");
+
const DirectoryEntry *Dir = File->getDir();
-
- llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
- = DirectoryHasModuleMap.find(Dir);
+ auto KnownDir = DirectoryHasModuleMap.find(Dir);
if (KnownDir != DirectoryHasModuleMap.end())
- return !KnownDir->second;
-
- bool Result = ModMap.parseModuleMapFile(File, IsSystem);
- if (!Result && llvm::sys::path::filename(File->getName()) == "module.map") {
- // If the file we loaded was a module.map, look for the corresponding
- // module_private.map.
- SmallString<128> PrivateFilename(Dir->getName());
- llvm::sys::path::append(PrivateFilename, "module_private.map");
- if (const FileEntry *PrivateFile = FileMgr.getFile(PrivateFilename))
- Result = ModMap.parseModuleMapFile(PrivateFile, IsSystem);
+ return KnownDir->second ? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
+
+ if (ModMap.parseModuleMapFile(File, IsSystem)) {
+ DirectoryHasModuleMap[Dir] = false;
+ return LMM_InvalidModuleMap;
}
-
- DirectoryHasModuleMap[Dir] = !Result;
- return Result;
+
+ // Try to load a corresponding private module map.
+ if (const FileEntry *PMMFile =
+ getPrivateModuleMap(File->getName(), Dir, FileMgr)) {
+ if (ModMap.parseModuleMapFile(PMMFile, IsSystem)) {
+ DirectoryHasModuleMap[Dir] = false;
+ return LMM_InvalidModuleMap;
+ }
+ }
+
+ // This directory has a module map.
+ DirectoryHasModuleMap[Dir] = true;
+ return LMM_NewlyLoaded;
+}
+
+const FileEntry *
+HeaderSearch::lookupModuleMapFile(const DirectoryEntry *Dir, bool IsFramework) {
+ // For frameworks, the preferred spelling is Modules/module.modulemap, but
+ // module.map at the framework root is also accepted.
+ SmallString<128> ModuleMapFileName(Dir->getName());
+ if (IsFramework)
+ llvm::sys::path::append(ModuleMapFileName, "Modules");
+ llvm::sys::path::append(ModuleMapFileName, "module.modulemap");
+ if (const FileEntry *F = FileMgr.getFile(ModuleMapFileName))
+ return F;
+
+ // Continue to allow module.map
+ ModuleMapFileName = Dir->getName();
+ llvm::sys::path::append(ModuleMapFileName, "module.map");
+ return FileMgr.getFile(ModuleMapFileName);
}
-Module *HeaderSearch::loadFrameworkModule(StringRef Name,
+Module *HeaderSearch::loadFrameworkModule(StringRef Name,
const DirectoryEntry *Dir,
bool IsSystem) {
if (Module *Module = ModMap.findModule(Name))
return Module;
// Try to load a module map file.
- switch (loadModuleMapFile(Dir, IsSystem)) {
+ switch (loadModuleMapFile(Dir, IsSystem, /*IsFramework*/true)) {
case LMM_InvalidModuleMap:
break;
@@ -1201,53 +1250,30 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name,
HeaderSearch::LoadModuleMapResult
-HeaderSearch::loadModuleMapFile(StringRef DirName, bool IsSystem) {
+HeaderSearch::loadModuleMapFile(StringRef DirName, bool IsSystem,
+ bool IsFramework) {
if (const DirectoryEntry *Dir = FileMgr.getDirectory(DirName))
- return loadModuleMapFile(Dir, IsSystem);
+ return loadModuleMapFile(Dir, IsSystem, IsFramework);
return LMM_NoDirectory;
}
HeaderSearch::LoadModuleMapResult
-HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir, bool IsSystem) {
- llvm::DenseMap<const DirectoryEntry *, bool>::iterator KnownDir
- = DirectoryHasModuleMap.find(Dir);
+HeaderSearch::loadModuleMapFile(const DirectoryEntry *Dir, bool IsSystem,
+ bool IsFramework) {
+ auto KnownDir = DirectoryHasModuleMap.find(Dir);
if (KnownDir != DirectoryHasModuleMap.end())
return KnownDir->second? LMM_AlreadyLoaded : LMM_InvalidModuleMap;
-
- SmallString<128> ModuleMapFileName;
- ModuleMapFileName += Dir->getName();
- unsigned ModuleMapDirNameLen = ModuleMapFileName.size();
- llvm::sys::path::append(ModuleMapFileName, "module.map");
- if (const FileEntry *ModuleMapFile = FileMgr.getFile(ModuleMapFileName)) {
- // We have found a module map file. Try to parse it.
- if (ModMap.parseModuleMapFile(ModuleMapFile, IsSystem)) {
- // No suitable module map.
- DirectoryHasModuleMap[Dir] = false;
- return LMM_InvalidModuleMap;
- }
- // This directory has a module map.
- DirectoryHasModuleMap[Dir] = true;
-
- // Check whether there is a private module map that we need to load as well.
- ModuleMapFileName.erase(ModuleMapFileName.begin() + ModuleMapDirNameLen,
- ModuleMapFileName.end());
- llvm::sys::path::append(ModuleMapFileName, "module_private.map");
- if (const FileEntry *PrivateModuleMapFile
- = FileMgr.getFile(ModuleMapFileName)) {
- if (ModMap.parseModuleMapFile(PrivateModuleMapFile, IsSystem)) {
- // No suitable module map.
- DirectoryHasModuleMap[Dir] = false;
- return LMM_InvalidModuleMap;
- }
- }
-
- return LMM_NewlyLoaded;
+ if (const FileEntry *ModuleMapFile = lookupModuleMapFile(Dir, IsFramework)) {
+ LoadModuleMapResult Result = loadModuleMapFileImpl(ModuleMapFile, IsSystem);
+ // Add Dir explicitly in case ModuleMapFile is in a subdirectory.
+ // E.g. Foo.framework/Modules/module.modulemap
+ // ^Dir ^ModuleMapFile
+ if (Result == LMM_NewlyLoaded)
+ DirectoryHasModuleMap[Dir] = true;
+ return Result;
}
-
- // No suitable module map.
- DirectoryHasModuleMap[Dir] = false;
return LMM_InvalidModuleMap;
}
@@ -1285,7 +1311,7 @@ void HeaderSearch::collectAllModules(SmallVectorImpl<Module *> &Modules) {
continue;
// Try to load a module map file for the search directory.
- loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem);
+ loadModuleMapFile(SearchDirs[Idx].getDir(), IsSystem, /*IsFramework*/false);
// Try to load module map files for immediate subdirectories of this search
// directory.
@@ -1310,7 +1336,8 @@ void HeaderSearch::loadTopLevelSystemModules() {
// Try to load a module map file for the search directory.
loadModuleMapFile(SearchDirs[Idx].getDir(),
- SearchDirs[Idx].isSystemHeaderDirectory());
+ SearchDirs[Idx].isSystemHeaderDirectory(),
+ SearchDirs[Idx].isFramework());
}
}
@@ -1323,7 +1350,8 @@ void HeaderSearch::loadSubdirectoryModuleMaps(DirectoryLookup &SearchDir) {
llvm::sys::path::native(SearchDir.getDir()->getName(), DirNative);
for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd;
Dir != DirEnd && !EC; Dir.increment(EC)) {
- loadModuleMapFile(Dir->path(), SearchDir.isSystemHeaderDirectory());
+ loadModuleMapFile(Dir->path(), SearchDir.isSystemHeaderDirectory(),
+ SearchDir.isFramework());
}
SearchDir.setSearchedAllModuleMaps(true);
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp
index d5e8af95fe6..e78806dc50b 100644
--- a/clang/lib/Lex/ModuleMap.cpp
+++ b/clang/lib/Lex/ModuleMap.cpp
@@ -594,9 +594,9 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
if (inferred == InferredDirectories.end()) {
// We haven't looked here before. Load a module map, if there is
// one.
- SmallString<128> ModMapPath = Parent;
- llvm::sys::path::append(ModMapPath, "module.map");
- if (const FileEntry *ModMapFile = FileMgr.getFile(ModMapPath)) {
+ bool IsFrameworkDir = Parent.endswith(".framework");
+ if (const FileEntry *ModMapFile =
+ HeaderInfo.lookupModuleMapFile(ParentDir, IsFrameworkDir)) {
parseModuleMapFile(ModMapFile, IsSystem);
inferred = InferredDirectories.find(ParentDir);
}
@@ -2219,10 +2219,21 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem) {
const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID);
if (!Buffer)
return ParsedModuleMap[File] = true;
+
+ // Find the directory for the module. For frameworks, that may require going
+ // up from the 'Modules' directory.
+ const DirectoryEntry *Dir = File->getDir();
+ StringRef DirName(Dir->getName());
+ if (llvm::sys::path::filename(DirName) == "Modules") {
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.endswith(".framework"))
+ Dir = SourceMgr.getFileManager().getDirectory(DirName);
+ assert(Dir && "parent must exist");
+ }
// Parse this module map file.
Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts);
- ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File->getDir(),
+ ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, Dir,
BuiltinIncludeDir, IsSystem);
bool Result = Parser.parseModuleMapFile();
ParsedModuleMap[File] = Result;
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both/a.h b/clang/test/Modules/Inputs/ModuleMapLocations/Both/a.h
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Both/a.h
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both/b.h b/clang/test/Modules/Inputs/ModuleMapLocations/Both/b.h
new file mode 100644
index 00000000000..3abbd398c7e
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Both/b.h
@@ -0,0 +1 @@
+void wont_be_found1(void);
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both/module.map b/clang/test/Modules/Inputs/ModuleMapLocations/Both/module.map
new file mode 100644
index 00000000000..bf5aaed37ab
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Both/module.map
@@ -0,0 +1,3 @@
+module both {
+ header "b.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both/module.modulemap b/clang/test/Modules/Inputs/ModuleMapLocations/Both/module.modulemap
new file mode 100644
index 00000000000..0bfa0968c45
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Both/module.modulemap
@@ -0,0 +1,3 @@
+module both {
+ header "a.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/a.h b/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/a.h
new file mode 100644
index 00000000000..9dabfc089a1
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/a.h
@@ -0,0 +1 @@
+void will_be_found2(void);
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/b.h b/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/b.h
new file mode 100644
index 00000000000..26169fa2f69
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Headers/b.h
@@ -0,0 +1 @@
+void wont_be_found2(void);
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Modules/module.modulemap b/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Modules/module.modulemap
new file mode 100644
index 00000000000..da49ba5392f
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/Modules/module.modulemap
@@ -0,0 +1,3 @@
+framework module Both_F {
+ header "a.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/module.map b/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/module.map
new file mode 100644
index 00000000000..8fc108d3eaa
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Both_F.framework/module.map
@@ -0,0 +1,3 @@
+framework module Both_F {
+ header "b.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Inferred.framework/Headers/Inferred.h b/clang/test/Modules/Inputs/ModuleMapLocations/Inferred.framework/Headers/Inferred.h
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Inferred.framework/Headers/Inferred.h
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/a.h b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/a.h
new file mode 100644
index 00000000000..d571c6e4f79
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/a.h
@@ -0,0 +1 @@
+void will_be_found1(void);
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/module.modulemap b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/module.modulemap
new file mode 100644
index 00000000000..2ac7cc52b4f
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap/module.modulemap
@@ -0,0 +1,3 @@
+module module_modulemap {
+ header "a.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Headers/a.h b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Headers/a.h
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Headers/a.h
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.modulemap b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.modulemap
new file mode 100644
index 00000000000..400f3043e7a
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.modulemap
@@ -0,0 +1,3 @@
+framework module Module_ModuleMap_F {
+ header "a.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.private.modulemap b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.private.modulemap
new file mode 100644
index 00000000000..25a469dafbe
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/Modules/module.private.modulemap
@@ -0,0 +1,3 @@
+explicit framework module Module_ModuleMap_F.Private {
+ header "private.h"
+}
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/PrivateHeaders/private.h b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/PrivateHeaders/private.h
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/Module_ModuleMap_F.framework/PrivateHeaders/private.h
diff --git a/clang/test/Modules/Inputs/ModuleMapLocations/module.modulemap b/clang/test/Modules/Inputs/ModuleMapLocations/module.modulemap
new file mode 100644
index 00000000000..a8f5d1fbf25
--- /dev/null
+++ b/clang/test/Modules/Inputs/ModuleMapLocations/module.modulemap
@@ -0,0 +1,2 @@
+framework module * {
+}
diff --git a/clang/test/Modules/modulemap-locations.m b/clang/test/Modules/modulemap-locations.m
new file mode 100644
index 00000000000..9acdcd63436
--- /dev/null
+++ b/clang/test/Modules/modulemap-locations.m
@@ -0,0 +1,18 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fmodules -fmodules-cache-path=%t -I %S/Inputs/ModuleMapLocations/Module_ModuleMap -I %S/Inputs/ModuleMapLocations/Both -F %S/Inputs/ModuleMapLocations -x objective-c -fsyntax-only %s -verify
+
+// regular
+@import module_modulemap;
+@import both;
+// framework
+@import Module_ModuleMap_F;
+@import Module_ModuleMap_F.Private;
+@import Both_F;
+@import Inferred;
+
+void test() {
+ will_be_found1();
+ wont_be_found1(); // expected-warning{{implicit declaration of function 'wont_be_found1' is invalid in C99}}
+ will_be_found2();
+ wont_be_found2(); // expected-warning{{implicit declaration of function 'wont_be_found2' is invalid in C99}}
+}
OpenPOWER on IntegriCloud