https://github.com/yronglin updated 
https://github.com/llvm/llvm-project/pull/203716

>From d2a6eaa165128c9cc32447dcbfd36413c758d35b Mon Sep 17 00:00:00 2001
From: yronglin <[email protected]>
Date: Sat, 13 Jun 2026 09:56:56 -0700
Subject: [PATCH 1/3] [clangd] Fix clangd crash when code completion EOF is
 reached while skipping a function body

Signed-off-by: yronglin <[email protected]>
---
 .../clangd/unittests/CodeCompleteTests.cpp      | 17 +++++++++++++++++
 clang/lib/Parse/ParseStmt.cpp                   | 14 +++++---------
 2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp 
b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 5808b2145965f..dc94af4dddf8c 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -1918,6 +1918,23 @@ TEST(SignatureHelpTest, StalePreamble) {
   EXPECT_EQ(0, Results.activeParameter);
 }
 
+TEST(SignatureHelpTest, EOFInSkippedFunctionBody) {
+  Annotations Test(R"cpp(
+#ifdef IS_HEADER
+void frameSizeBlocksWarning() {
+  auto fn = []() {
+  };
+  fn();
+}
+#else
+#define IS_HEADER
+#include __FILE__
+#^endif
+)cpp");
+  auto Results = signatures(Test.code(), Test.point());
+  EXPECT_THAT(Results.signatures, IsEmpty());
+}
+
 class IndexRequestCollector : public SymbolIndex {
 public:
   IndexRequestCollector(std::vector<Symbol> Syms = {}) : Symbols(Syms) {}
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 37f142e059930..e77d6066847b2 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -2496,8 +2496,10 @@ bool Parser::trySkippingFunctionBody() {
 
   // We're in code-completion mode. Skip parsing for all function bodies unless
   // the body contains the code-completion point.
+  if (Tok.is(tok::kw_try))
+    return false;
+
   TentativeParsingAction PA(*this);
-  bool IsTryCatch = Tok.is(tok::kw_try);
   CachedTokens Toks;
   bool ErrorInPrologue = ConsumeAndStoreFunctionPrologue(Toks);
   if (llvm::any_of(Toks, [](const Token &Tok) {
@@ -2511,18 +2513,12 @@ bool Parser::trySkippingFunctionBody() {
     SkipMalformedDecl();
     return true;
   }
-  if (!SkipUntil(tok::r_brace, StopAtCodeCompletion)) {
+  if (!SkipUntil(tok::r_brace, StopAtCodeCompletion | StopBeforeMatch)) {
     PA.Revert();
     return false;
   }
-  while (IsTryCatch && Tok.is(tok::kw_catch)) {
-    if (!SkipUntil(tok::l_brace, StopAtCodeCompletion) ||
-        !SkipUntil(tok::r_brace, StopAtCodeCompletion)) {
-      PA.Revert();
-      return false;
-    }
-  }
   PA.Commit();
+  ConsumeBrace();
   return true;
 }
 

>From 3aa2ba5f83ec50223d41bc7bede88d4719e3809c Mon Sep 17 00:00:00 2001
From: yronglin <[email protected]>
Date: Mon, 22 Jun 2026 16:57:31 +0800
Subject: [PATCH 2/3] Add explicit flag for caching lex mode

Signed-off-by: yronglin <[email protected]>
---
 clang/include/clang/Lex/Preprocessor.h | 16 +++++++++-------
 clang/lib/Lex/PPCaching.cpp            |  4 +++-
 clang/lib/Lex/PPLexerChange.cpp        |  6 +++++-
 clang/lib/Lex/Preprocessor.cpp         |  6 ++++--
 clang/lib/Parse/ParseStmt.cpp          | 13 +++++++++----
 5 files changed, 30 insertions(+), 15 deletions(-)

diff --git a/clang/include/clang/Lex/Preprocessor.h 
b/clang/include/clang/Lex/Preprocessor.h
index 8b684e85eb1c1..4d47976ec536f 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -1190,6 +1190,9 @@ class Preprocessor {
   /// Lex() should be invoked.
   CachedTokensTy::size_type CachedLexPos = 0;
 
+  /// True when the caching lexer is installed as the active lexer layer.
+  bool IsCachingLexMode = false;
+
   /// Stack of backtrack positions, allowing nested backtracks.
   ///
   /// The EnableBacktrackAtThisPos() method pushes a position to
@@ -2583,7 +2586,7 @@ class Preprocessor {
   friend void TokenLexer::ExpandFunctionArguments();
 
   void PushIncludeMacroStack() {
-    assert(CurLexerCallback != CLK_CachingLexer &&
+    assert(!IsCachingLexMode && CurLexerCallback != CLK_CachingLexer &&
            "cannot push a caching lexer");
     IncludeMacroStack.emplace_back(CurLexerCallback, CurLexerSubmodule,
                                    std::move(CurLexer), CurPPLexer,
@@ -2592,6 +2595,7 @@ class Preprocessor {
   }
 
   void PopIncludeMacroStack() {
+    IsCachingLexMode = false;
     if (CurLexer)
       PendingDestroyLexers.push_back(std::move(CurLexer));
     CurLexer = std::move(IncludeMacroStack.back().TheLexer);
@@ -2819,18 +2823,16 @@ class Preprocessor {
   // Caching stuff.
   void CachingLex(Token &Result);
 
-  bool InCachingLexMode() const {
-    // If the Lexer pointers are 0 and IncludeMacroStack is empty, it means
-    // that we are past EOF, not that we are in CachingLex mode.
-    return !CurPPLexer && !CurTokenLexer && !IncludeMacroStack.empty();
-  }
+  bool InCachingLexMode() const { return IsCachingLexMode; }
 
   void EnterCachingLexMode();
   void EnterCachingLexModeUnchecked();
 
   void ExitCachingLexMode() {
-    if (InCachingLexMode())
+    if (InCachingLexMode()) {
+      IsCachingLexMode = false;
       RemoveTopOfLexerStack();
+    }
   }
 
   const Token &PeekAhead(unsigned N);
diff --git a/clang/lib/Lex/PPCaching.cpp b/clang/lib/Lex/PPCaching.cpp
index cbacda9d31ae2..d64183a35122a 100644
--- a/clang/lib/Lex/PPCaching.cpp
+++ b/clang/lib/Lex/PPCaching.cpp
@@ -126,8 +126,10 @@ void Preprocessor::EnterCachingLexMode() {
 }
 
 void Preprocessor::EnterCachingLexModeUnchecked() {
-  assert(CurLexerCallback != CLK_CachingLexer && "already in caching lex 
mode");
+  assert(!InCachingLexMode() && CurLexerCallback != CLK_CachingLexer &&
+         "already in caching lex mode");
   PushIncludeMacroStack();
+  IsCachingLexMode = true;
   CurLexerCallback = CLK_CachingLexer;
 }
 
diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp
index 98ff9a9a04e7c..d901d02a44f7a 100644
--- a/clang/lib/Lex/PPLexerChange.cpp
+++ b/clang/lib/Lex/PPLexerChange.cpp
@@ -106,6 +106,9 @@ bool Preprocessor::EnterSourceFile(FileID FID, 
ConstSearchDirIterator CurDir,
 ///  and start lexing tokens from it instead of the current buffer.
 void Preprocessor::EnterSourceFileWithLexer(std::unique_ptr<Lexer> TheLexer,
                                             ConstSearchDirIterator CurDir) {
+  if (InCachingLexMode())
+    ExitCachingLexMode();
+
   PreprocessorLexer *PrevPPLexer = CurPPLexer;
 
   // Add the current lexer to the include stack.
@@ -172,7 +175,8 @@ void Preprocessor::EnterMacro(Token &Tok, SourceLocation 
ILEnd,
 void Preprocessor::EnterTokenStream(const Token *Toks, unsigned NumToks,
                                     bool DisableMacroExpansion, bool 
OwnsTokens,
                                     bool IsReinject) {
-  if (CurLexerCallback == CLK_CachingLexer) {
+  if (InCachingLexMode()) {
+    assert(CurLexerCallback == CLK_CachingLexer && "Unexpected lexer kind");
     if (CachedLexPos < CachedTokens.size()) {
       assert(IsReinject && "new tokens in the middle of cached stream");
       // We're entering tokens into the middle of our cached token stream. We
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 1e21b4a94cea3..c69d084d6514f 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -417,14 +417,16 @@ StringRef Preprocessor::getLastMacroWithSpelling(
 }
 
 void Preprocessor::recomputeCurLexerKind() {
-  if (CurLexer)
+  if (InCachingLexMode())
+    CurLexerCallback = CLK_CachingLexer;
+  else if (CurLexer)
     CurLexerCallback = CurLexer->isDependencyDirectivesLexer()
                            ? CLK_DependencyDirectivesLexer
                            : CLK_Lexer;
   else if (CurTokenLexer)
     CurLexerCallback = CLK_TokenLexer;
   else
-    CurLexerCallback = CLK_CachingLexer;
+    CurLexerCallback = CLK_Lexer;
 }
 
 bool Preprocessor::SetCodeCompletionPoint(FileEntryRef File,
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index e77d6066847b2..e8dd987414249 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -2496,10 +2496,9 @@ bool Parser::trySkippingFunctionBody() {
 
   // We're in code-completion mode. Skip parsing for all function bodies unless
   // the body contains the code-completion point.
-  if (Tok.is(tok::kw_try))
-    return false;
 
   TentativeParsingAction PA(*this);
+  bool IsTryCatch = Tok.is(tok::kw_try);
   CachedTokens Toks;
   bool ErrorInPrologue = ConsumeAndStoreFunctionPrologue(Toks);
   if (llvm::any_of(Toks, [](const Token &Tok) {
@@ -2513,12 +2512,18 @@ bool Parser::trySkippingFunctionBody() {
     SkipMalformedDecl();
     return true;
   }
-  if (!SkipUntil(tok::r_brace, StopAtCodeCompletion | StopBeforeMatch)) {
+  if (!SkipUntil(tok::r_brace, StopAtCodeCompletion)) {
     PA.Revert();
     return false;
   }
+  while (IsTryCatch && Tok.is(tok::kw_catch)) {
+    if (!SkipUntil(tok::l_brace, StopAtCodeCompletion) ||
+        !SkipUntil(tok::r_brace, StopAtCodeCompletion)) {
+      PA.Revert();
+      return false;
+    }
+  }
   PA.Commit();
-  ConsumeBrace();
   return true;
 }
 

>From 234dac06b8aa8d413f0a7379a096a95e39211011 Mon Sep 17 00:00:00 2001
From: Yihan Wang <[email protected]>
Date: Mon, 22 Jun 2026 22:51:12 +0800
Subject: [PATCH 3/3] Revert blank changes.

---
 clang/lib/Parse/ParseStmt.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index e8dd987414249..37f142e059930 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -2496,7 +2496,6 @@ bool Parser::trySkippingFunctionBody() {
 
   // We're in code-completion mode. Skip parsing for all function bodies unless
   // the body contains the code-completion point.
-
   TentativeParsingAction PA(*this);
   bool IsTryCatch = Tok.is(tok::kw_try);
   CachedTokens Toks;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to