https://github.com/freaknbigpanda updated https://github.com/llvm/llvm-project/pull/183425
>From dc6fefed70ebda39b3718ab35161c10011c84571 Mon Sep 17 00:00:00 2001 From: Benjamin Luke <[email protected]> Date: Fri, 20 Feb 2026 15:31:32 -0800 Subject: [PATCH 1/2] [clang][Lex] Preserve MultipleIncludeOpt state in Lexer::peekNextPPToken peekNextPPToken lexed a token and mutated MIOpt, which could clear the controlling-macro state for main files in C++20 modules mode. Save/restore MIOpt in Lexer::peekNextPPToken. Add regression coverage in LexerTest.MainFileHeaderGuardedWithCPlusPlusModules that checks to make sure the controlling macro is properly set in C++20 mode. `Add source level lit test in miopt-peek-restore-header-guard.cpp that checks to make sure that the warnings that depend on the MIOpt state machine are emitted in C++20 mode. --- clang/lib/Lex/Lexer.cpp | 2 ++ .../miopt-peek-restore-header-guard.cpp | 12 +++++++ clang/unittests/Lex/LexerTest.cpp | 34 +++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 clang/test/Preprocessor/miopt-peek-restore-header-guard.cpp diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 92c3046a6fd19..0e72a27b852d7 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -3231,6 +3231,7 @@ std::optional<Token> Lexer::peekNextPPToken() { bool atStartOfLine = IsAtStartOfLine; bool atPhysicalStartOfLine = IsAtPhysicalStartOfLine; bool leadingSpace = HasLeadingSpace; + MultipleIncludeOpt MIOptState = MIOpt; Token Tok; Lex(Tok); @@ -3241,6 +3242,7 @@ std::optional<Token> Lexer::peekNextPPToken() { HasLeadingSpace = leadingSpace; IsAtStartOfLine = atStartOfLine; IsAtPhysicalStartOfLine = atPhysicalStartOfLine; + MIOpt = MIOptState; // Restore the lexer back to non-skipping mode. LexingRawMode = false; diff --git a/clang/test/Preprocessor/miopt-peek-restore-header-guard.cpp b/clang/test/Preprocessor/miopt-peek-restore-header-guard.cpp new file mode 100644 index 0000000000000..8f3e9f49cf1b6 --- /dev/null +++ b/clang/test/Preprocessor/miopt-peek-restore-header-guard.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -Wheader-guard -verify %s + +// Regression test for Lexer::peekNextPPToken() saving/restoring MIOpt state. +// In C++20 module mode, the preprocessor peeks the first pp-token in the main +// file before lexing begins. That must not perturb MIOpt state used for +// header-guard analysis. + +#ifndef GOOD_GUARD +#define BAD_GUARD +#endif +// expected-warning@-3 {{'GOOD_GUARD' is used as a header guard here, followed by #define of a different macro}} +// expected-note@-3 {{'BAD_GUARD' is defined here; did you mean 'GOOD_GUARD'?}} diff --git a/clang/unittests/Lex/LexerTest.cpp b/clang/unittests/Lex/LexerTest.cpp index c51cd0d2bfdaa..da335d6e81820 100644 --- a/clang/unittests/Lex/LexerTest.cpp +++ b/clang/unittests/Lex/LexerTest.cpp @@ -89,6 +89,30 @@ class LexerTest : public ::testing::Test { return toks; } + bool MainFileIsMultipleIncludeGuarded(StringRef Filename, StringRef Source) { + FileEntryRef FE = FileMgr.getVirtualFileRef(Filename, Source.size(), 0); + SourceMgr.setMainFileID( + SourceMgr.createFileID(FE, SourceLocation(), SrcMgr::C_User)); + SourceMgr.overrideFileContents( + FE, llvm::MemoryBuffer::getMemBufferCopy(Source, Filename)); + + TrivialModuleLoader ModLoader; + HeaderSearchOptions HSOpts; + HeaderSearch HeaderInfo(HSOpts, SourceMgr, Diags, LangOpts, Target.get()); + PreprocessorOptions PPOpts; + std::unique_ptr<Preprocessor> LocalPP = std::make_unique<Preprocessor>( + PPOpts, Diags, LangOpts, SourceMgr, HeaderInfo, ModLoader, + /*IILookup=*/nullptr, + /*OwnsHeaderSearch=*/false); + if (!PreDefines.empty()) + LocalPP->setPredefines(PreDefines); + LocalPP->Initialize(*Target); + LocalPP->EnterMainSourceFile(); + std::vector<Token> Toks; + LocalPP->LexTokensUntilEOF(&Toks); + return LocalPP->getHeaderSearchInfo().isFileMultipleIncludeGuarded(FE); + } + std::string getSourceText(Token Begin, Token End) { bool Invalid; StringRef Str = @@ -360,6 +384,16 @@ TEST_F(LexerTest, LexAPI) { EXPECT_EQ("N", Lexer::getImmediateMacroName(idLoc4, SourceMgr, LangOpts)); } +TEST_F(LexerTest, MainFileHeaderGuardedWithCPlusPlusModules) { + LangOpts.CPlusPlus = true; + LangOpts.CPlusPlusModules = true; + + EXPECT_TRUE(MainFileIsMultipleIncludeGuarded("guarded.h", "#ifndef GUARD\n" + "#define GUARD\n" + "int x;\n" + "#endif\n")); +} + TEST_F(LexerTest, HandlesSplitTokens) { std::vector<tok::TokenKind> ExpectedTokens; // Line 1 (after the #defines) >From f95bb5ca1504f44bc7ac188cca2937e71f4afd39 Mon Sep 17 00:00:00 2001 From: Benjamin Luke <[email protected]> Date: Thu, 26 Feb 2026 16:51:26 -0800 Subject: [PATCH 2/2] Added release note --- clang/docs/ReleaseNotes.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index af124fce2bc64..2a297d9a71889 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -299,6 +299,7 @@ Bug Fixes in This Version - Fixed an assertion failure when evaluating ``_Countof`` on invalid ``void``-typed operands. (#GH180893) - Fixed an assertion failure in the serialized diagnostic printer when it is destroyed without calling ``finish()``. (#GH140433) - Fixed an assertion failure caused by error recovery while extending a nested name specifier with results from ordinary lookup. (#GH181470) +- Fixed a bug with multiple-include optimization (MIOpt) state not being preserved in some cases during lexing, which could suppress header-guard mismatch diagnostics and interfere with include-guard optimization. Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
