[clang] [clang] Disambiguate GMF internal functions across partitions (PR #219238)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 1 08:08:31 PDT 2026
https://github.com/cjc0013 updated https://github.com/llvm/llvm-project/pull/219238
>From 26800608844f90546741ee69c9b1461ac87aed59 Mon Sep 17 00:00:00 2001
From: cjc0013 <cjc0013 at users.noreply.github.com>
Date: Thu, 27 Aug 2026 12:26:09 -0400
Subject: [PATCH 1/4] [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 <cjc0013 at users.noreply.github.com>
Date: Thu, 27 Aug 2026 19:45:26 -0400
Subject: [PATCH 2/4] [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(); }
>From 6e2137b2fa175dc25aa52ac635d260fa061870c3 Mon Sep 17 00:00:00 2001
From: cjc0013 <cjc0013 at users.noreply.github.com>
Date: Mon, 31 Aug 2026 13:15:13 -0400
Subject: [PATCH 3/4] [clang] Address GMF disambiguation review feedback
---
clang/docs/StandardCPlusPlusModules.md | 7 +++++
clang/lib/AST/ItaniumMangle.cpp | 7 +++++
clang/lib/Serialization/ASTReaderDecl.cpp | 3 +++
...lobal-module-fragment-internal-linkage.cpp | 26 +++++++++++++++++++
4 files changed, 43 insertions(+)
diff --git a/clang/docs/StandardCPlusPlusModules.md b/clang/docs/StandardCPlusPlusModules.md
index e9a1c332fe8a2..99df4b6416dc0 100644
--- a/clang/docs/StandardCPlusPlusModules.md
+++ b/clang/docs/StandardCPlusPlusModules.md
@@ -498,6 +498,13 @@ fragment is disabled by default. These checks can be enabled by specifying
and you encounter incorrect or missing diagnostics, please report them via the
[community issue tracker](https://github.com/llvm/llvm-project/issues/).
+When global module fragment ODR checking is skipped, Clang also keeps
+internal-linkage functions from different named module units distinct and
+includes the module-unit owner in their mangled names. This is a practical,
+non-conforming strategy for C-style `static inline` functions in real-world
+headers. `-Xclang -fno-skip-odr-check-in-gmf` restores the ordinary
+internal-linkage identity and mangling.
+
### Privacy Issue
BMIs are not and should not be treated as an information hiding mechanism.
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index b172f1a302f0a..58fd1c339fc9b 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -1116,6 +1116,13 @@ void CXXNameMangler::mangleModuleName(const NamedDecl *ND) {
return;
}
+ // FIXME: Giving a TU-local entity a module-qualified name is not
+ // standard-conforming. This is Clang's practical strategy for real-world
+ // headers when GMF ODR checking is skipped; users can restore the ordinary
+ // internal-linkage mangling with -fno-skip-odr-check-in-gmf.
+ if (!getASTContext().getLangOpts().SkipODRCheckInGMF)
+ 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
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 0ff0472aacccb..f1012c2cb0154 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -3588,6 +3588,9 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
if (!C.isSameEntity(Existing, D))
return false;
+ if (!C.getLangOpts().SkipODRCheckInGMF)
+ return true;
+
auto *FD = dyn_cast<FunctionDecl>(D);
auto *ExistingFD = dyn_cast<FunctionDecl>(Existing);
if (!FD || !ExistingFD ||
diff --git a/clang/test/Modules/global-module-fragment-internal-linkage.cpp b/clang/test/Modules/global-module-fragment-internal-linkage.cpp
index c9fa548ddf6dd..a06106a49b191 100644
--- a/clang/test/Modules/global-module-fragment-internal-linkage.cpp
+++ b/clang/test/Modules/global-module-fragment-internal-linkage.cpp
@@ -3,20 +3,43 @@
// RUN: split-file %s %t
//
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
+// RUN: -fskip-odr-check-in-gmf \
// RUN: -emit-module-interface %t/part1.cppm -o %t/A-Part1.pcm
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
+// RUN: -fskip-odr-check-in-gmf \
// RUN: -emit-module-interface %t/part2.cppm -o %t/A-Part2.pcm
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
+// RUN: -fskip-odr-check-in-gmf \
// RUN: -emit-module-interface %t/A.cppm \
// 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: -fskip-odr-check-in-gmf \
// RUN: %t/use.cpp -fmodule-file=%t/A.pcm \
// RUN: -fmodule-file=A:Part1=%t/A-Part1.pcm \
// RUN: -fmodule-file=A:Part2=%t/A-Part2.pcm \
// RUN: | FileCheck %s
//
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
+// RUN: -fno-skip-odr-check-in-gmf \
+// RUN: -emit-module-interface %t/part1.cppm -o %t/no-A-Part1.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
+// RUN: -fno-skip-odr-check-in-gmf \
+// RUN: -emit-module-interface %t/part2.cppm -o %t/no-A-Part2.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
+// RUN: -fno-skip-odr-check-in-gmf \
+// RUN: -emit-module-interface %t/A.cppm \
+// RUN: -fmodule-file=A:Part1=%t/no-A-Part1.pcm \
+// RUN: -fmodule-file=A:Part2=%t/no-A-Part2.pcm \
+// RUN: -o %t/no-A.pcm
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -emit-llvm -o - \
+// RUN: -fno-skip-odr-check-in-gmf \
+// RUN: %t/use.cpp -fmodule-file=%t/no-A.pcm \
+// RUN: -fmodule-file=A:Part1=%t/no-A-Part1.pcm \
+// RUN: -fmodule-file=A:Part2=%t/no-A-Part2.pcm \
+// RUN: | FileCheck %s --check-prefix=NO-DISAMBIGUATION
+//
// Identical internal functions from the same textual header must remain
// distinct when separate global module fragments are imported together.
// CHECK-DAG: define internal {{.*}} @_ZW1AWP5Part1L6helperv()
@@ -26,6 +49,9 @@
// CHECK-DAG: ret i32 1
// CHECK-DAG: ret i32 1
+// NO-DISAMBIGUATION: define internal {{.*}} @_ZL6helperv()
+// NO-DISAMBIGUATION-NOT: @_ZW1AWP5Part
+
//--- part1.cppm
module;
static inline __attribute__((noinline)) int helper() { return 1; }
>From a7c1f633477822bf8b2e278a0ec0e66aa59ef755 Mon Sep 17 00:00:00 2001
From: cjc0013 <cjc0013 at users.noreply.github.com>
Date: Tue, 1 Sep 2026 11:01:39 -0400
Subject: [PATCH 4/4] [clang] Separate GMF identity from ODR checking
---
clang/docs/StandardCPlusPlusModules.md | 15 ++++++------
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Options/Options.td | 11 +++++++++
clang/lib/AST/ItaniumMangle.cpp | 6 ++---
clang/lib/Serialization/ASTReaderDecl.cpp | 4 ++--
...lobal-module-fragment-internal-linkage.cpp | 24 ++++++++++++-------
6 files changed, 41 insertions(+), 20 deletions(-)
diff --git a/clang/docs/StandardCPlusPlusModules.md b/clang/docs/StandardCPlusPlusModules.md
index 99df4b6416dc0..f3741e42a3955 100644
--- a/clang/docs/StandardCPlusPlusModules.md
+++ b/clang/docs/StandardCPlusPlusModules.md
@@ -498,13 +498,6 @@ fragment is disabled by default. These checks can be enabled by specifying
and you encounter incorrect or missing diagnostics, please report them via the
[community issue tracker](https://github.com/llvm/llvm-project/issues/).
-When global module fragment ODR checking is skipped, Clang also keeps
-internal-linkage functions from different named module units distinct and
-includes the module-unit owner in their mangled names. This is a practical,
-non-conforming strategy for C-style `static inline` functions in real-world
-headers. `-Xclang -fno-skip-odr-check-in-gmf` restores the ordinary
-internal-linkage identity and mangling.
-
### Privacy Issue
BMIs are not and should not be treated as an information hiding mechanism.
@@ -521,6 +514,14 @@ the Itanium C++ ABI are covered.
The declarations in a module unit which are not in the global module fragment
have new linkage names.
+By default, Clang also keeps internal-linkage functions from global module
+fragments in different named module units distinct and includes the
+module-unit owner in their mangled names. This is a practical, non-conforming
+strategy for C-style `static inline` functions in real-world headers. Specify
+`-Xclang -fno-modules-unique-gmf-internal-linkage` to restore the ordinary
+internal-linkage identity and mangling. This behavior is independent of
+whether global module fragment ODR checking is enabled.
+
For example,
```c++
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index ad993ce7e5d95..a6db47518eb92 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -158,6 +158,7 @@ LANGOPT(Modules , 1, 0, NotCompatible, "modules semantics")
LANGOPT(ClangModules , 1, 0, Compatible, "Clang header modules")
LANGOPT(CPlusPlusModules , 1, 0, Compatible, "C++ modules syntax")
LANGOPT(SkipODRCheckInGMF , 1, 0, NotCompatible, "Skip ODR checks for decls in the global module fragment")
+LANGOPT(ModulesUniqueGMFInternalLinkage, 1, 1, NotCompatible, "Use unique internal linkage for functions in global module fragments")
LANGOPT(BuiltinHeadersInSystemModules, 1, 0, NotCompatible, "builtin headers belong to system modules, and _Builtin_ modules are ignored for cstdlib headers")
ENUM_LANGOPT(CompilingModule, CompilingModuleKind, 3, CMK_None, Benign,
"compiling a module interface")
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 3b88dce9c822b..b08e3099f8ccd 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -3733,6 +3733,17 @@ defm skip_odr_check_in_gmf : BoolOption<"f", "skip-odr-check-in-gmf",
"Perform ODR checks for decls in the global module fragment.">>,
Group<f_Group>;
+defm modules_unique_gmf_internal_linkage : BoolOption<"f",
+ "modules-unique-gmf-internal-linkage",
+ LangOpts<"ModulesUniqueGMFInternalLinkage">, DefaultTrue,
+ PosFlag<SetTrue, [], [CC1Option],
+ "Use distinct internal-linkage identities for functions in global "
+ "module fragments.">,
+ NegFlag<SetFalse, [], [CC1Option],
+ "Use ordinary internal-linkage identities for functions in global "
+ "module fragments.">>,
+ Group<f_Group>;
+
defm modules_reduced_bmi : BoolOption<"f", "modules-reduced-bmi",
FrontendOpts<"GenReducedBMI">, DefaultFalse,
NegFlag<SetFalse>,
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index fb725dac727ef..cea17f6b82b6d 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -1119,9 +1119,9 @@ void CXXNameMangler::mangleModuleName(const NamedDecl *ND) {
// FIXME: Giving a TU-local entity a module-qualified name is not
// standard-conforming. This is Clang's practical strategy for real-world
- // headers when GMF ODR checking is skipped; users can restore the ordinary
- // internal-linkage mangling with -fno-skip-odr-check-in-gmf.
- if (!getASTContext().getLangOpts().SkipODRCheckInGMF)
+ // headers; users can restore the ordinary internal-linkage mangling with
+ // -fno-modules-unique-gmf-internal-linkage.
+ if (!getASTContext().getLangOpts().ModulesUniqueGMFInternalLinkage)
return;
// A function with internal linkage in a global module fragment denotes a
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 82a2837e8b30d..9d05ebd465edd 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -3590,7 +3590,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
if (!C.isSameEntity(Existing, D))
return false;
- if (!C.getLangOpts().SkipODRCheckInGMF)
+ if (!C.getLangOpts().ModulesUniqueGMFInternalLinkage)
return true;
auto *FD = dyn_cast<FunctionDecl>(D);
@@ -3606,7 +3606,7 @@ ASTDeclReader::FindExistingResult ASTDeclReader::findExisting(NamedDecl *D) {
!ExistingM->isGlobalModule())
return true;
- return M->getTopLevelModule() == ExistingM->getTopLevelModule();
+ return false;
};
DeclContext *DC = D->getDeclContext()->getRedeclContext();
if (TypedefNameForLinkage) {
diff --git a/clang/test/Modules/global-module-fragment-internal-linkage.cpp b/clang/test/Modules/global-module-fragment-internal-linkage.cpp
index a06106a49b191..0c90f4c7288e2 100644
--- a/clang/test/Modules/global-module-fragment-internal-linkage.cpp
+++ b/clang/test/Modules/global-module-fragment-internal-linkage.cpp
@@ -3,38 +3,46 @@
// RUN: split-file %s %t
//
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
-// RUN: -fskip-odr-check-in-gmf \
+// RUN: -fno-skip-odr-check-in-gmf \
+// RUN: -fmodules-unique-gmf-internal-linkage \
// RUN: -emit-module-interface %t/part1.cppm -o %t/A-Part1.pcm
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
-// RUN: -fskip-odr-check-in-gmf \
+// RUN: -fno-skip-odr-check-in-gmf \
+// RUN: -fmodules-unique-gmf-internal-linkage \
// RUN: -emit-module-interface %t/part2.cppm -o %t/A-Part2.pcm
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
-// RUN: -fskip-odr-check-in-gmf \
+// RUN: -fno-skip-odr-check-in-gmf \
+// RUN: -fmodules-unique-gmf-internal-linkage \
// RUN: -emit-module-interface %t/A.cppm \
// 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: -fskip-odr-check-in-gmf \
+// RUN: -fno-skip-odr-check-in-gmf \
+// RUN: -fmodules-unique-gmf-internal-linkage \
// RUN: %t/use.cpp -fmodule-file=%t/A.pcm \
// RUN: -fmodule-file=A:Part1=%t/A-Part1.pcm \
// RUN: -fmodule-file=A:Part2=%t/A-Part2.pcm \
// RUN: | FileCheck %s
//
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
-// RUN: -fno-skip-odr-check-in-gmf \
+// RUN: -fskip-odr-check-in-gmf \
+// RUN: -fno-modules-unique-gmf-internal-linkage \
// RUN: -emit-module-interface %t/part1.cppm -o %t/no-A-Part1.pcm
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
-// RUN: -fno-skip-odr-check-in-gmf \
+// RUN: -fskip-odr-check-in-gmf \
+// RUN: -fno-modules-unique-gmf-internal-linkage \
// RUN: -emit-module-interface %t/part2.cppm -o %t/no-A-Part2.pcm
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
-// RUN: -fno-skip-odr-check-in-gmf \
+// RUN: -fskip-odr-check-in-gmf \
+// RUN: -fno-modules-unique-gmf-internal-linkage \
// RUN: -emit-module-interface %t/A.cppm \
// RUN: -fmodule-file=A:Part1=%t/no-A-Part1.pcm \
// RUN: -fmodule-file=A:Part2=%t/no-A-Part2.pcm \
// RUN: -o %t/no-A.pcm
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -emit-llvm -o - \
-// RUN: -fno-skip-odr-check-in-gmf \
+// RUN: -fskip-odr-check-in-gmf \
+// RUN: -fno-modules-unique-gmf-internal-linkage \
// RUN: %t/use.cpp -fmodule-file=%t/no-A.pcm \
// RUN: -fmodule-file=A:Part1=%t/no-A-Part1.pcm \
// RUN: -fmodule-file=A:Part2=%t/no-A-Part2.pcm \
More information about the cfe-commits
mailing list