Author: Chuanqi Xu
Date: 2025-09-18T13:44:21+08:00
New Revision: ac2b51e6ce157b430b3823ebc90def9f1d49d36e

URL: 
https://github.com/llvm/llvm-project/commit/ac2b51e6ce157b430b3823ebc90def9f1d49d36e
DIFF: 
https://github.com/llvm/llvm-project/commit/ac2b51e6ce157b430b3823ebc90def9f1d49d36e.diff

LOG: [C++20] [Modules] Fix issues with non-exported in-class friend declarations

Close https://github.com/llvm/llvm-project/issues/159424
Close https://github.com/llvm/llvm-project/issues/133720

For in-class friend declaration, it is hard for the serializer to decide
if they are visible to other modules. But luckily, Sema can handle it
perfectly enough. So it is fine to make all of the in-class friend
declaration as generally visible in ASTWriter and let the Sema to make
the final call. This is safe as long as the corresponding class's
visibility are correct.

Added: 
    clang/test/Modules/pr133720.cppm
    clang/test/Modules/pr159424.cppm

Modified: 
    clang/lib/Serialization/ASTWriter.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Serialization/ASTWriter.cpp 
b/clang/lib/Serialization/ASTWriter.cpp
index 3293a54a0a093..09859da171fcd 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -4297,10 +4297,18 @@ static bool isModuleLocalDecl(NamedDecl *D) {
     if (auto *CDGD = dyn_cast<CXXDeductionGuideDecl>(FTD->getTemplatedDecl()))
       return isModuleLocalDecl(CDGD->getDeducedTemplate());
 
-  if (D->getFormalLinkage() == Linkage::Module)
-    return true;
+  if (D->getFormalLinkage() != Linkage::Module)
+    return false;
 
-  return false;
+  // It is hard for the serializer to judge if the in-class friend declaration
+  // is visible or not, so we just transfer the task to Sema. It should be a
+  // safe decision since Sema is able to handle the lookup rules for in-class
+  // friend declarations good enough already.
+  if (D->getFriendObjectKind() &&
+      isa<CXXRecordDecl>(D->getLexicalDeclContext()))
+    return false;
+
+  return true;
 }
 
 static bool isTULocalInNamedModules(NamedDecl *D) {

diff  --git a/clang/test/Modules/pr133720.cppm 
b/clang/test/Modules/pr133720.cppm
new file mode 100644
index 0000000000000..ba3f352857a18
--- /dev/null
+++ b/clang/test/Modules/pr133720.cppm
@@ -0,0 +1,31 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-reduced-module-interface -o 
%t/a.pcm
+// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fmodule-file=a=%t/a.pcm -fsyntax-only 
-verify
+
+//--- a.cppm
+export module a;
+
+struct Base {
+    template <class T>
+    friend constexpr auto f(T) { return 0; }
+};
+export struct A: Base {};
+
+//--- b.cppm
+export module b;
+
+import a;
+
+namespace n {
+
+struct B {};
+
+auto b() -> void {
+       f(A{});
+    f(B{}); // expected-error {{use of undeclared identifier 'f'}}
+}
+
+} // namespace n

diff  --git a/clang/test/Modules/pr159424.cppm 
b/clang/test/Modules/pr159424.cppm
new file mode 100644
index 0000000000000..59d515428893f
--- /dev/null
+++ b/clang/test/Modules/pr159424.cppm
@@ -0,0 +1,36 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+
+// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-reduced-module-interface -o 
%t/a.pcm
+// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fmodule-file=a=%t/a.pcm -fsyntax-only 
-verify
+
+//--- a.cppm
+export module a;
+
+namespace n {
+
+struct monostate {
+       friend auto operator==(monostate, monostate) -> bool = default;
+};
+
+export struct a {
+       friend auto operator==(a, a) -> bool = default;
+       monostate m;
+};
+
+} // namespace n
+
+//--- b.cppm
+// expected-no-diagnostics
+export module b;
+
+import a;
+
+namespace n {
+
+export auto b() -> bool {
+       return a() == a();
+}
+
+} // namespace n


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

Reply via email to