Skip to content

[clang][analyzer] Add location to CTU failure diagnostics#188795

Merged
necto merged 1 commit into
llvm:mainfrom
necto:az/ctu-error-loc
Mar 27, 2026
Merged

[clang][analyzer] Add location to CTU failure diagnostics#188795
necto merged 1 commit into
llvm:mainfrom
necto:az/ctu-error-loc

Conversation

@necto
Copy link
Copy Markdown
Contributor

@necto necto commented Mar 26, 2026

Report CTU import failures at the place where the imported symbol would be used. This helps to quicker understand why CSA might miss a certain expected CTU bug.

--
CPP-7804

Report CTU import failures at the place where the imported symbol would
be used. This helps to quicker understand why CSA might miss a certain
expected CTU bug.

--
CPP-7804
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:static analyzer labels Mar 26, 2026
@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Mar 26, 2026

@llvm/pr-subscribers-clang

Author: Arseniy Zaostrovnykh (necto)

Changes

Report CTU import failures at the place where the imported symbol would be used. This helps to quicker understand why CSA might miss a certain expected CTU bug.

--
CPP-7804


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

7 Files Affected:

  • (modified) clang/include/clang/CrossTU/CrossTranslationUnit.h (+1-1)
  • (modified) clang/lib/CrossTU/CrossTranslationUnit.cpp (+6-5)
  • (modified) clang/lib/StaticAnalyzer/Core/CallEvent.cpp (+3-1)
  • (modified) clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (+1-1)
  • (modified) clang/test/Analysis/ctu/diag/invalid-index.cpp (+1-4)
  • (modified) clang/test/Analysis/ctu/diag/missing-index.cpp (+1-4)
  • (modified) clang/test/Analysis/ctu/different-triples.cpp (+1-4)
diff --git a/clang/include/clang/CrossTU/CrossTranslationUnit.h b/clang/include/clang/CrossTU/CrossTranslationUnit.h
index 9e0721edfc323..145bc8df27de6 100644
--- a/clang/include/clang/CrossTU/CrossTranslationUnit.h
+++ b/clang/include/clang/CrossTU/CrossTranslationUnit.h
@@ -184,7 +184,7 @@ class CrossTranslationUnitContext {
   static std::optional<std::string> getLookupName(const Decl *D);
 
   /// Emit diagnostics for the user for potential configuration errors.
-  void emitCrossTUDiagnostics(const IndexError &IE);
+  void emitCrossTUDiagnostics(const IndexError &IE, SourceLocation Loc);
 
   /// Returns the MacroExpansionContext for the imported TU to which the given
   /// source-location corresponds.
diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp
index ef25ad454da2e..8dd0ef13123d1 100644
--- a/clang/lib/CrossTU/CrossTranslationUnit.cpp
+++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp
@@ -379,22 +379,23 @@ CrossTranslationUnitContext::getCrossTUDefinition(const VarDecl *VD,
                                   DisplayCTUProgress);
 }
 
