diff options
-rw-r--r-- | include/clang/Basic/Module.h | 6 | ||||
-rw-r--r-- | lib/Lex/ModuleMap.cpp | 100 | ||||
-rw-r--r-- | test/Modules/Inputs/NoUmbrella.framework/Headers/A.h | 1 | ||||
-rw-r--r-- | test/Modules/Inputs/NoUmbrella.framework/Headers/B.h | 1 | ||||
-rw-r--r-- | test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/A_Private.h | 1 | ||||
-rw-r--r-- | test/Modules/Inputs/NoUmbrella.framework/PrivateHeaders/B_Private.h | 1 | ||||
-rw-r--r-- | test/Modules/Inputs/NoUmbrella.framework/module.map | 4 | ||||
-rw-r--r-- | test/Modules/Inputs/NoUmbrella.framework/module_private.map | 4 | ||||
-rw-r--r-- | test/Modules/auto-module-import.m | 10 |
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'?}} |