Index: clang/include/clang/Driver/Options.td =================================================================== --- clang/include/clang/Driver/Options.td +++ clang/include/clang/Driver/Options.td @@ -6028,6 +6028,9 @@ Flag<["-"], "fallow-pch-with-different-modules-cache-path">, HelpText<"Accept a PCH file that was created with a different modules cache path">, MarshallingInfoFlag>; +def fno_modules_share_filemanager : Flag<["-"], "fno-modules-share-filemanager">, + HelpText<"Disable sharing the FileManager when building a module implicitly">, + MarshallingInfoNegativeFlag>; def dump_deserialized_pch_decls : Flag<["-"], "dump-deserialized-decls">, HelpText<"Dump declarations that are deserialized from PCH, for testing">, MarshallingInfoFlag>; Index: clang/include/clang/Frontend/FrontendOptions.h =================================================================== --- clang/include/clang/Frontend/FrontendOptions.h +++ clang/include/clang/Frontend/FrontendOptions.h @@ -356,6 +356,9 @@ /// Output (and read) PCM files regardless of compiler errors. unsigned AllowPCMWithCompilerErrors : 1; + /// Whether to share the FileManager when building modules. + unsigned ModulesShareFileManager : 1; + CodeCompleteOptions CodeCompleteOpts; /// Specifies the output format of the AST. @@ -523,7 +526,7 @@ BuildingImplicitModuleUsesLock(true), ModulesEmbedAllFiles(false), IncludeTimestamps(true), UseTemporary(true), OutputPathIndependentPCM(false), AllowPCMWithCompilerErrors(false), - TimeTraceGranularity(500) {} + ModulesShareFileManager(true), TimeTraceGranularity(500) {} /// getInputKindForExtension - Return the appropriate input kind for a file /// extension. For example, "c" would return Language::C. Index: clang/lib/Frontend/CompilerInstance.cpp =================================================================== --- clang/lib/Frontend/CompilerInstance.cpp +++ clang/lib/Frontend/CompilerInstance.cpp @@ -1213,11 +1213,16 @@ ImportingInstance.getDiagnosticClient()), /*ShouldOwnClient=*/true); - // Note that this module is part of the module build stack, so that we - // can detect cycles in the module graph. - Instance.setFileManager(&ImportingInstance.getFileManager()); + if (FrontendOpts.ModulesShareFileManager) { + Instance.setFileManager(&ImportingInstance.getFileManager()); + } else { + Instance.createFileManager(&ImportingInstance.getVirtualFileSystem()); + } Instance.createSourceManager(Instance.getFileManager()); SourceManager &SourceMgr = Instance.getSourceManager(); + + // Note that this module is part of the module build stack, so that we + // can detect cycles in the module graph. SourceMgr.setModuleBuildStack( ImportingInstance.getSourceManager().getModuleBuildStack()); SourceMgr.pushModuleBuildStack(ModuleName, @@ -1303,12 +1308,16 @@ ModuleMapFile, ImportingInstance.getFileManager())) ModuleMapFile = PublicMMFile; + // FIXME: Update header search to keep FileEntryRef rather than rely on + // getLastRef(). + StringRef ModuleMapFilePath = + ModuleMapFile->getLastRef().getNameAsRequested(); + // Use the module map where this module resides. Result = compileModuleImpl( ImportingInstance, ImportLoc, Module->getTopLevelModuleName(), - FrontendInputFile(ModuleMapFile->getName(), IK, +Module->IsSystem), - ModMap.getModuleMapFileForUniquing(Module)->getName(), - ModuleFileName); + FrontendInputFile(ModuleMapFilePath, IK, +Module->IsSystem), + ModMap.getModuleMapFileForUniquing(Module)->getName(), ModuleFileName); } else { // FIXME: We only need to fake up an input file here as a way of // transporting the module's directory to the module map parser. We should Index: clang/test/ClangScanDeps/modulemap-via-vfs.m =================================================================== --- clang/test/ClangScanDeps/modulemap-via-vfs.m +++ clang/test/ClangScanDeps/modulemap-via-vfs.m @@ -9,6 +9,7 @@ // CHECK-NOT: build/module.modulemap // CHECK: A/module.modulemap +// CHECK-NOT: build/module.modulemap //--- build/compile-commands.json.in @@ -17,6 +18,11 @@ "directory": "DIR", "command": "clang DIR/main.m -Imodules/A -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-modules -fimplicit-module-maps -ivfsoverlay build/vfs.yaml", "file": "DIR/main.m" +}, +{ + "directory": "DIR", + "command": "clang DIR/main.m -Imodules/A -fmodules -Xclang -fno-modules-share-filemanager -fmodules-cache-path=DIR/module-cache-unshared -fimplicit-modules -fimplicit-module-maps -ivfsoverlay build/vfs.yaml", + "file": "DIR/main.m" } ] @@ -35,6 +41,7 @@ { "version": 0, "case-sensitive": "false", + "use-external-names": true, "roots": [ { "contents": [ Index: clang/test/Modules/submodule-in-private-mmap-vfs.m =================================================================== --- /dev/null +++ clang/test/Modules/submodule-in-private-mmap-vfs.m @@ -0,0 +1,38 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: sed -e "s|DIR|%/t|g" %t/vfs.json.in > %t/vfs.json +// RUN: %clang_cc1 -fmodules -fno-modules-share-filemanager -fimplicit-module-maps \ +// RUN: -fmodules-cache-path=%t -I%t/Virtual -ivfsoverlay %t/vfs.json -fsyntax-only %t/tu.m -verify + +//--- Dir1/module.modulemap + +//--- Dir2/module.private.modulemap +module Foo_Private {} + +//--- vfs.json.in +{ + 'version': 0, + 'use-external-names': true, + 'roots': [ + { + 'name': 'DIR/Virtual', + 'type': 'directory', + 'contents': [ + { + 'name': 'module.modulemap', + 'type': 'file', + 'external-contents': 'DIR/Dir1/module.modulemap' + }, + { + 'name': 'module.private.modulemap', + 'type': 'file', + 'external-contents': 'DIR/Dir2/module.private.modulemap' + } + ] + } + ] +} + +//--- tu.m +@import Foo_Private; +// expected-no-diagnostics Index: clang/test/VFS/module-import.m =================================================================== --- clang/test/VFS/module-import.m +++ clang/test/VFS/module-import.m @@ -1,6 +1,7 @@ -// RUN: rm -rf %t +// RUN: rm -rf %t %t-unshared // RUN: sed -e "s@INPUT_DIR@%{/S:regex_replacement}/Inputs@g" -e "s@OUT_DIR@%{/t:regex_replacement}@g" %S/Inputs/vfsoverlay.yaml > %t.yaml // RUN: %clang_cc1 -Werror -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -ivfsoverlay %t.yaml -I %t -fsyntax-only %s +// RUN: %clang_cc1 -Werror -fmodules -fno-modules-share-filemanager -fimplicit-module-maps -fmodules-cache-path=%t-unshared -ivfsoverlay %t.yaml -I %t -fsyntax-only %s @import not_real; @@ -18,9 +19,12 @@ // Override the module map (vfsoverlay2 on top) // RUN: sed -e "s@INPUT_DIR@%{/S:regex_replacement}/Inputs@g" -e "s@OUT_DIR@%{/t:regex_replacement}@g" %S/Inputs/vfsoverlay2.yaml > %t2.yaml // RUN: %clang_cc1 -Werror -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -ivfsoverlay %t.yaml -ivfsoverlay %t2.yaml -I %t -fsyntax-only %s +// RUN: %clang_cc1 -Werror -fmodules -fno-modules-share-filemanager -fimplicit-module-maps -fmodules-cache-path=%t-unshared -ivfsoverlay %t.yaml -ivfsoverlay %t2.yaml -I %t -fsyntax-only %s // vfsoverlay2 not present // RUN: not %clang_cc1 -Werror -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -ivfsoverlay %t.yaml -I %t -fsyntax-only %s -DIMPORT2 2>&1 | FileCheck -check-prefix=CHECK-VFS2 %s +// RUN: not %clang_cc1 -Werror -fmodules -fno-modules-share-filemanager -fimplicit-module-maps -fmodules-cache-path=%t-unshared -ivfsoverlay %t.yaml -I %t -fsyntax-only %s -DIMPORT2 2>&1 | FileCheck -check-prefix=CHECK-VFS2 %s // vfsoverlay2 on the bottom // RUN: not %clang_cc1 -Werror -fmodules -fimplicit-module-maps -fmodules-cache-path=%t -ivfsoverlay %t2.yaml -ivfsoverlay %t.yaml -I %t -fsyntax-only %s -DIMPORT2 2>&1 | FileCheck -check-prefix=CHECK-VFS2 %s +// RUN: not %clang_cc1 -Werror -fmodules -fno-modules-share-filemanager -fimplicit-module-maps -fmodules-cache-path=%t-unshared -ivfsoverlay %t2.yaml -ivfsoverlay %t.yaml -I %t -fsyntax-only %s -DIMPORT2 2>&1 | FileCheck -check-prefix=CHECK-VFS2 %s