Skip to content

Commit c7836e3

Browse files
committed
[interop][SwiftToCxx] avoid emitting ambiguous C++ overloads
Just do an arity check for now
1 parent bf35e3f commit c7836e3

File tree

8 files changed

+120
-21
lines changed

8 files changed

+120
-21
lines changed

lib/AST/SwiftNameTranslation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ swift::cxx_translation::getNameForCxx(const ValueDecl *VD,
164164
if (customNamesOnly)
165165
return StringRef();
166166

167+
if (isa<ConstructorDecl>(VD))
168+
return "init";
169+
167170
if (auto *mod = dyn_cast<ModuleDecl>(VD)) {
168171
if (mod->isStdlibModule())
169172
return "swift";

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,39 @@ class DeclAndTypePrinter::Implementation
10121012
sel.getSelectorPieces().front().str() == "init";
10131013
}
10141014

1015+
/// Returns true if the given function overload is safe to emit in the current
1016+
/// C++ lexical scope.
1017+
bool canPrintOverloadOfFunction(const AbstractFunctionDecl *funcDecl) const {
1018+
assert(outputLang == OutputLanguageMode::Cxx);
1019+
auto &overloads =
1020+
owningPrinter.getCxxDeclEmissionScope().emittedFunctionOverloads;
1021+
auto cxxName = cxx_translation::getNameForCxx(funcDecl);
1022+
auto overloadIt = overloads.find(cxxName);
1023+
if (overloadIt == overloads.end()) {
1024+
overloads.insert(std::make_pair(
1025+
cxxName,
1026+
llvm::SmallVector<const AbstractFunctionDecl *>({funcDecl})));
1027+
return true;
1028+
}
1029+
auto selfArity =
1030+
funcDecl->getParameters() ? funcDecl->getParameters()->size() : 0;
1031+
for (const auto *overload : overloadIt->second) {
1032+
auto arity =
1033+
overload->getParameters() ? overload->getParameters()->size() : 0;
1034+
// Avoid printing out an overload with the same and arity, as that might
1035+
// be an ambiguous overload on the C++ side.
1036+
// FIXME: we should take types into account, not all overloads with the
1037+
// same arity are ambiguous in C++.
1038+
if (selfArity == arity) {
1039+
owningPrinter.getCxxDeclEmissionScope()
1040+
.additionalUnrepresentableDeclarations.push_back(funcDecl);
1041+
return false;
1042+
}
1043+
}
1044+
overloadIt->second.push_back(funcDecl);
1045+
return true;
1046+
}
1047+
10151048
void printAbstractFunctionAsMethod(AbstractFunctionDecl *AFD,
10161049
bool isClassMethod,
10171050
bool isNSUIntegerSubscript = false,
@@ -1051,6 +1084,12 @@ class DeclAndTypePrinter::Implementation
10511084
if (!dispatchInfo)
10521085
return;
10531086
}
1087+
// FIXME: handle getters/setters ambiguities here too.
1088+
if (!isa<AccessorDecl>(AFD)) {
1089+
if (!canPrintOverloadOfFunction(AFD))
1090+
return;
1091+
}
1092+
10541093
owningPrinter.prologueOS << cFuncPrologueOS.str();
10551094

10561095
printDocumentationComment(AFD);
@@ -1779,6 +1818,8 @@ class DeclAndTypePrinter::Implementation
17791818
.additionalUnrepresentableDeclarations.push_back(FD);
17801819
return;
17811820
}
1821+
if (!canPrintOverloadOfFunction(FD))
1822+
return;
17821823
owningPrinter.prologueOS << cFuncPrologueOS.str();
17831824
printAbstractFunctionAsCxxFunctionThunk(FD, *funcABI);
17841825
recordEmittedDeclInCurrentCxxLexicalScope(FD);

