[clang] [clang][Lexer] Save and restore MIOpt in `peekNextPPToken()` (PR #180700)

Thorsten Klein via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 10 01:03:19 PST 2026


https://github.com/thorsten-klein updated https://github.com/llvm/llvm-project/pull/180700

>From e22206b6053d311fbb84f931b9156a5e37372af1 Mon Sep 17 00:00:00 2001
From: Thorsten Klein <thorsten.klein at bshg.com>
Date: Mon, 9 Feb 2026 14:35:47 +0100
Subject: [PATCH] [clang][Lexer] Save and restore MIOpt in peekNextPPToken()

Fixes issue #180155 which is caused by peekNextPPToken() not saving and
restoring the MIOpt state when peeking ahead at tokens.

When processing C++20 code, peekNextPPToken() is called on the main file
to check the first token. Inside peekNextPPToken(), the Lex() call
modifies the MIOpt state machine by calling ReadToken(), which sets
ReadAnyTokens=true.
Without proper save/restore, this corrupts the MIOpt state for the file
being lexed.

The corruption can prevent include guard detection. If ReadAnyTokens is
already true from the peek, EnterTopLevelIfndef is not called, and the
controlling macro is not recorded.
---
 clang/lib/Lex/Lexer.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 1498657047bd6..2215a2c623bab 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -3233,6 +3233,7 @@ std::optional<Token> Lexer::peekNextPPToken() {
   bool atStartOfLine = IsAtStartOfLine;
   bool atPhysicalStartOfLine = IsAtPhysicalStartOfLine;
   bool leadingSpace = HasLeadingSpace;
+  MultipleIncludeOpt SavedMIOpt = MIOpt;
 
   Token Tok;
   Lex(Tok);
@@ -3243,6 +3244,7 @@ std::optional<Token> Lexer::peekNextPPToken() {
   HasLeadingSpace = leadingSpace;
   IsAtStartOfLine = atStartOfLine;
   IsAtPhysicalStartOfLine = atPhysicalStartOfLine;
+  MIOpt = SavedMIOpt;
   // Restore the lexer back to non-skipping mode.
   LexingRawMode = false;
 



More information about the cfe-commits mailing list