diff --git a/clang/docs/Modules.rst b/clang/docs/Modules.rst index 1575ce6964c8..1d4c1f46bc55 100644 --- a/clang/docs/Modules.rst +++ b/clang/docs/Modules.rst @@ -210,6 +210,12 @@ Command-line parameters ``-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 ================ diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index 3afe5966b4ef..afdd9269d097 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -81,6 +81,9 @@ def err_deleted_non_function : Error< "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< diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index f5c1a16ca711..48e3c73d1407 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -128,6 +128,7 @@ LANGOPT(ModulesSearchAll , 1, 1, "search even non-imported modules to find unre COMPATIBLE_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__)") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 221f545d0140..c4d3eda0978d 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -705,6 +705,9 @@ def fmodules_implicit_maps : 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; @@ -765,6 +768,8 @@ def fno_modules_decluse : Flag <["-"], "fno-modules-decluse">, Group, 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; diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index fc6773d21c52..b5f20608c147 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/lib/Driver/Tools.cpp @@ -3925,6 +3925,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, 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); diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 5d554b717b33..832aee22063d 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1378,6 +1378,12 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, 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 diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 4c1ac0a148a5..7a53cedc93b3 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1513,6 +1513,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, 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); diff --git a/clang/test/Modules/Inputs/no-implicit-builds/b.h b/clang/test/Modules/Inputs/no-implicit-builds/b.h new file mode 100644 index 000000000000..4fe1c76825cb --- /dev/null +++ b/clang/test/Modules/Inputs/no-implicit-builds/b.h @@ -0,0 +1,6 @@ +#ifndef B_H +#define B_H + +int b; + +#endif diff --git a/clang/test/Modules/Inputs/no-implicit-builds/b.modulemap b/clang/test/Modules/Inputs/no-implicit-builds/b.modulemap new file mode 100644 index 000000000000..3c8ca540010c --- /dev/null +++ b/clang/test/Modules/Inputs/no-implicit-builds/b.modulemap @@ -0,0 +1,3 @@ +module "b" { + header "b.h" +} diff --git a/clang/test/Modules/no-implicit-builds.cpp b/clang/test/Modules/no-implicit-builds.cpp new file mode 100644 index 000000000000..d9e8fa1da1c8 --- /dev/null +++ b/clang/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}}