Skip to content

Commit 168ef49

Browse files
committed
[cxx-interop] Disambiguate const and non-const methods consistently
When importing a C++ struct that contains two methods that only differ in const-ness, we append `Mutating` to the name of the non-const method to make it possible to call from Swift unambiguously. Unfortunately that logic was dependent on the order in which we import methods of a class: the `Mutating` suffix was added when another method with the same name was already imported. This caused lookup failures, and the behavior was incorrect when the pair of methods return instances of an unsafe type: the const overload was renamed as `Unsafe` properly, but the non-const overload was not renamed.
1 parent 9cebd69 commit 168ef49

File tree

7 files changed

+46
-69
lines changed

7 files changed

+46
-69
lines changed

lib/ClangImporter/ImportDecl.cpp

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2105,30 +2105,6 @@ namespace {
21052105
// The name of every member.
21062106
llvm::DenseSet<StringRef> allMemberNames;
21072107

2108-
// Cxx methods may have the same name but differ in "constness".
2109-
// In such a case we must differentiate in swift (See VisitFunction).
2110-
// Before importing the different CXXMethodDecl's we track functions
2111-
// that differ this way so we can disambiguate later
2112-
for (auto m : decl->decls()) {
2113-
if (auto method = dyn_cast<clang::CXXMethodDecl>(m)) {
2114-
if (method->getDeclName().isIdentifier()) {
2115-
auto contextMap = Impl.cxxMethods.find(method->getDeclContext());
2116-
if (contextMap == Impl.cxxMethods.end() ||
2117-
contextMap->second.find(method->getName()) ==
2118-
contextMap->second.end()) {
2119-
Impl.cxxMethods[method->getDeclContext()][method->getName()] = {};
2120-
}
2121-
if (method->isConst()) {
2122-
// Add to const set
2123-
Impl.cxxMethods[method->getDeclContext()][method->getName()].first.insert(method);
2124-
} else {
2125-
// Add to mutable set
2126-
Impl.cxxMethods[method->getDeclContext()][method->getName()].second.insert(method);
2127-
}
2128-
}
2129-
}
2130-
}
2131-
21322108
// FIXME: Import anonymous union fields and support field access when
21332109
// it is nested in a struct.
21342110
for (auto m : decl->decls()) {
@@ -2214,10 +2190,6 @@ namespace {
22142190
}
22152191

22162192
if (auto MD = dyn_cast<FuncDecl>(member)) {
2217-
2218-
// When 2 CXXMethods diff by "constness" alone we differentiate them
2219-
// by changing the name of one. That changed method needs to be added
2220-
// to the lookup table since it cannot be found lazily.
22212193
if (auto cxxMethod = dyn_cast<clang::CXXMethodDecl>(m)) {
22222194
auto cxxOperatorKind = cxxMethod->getOverloadedOperator();
22232195

@@ -2272,16 +2244,6 @@ namespace {
22722244
// Make sure the synthesized decl can be found by lookupDirect.
22732245
result->addMemberToLookupTable(opFuncDecl);
22742246
}
2275-
2276-
if (cxxMethod->getDeclName().isIdentifier()) {
2277-
auto &mutableFuncPtrs =
2278-
Impl.cxxMethods[cxxMethod->getDeclContext()]
2279-
[cxxMethod->getName()]
2280-
.second;
2281-
if (mutableFuncPtrs.contains(cxxMethod)) {
2282-
result->addMemberToLookupTable(member);
2283-
}
2284-
}
22852247
}
22862248
methods.push_back(MD);
22872249
continue;
@@ -3031,25 +2993,6 @@ namespace {
30312993
return nullptr;
30322994
}
30332995

3034-
// Handle cases where 2 CXX methods differ strictly in "constness"
3035-
// In such a case append a suffix ("Mutating") to the mutable version
3036-
// of the method when importing to swift
3037-
if(decl->getDeclName().isIdentifier()) {
3038-
const auto &cxxMethodPair = Impl.cxxMethods[decl->getDeclContext()][decl->getName()];
3039-
const auto &constFuncPtrs = cxxMethodPair.first;
3040-
const auto &mutFuncPtrs = cxxMethodPair.second;
3041-
3042-
// Check to see if this function has both const & mut versions and
3043-
// that this decl refers to the mutable version.
3044-
if (!constFuncPtrs.empty() && mutFuncPtrs.contains(decl)) {
3045-
auto newName = decl->getName().str() + "Mutating";
3046-
auto newId = dc->getASTContext().getIdentifier(newName);
3047-
auto oldArgNames = importedName.getDeclName().getArgumentNames();
3048-
auto newDeclName = DeclName(Impl.SwiftContext, newId, oldArgNames);
3049-
importedName.setDeclName(newDeclName);
3050-
}
3051-
}
3052-
30532996
DeclName name = accessorInfo ? DeclName() : importedName.getDeclName();
30542997
auto selfIdx = importedName.getSelfIndex();
30552998

lib/ClangImporter/ImportName.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2200,6 +2200,34 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
22002200
}
22012201
}
22022202

2203+
SmallString<16> newName;
2204+
// Check if we need to rename the C++ method to disambiguate it.
2205+
if (auto method = dyn_cast<clang::CXXMethodDecl>(D)) {
2206+
if (!method->isConst() && !method->isOverloadedOperator()) {
2207+
// See if any other methods within the same struct have the same name, but
2208+
// differ in constness.
2209+
auto otherDecls = dc->lookup(method->getDeclName());
2210+
bool shouldRename = false;
2211+
for (auto otherDecl : otherDecls) {
2212+
if (otherDecl == D)
2213+
continue;
2214+
if (auto otherMethod = dyn_cast<clang::CXXMethodDecl>(otherDecl)) {
2215+
// TODO: what if the other method is also non-const?
2216+
if (otherMethod->isConst()) {
2217+
shouldRename = true;
2218+
break;
2219+
}
2220+
}
2221+
}
2222+
2223+
if (shouldRename) {
2224+
newName = baseName;
2225+
newName += "Mutating";
2226+
baseName = newName;
2227+
}
2228+
}
2229+
}
2230+
22032231
// swift_newtype-ed declarations may have common words with the type name
22042232
// stripped.
22052233
if (auto newtypeDecl = findSwiftNewtype(D, clangSema, version)) {

lib/ClangImporter/ImporterImpl.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -614,14 +614,6 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation
614614
llvm::MapVector<std::pair<NominalTypeDecl *, Type>,
615615
std::pair<FuncDecl *, FuncDecl *>> cxxSubscripts;
616616

617-
/// Keep track of cxx function names, params etc in order to
618-
/// allow for de-duping functions that differ strictly on "constness".
619-
llvm::DenseMap<const clang::DeclContext *, llvm::DenseMap<llvm::StringRef,
620-
std::pair<
621-
llvm::DenseSet<clang::FunctionDecl *>,
622-
llvm::DenseSet<clang::FunctionDecl *>>>>
623-
cxxMethods;
624-
625617
// Keep track of the decls that were already cloned for this specific class.
626618
llvm::DenseMap<std::pair<ValueDecl *, DeclContext *>, ValueDecl *>
627619
clonedBaseMembers;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
10
1+
11

test/Interop/Cxx/class/method/Inputs/ambiguous_methods.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,13 @@ struct HasAmbiguousMethods2 {
4747
}
4848
};
4949

50+
struct Unsafe {
51+
int *ptr;
52+
};
53+
54+
struct HasAmbiguousUnsafeMethods {
55+
Unsafe getUnsafe() const { return Unsafe(); }
56+
Unsafe getUnsafe() { return Unsafe(); }
57+
};
58+
5059
#endif // TEST_INTEROP_CXX_CLASS_AMBIGUOUS_METHOD_METHODS_H

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,9 @@
1414

1515
// CHECK: struct HasAmbiguousMethods2
1616
// CHECK: func increment(_ a: Int32) -> Int32
17-
// CHECK-NOT: mutating func incrementMutating(_ a: Int32) -> Int32
17+
// CHECK-NOT: mutating func incrementMutating(_ a: Int32) -> Int32
18+
19+
// CHECK: struct HasAmbiguousUnsafeMethods {
20+
// CHECK: func __getUnsafeUnsafe() -> Unsafe
21+
// CHECK: mutating func __getUnsafeMutatingUnsafe() -> Unsafe
22+
// CHECK: }

test/Interop/Cxx/stdlib/msvcprt-module-interface.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@
1212
// CHECK-STRING: typealias size_t = size_t
1313
// CHECK-STRING: static func to_string(_ _Val: Int32) -> std.string
1414
// CHECK-STRING: static func to_wstring(_ _Val: Int32) -> std.wstring
15-
// CHECK-STRING: struct __CxxTemplateInstSs {
15+
// CHECK-STRING: struct __CxxTemplateInstSs : CxxRandomAccessCollection {
1616
// CHECK-STRING: typealias value_type = CChar
1717
// CHECK-STRING: }
18-
// CHECK-STRING: struct __CxxTemplateInstSbIwSt11char_traitsIwESaIwEE {
18+
// CHECK-STRING: struct __CxxTemplateInstSbIwSt11char_traitsIwESaIwEE : CxxRandomAccessCollection {
1919
// CHECK-STRING: typealias value_type = CWideChar
2020
// CHECK-STRING: }
2121
// CHECK-STRING: typealias string = std.__CxxTemplateInstSs

0 commit comments

Comments
 (0)