https://github.com/jansvoboda11 updated 
https://github.com/llvm/llvm-project/pull/181772

>From 7aa5806853848cea8022cff02d443c00ac54fa6a Mon Sep 17 00:00:00 2001
From: Jan Svoboda <[email protected]>
Date: Mon, 16 Feb 2026 15:55:35 -0800
Subject: [PATCH 1/3] [clang][deps] Ensure the service outlives async module
 compiles

---
 .../DependencyScannerImpl.cpp                 | 73 ++++++++++++++-----
 1 file changed, 54 insertions(+), 19 deletions(-)

diff --git a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp 
b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
index 28fa2571a24dc..ef2712ac3b56e 100644
--- a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
@@ -554,11 +554,42 @@ dependencies::initializeScanInstanceDependencyCollector(
   return MDC;
 }
 
+/// Manages (and terminates) the asynchronous compilation of modules.
+class AsyncModuleCompiles {
+  std::mutex Mutex;
+  bool Stop = false;
+  // FIXME: Have the service own a thread pool and use that instead.
+  std::vector<std::thread> Compiles;
+
+public:
+  /// Registers the module compilation, unless this instance is about to be
+  /// destroyed.
+  void add(llvm::unique_function<void()> Compile) {
+    std::lock_guard Lock(Mutex);
+    if (!Stop)
+      Compiles.emplace_back(std::move(Compile));
+  }
+
+  ~AsyncModuleCompiles() {
+    {
+      // Prevent registration of further module compiles.
+      std::lock_guard Lock(Mutex);
+      Stop = true;
+    }
+
+    // Wait for outstanding module compiles to finish.
+    for (std::thread &Compile : Compiles)
+      Compile.join();
+  }
+};
+
 struct SingleModuleWithAsyncModuleCompiles : PreprocessOnlyAction {
   DependencyScanningService &Service;
+  AsyncModuleCompiles &Compiles;
 
-  SingleModuleWithAsyncModuleCompiles(DependencyScanningService &Service)
-      : Service(Service) {}
+  SingleModuleWithAsyncModuleCompiles(DependencyScanningService &Service,
+                                      AsyncModuleCompiles &Compiles)
+      : Service(Service), Compiles(Compiles) {}
 
   bool BeginSourceFileAction(CompilerInstance &CI) override;
 };
