Skip to content

Commit ac2b51e

Browse files
committed
[C++20] [Modules] Fix issues with non-exported in-class friend declarations
Close #159424 Close #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.
1 parent 4663d25 commit ac2b51e

File tree

3 files changed

+78
-3
lines changed

3 files changed

+78
-3
lines changed

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4297,10 +4297,18 @@ static bool isModuleLocalDecl(NamedDecl *D) {
42974297
if (auto *CDGD = dyn_cast<CXXDeductionGuideDecl>(FTD->getTemplatedDecl()))
42984298
return isModuleLocalDecl(CDGD->getDeducedTemplate());
42994299

4300-
if (D->getFormalLinkage() == Linkage::Module)
4301-
return true;
4300+
if (D->getFormalLinkage() != Linkage::Module)
4301+
return false;
43024302

4303-
return false;
4303+
// It is hard for the serializer to judge if the in-class friend declaration
4304+
// is visible or not, so we just transfer the task to Sema. It should be a
4305+
// safe decision since Sema is able to handle the lookup rules for in-class
4306+
// friend declarations good enough already.
4307+
if (D->getFriendObjectKind() &&
4308+
isa<CXXRecordDecl>(D->getLexicalDeclContext()))
4309+
return false;
4310+
4311+
return true;
43044312
}
43054313

43064314
static bool isTULocalInNamedModules(NamedDecl *D) {

clang/test/Modules/pr133720.cppm

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: split-file %s %t
4+
5+
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-reduced-module-interface -o %t/a.pcm
6+
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fmodule-file=a=%t/a.pcm -fsyntax-only -verify
7+
8+
//--- a.cppm
9+
export module a;
10+
11+
struct Base {
12+
template <class T>
13+
friend constexpr auto f(T) { return 0; }
14+
};
15+
export struct A: Base {};
16+
17+
//--- b.cppm
18+
export module b;
19+
20+
import a;
21+
22+
namespace n {
23+
24+
struct B {};
25+
26+
auto b() -> void {
27+
f(A{});
28+
f(B{}); // expected-error {{use of undeclared identifier 'f'}}
29+
}
30+
31+
} // namespace n

clang/test/Modules/pr159424.cppm

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: split-file %s %t
4+
5+
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-reduced-module-interface -o %t/a.pcm
6+
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fmodule-file=a=%t/a.pcm -fsyntax-only -verify
7+
8+
//--- a.cppm
9+
export module a;
10+
11+
namespace n {
12+
13+
struct monostate {
14+
friend auto operator==(monostate, monostate) -> bool = default;
15+
};
16+
17+
export struct a {
18+
friend auto operator==(a, a) -> bool = default;
19+
monostate m;
20+
};
21+
22+
} // namespace n
23+
24+
//--- b.cppm
25+
// expected-no-diagnostics
26+
export module b;
27+
28+
import a;
29+
30+
namespace n {
31+
32+
export auto b() -> bool {
33+
return a() == a();
34+
}
35+
36+
} // namespace n

0 commit comments

Comments
 (0)