https://github.com/combinatorial updated 
https://github.com/llvm/llvm-project/pull/210825

>From fb78a6b2326248aeeedff057e008cbec06b973e9 Mon Sep 17 00:00:00 2001
From: David Brittain <[email protected]>
Date: Mon, 20 Jul 2026 21:56:47 +0000
Subject: [PATCH] [clang][Modules] Keep current-TU global-module-fragment
 internal-linkage functions viable in overload resolution

An internal-linkage function (e.g. a `static` or anonymous-namespace helper)
declared in the global module fragment of the current translation unit is
usable within the module unit ([module.global.frag]/p1). However,
Sema::AddOverloadCandidate removed such a function from the overload set
whenever Function->isInAnotherModuleUnit() was true. That predicate misfires
for a current-TU GMF declaration when the enclosing template is instantiated
after the global module fragment is closed: pending instantiations run in
ActOnEndOfTranslationUnitFragment, and isInAnotherModuleUnit() consults
ASTContext's current named module, which is not in scope yet at that point.
The candidate was then dropped with the hidden ovl_fail_module_mismatched
failure kind -- yielding a spurious "no matching function" error with no
candidate notes.

The existing carve-out only exempted inline / implicitly-instantiated GMF
functions (added in #104701), so a plain `static` helper reached through such
a template still failed.

Recognise a global-module-fragment function as belonging to the current unit
by comparing its top-level module against Sema::getCurrentModule() (the module
scope, which is still correct while the GMF is being finalised), and keep it in
the overload set. Uses of a `static` function genuinely imported from another
module unit remain subject to the internal-linkage rule.

Fixes #210822.
---
 clang/docs/ReleaseNotes.md                    |  7 ++++
 clang/lib/Sema/SemaOverload.cpp               | 11 +++++-
 .../gmf-internal-linkage-in-template.cppm     | 37 +++++++++++++++++++
 3 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/Modules/gmf-internal-linkage-in-template.cppm

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 5a07e77076d17..dbbf858ad68be 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -323,6 +323,13 @@ latest release, please see the [Clang Web 
Site](https://clang.llvm.org) or the
 - Fixed a crash when a using-declaration naming an unresolvable member of a
   dependent base was shadowed by an invalid using-declaration. (#GH209427)
 
+- Fixed a regression where an internal-linkage function (e.g. a `static` or
+  anonymous-namespace helper) declared in the global module fragment of the
+  current translation unit was removed from the overload set when the calling
+  template was instantiated after the global module fragment was closed,
+  producing a spurious "no matching function" error with no candidate notes.
+  (#GH210822)
+
 #### Bug Fixes to AST Handling
 
 - Fixed a non-deterministic ordering of unused local typedefs that made
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index dc912e8e95fc4..d66dea0d918fa 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -7388,7 +7388,16 @@ void Sema::AddOverloadCandidate(
         Function->isFromGlobalModule() &&
         (IsImplicitlyInstantiated || Function->isInlined());
 
-    if (ND->getFormalLinkage() == Linkage::Internal && !IsInlineFunctionInGMF) 
{
+    // Don't exclude internal-linkage entities from the current TU's global
+    // module fragment.
+    const Module *CurrentModule = getCurrentModule();
+    const bool IsCurrentUnitGMFDecl =
+        Function->isFromGlobalModule() && CurrentModule &&
+        Function->getOwningModule()->getTopLevelModule() ==
+            CurrentModule->getTopLevelModule();
+
+    if (ND->getFormalLinkage() == Linkage::Internal && !IsInlineFunctionInGMF 
&&
+        !IsCurrentUnitGMFDecl) {
       Candidate.Viable = false;
       Candidate.FailureKind = ovl_fail_module_mismatched;
       return;
diff --git a/clang/test/Modules/gmf-internal-linkage-in-template.cppm 
b/clang/test/Modules/gmf-internal-linkage-in-template.cppm
new file mode 100644
index 0000000000000..faa41fe2ba041
--- /dev/null
+++ b/clang/test/Modules/gmf-internal-linkage-in-template.cppm
@@ -0,0 +1,37 @@
+// Verify that an internal-linkage function declared in the global module
+// fragment of the current translation unit remains usable from within the
+// module unit when it is only reached through a template instantiation that is
+// performed after the global module fragment is closed (i.e. the instantiation
+// is triggered by another entity in the global module fragment).
+//
+// This is a regression test: such a plain 'static' (non-inline) helper used to
+// be wrongly removed from the overload set, producing a bogus "no matching
+// function" error with no candidate notes.
+//
+// RUN: %clang_cc1 -std=c++20 %s -emit-module-interface -o %t.pcm -verify
+// RUN: %clang_cc1 -std=c++23 %s -emit-module-interface -o %t.pcm -verify
+
+// expected-no-diagnostics
+
+module;
+static void slow(unsigned long *o) { *o = 0; }
+static void slow(unsigned int *o) { *o = 0; }
+
+template <typename T> void parse(T *o) { slow(o); }
+
+// These inline functions are in the global module fragment; the template
+// specializations they use are instantiated when the fragment is closed.
+inline unsigned long read64() {
+  unsigned long t;
+  parse(&t);
+  return t;
+}
+inline unsigned int read32() {
+  unsigned int t;
+  parse(&t);
+  return t;
+}
+
+export module a;
+
+export inline unsigned long use() { return read64() + read32(); }

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

Reply via email to