https://github.com/balazske updated 
https://github.com/llvm/llvm-project/pull/204188

From 4dd27d53e80e2fb413c9e4467d6d4f7227f0aa72 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <[email protected]>
Date: Tue, 16 Jun 2026 18:15:19 +0200
Subject: [PATCH 1/2] [clang][CrossTU] Indicate weak link attribute in
 ExternalDefMap.

Names with "weak" link attribute can have a definition in multiple
source files. The externalDefMap file used at CTU analysis did not
contain information about this and using more (weak) definitions
with same name was indicated as error.

Format of the externalDefMap file is changed in a way that the
USR string contains a '-' character at the begin if the symbol is
weak (this is counted in the USR-length value). At non-weak
symbols the format remains unchanged. At reading the definitions,
one of the weak symbols is chosen if there is no "strong" definition,
otherwise the "strong" is used, and multiple "strong" definitions
are error (like before).
---
 clang/lib/CrossTU/CrossTranslationUnit.cpp | 43 ++++++++++++++++++----
 clang/test/Analysis/ctu/test-weak-sym-1.c  | 42 +++++++++++++++++++++
 clang/test/Analysis/ctu/test-weak-sym-2.c  | 42 +++++++++++++++++++++
 3 files changed, 120 insertions(+), 7 deletions(-)
 create mode 100644 clang/test/Analysis/ctu/test-weak-sym-1.c
 create mode 100644 clang/test/Analysis/ctu/test-weak-sym-2.c

