https://github.com/hahnjo updated 
https://github.com/llvm/llvm-project/pull/219189

>From a520ad10573f35dfca27b42847c589d8d9511f88 Mon Sep 17 00:00:00 2001
From: Jonas Hahnfeld <[email protected]>
Date: Thu, 27 Aug 2026 13:11:37 +0200
Subject: [PATCH 1/2] [clang][AST] Fix generation with multiple external
 sources

ExternalASTSource::incrementGeneration returns the OldGeneration,
which must be taken into account in case it is delegated to the
topmost external source.

This obsoletes a long-standing downstream patch in Cling that was
previously submitted in https://reviews.llvm.org/D39714.
---
 clang/lib/AST/ExternalASTSource.cpp | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/clang/lib/AST/ExternalASTSource.cpp 
b/clang/lib/AST/ExternalASTSource.cpp
index e8c1004089713..1888ffd6bd27c 100644
--- a/clang/lib/AST/ExternalASTSource.cpp
+++ b/clang/lib/AST/ExternalASTSource.cpp
@@ -118,19 +118,20 @@ void ExternalASTSource::FindExternalLexicalDecls(
 void ExternalASTSource::getMemoryBufferSizes(MemoryBufferSizes &sizes) const {}
 
 uint32_t ExternalASTSource::incrementGeneration(ASTContext &C) {
-  uint32_t OldGeneration = CurrentGeneration;
-
   // Make sure the generation of the topmost external source for the context is
   // incremented. That might not be us.
   auto *P = C.getExternalSource();
-  if (P && P != this)
+  if (P && P != this) {
+    // The call itself returns the OldGeneration of the topmost external 
source.
     CurrentGeneration = P->incrementGeneration(C);
-  else {
-    // FIXME: Only bump the generation counter if the current generation number
-    // has been observed?
-    if (!++CurrentGeneration)
-      llvm::reportFatalUsageError("generation counter overflowed");
   }
 
+  uint32_t OldGeneration = CurrentGeneration;
+
+  // FIXME: Only bump the generation counter if the current generation number
+  // has been observed?
+  if (!++CurrentGeneration)
+    llvm::reportFatalUsageError("generation counter overflowed");
+
   return OldGeneration;
 }

>From 2f7eee6c34a7ffac29b42e740e21954c7143775a Mon Sep 17 00:00:00 2001
From: Jonas Hahnfeld <[email protected]>
Date: Mon, 31 Aug 2026 17:16:51 +0200
Subject: [PATCH 2/2] Add test

Co-authored-by: Vassil Vassilev <[email protected]>
Assisted-by: Claude
---
 clang/unittests/AST/ExternalASTSourceTest.cpp | 43 +++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/clang/unittests/AST/ExternalASTSourceTest.cpp 
b/clang/unittests/AST/ExternalASTSourceTest.cpp
index 19bc143ddb3d3..fa4e96fca8fa3 100644
--- a/clang/unittests/AST/ExternalASTSourceTest.cpp
+++ b/clang/unittests/AST/ExternalASTSourceTest.cpp
@@ -19,6 +19,7 @@
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Tooling/Tooling.h"
 #include "llvm/Support/VirtualFileSystem.h"
 #include "gtest/gtest.h"
 
@@ -182,3 +183,45 @@ TEST(ExternalASTSourceTest, CompletesPatternInEitherOrder) 
{
     EXPECT_EQ(1u, Source->PartialCompletions) << Code;
   }
 }
+
+namespace {
+// incrementGeneration is protected, so reaching it needs a source of our own.
+struct BumpableSource : ExternalASTSource {
+  uint32_t bump(ASTContext &C) { return incrementGeneration(C); }
+};
+} // namespace
+
+// Multiple external sources synchronize their generations, and the return
+// values of incrementGeneration() and getGeneration() are as expected. This
+// is relied upon by ASTReader and LazyGenerationalUpdatePtr.
+TEST(ExternalASTSourceTest, IncrementGeneration) {
+  std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCode("");
+  ASSERT_TRUE(AST != nullptr);
+  ASTContext &Ctx = AST->getASTContext();
+
+  auto Topmost = llvm::makeIntrusiveRefCnt<BumpableSource>();
+  auto Secondary = llvm::makeIntrusiveRefCnt<BumpableSource>();
+  Ctx.setExternalSource(Topmost);
+  ASSERT_EQ(Ctx.getExternalSource(), Topmost.get());
+
+  // The generation starts at the same value for the two sources.
+  ASSERT_EQ(Topmost->getGeneration(), 0u);
+  ASSERT_EQ(Secondary->getGeneration(), 0u);
+
+  // Bumping the "secondary" source bumps the toplevel one, and leaves the two
+  // agreeing on the generation afterwards.
+  EXPECT_EQ(Secondary->bump(Ctx), 0u);
+  EXPECT_EQ(Secondary->getGeneration(), 1u);
+  EXPECT_EQ(Topmost->getGeneration(), 1u);
+
+  // Bumping the topmost source increments its generation by one.
+  EXPECT_EQ(Topmost->bump(Ctx), 1u);
+  EXPECT_EQ(Topmost->getGeneration(), 2u);
+  // At this point, the "secondary" source is out-of-sync...
+  EXPECT_EQ(Secondary->getGeneration(), 1u);
+
+  // Another bump synchronizes the two sources.
+  EXPECT_EQ(Secondary->bump(Ctx), 2u);
+  EXPECT_EQ(Secondary->getGeneration(), 3u);
+  EXPECT_EQ(Topmost->getGeneration(), 3u);
+}

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

Reply via email to