[clang] [Sema] Skip ExternalSource query and clear DeleteExprs in incremental mode (PR #192856)

via cfe-commits cfe-commits at lists.llvm.org
Sun Apr 19 08:57:11 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: lucasvallejoo

<details>
<summary>Changes</summary>

Hi @<!-- -->vgvassilev, 

I've just finished upstreaming this patch from ROOT/Cling to improve performance during incremental compilation sessions.

### Problem
In an incremental environment, `ActOnEndOfTranslationUnit()` is called after every input line. Previously, Clang would:
1. Query the `ExternalSource` (PCH/modules) for mismatching delete expressions on every cycle, causing redundant disk I/O.
2. Accumulate entries in `DeleteExprs` without clearing them, leading to unnecessary AST traversals in subsequent cycles.

### Solution
This patch guards the `ExternalSource` query with `!PP.isIncrementalProcessingEnabled()` and ensures `DeleteExprs.clear()` is called after the analysis pass.

### Testing
A regression test is included in `clang/test/SemaCXX` to verify that local diagnostics still fire correctly in incremental mode. Note that empirical testing showed that `%clang_cc1` PCH tests are insufficient to simulate the specific `ExternalSource` serialization bottleneck, so a direct PCH test was omitted to avoid false positives.

*Note: This effort is part of my preparation for the compiler fellowship program.*

Let me know if you have any feedback!

---
Full diff: https://github.com/llvm/llvm-project/pull/192856.diff


4 Files Affected:

- (modified) clang/lib/Lex/Lexer.cpp (+4) 
- (modified) clang/lib/Sema/Sema.cpp (+2-1) 
- (added) clang/test/Lexer/pch-deleted-header.cpp (+15) 
- (added) clang/test/SemaCXX/warn-mismatched-delete-incremental.cpp (+12) 


``````````diff
diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp
index 10246552bb13d..39686caa1879d 100644
--- a/clang/lib/Lex/Lexer.cpp
+++ b/clang/lib/Lex/Lexer.cpp
@@ -874,6 +874,10 @@ SourceLocation Lexer::getLocForEndOfToken(SourceLocation Loc, unsigned Offset,
       return Loc;
   }
 
+  // Don't hit the file system for ASTReader tokens.
+  if (SM.isLoadedSourceLocation(Loc))
+    return Loc;
+
   unsigned Len = Lexer::MeasureTokenLength(Loc, SM, LangOpts);
   if (Len > Offset)
     Len = Len - Offset;
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 8a68f2f19bf3d..6f539a8fbd7b5 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1670,7 +1670,7 @@ void Sema::ActOnEndOfTranslationUnit() {
   }
 
   if (!Diags.isIgnored(diag::warn_mismatched_delete_new, SourceLocation())) {
-    if (ExternalSource)
+    if (ExternalSource && !PP.isIncrementalProcessingEnabled())
       ExternalSource->ReadMismatchingDeleteExpressions(DeleteExprs);
     for (const auto &DeletedFieldInfo : DeleteExprs) {
       for (const auto &DeleteExprLoc : DeletedFieldInfo.second) {
@@ -1678,6 +1678,7 @@ void Sema::ActOnEndOfTranslationUnit() {
                                   DeleteExprLoc.second);
       }
     }
+    DeleteExprs.clear();
   }
 
   AnalysisWarnings.IssueWarnings(Context.getTranslationUnitDecl());
diff --git a/clang/test/Lexer/pch-deleted-header.cpp b/clang/test/Lexer/pch-deleted-header.cpp
new file mode 100644
index 0000000000000..31b7ed330fd9f
--- /dev/null
+++ b/clang/test/Lexer/pch-deleted-header.cpp
@@ -0,0 +1,15 @@
+// RUN: rm -f %t.h %t.pch
+// RUN: echo "int variable_del_cern = 42;" > %t.h
+// RUN: %clang_cc1 -x c++-header -emit-pch -o %t.pch %t.h
+// RUN: rm %t.h
+// RUN: %clang_cc1 -fno-validate-pch -ast-dump -include-pch %t.pch %s
+
+// This test ensures that Clang does not access the filesystem when
+// handling SourceLocations originating from a PCH.
+//
+// After generating the PCH, the original header is removed. If Clang
+// attempts to access it (e.g. via MeasureTokenLength), the test will fail.
+
+int function() { 
+    return variable_del_cern; 
+}
diff --git a/clang/test/SemaCXX/warn-mismatched-delete-incremental.cpp b/clang/test/SemaCXX/warn-mismatched-delete-incremental.cpp
new file mode 100644
index 0000000000000..aba924bae59a1
--- /dev/null
+++ b/clang/test/SemaCXX/warn-mismatched-delete-incremental.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -fincremental-extensions -verify %s
+// Regression test for incremental-mode handling of warn_mismatched_delete_new
+// in Sema::ActOnEndOfTranslationUnit(). Ensures the diagnostic fires correctly
+// in incremental mode and that DeleteExprs does not accumulate stale entries
+// across EndOfTU cycles.
+
+struct S {
+  int *p;
+  S() : p(new int[10]) {}
+  ~S() { delete p; } // expected-warning {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}}
+                      // expected-note at -2 {{allocated with 'new[]' here}}
+};
\ No newline at end of file

``````````

</details>


https://github.com/llvm/llvm-project/pull/192856


More information about the cfe-commits mailing list