https://github.com/cjc0013 updated 
https://github.com/llvm/llvm-project/pull/219238

>From 26800608844f90546741ee69c9b1461ac87aed59 Mon Sep 17 00:00:00 2001
From: cjc0013 <[email protected]>
Date: Thu, 27 Aug 2026 12:26:09 -0400
Subject: [PATCH 1/2] [clang] Disambiguate GMF internal functions across
 partitions

---
 clang/lib/AST/ItaniumMangle.cpp               | 27 ++++++++++-
 ...lobal-module-fragment-internal-linkage.cpp | 46 +++++++++++++++++++
 2 files changed, 72 insertions(+), 1 deletion(-)
 create mode 100644 
clang/test/Modules/global-module-fragment-internal-linkage.cpp

diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 7fb162a68fe88..b172f1a302f0a 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -1110,9 +1110,34 @@ void CXXNameMangler::mangleNameWithAbiTags(
 }
 
 void CXXNameMangler::mangleModuleName(const NamedDecl *ND) {
-  if (ND->isExternallyVisible())
+  if (ND->isExternallyVisible()) {
     if (Module *M = ND->getOwningModuleForLinkage())
       mangleModuleNamePrefix(M->getPrimaryModuleInterfaceName());
+    return;
+  }
+
+  // A function with internal linkage in a global module fragment denotes a
+  // different entity in every module unit. When definitions from multiple
+  // imported units are emitted into one translation unit, their ordinary
+  // internal-linkage names would otherwise collide.
+  const auto *FD = dyn_cast<FunctionDecl>(ND);
+  Module *M = ND->getOwningModule();
+  if (!FD || FD->getFormalLinkage() != Linkage::Internal || !M ||
+      !M->isGlobalModule() || !M->Parent ||
+      !M->Parent->isNamedModuleUnit())
+    return;
+
+  M = M->Parent;
+  if (!M->isModulePartition()) {
+    mangleModuleNamePrefix(M->Name);
+    return;
+  }
+
+  auto [PrimaryName, PartitionName] = StringRef(M->Name).rsplit(':');
+  assert(!PrimaryName.empty() && !PartitionName.empty() &&
+         "invalid module partition name");
+  mangleModuleNamePrefix(PrimaryName);
+  mangleModuleNamePrefix(PartitionName, /*IsPartition=*/true);
 }
 
 // <module-name> ::= <module-subname>
diff --git a/clang/test/Modules/global-module-fragment-internal-linkage.cpp 
b/clang/test/Modules/global-module-fragment-internal-linkage.cpp
new file mode 100644
index 0000000000000..5298015d92abe
--- /dev/null
+++ b/clang/test/Modules/global-module-fragment-internal-linkage.cpp
@@ -0,0 +1,46 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
+// RUN:   -emit-module-interface %t/part1.cppm -o %t/A-Part1.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
+// RUN:   -emit-module-interface %t/part2.cppm -o %t/A-Part2.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
+// RUN:   -emit-module-interface %t/A.cppm \
+// RUN:   -fmodule-file=%t/A-Part1.pcm -fmodule-file=%t/A-Part2.pcm \
+// RUN:   -o %t/A.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -emit-llvm -o - \
+// RUN:   %t/use.cpp -fmodule-file=%t/A.pcm \
+// RUN:   -fmodule-file=%t/A-Part1.pcm -fmodule-file=%t/A-Part2.pcm \
+// RUN:   | FileCheck %s
+//
+// Two internal functions with the same ordinary mangled name must remain
+// distinct when their global module fragments are imported together.
+// CHECK-DAG: define internal {{.*}} @_ZLW1AWP5Part16helperv()
+// CHECK-DAG: define internal {{.*}} @_ZLW1AWP5Part26helperv()
+// CHECK-DAG: call {{.*}} @_ZLW1AWP5Part16helperv()
+// CHECK-DAG: call {{.*}} @_ZLW1AWP5Part26helperv()
+// CHECK-DAG: ret i32 1
+// CHECK-DAG: ret i32 2
+
+//--- part1.cppm
+module;
+static inline __attribute__((noinline)) int helper() { return 1; }
+export module A:Part1;
+export inline int part1() { return helper(); }
+
+//--- part2.cppm
+module;
+static inline __attribute__((noinline)) int helper() { return 2; }
+export module A:Part2;
+export inline int part2() { return helper(); }
+
+//--- A.cppm
+export module A;
+export import :Part1;
+export import :Part2;
+
+//--- use.cpp
+import A;
+int use() { return part1() + part2(); }

>From 0571efbe9495ecfc070b5aab9d75e9d8d0e9c034 Mon Sep 17 00:00:00 2001
From: cjc0013 <[email protected]>
Date: Thu, 27 Aug 2026 19:45:26 -0400
Subject: [PATCH 2/2] [clang] Distinguish GMF internal functions across module
 units

---
 clang/lib/Serialization/ASTReaderDecl.cpp     | 27 ++++++++++++++++---
 ...lobal-module-fragment-internal-linkage.cpp | 22 ++++++++-------
 2 files changed, 35 insertions(+), 14 deletions(-)

diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp 
b/clang/lib/Serialization/ASTReaderDecl.cpp
index 74e0106520011..0ff0472aacccb 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -3584,12 +3584,31 @@ ASTDeclReader::FindExistingResult 
ASTDeclReader::findExisting(NamedDecl *D) {
   }
 
   ASTContext &C = Reader.getContext();