lib/PrintAsClang/DeclAndTypePrinter.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ struct CxxDeclEmissionScope {
3737
std::vector<const ValueDecl *> additionalUnrepresentableDeclarations;
3838
/// Records the C++ declaration names already emitted in this lexical scope.
3939
llvm::StringSet<> emittedDeclarationNames;
40+
/// Records the names of the function overloads already emitted in this
41+
/// lexical scope.
42+
llvm::StringMap<llvm::SmallVector<const AbstractFunctionDecl *, 2>>
43+
emittedFunctionOverloads;
4044
};
4145

4246
/// Responsible for printing a Swift Decl or Type in Objective-C, to be

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "swift/AST/ProtocolConformance.h"
2828
#include "swift/AST/SwiftNameTranslation.h"
2929
#include "swift/AST/TypeDeclFinder.h"
30+
#include "swift/Basic/SourceManager.h"
3031
#include "swift/ClangImporter/ClangImporter.h"
3132
#include "swift/Strings.h"
3233

@@ -676,8 +677,26 @@ class ModuleWriter {
676677
if (result != 0)
677678
return result;
678679
// Two overloaded functions can have the same name when emitting C++.
679-
if (isa<AbstractFunctionDecl>(*rhs) && isa<AbstractFunctionDecl>(*lhs))
680+
if (isa<AbstractFunctionDecl>(*rhs) && isa<AbstractFunctionDecl>(*lhs)) {
681+
// Sort top level functions with the same C++ name by their location to
682+
// have stable sorting that depends on users source but not on the
683+
// compiler invocation.
684+
if ((*rhs)->getLoc().isValid() && (*lhs)->getLoc().isValid()) {
685+
std::string rhsLoc, lhsLoc;
686+
auto getLocText = [](const AbstractFunctionDecl *afd) {
687+
std::string res;
688+
llvm::raw_string_ostream os(res);
689+
afd->getLoc().print(os, afd->getASTContext().SourceMgr);
690+
return std::move(os.str());
691+
};
692+
if (getLocText(cast<AbstractFunctionDecl>(*lhs)) <
693+
getLocText(cast<AbstractFunctionDecl>(*rhs)))
694+
return Descending;
695+
return Ascending;
696+
}
680697
return result;
698+
}
699+
681700
// A function and a global variable can have the same name in C++,
682701
// even when the variable might not actually be emitted by the emitter.
683702
// In that case, order the function before the variable.

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1369,16 +1369,6 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
13691369
}
13701370
}
13711371

