Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -157,6 +157,8 @@ - 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 ------------------ 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; } + /// 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; } Index: clang/lib/Lex/PPDirectives.cpp =================================================================== --- clang/lib/Lex/PPDirectives.cpp +++ clang/lib/Lex/PPDirectives.cpp @@ -1177,6 +1177,10 @@ 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(); 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"