Skip to content

Commit d99c179

Browse files
committed
[cxx-interop] Fix friend operators that come from class template specializations.
1 parent 992cae4 commit d99c179

File tree

5 files changed

+61
-2
lines changed

5 files changed

+61
-2
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2712,6 +2712,11 @@ static bool isVisibleFromModule(const ClangModuleUnit *ModuleFilter,
27122712
if (OwningClangModule == ModuleFilter->getClangModule())
27132713
return true;
27142714

2715+
// Friends from class templates don't have an owning module. Just return true.
2716+
if (isa<clang::FunctionDecl>(D) &&
2717+
cast<clang::FunctionDecl>(D)->isThisDeclarationInstantiatedFromAFriendDefinition())
2718+
return true;
2719+
27152720
// Handle redeclarable Clang decls by checking each redeclaration.
27162721
bool IsTagDecl = isa<clang::TagDecl>(D);
27172722
if (!(IsTagDecl || isa<clang::FunctionDecl>(D) || isa<clang::VarDecl>(D) ||
@@ -4124,7 +4129,13 @@ bool ClangImporter::Implementation::lookupValue(SwiftLookupTable &table,
41244129

41254130
// If the name matched, report this result.
41264131
bool anyMatching = false;
4127-
if (decl->getName().matchesRef(name) &&
4132+
4133+
// Use the base name for operators; they likely won't have parameters.
4134+
auto foundDeclName = decl->getName();
4135+
if (foundDeclName.isOperator())
4136+
foundDeclName = foundDeclName.getBaseName();
4137+
4138+
if (foundDeclName.matchesRef(name) &&
41284139
decl->getDeclContext()->isModuleScopeContext()) {
41294140
consumer.foundDecl(decl, DeclVisibilityKind::VisibleAtTopLevel);
41304141
anyMatching = true;

lib/ClangImporter/ImportDecl.cpp

Lines changed: 19 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
}
@@ -8241,6 +8250,15 @@ ClangImporter::Implementation::importDeclContextOf(
82418250
if (dc->getDeclKind() == clang::Decl::LinkageSpec)
82428251
dc = dc->getParent();
82438252

8253+
// Treat friend decls like top-level decls.
8254+
if (auto functionDecl = dyn_cast<clang::FunctionDecl>(decl)) {
8255+
if (functionDecl->getFriendObjectKind()) {
8256+
// Find the top-level decl context.
8257+
while (isa<clang::NamedDecl>(dc))
8258+
dc = dc->getParent();
8259+
}
8260+
}
8261+
82448262
if (dc->isTranslationUnit()) {
82458263
if (auto *module = getClangModuleForDecl(decl))
82468264
return module;

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@ struct LoadableBoolWrapper {
5050
}
5151
};
5252

53+
template<class T>
54+
struct TemplatedWithFriendOperator {
55+
friend bool operator==(const TemplatedWithFriendOperator &lhs,
56+
const TemplatedWithFriendOperator &rhs) {
57+
return true;
58+
}
59+
};
60+
61+
using TemplatedWithFriendOperatorSpec = TemplatedWithFriendOperator<int>;
62+
5363
struct __attribute__((swift_attr("import_owned"))) AddressOnlyIntWrapper {
5464
int value;
5565

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

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

92+
OperatorsTestSuite.test("TemplatedWithFriendOperator.equal (inline)") {
93+
let lhs = TemplatedWithFriendOperatorSpec()
94+
let rhs = TemplatedWithFriendOperatorSpec()
95+
96+
let result = lhs == rhs
97+
98+
expectTrue(result)
99+
}
100+
92101
#if !os(Windows) // https://github.com/apple/swift/issues/55575
93102
OperatorsTestSuite.test("LoadableBoolWrapper.exclaim (inline)") {
94103
var wrapper = LoadableBoolWrapper(value: true)

test/Interop/Cxx/stdlib/use-std-map.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,15 @@ StdMapTestSuite.test("subscript") {
2626
expectEqual(m[3], 3)
2727
}
2828

29+
extension Map.const_iterator : UnsafeCxxInputIterator { }
30+
extension Map : CxxSequence { }
31+
32+
StdMapTestSuite.test("first(where:)") {
33+
let m = initMap()
34+
let found = m.first(where: { $0.first > 1 })
35+
36+
expectEqual(found!.first, 2)
37+
expectEqual(found!.second, 2)
38+
}
39+
2940
runAllTests()

0 commit comments

Comments
 (0)