1372-
static StringRef getConstructorName(const AbstractFunctionDecl *FD) {
1373-
auto name = cxx_translation::getNameForCxx(
1374-
FD, cxx_translation::CustomNamesOnly_t::CustomNamesOnly);
1375-
if (!name.empty()) {
1376-
assert(name.startswith("init"));
1377-
return name;
1378-
}
1379-
return "init";
1380-
}
1381-
13821372
void DeclAndTypeClangFunctionPrinter::printCxxMethod(
13831373
DeclAndTypePrinter &declAndTypePrinter,
13841374
const NominalTypeDecl *typeDeclContext, const AbstractFunctionDecl *FD,
@@ -1399,10 +1389,8 @@ void DeclAndTypeClangFunctionPrinter::printCxxMethod(
13991389
!isConstructor && !isStatic;
14001390
modifiers.hasSymbolUSR = !isDefinition;
14011391
auto result = printFunctionSignature(
1402-
FD, signature,
1403-
isConstructor ? getConstructorName(FD)
1404-
: cxx_translation::getNameForCxx(FD),
1405-
resultTy, FunctionSignatureKind::CxxInlineThunk, modifiers);
1392+
FD, signature, cxx_translation::getNameForCxx(FD), resultTy,
1393+
FunctionSignatureKind::CxxInlineThunk, modifiers);
14061394
assert(!result.isUnsupported() && "C signature should be unsupported too");
14071395

14081396
declAndTypePrinter.printAvailability(os, FD);

test/Interop/SwiftToCxx/functions/swift-function-overloads.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@
44

55
// RUN: %check-interop-cxx-header-in-clang(%t/functions.h)
66

7-
8-
97
public func overloadedFunc(_ x: Int) { }
108
public func overloadedFunc(_ y: Float) { }
119

1210
public func overloadedFuncArgLabel(x _: Int) { }
1311
public func overloadedFuncArgLabel(y _: Float) { }
1412

15-
// CHECK-DAG: void overloadedFunc(float y) noexcept
16-
// CHECK-DAG: void overloadedFunc(swift::Int x) noexcept
17-
// CHECK-DAG: void overloadedFuncArgLabel(float _1) noexcept
18-
// CHECK-DAG: void overloadedFuncArgLabel(swift::Int _1) noexcept
13+
// CHECK: void overloadedFunc(swift::Int x) noexcept
14+
// CHECK: void overloadedFuncArgLabel(swift::Int _1) noexcept
15+
16+
// CHECK: // Unavailable in C++: Swift global function 'overloadedFunc(_:)'.
17+
18+
// CHECK: // Unavailable in C++: Swift global function 'overloadedFuncArgLabel(y:)'.

test/Interop/SwiftToCxx/initializers/init-in-cxx.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,21 @@ public class DerivedClass: BaseClass {
126126
public class DerivedClassTwo: BaseClass {
127127
}
128128

129+
public struct WrapOverloadedInits {
130+
let x: Int
131+
132+
public init(_ x: Int) {
133+
self.x = x
134+
}
135+
public init(_ x: Float) {
136+
self.x = Int(x)
137+
}
138+
}
139+
140+
// CHECK: static SWIFT_INLINE_THUNK WrapOverloadedInits init
141+
// CHECK-SAME: (swift::Int x) SWIFT_SYMBOL("s:4Init19WrapOverloadedInitsVyACSicfc");
142+
// CHECK-NOT: WrapOverloadedInits init(
143+
129144
// CHECK: BaseClass BaseClass::init(swift::Int x, swift::Int y) {
130145
// CHECK-NEXT: return _impl::_impl_BaseClass::makeRetained(_impl::$s4Init9BaseClassCyACSi_SitcfC(x, y, swift::TypeMetadataTrait<BaseClass>::getTypeMetadata()));
131146

test/Interop/SwiftToCxx/methods/method-in-cxx.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,35 @@ public final class PassStructInClassMethod {
103103
// CHECK-NEXT: static SWIFT_INLINE_THUNK void staticMethod() SWIFT_SYMBOL("s:7Methods11LargeStructV12staticMethodyyFZ");
104104
// CHECK-NEXT: private
105105

106+
public struct WrapOverloadedMethods {
107+
let x: Int
108+
109+
public func method(_ x: Int) {
110+
}
111+
public func method(_ x: Float) {
112+
}
113+
public func method(argLabel y: Int64) {
114+
}
115+
}
116+
117+
// CHECK: WrapOverloadedMethods final {
118+
// CHECK: SWIFT_INLINE_THUNK void method
119+
// CHECK-SAME: (swift::Int x) const SWIFT_SYMBOL("s:7Methods014WrapOverloadedA0V6methodyySiF");
120+
// CHECK-NEXT: private:
121+
122+
public struct WrapOverloadedMethodsSibling {
123+
let x: Int
124+
125+
// Sibling method with same name should be emitted.
126+
public func method(_ x: Int) {
127+
}
128+
}
129+
130+
// CHECK: WrapOverloadedMethodsSibling final {
131+
// CHECK: SWIFT_INLINE_THUNK void method
132+
// CHECK-SAME: (swift::Int x) const SWIFT_SYMBOL("s:7Methods014WrapOverloadedA7SiblingV6methodyySiF");
133+
// CHECK-NEXT: private:
134+
106135
public func createClassWithMethods(_ x: Int) -> ClassWithMethods {
107136
return ClassWithMethods(x)
108137
}

0 commit comments

Comments
 (0)