diff --git a/clang/lib/CrossTU/CrossTranslationUnit.cpp 
b/clang/lib/CrossTU/CrossTranslationUnit.cpp
index 248c6320bc61b..77909cf613b20 100644
--- a/clang/lib/CrossTU/CrossTranslationUnit.cpp
+++ b/clang/lib/CrossTU/CrossTranslationUnit.cpp
@@ -179,10 +179,14 @@ std::error_code IndexError::convertToErrorCode() const {
 ///
 /// @param[in]  LineRef     The input CTU index item in format
 ///                         "<USR-Length>:<USR> <File-Path>".
-/// @param[out] LookupName  The lookup name in format "<USR-Length>:<USR>".
+///                         <USR> may contain a '-' at the start which 
indicates
+///                         that the symbol is weak.
+/// @param[out] IsWeak      The weakness status of the symbol.
+/// @param[out] LookupName  The lookup name in format "<USR-Length>:<USR>". The
+///                         optional '-' is removed from it.
 /// @param[out] FilePath    The file path "<File-Path>".
-static bool parseCrossTUIndexItem(StringRef LineRef, StringRef &LookupName,
-                                  StringRef &FilePath) {
+static bool parseCrossTUIndexItem(StringRef LineRef, bool &IsWeak,
+                                  StringRef &LookupName, StringRef &FilePath) {
   // `LineRef` is "<USR-Length>:<USR> <File-Path>" now.
 
   size_t USRLength = 0;
@@ -199,6 +203,16 @@ static bool parseCrossTUIndexItem(StringRef LineRef, 
StringRef &LookupName,
   if (USRLength >= LineRef.size() || ' ' != LineRef[USRLength])
     return false;
 
+  // The first character of this USR can be a '-' to indicate weakness of the
+  // symbol. The input USR-length includes this character, it is removed from
+  // the result.
+  char MaybeWeak = LineRef.front();
+  IsWeak = MaybeWeak == '-';
+  if (IsWeak) {
+    LineRef.consume_front(MaybeWeak);
+    --USRLength;
+  }
+
   LookupName = LineRef.substr(0, USRLength);
   FilePath = LineRef.substr(USRLength + 1);
   return true;
@@ -212,12 +226,14 @@ parseCrossTUIndex(StringRef IndexPath) {
                                         IndexPath.str());
 
   llvm::StringMap<std::string> Result;
+  llvm::StringSet<> WeakSyms;
   std::string Line;
   unsigned LineNo = 1;
   while (std::getline(ExternalMapFile, Line)) {
     // Split lookup name and file path
     StringRef LookupName, FilePathInIndex;
-    if (!parseCrossTUIndexItem(Line, LookupName, FilePathInIndex))
+    bool IsWeak;
+    if (!parseCrossTUIndexItem(Line, IsWeak, LookupName, FilePathInIndex))
       return llvm::make_error<IndexError>(
           index_error_code::invalid_index_format, IndexPath.str(), LineNo);
 
@@ -228,9 +244,20 @@ parseCrossTUIndex(StringRef IndexPath) {
     bool InsertionOccurred;
     std::tie(std::ignore, InsertionOccurred) =
         Result.try_emplace(LookupName, FilePath.begin(), FilePath.end());
-    if (!InsertionOccurred)
-      return llvm::make_error<IndexError>(
-          index_error_code::multiple_definitions, IndexPath.str(), LineNo);
+    if (!InsertionOccurred) {
+      if (!IsWeak) {
+        if (!WeakSyms.contains(LookupName)) {
+          return llvm::make_error<IndexError>(
+              index_error_code::multiple_definitions, IndexPath.str(), LineNo);
+        } else {
+          Result[LookupName].assign(FilePath.begin(), FilePath.end());
+          WeakSyms.erase(LookupName);
+        }
+      }
+    } else {
+      if (IsWeak)
+        WeakSyms.insert(LookupName);
+    }
 
     ++LineNo;
   }
@@ -279,6 +306,8 @@ CrossTranslationUnitContext::~CrossTranslationUnitContext() 
{}
 std::optional<std::string>
 CrossTranslationUnitContext::getLookupName(const Decl *D) {
   SmallString<128> DeclUSR;
+  if (D->hasAttr<WeakAttr>())
+    DeclUSR.push_back('-');
   bool Ret = index::generateUSRForDecl(D, DeclUSR);
   if (Ret)
     return {};
diff --git a/clang/test/Analysis/ctu/test-weak-sym-1.c 
b/clang/test/Analysis/ctu/test-weak-sym-1.c
new file mode 100644
index 0000000000000..602f9aa2f752f
--- /dev/null
+++ b/clang/test/Analysis/ctu/test-weak-sym-1.c
@@ -0,0 +1,42 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -x c -emit-pch -o %t/a.c.ast %t/a.c
+// RUN: %clang_cc1 -x c -emit-pch -o %t/b.c.ast %t/b.c
+
+// RUN: %clang_extdef_map %t/a.c %t/b.c -- -c -x c > %t/externalDefMap.tmp1.txt
+// RUN: sed -e 's|\.c$|.c.ast|g' %t/externalDefMap.tmp1.txt > 
%t/externalDefMap.tmp2.txt
+// RUN: sed -e 's|%t\/||g' %t/externalDefMap.tmp2.txt > %t/externalDefMap.txt
+
+// RUN: %clang_cc1 -analyze \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
+// RUN:   -analyzer-config display-ctu-progress=true \
+// RUN:   -analyzer-config ctu-dir=%t \
+// RUN:   -verify %t/main.c 2>&1 | FileCheck %s
+
+//--- main.c
+
+// expected-no-diagnostics
+// CHECK: CTU loaded AST file: b.c.ast
+
+int fn(void);
+
+int main(int argc, char* argv[]) {
+  return fn();
+}
+
+//--- a.c
+
+int fn(void) __attribute__((weak));
+
+int fn(void) {
+   return 1;
+}
+
+//--- b.c
+
+int fn(void) {
+   return 0;
+}
diff --git a/clang/test/Analysis/ctu/test-weak-sym-2.c 
b/clang/test/Analysis/ctu/test-weak-sym-2.c
new file mode 100644
index 0000000000000..6335f38867e00
--- /dev/null
+++ b/clang/test/Analysis/ctu/test-weak-sym-2.c
@@ -0,0 +1,42 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -x c -emit-pch -o %t/a.c.ast %t/a.c
+// RUN: %clang_cc1 -x c -emit-pch -o %t/b.c.ast %t/b.c
+
+// RUN: %clang_extdef_map %t/a.c %t/b.c -- -c -x c > %t/externalDefMap.tmp1.txt
+// RUN: sed -e 's|\.c$|.c.ast|g' %t/externalDefMap.tmp1.txt > 
%t/externalDefMap.tmp2.txt
+// RUN: sed -e 's|%t\/||g' %t/externalDefMap.tmp2.txt > %t/externalDefMap.txt
+
+// RUN: %clang_cc1 -analyze \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
+// RUN:   -analyzer-config display-ctu-progress=true \
+// RUN:   -analyzer-config ctu-dir=%t \
+// RUN:   -verify %t/main.c 2>&1 | FileCheck %s
+
+//--- main.c
+
+// expected-no-diagnostics
+// CHECK: CTU loaded AST file: a.c.ast
+
+int fn(void);
+
+int main(int argc, char* argv[]) {
+  return fn();
+}
+
+//--- a.c
+
+int fn(void) {
+   return 1;
+}
+
+//--- b.c
+
+int fn(void) __attribute__((weak));
+
+int fn(void) {
+   return 0;
+}

From ca6aeb5541afb7c2e89392c06dee464944669666 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= <[email protected]>
Date: Wed, 17 Jun 2026 11:21:30 +0200
Subject: [PATCH 2/2] added test

---
 clang/test/Analysis/ctu/test-weak-sym-1.c |  2 +-
 clang/test/Analysis/ctu/test-weak-sym-2.c |  2 +-
 clang/test/Analysis/ctu/test-weak-sym-3.c | 51 +++++++++++++++++++++++
 3 files changed, 53 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/Analysis/ctu/test-weak-sym-3.c

diff --git a/clang/test/Analysis/ctu/test-weak-sym-1.c 
b/clang/test/Analysis/ctu/test-weak-sym-1.c
index 602f9aa2f752f..2397e4988a22a 100644
--- a/clang/test/Analysis/ctu/test-weak-sym-1.c
+++ b/clang/test/Analysis/ctu/test-weak-sym-1.c
@@ -9,7 +9,7 @@
 // RUN: sed -e 's|\.c$|.c.ast|g' %t/externalDefMap.tmp1.txt > 
%t/externalDefMap.tmp2.txt
 // RUN: sed -e 's|%t\/||g' %t/externalDefMap.tmp2.txt > %t/externalDefMap.txt
 
-// RUN: %clang_cc1 -analyze \
+// RUN: %clang_cc1 -analyze -triple x86_64-pc-linux-gnu \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
 // RUN:   -analyzer-config display-ctu-progress=true \
diff --git a/clang/test/Analysis/ctu/test-weak-sym-2.c 
b/clang/test/Analysis/ctu/test-weak-sym-2.c
index 6335f38867e00..bac41caf93e0b 100644
--- a/clang/test/Analysis/ctu/test-weak-sym-2.c
+++ b/clang/test/Analysis/ctu/test-weak-sym-2.c
@@ -9,7 +9,7 @@
 // RUN: sed -e 's|\.c$|.c.ast|g' %t/externalDefMap.tmp1.txt > 
%t/externalDefMap.tmp2.txt
 // RUN: sed -e 's|%t\/||g' %t/externalDefMap.tmp2.txt > %t/externalDefMap.txt
 
-// RUN: %clang_cc1 -analyze \
+// RUN: %clang_cc1 -analyze -triple x86_64-pc-linux-gnu \
 // RUN:   -analyzer-checker=core \
 // RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
 // RUN:   -analyzer-config display-ctu-progress=true \
diff --git a/clang/test/Analysis/ctu/test-weak-sym-3.c 
b/clang/test/Analysis/ctu/test-weak-sym-3.c
new file mode 100644
index 0000000000000..446bd15d74cc0
--- /dev/null
+++ b/clang/test/Analysis/ctu/test-weak-sym-3.c
@@ -0,0 +1,51 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -x c -emit-pch -o %t/a.c.ast %t/a.c
+// RUN: %clang_cc1 -x c -emit-pch -o %t/b.c.ast %t/b.c
+// RUN: %clang_cc1 -x c -emit-pch -o %t/c.c.ast %t/c.c
+
+// RUN: %clang_extdef_map %t/a.c %t/b.c %t/c.c -- -c -x c > 
%t/externalDefMap.tmp1.txt
+// RUN: sed -e 's|\.c$|.c.ast|g' %t/externalDefMap.tmp1.txt > 
%t/externalDefMap.tmp2.txt
+// RUN: sed -e 's|%t\/||g' %t/externalDefMap.tmp2.txt > %t/externalDefMap.txt
+
+// RUN: %clang_cc1 -analyze -triple x86_64-pc-linux-gnu \
+// RUN:   -analyzer-checker=core \
+// RUN:   -analyzer-config experimental-enable-naive-ctu-analysis=true \
+// RUN:   -analyzer-config display-ctu-progress=true \
+// RUN:   -analyzer-config ctu-dir=%t \
+// RUN:   -verify %t/main.c 2>&1 | FileCheck %s
+
+//--- main.c
+
+// expected-no-diagnostics
+// CHECK: CTU loaded AST file: b.c.ast
+
+int fn(void);
+
+int main(int argc, char* argv[]) {
+  return fn();
+}
+
+//--- a.c
+
+int fn(void) __attribute__((weak));
+
+int fn(void) {
+   return 0;
+}
+
+//--- b.c
+
+int fn(void) {
+   return 1;
+}
+
+//--- c.c
+
+int fn(void) __attribute__((weak));
+
+int fn(void) {
+   return 0;
+}

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

Reply via email to