aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/Module.h6
-rw-r--r--lib/Lex/ModuleMap.cpp100
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/Headers/A.h1
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/Headers/B.h1
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/A_Private.h1
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h1
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/module.map4
-rw-r--r--test/Modules/Inputs/NoUmbrella.framework/module_private.map4
-rw-r--r--test/Modules/auto-module-import.m10
9 files changed, 61 insertions, 67 deletions
diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h
index 0f2a9a7b3d..aef2db0fed 100644
--- a/include/clang/Basic/Module.h
+++ b/include/clang/Basic/Module.h
@@ -194,6 +194,12 @@ public:
return Umbrella.dyn_cast<const FileEntry *>();
}
+ /// \brief Determine whether this module has an umbrella directory that is
+ /// not based on an umbrella header.
+ bool hasUmbrellaDir() const {
+ return Umbrella && Umbrella.is<const DirectoryEntry *>();
+ }
+
/// \brief Print the module map for this module to the given stream.
///
void print(llvm::raw_ostream &OS, unsigned Indent = 0) const;
diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp
index c9efbf0b53..12e636c1be 100644
--- a/lib/Lex/ModuleMap.cpp
+++ b/lib/Lex/ModuleMap.cpp
@@ -115,27 +115,9 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) {
// Infer submodules for each of the directories we found between
// the directory of the umbrella header and the directory where
// the actual header is located.
-
- // For a framework module, the umbrella directory is the framework
- // directory, so strip off the "Headers" or "PrivateHeaders".
bool Explicit = UmbrellaModule->InferExplicitSubmodules;
- unsigned LastSkippedDir = SkippedDirs.size();
- if (LastSkippedDir && UmbrellaModule->IsFramework) {
- if (llvm::sys::path::filename(SkippedDirs.back()->getName())
- == "PrivateHeaders") {
- // For private headers, add an explicit "Private" module.
- // FIXME: This feels somewhat hackish. Do we want to introduce
- // some kind of "umbrella directory" here?
- Result = findOrCreateModule("Private", Result,
- /*IsFramework=*/false,
- /*IsExplicit=*/true).first;
- Explicit = true;
- }
-
- --LastSkippedDir;
- }
- for (unsigned I = LastSkippedDir; I != 0; --I) {
+ for (unsigned I = SkippedDirs.size(); I != 0; --I) {
// Find or create the module that corresponds to this directory name.
StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName());
Result = findOrCreateModule(Name, Result, /*IsFramework=*/false,
@@ -294,41 +276,16 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
}
// Look for private headers.
- Module *ModulePrivate = 0;
llvm::SmallString<128> PrivateHeadersDirName(FrameworkDir->getName());
llvm::sys::path::append(PrivateHeadersDirName, "PrivateHeaders");
- llvm::SmallString<128> PrivateHeadersDirNameNative;
- llvm::sys::path::native(PrivateHeadersDirName.str(),
- PrivateHeadersDirNameNative);
- for (llvm::sys::fs::directory_iterator
- Dir(PrivateHeadersDirNameNative.str(), EC), DirEnd;
- Dir != DirEnd && !EC; Dir.increment(EC)) {
- // Check whether this entry has an extension typically associated with
- // headers.
- if (!llvm::StringSwitch<bool>(llvm::sys::path::extension(Dir->path()))
- .Cases(".h", ".H", ".hh", ".hpp", true)
- .Default(false))
- continue;
-
- if (const FileEntry *PrivateHeader = FileMgr.getFile(Dir->path())) {
- // Create the "private" submodule, if we haven't done so already.
- if (!ModulePrivate) {
- ModulePrivate = findOrCreateModule("Private", Result,
- /*IsFramework=*/false,
- /*IsExplicit=*/true).first;
- }
-
- Module *Sub = findOrCreateModule(llvm::sys::path::stem(Dir->path()),
- ModulePrivate, /*IsFramework=*/false,
- /*IsExplicit=*/true).first;
- // header "the private header"
- Sub->Headers.push_back(PrivateHeader);
-
- // export *
- Sub->Exports.push_back(Module::ExportDecl(0, true));
-
- Headers[PrivateHeader] = Sub;
- }
+ if (const DirectoryEntry *Dir = FileMgr.getDirectory(PrivateHeadersDirName)) {
+ Module *Private = findOrCreateModule("Private", Result,
+ /*IsFramework=*/false,
+ /*IsExplicit=*/true).first;
+ setUmbrellaDir(Private, Dir);
+ Private->InferSubmodules = true;
+ Private->InferExplicitSubmodules = true;
+ Private->InferExportWildcard = true;
}
return Result;
@@ -337,13 +294,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName,
void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){
Headers[UmbrellaHeader] = Mod;
Mod->Umbrella = UmbrellaHeader;
-
- const DirectoryEntry *UmbrellaDir = UmbrellaHeader->getDir();
- if (Mod->IsFramework)
- UmbrellaDir = SourceMgr->getFileManager().getDirectory(
- llvm::sys::path::parent_path(UmbrellaDir->getName()));
-
- UmbrellaDirs[UmbrellaDir] = Mod;
+ UmbrellaDirs[UmbrellaHeader->getDir()] = Mod;
}
void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) {
@@ -503,6 +454,8 @@ namespace clang {
void parseExportDecl();
void parseInferredSubmoduleDecl(bool Explicit);
+ const DirectoryEntry *getOverriddenHeaderSearchDir();
+
public:
explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr,
DiagnosticsEngine &Diags,
@@ -888,9 +841,13 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
if (llvm::sys::path::is_absolute(FileName)) {
PathName = FileName;
File = SourceMgr.getFileManager().getFile(PathName);
+ } else if (const DirectoryEntry *Dir = getOverriddenHeaderSearchDir()) {
+ PathName = Dir->getName();
+ llvm::sys::path::append(PathName, FileName);
+ File = SourceMgr.getFileManager().getFile(PathName);
} else {
// Search for the header file within the search directory.
- PathName += Directory->getName();
+ PathName = Directory->getName();
unsigned PathLength = PathName.size();
if (ActiveModule->isPartOfFramework()) {
@@ -924,13 +881,6 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) {
HadError = true;
} else if (Umbrella) {
const DirectoryEntry *UmbrellaDir = File->getDir();
- if (ActiveModule->IsFramework) {
- // For framework modules, use the framework directory as the umbrella
- // directory.
- UmbrellaDir = SourceMgr.getFileManager().getDirectory(
- llvm::sys::path::parent_path(UmbrellaDir->getName()));
- }
-
if ((OwningModule = Map.UmbrellaDirs[UmbrellaDir])) {
Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash)
<< OwningModule->getFullModuleName();
@@ -1141,6 +1091,22 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) {
}
}
+/// \brief If there is a specific header search directory due the presence
+/// of an umbrella directory, retrieve that directory. Otherwise, returns null.
+const DirectoryEntry *ModuleMapParser::getOverriddenHeaderSearchDir() {
+ for (Module *Mod = ActiveModule; Mod; Mod = Mod->Parent) {
+ // If we have an umbrella directory, use that.
+ if (Mod->hasUmbrellaDir())
+ return Mod->getUmbrellaDir();
+
+ // If we have a framework directory, stop looking.
+ if (Mod->IsFramework)
+ return 0;
+ }
+
+ return 0;
+}
+
/// \brief Parse a module map file.
///
/// module-map-file:
diff --git a/test/Modules/Inputs/NoUmbrella.framework/Headers/A.h b/test/Modules/Inputs/NoUmbrella.framework/Headers/A.h
new file mode 100644
index 0000000000..0de118c4f8
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/Headers/A.h
@@ -0,0 +1 @@
+int no_umbrella_A;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/Headers/B.h b/test/Modules/Inputs/NoUmbrella.framework/Headers/B.h
new file mode 100644
index 0000000000..dc6770fe56
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/Headers/B.h
@@ -0,0 +1 @@
+int no_umbrella_B;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/A_Private.h b/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/A_Private.h
new file mode 100644
index 0000000000..bd606d20fd
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/A_Private.h
@@ -0,0 +1 @@
+int no_umbrella_A_private;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h b/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h
new file mode 100644
index 0000000000..442be2da4e
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h
@@ -0,0 +1 @@
+int no_umbrella_B_private;
diff --git a/test/Modules/Inputs/NoUmbrella.framework/module.map b/test/Modules/Inputs/NoUmbrella.framework/module.map
new file mode 100644
index 0000000000..944150146f
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/module.map
@@ -0,0 +1,4 @@
+framework module NoUmbrella {
+ umbrella "Headers"
+ module * { }
+} \ No newline at end of file
diff --git a/test/Modules/Inputs/NoUmbrella.framework/module_private.map b/test/Modules/Inputs/NoUmbrella.framework/module_private.map
new file mode 100644
index 0000000000..0507ba02d0
--- /dev/null
+++ b/test/Modules/Inputs/NoUmbrella.framework/module_private.map
@@ -0,0 +1,4 @@
+explicit module NoUmbrella.Private {
+ umbrella "PrivateHeaders"
+ explicit module * { }
+}
diff --git a/test/Modules/auto-module-import.m b/test/Modules/auto-module-import.m
index 3703127f34..d59099f5de 100644
--- a/test/Modules/auto-module-import.m
+++ b/test/Modules/auto-module-import.m
@@ -1,3 +1,4 @@
+// other file: expected-note{{'no_umbrella_A_private' declared here}}
// RUN: rm -rf %t
// RUN: %clang_cc1 -Wauto-import -fmodule-cache-path %t -fauto-module-import -F %S/Inputs %s -verify
@@ -23,6 +24,10 @@ void testSubframeworkOther() {
double *sfo1 = sub_framework_other; // expected-error{{use of undeclared identifier 'sub_framework_other'}}
}
+// Test umbrella-less submodule includes
+#include <NoUmbrella/A.h> // expected-warning{{treating #include as an import of module 'NoUmbrella.A'}}
+int getNoUmbrellaA() { return no_umbrella_A; }
+
// Test header cross-subframework include pattern.
#include <DependsOnModule/../Frameworks/SubFramework.framework/Headers/Other.h> // expected-warning{{treating #include as an import of module 'DependsOnModule.SubFramework.Other'}}
@@ -48,3 +53,8 @@ int getDependsOnModulePrivate() { return depends_on_module_private; }
#include <Module/ModulePrivate.h> // expected-warning{{treating #include as an import of module 'Module.Private.ModulePrivate'}}
int getModulePrivate() { return module_private; }
+
+#include <NoUmbrella/A_Private.h> // expected-warning{{treating #include as an import of module 'NoUmbrella.Private.A_Private'}}
+int getNoUmbrellaAPrivate() { return no_umbrella_A_private; }
+
+int getNoUmbrellaBPrivateFail() { return no_umbrella_B_private; } // expected-error{{use of undeclared identifier 'no_umbrella_B_private'; did you mean 'no_umbrella_A_private'?}}