From 65165eb3f833a3f0415fd76913bf85722a13fbe0 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Wed, 3 Feb 2021 11:37:35 -0800 Subject: Add -f[no-]header-guard-opt Added so that one can determine the include graph from the -E output. --- gcc/c-family/c-opts.c | 4 +++ gcc/c-family/c.opt | 4 +++ gcc/cp/module.cc | 32 ++++++++++++++---------- gcc/doc/cppopts.texi | 14 +++++++++++ gcc/testsuite/c-c++-common/cpp/headerguard.c | 8 ++++++ gcc/testsuite/c-c++-common/cpp/noheaderguard-a.h | 3 +++ gcc/testsuite/c-c++-common/cpp/noheaderguard-b.h | 4 +++ gcc/testsuite/c-c++-common/cpp/noheaderguard.c | 9 +++++++ gcc/testsuite/g++.dg/modules/noheaderguard-1_a.H | 5 ++++ gcc/testsuite/g++.dg/modules/noheaderguard-1_b.C | 7 ++++++ gcc/testsuite/g++.dg/modules/noheaderguard-1_c.C | 7 ++++++ libcpp/files.c | 25 +++++++++++++----- libcpp/include/cpplib.h | 3 +++ 13 files changed, 106 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/cpp/headerguard.c create mode 100644 gcc/testsuite/c-c++-common/cpp/noheaderguard-a.h create mode 100644 gcc/testsuite/c-c++-common/cpp/noheaderguard-b.h create mode 100644 gcc/testsuite/c-c++-common/cpp/noheaderguard.c create mode 100644 gcc/testsuite/g++.dg/modules/noheaderguard-1_a.H create mode 100644 gcc/testsuite/g++.dg/modules/noheaderguard-1_b.C create mode 100644 gcc/testsuite/g++.dg/modules/noheaderguard-1_c.C diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index bd15b9cd902..240d3b8839e 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -477,6 +477,10 @@ c_common_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, cpp_opts->extended_identifiers = value; break; + case OPT_fheader_guard_opt: + cpp_opts->no_header_guard_opt = !value; + break; + case OPT_fmax_include_depth_: cpp_opts->max_include_depth = value; break; diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index b209d46d32b..7c155b01cc6 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1660,6 +1660,10 @@ C++ ObjC++ WarnRemoved fhandle-exceptions C++ ObjC++ Optimization Alias(fexceptions) Warn({%<-fhandle-exceptions%> has been renamed %<-fexceptions%> (and is now on by default)}) +fheader-guard-opt +C ObjC C++ ObjC++ +Enable header file include guard optimization. + fhonor-std C++ ObjC++ WarnRemoved diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc index 41ce2011525..213d9f699b8 100644 --- a/gcc/cp/module.cc +++ b/gcc/cp/module.cc @@ -19144,22 +19144,28 @@ maybe_translate_include (cpp_reader *reader, line_maps *lmaps, location_t loc, size_t len = strlen (path); path = canonicalize_header_name (NULL, loc, true, path, len); - auto packet = mapper->IncludeTranslate (path, Cody::Flags::None, len); int xlate = false; - if (packet.GetCode () == Cody::Client::PC_BOOL) - xlate = -int (packet.GetInteger ()); - else if (packet.GetCode () == Cody::Client::PC_PATHNAME) - { - /* Record the CMI name for when we do the import. */ - module_state *import = get_module (build_string (len, path)); - import->set_filename (packet); - xlate = +1; - } + auto name_str = build_string (len, path); + if (get_module_slot (name_str, nullptr, false, false)) + /* We've already met this header. */ + xlate = +1; else { - gcc_checking_assert (packet.GetCode () == Cody::Client::PC_ERROR); - error_at (loc, "cannot determine %<#include%> translation of %s: %s", - path, packet.GetString ().c_str ()); + auto packet = mapper->IncludeTranslate (path, Cody::Flags::None, len); + if (packet.GetCode () == Cody::Client::PC_BOOL) + xlate = -int (packet.GetInteger ()); + else if (packet.GetCode () == Cody::Client::PC_PATHNAME) + { + /* Record the CMI name for when we do the import. */ + get_module (name_str)->set_filename (packet); + xlate = +1; + } + else + { + gcc_checking_assert (packet.GetCode () == Cody::Client::PC_ERROR); + error_at (loc, "cannot determine %<#include%> translation of %s: %s", + path, packet.GetString ().c_str ()); + } } bool note = false; diff --git a/gcc/doc/cppopts.texi b/gcc/doc/cppopts.texi index b941de6df1b..a3bad58f6ab 100644 --- a/gcc/doc/cppopts.texi +++ b/gcc/doc/cppopts.texi @@ -266,6 +266,20 @@ standard versions) and C++. @opindex fno-canonical-system-headers When preprocessing, do not shorten system header paths with canonicalization. +@item -fno-header-guard-opt +@opindex fno-header-guard-opt +This disables the preprocessor's optimization of header files that +have a macro header-guard. Usually such files are do not appear at +all in the preprocessed output on their second and subsequent +inclusion. This disables that optimization such that they will appear +in the @code{#} line directive output, but of course their contents +will be elided by the controlling @code{#if} directive. This also +covers C++ 20 include-translated header-unit imports, those will be +subject to multiple include translations. This option is useful to +discover the complete #include graph of a translation unit. It does +not apply to idempotent headerfiles marked with @code{#pragma once}, +nor to headers read with @code{#import}. + @item -fmax-include-depth=@var{depth} @opindex fmax-include-depth Set the maximum depth of the nested #include. The default is 200. diff --git a/gcc/testsuite/c-c++-common/cpp/headerguard.c b/gcc/testsuite/c-c++-common/cpp/headerguard.c new file mode 100644 index 00000000000..be63849d33c --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/headerguard.c @@ -0,0 +1,8 @@ +/* { dg-do preprocess } */ +/* Check header guards are optimized. */ + +#include "noheaderguard-b.h" +#include "noheaderguard-b.h" +#include "noheaderguard-a.h" + +/* { dg-final { scan-file headerguard.i {# [0-9]* "[^\n]*headerguard.c"\n\n*# [0-9]* "[^\n]*headerguard-b.h" 1\n\n*# [0-9]* "[^\n]*headerguard-a.h" 1\n\n*# [0-9]* "[^\n]*headerguard-b.h" 2\n\n*# [0-9]* "[^\n]*headerguard.c" 2\n} } } */ diff --git a/gcc/testsuite/c-c++-common/cpp/noheaderguard-a.h b/gcc/testsuite/c-c++-common/cpp/noheaderguard-a.h new file mode 100644 index 00000000000..6a6c2b49e8f --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/noheaderguard-a.h @@ -0,0 +1,3 @@ +#ifndef INNER +#define INNER +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/noheaderguard-b.h b/gcc/testsuite/c-c++-common/cpp/noheaderguard-b.h new file mode 100644 index 00000000000..8b72a9fbb7a --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/noheaderguard-b.h @@ -0,0 +1,4 @@ +#ifndef OUTER +#define OUTER +#include "noheaderguard-a.h" +#endif diff --git a/gcc/testsuite/c-c++-common/cpp/noheaderguard.c b/gcc/testsuite/c-c++-common/cpp/noheaderguard.c new file mode 100644 index 00000000000..3e6fd876f1b --- /dev/null +++ b/gcc/testsuite/c-c++-common/cpp/noheaderguard.c @@ -0,0 +1,9 @@ +/* { dg-do preprocess } */ +/* { dg-additional-options -fno-header-guard-opt } */ +/* Check header guard optimization is disabled. */ + +#include "noheaderguard-b.h" +#include "noheaderguard-b.h" +#include "noheaderguard-a.h" + +/* { dg-final { scan-file noheaderguard.i {# [0-9]* "[^\n]*noheaderguard.c"\n\n*# [0-9]* "[^\n]*noheaderguard-b.h" 1\n\n*# [0-9]* "[^\n]*noheaderguard-a.h" 1\n\n*# [0-9]* "[^\n]*noheaderguard-b.h" 2\n\n*# [0-9]* "[^\n]*noheaderguard.c" 2\n\n*# [0-9]* "[^\n]*noheaderguard-b.h" 1\n\n*# [0-9]* "[^\n]*noheaderguard.c" 2\n\n*# [0-9]* "[^\n]*noheaderguard-a.h" 1\n\n*# [0-9]* "[^\n]*noheaderguard.c" 2\n} } } */ diff --git a/gcc/testsuite/g++.dg/modules/noheaderguard-1_a.H b/gcc/testsuite/g++.dg/modules/noheaderguard-1_a.H new file mode 100644 index 00000000000..6d552bf9cc9 --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/noheaderguard-1_a.H @@ -0,0 +1,5 @@ +// { dg-additional-options -fmodule-header } + +#ifndef OUTER +#define OUTER +#endif diff --git a/gcc/testsuite/g++.dg/modules/noheaderguard-1_b.C b/gcc/testsuite/g++.dg/modules/noheaderguard-1_b.C new file mode 100644 index 00000000000..d5de8b2362f --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/noheaderguard-1_b.C @@ -0,0 +1,7 @@ +// { dg-do preprocess } +// { dg-additional-options {-fmodules-ts -fno-header-guard-opt} } + +#include "noheaderguard-1_a.H" +#include "noheaderguard-1_a.H" + +// { dg-final { scan-file noheaderguard-1_b.i {# [0-9]* "[^\n]*noheaderguard-1_b.C"\n\n*import "[^\n]*noheaderguard-1_a.H" \[\[__translated\]\];\nimport "[^\n]*noheaderguard-1_a.H" \[\[__translated\]\];\n} } } diff --git a/gcc/testsuite/g++.dg/modules/noheaderguard-1_c.C b/gcc/testsuite/g++.dg/modules/noheaderguard-1_c.C new file mode 100644 index 00000000000..b4f0442769e --- /dev/null +++ b/gcc/testsuite/g++.dg/modules/noheaderguard-1_c.C @@ -0,0 +1,7 @@ +// { dg-do preprocess } +// { dg-additional-options {-fmodules-ts -fno-header-guard-opt} } + +import "noheaderguard-1_a.H"; +#include "noheaderguard-1_a.H" + +// { dg-final { scan-file noheaderguard-1_c.i {# [0-9]* "[^\n]*noheaderguard-1_c.C"\n\n*import "[^\n]*noheaderguard-1_a.H";\nimport "[^\n]*noheaderguard-1_a.H" \[\[__translated\]\];\n} } } diff --git a/libcpp/files.c b/libcpp/files.c index 5ea3f8e1bf3..44c51fad729 100644 --- a/libcpp/files.c +++ b/libcpp/files.c @@ -803,7 +803,9 @@ is_known_idempotent_file (cpp_reader *pfile, _cpp_file *file, bool import) /* Skip if the file had a header guard and the macro is defined. PCH relies on this appearing before the PCH handler below. */ - if (file->cmacro && cpp_macro_p (file->cmacro)) + if (file->cmacro && cpp_macro_p (file->cmacro) + /* Ignore if the idempotency optimization is disabled. */ + && (file->pchname || !CPP_OPTION (pfile, no_header_guard_opt))) return true; /* Handle PCH files immediately; don't stack them. */ @@ -819,6 +821,18 @@ is_known_idempotent_file (cpp_reader *pfile, _cpp_file *file, bool import) return false; } +/* Mark FILE as a header_unit, if we're spotting idempotency. */ + +static void +maybe_mark_header_unit (cpp_reader *pfile, _cpp_file *file) +{ + if (!CPP_OPTION (pfile, no_header_guard_opt)) + { + file->header_unit = +1; + _cpp_mark_file_once_only (pfile, file); + } +} + /* Return TRUE if file has unique contents, so we should read process it. The file's contents must already have been read. */ @@ -927,8 +941,7 @@ _cpp_stack_file (cpp_reader *pfile, _cpp_file *file, include_type type, strlen (buf), true); buffer->to_free = buffer->buf; - file->header_unit = +1; - _cpp_mark_file_once_only (pfile, file); + maybe_mark_header_unit (pfile, file); } else { @@ -983,7 +996,7 @@ _cpp_stack_file (cpp_reader *pfile, _cpp_file *file, include_type type, if (decrement) pfile->line_table->highest_location--; - if (file->header_unit <= 0) + if (!buf) /* Add line map and do callbacks. */ _cpp_do_file_change (pfile, LC_ENTER, file->path, /* With preamble injection, start on line zero, @@ -1126,8 +1139,8 @@ cpp_find_header_unit (cpp_reader *pfile, const char *name, bool angle, file->fd = 0; } - file->header_unit = +1; - _cpp_mark_file_once_only (pfile, file); + maybe_mark_header_unit (pfile, file); + return file->path; } diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 4467c73284d..2b089a18c26 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -528,6 +528,9 @@ struct cpp_options /* True if warn about differences between C++98 and C++11. */ bool cpp_warn_cxx11_compat; + /* True if header file idempotency should not be optimized. */ + bool no_header_guard_opt; + /* Dependency generation. */ struct { -- cgit v1.2.1