[PATCH] D147928: [clang] Keep multiple-include optimization for null directives

Elliot Goodrich via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 10 04:15:19 PDT 2023


IncludeGuardian created this revision.
IncludeGuardian added a reviewer: clang.
IncludeGuardian added a project: clang.
Herald added a project: All.
IncludeGuardian requested review of this revision.
Herald added a subscriber: cfe-commits.

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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D147928

Files:
  clang/include/clang/Lex/MultipleIncludeOpt.h
  clang/lib/Lex/PPDirectives.cpp
  clang/test/Preprocessor/multiple-inclusion-opt.cpp
  clang/test/Preprocessor/multiple-inclusion-opt.h


Index: clang/test/Preprocessor/multiple-inclusion-opt.h
===================================================================
--- /dev/null
+++ 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 */
Index: clang/test/Preprocessor/multiple-inclusion-opt.cpp
===================================================================
--- /dev/null
+++ 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"
Index: clang/lib/Lex/PPDirectives.cpp
===================================================================
--- clang/lib/Lex/PPDirectives.cpp
+++ clang/lib/Lex/PPDirectives.cpp
@@ -1177,6 +1177,12 @@
 
   switch (Result.getKind()) {
   case tok::eod:
+    // Allow the null directive to appear outside of the include guard and still
+    // keep multiple-include optimization. So if we haven't recorded any tokens
+    // yet we can reset MIOpt to forget about the null directive.
+    if (!ReadAnyTokensBeforeDirective) {
+      CurPPLexer->MIOpt.ResetReadToken();
+    }
     return;   // null directive.
   case tok::code_completion:
     setCodeCompletionReached();
Index: clang/include/clang/Lex/MultipleIncludeOpt.h
===================================================================
--- clang/include/clang/Lex/MultipleIncludeOpt.h
+++ clang/include/clang/Lex/MultipleIncludeOpt.h
@@ -108,6 +108,12 @@
     ImmediatelyAfterTopLevelIfndef = false;
   }
 
+  /// ResetReadToken - reset whether we have read any tokens. Called 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 ResetReadToken() { ReadAnyTokens = false; }
+
   /// 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; }


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D147928.512109.patch
Type: text/x-patch
Size: 2443 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20230410/27a93f7d/attachment.bin>


More information about the cfe-commits mailing list