Skip to content

Commit a6960ff

Browse files
committed
[cxx-interop] Fix friend operators that come from class template specializations.
1 parent 453fd22 commit a6960ff

File tree

8 files changed

+82
-6
lines changed

8 files changed

+82
-6
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2689,6 +2689,11 @@ static bool isVisibleFromModule(const ClangModuleUnit *ModuleFilter,
26892689
if (OwningClangModule == ModuleFilter->getClangModule())
26902690
return true;
26912691

2692+
// Friends from class templates don't have an owning module. Just return true.
2693+
if (isa<clang::FunctionDecl>(D) &&
2694+
cast<clang::FunctionDecl>(D)->isThisDeclarationInstantiatedFromAFriendDefinition())
2695+
return true;
2696+
26922697
// Handle redeclarable Clang decls by checking each redeclaration.
26932698
bool IsTagDecl = isa<clang::TagDecl>(D);
26942699
if (!(IsTagDecl || isa<clang::FunctionDecl>(D) || isa<clang::VarDecl>(D) ||

lib/ClangImporter/ImportDecl.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2139,7 +2139,16 @@ namespace {
21392139
if (auto friendDecl = dyn_cast<clang::FriendDecl>(m)) {
21402140
if (friendDecl->getFriendDecl()) {
21412141
m = friendDecl->getFriendDecl();
2142-
auto lookupTable = Impl.findLookupTable(m->getOwningModule());
2142+
2143+
// Find the owning module of the class template. Members of class
2144+
// template specializations don't have an owning module.
2145+
clang::Module *owningModule = nullptr;
2146+
if (auto spec = dyn_cast<clang::ClassTemplateSpecializationDecl>(decl))
2147+
owningModule = spec->getSpecializedTemplate()->getOwningModule();
2148+
else
2149+
owningModule = decl->getOwningModule();
2150+
2151+
auto lookupTable = Impl.findLookupTable(owningModule);
21432152
addEntryToLookupTable(*lookupTable, friendDecl->getFriendDecl(),
21442153
Impl.getNameImporter());
21452154
}

lib/ClangImporter/SwiftLookupTable.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -808,11 +808,6 @@ SwiftLookupTable::lookupMemberOperators(SerializedSwiftName baseName) {
808808

809809
// Walk each of the entries.
810810
for (auto &entry : known->second) {
811-
// We're only looking for C++ operators
812-
if (entry.Context.first != ContextKind::Tag) {
813-
continue;
814-
}
815-
816811
// Map each of the declarations.
817812
for (auto &stored : entry.DeclsOrMacros) {
818813
assert(isDeclEntry(stored) && "Not a declaration?");

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,16 @@ struct LoadableBoolWrapper {
4040
}
4141
};
4242

43+
template<class T>
44+
struct TemplatedWithFriendOperator {
45+
friend bool operator==(const TemplatedWithFriendOperator &lhs,
46+
const TemplatedWithFriendOperator &rhs) {
47+
return true;
48+
}
49+
};
50+
51+
using TemplatedWithFriendOperatorSpec = TemplatedWithFriendOperator<int>;
52+
4353
struct __attribute__((swift_attr("import_owned"))) AddressOnlyIntWrapper {
4454
int value;
4555

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

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

72+
OperatorsTestSuite.test("TemplatedWithFriendOperator.equal (inline)") {
73+
let lhs = TemplatedWithFriendOperatorSpec()
74+
let rhs = TemplatedWithFriendOperatorSpec()
75+
76+
let result = lhs == rhs
77+
78+
expectTrue(result)
79+
}
80+
7281
#if !os(Windows) // https://github.com/apple/swift/issues/55575
7382
OperatorsTestSuite.test("LoadableBoolWrapper.exclaim (inline)") {
7483
var wrapper = LoadableBoolWrapper(value: true)

test/Interop/Cxx/stdlib/Inputs/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@ module StdString {
77
header "std-string.h"
88
requires cplusplus
99
}
10+
11+
module StdMap {
12+
header "std-map.h"
13+
requires cplusplus
14+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#ifndef TEST_INTEROP_CXX_STDLIB_INPUTS_STD_VECTOR_H
2+
#define TEST_INTEROP_CXX_STDLIB_INPUTS_STD_VECTOR_H
3+
4+
#include <map>
5+
6+
using Map = std::map<int, int>;
7+
8+
inline Map initMap() {
9+
Map map;
10+
map[1] = 1;
11+
map[2] = 2;
12+
map[3] = 3;
13+
map[4] = 4;
14+
return map;
15+
}
16+
17+
#endif // TEST_INTEROP_CXX_STDLIB_INPUTS_STD_VECTOR_H
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %target-run-simple-swift(-I %S/Inputs -Xfrontend -enable-experimental-cxx-interop)
2+
//
3+
// REQUIRES: executable_test
4+
//
5+
// Enable this everywhere once we have a solution for modularizing libstdc++: rdar://87654514
6+
// REQUIRES: OS=macosx
7+
8+
import StdlibUnittest
9+
import StdMap
10+
import std.map
11+
import Cxx
12+
13+
var StdMapTestSuite = TestSuite("std::map")
14+
15+
extension Map.const_iterator : UnsafeCxxInputIterator { }
16+
extension Map : CxxSequence { }
17+
18+
StdMapTestSuite.test("first(where:)") {
19+
let m = initMap()
20+
let found = m.first(where: { $0.first > 1 })
21+
22+
expectEqual(found!.first, 2)
23+
expectEqual(found!.second, 2)
24+
}
25+
26+
runAllTests()

0 commit comments

Comments
 (0)