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 */