@@ -568,9 +599,11 @@ struct SingleModuleWithAsyncModuleCompiles : 
PreprocessOnlyAction {
 struct AsyncModuleCompile : PPCallbacks {
   CompilerInstance &CI;
   DependencyScanningService &Service;
+  AsyncModuleCompiles &Compiles;
 
-  AsyncModuleCompile(CompilerInstance &CI, DependencyScanningService &Service)
-      : CI(CI), Service(Service) {}
+  AsyncModuleCompile(CompilerInstance &CI, DependencyScanningService &Service,
+                     AsyncModuleCompiles &Compiles)
+      : CI(CI), Service(Service), Compiles(Compiles) {}
 
   void moduleLoadSkipped(Module *M) override {
     M = M->getTopLevelModule();
@@ -635,25 +668,23 @@ struct AsyncModuleCompile : PPCallbacks {
     auto ModCI2 = CI.cloneForModuleCompile(SourceLocation(), M, ModuleFileName,
                                            CloneConfig);
 
-    // FIXME: Have the service own a thread pool and use that instead.
-    // FIXME: This lock belongs to a module cache that might not outlive the
-    // thread. (This should work for now, because the in-process lock only
-    // refers to an object managed by the service, which should outlive this
-    // thread.)
-    std::thread([Lock = std::move(Lock), ModCI1 = std::move(ModCI1),
-                 ModCI2 = std::move(ModCI2), DC = std::move(DC),
-                 Service = &Service] {
+    // Note: This lock belongs to a module cache that might not outlive the
+    // thread. This works, because the in-process lock only refers to an object
+    // managed by the service, which does outlive the thread.
+    Compiles.add([Lock = std::move(Lock), ModCI1 = std::move(ModCI1),
+                  ModCI2 = std::move(ModCI2), DC = std::move(DC),
+                  Service = &Service, Compiles = &Compiles] {
       llvm::CrashRecoveryContext CRC;
       (void)CRC.RunSafely([&] {
         // Quickly discovers and compiles modules for the real scan below.
-        SingleModuleWithAsyncModuleCompiles Action1(*Service);
+        SingleModuleWithAsyncModuleCompiles Action1(*Service, *Compiles);
         (void)ModCI1->ExecuteAction(Action1);
         // The real scan below.
         ModCI2->getPreprocessorOpts().SingleModuleParseMode = false;
         GenerateModuleFromModuleMapAction Action2;
         (void)ModCI2->ExecuteAction(Action2);
       });
-    }).detach();
+    });
   }
 };
 
@@ -661,14 +692,16 @@ struct AsyncModuleCompile : PPCallbacks {
 /// modules asynchronously without blocking or importing them.
 struct SingleTUWithAsyncModuleCompiles : PreprocessOnlyAction {
   DependencyScanningService &Service;
+  AsyncModuleCompiles &Compiles;
 
-  SingleTUWithAsyncModuleCompiles(DependencyScanningService &Service)
-      : Service(Service) {}
+  SingleTUWithAsyncModuleCompiles(DependencyScanningService &Service,
+                                  AsyncModuleCompiles &Compiles)
+      : Service(Service), Compiles(Compiles) {}
 
   bool BeginSourceFileAction(CompilerInstance &CI) override {
     CI.getInvocation().getPreprocessorOpts().SingleModuleParseMode = true;
     CI.getPreprocessor().addPPCallbacks(
-        std::make_unique<AsyncModuleCompile>(CI, Service));
+        std::make_unique<AsyncModuleCompile>(CI, Service, Compiles));
     return true;
   }
 };
@@ -677,7 +710,7 @@ bool 
SingleModuleWithAsyncModuleCompiles::BeginSourceFileAction(
     CompilerInstance &CI) {
   CI.getInvocation().getPreprocessorOpts().SingleModuleParseMode = true;
   CI.getPreprocessor().addPPCallbacks(
-      std::make_unique<AsyncModuleCompile>(CI, Service));
+      std::make_unique<AsyncModuleCompile>(CI, Service, Compiles));
   return true;
 }
 
@@ -711,6 +744,7 @@ bool DependencyScanningAction::runInvocation(
       createScanCompilerInvocation(*OriginalInvocation, Service);
 
   // Quickly discovers and compiles modules for the real scan below.
+  std::optional<AsyncModuleCompiles> AsyncCompiles;
   if (Service.getOpts().AsyncScanModules) {
     auto ModCache = makeInProcessModuleCache(Service.getModuleCacheEntries());
     auto ScanInstanceStorage = std::make_unique<CompilerInstance>(
@@ -733,7 +767,8 @@ bool DependencyScanningAction::runInvocation(
     if (ScanInstance.getFrontendOpts().ProgramAction == frontend::GeneratePCH)
       ScanInstance.getLangOpts().CompilingPCH = true;
 
-    SingleTUWithAsyncModuleCompiles Action(Service);
+    AsyncCompiles.emplace();
+    SingleTUWithAsyncModuleCompiles Action(Service, *AsyncCompiles);
     (void)ScanInstance.ExecuteAction(Action);
   }
 

>From 8eeb93364004fd8dd0d5b0a0e361f44e36117cc1 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <[email protected]>
Date: Tue, 17 Feb 2026 09:25:20 -0800
Subject: [PATCH 2/3] Add missing include

---
 clang/lib/DependencyScanning/DependencyScannerImpl.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp 
b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
index ef2712ac3b56e..89c96c7bf9876 100644
--- a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
@@ -21,6 +21,7 @@
 #include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/TargetParser/Host.h"
 
+#include <mutex>
 #include <thread>
 
 using namespace clang;

>From c398127df091437d10b62af94359bf72b6a38d48 Mon Sep 17 00:00:00 2001
From: Jan Svoboda <[email protected]>
Date: Tue, 17 Feb 2026 09:47:01 -0800
Subject: [PATCH 3/3] Don't rely on CTAD

---
 clang/lib/DependencyScanning/DependencyScannerImpl.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp 
b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
index 89c96c7bf9876..51f98cdefb9b7 100644
--- a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
@@ -566,7 +566,7 @@ class AsyncModuleCompiles {
   /// Registers the module compilation, unless this instance is about to be
   /// destroyed.
   void add(llvm::unique_function<void()> Compile) {
-    std::lock_guard Lock(Mutex);
+    std::lock_guard<std::mutex> Lock(Mutex);
     if (!Stop)
       Compiles.emplace_back(std::move(Compile));
   }
@@ -574,7 +574,7 @@ class AsyncModuleCompiles {
   ~AsyncModuleCompiles() {
     {
       // Prevent registration of further module compiles.
-      std::lock_guard Lock(Mutex);
+      std::lock_guard<std::mutex> Lock(Mutex);
       Stop = true;
     }
 

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

Reply via email to