diff options
18 files changed, 166 insertions, 81 deletions
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 2603307775a..871f5f65447 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -551,8 +551,6 @@ def err_mmap_expected_mmap_file : Error<"expected a module map file name">; def err_mmap_module_redefinition : Error< "redefinition of module '%0'">; def note_mmap_prev_definition : Note<"previously defined here">; -def err_mmap_header_conflict : Error< - "header '%0' is already part of module '%1'">; def err_mmap_header_not_found : Error< "%select{|umbrella }0header '%1' not found">; def err_mmap_umbrella_dir_not_found : Error< diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index 90cfc6c7e18..b7982a17aa5 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -106,7 +106,8 @@ public: }; private: - typedef llvm::DenseMap<const FileEntry *, KnownHeader> HeadersMap; + typedef llvm::DenseMap<const FileEntry *, SmallVector<KnownHeader, 1> > + HeadersMap; /// \brief Mapping from each header to the module that owns the contents of /// that header. @@ -208,10 +209,15 @@ public: /// /// \param File The header file that is likely to be included. /// + /// \param RequestingModule Specifies the module the header is intended to be + /// used from. Used to disambiguate if a header is present in multiple + /// modules. + /// /// \returns The module KnownHeader, which provides the module that owns the /// given header file. The KnownHeader is default constructed to indicate /// that no module owns this header file. - KnownHeader findModuleForHeader(const FileEntry *File); + KnownHeader findModuleForHeader(const FileEntry *File, + Module *RequestingModule = NULL); /// \brief Determine whether the given header is part of a module /// marked 'unavailable'. diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index f9eae976348..adfc6f1951b 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -1461,10 +1461,9 @@ private: /// \brief Verify that it is legal for the source file that \p FilenameLoc /// points to to include the file \p Filename. /// - /// Tries to reuse \p IncFileEnt and \p SuggestedModule. + /// Tries to reuse \p IncFileEnt. void verifyModuleInclude(SourceLocation FilenameLoc, StringRef Filename, - const FileEntry *IncFileEnt, - ModuleMap::KnownHeader *SuggestedModule); + const FileEntry *IncFileEnt); // Macro handling. void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterTopLevelIfndef); diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 5bcc4ea0441..84d205acdae 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -247,16 +247,18 @@ const FileEntry *DirectoryLookup::LookupFile( // If we have a module map that might map this header, load it and // check whether we'll have a suggestion for a module. - if (SuggestedModule && - HS.hasModuleMap(TmpDir, getDir(), isSystemHeaderDirectory())) { - const FileEntry *File = HS.getFileMgr().getFile(TmpDir.str(), + HS.hasModuleMap(TmpDir, getDir(), isSystemHeaderDirectory()); + if (SuggestedModule) { + const FileEntry *File = HS.getFileMgr().getFile(TmpDir.str(), /*openFile=*/false); if (!File) return File; - // If there is a module that corresponds to this header, - // suggest it. + // If there is a module that corresponds to this header, suggest it. *SuggestedModule = HS.findModuleForHeader(File); + if (!SuggestedModule->getModule() && + HS.hasModuleMap(TmpDir, getDir(), isSystemHeaderDirectory())) + *SuggestedModule = HS.findModuleForHeader(File); return File; } @@ -503,6 +505,24 @@ const FileEntry *HeaderSearch::LookupFile( ModuleMap::KnownHeader *SuggestedModule, bool SkipCache) { + if (!HSOpts->ModuleMapFiles.empty()) { + // Preload all explicitly specified module map files. This enables modules + // map files lying in a directory structure separate from the header files + // that they describe. These cannot be loaded lazily upon encountering a + // header file, as there is no other knwon mapping from a header file to its + // module map file. + for (llvm::SetVector<std::string>::iterator + I = HSOpts->ModuleMapFiles.begin(), + E = HSOpts->ModuleMapFiles.end(); + I != E; ++I) { + const FileEntry *File = FileMgr.getFile(*I); + if (!File) + continue; + loadModuleMapFile(File, /*IsSystem=*/false); + } + HSOpts->ModuleMapFiles.clear(); + } + if (SuggestedModule) *SuggestedModule = ModuleMap::KnownHeader(); @@ -946,43 +966,20 @@ bool HeaderSearch::hasModuleMap(StringRef FileName, const DirectoryEntry *Dir = FileMgr.getDirectory(DirName); if (!Dir) return false; - - // Load user-specified module map files in 'Dir'. - bool ModuleMapFound = false; - for (llvm::SetVector<std::string>::iterator - I = HSOpts->ModuleMapFiles.begin(), - E = HSOpts->ModuleMapFiles.end(); - I != E; ++I) { - StringRef ModuleMapFileDir = llvm::sys::path::parent_path(*I); - if (!llvm::sys::fs::equivalent(ModuleMapFileDir, DirName)) - continue; - - const FileEntry *File = FileMgr.getFile(*I); - if (!File) - continue; - - loadModuleMapFile(File, /*IsSystem=*/false); - ModuleMapFound = true; - } // Try to load the "module.map" file in this directory. switch (loadModuleMapFile(Dir, IsSystem)) { case LMM_NewlyLoaded: case LMM_AlreadyLoaded: - ModuleMapFound = true; - break; - - case LMM_NoDirectory: - case LMM_InvalidModuleMap: - break; - } - - if (ModuleMapFound) { // Success. All of the directories we stepped through inherit this module // map file. for (unsigned I = 0, N = FixUpDirectories.size(); I != N; ++I) DirectoryHasModuleMap[FixUpDirectories[I]] = true; return true; + + case LMM_NoDirectory: + case LMM_InvalidModuleMap: + break; } // If we hit the top of our search, we're done. diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index a10679af158..25d68ace0f1 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -168,14 +168,41 @@ static bool isBuiltinHeader(StringRef FileName) { .Default(false); } -ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File) { +ModuleMap::KnownHeader +ModuleMap::findModuleForHeader(const FileEntry *File, + Module *RequestingModule) { HeadersMap::iterator Known = Headers.find(File); if (Known != Headers.end()) { - // If a header is not available, don't report that it maps to anything. - if (!Known->second.isAvailable()) - return KnownHeader(); + ModuleMap::KnownHeader Result = KnownHeader(); + + // Iterate over all modules that 'File' is part of to find the best fit. + for (SmallVectorImpl<KnownHeader>::iterator I = Known->second.begin(), + E = Known->second.end(); + I != E; ++I) { + // Cannot use a module if the header is excluded or unavailable in it. + if (I->getRole() == ModuleMap::ExcludedHeader || + !I->getModule()->isAvailable()) + continue; - return Known->second; + // If 'File' is part of 'RequestingModule', 'RequestingModule' is the + // module we are looking for. + if (I->getModule() == RequestingModule) + return *I; + + // If uses need to be specified explicitly, we are only allowed to return + // modules that are explicitly used by the requesting module. + if (RequestingModule && LangOpts.ModulesDeclUse && + std::find(RequestingModule->DirectUses.begin(), + RequestingModule->DirectUses.end(), + I->getModule()) == RequestingModule->DirectUses.end()) + continue; + Result = *I; + // If 'File' is a public header of this module, this is as good as we + // are going to get. + if (I->getRole() == ModuleMap::NormalHeader) + break; + } + return Result; } // If we've found a builtin header within Clang's builtin include directory, @@ -186,14 +213,8 @@ ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File) { HeaderInfo.loadTopLevelSystemModules(); // Check again. - Known = Headers.find(File); - if (Known != Headers.end()) { - // If a header is not available, don't report that it maps to anything. - if (!Known->second.isAvailable()) - return KnownHeader(); - - return Known->second; - } + if (Headers.find(File) != Headers.end()) + return findModuleForHeader(File, RequestingModule); } const DirectoryEntry *Dir = File->getDir(); @@ -262,14 +283,14 @@ ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File) { UmbrellaDirs[SkippedDirs[I]] = Result; } - Headers[File] = KnownHeader(Result, NormalHeader); + Headers[File].push_back(KnownHeader(Result, NormalHeader)); // If a header corresponds to an unavailable module, don't report // that it maps to anything. if (!Result->isAvailable()) return KnownHeader(); - return Headers[File]; + return Headers[File].back(); } SkippedDirs.push_back(Dir); @@ -288,8 +309,16 @@ ModuleMap::KnownHeader ModuleMap::findModuleForHeader(const FileEntry *File) { bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const { HeadersMap::const_iterator Known = Headers.find(Header); - if (Known != Headers.end()) - return !Known->second.isAvailable(); + if (Known != Headers.end()) { + for (SmallVectorImpl<KnownHeader>::const_iterator + I = Known->second.begin(), + E = Known->second.end(); + I != E; ++I) { + if (I->isAvailable()) + return false; + } + return true; + } const DirectoryEntry *Dir = Header->getDir(); SmallVector<const DirectoryEntry *, 2> SkippedDirs; @@ -534,7 +563,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, // umbrella header "umbrella-header-name" Result->Umbrella = UmbrellaHeader; - Headers[UmbrellaHeader] = KnownHeader(Result, NormalHeader); + Headers[UmbrellaHeader].push_back(KnownHeader(Result, NormalHeader)); UmbrellaDirs[UmbrellaHeader->getDir()] = Result; // export * @@ -598,7 +627,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, } void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){ - Headers[UmbrellaHeader] = KnownHeader(Mod, NormalHeader); + Headers[UmbrellaHeader].push_back(KnownHeader(Mod, NormalHeader)); Mod->Umbrella = UmbrellaHeader; UmbrellaDirs[UmbrellaHeader->getDir()] = Mod; } @@ -620,7 +649,7 @@ void ModuleMap::addHeader(Module *Mod, const FileEntry *Header, bool isCompilingModuleHeader = Mod->getTopLevelModule() == CompilingModule; HeaderInfo.MarkFileModuleHeader(Header, Role, isCompilingModuleHeader); } - Headers[Header] = KnownHeader(Mod, Role); + Headers[Header].push_back(KnownHeader(Mod, Role)); } const FileEntry * @@ -642,8 +671,15 @@ void ModuleMap::dump() { llvm::errs() << "Headers:"; for (HeadersMap::iterator H = Headers.begin(), HEnd = Headers.end(); H != HEnd; ++H) { - llvm::errs() << " \"" << H->first->getName() << "\" -> " - << H->second.getModule()->getFullModuleName() << "\n"; + llvm::errs() << " \"" << H->first->getName() << "\" -> "; + for (SmallVectorImpl<KnownHeader>::const_iterator I = H->second.begin(), + E = H->second.end(); + I != E; ++I) { + if (I != H->second.begin()) + llvm::errs() << ","; + llvm::errs() << I->getModule()->getFullModuleName(); + } + llvm::errs() << "\n"; } } @@ -1494,11 +1530,7 @@ void ModuleMapParser::parseHeaderDecl(MMToken::TokenKind LeadingToken, // FIXME: We shouldn't be eagerly stat'ing every file named in a module map. // Come up with a lazy way to do this. if (File) { - if (ModuleMap::KnownHeader OwningModule = Map.Headers[File]) { - Diags.Report(FileNameLoc, diag::err_mmap_header_conflict) - << FileName << OwningModule.getModule()->getFullModuleName(); - HadError = true; - } else if (LeadingToken == MMToken::UmbrellaKeyword) { + if (LeadingToken == MMToken::UmbrellaKeyword) { const DirectoryEntry *UmbrellaDir = File->getDir(); if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) { Diags.Report(LeadingLoc, diag::err_mmap_umbrella_clash) diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 99b30c67ac3..a952b2ef1b9 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -583,33 +583,33 @@ bool Preprocessor::violatesUseDeclarations( return Declared == AllowedUses.end(); } -void Preprocessor::verifyModuleInclude( - SourceLocation FilenameLoc, - StringRef Filename, - const FileEntry *IncFileEnt, - ModuleMap::KnownHeader *SuggestedModule) { +void Preprocessor::verifyModuleInclude(SourceLocation FilenameLoc, + StringRef Filename, + const FileEntry *IncFileEnt) { Module *RequestingModule = getModuleForLocation(FilenameLoc); - Module *RequestedModule = SuggestedModule->getModule(); - if (!RequestedModule) - RequestedModule = HeaderInfo.findModuleForHeader(IncFileEnt).getModule(); + if (RequestingModule) + HeaderInfo.getModuleMap().resolveUses(RequestingModule, /*Complain=*/false); + ModuleMap::KnownHeader RequestedModule = + HeaderInfo.getModuleMap().findModuleForHeader(IncFileEnt, + RequestingModule); - if (RequestingModule == RequestedModule) + if (RequestingModule == RequestedModule.getModule()) return; // No faults wihin a module, or between files both not in modules. if (RequestingModule != HeaderInfo.getModuleMap().SourceModule) return; // No errors for indirect modules. // This may be a bit of a problem for modules with no source files. - if (RequestedModule && - violatesPrivateInclude(RequestingModule, IncFileEnt, - SuggestedModule->getRole(), RequestedModule)) + if (RequestedModule && violatesPrivateInclude(RequestingModule, IncFileEnt, + RequestedModule.getRole(), + RequestedModule.getModule())) Diag(FilenameLoc, diag::error_use_of_private_header_outside_module) << Filename; // FIXME: Add support for FixIts in module map files and offer adding the // required use declaration. if (RequestingModule && getLangOpts().ModulesDeclUse && - violatesUseDeclarations(RequestingModule, RequestedModule)) + violatesUseDeclarations(RequestingModule, RequestedModule.getModule())) Diag(FilenameLoc, diag::error_undeclared_use_of_module) << Filename; } @@ -650,7 +650,7 @@ const FileEntry *Preprocessor::LookupFile( SearchPath, RelativePath, SuggestedModule, SkipCache); if (FE) { if (SuggestedModule) - verifyModuleInclude(FilenameLoc, Filename, FE, SuggestedModule); + verifyModuleInclude(FilenameLoc, Filename, FE); return FE; } diff --git a/clang/test/Modules/Inputs/modular_maps/common.h b/clang/test/Modules/Inputs/modular_maps/common.h new file mode 100644 index 00000000000..f690bcbd399 --- /dev/null +++ b/clang/test/Modules/Inputs/modular_maps/common.h @@ -0,0 +1,4 @@ +#ifndef COMMON_H +#define COMMON_H +const int c = 2; +#endif diff --git a/clang/test/Modules/Inputs/modular_maps/modulea.map b/clang/test/Modules/Inputs/modular_maps/modulea.map index 7018c413042..58c5f6464e4 100644 --- a/clang/test/Modules/Inputs/modular_maps/modulea.map +++ b/clang/test/Modules/Inputs/modular_maps/modulea.map @@ -1,4 +1,5 @@ module A { + header "common.h" header "a.h" } diff --git a/clang/test/Modules/Inputs/modular_maps/moduleb.map b/clang/test/Modules/Inputs/modular_maps/moduleb.map index 6f36ccd3baa..7b35e8f91e4 100644 --- a/clang/test/Modules/Inputs/modular_maps/moduleb.map +++ b/clang/test/Modules/Inputs/modular_maps/moduleb.map @@ -1,3 +1,4 @@ module B { + header "common.h" private header "b.h" } diff --git a/clang/test/Modules/Inputs/separate_map_tree/maps/modulea.map b/clang/test/Modules/Inputs/separate_map_tree/maps/modulea.map new file mode 100644 index 00000000000..736503ecaeb --- /dev/null +++ b/clang/test/Modules/Inputs/separate_map_tree/maps/modulea.map @@ -0,0 +1,12 @@ +module D { + header "../src/common.h" +} + +module A { + header "../src/common.h" + use C +} + +extern module B "moduleb.map" +extern module C "modulec.map" + diff --git a/clang/test/Modules/Inputs/separate_map_tree/maps/moduleb.map b/clang/test/Modules/Inputs/separate_map_tree/maps/moduleb.map new file mode 100644 index 00000000000..d3877965c71 --- /dev/null +++ b/clang/test/Modules/Inputs/separate_map_tree/maps/moduleb.map @@ -0,0 +1,4 @@ +module B { + header "../src/public-in-b.h" + private header "../src/public-in-c.h" +} diff --git a/clang/test/Modules/Inputs/separate_map_tree/maps/modulec.map b/clang/test/Modules/Inputs/separate_map_tree/maps/modulec.map new file mode 100644 index 00000000000..91063b65f37 --- /dev/null +++ b/clang/test/Modules/Inputs/separate_map_tree/maps/modulec.map @@ -0,0 +1,5 @@ +module C { + header "../src/public-in-c.h" + private header "../src/public-in-b.h" + private header "../src/private-in-c.h" +} diff --git a/clang/test/Modules/Inputs/separate_map_tree/src/common.h b/clang/test/Modules/Inputs/separate_map_tree/src/common.h new file mode 100644 index 00000000000..1d2ecb5a194 --- /dev/null +++ b/clang/test/Modules/Inputs/separate_map_tree/src/common.h @@ -0,0 +1,4 @@ +#ifndef COMMON_H +#define COMMON_H +const int common = 2; +#endif diff --git a/clang/test/Modules/Inputs/separate_map_tree/src/private-in-c.h b/clang/test/Modules/Inputs/separate_map_tree/src/private-in-c.h new file mode 100644 index 00000000000..bc9e2c1bb34 --- /dev/null +++ b/clang/test/Modules/Inputs/separate_map_tree/src/private-in-c.h @@ -0,0 +1,4 @@ +#ifndef PRIVATE_IN_C_H +#define PRIVATE_IN_C_H +const int c_ = 2; +#endif diff --git a/clang/test/Modules/Inputs/separate_map_tree/src/public-in-b.h b/clang/test/Modules/Inputs/separate_map_tree/src/public-in-b.h new file mode 100644 index 00000000000..9ea6c1b4410 --- /dev/null +++ b/clang/test/Modules/Inputs/separate_map_tree/src/public-in-b.h @@ -0,0 +1,4 @@ +#ifndef PUBLIC_IN_B_H +#define PUBLIC_IN_B_H +const int b = 3; +#endif diff --git a/clang/test/Modules/Inputs/separate_map_tree/src/public-in-c.h b/clang/test/Modules/Inputs/separate_map_tree/src/public-in-c.h new file mode 100644 index 00000000000..fa3d2fd2cb7 --- /dev/null +++ b/clang/test/Modules/Inputs/separate_map_tree/src/public-in-c.h @@ -0,0 +1,4 @@ +#ifndef PUBLIC_IN_C_H +#define PUBLIC_IN_C_H +const int c = 2; +#endif diff --git a/clang/test/Modules/modular_maps.cpp b/clang/test/Modules/modular_maps.cpp index 5070f7d5bf9..9c9aba85a91 100644 --- a/clang/test/Modules/modular_maps.cpp +++ b/clang/test/Modules/modular_maps.cpp @@ -1,6 +1,8 @@ // RUN: rm -rf %t // RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodule-map-file=%S/Inputs/modular_maps/modulea.map -I %S/Inputs/modular_maps %s -verify +#include "common.h" #include "a.h" #include "b.h" // expected-error {{private header}} -const int val = a + b; // expected-error {{undeclared identifier}} +const int v = a + c; +const int val = a + b + c; // expected-error {{undeclared identifier}} diff --git a/clang/test/Modules/separate_map_tree.cpp b/clang/test/Modules/separate_map_tree.cpp new file mode 100644 index 00000000000..5a1fff4efc7 --- /dev/null +++ b/clang/test/Modules/separate_map_tree.cpp @@ -0,0 +1,8 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=A -fmodule-map-file=%S/Inputs/separate_map_tree/maps/modulea.map -I %S/Inputs/separate_map_tree/src %s -verify + +#include "common.h" +#include "public-in-b.h" // expected-error {{private header}} +#include "public-in-c.h" +#include "private-in-c.h" // expected-error {{private header}} +const int val = common + b + c + c_; // expected-error {{undeclared identifier}} |