-void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
+void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE,
+                                                         SourceLocation Loc) {
   switch (IE.getCode()) {
   case index_error_code::missing_index_file:
-    Context.getDiagnostics().Report(diag::err_ctu_error_opening)
+    Context.getDiagnostics().Report(Loc, diag::err_ctu_error_opening)
         << IE.getFileName();
     return;
   case index_error_code::invalid_index_format:
-    Context.getDiagnostics().Report(diag::err_extdefmap_parsing)
+    Context.getDiagnostics().Report(Loc, diag::err_extdefmap_parsing)
         << IE.getFileName() << IE.getLineNum();
     return;
   case index_error_code::multiple_definitions:
-    Context.getDiagnostics().Report(diag::err_multiple_def_index)
+    Context.getDiagnostics().Report(Loc, diag::err_multiple_def_index)
         << IE.getLineNum();
     return;
   case index_error_code::triple_mismatch:
-    Context.getDiagnostics().Report(diag::warn_ctu_incompat_triple)
+    Context.getDiagnostics().Report(Loc, diag::warn_ctu_incompat_triple)
         << IE.getFileName() << IE.getTripleToName() << IE.getTripleFromName();
     return;
   case index_error_code::success:
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index cd52083a278ae..e23f9fff4533a 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -623,7 +623,9 @@ RuntimeDefinition AnyFunctionCall::getRuntimeDefinition() const {
   if (!CTUDeclOrError) {
     handleAllErrors(CTUDeclOrError.takeError(),
                     [&](const cross_tu::IndexError &IE) {
-                      CTUCtx.emitCrossTUDiagnostics(IE);
+                      auto Loc = getOriginExpr() ? getOriginExpr()->getExprLoc()
+                                                 : FD->getLocation();
+                      CTUCtx.emitCrossTUDiagnostics(IE, Loc);
                     });
     return {};
   }
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 1cc2b8dfb9bee..4f435b70013ec 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -309,7 +309,7 @@ class AnalysisConsumer : public AnalysisASTConsumer,
     if (!CTUDeclOrError) {
       handleAllErrors(CTUDeclOrError.takeError(),
                       [&](const cross_tu::IndexError &IE) {
-                        CTU.emitCrossTUDiagnostics(IE);
+                        CTU.emitCrossTUDiagnostics(IE, VD->getLocation());
                       });
     }
 
diff --git a/clang/test/Analysis/ctu/diag/invalid-index.cpp b/clang/test/Analysis/ctu/diag/invalid-index.cpp
index 640e6ceee654c..f8cc98c346fa1 100644
--- a/clang/test/Analysis/ctu/diag/invalid-index.cpp
+++ b/clang/test/Analysis/ctu/diag/invalid-index.cpp
@@ -8,11 +8,8 @@
 // RUN:   -analyzer-config ctu-dir=%t \
 // RUN:   -verify %s
 
-// We expect an error in this file, but without a location.
-// expected-error-re@./invalid-index.cpp:*{{error parsing index file: '{{.+}}externalDefMap.txt' line: 1 '<USR-Length>:<USR> <File-Path>' format expected}}
-
 int foo(int);
 
 void test() {
-  foo(1);
+  foo(1); // expected-error-re{{error parsing index file: '{{.+}}externalDefMap.txt' line: 1 '<USR-Length>:<USR> <File-Path>' format expected}}
 }
diff --git a/clang/test/Analysis/ctu/diag/missing-index.cpp b/clang/test/Analysis/ctu/diag/missing-index.cpp
index e09042f9538f7..351537165a466 100644
--- a/clang/test/Analysis/ctu/diag/missing-index.cpp
+++ b/clang/test/Analysis/ctu/diag/missing-index.cpp
@@ -8,11 +8,8 @@
 // RUN:   -analyzer-config ctu-index-name=non-existing.txt \
 // RUN:   -verify %s
 
-// We expect an error in this file, but without a location.
-// expected-error-re@./missing-index.cpp:*{{error opening '{{.+}}non-existing.txt': required by the CrossTU functionality}}
-
 int foo(int);
 
 void test() {
-  foo(1);
+  foo(1); // expected-error-re{{error opening '{{.+}}non-existing.txt': required by the CrossTU functionality}}
 }
diff --git a/clang/test/Analysis/ctu/different-triples.cpp b/clang/test/Analysis/ctu/different-triples.cpp
index 95b7f8d4c3fed..17170772c0207 100644
--- a/clang/test/Analysis/ctu/different-triples.cpp
+++ b/clang/test/Analysis/ctu/different-triples.cpp
@@ -10,11 +10,8 @@
 // RUN:   -Werror=ctu \
 // RUN:   -verify %s
 
-// We expect an error in this file, but without a location.
-// expected-error-re@./different-triples.cpp:*{{imported AST from {{.*}} had been generated for a different target, current: powerpc64-montavista-linux-gnu, imported: x86_64-pc-linux-gnu}}
-
 int f(int);
 
 int main() {
-  return f(5);
+  return f(5); // expected-error-re{{imported AST from '{{.*}}' had been generated for a different target, current: powerpc64-montavista-linux-gnu, imported: x86_64-pc-linux-gnu}}
 }

@llvmbot
Copy link
Copy Markdown
Member

llvmbot commented Mar 26, 2026

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Arseniy Zaostrovnykh (necto)

Changes

Report CTU import failures at the place where the imported symbol would be used. This helps to quicker understand why CSA might miss a certain expected CTU bug.

--
CPP-7804


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

7 Files Affected:

  • (modified) clang/include/clang/CrossTU/CrossTranslationUnit.h (+1-1)
  • (modified) clang/lib/CrossTU/CrossTranslationUnit.cpp (+6-5)
  • (modified) clang/lib/StaticAnalyzer/Core/CallEvent.cpp (+3-1)
  • (modified) clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp (+1-1)
  • (modified) clang/test/Analysis/ctu/diag/invalid-index.cpp (+1-4)
  • (modified) clang/test/Analysis/ctu/diag/missing-index.cpp (+1-4)
  • (modified) clang/test/Analysis/ctu/different-triples.cpp (+1-4)
diff --git a/clang/include/clang/CrossTU/CrossTranslationUnit.h b/clang/include/clang/CrossTU/CrossTranslationUnit.h
index 9e0721edfc323..145bc8df27de6 100644
--- a/clang/include/clang/CrossTU/CrossTranslationUnit.h
+++ b/clang/include/clang/CrossTU/CrossTranslationUnit.h
@@ -184,7 +184,7 @@ class CrossTranslationUnitContext {
   static std::optional<std::string> getLookupName(const Decl *D);
 
   /// Emit diagnostics for the user for potential configuration errors.
-  void emitCrossTUDiagnostics(const IndexError &IE);
+  void emitCrossTUDiagnostics(const IndexError &IE, SourceLocation Loc);
 
   /// Returns the MacroExpansionContext for the imported TU to which the given
   /// source-location corresponds.
diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp b/clang/lib/CrossTU/CrossTranslationUnit.cpp
index ef25ad454da2e..8dd0ef13123d1 100644
--- a/clang/lib/CrossTU/CrossTranslationUnit.cpp
+++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp
@@ -379,22 +379,23 @@ CrossTranslationUnitContext::getCrossTUDefinition(const VarDecl *VD,
                                   DisplayCTUProgress);
 }
 
-void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE) {
+void CrossTranslationUnitContext::emitCrossTUDiagnostics(const IndexError &IE,
+                                                         SourceLocation Loc) {
   switch (IE.getCode()) {
   case index_error_code::missing_index_file:
-    Context.getDiagnostics().Report(diag::err_ctu_error_opening)
+    Context.getDiagnostics().Report(Loc, diag::err_ctu_error_opening)
         << IE.getFileName();
     return;
   case index_error_code::invalid_index_format:
-    Context.getDiagnostics().Report(diag::err_extdefmap_parsing)
+    Context.getDiagnostics().Report(Loc, diag::err_extdefmap_parsing)
         << IE.getFileName() << IE.getLineNum();
     return;
   case index_error_code::multiple_definitions:
-    Context.getDiagnostics().Report(diag::err_multiple_def_index)
+    Context.getDiagnostics().Report(Loc, diag::err_multiple_def_index)
         << IE.getLineNum();
     return;
   case index_error_code::triple_mismatch:
-    Context.getDiagnostics().Report(diag::warn_ctu_incompat_triple)
+    Context.getDiagnostics().Report(Loc, diag::warn_ctu_incompat_triple)
         << IE.getFileName() << IE.getTripleToName() << IE.getTripleFromName();
     return;
   case index_error_code::success:
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index cd52083a278ae..e23f9fff4533a 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -623,7 +623,9 @@ RuntimeDefinition AnyFunctionCall::getRuntimeDefinition() const {
   if (!CTUDeclOrError) {
     handleAllErrors(CTUDeclOrError.takeError(),
                     [&](const cross_tu::IndexError &IE) {
-                      CTUCtx.emitCrossTUDiagnostics(IE);
+                      auto Loc = getOriginExpr() ? getOriginExpr()->getExprLoc()
+                                                 : FD->getLocation();
+                      CTUCtx.emitCrossTUDiagnostics(IE, Loc);
                     });
     return {};
   }
diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 1cc2b8dfb9bee..4f435b70013ec 100644
--- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -309,7 +309,7 @@ class AnalysisConsumer : public AnalysisASTConsumer,
     if (!CTUDeclOrError) {
       handleAllErrors(CTUDeclOrError.takeError(),
                       [&](const cross_tu::IndexError &IE) {
-                        CTU.emitCrossTUDiagnostics(IE);
+                        CTU.emitCrossTUDiagnostics(IE, VD->getLocation());
                       });
     }
 
diff --git a/clang/test/Analysis/ctu/diag/invalid-index.cpp b/clang/test/Analysis/ctu/diag/invalid-index.cpp
index 640e6ceee654c..f8cc98c346fa1 100644
--- a/clang/test/Analysis/ctu/diag/invalid-index.cpp
+++ b/clang/test/Analysis/ctu/diag/invalid-index.cpp
@@ -8,11 +8,8 @@
 // RUN:   -analyzer-config ctu-dir=%t \
 // RUN:   -verify %s
 
-// We expect an error in this file, but without a location.
-// expected-error-re@./invalid-index.cpp:*{{error parsing index file: '{{.+}}externalDefMap.txt' line: 1 '<USR-Length>:<USR> <File-Path>' format expected}}
-
 int foo(int);
 
 void test() {
-  foo(1);
+  foo(1); // expected-error-re{{error parsing index file: '{{.+}}externalDefMap.txt' line: 1 '<USR-Length>:<USR> <File-Path>' format expected}}
 }
diff --git a/clang/test/Analysis/ctu/diag/missing-index.cpp b/clang/test/Analysis/ctu/diag/missing-index.cpp
index e09042f9538f7..351537165a466 100644
--- a/clang/test/Analysis/ctu/diag/missing-index.cpp
+++ b/clang/test/Analysis/ctu/diag/missing-index.cpp
@@ -8,11 +8,8 @@
 // RUN:   -analyzer-config ctu-index-name=non-existing.txt \
 // RUN:   -verify %s
 
-// We expect an error in this file, but without a location.
-// expected-error-re@./missing-index.cpp:*{{error opening '{{.+}}non-existing.txt': required by the CrossTU functionality}}
-
 int foo(int);
 
 void test() {
-  foo(1);
+  foo(1); // expected-error-re{{error opening '{{.+}}non-existing.txt': required by the CrossTU functionality}}
 }
diff --git a/clang/test/Analysis/ctu/different-triples.cpp b/clang/test/Analysis/ctu/different-triples.cpp
index 95b7f8d4c3fed..17170772c0207 100644
--- a/clang/test/Analysis/ctu/different-triples.cpp
+++ b/clang/test/Analysis/ctu/different-triples.cpp
@@ -10,11 +10,8 @@
 // RUN:   -Werror=ctu \
 // RUN:   -verify %s
 
-// We expect an error in this file, but without a location.
-// expected-error-re@./different-triples.cpp:*{{imported AST from {{.*}} had been generated for a different target, current: powerpc64-montavista-linux-gnu, imported: x86_64-pc-linux-gnu}}
-
 int f(int);
 
 int main() {
-  return f(5);
+  return f(5); // expected-error-re{{imported AST from '{{.*}}' had been generated for a different target, current: powerpc64-montavista-linux-gnu, imported: x86_64-pc-linux-gnu}}
 }

@necto
Copy link
Copy Markdown
Contributor Author

necto commented Mar 26, 2026

@balazske @NagyDonat @steakhal
Here is the first improvement I would like to upstream. I have no visibility into other users of CTU, so don't hesitate to let me know if the missing source location of the CTU reports is by design, rather than by omission.

@necto necto changed the title [clang][analyzer] Add location to CTU diagnostics [clang][analyzer] Add location to CTU failure diagnostics Mar 27, 2026
@necto necto merged commit 94c0d37 into llvm:main Mar 27, 2026
13 checks passed
@necto necto deleted the az/ctu-error-loc branch March 27, 2026 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:static analyzer clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants