Skip to content

Commit d7b7c5e

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

File tree

7 files changed

+98
-2
lines changed

7 files changed

+98
-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
}
@@ -8239,6 +8248,15 @@ ClangImporter::Implementation::importDeclContextOf(
82398248
if (dc->getDeclKind() == clang::Decl::LinkageSpec)
82408249
dc = dc->getParent();
82418250

8251+
// Treat friend decls like top-level decls.
8252+
if (auto functionDecl = dyn_cast<clang::FunctionDecl>(decl)) {
8253+
if (functionDecl->getFriendObjectKind()) {
8254+
// Find the top-level decl context.
8255+
while (isa<clang::NamedDecl>(dc))
8256+
dc = dc->getParent();
8257+
}
8258+
}
8259+
82428260
if (dc->isTranslationUnit()) {
82438261
if (auto *module = getClangModuleForDecl(decl))
82448262
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/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)