Skip to content

Commit 5e1e0c1

Browse files
authored
Merge pull request #41308 from Huddie/cxx-mutable-const-import
[cxx Interop] Disambiguate methods within the same class with same name but differing "constness"
2 parents 825fa53 + f3f75ba commit 5e1e0c1

File tree

7 files changed

+192
-2
lines changed

7 files changed

+192
-2
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3438,9 +3438,29 @@ namespace {
34383438
SmallVector<FuncDecl *, 4> methods;
34393439
SmallVector<ConstructorDecl *, 4> ctors;
34403440

3441+
// Cxx methods may have the same name but differ in "constness".
3442+
// In such a case we must differentiate in swift (See VisitFunction).
3443+
// Before importing the different CXXMethodDecl's we track functions
3444+
// that differ this way so we can disambiguate later
3445+
for (auto m : decl->decls()) {
3446+
if (auto method = dyn_cast<clang::CXXMethodDecl>(m)) {
3447+
if(method->getDeclName().isIdentifier()) {
3448+
if(Impl.cxxMethods.find(method->getName()) == Impl.cxxMethods.end()) {
3449+
Impl.cxxMethods[method->getName()] = {};
3450+
}
3451+
if(method->isConst()) {
3452+
// Add to const set
3453+
Impl.cxxMethods[method->getName()].first.insert(method);
3454+
} else {
3455+
// Add to mutable set
3456+
Impl.cxxMethods[method->getName()].second.insert(method);
3457+
}
3458+
}
3459+
}
3460+
}
3461+
34413462
// FIXME: Import anonymous union fields and support field access when
34423463
// it is nested in a struct.
3443-
34443464
for (auto m : decl->decls()) {
34453465
if (isa<clang::AccessSpecDecl>(m)) {
34463466
// The presence of AccessSpecDecls themselves does not influence
@@ -3983,6 +4003,25 @@ namespace {
39834003
if (!dc)
39844004
return nullptr;
39854005

4006+
// Handle cases where 2 CXX methods differ strictly in "constness"
4007+
// In such a case append a suffix ("Mutating") to the mutable version
4008+
// of the method when importing to swift
4009+
if(decl->getDeclName().isIdentifier()) {
4010+
const auto &cxxMethodPair = Impl.cxxMethods[decl->getName()];
4011+
const auto &constFuncPtrs = cxxMethodPair.first;
4012+
const auto &mutFuncPtrs = cxxMethodPair.second;
4013+
4014+
// Check to see if this function has both const & mut versions and
4015+
// that this decl refers to the mutable version.
4016+
if (!constFuncPtrs.empty() && mutFuncPtrs.contains(decl)) {
4017+
auto newName = decl->getName().str() + "Mutating";
4018+
auto newId = dc->getASTContext().getIdentifier(newName);
4019+
auto oldArgNames = importedName.getDeclName().getArgumentNames();
4020+
auto newDeclName = DeclName(Impl.SwiftContext, newId, oldArgNames);
4021+
importedName.setDeclName(newDeclName);
4022+
}
4023+
}
4024+
39864025
DeclName name = accessorInfo ? DeclName() : importedName.getDeclName();
39874026
auto selfIdx = importedName.getSelfIndex();
39884027

lib/ClangImporter/ImporterImpl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,10 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
569569
llvm::MapVector<std::pair<NominalTypeDecl *, Type>,
570570
std::pair<FuncDecl *, FuncDecl *>> cxxSubscripts;
571571

572+
/// Keep track of cxx function names, params etc in order to
573+
/// allow for de-duping functions that differ strictly on "constness".
574+
llvm::DenseMap<llvm::StringRef, std::pair<llvm::DenseSet<clang::FunctionDecl *>, llvm::DenseSet<clang::FunctionDecl *>>> cxxMethods;
575+
572576
/// Keeps track of the Clang functions that have been turned into
573577
/// properties.
574578
llvm::DenseMap<const clang::FunctionDecl *, VarDecl *> FunctionsAsProperties;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#ifndef TEST_INTEROP_CXX_CLASS_AMBIGUOUS_METHOD_METHODS_H
2+
#define TEST_INTEROP_CXX_CLASS_AMBIGUOUS_METHOD_METHODS_H
3+
4+
struct HasAmbiguousMethods {
5+
6+
// No input
7+
void ping() { ++mutableMethodsCalledCount; }
8+
void ping() const {}
9+
10+
// One input (const first)
11+
int increment(int a) const {
12+
return a + 1;
13+
}
14+
15+
int increment(int a) {
16+
++mutableMethodsCalledCount;
17+
return a + 1;
18+
}
19+
20+
// Multiple input with out param
21+
void increment(int a, int b, int &c) {
22+
++mutableMethodsCalledCount;
23+
c = a + b;
24+
}
25+
26+
void increment(int a, int b, int &c) const {
27+
c = a + b;
28+
}
29+
30+
// Multiple input with inout param
31+
void increment(int &a, int b) {
32+
++mutableMethodsCalledCount;
33+
a += b;
34+
}
35+
36+
void increment(int &a, int b) const {
37+
a += b;
38+
}
39+
40+
// No input with output (const first)
41+
int numberOfMutableMethodsCalled() const { return mutableMethodsCalledCount; }
42+
int numberOfMutableMethodsCalled() { return ++mutableMethodsCalledCount; }
43+
44+
private:
45+
int mutableMethodsCalledCount = 0;
46+
};
47+
48+
#endif // TEST_INTEROP_CXX_CLASS_AMBIGUOUS_METHOD_METHODS_H
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
module Methods {
22
header "methods.h"
33
requires cplusplus
4+
}
5+
6+
module AmbiguousMethods {
7+
header "ambiguous_methods.h"
8+
requires cplusplus
49
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %target-swift-ide-test -print-module -module-to-print=AmbiguousMethods -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s
2+
3+
// CHECK: mutating func pingMutating()
4+
// CHECK: func ping()
5+
6+
// CHECK: func increment(_ a: Int32) -> Int32
7+
// CHECK: mutating func incrementMutating(_ a: Int32) -> Int32
8+
9+
// CHECK: mutating func incrementMutating(_ a: Int32, _ b: Int32, _ c: inout Int32)
10+
// CHECK: func increment(_ a: Int32, _ b: Int32, _ c: inout Int32)
11+
12+
// CHECK: mutating func incrementMutating(_ a: inout Int32, _ b: Int32)
13+
// CHECK: func increment(_ a: inout Int32, _ b: Int32)
14+
15+
// CHECK: func numberOfMutableMethodsCalled() -> Int32
16+
// CHECK: mutating func numberOfMutableMethodsCalledMutating() -> Int32
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -enable-cxx-interop)
2+
//
3+
// REQUIRES: executable_test
4+
//
5+
6+
import StdlibUnittest
7+
import AmbiguousMethods
8+
9+
var CxxAmbiguousMethodTestSuite = TestSuite("CxxAmbiguousMethods")
10+
11+
CxxAmbiguousMethodTestSuite.test("numberOfMutableMethodsCalled: () -> Int") {
12+
var instance = HasAmbiguousMethods()
13+
14+
// Sanity check. Make sure we start at 0
15+
expectEqual(0, instance.numberOfMutableMethodsCalled())
16+
17+
// Make sure calling numberOfMutableMethodsCalled above didn't
18+
// change the count
19+
expectEqual(0, instance.numberOfMutableMethodsCalled())
20+
21+
// Check that mutable version _does_ change the mutable call count
22+
expectEqual(1, instance.numberOfMutableMethodsCalledMutating())
23+
24+
expectEqual(1, instance.numberOfMutableMethodsCalled())
25+
}
26+
27+
CxxAmbiguousMethodTestSuite.test("Basic Increment: (Int) -> Int") {
28+
var instance = HasAmbiguousMethods()
29+
var a: Int32 = 0
30+
31+
// Sanity check. Make sure we start at 0
32+
expectEqual(0, instance.numberOfMutableMethodsCalled())
33+
34+
// Non mutable version should NOT change count
35+
a = instance.increment(a);
36+
expectEqual(1, a)
37+
expectEqual(0, instance.numberOfMutableMethodsCalled())
38+
39+
a = instance.incrementMutating(a);
40+
expectEqual(2, a)
41+
expectEqual(1, instance.numberOfMutableMethodsCalled())
42+
}
43+
44+
CxxAmbiguousMethodTestSuite.test("Out Param Increment: (Int, Int, inout Int) -> Void") {
45+
var instance = HasAmbiguousMethods()
46+
var out: Int32 = 0
47+
48+
// Sanity check. Make sure we start at 0
49+
expectEqual(0, instance.numberOfMutableMethodsCalled())
50+
51+
// Non mutable version should NOT change count
52+
instance.increment(0, 1, &out);
53+
expectEqual(1, out)
54+
expectEqual(0, instance.numberOfMutableMethodsCalled())
55+
56+
instance.incrementMutating(5, 2, &out);
57+
expectEqual(7, out)
58+
expectEqual(1, instance.numberOfMutableMethodsCalled())
59+
}
60+
61+
CxxAmbiguousMethodTestSuite.test("Inout Param Increment: (inout Int, Int) -> Void") {
62+
var instance = HasAmbiguousMethods()
63+
var inoutVal: Int32 = 0
64+
65+
// Sanity check. Make sure we start at 0
66+
expectEqual(0, instance.numberOfMutableMethodsCalled())
67+
68+
// Non mutable version should NOT change count
69+
instance.increment(&inoutVal, 1);
70+
expectEqual(1, inoutVal)
71+
expectEqual(0, instance.numberOfMutableMethodsCalled())
72+
73+
instance.incrementMutating(&inoutVal, 2);
74+
expectEqual(3, inoutVal)
75+
expectEqual(1, instance.numberOfMutableMethodsCalled())
76+
}
77+
78+
runAllTests()

test/Interop/Cxx/class/method/methods-module-interface.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
// CHECK: func constSumAsWrapper(_ a: NonTrivialInWrapper, _ b: NonTrivialInWrapper) -> NonTrivialInWrapper
1717

1818
// CHECK: mutating func nonConstPassThroughAsWrapper(_ a: Int32) -> NonTrivialInWrapper
19-
// CHECK: func constPassThroughAsWrapper(_ a: Int32) -> NonTrivialInWrapper
19+
// CHECK: func constPassThroughAsWrapper(_ a: Int32) -> NonTrivialInWrapper

0 commit comments

Comments
 (0)