Tested x86_64-pc-linux-gnu. Any other ideas for how to communicate headerness to the front-end?
-- 8< -- C++20 modules support has depended on the driver seeing the -fmodules-ts flag in order to implicitly add other flags. This won't work when we start enabling modules support by default; it's better to leave it up to the front-end to decide what behaviors are implied by modules. But for header units to be generated properly, we still need some way for the driver to communicate to the front-end that we're dealing with a header. We could almost exploit the --output-pch flag for this, but that doesn't help with preprocessed output, including during -save-temps. So this patch adds an internal --header flag for communication between the driver and the front-end. Users are not expected to pass this flag themselves. The patch then removes all -fmodules-ts checks from C++ lang-spec.h in favor of a few lines in c_common_post_options. It also replaces -fmodule-header= with -fsearch-include-path= and adds --header as appropriate. Instead of implying -fdirectives-only when preprocessing a header unit, this patch implies only -dD, which seems like enough to transmit the macro definitions to the eventual header unit CMI. Before this change, legacy-3_b.H got neither -fdirectives-only nor -dD because lang-specs was only checking for -fmodules-ts, not -fmodule-header. After this change it has -dD active, so I needed to add some blank lines as suggested by the comment, and adjust the expected line numbers accordingly. gcc/ChangeLog: * doc/invoke.texi: Update module header preprocessing guidance. gcc/c-family/ChangeLog: * c.opt: Add --header. * c-opts.cc (c_common_post_options): Use it to enable modules header unit mode. gcc/cp/ChangeLog: * lang-specs.h: Use --header and -fsearch-include-path instead of -fmodule-header and checking -fmodules-ts. * module.cc (init_modules): Update PCH comment. (handle_module_option): -fmodule-header implies --header. gcc/testsuite/ChangeLog: * g++.dg/modules/legacy-3_b.H: Adjust for -dD. --- gcc/doc/invoke.texi | 15 ++++---- gcc/c-family/c.opt | 3 ++ gcc/cp/lang-specs.h | 42 ++++++++--------------- gcc/c-family/c-opts.cc | 12 +++++++ gcc/cp/module.cc | 4 +-- gcc/testsuite/g++.dg/modules/legacy-3_b.H | 6 +++- 6 files changed, 46 insertions(+), 36 deletions(-) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index c69d032323e..b27e85bc38a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -38235,14 +38235,17 @@ does not require macro expansion, so it is not necessary to use @option{-MD}. See also @option{-fdeps-*} for an alternate format for module dependency information. -The @option{-save-temps} option uses @option{-fdirectives-only} for -preprocessing, and preserve the macro definitions in the preprocessed -output. Usually you also want to use this option when explicitly -preprocessing a header-unit, or consuming such preprocessed output: +Preprocessing a header with modules enabled implicitly enables +@option{-dD} so that if the preprocessed output is then compiled to +produce a header unit, the macro definitions are included. In that +second compilation you also need to tell the compiler that it's a +preprocessed header; the simplest way to do that is compiling the +@samp{.ii} file (which implies @option{-x c++-cpp-output}) with +@option{-fmodule-header}. @smallexample -g++ -fmodules-ts -E -fdirectives-only my-header.hh -o my-header.ii -g++ -x c++-header -fmodules-ts -fpreprocessed -fdirectives-only my-header.ii +g++ -fmodules-ts -E my-header.hh -o my-header.ii +g++ -c -fmodule-header my-header.ii @end smallexample @node C++ Compiled Module Interface diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 0aada1c3080..6056dbde4b4 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -76,6 +76,9 @@ C ObjC C++ ObjC++ Separate Alias(-embed-dir=) MissingArgError(missing path after -embed-directory= C ObjC C++ ObjC++ Joined Alias(-embed-dir=) MissingArgError(missing path after %qs) +-header +C ObjC C++ ObjC++ Undocumented Var(flag_header) + -imacros C ObjC C++ ObjC++ Separate Alias(imacros) MissingArgError(missing filename after %qs) diff --git a/gcc/cp/lang-specs.h b/gcc/cp/lang-specs.h index e5651567a2d..b6ed85c399c 100644 --- a/gcc/cp/lang-specs.h +++ b/gcc/cp/lang-specs.h @@ -46,63 +46,51 @@ along with GCC; see the file COPYING3. If not see {".c++m", "@c++", 0, 0, 0}, {".ccm", "@c++", 0, 0, 0}, {"@c++-header", - "%{E|M|MM:cc1plus -E %{fmodules-ts:-fdirectives-only -fmodule-header}" + "%{E|M|MM:cc1plus -E --header" " %(cpp_options) %2 %(cpp_debug_options)}" "%{!E:%{!M:%{!MM:" - " %{save-temps*|no-integrated-cpp:cc1plus -E" - " %{fmodules-ts:-fdirectives-only -fmodule-header}" + " %{save-temps*|no-integrated-cpp:cc1plus -E --header" " %(cpp_options) %2 -o %{save-temps*:%b.ii} %{!save-temps*:%g.ii} \n}" " cc1plus %{save-temps*|no-integrated-cpp:-fpreprocessed" - " %{fmodules-ts:-fdirectives-only}" " %{save-temps*:%b.ii} %{!save-temps*:%g.ii}}" " %{!save-temps*:%{!no-integrated-cpp:%(cpp_unique_options)}}" - " %{fmodules-ts:-fmodule-header %{fpreprocessed:-fdirectives-only}}" - " %(cc1_options) %2" + " %(cc1_options) %2 --header" " %{!fsyntax-only:" " %{!S:-o %g.s}" - " %{!fmodule-*:%{!fmodules-*:%{!fdump-ada-spec*:" - " %{!o*:--output-pch %w%i.gch}%W{o*:--output-pch %w%*}}}}%{!S:%V}}" + " %{!fdump-ada-spec*:" + " %{!o*:--output-pch %w%i.gch}%W{o*:--output-pch %w%*}}%{!S:%V}}" "}}}", CPLUSPLUS_CPP_SPEC, 0, 0}, {"@c++-system-header", - "%{E|M|MM:cc1plus -E" - " %{fmodules-ts:-fdirectives-only -fmodule-header=system}" + "%{E|M|MM:cc1plus -E --header -fsearch-include-path=system" " %(cpp_options) %2 %(cpp_debug_options)}" "%{!E:%{!M:%{!MM:" - " %{save-temps*|no-integrated-cpp:cc1plus -E" - " %{fmodules-ts:-fdirectives-only -fmodule-header=system}" + " %{save-temps*|no-integrated-cpp:cc1plus -E --header" " %(cpp_options) %2 -o %{save-temps*:%b.ii} %{!save-temps*:%g.ii} \n}" " cc1plus %{save-temps*|no-integrated-cpp:-fpreprocessed" - " %{fmodules-ts:-fdirectives-only}" " %{save-temps*:%b.ii} %{!save-temps*:%g.ii}}" " %{!save-temps*:%{!no-integrated-cpp:%(cpp_unique_options)}}" - " %{fmodules-ts:-fmodule-header=system" - " %{fpreprocessed:-fdirectives-only}}" - " %(cc1_options) %2" + " %(cc1_options) %2 --header -fsearch-include-path=system" " %{!fsyntax-only:" " %{!S:-o %g.s}" - " %{!fmodule-*:%{!fmodules-*:%{!fdump-ada-spec*:" - " %{!o*:--output-pch %w%i.gch}%W{o*:--output-pch %w%*}}}}%{!S:%V}}" + " %{!fdump-ada-spec*:" + " %{!o*:--output-pch %w%i.gch}%W{o*:--output-pch %w%*}}%{!S:%V}}" "}}}", CPLUSPLUS_CPP_SPEC, 0, 0}, {"@c++-user-header", - "%{E|M|MM:cc1plus -E" - " %{fmodules-ts:-fdirectives-only -fmodule-header=user}" + "%{E|M|MM:cc1plus -E --header -fsearch-include-path=user" " %(cpp_options) %2 %(cpp_debug_options)}" "%{!E:%{!M:%{!MM:" - " %{save-temps*|no-integrated-cpp:cc1plus -E" - " %{fmodules-ts:-fdirectives-only -fmodule-header=user}" + " %{save-temps*|no-integrated-cpp:cc1plus -E --header" " %(cpp_options) %2 -o %{save-temps*:%b.ii} %{!save-temps*:%g.ii} \n}" " cc1plus %{save-temps*|no-integrated-cpp:-fpreprocessed" - " %{fmodules-ts:-fdirectives-only}" " %{save-temps*:%b.ii} %{!save-temps*:%g.ii}}" " %{!save-temps*:%{!no-integrated-cpp:%(cpp_unique_options)}}" - " %{fmodules-ts:-fmodule-header=user %{fpreprocessed:-fdirectives-only}}" - " %(cc1_options) %2" + " %(cc1_options) %2 --header -fsearch-include-path=user" " %{!fsyntax-only:" " %{!S:-o %g.s}" - " %{!fmodule-*:%{!fmodules-*:%{!fdump-ada-spec*:" - " %{!o*:--output-pch %w%i.gch}%W{o*:--output-pch %w%*}}}}%{!S:%V}}" + " %{!fdump-ada-spec*:" + " %{!o*:--output-pch %w%i.gch}%W{o*:--output-pch %w%*}}%{!S:%V}}" "}}}", CPLUSPLUS_CPP_SPEC, 0, 0}, {"@c++", diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index 2798b4d295f..c7115e63ce7 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -1209,6 +1209,18 @@ c_common_post_options (const char **pfilename) error ("too many filenames given; type %<%s %s%> for usage", progname, "--help"); + if (flag_modules && flag_header) + { + flag_header_unit = true; + /* Ignore --output-pch. */ + pch_file = NULL; + + /* Preserve macros so that they go in the header unit when we feed + the preprocessed output back to the compiler. */ + if (flag_preprocess_only) + flag_dump_macros = 'D'; + } + if (flag_preprocess_only) { /* Open the output now. We must do so even if flag_no_output is diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index e58c057a96e..c43aa9dc324 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -20524,8 +20524,7 @@ maybe_add_global (tree val, unsigned &crc) void init_modules (cpp_reader *reader) { - /* PCH should not be reachable because of lang-specs, but the - user could have overriden that. */ + /* We should have cleared this in c_common_post_options. */ if (pch_file) fatal_error (input_location, "C++ modules are incompatible with precompiled headers"); @@ -21030,6 +21029,7 @@ handle_module_option (unsigned code, const char *str, int) case OPT_fmodule_header: flag_header_unit = hdr; + flag_header = 1; flag_modules = 1; return true; diff --git a/gcc/testsuite/g++.dg/modules/legacy-3_b.H b/gcc/testsuite/g++.dg/modules/legacy-3_b.H index 3bf819db661..145bfbbddd1 100644 --- a/gcc/testsuite/g++.dg/modules/legacy-3_b.H +++ b/gcc/testsuite/g++.dg/modules/legacy-3_b.H @@ -5,6 +5,10 @@ // Enough blank lines to force a line sync before the legacy import + + + + // this should be diverted, if it isn't the above #define will break us #include "legacy-3_a.H" int move (int X = __LINE__); // Capture __LINE__ in a non-definition @@ -12,5 +16,5 @@ int move (int X = __LINE__); // Capture __LINE__ in a non-definition // this should not be diverted #include "legacy-3.h" -// { dg-final { scan-file legacy-3_b.i {\n# 9 "[^\n]*legacy-3_b.H"\nimport "[^\n]*legacy-3_a.H" \[\[__translated\]\];\nint move \(int X = 10\);\n} } } +// { dg-final { scan-file legacy-3_b.i {\n# 13 "[^\n]*legacy-3_b.H"\nimport "[^\n]*legacy-3_a.H" \[\[__translated\]\];\nint move \(int X = 14\);\n} } } -- 2.46.2