[clang] d7354fb - Keep multiple-include optimization for null directives

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 27 10:44:20 PDT 2023


Author: Elliot Goodrich
Date: 2023-04-27T13:44:11-04:00
New Revision: d7354fb63471a7a38993280c8264fd8d57432dc7

URL: https://github.com/llvm/llvm-project/commit/d7354fb63471a7a38993280c8264fd8d57432dc7
DIFF: https://github.com/llvm/llvm-project/commit/d7354fb63471a7a38993280c8264fd8d57432dc7.diff

LOG: Keep multiple-include optimization for null directives

The multiple-include optimization allows Clang to avoid opening a
files when they contain #pragma once or a proper include guard.

Both GCC and Microsoft Visual Studio allow null directives outside of
the #ifndef/#endif pair without disabling this multiple-include
optimization. GCC documents this behavior here
https://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html.

> There must be no directives outside the controlling directive pair,
> but the null directive (a line containing nothing other than a
> single '#' and possibly whitespace) is permitted.

However, Clang disables the multiple-include optimization when
encountering the null directive.

In particular, this slows down preprocessing of most projects that
depend on boost as many boost libraries depend on the boost
preprocessor library, which contains null directives outside the
include guard on every header file.

Differential Revision: https://reviews.llvm.org/D147928

Added: 
    clang/test/Preprocessor/multiple-inclusion-opt.cpp
    clang/test/Preprocessor/multiple-inclusion-opt.h

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Lex/MultipleIncludeOpt.h
    clang/lib/Lex/PPDirectives.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 85eb445a87392..71b197a2ad297 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -157,6 +157,8 @@ Non-comprehensive list of changes in this release
 - A new builtin type trait ``__is_trivially_equaltiy_comparable`` has been added,
   which checks whether comparing two instances of a type is equivalent to
   ``memcmp(&lhs, &rhs, sizeof(T)) == 0``.
+- Clang now ignores null directives outside of the include guard when deciding
+  whether a file can be enabled for the multiple-include optimization.
 
 New Compiler Flags
 ------------------

diff  --git a/clang/include/clang/Lex/MultipleIncludeOpt.h b/clang/include/clang/Lex/MultipleIncludeOpt.h
index 7ceb7e53c75d7..8e570226c4b27 100644
--- a/clang/include/clang/Lex/MultipleIncludeOpt.h
+++ b/clang/include/clang/Lex/MultipleIncludeOpt.h
@@ -108,6 +108,12 @@ class MultipleIncludeOpt {
     ImmediatelyAfterTopLevelIfndef = false;
   }
 
+  /// SetReadToken - Set whether the value of 'ReadAnyTokens'.  Called to
+  /// override when encountering tokens outside of the include guard that have
+  /// no effect if the file in question is is included multiple times (e.g. the
+  /// null directive).
+  void SetReadToken(bool Value) { ReadAnyTokens = Value; }
+
   /// ExpandedMacro - When a macro is expanded with this lexer as the current
   /// buffer, this method is called to disable the MIOpt if needed.
   void ExpandedMacro() { DidMacroExpansion = true; }

diff  --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp
index 3132d57a62d3f..7e4ba9851446a 100644
--- a/clang/lib/Lex/PPDirectives.cpp
+++ b/clang/lib/Lex/PPDirectives.cpp
@@ -1177,6 +1177,10 @@ void Preprocessor::HandleDirective(Token &Result) {
 
   switch (Result.getKind()) {
   case tok::eod:
+    // Ignore the null directive with regards to the multiple-include
+    // optimization, i.e. allow the null directive to appear outside of the
+    // include guard and still enable the multiple-include optimization.
+    CurPPLexer->MIOpt.SetReadToken(ReadAnyTokensBeforeDirective);
     return;   // null directive.
   case tok::code_completion:
     setCodeCompletionReached();

diff  --git a/clang/test/Preprocessor/multiple-inclusion-opt.cpp b/clang/test/Preprocessor/multiple-inclusion-opt.cpp
new file mode 100644
index 0000000000000..0da20331fada6
--- /dev/null
+++ b/clang/test/Preprocessor/multiple-inclusion-opt.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 -E -P -H %s 2>&1 | grep "multiple-inclusion-opt.h" | count 1
+
+#include "multiple-inclusion-opt.h"
+#include "multiple-inclusion-opt.h"
+#include "multiple-inclusion-opt.h"
+#include "multiple-inclusion-opt.h"
+#include "multiple-inclusion-opt.h"

diff  --git a/clang/test/Preprocessor/multiple-inclusion-opt.h b/clang/test/Preprocessor/multiple-inclusion-opt.h
new file mode 100644
index 0000000000000..d346c9d5d22e4
--- /dev/null
+++ b/clang/test/Preprocessor/multiple-inclusion-opt.h
@@ -0,0 +1,18 @@
+# // null directive and comments before include guard
+
+#ifndef MULTIPLE_INCLUSION_OPT
+
+int foo();
+
+// The position of the define should not matter
+#define MULTIPLE_INCLUSION_OPT
+
+int bar();
+
+#endif
+
+#
+#
+/* Two null directives
+   and a multiline comment
+   after the #endif */


        


More information about the cfe-commits mailing list