This is an archive of the discontinued LLVM Phabricator instance.

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

Authored by IncludeGuardian on Apr 10 2023, 4:15 AM.

Details

Summary

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.

Diff Detail

Event Timeline

Herald added a project: Restricted Project. · View Herald TranscriptApr 10 2023, 4:15 AM
IncludeGuardian requested review of this revision.Apr 10 2023, 4:15 AM

Differences between the behaviors of compilers can be found here https://github.com/IncludeGuardian/multiple-inclusion-optimization-tests

You can see the number of boost preprocessor files failing the include guard optimization when running IncludeGuardian over Boost Graph https://gist.github.com/IncludeGuardian/0837719e0d1162d5b50e4c8fed4d3c0d#file-boost_graph-yaml-L345-L749

An example boost preprocessor header can be found here https://github.com/boostorg/preprocessor/blob/667e87b3392db338a919cbe0213979713aca52e3/include/boost/preprocessor.hpp. Note the consistent use of null directives outside of the guard.

aaron.ballman added inline comments.Apr 17 2023, 9:33 AM
clang/lib/Lex/PPDirectives.cpp
1183–1185

NFC but matches our style guide.

One thing to consider: making the call a setter instead of a reset would simplify this logic into: CurPPLexer->SetReadToken(ReadAnyTokensBeforeDirective); without any branching required. WDYT?

clang/lib/Lex/PPDirectives.cpp
1183–1185

Sounds good. Removing the condition here should look neater.

Replace ResetReadToken with SetReadToken to avoid a conditional

IncludeGuardian marked an inline comment as done.Apr 20 2023, 3:13 PM
aaron.ballman accepted this revision.Apr 24 2023, 12:16 PM

LGTM, though please add a release note to clang/docs/ReleaseNotes.rst for the fix. Do you need me to commit on your behalf? If so, please let me know what name and email address you'd like used for patch attribution.

This revision is now accepted and ready to land.Apr 24 2023, 12:16 PM

Update Clang release notes

@aaron.ballman If you could commit for me that would be great. Please use "Elliot Goodrich" for the name and "elliotgoodrich@gmail.com" for the email - thank you!

Rebase on upstream to resolve conflicts in release notes

This revision was automatically updated to reflect the committed changes.