Skip to content

Commit c8017e7

Browse files
committed
[cxx-interop] Add friend operators to the lookup table properly
Previously, `friend` operators declared in C++ classes were added to the lookup table when the class is being imported. The operators were added to the wrong lookup table if the class is declared in a C++ namespace. Since a namespace can span across multiple Clang modules, its contents should be added to a translation unit level lookup table, not to a module level lookup table. This change makes sure we add `friend` operators to the lookup table earlier, when we are actually building the lookup table. Note that this is not possible for class template instantiations, because those are instantiated later, so for templates we still handle `friend` operators when importing the instantiation. rdar://116349899
1 parent 5d09913 commit c8017e7

File tree

5 files changed

+32
-5
lines changed

5 files changed

+32
-5
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2243,10 +2243,6 @@ namespace {
22432243
if (auto friendDecl = dyn_cast<clang::FriendDecl>(m)) {
22442244
if (friendDecl->getFriendDecl()) {
22452245
m = friendDecl->getFriendDecl();
2246-
2247-
auto lookupTable = Impl.findLookupTable(decl);
2248-
addEntryToLookupTable(*lookupTable, friendDecl->getFriendDecl(),
2249-
Impl.getNameImporter());
22502246
}
22512247
}
22522248

@@ -2989,7 +2985,11 @@ namespace {
29892985
// This cannot be done when building the lookup table,
29902986
// because templates are instantiated lazily.
29912987
for (auto member : def->decls()) {
2992-
if (auto method = dyn_cast<clang::CXXMethodDecl>(member)) {
2988+
if (auto friendDecl = dyn_cast<clang::FriendDecl>(member))
2989+
if (auto underlyingDecl = friendDecl->getFriendDecl())
2990+
member = underlyingDecl;
2991+
2992+
if (auto method = dyn_cast<clang::FunctionDecl>(member)) {
29932993
if (method->isOverloadedOperator()) {
29942994
addEntryToLookupTable(*Impl.findLookupTable(decl), method,
29952995
Impl.getNameImporter());

lib/ClangImporter/SwiftLookupTable.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1965,6 +1965,10 @@ void importer::addEntryToLookupTable(SwiftLookupTable &table,
19651965
isa<clang::ObjCCategoryDecl>(named)) {
19661966
clang::DeclContext *dc = cast<clang::DeclContext>(named);
19671967
for (auto member : dc->decls()) {
1968+
if (auto friendDecl = dyn_cast<clang::FriendDecl>(member))
1969+
if (auto underlyingDecl = friendDecl->getFriendDecl())
1970+
member = underlyingDecl;
1971+
19681972
if (auto namedMember = dyn_cast<clang::NamedDecl>(member))
19691973
addEntryToLookupTable(table, namedMember, nameImporter);
19701974
}

test/Interop/Cxx/operators/Inputs/member-inline.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ struct LoadableIntWrapper {
4545
}
4646
};
4747

48+
namespace NS {
49+
struct IntWrapperInNamespace {
50+
int value;
51+
friend bool operator==(const IntWrapperInNamespace &lhs,
52+
const IntWrapperInNamespace &rhs) {
53+
return lhs.value == rhs.value;
54+
}
55+
};
56+
} // namespace NS
57+
4858
struct LoadableBoolWrapper {
4959
bool value;
5060
LoadableBoolWrapper operator!() {

test/Interop/Cxx/operators/member-inline-module-interface.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
// CHECK: mutating func callAsFunction(_ x: Int32) -> Int32
99
// CHECK: mutating func callAsFunction(_ x: Int32, _ y: Int32) -> Int32
1010
// CHECK: }
11+
// CHECK: func == (lhs: LoadableIntWrapper, rhs: LoadableIntWrapper) -> Bool
12+
// CHECK: func -= (lhs: inout LoadableIntWrapper, rhs: LoadableIntWrapper)
13+
14+
// CHECK: func == (lhs: NS.IntWrapperInNamespace, rhs: NS.IntWrapperInNamespace) -> Bool
1115

1216
// CHECK: struct LoadableBoolWrapper
1317
// CHECK: prefix static func ! (lhs: inout LoadableBoolWrapper) -> LoadableBoolWrapper

test/Interop/Cxx/operators/member-inline.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ OperatorsTestSuite.test("LoadableIntWrapper.successor() (inline)") {
8383
expectEqual(42, wrapper.value)
8484
}
8585

86+
OperatorsTestSuite.test("IntWrapperInNamespace.equal (inline)") {
87+
let lhs = NS.IntWrapperInNamespace(value: 42)
88+
let rhs = NS.IntWrapperInNamespace(value: 42)
89+
90+
let result = lhs == rhs
91+
92+
expectTrue(result)
93+
}
94+
8695
OperatorsTestSuite.test("TemplatedWithFriendOperator.equal (inline)") {
8796
let lhs = TemplatedWithFriendOperatorSpec()
8897
let rhs = TemplatedWithFriendOperatorSpec()

0 commit comments

Comments
 (0)