+  auto IsSameEntity = [&](NamedDecl *Existing) {
+    if (!C.isSameEntity(Existing, D))
+      return false;
+
+    auto *FD = dyn_cast<FunctionDecl>(D);
+    auto *ExistingFD = dyn_cast<FunctionDecl>(Existing);
+    if (!FD || !ExistingFD ||
+        FD->getFormalLinkage() != Linkage::Internal ||
+        ExistingFD->getFormalLinkage() != Linkage::Internal)
+      return true;
+
+    Module *M = FD->getOwningModule();
+    Module *ExistingM = ExistingFD->getOwningModule();
+    if (!M || !ExistingM || !M->isGlobalModule() ||
+        !ExistingM->isGlobalModule())
+      return true;
+
+    return M->getTopLevelModule() == ExistingM->getTopLevelModule();
+  };
   DeclContext *DC = D->getDeclContext()->getRedeclContext();
   if (TypedefNameForLinkage) {
     auto It = Reader.ImportedTypedefNamesForLinkage.find(
         std::make_pair(DC, TypedefNameForLinkage));
     if (It != Reader.ImportedTypedefNamesForLinkage.end())
-      if (C.isSameEntity(It->second, D))
+      if (IsSameEntity(It->second))
         return FindExistingResult(Reader, D, It->second, AnonymousDeclNumber,
                                   TypedefNameForLinkage);
     // Go on to check in other places in case an existing typedef name
@@ -3601,7 +3620,7 @@ ASTDeclReader::FindExistingResult 
ASTDeclReader::findExisting(NamedDecl *D) {
     // in its context by number.
     if (auto *Existing = getAnonymousDeclForMerging(
             Reader, D->getLexicalDeclContext(), AnonymousDeclNumber))
-      if (C.isSameEntity(Existing, D))
+      if (IsSameEntity(Existing))
         return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
                                   TypedefNameForLinkage);
   } else if (DC->isTranslationUnit() &&
@@ -3635,7 +3654,7 @@ ASTDeclReader::FindExistingResult 
ASTDeclReader::findExisting(NamedDecl *D) {
       if (NamedDecl *Existing =
               getDeclForMerging(*I, TypedefNameForLinkage,
                                 /*FilteringUsingShadowDecl=*/false))
-        if (C.isSameEntity(Existing, D))
+        if (IsSameEntity(Existing))
           return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
                                     TypedefNameForLinkage);
     }
@@ -3644,7 +3663,7 @@ ASTDeclReader::FindExistingResult 
ASTDeclReader::findExisting(NamedDecl *D) {
     for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) 
{
       if (NamedDecl *Existing = getDeclForMerging(*I, TypedefNameForLinkage,
                                                   !isa<UsingShadowDecl>(D)))
-        if (C.isSameEntity(Existing, D)) {
+        if (IsSameEntity(Existing)) {
           return FindExistingResult(Reader, D, Existing, AnonymousDeclNumber,
                                     TypedefNameForLinkage);
         }
diff --git a/clang/test/Modules/global-module-fragment-internal-linkage.cpp 
b/clang/test/Modules/global-module-fragment-internal-linkage.cpp
index 5298015d92abe..c9fa548ddf6dd 100644
--- a/clang/test/Modules/global-module-fragment-internal-linkage.cpp
+++ b/clang/test/Modules/global-module-fragment-internal-linkage.cpp
@@ -8,21 +8,23 @@
 // RUN:   -emit-module-interface %t/part2.cppm -o %t/A-Part2.pcm
 // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
 // RUN:   -emit-module-interface %t/A.cppm \
-// RUN:   -fmodule-file=%t/A-Part1.pcm -fmodule-file=%t/A-Part2.pcm \
+// RUN:   -fmodule-file=A:Part1=%t/A-Part1.pcm \
+// RUN:   -fmodule-file=A:Part2=%t/A-Part2.pcm \
 // RUN:   -o %t/A.pcm
 // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -emit-llvm -o - \
 // RUN:   %t/use.cpp -fmodule-file=%t/A.pcm \
-// RUN:   -fmodule-file=%t/A-Part1.pcm -fmodule-file=%t/A-Part2.pcm \
+// RUN:   -fmodule-file=A:Part1=%t/A-Part1.pcm \
+// RUN:   -fmodule-file=A:Part2=%t/A-Part2.pcm \
 // RUN:   | FileCheck %s
 //
-// Two internal functions with the same ordinary mangled name must remain
-// distinct when their global module fragments are imported together.
-// CHECK-DAG: define internal {{.*}} @_ZLW1AWP5Part16helperv()
-// CHECK-DAG: define internal {{.*}} @_ZLW1AWP5Part26helperv()
-// CHECK-DAG: call {{.*}} @_ZLW1AWP5Part16helperv()
-// CHECK-DAG: call {{.*}} @_ZLW1AWP5Part26helperv()
+// Identical internal functions from the same textual header must remain
+// distinct when separate global module fragments are imported together.
+// CHECK-DAG: define internal {{.*}} @_ZW1AWP5Part1L6helperv()
+// CHECK-DAG: define internal {{.*}} @_ZW1AWP5Part2L6helperv()
+// CHECK-DAG: call {{.*}} @_ZW1AWP5Part1L6helperv()
+// CHECK-DAG: call {{.*}} @_ZW1AWP5Part2L6helperv()
+// CHECK-DAG: ret i32 1
 // CHECK-DAG: ret i32 1
-// CHECK-DAG: ret i32 2
 
 //--- part1.cppm
 module;
@@ -32,7 +34,7 @@ export inline int part1() { return helper(); }
 
 //--- part2.cppm
 module;
-static inline __attribute__((noinline)) int helper() { return 2; }
+static inline __attribute__((noinline)) int helper() { return 1; }
 export module A:Part2;
 export inline int part2() { return helper(); }
 

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

Reply via email to