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' needs to be compiled, but implicit module compilation was " + "disabled">, DefaultFatal; def err_module_lock_failure : Error< "could not acquire lock file for module '%0'">, DefaultFatal; def err_module_cycle : Error<"cyclic dependency in module '%0': %1">, Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def +++ include/clang/Basic/LangOptions.def @@ -127,6 +127,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__)") @@ -228,4 +229,3 @@ #undef COMPATIBLE_ENUM_LANGOPT #undef BENIGN_ENUM_LANGOPT #undef VALUE_LANGOPT - Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -681,6 +681,12 @@ def fno_modules_implicit_maps : Flag <["-"], "fno-modules-implicit-maps">, Group, Flags<[DriverOption, CC1Option]>; +def fimplicit_modules : + Flag <["-"], "fimplicit-modules">, + 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; Index: lib/Frontend/CompilerInstance.cpp =================================================================== --- lib/Frontend/CompilerInstance.cpp +++ lib/Frontend/CompilerInstance.cpp @@ -1373,6 +1373,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 @@ -1476,6 +1476,8 @@ 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.hasFlag(OPT_fimplicit_modules, OPT_fno_implicit_modules, true); 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/a.modulemap =================================================================== --- /dev/null +++ test/Modules/Inputs/no-implicit-builds/a.modulemap @@ -0,0 +1,4 @@ +module "a" { + use "b" +} +extern module "b" "b.modulemap" \ No newline at end of file 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,34 @@ +// 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 -fmodule-name=a \ +// RUN: -fmodule-map-file=%S/Inputs/no-implicit-builds/a.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 -fmodule-name=a \ +// RUN: -fmodule-map-file=%S/Inputs/no-implicit-builds/a.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 -fmodule-name=a \ +// RUN: -fmodule-map-file=%S/Inputs/no-implicit-builds/a.modulemap \ +// RUN: -fno-implicit-modules %s -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 -Rmodule-build \ +// RUN: -fno-implicit-modules 2>&1 | FileCheck --check-prefix=CHECK-BUILD --allow-empty %s +// CHECK-BUILD-NOT: {{building module 'b'}} +// +// - Next, verify that we can load it: +// RUN: %clang_cc1 -x c++ -std=c++11 -fmodules -fmodule-name=a -fmodule-file=%t/b.pcm \ +// RUN: -fmodule-map-file=%S/Inputs/no-implicit-builds/a.modulemap \ +// RUN: -fno-implicit-modules %s + +#include "Inputs/no-implicit-builds/b.h" // expected-error {{needs to be compiled}}