Index: include/clang/Basic/DiagnosticDriverKinds.td =================================================================== --- include/clang/Basic/DiagnosticDriverKinds.td +++ include/clang/Basic/DiagnosticDriverKinds.td @@ -232,6 +232,8 @@ def err_drv_modules_validate_once_requires_timestamp : Error< "option '-fmodules-validate-once-per-build-session' requires " "'-fbuild-session-timestamp=' or '-fbuild-session-file='">; +def err_drv_modules_use_prebuilt_modules_conflicts_implicit : Error< + "option '-fmodules-use-prebuilt-modules' conflicts with '-fimplicit-module-maps'">; def err_test_module_file_extension_format : Error< "-ftest-module-file-extension argument '%0' is not of the required form " Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -860,6 +860,9 @@ def fmodules_disable_diagnostic_validation : Flag<["-"], "fmodules-disable-diagnostic-validation">, Group, Flags<[CC1Option]>, HelpText<"Disable validation of the diagnostic options when loading the module">; +def fmodules_use_prebuilt_modules : Flag<["-"], "fmodules-use-prebuilt-modules">, + Group, Flags<[CC1Option]>, + HelpText<"Use prebuilt modules without loading any module map">; def fmodules_validate_system_headers : Flag<["-"], "fmodules-validate-system-headers">, Group, Flags<[CC1Option]>, HelpText<"Validate the system headers that a module depends on when loading the module">; Index: include/clang/Lex/HeaderSearchOptions.h =================================================================== --- include/clang/Lex/HeaderSearchOptions.h +++ include/clang/Lex/HeaderSearchOptions.h @@ -174,6 +174,8 @@ unsigned ModulesValidateDiagnosticOptions : 1; + unsigned ModulesUsePrebuiltModules : 1; + HeaderSearchOptions(StringRef _Sysroot = "/") : Sysroot(_Sysroot), ModuleFormat("raw"), DisableModuleHash(0), ImplicitModuleMaps(0), ModuleMapFileHomeIsCwd(0), @@ -183,7 +185,8 @@ UseStandardCXXIncludes(true), UseLibcxx(false), Verbose(false), ModulesValidateOncePerBuildSession(false), ModulesValidateSystemHeaders(false), - UseDebugInfo(false), ModulesValidateDiagnosticOptions(true) {} + UseDebugInfo(false), ModulesValidateDiagnosticOptions(true), + ModulesUsePrebuiltModules(false) {} /// AddPath - Add the \p Path path to the specified \p Group list. void AddPath(StringRef Path, frontend::IncludeDirGroup Group, Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -5297,9 +5297,16 @@ // -fmodule-maps enables implicit reading of module map files. By default, // this is enabled if we are using precompiled modules. + bool IsPrebuilt = Args.getLastArg(options::OPT_fmodules_use_prebuilt_modules); if (Args.hasFlag(options::OPT_fimplicit_module_maps, - options::OPT_fno_implicit_module_maps, HaveModules)) { - CmdArgs.push_back("-fimplicit-module-maps"); + options::OPT_fno_implicit_module_maps, + HaveModules && !IsPrebuilt)) { + // When using prebuilt modules, the default is no implicit module maps; + // if user specifies implicit module maps, emit error. + if (IsPrebuilt) + D.Diag(diag::err_drv_modules_use_prebuilt_modules_conflicts_implicit); + else + CmdArgs.push_back("-fimplicit-module-maps"); } // -fmodules-decluse checks that modules used are declared so (off by @@ -5406,6 +5413,12 @@ Args.AddLastArg(CmdArgs, options::OPT_fmodules_validate_system_headers); Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation); + if (Args.getLastArg(options::OPT_fmodules_use_prebuilt_modules)) { + // When using prebuilt modules, we disable module hash. + CmdArgs.push_back("-fdisable-module-hash"); + Args.AddLastArg(CmdArgs, options::OPT_fmodules_use_prebuilt_modules); + } + // -faccess-control is default. if (Args.hasFlag(options::OPT_fno_access_control, options::OPT_faccess_control, false)) Index: lib/Frontend/CompilerInstance.cpp =================================================================== --- lib/Frontend/CompilerInstance.cpp +++ lib/Frontend/CompilerInstance.cpp @@ -1433,18 +1433,26 @@ } else { // Search for a module with the given name. Module = PP->getHeaderSearchInfo().lookupModule(ModuleName); - if (!Module) { + HeaderSearchOptions &HSOpts = + PP->getHeaderSearchInfo().getHeaderSearchOpts(); + if (!Module && !HSOpts.ModulesUsePrebuiltModules) { getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) << ModuleName << SourceRange(ImportLoc, ModuleNameLoc); ModuleBuildFailed = true; return ModuleLoadResult(); } + std::string ModuleFileName; + if (HSOpts.ModulesUsePrebuiltModules) + // Try to load the pcm file without a module map. + ModuleFileName = + PP->getHeaderSearchInfo().getModuleFileName(ModuleName, ""); + else + ModuleFileName = PP->getHeaderSearchInfo().getModuleFileName(Module); - std::string ModuleFileName = - PP->getHeaderSearchInfo().getModuleFileName(Module); if (ModuleFileName.empty()) { - if (Module->HasIncompatibleModuleFile) { + if (!HSOpts.ModulesUsePrebuiltModules && + Module->HasIncompatibleModuleFile) { // We tried and failed to load a module file for this module. Fall // back to textual inclusion for its headers. return ModuleLoadResult(nullptr, /*missingExpected*/true); @@ -1465,16 +1473,42 @@ Timer.init("Loading " + ModuleFileName, *FrontendTimerGroup); llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr); - // Try to load the module file. + // Try to load the module file. If we are using prebuilt modules, we + // don't have the module map files and don't know how to rebuild modules. unsigned ARRFlags = ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing; switch (ModuleManager->ReadAST(ModuleFileName, serialization::MK_ImplicitModule, - ImportLoc, ARRFlags)) { - case ASTReader::Success: + ImportLoc, + HSOpts.ModulesUsePrebuiltModules ? + ASTReader::ARR_ConfigurationMismatch : + ARRFlags)) { + case ASTReader::Success: { + if (HSOpts.ModulesUsePrebuiltModules && !Module) { + // Create a Module if we are using the prebuilt modules. + Module = PP->getHeaderSearchInfo().getModuleMap().findOrCreateModule( + ModuleName, nullptr, false/*IsFramework*/, + false/*IsExplicit*/).first; + // FIXME: Since we are mostly prebuilding system modules, we set + // IsSystem to true here. This is not always the correct choice, + // and IsSystem can affect diagnostics. + Module->IsSystem = true; + Module->IsFromModuleFile = true; + } break; + } case ASTReader::OutOfDate: case ASTReader::Missing: { + if (HSOpts.ModulesUsePrebuiltModules) { + // We can't rebuild the module without a module map. Throw diagnostics + // here if using prebuilt modules. + getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) + << ModuleName + << SourceRange(ImportLoc, ModuleNameLoc); + ModuleBuildFailed = true; + return ModuleLoadResult(); + } + // The module file is missing or out-of-date. Build it. assert(Module && "missing module file"); // Check whether there is a cycle in the module graph. Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -1367,6 +1367,8 @@ Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); Opts.ModulesValidateDiagnosticOptions = !Args.hasArg(OPT_fmodules_disable_diagnostic_validation); + Opts.ModulesUsePrebuiltModules = + Args.hasArg(OPT_fmodules_use_prebuilt_modules); Opts.ImplicitModuleMaps = Args.hasArg(OPT_fimplicit_module_maps); Opts.ModuleMapFileHomeIsCwd = Args.hasArg(OPT_fmodule_map_file_home_is_cwd); Opts.ModuleCachePruneInterval = Index: lib/Serialization/ASTReader.cpp =================================================================== --- lib/Serialization/ASTReader.cpp +++ lib/Serialization/ASTReader.cpp @@ -492,6 +492,11 @@ } } +static bool isPrebuiltModule(Preprocessor &PP, ModuleKind MK) { + return (MK == MK_ExplicitModule || MK == MK_ImplicitModule) && + PP.getHeaderSearchInfo().getHeaderSearchOpts().ModulesUsePrebuiltModules; +} + /// \brief Check the preprocessor options deserialized from the control block /// against the preprocessor options in an existing preprocessor. /// @@ -2194,7 +2199,8 @@ // All user input files reside at the index range [0, NumUserInputs), and // system input files reside at [NumUserInputs, NumInputs). For explicitly // loaded module files, ignore missing inputs. - if (!DisableValidation && F.Kind != MK_ExplicitModule) { + if (!DisableValidation && F.Kind != MK_ExplicitModule && + !isPrebuiltModule(PP, F.Kind)) { bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; // If we are reading a module, we will create a verification timestamp, @@ -2225,7 +2231,8 @@ bool IsSystem = I >= NumUserInputs; InputFileInfo FI = readInputFileInfo(F, I+1); Listener->visitInputFile(FI.Filename, IsSystem, FI.Overridden, - F.Kind == MK_ExplicitModule); + F.Kind == MK_ExplicitModule || + isPrebuiltModule(PP, F.Kind)); } } @@ -2255,7 +2262,7 @@ // // FIXME: Allow this for files explicitly specified with -include-pch. bool AllowCompatibleConfigurationMismatch = - F.Kind == MK_ExplicitModule; + F.Kind == MK_ExplicitModule || isPrebuiltModule(PP, F.Kind); const HeaderSearchOptions &HSOpts = PP.getHeaderSearchInfo().getHeaderSearchOpts(); @@ -2269,7 +2276,8 @@ } if (DisableValidation || - (AllowConfigurationMismatch && Result == ConfigurationMismatch)) + ((AllowConfigurationMismatch || isPrebuiltModule(PP, F.Kind)) && + Result == ConfigurationMismatch)) Result = Success; // If we can't load the module, exit early since we likely @@ -2417,7 +2425,8 @@ if (M && M->Directory) { // If we're implicitly loading a module, the base directory can't // change between the build and use. - if (F.Kind != MK_ExplicitModule) { + if (F.Kind != MK_ExplicitModule && + !isPrebuiltModule(PP, F.Kind)) { const DirectoryEntry *BuildDir = PP.getFileManager().getDirectory(Blob); if (!BuildDir || BuildDir != M->Directory) { @@ -3225,7 +3234,7 @@ unsigned Idx = 0; F.ModuleMapPath = ReadPath(F, Record, Idx); - if (F.Kind == MK_ExplicitModule) { + if (F.Kind == MK_ExplicitModule || isPrebuiltModule(PP, F.Kind)) { // For an explicitly-loaded module, we don't care whether the original // module map file exists or matches. return Success; Index: test/Driver/modules.m =================================================================== --- test/Driver/modules.m +++ test/Driver/modules.m @@ -39,6 +39,16 @@ // RUN: %clang -fmodules-disable-diagnostic-validation -### %s 2>&1 | FileCheck -check-prefix=MODULES_DISABLE_DIAGNOSTIC_VALIDATION %s // MODULES_DISABLE_DIAGNOSTIC_VALIDATION: -fmodules-disable-diagnostic-validation +// RUN: %clang -fmodules -### %s 2>&1 | FileCheck -check-prefix=MODULES_USE_PREBUILT_MODULES_DEFAULT %s +// MODULES_USE_PREBUILT_MODULES_DEFAULT-NOT: -fmodules-use-prebuilt-modules + +// RUN: %clang -fmodules -fmodules-use-prebuilt-modules -### %s 2>&1 | FileCheck -check-prefix=MODULES_USE_PREBUILT_MODULES %s +// MODULES_USE_PREBUILT_MODULES: "-fdisable-module-hash" +// MODULES_USE_PREBUILT_MODULES: "-fmodules-use-prebuilt-modules" + +// RUN: %clang -fmodules -fmodules-use-prebuilt-modules -fimplicit-module-maps -### %s 2>&1 | FileCheck -check-prefix=MODULES_USE_PREBUILT_MODULES_ERR %s +// MODULES_USE_PREBUILT_MODULES_ERR: option '-fmodules-use-prebuilt-modules' conflicts with '-fimplicit-module-maps' + // RUN: %clang -fmodules -fmodule-map-file=foo.map -fmodule-map-file=bar.map -### %s 2>&1 | FileCheck -check-prefix=CHECK-MODULE-MAP-FILES %s // CHECK-MODULE-MAP-FILES: "-fmodules" // CHECK-MODULE-MAP-FILES: "-fmodule-map-file=foo.map" Index: test/Modules/Inputs/prebuilt-module/a.h =================================================================== --- test/Modules/Inputs/prebuilt-module/a.h +++ test/Modules/Inputs/prebuilt-module/a.h @@ -0,0 +1 @@ +const int a = 1; Index: test/Modules/Inputs/prebuilt-module/module.modulemap =================================================================== --- test/Modules/Inputs/prebuilt-module/module.modulemap +++ test/Modules/Inputs/prebuilt-module/module.modulemap @@ -0,0 +1 @@ +module prebuilt { header "a.h" } Index: test/Modules/prebuilt-module.m =================================================================== --- test/Modules/prebuilt-module.m +++ test/Modules/prebuilt-module.m @@ -0,0 +1,10 @@ +// RUN: rm -rf %t +// +// RUN: %clang_cc1 -fmodules -x objective-c -I %S/Inputs/prebuilt-module -triple %itanium_abi_triple -emit-module %S/Inputs/prebuilt-module/module.modulemap -fmodule-name=prebuilt -o %t/prebuilt.pcm +// RUN: %clang_cc1 -fmodules -fmodules-use-prebuilt-modules -fdisable-module-hash -fmodules-cache-path=%t/ %s -verify + +// expected-no-diagnostics +@import prebuilt; +int test() { + return a; +}