Index: docs/Modules.rst =================================================================== --- docs/Modules.rst +++ docs/Modules.rst @@ -210,6 +210,12 @@ ``-fno-modules-implicit-maps`` Suppresses the implicit search for files called ``module.modulemap`` and similar. Instead, module files need to be explicitly specified via ``-fmodule-map-file`` or transitively used. +``-fno-implicit-modules`` + All modules used by the build must be specified with ``-fmodule-file``. + +``-fmodule-file=`` + Load the given precompiled module file. + Module Semantics ================ Index: include/clang/Basic/DiagnosticCommonKinds.td =================================================================== --- include/clang/Basic/DiagnosticCommonKinds.td +++ include/clang/Basic/DiagnosticCommonKinds.td @@ -81,6 +81,9 @@ "only functions can have deleted definitions">; def err_module_not_found : Error<"module '%0' not found">, DefaultFatal; def err_module_not_built : Error<"could not build module '%0'">, DefaultFatal; +def err_module_build_disabled: Error< + "module '%0' is needed but has not been provided, and implicit use of module " + "files is disabled">, DefaultFatal; def err_module_lock_failure : Error< "could not acquire lock file for module '%0'">, DefaultFatal; def err_module_lock_timeout : Error< Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -128,6 +128,7 @@ LANGOPT(ModulesStrictDeclUse, 1, 0, "require declaration of module uses and all headers to be in modules") LANGOPT(ModulesErrorRecovery, 1, 1, "automatically import modules as needed when performing error recovery") BENIGN_LANGOPT(ModulesImplicitMaps, 1, 1, "use files called module.modulemap implicitly as module maps") +BENIGN_LANGOPT(ImplicitModules, 1, 1, "build modules that are not specified via -fmodule-file") COMPATIBLE_LANGOPT(Optimize , 1, 0, "__OPTIMIZE__ predefined macro") COMPATIBLE_LANGOPT(OptimizeSize , 1, 0, "__OPTIMIZE_SIZE__ predefined macro") LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)") Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -703,6 +703,9 @@ def fno_modules_implicit_maps : Flag <["-"], "fno-modules-implicit-maps">, Group, Flags<[DriverOption, CC1Option]>; +def fno_implicit_modules : + Flag <["-"], "fno-implicit-modules">, + Group, Flags<[DriverOption, CC1Option]>; def fretain_comments_from_system_headers : Flag<["-"], "fretain-comments-from-system-headers">, Group, Flags<[CC1Option]>; def fmudflapth : Flag<["-"], "fmudflapth">, Group; @@ -763,6 +766,8 @@ Flags<[DriverOption]>; def fno_modules_strict_decluse : Flag <["-"], "fno-strict-modules-decluse">, Group, Flags<[DriverOption]>; +def fimplicit_modules : Flag <["-"], "fimplicit-modules">, Group, + Flags<[DriverOption]>; def fno_ms_extensions : Flag<["-"], "fno-ms-extensions">, Group; def fno_ms_compatibility : Flag<["-"], "fno-ms-compatibility">, Group; def fno_delayed_template_parsing : Flag<["-"], "fno-delayed-template-parsing">, Group; Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -3925,6 +3925,12 @@ CmdArgs.push_back("-fmodules-strict-decluse"); } + // -fno-implicit-modules turns off implicitly compiling modules on demand. + if (!Args.hasFlag(options::OPT_fimplicit_modules, + options::OPT_fno_implicit_modules)) { + CmdArgs.push_back("-fno-implicit-modules"); + } + // -fmodule-name specifies the module that is currently being built (or // used for header checking by -fmodule-maps). Args.AddLastArg(CmdArgs, options::OPT_fmodule_name); Index: lib/Frontend/CompilerInstance.cpp =================================================================== --- lib/Frontend/CompilerInstance.cpp +++ lib/Frontend/CompilerInstance.cpp @@ -1374,6 +1374,12 @@ auto Override = ModuleFileOverrides.find(ModuleName); bool Explicit = Override != ModuleFileOverrides.end(); + if (!Explicit && !getLangOpts().ImplicitModules) { + getDiagnostics().Report(ModuleNameLoc, diag::err_module_build_disabled) + << ModuleName; + ModuleBuildFailed = true; + return ModuleLoadResult(); + } std::string ModuleFileName = Explicit ? Override->second Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -1513,6 +1513,7 @@ Opts.ModulesErrorRecovery = !Args.hasArg(OPT_fno_modules_error_recovery); Opts.ModulesImplicitMaps = Args.hasFlag(OPT_fmodules_implicit_maps, OPT_fno_modules_implicit_maps, true); + Opts.ImplicitModules = !Args.hasArg(OPT_fno_implicit_modules); Opts.CharIsSigned = Opts.OpenCL || !Args.hasArg(OPT_fno_signed_char); Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar); Opts.ShortWChar = Args.hasFlag(OPT_fshort_wchar, OPT_fno_short_wchar, false); Index: test/Modules/Inputs/no-implicit-builds/b.h =================================================================== --- /dev/null +++ test/Modules/Inputs/no-implicit-builds/b.h @@ -0,0 +1,6 @@ +#ifndef B_H +#define B_H + +int b; + +#endif Index: test/Modules/Inputs/no-implicit-builds/b.modulemap =================================================================== --- /dev/null +++ test/Modules/Inputs/no-implicit-builds/b.modulemap @@ -0,0 +1,3 @@ +module "b" { + header "b.h" +} Index: test/Modules/no-implicit-builds.cpp =================================================================== --- /dev/null +++ test/Modules/no-implicit-builds.cpp @@ -0,0 +1,33 @@ +// RUN: rm -rf %t + +// Produce an error if a module is needed, but not found. +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t \ +// RUN: -fmodule-map-file=%S/Inputs/no-implicit-builds/b.modulemap \ +// RUN: -fno-implicit-modules %s -verify + +// Compile the module and put it into the cache. +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t \ +// RUN: -fmodule-map-file=%S/Inputs/no-implicit-builds/b.modulemap \ +// RUN: %s -Rmodule-build 2>&1 | FileCheck --check-prefix=CHECK-CACHE-BUILD %s +// CHECK-CACHE-BUILD: {{building module 'b'}} + +// Produce an error if a module is found in the cache but implicit modules is off. +// Note that the command line must match the command line for the first check, otherwise +// this check might not find the module in the cache and trivially succeed. +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodules-cache-path=%t \ +// RUN: -fmodule-map-file=%S/Inputs/no-implicit-builds/b.modulemap \ +// RUN: %s -Rmodule-build -fno-implicit-modules -verify + +// Verify that we can still pass the module via -fmodule-file when implicit modules +// are switched off: +// - First, explicitly compile the module: +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodule-name=b -o %t/b.pcm \ +// RUN: -emit-module %S/Inputs/no-implicit-builds/b.modulemap \ +// RUN: -fno-implicit-modules +// +// - Next, verify that we can load it: +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodule-file=%t/b.pcm \ +// RUN: -fmodule-map-file=%S/Inputs/no-implicit-builds/b.modulemap \ +// RUN: -fno-implicit-modules %s + +#include "Inputs/no-implicit-builds/b.h" // expected-error {{is needed but has not been provided}}