[cfe-dev] Loading of named modules during preprocessing in c++2a

Boris Kolpackov via cfe-dev cfe-dev at lists.llvm.org
Thu Oct 17 03:16:40 PDT 2019


In build2 we scan a preprocessed TU in order to discover named modules
that are needed to compile said TU. Clang, however, tries to load named
modules during preprocessing, because, I believe, Clang's module map-
based modules can also be named and such modules can export macros. This
poses a problem for build systems that are only attempting to support
C++20 modules.

Prior to Clang 9 we hacked around this by simply not enabling (i.e., not
passing -fmodules-ts) modules during preprocessing. However, starting
with Clang 9, modules are enabled by default in the c++2a mode[1] and
there doesn't seem to be a way to disable them. Plus, disabling them is
really a hack rather than a solution: for example, it will fall apart
once we try to support header units (e.g., via the module mapper).

I would therefore like to propose a "strict" C++20 modules mode either
as a default or as an opt-in. Another approach (suggested by Richard
in private communication) is to try to load such a module but to not
fail if it doesn't exist. I see two issues with this approach:

1. It would be hard to distinguish intentional and unintentional
   "absence" of a BMI.

2. More importantly, the BMI might exist but be out of date.

On the other hand, the strict mode sounds like a fairly simple solution
(but I am happy to explore Richard's suggestion if this is preferred).

I've done a quick survey of the modules-related options and modes in
Clang. Options:

  -f[no-]modules      # Enable/Disable Clang modules.
  -f[no-]cxx-modules  # Enable/Disable Clang modules in C++ TUs.
  -fmodules-ts        # Enable Modules TS.
  -std=c++2a          # Enables C++20 modules.

LangOpts:

  CPlusPlusModules
  ModulesTS
  Modules

The current mapping of the options to LangOpts is best captured by this
fragment from lib/Frontend/CompilerInvocation.cpp[2]:

  Opts.CPlusPlusModules = Opts.CPlusPlus2a;
  Opts.ModulesTS = Args.hasArg(OPT_fmodules_ts);
  Opts.Modules =
    Args.hasArg(OPT_fmodules) || Opts.ModulesTS || Opts.CPlusPlusModules;

To support strict C++20 modules at the LangOpts level, it seems natural
to introduce ClangModules (there is already a precedent in
lib/Driver/ToolChains/Clang.cpp:RenderModuleOptions()[3]) with the
following basic semantics:

  Opts.ClangModules = Args.hasArg(OPT_fmodules);
  Opts.Modules = Opts.ClangModules || Opts.ModulesTS || Opts.CPlusPlusModules;

At the options level, the approach depends on whether we want the default
to be strict or if we want to make it opt-in. If it's strict by default,
then using -fmodules in addition to -std=c++2a seems like a natural way to
additionally request the Clang modules semantics. If we want it as opt-in,
then -fno-modules again in combination with -std=c++2a seems natural (in
fact, I was surprised that neither -fno-modules nor -fno-cxx-modules had
any effect when -std=c++2a was specified).

To me personally, strict by default seems cleaner (the Clang modules
semantics would have been more appropriate for something like
-std=clang++2a). But I am also ok with opt-in.

What do you thinks? If this sounds sensible, I can come up with a patch.

[1] https://github.com/llvm-mirror/clang/commit/cab7f1f7bc141ac88d15030088b311bd450b2c94
[2] https://github.com/llvm-mirror/clang/blob/master/lib/Frontend/CompilerInvocation.cpp#L2754
[3] https://github.com/llvm-mirror/clang/blob/master/lib/Driver/ToolChains/Clang.cpp#L2698



More information about the cfe-dev mailing list