diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h index 84dd6eb44117..fb1a86206354 100644 --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -240,7 +240,7 @@ class HeaderSearch { public: HeaderSearch(IntrusiveRefCntPtr HSOpts, - FileManager &FM, DiagnosticsEngine &Diags, + SourceManager &SourceMgr, DiagnosticsEngine &Diags, const LangOptions &LangOpts, const TargetInfo *Target); ~HeaderSearch(); diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index b7982a17aa56..3a17157f94d5 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -37,7 +37,7 @@ class HeaderSearch; class ModuleMapParser; class ModuleMap { - SourceManager *SourceMgr; + SourceManager &SourceMgr; IntrusiveRefCntPtr Diags; const LangOptions &LangOpts; const TargetInfo *Target; @@ -178,9 +178,9 @@ private: public: /// \brief Construct a new module map. /// - /// \param FileMgr The file manager used to find module files and headers. - /// This file manager should be shared with the header-search mechanism, since - /// they will refer to the same headers. + /// \param SourceMgr The source manager used to find module files and headers. + /// This source manager should be shared with the header-search mechanism, + /// since they will refer to the same headers. /// /// \param DC A diagnostic consumer that will be cloned for use in generating /// diagnostics. @@ -188,7 +188,7 @@ public: /// \param LangOpts Language options for this translation unit. /// /// \param Target The target for this translation unit. - ModuleMap(FileManager &FileMgr, DiagnosticConsumer &DC, + ModuleMap(SourceManager &SourceMgr, DiagnosticConsumer &DC, const LangOptions &LangOpts, const TargetInfo *Target, HeaderSearch &HeaderInfo); diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 610c20d9fb14..a8c587638a28 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -707,7 +707,7 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, AST->HSOpts = new HeaderSearchOptions(); AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts, - AST->getFileManager(), + AST->getSourceManager(), AST->getDiagnostics(), AST->ASTFileLangOpts, /*Target=*/0)); diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 9f0ca3b31e92..5d3fd456c44b 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -218,7 +218,7 @@ void CompilerInstance::createPreprocessor() { // Create the Preprocessor. HeaderSearch *HeaderInfo = new HeaderSearch(&getHeaderSearchOpts(), - getFileManager(), + getSourceManager(), getDiagnostics(), getLangOpts(), &getTarget()); @@ -851,29 +851,6 @@ static void compileModule(CompilerInstance &ImportingInstance, FrontendOpts.Inputs.clear(); InputKind IK = getSourceInputKindFromOptions(*Invocation->getLangOpts()); - // Get or create the module map that we'll use to build this module. - SmallString<128> TempModuleMapFileName; - if (const FileEntry *ModuleMapFile - = ModMap.getContainingModuleMapFile(Module)) { - // Use the module map where this module resides. - FrontendOpts.Inputs.push_back(FrontendInputFile(ModuleMapFile->getName(), - IK)); - } else { - // Create a temporary module map file. - int FD; - if (llvm::sys::fs::createTemporaryFile(Module->Name, "map", FD, - TempModuleMapFileName)) { - ImportingInstance.getDiagnostics().Report(diag::err_module_map_temp_file) - << TempModuleMapFileName; - return; - } - // Print the module map to this file. - llvm::raw_fd_ostream OS(FD, /*shouldClose=*/true); - Module->print(OS); - FrontendOpts.Inputs.push_back( - FrontendInputFile(TempModuleMapFileName.str().str(), IK)); - } - // Don't free the remapped file buffers; they are owned by our caller. PPOpts.RetainRemappedFileBuffers = true; @@ -900,6 +877,26 @@ static void compileModule(CompilerInstance &ImportingInstance, SourceMgr.pushModuleBuildStack(Module->getTopLevelModuleName(), FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager())); + // Get or create the module map that we'll use to build this module. + std::string InferredModuleMapContent; + if (const FileEntry *ModuleMapFile = + ModMap.getContainingModuleMapFile(Module)) { + // Use the module map where this module resides. + FrontendOpts.Inputs.push_back( + FrontendInputFile(ModuleMapFile->getName(), IK)); + } else { + llvm::raw_string_ostream OS(InferredModuleMapContent); + Module->print(OS); + OS.flush(); + FrontendOpts.Inputs.push_back( + FrontendInputFile("__inferred_module.map", IK)); + + const llvm::MemoryBuffer *ModuleMapBuffer = + llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent); + ModuleMapFile = Instance.getFileManager().getVirtualFile( + "__inferred_module.map", InferredModuleMapContent.size(), 0); + SourceMgr.overrideFileContents(ModuleMapFile, ModuleMapBuffer); + } // Construct a module-generating action. GenerateModuleAction CreateModuleAction(Module->IsSystem); @@ -917,8 +914,6 @@ static void compileModule(CompilerInstance &ImportingInstance, // be nice to do this with RemoveFileOnSignal when we can. However, that // doesn't make sense for all clients, so clean this up manually. Instance.clearOutputFiles(/*EraseFiles=*/true); - if (!TempModuleMapFileName.empty()) - llvm::sys::fs::remove(TempModuleMapFileName.str()); // We've rebuilt a module. If we're allowed to generate or update the global // module index, record that fact in the importing compiler instance. diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 84d205acdaec..2da2c9efba9e 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -44,11 +44,11 @@ HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) { ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {} HeaderSearch::HeaderSearch(IntrusiveRefCntPtr HSOpts, - FileManager &FM, DiagnosticsEngine &Diags, + SourceManager &SourceMgr, DiagnosticsEngine &Diags, const LangOptions &LangOpts, const TargetInfo *Target) - : HSOpts(HSOpts), FileMgr(FM), FrameworkMap(64), - ModMap(FileMgr, *Diags.getClient(), LangOpts, Target, *this) + : HSOpts(HSOpts), FileMgr(SourceMgr.getFileManager()), FrameworkMap(64), + ModMap(SourceMgr, *Diags.getClient(), LangOpts, Target, *this) { AngledDirIdx = 0; SystemDirIdx = 0; diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 25d68ace0f19..54007c78d839 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -83,18 +83,18 @@ Module *ModuleMap::resolveModuleId(const ModuleId &Id, Module *Mod, return Context; } -ModuleMap::ModuleMap(FileManager &FileMgr, DiagnosticConsumer &DC, +ModuleMap::ModuleMap(SourceManager &SourceMgr, DiagnosticConsumer &DC, const LangOptions &LangOpts, const TargetInfo *Target, HeaderSearch &HeaderInfo) - : LangOpts(LangOpts), Target(Target), HeaderInfo(HeaderInfo), - BuiltinIncludeDir(0), CompilingModule(0), SourceModule(0) -{ + : SourceMgr(SourceMgr), LangOpts(LangOpts), Target(Target), + HeaderInfo(HeaderInfo), BuiltinIncludeDir(0), CompilingModule(0), + SourceModule(0) { IntrusiveRefCntPtr DiagIDs(new DiagnosticIDs); Diags = IntrusiveRefCntPtr( new DiagnosticsEngine(DiagIDs, new DiagnosticOptions)); Diags->setClient(new ForwardingDiagnosticConsumer(DC), /*ShouldOwnClient=*/true); - SourceMgr = new SourceManager(*Diags, FileMgr); + Diags->setSourceManager(&SourceMgr); } ModuleMap::~ModuleMap() { @@ -103,8 +103,6 @@ ModuleMap::~ModuleMap() { I != IEnd; ++I) { delete I->getValue(); } - - delete SourceMgr; } void ModuleMap::setTarget(const TargetInfo &Target) { @@ -224,7 +222,7 @@ ModuleMap::findModuleForHeader(const FileEntry *File, // frameworks moving from top-level frameworks to embedded frameworks tend // to be symlinked from the top-level location to the embedded location, // and we need to resolve lookups as if we had found the embedded location. - StringRef DirName = SourceMgr->getFileManager().getCanonicalName(Dir); + StringRef DirName = SourceMgr.getFileManager().getCanonicalName(Dir); // Keep walking up the directory hierarchy, looking for a directory with // an umbrella header. @@ -301,7 +299,7 @@ ModuleMap::findModuleForHeader(const FileEntry *File, break; // Resolve the parent path to a directory entry. - Dir = SourceMgr->getFileManager().getDirectory(DirName); + Dir = SourceMgr.getFileManager().getDirectory(DirName); } while (Dir); return KnownHeader(); @@ -375,7 +373,7 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) const { break; // Resolve the parent path to a directory entry. - Dir = SourceMgr->getFileManager().getDirectory(DirName); + Dir = SourceMgr.getFileManager().getDirectory(DirName); } while (Dir); return false; @@ -480,7 +478,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, if (Module *Mod = lookupModuleQualified(ModuleName, Parent)) return Mod; - FileManager &FileMgr = SourceMgr->getFileManager(); + FileManager &FileMgr = SourceMgr.getFileManager(); // If the framework has a parent path from which we're allowed to infer // a framework module, do so. @@ -492,7 +490,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, // top-level framework, and we need to infer as if we were naming the // top-level framework. StringRef FrameworkDirName - = SourceMgr->getFileManager().getCanonicalName(FrameworkDir); + = SourceMgr.getFileManager().getCanonicalName(FrameworkDir); bool canInfer = false; if (llvm::sys::path::has_parent_path(FrameworkDirName)) { @@ -654,11 +652,11 @@ void ModuleMap::addHeader(Module *Mod, const FileEntry *Header, const FileEntry * ModuleMap::getContainingModuleMapFile(Module *Module) const { - if (Module->DefinitionLoc.isInvalid() || !SourceMgr) + if (Module->DefinitionLoc.isInvalid()) return 0; - return SourceMgr->getFileEntryForID( - SourceMgr->getFileID(Module->DefinitionLoc)); + return SourceMgr.getFileEntryForID( + SourceMgr.getFileID(Module->DefinitionLoc)); } void ModuleMap::dump() { @@ -2110,15 +2108,15 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File, bool IsSystem) { return Known->second; assert(Target != 0 && "Missing target information"); - FileID ID = SourceMgr->createFileID(File, SourceLocation(), SrcMgr::C_User); - const llvm::MemoryBuffer *Buffer = SourceMgr->getBuffer(ID); + FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User); + const llvm::MemoryBuffer *Buffer = SourceMgr.getBuffer(ID); if (!Buffer) return ParsedModuleMap[File] = true; // Parse this module map file. - Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts); + Lexer L(ID, SourceMgr.getBuffer(ID), SourceMgr, MMapLangOpts); Diags->getClient()->BeginSourceFile(MMapLangOpts); - ModuleMapParser Parser(L, *SourceMgr, Target, *Diags, *this, File->getDir(), + ModuleMapParser Parser(L, SourceMgr, Target, *Diags, *this, File->getDir(), BuiltinIncludeDir, IsSystem); bool Result = Parser.parseModuleMapFile(); Diags->getClient()->EndSourceFile(); diff --git a/clang/test/Modules/Inputs/declare-use/module.map b/clang/test/Modules/Inputs/declare-use/module.map index ae3e90801ec0..774fc37760c9 100644 --- a/clang/test/Modules/Inputs/declare-use/module.map +++ b/clang/test/Modules/Inputs/declare-use/module.map @@ -1,43 +1,43 @@ -module A { +module XA { header "a.h" } -module B { +module XB { header "b.h" } -module C { +module XC { header "c.h" - use A + use XA } -module D { +module XD { header "d.h" - use A + use XA } -module E { +module XE { header "e.h" - use A - use B + use XA + use XB } -module F { +module XF { header "f.h" - use A - use B + use XA + use XB } -module G { +module XG { header "g.h" header "g1.h" - use C - use E + use XC + use XE } -module H { +module XH { header "h.h" header "h1.h" - use C - use E + use XC + use XE } diff --git a/clang/test/Modules/Inputs/private1/module.map b/clang/test/Modules/Inputs/private1/module.map index 445c8010db9b..0904fe68a62c 100644 --- a/clang/test/Modules/Inputs/private1/module.map +++ b/clang/test/Modules/Inputs/private1/module.map @@ -1,4 +1,4 @@ -module libPrivate1 { +module libPrivate { header "public1.h" private header "private1.h" } diff --git a/clang/test/Modules/Inputs/private2/module.map b/clang/test/Modules/Inputs/private2/module.map index 6c5efb60209d..3d2a5786f9b1 100644 --- a/clang/test/Modules/Inputs/private2/module.map +++ b/clang/test/Modules/Inputs/private2/module.map @@ -1,4 +1,4 @@ -module libPrivate2 { +module libPrivateN2 { header "public2.h" private header "private2.h" } diff --git a/clang/test/Modules/declare-use1.cpp b/clang/test/Modules/declare-use1.cpp index 5bb7e2a47aff..4508017c12d2 100644 --- a/clang/test/Modules/declare-use1.cpp +++ b/clang/test/Modules/declare-use1.cpp @@ -1,5 +1,5 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=G -I %S/Inputs/declare-use %s -verify +// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=XG -I %S/Inputs/declare-use %s -verify #include "g.h" #include "e.h" diff --git a/clang/test/Modules/declare-use2.cpp b/clang/test/Modules/declare-use2.cpp index 807962cbdb4a..a2ec55e5e5ca 100644 --- a/clang/test/Modules/declare-use2.cpp +++ b/clang/test/Modules/declare-use2.cpp @@ -1,5 +1,5 @@ // RUN: rm -rf %t -// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=H -I %S/Inputs/declare-use %s -verify +// RUN: %clang_cc1 -x objective-c++ -fmodules-cache-path=%t -fmodules -fmodules-decluse -fmodule-name=XH -I %S/Inputs/declare-use %s -verify #include "h.h" #include "e.h" diff --git a/clang/test/Modules/private1.cpp b/clang/test/Modules/private1.cpp index e4eec0a515c8..811a2333d1db 100644 --- a/clang/test/Modules/private1.cpp +++ b/clang/test/Modules/private1.cpp @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -x objective-c -fmodules-cache-path=%t -fmodules -I %S/Inputs/private0 -I %S/Inputs/private1 -I %S/Inputs/private2 %s -verify #include "common.h" -@import libPrivate1; +@import libPrivateN2; #include "private1.h" // expected-error {{use of private header from outside its module}} #include "public2.h" #include "private2.h" // expected-error {{use of private header from outside its module}} diff --git a/clang/unittests/Basic/SourceManagerTest.cpp b/clang/unittests/Basic/SourceManagerTest.cpp index 8e7f4a0371af..d94cfe9c3fab 100644 --- a/clang/unittests/Basic/SourceManagerTest.cpp +++ b/clang/unittests/Basic/SourceManagerTest.cpp @@ -73,7 +73,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnit) { FileID mainFileID = SourceMgr.createMainFileIDForMemBuffer(buf); VoidModuleLoader ModLoader; - HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts, + HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, &*Target); Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(), SourceMgr, HeaderInfo, ModLoader, @@ -188,7 +188,7 @@ TEST_F(SourceManagerTest, getMacroArgExpandedLocation) { SourceMgr.overrideFileContents(headerFile, headerBuf); VoidModuleLoader ModLoader; - HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts, + HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, &*Target); Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(), SourceMgr, HeaderInfo, ModLoader, @@ -286,7 +286,7 @@ TEST_F(SourceManagerTest, isBeforeInTranslationUnitWithMacroInInclude) { SourceMgr.overrideFileContents(headerFile, headerBuf); VoidModuleLoader ModLoader; - HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts, + HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, &*Target); Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(), SourceMgr, HeaderInfo, ModLoader, diff --git a/clang/unittests/Lex/LexerTest.cpp b/clang/unittests/Lex/LexerTest.cpp index a8e25cb2a394..40ce928014d5 100644 --- a/clang/unittests/Lex/LexerTest.cpp +++ b/clang/unittests/Lex/LexerTest.cpp @@ -62,7 +62,7 @@ protected: (void) SourceMgr.createMainFileIDForMemBuffer(buf); VoidModuleLoader ModLoader; - HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts, + HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, Target.getPtr()); Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts, Target.getPtr(), SourceMgr, HeaderInfo, ModLoader, /*IILookup =*/ 0, diff --git a/clang/unittests/Lex/PPCallbacksTest.cpp b/clang/unittests/Lex/PPCallbacksTest.cpp index fd407b52c6eb..9405a84024bd 100644 --- a/clang/unittests/Lex/PPCallbacksTest.cpp +++ b/clang/unittests/Lex/PPCallbacksTest.cpp @@ -162,7 +162,8 @@ protected: VoidModuleLoader ModLoader; IntrusiveRefCntPtr HSOpts = new HeaderSearchOptions(); - HeaderSearch HeaderInfo(HSOpts, FileMgr, Diags, LangOpts, Target.getPtr()); + HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, + Target.getPtr()); AddFakeHeader(HeaderInfo, HeaderPath, SystemHeader); IntrusiveRefCntPtr PPOpts = new PreprocessorOptions(); @@ -198,7 +199,7 @@ protected: (void)SourceMgr.createMainFileIDForMemBuffer(sourceBuf); VoidModuleLoader ModLoader; - HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, + HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, OpenCLLangOpts, Target.getPtr()); Preprocessor PP(new PreprocessorOptions(), Diags, OpenCLLangOpts, diff --git a/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp b/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp index 082eced2d854..58857fa5a133 100644 --- a/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp +++ b/clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp @@ -90,7 +90,7 @@ TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) { SourceMgr.createMainFileIDForMemBuffer(buf); VoidModuleLoader ModLoader; - HeaderSearch HeaderInfo(new HeaderSearchOptions, FileMgr, Diags, LangOpts, + HeaderSearch HeaderInfo(new HeaderSearchOptions, SourceMgr, Diags, LangOpts, Target.getPtr()); Preprocessor PP(new PreprocessorOptions(), Diags, LangOpts,Target.getPtr(), SourceMgr, HeaderInfo, ModLoader, diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp index e435ea92e235..412af7adda9b 100644 --- a/clang/unittests/Tooling/ToolingTest.cpp +++ b/clang/unittests/Tooling/ToolingTest.cpp @@ -131,6 +131,26 @@ TEST(ToolInvocation, TestMapVirtualFile) { EXPECT_TRUE(Invocation.run()); } +TEST(ToolInvocation, TestVirtualModulesCompilation) { + // FIXME: Currently, this only tests that we don't exit with an error if a + // mapped module.map is found on the include path. In the future, expand this + // test to run a full modules enabled compilation, so we make sure we can + // rerun modules compilations with a virtual file system. + clang::FileManager Files((clang::FileSystemOptions())); + std::vector Args; + Args.push_back("tool-executable"); + Args.push_back("-Idef"); + Args.push_back("-fsyntax-only"); + Args.push_back("test.cpp"); + clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction, &Files); + Invocation.mapVirtualFile("test.cpp", "#include \n"); + Invocation.mapVirtualFile("def/abc", "\n"); + // Add a module.map file in the include directory of our header, so we trigger + // the module.map header search logic. + Invocation.mapVirtualFile("def/module.map", "\n"); + EXPECT_TRUE(Invocation.run()); +} + struct VerifyEndCallback : public SourceFileCallbacks { VerifyEndCallback() : BeginCalled(0), EndCalled(0), Matched(false) {} virtual bool handleBeginSource(CompilerInstance &CI,